Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1345 lines
33 KiB

  1. /*****************************************************************************
  2. *
  3. * Copyright (C) Microsoft Corporation, 1995 - 1999
  4. *
  5. * File: irmon.c
  6. *
  7. * Description: Infrared monitor
  8. *
  9. * Author: mbert/mikezin
  10. *
  11. * Date: 3/1/98
  12. *
  13. */
  14. #define UNICODE
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <windows.h>
  21. #include <winsock2.h>
  22. #include <af_irda.h>
  23. #include <shellapi.h>
  24. #include <resource.h>
  25. #include <resrc1.h>
  26. #include <irioctl.h>
  27. // allocate storage! and initialize the GUIDS
  28. #include <initguid.h>
  29. #include <devguid.h>
  30. #include <setupapi.h>
  31. #include <cfgmgr32.h>
  32. #include <mmsystem.h>
  33. #include <wtsapi32.h>
  34. #include <strsafe.h>
  35. #include "internal.h"
  36. #include <devlist.h>
  37. #include <irtypes.h>
  38. #include <irmon.h>
  39. #include "irdisc.h"
  40. #include <irmonftp.h>
  41. #define WM_IP_DEVICE_CHANGE (WM_USER+500)
  42. #define WM_IR_DEVICE_CHANGE (WM_USER+501)
  43. #define WM_IR_LINK_CHANGE (WM_USER+502)
  44. #define IRXFER_DLL TEXT("irxfer.dll")
  45. #define IAS_LSAP_SEL "IrDA:TinyTP:LsapSel"
  46. #define IRXFER_CLASSNAME "OBEX:IrXfer"
  47. #define IRXFER_CLASSNAME2 "OBEX"
  48. #define IRMON_SERVICE_NAME TEXT("irmon")
  49. #define IRMON_CONFIG_KEY TEXT("System\\CurrentControlSet\\Services\\Irmon")
  50. #define IRMON_SHOW_ICON_KEY TEXT("ShowTrayIcon")
  51. #define IRMON_NO_SOUND_KEY TEXT("NoSound")
  52. #define TRANSFER_EXE TEXT("irxfer")
  53. #define PROPERTIES_EXE TEXT("irxfer /s")
  54. #define IRDA_DEVICE_NAME TEXT("\\Device\\IrDA")
  55. #define DEVICE_LIST_LEN 5
  56. #define TOOL_TIP_STR_SIZE 64
  57. #define EMPTY_STR TEXT("")
  58. #define SYSTRAYEVENTID WM_USER + 1
  59. #define EV_STOP_EVENT 0
  60. #define EV_REG_CHANGE_EVENT 1
  61. #define EV_TRAY_STATUS_EVENT 2
  62. #define WAIT_EVENT_CNT 3
  63. #define MAX_ATTRIB_LEN 64
  64. #define MAKE_LT_UPDATE(a,b) (a << 16) + b
  65. #define RETRY_DSCV_TIMER 1
  66. #define RETRY_DSCV_INTERVAL 10000 // 10 seconds
  67. #define CONN_ANIMATION_TIMER 2
  68. #define CONN_ANIMATION_INTERVAL 250
  69. #define RETRY_TRAY_UPDATE_TIMER 3
  70. #define RETRY_TRAY_UPDATE_INTERVAL 4000 // 4 seconds
  71. typedef enum
  72. {
  73. ICON_ST_NOICON,
  74. ICON_ST_CONN1 = 1,
  75. ICON_ST_CONN2,
  76. ICON_ST_CONN3,
  77. ICON_ST_CONN4,
  78. ICON_ST_IN_RANGE,
  79. ICON_ST_IP_IN_RANGE,
  80. ICON_ST_INTR
  81. } ICON_STATE;
  82. typedef struct _IRMON_CONTROL {
  83. CRITICAL_SECTION Lock;
  84. PVOID IrxferContext;
  85. HWND hWnd;
  86. WSAOVERLAPPED Overlapped;
  87. HANDLE DiscoveryObject;
  88. BOOL SoundOn;
  89. } IRMON_CONTROL, *PIRMON_CONTROL;
  90. IRMON_CONTROL GlobalIrmonControl;
  91. HANDLE hIrmonEvents[WAIT_EVENT_CNT];
  92. BYTE FoundDevListBuf[ sizeof(OBEX_DEVICE_LIST) + sizeof(OBEX_DEVICE)*MAX_OBEX_DEVICES];
  93. OBEX_DEVICE_LIST * const pDeviceList=(POBEX_DEVICE_LIST)FoundDevListBuf;
  94. TCHAR IrmonClassName[] = TEXT("IrmonClass");
  95. BOOLEAN IconInTray;
  96. BOOLEAN IrmonStopped;
  97. HICON hInRange;
  98. HICON hIpInRange;
  99. HICON hInterrupt;
  100. HICON hConn1;
  101. HICON hConn2;
  102. HICON hConn3;
  103. HICON hConn4;
  104. IRLINK_STATUS LinkStatus;
  105. HINSTANCE ghInstance;
  106. BOOLEAN UserLoggedIn;
  107. BOOLEAN TrayEnabled;
  108. BOOLEAN DeviceListUpdated;
  109. UINT LastTrayUpdate; // debug purposes
  110. UINT_PTR RetryTrayUpdateTimerId;
  111. BOOLEAN RetryTrayUpdateTimerRunning;
  112. int TrayUpdateFailures;
  113. UINT_PTR ConnAnimationTimerId;
  114. TCHAR ConnDevName[64];
  115. UINT ConnIcon;
  116. int ConnAddition;
  117. BOOLEAN InterruptedSoundPlaying;
  118. HKEY ghCurrentUserKey = 0;
  119. BOOLEAN ShowBalloonTip;
  120. BOOLEAN IrxferDeviceInRange;
  121. HMODULE hIrxfer;
  122. extern BOOL ShowSendWindow();
  123. extern BOOL ShowPropertiesPage();
  124. extern
  125. void
  126. UpdateDiscoveredDevices(
  127. const OBEX_DEVICE_LIST *IrDevices
  128. );
  129. VOID
  130. InitiateLazyDscv(
  131. PIRMON_CONTROL IrmonControl
  132. );
  133. VOID
  134. InitiateLinkStatusQuery(
  135. PIRMON_CONTROL IrmonControl
  136. );
  137. #if DBG
  138. TCHAR *
  139. GetLastErrorText()
  140. {
  141. switch (WSAGetLastError())
  142. {
  143. case WSAEINTR:
  144. return (TEXT("WSAEINTR"));
  145. break;
  146. case WSAEBADF:
  147. return(TEXT("WSAEBADF"));
  148. break;
  149. case WSAEACCES:
  150. return(TEXT("WSAEACCES"));
  151. break;
  152. case WSAEFAULT:
  153. return(TEXT("WSAEFAULT"));
  154. break;
  155. case WSAEINVAL:
  156. return(TEXT("WSAEINVAL"));
  157. break;
  158. case WSAEMFILE:
  159. return(TEXT("WSAEMFILE"));
  160. break;
  161. case WSAEWOULDBLOCK:
  162. return(TEXT("WSAEWOULDBLOCK"));
  163. break;
  164. case WSAEINPROGRESS:
  165. return(TEXT("WSAEINPROGRESS"));
  166. break;
  167. case WSAEALREADY:
  168. return(TEXT("WSAEALREADY"));
  169. break;
  170. case WSAENOTSOCK:
  171. return(TEXT("WSAENOTSOCK"));
  172. break;
  173. case WSAEDESTADDRREQ:
  174. return(TEXT("WSAEDESTADDRREQ"));
  175. break;
  176. case WSAEMSGSIZE:
  177. return(TEXT("WSAEMSGSIZE"));
  178. break;
  179. case WSAEPROTOTYPE:
  180. return(TEXT("WSAEPROTOTYPE"));
  181. break;
  182. case WSAENOPROTOOPT:
  183. return(TEXT("WSAENOPROTOOPT"));
  184. break;
  185. case WSAEPROTONOSUPPORT:
  186. return(TEXT("WSAEPROTONOSUPPORT"));
  187. break;
  188. case WSAESOCKTNOSUPPORT:
  189. return(TEXT("WSAESOCKTNOSUPPORT"));
  190. break;
  191. case WSAEOPNOTSUPP:
  192. return(TEXT("WSAEOPNOTSUPP"));
  193. break;
  194. case WSAEPFNOSUPPORT:
  195. return(TEXT("WSAEPFNOSUPPORT"));
  196. break;
  197. case WSAEAFNOSUPPORT:
  198. return(TEXT("WSAEAFNOSUPPORT"));
  199. break;
  200. case WSAEADDRINUSE:
  201. return(TEXT("WSAEADDRINUSE"));
  202. break;
  203. case WSAEADDRNOTAVAIL:
  204. return(TEXT("WSAEADDRNOTAVAIL"));
  205. break;
  206. case WSAENETDOWN:
  207. return(TEXT("WSAENETDOWN"));
  208. break;
  209. case WSAENETUNREACH:
  210. return(TEXT("WSAENETUNREACH"));
  211. break;
  212. case WSAENETRESET:
  213. return(TEXT("WSAENETRESET"));
  214. break;
  215. case WSAECONNABORTED:
  216. return(TEXT("WSAECONNABORTED"));
  217. break;
  218. case WSAECONNRESET:
  219. return(TEXT("WSAECONNRESET"));
  220. break;
  221. case WSAENOBUFS:
  222. return(TEXT("WSAENOBUFS"));
  223. break;
  224. case WSAEISCONN:
  225. return(TEXT("WSAEISCONN"));
  226. break;
  227. case WSAENOTCONN:
  228. return(TEXT("WSAENOTCONN"));
  229. break;
  230. case WSAESHUTDOWN:
  231. return(TEXT("WSAESHUTDOWN"));
  232. break;
  233. case WSAETOOMANYREFS:
  234. return(TEXT("WSAETOOMANYREFS"));
  235. break;
  236. case WSAETIMEDOUT:
  237. return(TEXT("WSAETIMEDOUT"));
  238. break;
  239. case WSAECONNREFUSED:
  240. return(TEXT("WSAECONNREFUSED"));
  241. break;
  242. case WSAELOOP:
  243. return(TEXT("WSAELOOP"));
  244. break;
  245. case WSAENAMETOOLONG:
  246. return(TEXT("WSAENAMETOOLONG"));
  247. break;
  248. case WSAEHOSTDOWN:
  249. return(TEXT("WSAEHOSTDOWN"));
  250. break;
  251. case WSAEHOSTUNREACH:
  252. return(TEXT("WSAEHOSTUNREACH"));
  253. break;
  254. case WSAENOTEMPTY:
  255. return(TEXT("WSAENOTEMPTY"));
  256. break;
  257. case WSAEPROCLIM:
  258. return(TEXT("WSAEPROCLIM"));
  259. break;
  260. case WSAEUSERS:
  261. return(TEXT("WSAEUSERS"));
  262. break;
  263. case WSAEDQUOT:
  264. return(TEXT("WSAEDQUOT"));
  265. break;
  266. case WSAESTALE:
  267. return(TEXT("WSAESTALE"));
  268. break;
  269. case WSAEREMOTE:
  270. return(TEXT("WSAEREMOTE"));
  271. break;
  272. case WSAEDISCON:
  273. return(TEXT("WSAEDISCON"));
  274. break;
  275. case WSASYSNOTREADY:
  276. return(TEXT("WSASYSNOTREADY"));
  277. break;
  278. case WSAVERNOTSUPPORTED:
  279. return(TEXT("WSAVERNOTSUPPORTED"));
  280. break;
  281. case WSANOTINITIALISED:
  282. return(TEXT("WSANOTINITIALISED"));
  283. break;
  284. /*
  285. case WSAHOST:
  286. return(TEXT("WSAHOST"));
  287. break;
  288. case WSATRY:
  289. return(TEXT("WSATRY"));
  290. break;
  291. case WSANO:
  292. return(TEXT("WSANO"));
  293. break;
  294. */
  295. default:
  296. return(TEXT("Unknown Error"));
  297. }
  298. }
  299. #endif
  300. HKEY
  301. OpenCurrentUserKey()
  302. {
  303. HKEY hUserKey;
  304. //
  305. // Open all our keys. If we can't open the user's key
  306. // or the key to watch for changes, we bail.
  307. //
  308. if (RegOpenKeyEx(HKEY_CURRENT_USER, NULL, 0, KEY_READ, &hUserKey)) {
  309. DEBUGMSG(("IRMON-FTP: RegOpenKey1 failed %d\n", GetLastError()));
  310. return 0;
  311. }
  312. return hUserKey;
  313. }
  314. VOID
  315. LoadTrayIconImages()
  316. {
  317. hInRange = LoadImage(ghInstance, MAKEINTRESOURCE(IDI_IN_RANGE),
  318. IMAGE_ICON, 16,16,0);
  319. hInterrupt= LoadImage(ghInstance, MAKEINTRESOURCE(IDI_INTR),
  320. IMAGE_ICON, 16,16,0);
  321. hConn1 = LoadImage(ghInstance, MAKEINTRESOURCE(IDI_CONN1),
  322. IMAGE_ICON, 16,16,0);
  323. hConn2 = LoadImage(ghInstance, MAKEINTRESOURCE(IDI_CONN2),
  324. IMAGE_ICON, 16,16,0);
  325. hConn3 = LoadImage(ghInstance, MAKEINTRESOURCE(IDI_CONN3),
  326. IMAGE_ICON, 16,16,0);
  327. hConn4 = LoadImage(ghInstance, MAKEINTRESOURCE(IDI_CONN4),
  328. IMAGE_ICON, 16,16,0);
  329. hIpInRange= LoadImage(ghInstance, MAKEINTRESOURCE(IDI_IP),
  330. IMAGE_ICON, 16,16,0);
  331. }
  332. VOID
  333. UpdateTray(
  334. PIRMON_CONTROL IrmonControl,
  335. ICON_STATE IconState,
  336. DWORD MsgId,
  337. LPTSTR DeviceName,
  338. UINT Baud
  339. )
  340. {
  341. NOTIFYICONDATA NotifyIconData;
  342. DWORD Cnt;
  343. TCHAR FormatStr[256];
  344. BOOL Result = TRUE;
  345. BOOLEAN TrayUpdateFailed = FALSE;
  346. if (!TrayEnabled && IconState != ICON_ST_NOICON)
  347. {
  348. return;
  349. }
  350. if (!hInRange)
  351. {
  352. LoadTrayIconImages();
  353. }
  354. NotifyIconData.cbSize = sizeof(NOTIFYICONDATA);
  355. NotifyIconData.uID = 0;
  356. NotifyIconData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_INFO;
  357. NotifyIconData.uCallbackMessage = SYSTRAYEVENTID;
  358. NotifyIconData.hWnd = IrmonControl->hWnd;
  359. NotifyIconData.hIcon = 0;
  360. NotifyIconData.szInfo[0] = 0;
  361. NotifyIconData.szInfoTitle[0] = 0;
  362. if (MsgId == 0)
  363. {
  364. NotifyIconData.szTip[0] = L'\0';
  365. }
  366. else
  367. {
  368. if (LoadString(ghInstance, MsgId, FormatStr, sizeof(FormatStr)/sizeof(TCHAR)))
  369. {
  370. StringCbPrintf(NotifyIconData.szTip, sizeof(NotifyIconData.szTip), FormatStr, DeviceName, Baud);
  371. }
  372. }
  373. if (IrmonStopped && IconState != ICON_ST_NOICON)
  374. return;
  375. switch (IconState)
  376. {
  377. case ICON_ST_NOICON:
  378. ShowBalloonTip = TRUE;
  379. if (IconInTray)
  380. {
  381. NotifyIconData.uFlags = 0;
  382. IconInTray = FALSE;
  383. if (Shell_NotifyIcon(NIM_DELETE, &NotifyIconData)) {
  384. LastTrayUpdate = MAKE_LT_UPDATE(NIM_DELETE,ICON_ST_NOICON);
  385. if (IrmonControl->SoundOn) {
  386. PlayIrSound(OUTOFRANGE_SOUND);
  387. }
  388. } else {
  389. DEBUGMSG(("IRMON-FTP: Shell_NotifyIcon(Delete) failed %d, %d\n", TrayUpdateFailures, GetLastError()));
  390. }
  391. }
  392. return;
  393. case ICON_ST_IN_RANGE:
  394. case ICON_ST_IP_IN_RANGE:
  395. if (IconState == ICON_ST_IP_IN_RANGE) {
  396. NotifyIconData.hIcon = hIpInRange;
  397. } else {
  398. NotifyIconData.hIcon = hInRange;
  399. }
  400. if (ShowBalloonTip)
  401. {
  402. ShowBalloonTip = FALSE;
  403. if (IrxferDeviceInRange &&
  404. LoadString(ghInstance, IDS_BALLOON_TITLE,
  405. NotifyIconData.szInfoTitle,
  406. sizeof(NotifyIconData.szInfoTitle)/sizeof(TCHAR)))
  407. {
  408. NotifyIconData.uFlags |= NIF_INFO;
  409. NotifyIconData.uTimeout = 10000; // in milliseconds
  410. // NotifyIconData.dwInfoFlags = NIIF_INFO;
  411. if (DeviceName)
  412. {
  413. LoadString(ghInstance, IDS_BALLOON_TXT,
  414. FormatStr,
  415. sizeof(FormatStr)/sizeof(TCHAR));
  416. StringCbPrintf(NotifyIconData.szInfo, sizeof(NotifyIconData.szInfo), FormatStr, DeviceName);
  417. }
  418. else
  419. {
  420. LoadString(ghInstance, IDS_BALLOON_TXT2,
  421. NotifyIconData.szInfo,
  422. sizeof(NotifyIconData.szInfo)/sizeof(TCHAR));
  423. }
  424. }
  425. }
  426. break;
  427. case ICON_ST_CONN1:
  428. NotifyIconData.hIcon = hConn1;
  429. break;
  430. case ICON_ST_CONN2:
  431. NotifyIconData.hIcon = hConn2;
  432. break;
  433. case ICON_ST_CONN3:
  434. NotifyIconData.hIcon = hConn3;
  435. break;
  436. case ICON_ST_CONN4:
  437. NotifyIconData.hIcon = hConn4;
  438. break;
  439. case ICON_ST_INTR:
  440. NotifyIconData.hIcon = hInterrupt;
  441. if (LoadString(ghInstance, IDS_BLOCKED_TITLE,
  442. NotifyIconData.szInfoTitle,
  443. sizeof(NotifyIconData.szInfoTitle)/sizeof(TCHAR)) &&
  444. LoadString(ghInstance, IDS_BLOCKED_TXT,
  445. NotifyIconData.szInfo,
  446. sizeof(NotifyIconData.szInfo)/sizeof(TCHAR)))
  447. {
  448. NotifyIconData.uFlags |= NIF_INFO;
  449. NotifyIconData.uTimeout = 10000; // in milliseconds
  450. NotifyIconData.dwInfoFlags = NIIF_WARNING;
  451. }
  452. break;
  453. }
  454. if (IconState == ICON_ST_INTR) {
  455. if (IrmonControl->SoundOn) {
  456. PlayIrSound(INTERRUPTED_SOUND);
  457. InterruptedSoundPlaying = TRUE;
  458. }
  459. } else {
  460. if (InterruptedSoundPlaying) {
  461. InterruptedSoundPlaying = FALSE;
  462. PlayIrSound(END_INTERRUPTED_SOUND);
  463. }
  464. }
  465. if (!IconInTray)
  466. {
  467. if (Shell_NotifyIcon(NIM_ADD, &NotifyIconData))
  468. {
  469. LastTrayUpdate = MAKE_LT_UPDATE(NIM_ADD, IconState);
  470. if (IrmonControl->SoundOn) {
  471. PlayIrSound(INRANGE_SOUND);
  472. }
  473. IconInTray = TRUE;
  474. }
  475. else
  476. {
  477. TrayUpdateFailures++;
  478. DEBUGMSG(("IRMON-FTP: Shell_NotifyIcon(ADD) failed %d, %d\n", TrayUpdateFailures, GetLastError()));
  479. NotifyIconData.uFlags = 0;
  480. NotifyIconData.cbSize = sizeof(NOTIFYICONDATA);
  481. NotifyIconData.uID = 0;
  482. NotifyIconData.uCallbackMessage = SYSTRAYEVENTID;
  483. NotifyIconData.hWnd = IrmonControl->hWnd;
  484. NotifyIconData.hIcon = 0;
  485. NotifyIconData.szInfo[0] = 0;
  486. NotifyIconData.szInfoTitle[0] = 0;
  487. Shell_NotifyIcon(NIM_DELETE, &NotifyIconData);
  488. TrayUpdateFailed = TRUE;
  489. ShowBalloonTip = TRUE;
  490. }
  491. }
  492. else
  493. {
  494. if (!Shell_NotifyIcon(NIM_MODIFY, &NotifyIconData))
  495. {
  496. TrayUpdateFailures++;
  497. DEBUGMSG(("IRMON-FTP: Shell_NotifyIcon(Modify) failed %d, %d\n", TrayUpdateFailures, GetLastError()));
  498. TrayUpdateFailed = TRUE;
  499. }
  500. else
  501. {
  502. LastTrayUpdate = MAKE_LT_UPDATE(NIM_MODIFY, IconState);
  503. }
  504. }
  505. if (TrayUpdateFailed && !RetryTrayUpdateTimerRunning)
  506. {
  507. RetryTrayUpdateTimerId = SetTimer(IrmonControl->hWnd, RETRY_TRAY_UPDATE_TIMER,
  508. RETRY_TRAY_UPDATE_INTERVAL, NULL);
  509. RetryTrayUpdateTimerRunning = TRUE;
  510. }
  511. }
  512. VOID
  513. ConnAnimationTimerExp(
  514. PIRMON_CONTROL IrmonControl
  515. )
  516. {
  517. UpdateTray(
  518. IrmonControl,ConnIcon,
  519. IDS_CONNECTED_TO,
  520. ConnDevName,
  521. LinkStatus.ConnectSpeed
  522. );
  523. ConnIcon += ConnAddition;
  524. if (ConnIcon == 4)
  525. {
  526. ConnAddition = -1;
  527. }
  528. else if (ConnIcon == 1)
  529. {
  530. ConnAddition = 1;
  531. }
  532. }
  533. VOID
  534. IsIrxferDeviceInRange()
  535. {
  536. int i, LsapSel, Attempt, Status;
  537. IrxferDeviceInRange = FALSE;
  538. for (i = 0; i < (int)pDeviceList->DeviceCount; i++) {
  539. if (pDeviceList->DeviceList[i].DeviceSpecific.s.Irda.ObexSupport) {
  540. IrxferDeviceInRange = TRUE;
  541. break;
  542. }
  543. }
  544. return;
  545. }
  546. VOID
  547. DevListChangeOrUpdatedLinkStatus(
  548. PIRMON_CONTROL IrmonControl
  549. )
  550. {
  551. if (!UserLoggedIn)
  552. {
  553. DEBUGMSG(("IRMON-FTP: User not logged in, ignoring device change\n"));
  554. return;
  555. }
  556. if (DeviceListUpdated)
  557. {
  558. IsIrxferDeviceInRange();
  559. }
  560. if (LinkStatus.Flags & LF_INTERRUPTED)
  561. {
  562. KillTimer(IrmonControl->hWnd, ConnAnimationTimerId);
  563. UpdateTray(IrmonControl,ICON_ST_INTR, IDS_INTERRUPTED, NULL, 0);
  564. }
  565. else if ((LinkStatus.Flags & LF_CONNECTED) && (pDeviceList->DeviceCount > 0))
  566. {
  567. ULONG i;
  568. ConnDevName[0] = 0;
  569. ConnIcon = 1;
  570. ConnAddition = 1;
  571. for (i = 0; i < pDeviceList->DeviceCount; i++)
  572. {
  573. if (memcmp(&pDeviceList->DeviceList[i].DeviceSpecific.s.Irda.DeviceId,
  574. LinkStatus.ConnectedDeviceId, 4) == 0)
  575. {
  576. //
  577. // the name is in unicode
  578. //
  579. ZeroMemory(ConnDevName,sizeof(ConnDevName));
  580. StringCbCopy(ConnDevName, sizeof(ConnDevName),
  581. pDeviceList->DeviceList[i].DeviceName);
  582. break;
  583. }
  584. }
  585. ConnAnimationTimerExp(IrmonControl);
  586. ConnAnimationTimerId = SetTimer(IrmonControl->hWnd, CONN_ANIMATION_TIMER,
  587. CONN_ANIMATION_INTERVAL, NULL);
  588. }
  589. else
  590. {
  591. KillTimer(IrmonControl->hWnd, ConnAnimationTimerId);
  592. if ((pDeviceList->DeviceCount == 0)) {
  593. //
  594. // no devices in range
  595. //
  596. UpdateTray(IrmonControl,ICON_ST_NOICON, 0, NULL, 0);
  597. } else {
  598. //
  599. // atleast one device in range
  600. //
  601. if ((pDeviceList->DeviceCount == 1) ) {
  602. //
  603. // one ir device in range
  604. //
  605. StringCbCopy(ConnDevName, sizeof(ConnDevName),
  606. pDeviceList->DeviceList[0].DeviceName
  607. );
  608. UpdateTray(IrmonControl,ICON_ST_IN_RANGE, IDS_IN_RANGE, ConnDevName, 0);
  609. } else {
  610. //
  611. // more than one device total
  612. //
  613. UpdateTray(IrmonControl,ICON_ST_IN_RANGE, IDS_DEVS_IN_RANGE, NULL, 0);
  614. }
  615. }
  616. }
  617. if (DeviceListUpdated)
  618. {
  619. HANDLE hThread;
  620. DWORD ThreadId;
  621. DeviceListUpdated = FALSE;
  622. // PnP Printers, Notify transfer app
  623. if (GlobalIrmonControl.IrxferContext != NULL) {
  624. UpdateDiscoveredDevices(pDeviceList);
  625. }
  626. }
  627. }
  628. VOID
  629. UserLogonEvent(
  630. PIRMON_CONTROL IrmonControl
  631. )
  632. {
  633. UINT DevListLen;
  634. NTSTATUS Status;
  635. OBJECT_ATTRIBUTES ObjAttr;
  636. UNICODE_STRING DeviceName;
  637. IO_STATUS_BLOCK IoStatusBlock;
  638. UserLoggedIn = TRUE;
  639. //
  640. // Create the window that will receive the taskbar menu messages.
  641. // The window has to be created after opening the user's desktop
  642. // or the call to SetThreadDesktop() will if the thread has
  643. // any windows
  644. //
  645. IrmonControl->hWnd = CreateWindow(
  646. IrmonClassName,
  647. NULL,
  648. WS_OVERLAPPEDWINDOW,
  649. CW_USEDEFAULT,
  650. CW_USEDEFAULT,
  651. CW_USEDEFAULT,
  652. CW_USEDEFAULT,
  653. NULL,
  654. NULL,
  655. ghInstance,
  656. &GlobalIrmonControl
  657. );
  658. ShowWindow(IrmonControl->hWnd, SW_HIDE);
  659. UpdateWindow(IrmonControl->hWnd);
  660. WTSRegisterSessionNotification(IrmonControl->hWnd,NOTIFY_FOR_THIS_SESSION);
  661. ghCurrentUserKey = OpenCurrentUserKey();
  662. InitializeSound(
  663. ghCurrentUserKey,
  664. hIrmonEvents[EV_REG_CHANGE_EVENT]
  665. );
  666. ShowBalloonTip = TRUE;
  667. IrmonControl->DiscoveryObject=CreateIrDiscoveryObject(
  668. IrmonControl->hWnd,
  669. WM_IR_DEVICE_CHANGE,
  670. WM_IR_LINK_CHANGE
  671. );
  672. if (IrmonControl->DiscoveryObject == NULL) {
  673. #if DBG
  674. DbgPrint("IRMON-FTP: could not create ir discovery object\n");
  675. #endif
  676. return;
  677. }
  678. }
  679. VOID
  680. UserLogoffEvent(
  681. PIRMON_CONTROL IrmonControl
  682. )
  683. {
  684. DEBUGMSG(("IRMON-FTP: User logoff event\n"));
  685. UserLoggedIn = FALSE;
  686. if (IrmonControl->DiscoveryObject != NULL) {
  687. CloseIrDiscoveryObject(IrmonControl->DiscoveryObject);
  688. IrmonControl->DiscoveryObject = NULL;
  689. }
  690. UninitializeSound();
  691. if (ghCurrentUserKey)
  692. {
  693. RegCloseKey(ghCurrentUserKey);
  694. ghCurrentUserKey = 0;
  695. }
  696. if (IrmonControl->hWnd) {
  697. KillTimer(IrmonControl->hWnd, ConnAnimationTimerId);
  698. UpdateTray(&GlobalIrmonControl,ICON_ST_NOICON, 0, NULL, 0);
  699. DestroyWindow(IrmonControl->hWnd);
  700. IrmonControl->hWnd = 0;
  701. }
  702. }
  703. VOID
  704. SetSoundStatus(
  705. PVOID Context,
  706. BOOL SoundOn
  707. )
  708. {
  709. PIRMON_CONTROL IrmonControl=(PIRMON_CONTROL)Context;
  710. // DbgPrint("IRMON-FTP: sound %d\n",SoundOn);
  711. IrmonControl->SoundOn=SoundOn;
  712. return;
  713. }
  714. VOID
  715. SetTrayStatus(
  716. PVOID Context,
  717. BOOL lTrayEnabled
  718. )
  719. {
  720. PIRMON_CONTROL IrmonControl=(PIRMON_CONTROL)Context;
  721. if (lTrayEnabled)
  722. {
  723. DEBUGMSG(("IRMON-FTP: Tray enabled\n"));
  724. TrayEnabled = TRUE;
  725. }
  726. else
  727. {
  728. DEBUGMSG(("IRMON-FTP: Tray disabled\n"));
  729. TrayEnabled = FALSE;
  730. }
  731. SetEvent(hIrmonEvents[EV_TRAY_STATUS_EVENT]);
  732. }
  733. LONG_PTR FAR PASCAL
  734. WndProc(
  735. HWND hWnd,
  736. unsigned message,
  737. WPARAM wParam,
  738. LPARAM lParam)
  739. {
  740. PIRMON_CONTROL IrmonControl=(PIRMON_CONTROL)GetWindowLongPtr(hWnd,GWLP_USERDATA);
  741. switch (message)
  742. {
  743. case WM_CREATE: {
  744. LPCREATESTRUCT CreateStruct=(LPCREATESTRUCT)lParam;
  745. SetWindowLongPtr(hWnd,GWLP_USERDATA,(LONG_PTR)CreateStruct->lpCreateParams);
  746. return 0;
  747. }
  748. break;
  749. case WM_COMMAND:
  750. {
  751. switch (wParam)
  752. {
  753. case IDC_TX_FILES:
  754. ShowSendWindow();
  755. break;
  756. case IDC_PROPERTIES:
  757. DEBUGMSG(("IRMON-FTP: Launch Properties page\n"));
  758. ShowPropertiesPage();
  759. break;
  760. default:
  761. ;
  762. //DEBUGMSG(("Other WM_COMMAND %X\n", wParam));
  763. }
  764. break;
  765. }
  766. case SYSTRAYEVENTID:
  767. {
  768. POINT pt;
  769. HMENU hMenu, hMenuPopup;
  770. switch (lParam)
  771. {
  772. case WM_LBUTTONDOWN:
  773. ShowSendWindow();
  774. break;
  775. case WM_RBUTTONDOWN:
  776. SetForegroundWindow(hWnd);
  777. GetCursorPos(&pt);
  778. hMenu = LoadMenu(ghInstance, MAKEINTRESOURCE(IDR_TRAY_MENU));
  779. if (!hMenu)
  780. {
  781. DEBUGMSG(("IRMON-FTP: failed to load menu\n"));
  782. break;
  783. }
  784. hMenuPopup = GetSubMenu(hMenu, 0);
  785. SetMenuDefaultItem(hMenuPopup, 0, TRUE);
  786. TrackPopupMenuEx(hMenuPopup,
  787. TPM_LEFTALIGN | TPM_RIGHTBUTTON,
  788. pt.x, pt.y, hWnd, NULL);
  789. DestroyMenu(hMenu);
  790. break;
  791. //default:DEBUGMSG(("IRMON-FTP: Systray other %d\n", lParam));
  792. }
  793. break;
  794. }
  795. case WM_TIMER:
  796. if (wParam == ConnAnimationTimerId)
  797. {
  798. ConnAnimationTimerExp(IrmonControl);
  799. }
  800. else if (wParam == RetryTrayUpdateTimerId)
  801. {
  802. DEBUGMSG(("IRMON-FTP: RetryTrayUpdateTimer expired\n"));
  803. KillTimer(IrmonControl->hWnd, RetryTrayUpdateTimerId);
  804. RetryTrayUpdateTimerRunning = FALSE;
  805. DevListChangeOrUpdatedLinkStatus(IrmonControl);
  806. }
  807. break;
  808. case WM_QUERYENDSESSION:
  809. {
  810. extern BOOL IrxferHandlePowerMessage( HWND hWnd, unsigned message, WPARAM wParam, LPARAM lParam );
  811. return IrxferHandlePowerMessage( hWnd, message, wParam, lParam );
  812. break;
  813. }
  814. case WM_ENDSESSION:
  815. break;
  816. case WM_POWERBROADCAST:
  817. {
  818. extern BOOL IrxferHandlePowerMessage( HWND hWnd, unsigned message, WPARAM wParam, LPARAM lParam );
  819. return IrxferHandlePowerMessage( hWnd, message, wParam, lParam );
  820. break;
  821. }
  822. case WM_IR_DEVICE_CHANGE: {
  823. ULONG BufferSize=sizeof(FoundDevListBuf);
  824. GetDeviceList(
  825. IrmonControl->DiscoveryObject,
  826. pDeviceList,
  827. &BufferSize
  828. );
  829. DeviceListUpdated = TRUE;
  830. DEBUGMSG(("IRMON-FTP: %d IR device(s) found:\n", pDeviceList->DeviceCount));
  831. DevListChangeOrUpdatedLinkStatus(IrmonControl);
  832. }
  833. break;
  834. case WM_IR_LINK_CHANGE: {
  835. GetLinkStatus(
  836. IrmonControl->DiscoveryObject,
  837. &LinkStatus
  838. );
  839. DEBUGMSG(("IRMON-FTP: link state change %x\n",LinkStatus.Flags));
  840. DevListChangeOrUpdatedLinkStatus(IrmonControl);
  841. }
  842. break;
  843. case WM_WTSSESSION_CHANGE:
  844. DEBUGMSG(("IRMON-FTP: session change %d %d\n",wParam,lParam));
  845. if (wParam == WTS_CONSOLE_DISCONNECT) {
  846. if (GlobalIrmonControl.IrxferContext != NULL) {
  847. pDeviceList->DeviceCount=0;
  848. UpdateTray(&GlobalIrmonControl,ICON_ST_NOICON, 0, NULL, 0);
  849. // UpdateDiscoveredDevices(pDeviceList,IpDeviceList);
  850. Sleep(100);
  851. CloseDownUI();
  852. }
  853. // TerminateProcess(GetCurrentProcess(),0);
  854. }
  855. break;
  856. default:
  857. //DEBUGMSG(("Msg %X, wParam %d, lParam %d\n", message, wParam, lParam));
  858. return (DefWindowProc(hWnd, message, wParam, lParam));
  859. }
  860. return 0;
  861. }
  862. VOID
  863. ServiceMain(
  864. DWORD cArgs,
  865. LPWSTR *pArgs)
  866. {
  867. DWORD Error = NO_ERROR;
  868. DWORD Status;
  869. WNDCLASS Wc;
  870. MSG Msg;
  871. HKEY hKey;
  872. LONG rc;
  873. WSADATA WSAData;
  874. WORD WSAVerReq = MAKEWORD(2,0);
  875. char c;
  876. BOOL bResult;
  877. hIrmonEvents[EV_STOP_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL);
  878. hIrmonEvents[EV_REG_CHANGE_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL);
  879. hIrmonEvents[EV_TRAY_STATUS_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL);
  880. // Initialize all necessary globals to 0, FALSE, or NULL because
  881. // we might be restarting within the same services process
  882. pDeviceList->DeviceCount = 0;
  883. IconInTray = FALSE;
  884. IrmonStopped = FALSE;
  885. UserLoggedIn = FALSE;
  886. TrayEnabled = FALSE;
  887. DeviceListUpdated = FALSE;
  888. LastTrayUpdate = 0;
  889. // RetryLazyDscvTimerRunning = FALSE;
  890. RetryTrayUpdateTimerRunning = FALSE;
  891. hInRange = 0;
  892. RtlZeroMemory(&LinkStatus, sizeof(LinkStatus));
  893. ZeroMemory(&GlobalIrmonControl,sizeof(GlobalIrmonControl));
  894. try
  895. {
  896. InitializeCriticalSection(&GlobalIrmonControl.Lock);
  897. }
  898. except (STATUS_NO_MEMORY == GetExceptionCode())
  899. {
  900. DEBUGMSG(("IRMON-FTP: Failed to InitializeCriticalSection, Aborting.\n"));
  901. return;
  902. }
  903. if (WSAStartup(WSAVerReq, &WSAData) != 0)
  904. {
  905. DEBUGMSG(("IRMON-FTP: WSAStartup failed\n"));
  906. Error = 1;
  907. goto done;
  908. }
  909. Wc.style = CS_NOCLOSE;
  910. Wc.cbClsExtra = 0;
  911. Wc.cbWndExtra = 0;
  912. Wc.hInstance = ghInstance;
  913. Wc.hIcon = NULL;
  914. Wc.hCursor = NULL;
  915. Wc.hbrBackground = NULL;
  916. Wc.lpszMenuName = NULL;
  917. Wc.lpfnWndProc = WndProc;
  918. Wc.lpszClassName = IrmonClassName;
  919. if (!RegisterClass(&Wc))
  920. {
  921. DEBUGMSG(("IRMON-FTP: failed to register class\n"));
  922. }
  923. // Initialize OBEX and IrTran-P:
  924. //
  925. bResult=InitializeIrxfer(
  926. &GlobalIrmonControl,
  927. SetTrayStatus,
  928. SetSoundStatus,
  929. &GlobalIrmonControl.IrxferContext
  930. );
  931. if (bResult) {
  932. DEBUGMSG(("IRMON-FTP: Irxfer initialized\n"));
  933. } else {
  934. DEBUGMSG(("IRMON-FTP: Irxfer initializtion failed\n"));
  935. goto done;
  936. }
  937. IrmonStopped = FALSE;
  938. DEBUGMSG(("IRMON-FTP: Service running\n"));
  939. UserLogonEvent(&GlobalIrmonControl);
  940. while (!IrmonStopped)
  941. {
  942. Status = MsgWaitForMultipleObjectsEx(WAIT_EVENT_CNT, hIrmonEvents, INFINITE,
  943. QS_ALLINPUT | QS_ALLEVENTS | QS_ALLPOSTMESSAGE,
  944. MWMO_ALERTABLE);
  945. switch (Status)
  946. {
  947. case WAIT_OBJECT_0 + EV_STOP_EVENT:
  948. IrmonStopped = TRUE;
  949. break;
  950. case WAIT_OBJECT_0 + EV_REG_CHANGE_EVENT:
  951. if (UserLoggedIn)
  952. {
  953. GetRegSoundData(hIrmonEvents[EV_REG_CHANGE_EVENT]);
  954. }
  955. break;
  956. case WAIT_OBJECT_0 + EV_TRAY_STATUS_EVENT:
  957. if (TrayEnabled)
  958. {
  959. DevListChangeOrUpdatedLinkStatus(&GlobalIrmonControl);
  960. }
  961. else if (IconInTray)
  962. {
  963. UpdateTray(&GlobalIrmonControl,ICON_ST_NOICON, 0, NULL, 0);
  964. }
  965. break;
  966. case WAIT_IO_COMPLETION:
  967. break;
  968. default:
  969. while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
  970. {
  971. if (Msg.message == WM_QUIT)
  972. {
  973. IrmonStopped = TRUE;
  974. break;
  975. }
  976. if (!IsDialogMessage(GlobalIrmonControl.hWnd, &Msg))
  977. {
  978. TranslateMessage(&Msg);
  979. DispatchMessage(&Msg);
  980. }
  981. }
  982. }
  983. }
  984. if (UserLoggedIn) {
  985. UserLogoffEvent(&GlobalIrmonControl);
  986. }
  987. if (!UninitializeIrxfer(GlobalIrmonControl.IrxferContext)) {
  988. DEBUGMSG(("IRMON-FTP: Failed to unitialize irxfer!!\n"));
  989. IrmonStopped = FALSE;
  990. } else {
  991. DEBUGMSG(("IRMON-FTP: irxfer unitialized\n"));
  992. }
  993. UpdateTray(&GlobalIrmonControl,ICON_ST_NOICON, 0, NULL, 0);
  994. done:
  995. DeleteCriticalSection(&GlobalIrmonControl.Lock);
  996. DEBUGMSG(("IRMON-FTP: Service stopped\n"));
  997. }
  998. VOID
  999. SetInstance(
  1000. HINSTANCE hInst
  1001. )
  1002. {
  1003. ghInstance=hInst;
  1004. return;
  1005. }
  1006. VOID
  1007. SignalIrmonExit(
  1008. VOID
  1009. )
  1010. {
  1011. SetEvent(hIrmonEvents[EV_STOP_EVENT]);
  1012. }