/***************************************************************************** * * Copyright (C) Microsoft Corporation, 1995 - 1999 * * File: irmon.c * * Description: Infrared monitor * * Author: mbert/mikezin * * Date: 3/1/98 * */ #define UNICODE #include #include #include #include #include #include #include #include #include #include #include #include // allocate storage! and initialize the GUIDS #include #include #include #include #include #include #include #include "internal.h" #include #include #include #include "irdisc.h" #include #define WM_IP_DEVICE_CHANGE (WM_USER+500) #define WM_IR_DEVICE_CHANGE (WM_USER+501) #define WM_IR_LINK_CHANGE (WM_USER+502) #define IRXFER_DLL TEXT("irxfer.dll") #define IAS_LSAP_SEL "IrDA:TinyTP:LsapSel" #define IRXFER_CLASSNAME "OBEX:IrXfer" #define IRXFER_CLASSNAME2 "OBEX" #define IRMON_SERVICE_NAME TEXT("irmon") #define IRMON_CONFIG_KEY TEXT("System\\CurrentControlSet\\Services\\Irmon") #define IRMON_SHOW_ICON_KEY TEXT("ShowTrayIcon") #define IRMON_NO_SOUND_KEY TEXT("NoSound") #define TRANSFER_EXE TEXT("irxfer") #define PROPERTIES_EXE TEXT("irxfer /s") #define IRDA_DEVICE_NAME TEXT("\\Device\\IrDA") #define DEVICE_LIST_LEN 5 #define TOOL_TIP_STR_SIZE 64 #define EMPTY_STR TEXT("") #define SYSTRAYEVENTID WM_USER + 1 #define EV_STOP_EVENT 0 #define EV_REG_CHANGE_EVENT 1 #define EV_TRAY_STATUS_EVENT 2 #define WAIT_EVENT_CNT 3 #define MAX_ATTRIB_LEN 64 #define MAKE_LT_UPDATE(a,b) (a << 16) + b #define RETRY_DSCV_TIMER 1 #define RETRY_DSCV_INTERVAL 10000 // 10 seconds #define CONN_ANIMATION_TIMER 2 #define CONN_ANIMATION_INTERVAL 250 #define RETRY_TRAY_UPDATE_TIMER 3 #define RETRY_TRAY_UPDATE_INTERVAL 4000 // 4 seconds typedef enum { ICON_ST_NOICON, ICON_ST_CONN1 = 1, ICON_ST_CONN2, ICON_ST_CONN3, ICON_ST_CONN4, ICON_ST_IN_RANGE, ICON_ST_IP_IN_RANGE, ICON_ST_INTR } ICON_STATE; typedef struct _IRMON_CONTROL { CRITICAL_SECTION Lock; PVOID IrxferContext; HWND hWnd; WSAOVERLAPPED Overlapped; HANDLE DiscoveryObject; BOOL SoundOn; } IRMON_CONTROL, *PIRMON_CONTROL; IRMON_CONTROL GlobalIrmonControl; HANDLE hIrmonEvents[WAIT_EVENT_CNT]; BYTE FoundDevListBuf[ sizeof(OBEX_DEVICE_LIST) + sizeof(OBEX_DEVICE)*MAX_OBEX_DEVICES]; OBEX_DEVICE_LIST * const pDeviceList=(POBEX_DEVICE_LIST)FoundDevListBuf; TCHAR IrmonClassName[] = TEXT("IrmonClass"); BOOLEAN IconInTray; BOOLEAN IrmonStopped; HICON hInRange; HICON hIpInRange; HICON hInterrupt; HICON hConn1; HICON hConn2; HICON hConn3; HICON hConn4; IRLINK_STATUS LinkStatus; HINSTANCE ghInstance; BOOLEAN UserLoggedIn; BOOLEAN TrayEnabled; BOOLEAN DeviceListUpdated; UINT LastTrayUpdate; // debug purposes UINT_PTR RetryTrayUpdateTimerId; BOOLEAN RetryTrayUpdateTimerRunning; int TrayUpdateFailures; UINT_PTR ConnAnimationTimerId; TCHAR ConnDevName[64]; UINT ConnIcon; int ConnAddition; BOOLEAN InterruptedSoundPlaying; HKEY ghCurrentUserKey = 0; BOOLEAN ShowBalloonTip; BOOLEAN IrxferDeviceInRange; HMODULE hIrxfer; extern BOOL ShowSendWindow(); extern BOOL ShowPropertiesPage(); extern void UpdateDiscoveredDevices( const OBEX_DEVICE_LIST *IrDevices ); VOID InitiateLazyDscv( PIRMON_CONTROL IrmonControl ); VOID InitiateLinkStatusQuery( PIRMON_CONTROL IrmonControl ); #if DBG TCHAR * GetLastErrorText() { switch (WSAGetLastError()) { case WSAEINTR: return (TEXT("WSAEINTR")); break; case WSAEBADF: return(TEXT("WSAEBADF")); break; case WSAEACCES: return(TEXT("WSAEACCES")); break; case WSAEFAULT: return(TEXT("WSAEFAULT")); break; case WSAEINVAL: return(TEXT("WSAEINVAL")); break; case WSAEMFILE: return(TEXT("WSAEMFILE")); break; case WSAEWOULDBLOCK: return(TEXT("WSAEWOULDBLOCK")); break; case WSAEINPROGRESS: return(TEXT("WSAEINPROGRESS")); break; case WSAEALREADY: return(TEXT("WSAEALREADY")); break; case WSAENOTSOCK: return(TEXT("WSAENOTSOCK")); break; case WSAEDESTADDRREQ: return(TEXT("WSAEDESTADDRREQ")); break; case WSAEMSGSIZE: return(TEXT("WSAEMSGSIZE")); break; case WSAEPROTOTYPE: return(TEXT("WSAEPROTOTYPE")); break; case WSAENOPROTOOPT: return(TEXT("WSAENOPROTOOPT")); break; case WSAEPROTONOSUPPORT: return(TEXT("WSAEPROTONOSUPPORT")); break; case WSAESOCKTNOSUPPORT: return(TEXT("WSAESOCKTNOSUPPORT")); break; case WSAEOPNOTSUPP: return(TEXT("WSAEOPNOTSUPP")); break; case WSAEPFNOSUPPORT: return(TEXT("WSAEPFNOSUPPORT")); break; case WSAEAFNOSUPPORT: return(TEXT("WSAEAFNOSUPPORT")); break; case WSAEADDRINUSE: return(TEXT("WSAEADDRINUSE")); break; case WSAEADDRNOTAVAIL: return(TEXT("WSAEADDRNOTAVAIL")); break; case WSAENETDOWN: return(TEXT("WSAENETDOWN")); break; case WSAENETUNREACH: return(TEXT("WSAENETUNREACH")); break; case WSAENETRESET: return(TEXT("WSAENETRESET")); break; case WSAECONNABORTED: return(TEXT("WSAECONNABORTED")); break; case WSAECONNRESET: return(TEXT("WSAECONNRESET")); break; case WSAENOBUFS: return(TEXT("WSAENOBUFS")); break; case WSAEISCONN: return(TEXT("WSAEISCONN")); break; case WSAENOTCONN: return(TEXT("WSAENOTCONN")); break; case WSAESHUTDOWN: return(TEXT("WSAESHUTDOWN")); break; case WSAETOOMANYREFS: return(TEXT("WSAETOOMANYREFS")); break; case WSAETIMEDOUT: return(TEXT("WSAETIMEDOUT")); break; case WSAECONNREFUSED: return(TEXT("WSAECONNREFUSED")); break; case WSAELOOP: return(TEXT("WSAELOOP")); break; case WSAENAMETOOLONG: return(TEXT("WSAENAMETOOLONG")); break; case WSAEHOSTDOWN: return(TEXT("WSAEHOSTDOWN")); break; case WSAEHOSTUNREACH: return(TEXT("WSAEHOSTUNREACH")); break; case WSAENOTEMPTY: return(TEXT("WSAENOTEMPTY")); break; case WSAEPROCLIM: return(TEXT("WSAEPROCLIM")); break; case WSAEUSERS: return(TEXT("WSAEUSERS")); break; case WSAEDQUOT: return(TEXT("WSAEDQUOT")); break; case WSAESTALE: return(TEXT("WSAESTALE")); break; case WSAEREMOTE: return(TEXT("WSAEREMOTE")); break; case WSAEDISCON: return(TEXT("WSAEDISCON")); break; case WSASYSNOTREADY: return(TEXT("WSASYSNOTREADY")); break; case WSAVERNOTSUPPORTED: return(TEXT("WSAVERNOTSUPPORTED")); break; case WSANOTINITIALISED: return(TEXT("WSANOTINITIALISED")); break; /* case WSAHOST: return(TEXT("WSAHOST")); break; case WSATRY: return(TEXT("WSATRY")); break; case WSANO: return(TEXT("WSANO")); break; */ default: return(TEXT("Unknown Error")); } } #endif HKEY OpenCurrentUserKey() { HKEY hUserKey; // // Open all our keys. If we can't open the user's key // or the key to watch for changes, we bail. // if (RegOpenKeyEx(HKEY_CURRENT_USER, NULL, 0, KEY_READ, &hUserKey)) { DEBUGMSG(("IRMON-FTP: RegOpenKey1 failed %d\n", GetLastError())); return 0; } return hUserKey; } VOID LoadTrayIconImages() { hInRange = LoadImage(ghInstance, MAKEINTRESOURCE(IDI_IN_RANGE), IMAGE_ICON, 16,16,0); hInterrupt= LoadImage(ghInstance, MAKEINTRESOURCE(IDI_INTR), IMAGE_ICON, 16,16,0); hConn1 = LoadImage(ghInstance, MAKEINTRESOURCE(IDI_CONN1), IMAGE_ICON, 16,16,0); hConn2 = LoadImage(ghInstance, MAKEINTRESOURCE(IDI_CONN2), IMAGE_ICON, 16,16,0); hConn3 = LoadImage(ghInstance, MAKEINTRESOURCE(IDI_CONN3), IMAGE_ICON, 16,16,0); hConn4 = LoadImage(ghInstance, MAKEINTRESOURCE(IDI_CONN4), IMAGE_ICON, 16,16,0); hIpInRange= LoadImage(ghInstance, MAKEINTRESOURCE(IDI_IP), IMAGE_ICON, 16,16,0); } VOID UpdateTray( PIRMON_CONTROL IrmonControl, ICON_STATE IconState, DWORD MsgId, LPTSTR DeviceName, UINT Baud ) { NOTIFYICONDATA NotifyIconData; DWORD Cnt; TCHAR FormatStr[256]; BOOL Result = TRUE; BOOLEAN TrayUpdateFailed = FALSE; if (!TrayEnabled && IconState != ICON_ST_NOICON) { return; } if (!hInRange) { LoadTrayIconImages(); } NotifyIconData.cbSize = sizeof(NOTIFYICONDATA); NotifyIconData.uID = 0; NotifyIconData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_INFO; NotifyIconData.uCallbackMessage = SYSTRAYEVENTID; NotifyIconData.hWnd = IrmonControl->hWnd; NotifyIconData.hIcon = 0; NotifyIconData.szInfo[0] = 0; NotifyIconData.szInfoTitle[0] = 0; if (MsgId == 0) { NotifyIconData.szTip[0] = L'\0'; } else { if (LoadString(ghInstance, MsgId, FormatStr, sizeof(FormatStr)/sizeof(TCHAR))) { StringCbPrintf(NotifyIconData.szTip, sizeof(NotifyIconData.szTip), FormatStr, DeviceName, Baud); } } if (IrmonStopped && IconState != ICON_ST_NOICON) return; switch (IconState) { case ICON_ST_NOICON: ShowBalloonTip = TRUE; if (IconInTray) { NotifyIconData.uFlags = 0; IconInTray = FALSE; if (Shell_NotifyIcon(NIM_DELETE, &NotifyIconData)) { LastTrayUpdate = MAKE_LT_UPDATE(NIM_DELETE,ICON_ST_NOICON); if (IrmonControl->SoundOn) { PlayIrSound(OUTOFRANGE_SOUND); } } else { DEBUGMSG(("IRMON-FTP: Shell_NotifyIcon(Delete) failed %d, %d\n", TrayUpdateFailures, GetLastError())); } } return; case ICON_ST_IN_RANGE: case ICON_ST_IP_IN_RANGE: if (IconState == ICON_ST_IP_IN_RANGE) { NotifyIconData.hIcon = hIpInRange; } else { NotifyIconData.hIcon = hInRange; } if (ShowBalloonTip) { ShowBalloonTip = FALSE; if (IrxferDeviceInRange && LoadString(ghInstance, IDS_BALLOON_TITLE, NotifyIconData.szInfoTitle, sizeof(NotifyIconData.szInfoTitle)/sizeof(TCHAR))) { NotifyIconData.uFlags |= NIF_INFO; NotifyIconData.uTimeout = 10000; // in milliseconds // NotifyIconData.dwInfoFlags = NIIF_INFO; if (DeviceName) { LoadString(ghInstance, IDS_BALLOON_TXT, FormatStr, sizeof(FormatStr)/sizeof(TCHAR)); StringCbPrintf(NotifyIconData.szInfo, sizeof(NotifyIconData.szInfo), FormatStr, DeviceName); } else { LoadString(ghInstance, IDS_BALLOON_TXT2, NotifyIconData.szInfo, sizeof(NotifyIconData.szInfo)/sizeof(TCHAR)); } } } break; case ICON_ST_CONN1: NotifyIconData.hIcon = hConn1; break; case ICON_ST_CONN2: NotifyIconData.hIcon = hConn2; break; case ICON_ST_CONN3: NotifyIconData.hIcon = hConn3; break; case ICON_ST_CONN4: NotifyIconData.hIcon = hConn4; break; case ICON_ST_INTR: NotifyIconData.hIcon = hInterrupt; if (LoadString(ghInstance, IDS_BLOCKED_TITLE, NotifyIconData.szInfoTitle, sizeof(NotifyIconData.szInfoTitle)/sizeof(TCHAR)) && LoadString(ghInstance, IDS_BLOCKED_TXT, NotifyIconData.szInfo, sizeof(NotifyIconData.szInfo)/sizeof(TCHAR))) { NotifyIconData.uFlags |= NIF_INFO; NotifyIconData.uTimeout = 10000; // in milliseconds NotifyIconData.dwInfoFlags = NIIF_WARNING; } break; } if (IconState == ICON_ST_INTR) { if (IrmonControl->SoundOn) { PlayIrSound(INTERRUPTED_SOUND); InterruptedSoundPlaying = TRUE; } } else { if (InterruptedSoundPlaying) { InterruptedSoundPlaying = FALSE; PlayIrSound(END_INTERRUPTED_SOUND); } } if (!IconInTray) { if (Shell_NotifyIcon(NIM_ADD, &NotifyIconData)) { LastTrayUpdate = MAKE_LT_UPDATE(NIM_ADD, IconState); if (IrmonControl->SoundOn) { PlayIrSound(INRANGE_SOUND); } IconInTray = TRUE; } else { TrayUpdateFailures++; DEBUGMSG(("IRMON-FTP: Shell_NotifyIcon(ADD) failed %d, %d\n", TrayUpdateFailures, GetLastError())); NotifyIconData.uFlags = 0; NotifyIconData.cbSize = sizeof(NOTIFYICONDATA); NotifyIconData.uID = 0; NotifyIconData.uCallbackMessage = SYSTRAYEVENTID; NotifyIconData.hWnd = IrmonControl->hWnd; NotifyIconData.hIcon = 0; NotifyIconData.szInfo[0] = 0; NotifyIconData.szInfoTitle[0] = 0; Shell_NotifyIcon(NIM_DELETE, &NotifyIconData); TrayUpdateFailed = TRUE; ShowBalloonTip = TRUE; } } else { if (!Shell_NotifyIcon(NIM_MODIFY, &NotifyIconData)) { TrayUpdateFailures++; DEBUGMSG(("IRMON-FTP: Shell_NotifyIcon(Modify) failed %d, %d\n", TrayUpdateFailures, GetLastError())); TrayUpdateFailed = TRUE; } else { LastTrayUpdate = MAKE_LT_UPDATE(NIM_MODIFY, IconState); } } if (TrayUpdateFailed && !RetryTrayUpdateTimerRunning) { RetryTrayUpdateTimerId = SetTimer(IrmonControl->hWnd, RETRY_TRAY_UPDATE_TIMER, RETRY_TRAY_UPDATE_INTERVAL, NULL); RetryTrayUpdateTimerRunning = TRUE; } } VOID ConnAnimationTimerExp( PIRMON_CONTROL IrmonControl ) { UpdateTray( IrmonControl,ConnIcon, IDS_CONNECTED_TO, ConnDevName, LinkStatus.ConnectSpeed ); ConnIcon += ConnAddition; if (ConnIcon == 4) { ConnAddition = -1; } else if (ConnIcon == 1) { ConnAddition = 1; } } VOID IsIrxferDeviceInRange() { int i, LsapSel, Attempt, Status; IrxferDeviceInRange = FALSE; for (i = 0; i < (int)pDeviceList->DeviceCount; i++) { if (pDeviceList->DeviceList[i].DeviceSpecific.s.Irda.ObexSupport) { IrxferDeviceInRange = TRUE; break; } } return; } VOID DevListChangeOrUpdatedLinkStatus( PIRMON_CONTROL IrmonControl ) { if (!UserLoggedIn) { DEBUGMSG(("IRMON-FTP: User not logged in, ignoring device change\n")); return; } if (DeviceListUpdated) { IsIrxferDeviceInRange(); } if (LinkStatus.Flags & LF_INTERRUPTED) { KillTimer(IrmonControl->hWnd, ConnAnimationTimerId); UpdateTray(IrmonControl,ICON_ST_INTR, IDS_INTERRUPTED, NULL, 0); } else if ((LinkStatus.Flags & LF_CONNECTED) && (pDeviceList->DeviceCount > 0)) { ULONG i; ConnDevName[0] = 0; ConnIcon = 1; ConnAddition = 1; for (i = 0; i < pDeviceList->DeviceCount; i++) { if (memcmp(&pDeviceList->DeviceList[i].DeviceSpecific.s.Irda.DeviceId, LinkStatus.ConnectedDeviceId, 4) == 0) { // // the name is in unicode // ZeroMemory(ConnDevName,sizeof(ConnDevName)); StringCbCopy(ConnDevName, sizeof(ConnDevName), pDeviceList->DeviceList[i].DeviceName); break; } } ConnAnimationTimerExp(IrmonControl); ConnAnimationTimerId = SetTimer(IrmonControl->hWnd, CONN_ANIMATION_TIMER, CONN_ANIMATION_INTERVAL, NULL); } else { KillTimer(IrmonControl->hWnd, ConnAnimationTimerId); if ((pDeviceList->DeviceCount == 0)) { // // no devices in range // UpdateTray(IrmonControl,ICON_ST_NOICON, 0, NULL, 0); } else { // // atleast one device in range // if ((pDeviceList->DeviceCount == 1) ) { // // one ir device in range // StringCbCopy(ConnDevName, sizeof(ConnDevName), pDeviceList->DeviceList[0].DeviceName ); UpdateTray(IrmonControl,ICON_ST_IN_RANGE, IDS_IN_RANGE, ConnDevName, 0); } else { // // more than one device total // UpdateTray(IrmonControl,ICON_ST_IN_RANGE, IDS_DEVS_IN_RANGE, NULL, 0); } } } if (DeviceListUpdated) { HANDLE hThread; DWORD ThreadId; DeviceListUpdated = FALSE; // PnP Printers, Notify transfer app if (GlobalIrmonControl.IrxferContext != NULL) { UpdateDiscoveredDevices(pDeviceList); } } } VOID UserLogonEvent( PIRMON_CONTROL IrmonControl ) { UINT DevListLen; NTSTATUS Status; OBJECT_ATTRIBUTES ObjAttr; UNICODE_STRING DeviceName; IO_STATUS_BLOCK IoStatusBlock; UserLoggedIn = TRUE; // // Create the window that will receive the taskbar menu messages. // The window has to be created after opening the user's desktop // or the call to SetThreadDesktop() will if the thread has // any windows // IrmonControl->hWnd = CreateWindow( IrmonClassName, NULL, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, ghInstance, &GlobalIrmonControl ); ShowWindow(IrmonControl->hWnd, SW_HIDE); UpdateWindow(IrmonControl->hWnd); WTSRegisterSessionNotification(IrmonControl->hWnd,NOTIFY_FOR_THIS_SESSION); ghCurrentUserKey = OpenCurrentUserKey(); InitializeSound( ghCurrentUserKey, hIrmonEvents[EV_REG_CHANGE_EVENT] ); ShowBalloonTip = TRUE; IrmonControl->DiscoveryObject=CreateIrDiscoveryObject( IrmonControl->hWnd, WM_IR_DEVICE_CHANGE, WM_IR_LINK_CHANGE ); if (IrmonControl->DiscoveryObject == NULL) { #if DBG DbgPrint("IRMON-FTP: could not create ir discovery object\n"); #endif return; } } VOID UserLogoffEvent( PIRMON_CONTROL IrmonControl ) { DEBUGMSG(("IRMON-FTP: User logoff event\n")); UserLoggedIn = FALSE; if (IrmonControl->DiscoveryObject != NULL) { CloseIrDiscoveryObject(IrmonControl->DiscoveryObject); IrmonControl->DiscoveryObject = NULL; } UninitializeSound(); if (ghCurrentUserKey) { RegCloseKey(ghCurrentUserKey); ghCurrentUserKey = 0; } if (IrmonControl->hWnd) { KillTimer(IrmonControl->hWnd, ConnAnimationTimerId); UpdateTray(&GlobalIrmonControl,ICON_ST_NOICON, 0, NULL, 0); DestroyWindow(IrmonControl->hWnd); IrmonControl->hWnd = 0; } } VOID SetSoundStatus( PVOID Context, BOOL SoundOn ) { PIRMON_CONTROL IrmonControl=(PIRMON_CONTROL)Context; // DbgPrint("IRMON-FTP: sound %d\n",SoundOn); IrmonControl->SoundOn=SoundOn; return; } VOID SetTrayStatus( PVOID Context, BOOL lTrayEnabled ) { PIRMON_CONTROL IrmonControl=(PIRMON_CONTROL)Context; if (lTrayEnabled) { DEBUGMSG(("IRMON-FTP: Tray enabled\n")); TrayEnabled = TRUE; } else { DEBUGMSG(("IRMON-FTP: Tray disabled\n")); TrayEnabled = FALSE; } SetEvent(hIrmonEvents[EV_TRAY_STATUS_EVENT]); } LONG_PTR FAR PASCAL WndProc( HWND hWnd, unsigned message, WPARAM wParam, LPARAM lParam) { PIRMON_CONTROL IrmonControl=(PIRMON_CONTROL)GetWindowLongPtr(hWnd,GWLP_USERDATA); switch (message) { case WM_CREATE: { LPCREATESTRUCT CreateStruct=(LPCREATESTRUCT)lParam; SetWindowLongPtr(hWnd,GWLP_USERDATA,(LONG_PTR)CreateStruct->lpCreateParams); return 0; } break; case WM_COMMAND: { switch (wParam) { case IDC_TX_FILES: ShowSendWindow(); break; case IDC_PROPERTIES: DEBUGMSG(("IRMON-FTP: Launch Properties page\n")); ShowPropertiesPage(); break; default: ; //DEBUGMSG(("Other WM_COMMAND %X\n", wParam)); } break; } case SYSTRAYEVENTID: { POINT pt; HMENU hMenu, hMenuPopup; switch (lParam) { case WM_LBUTTONDOWN: ShowSendWindow(); break; case WM_RBUTTONDOWN: SetForegroundWindow(hWnd); GetCursorPos(&pt); hMenu = LoadMenu(ghInstance, MAKEINTRESOURCE(IDR_TRAY_MENU)); if (!hMenu) { DEBUGMSG(("IRMON-FTP: failed to load menu\n")); break; } hMenuPopup = GetSubMenu(hMenu, 0); SetMenuDefaultItem(hMenuPopup, 0, TRUE); TrackPopupMenuEx(hMenuPopup, TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, hWnd, NULL); DestroyMenu(hMenu); break; //default:DEBUGMSG(("IRMON-FTP: Systray other %d\n", lParam)); } break; } case WM_TIMER: if (wParam == ConnAnimationTimerId) { ConnAnimationTimerExp(IrmonControl); } else if (wParam == RetryTrayUpdateTimerId) { DEBUGMSG(("IRMON-FTP: RetryTrayUpdateTimer expired\n")); KillTimer(IrmonControl->hWnd, RetryTrayUpdateTimerId); RetryTrayUpdateTimerRunning = FALSE; DevListChangeOrUpdatedLinkStatus(IrmonControl); } break; case WM_QUERYENDSESSION: { extern BOOL IrxferHandlePowerMessage( HWND hWnd, unsigned message, WPARAM wParam, LPARAM lParam ); return IrxferHandlePowerMessage( hWnd, message, wParam, lParam ); break; } case WM_ENDSESSION: break; case WM_POWERBROADCAST: { extern BOOL IrxferHandlePowerMessage( HWND hWnd, unsigned message, WPARAM wParam, LPARAM lParam ); return IrxferHandlePowerMessage( hWnd, message, wParam, lParam ); break; } case WM_IR_DEVICE_CHANGE: { ULONG BufferSize=sizeof(FoundDevListBuf); GetDeviceList( IrmonControl->DiscoveryObject, pDeviceList, &BufferSize ); DeviceListUpdated = TRUE; DEBUGMSG(("IRMON-FTP: %d IR device(s) found:\n", pDeviceList->DeviceCount)); DevListChangeOrUpdatedLinkStatus(IrmonControl); } break; case WM_IR_LINK_CHANGE: { GetLinkStatus( IrmonControl->DiscoveryObject, &LinkStatus ); DEBUGMSG(("IRMON-FTP: link state change %x\n",LinkStatus.Flags)); DevListChangeOrUpdatedLinkStatus(IrmonControl); } break; case WM_WTSSESSION_CHANGE: DEBUGMSG(("IRMON-FTP: session change %d %d\n",wParam,lParam)); if (wParam == WTS_CONSOLE_DISCONNECT) { if (GlobalIrmonControl.IrxferContext != NULL) { pDeviceList->DeviceCount=0; UpdateTray(&GlobalIrmonControl,ICON_ST_NOICON, 0, NULL, 0); // UpdateDiscoveredDevices(pDeviceList,IpDeviceList); Sleep(100); CloseDownUI(); } // TerminateProcess(GetCurrentProcess(),0); } break; default: //DEBUGMSG(("Msg %X, wParam %d, lParam %d\n", message, wParam, lParam)); return (DefWindowProc(hWnd, message, wParam, lParam)); } return 0; } VOID ServiceMain( DWORD cArgs, LPWSTR *pArgs) { DWORD Error = NO_ERROR; DWORD Status; WNDCLASS Wc; MSG Msg; HKEY hKey; LONG rc; WSADATA WSAData; WORD WSAVerReq = MAKEWORD(2,0); char c; BOOL bResult; hIrmonEvents[EV_STOP_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL); hIrmonEvents[EV_REG_CHANGE_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL); hIrmonEvents[EV_TRAY_STATUS_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL); // Initialize all necessary globals to 0, FALSE, or NULL because // we might be restarting within the same services process pDeviceList->DeviceCount = 0; IconInTray = FALSE; IrmonStopped = FALSE; UserLoggedIn = FALSE; TrayEnabled = FALSE; DeviceListUpdated = FALSE; LastTrayUpdate = 0; // RetryLazyDscvTimerRunning = FALSE; RetryTrayUpdateTimerRunning = FALSE; hInRange = 0; RtlZeroMemory(&LinkStatus, sizeof(LinkStatus)); ZeroMemory(&GlobalIrmonControl,sizeof(GlobalIrmonControl)); try { InitializeCriticalSection(&GlobalIrmonControl.Lock); } except (STATUS_NO_MEMORY == GetExceptionCode()) { DEBUGMSG(("IRMON-FTP: Failed to InitializeCriticalSection, Aborting.\n")); return; } if (WSAStartup(WSAVerReq, &WSAData) != 0) { DEBUGMSG(("IRMON-FTP: WSAStartup failed\n")); Error = 1; goto done; } Wc.style = CS_NOCLOSE; Wc.cbClsExtra = 0; Wc.cbWndExtra = 0; Wc.hInstance = ghInstance; Wc.hIcon = NULL; Wc.hCursor = NULL; Wc.hbrBackground = NULL; Wc.lpszMenuName = NULL; Wc.lpfnWndProc = WndProc; Wc.lpszClassName = IrmonClassName; if (!RegisterClass(&Wc)) { DEBUGMSG(("IRMON-FTP: failed to register class\n")); } // Initialize OBEX and IrTran-P: // bResult=InitializeIrxfer( &GlobalIrmonControl, SetTrayStatus, SetSoundStatus, &GlobalIrmonControl.IrxferContext ); if (bResult) { DEBUGMSG(("IRMON-FTP: Irxfer initialized\n")); } else { DEBUGMSG(("IRMON-FTP: Irxfer initializtion failed\n")); goto done; } IrmonStopped = FALSE; DEBUGMSG(("IRMON-FTP: Service running\n")); UserLogonEvent(&GlobalIrmonControl); while (!IrmonStopped) { Status = MsgWaitForMultipleObjectsEx(WAIT_EVENT_CNT, hIrmonEvents, INFINITE, QS_ALLINPUT | QS_ALLEVENTS | QS_ALLPOSTMESSAGE, MWMO_ALERTABLE); switch (Status) { case WAIT_OBJECT_0 + EV_STOP_EVENT: IrmonStopped = TRUE; break; case WAIT_OBJECT_0 + EV_REG_CHANGE_EVENT: if (UserLoggedIn) { GetRegSoundData(hIrmonEvents[EV_REG_CHANGE_EVENT]); } break; case WAIT_OBJECT_0 + EV_TRAY_STATUS_EVENT: if (TrayEnabled) { DevListChangeOrUpdatedLinkStatus(&GlobalIrmonControl); } else if (IconInTray) { UpdateTray(&GlobalIrmonControl,ICON_ST_NOICON, 0, NULL, 0); } break; case WAIT_IO_COMPLETION: break; default: while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)) { if (Msg.message == WM_QUIT) { IrmonStopped = TRUE; break; } if (!IsDialogMessage(GlobalIrmonControl.hWnd, &Msg)) { TranslateMessage(&Msg); DispatchMessage(&Msg); } } } } if (UserLoggedIn) { UserLogoffEvent(&GlobalIrmonControl); } if (!UninitializeIrxfer(GlobalIrmonControl.IrxferContext)) { DEBUGMSG(("IRMON-FTP: Failed to unitialize irxfer!!\n")); IrmonStopped = FALSE; } else { DEBUGMSG(("IRMON-FTP: irxfer unitialized\n")); } UpdateTray(&GlobalIrmonControl,ICON_ST_NOICON, 0, NULL, 0); done: DeleteCriticalSection(&GlobalIrmonControl.Lock); DEBUGMSG(("IRMON-FTP: Service stopped\n")); } VOID SetInstance( HINSTANCE hInst ) { ghInstance=hInst; return; } VOID SignalIrmonExit( VOID ) { SetEvent(hIrmonEvents[EV_STOP_EVENT]); }