/***************************************************************************** * * 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 "internal.h" #include #include #include #include #include "irdisc.h" #define BUILD_SERVICE_EXE 1 #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 TASK_BAR_CREATED TEXT("TaskbarCreated") #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_LOGON_EVENT 1 #define EV_LOGOFF_EVENT 2 #define EV_REG_CHANGE_EVENT 3 #define EV_TRAY_STATUS_EVENT 4 #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 #define WAIT_EVENT_CNT 5 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_IDLE, ICON_ST_RX, ICON_ST_TX, ICON_ST_RXTX, */ ICON_ST_INTR } ICON_STATE; typedef struct _IRMON_CONTROL { CRITICAL_SECTION Lock; PVOID IrxferContext; #ifdef IP_OBEX HANDLE SsdpContext; #endif HWND hWnd; WSAOVERLAPPED Overlapped; HANDLE DiscoveryObject; BOOL SoundOn; } IRMON_CONTROL, *PIRMON_CONTROL; IRMON_CONTROL GlobalIrmonControl; extern WAVE_NUM_DEV_FN WaveNumDev; SERVICE_STATUS_HANDLE IrmonStatusHandle; SERVICE_STATUS IrmonServiceStatus; 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; BYTE FoundIpListBuffer[sizeof(OBEX_DEVICE_LIST) + sizeof(OBEX_DEVICE)*MAX_OBEX_DEVICES]; OBEX_DEVICE_LIST * const IpDeviceList=(POBEX_DEVICE_LIST)FoundIpListBuffer; LONG UpdatingIpAddressList=0; TCHAR IrmonClassName[] = TEXT("IrmonClass"); BOOLEAN IconInTray; BOOLEAN IrmonStopped; HICON hInRange; HICON hIpInRange; HICON hInterrupt; HICON hConn1; HICON hConn2; HICON hConn3; HICON hConn4; /* HICON hIdle; HICON hTx; HICON hRxTx; HICON hRx; */ IRLINK_STATUS LinkStatus; HINSTANCE ghInstance; BOOLEAN UserLoggedIn; BOOLEAN TrayEnabled; BOOLEAN DeviceListUpdated; //UINT gTaskbarCreated; UINT LastTrayUpdate; // debug purposes UINT_PTR RetryTrayUpdateTimerId; BOOLEAN RetryTrayUpdateTimerRunning; int TrayUpdateFailures; extern HANDLE g_UserToken; UINT_PTR ConnAnimationTimerId; TCHAR ConnDevName[64]; UINT ConnIcon; int ConnAddition; BOOLEAN InterruptedSoundPlaying; HKEY ghCurrentUserKey = 0; BOOLEAN ShowBalloonTip; BOOLEAN IrxferDeviceInRange; HMODULE hIrxfer; HWINSTA hWinStaUser = 0; HWINSTA hSaveWinSta = 0; HDESK hDeskUser = 0; HDESK hSaveDesk = 0; extern BOOL ShowSendWindow(); extern BOOL ShowPropertiesPage(); extern void UpdateDiscoveredDevices( const OBEX_DEVICE_LIST *IrDevices, const OBEX_DEVICE_LIST *IpDevices ); VOID InitiateLazyDscv( PIRMON_CONTROL IrmonControl ); VOID InitiateLinkStatusQuery( PIRMON_CONTROL IrmonControl ); VOID SetLogonStatus(BOOL LoggedOn); VOID MySetLogonStatus(BOOL LoggedOn); #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; DWORD SizeNeeded; TOKEN_USER *TokenData; WCHAR UnicodeBuffer[256]; UNICODE_STRING UnicodeString; NTSTATUS NtStatus; // Get current user token so we can access the sound data in the // user's hive if (!GetTokenInformation(g_UserToken, TokenUser, 0, 0, &SizeNeeded)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { TokenData = (TOKEN_USER *) _alloca( SizeNeeded ); } else { DEBUGMSG(("IRMON: GetTokenInformation failed %d\n", GetLastError())); return 0; } } else { DEBUGMSG(("IRMON: GetTokenInformation should have failed\n")); return 0; } if (!TokenData) { DEBUGMSG(("IRMON: alloc failed\n")); return 0; } if (!GetTokenInformation(g_UserToken, TokenUser, TokenData, SizeNeeded, &SizeNeeded)) { DEBUGMSG(("IRMON: GetTokenInformation failed %d\n", GetLastError())); return 0; } UnicodeString.Buffer = UnicodeBuffer; UnicodeString.Length = 0; UnicodeString.MaximumLength = sizeof(UnicodeBuffer); NtStatus = RtlConvertSidToUnicodeString(&UnicodeString, TokenData->User.Sid, FALSE); if (!NT_SUCCESS(NtStatus)) { DEBUGMSG(("IRMON: RtlConvertSidToUnicodeString failed %\n", GetLastError())); return 0; } UnicodeString.Buffer[UnicodeString.Length] = 0; // // 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_USERS, UnicodeString.Buffer, 0, KEY_READ, &hUserKey)) { DEBUGMSG(("IRMON: 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) { lstrcpy(NotifyIconData.szTip, EMPTY_STR); } else { if (LoadString(ghInstance, MsgId, FormatStr, sizeof(FormatStr)/sizeof(TCHAR))) { wsprintf(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: 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)); wsprintf(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_IDLE: NotifyIconData.hIcon = hIdle; break; case ICON_ST_RX: NotifyIconData.hIcon = hRx; break; case ICON_ST_TX: NotifyIconData.hIcon = hTx; break; case ICON_ST_RXTX: NotifyIconData.hIcon = hRxTx; 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: 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: 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 ) { /* if (ConnDevName[0] == 0) { UpdateTray(ICON_ST_CONN1, 0, NULL, 0); } else { */ 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; if (IpDeviceList->DeviceCount > 0) { IrxferDeviceInRange = TRUE; return; } 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: 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) { // ICON_STATE IconState = ICON_ST_IDLE; 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)); lstrcpy( 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) && (IpDeviceList->DeviceCount == 0)) { // // no devices in range // UpdateTray(IrmonControl,ICON_ST_NOICON, 0, NULL, 0); } else { // // atleast on device in range // if ((pDeviceList->DeviceCount == 1) && (IpDeviceList->DeviceCount == 0)) { // // one ir device in range // lstrcpy( ConnDevName, pDeviceList->DeviceList[0].DeviceName ); UpdateTray(IrmonControl,ICON_ST_IN_RANGE, IDS_IN_RANGE, ConnDevName, 0); } else { if ((pDeviceList->DeviceCount == 0) && (IpDeviceList->DeviceCount == 1)) { // // one ip device in range // lstrcpy( ConnDevName, IpDeviceList->DeviceList[0].DeviceName ); lstrcat(ConnDevName,TEXT("(IP)")); UpdateTray(IrmonControl,ICON_ST_IP_IN_RANGE, IDS_IN_RANGE, ConnDevName, 0); } else { // // more than one device total // if (pDeviceList->DeviceCount > IpDeviceList->DeviceCount) { UpdateTray(IrmonControl,ICON_ST_IN_RANGE, IDS_DEVS_IN_RANGE, NULL, 0); } else { UpdateTray(IrmonControl,ICON_ST_IP_IN_RANGE, IDS_DEVS_IN_RANGE, NULL, 0); } } } } } if (!UserLoggedIn) { // Check again because UpdateTray() may have changed logon status // because of premature notification from irxfer DEBUGMSG(("IRMON: User not logged in because UpdateTray must have logged us off\n")); return; } if (DeviceListUpdated) { HANDLE hThread; DWORD ThreadId; DeviceListUpdated = FALSE; // PnP Printers, Notify transfer app UpdateDiscoveredDevices(pDeviceList,IpDeviceList); } } VOID UserLogonEvent( PIRMON_CONTROL IrmonControl ) { UINT DevListLen; NTSTATUS Status; OBJECT_ATTRIBUTES ObjAttr; UNICODE_STRING DeviceName; IO_STATUS_BLOCK IoStatusBlock; // // save current desktop and window station // so that it can be restored when the user logs off. // hSaveWinSta = GetProcessWindowStation(); hSaveDesk = GetThreadDesktop(GetCurrentThreadId()); // // Open the current user's window station and desktop so // we can add an icon to the taskbar // hWinStaUser = OpenWindowStation(L"WinSta0", FALSE, MAXIMUM_ALLOWED); if (hWinStaUser == NULL) { DEBUGMSG(("IRMON: OpenWindowStation FAILED %d\n", GetLastError())); } else { if (!SetProcessWindowStation(hWinStaUser)) { DEBUGMSG(("IRMON: SetProcessWindowStation failed %d\n", GetLastError())); } else { DEBUGMSG(("IRMON: SetProcessWindowStation succeeded\n")); } } hDeskUser = OpenDesktop(L"Default", 0 , FALSE, MAXIMUM_ALLOWED); if (hDeskUser == NULL) { DEBUGMSG(("IRMON: OpenDesktop failed %d\n", GetLastError())); } else { if (!SetThreadDesktop(hDeskUser)) { DEBUGMSG(("IRMON: SetThreadDesktop failed %d\n", GetLastError())); } else { DEBUGMSG(("IRMON: SetThreadDesktop succeeded %d\n")); } } // // 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); 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) { DbgPrint("irmon: could not create ir discovery object\n"); return; } } VOID UserLogoffEvent( PIRMON_CONTROL IrmonControl ) { DEBUGMSG(("IRMON: User logoff event\n")); UserLoggedIn = FALSE; IconInTray = FALSE; KillTimer(IrmonControl->hWnd, ConnAnimationTimerId); if (IrmonControl->DiscoveryObject != NULL) { CloseIrDiscoveryObject(IrmonControl->DiscoveryObject); IrmonControl->DiscoveryObject = NULL; } UninitializeSound(); if (ghCurrentUserKey) { RegCloseKey(ghCurrentUserKey); ghCurrentUserKey = 0; } if (hSaveDesk) { SetThreadDesktop(hSaveDesk); if (hSaveWinSta) { SetProcessWindowStation(hSaveWinSta); } CloseDesktop(hSaveDesk); hSaveDesk = 0; if (hSaveWinSta) { CloseWindowStation(hSaveWinSta); hSaveWinSta = 0; } } if (hDeskUser) { CloseDesktop(hDeskUser); hDeskUser = 0; } if (hWinStaUser) { CloseWindowStation(hWinStaUser); hWinStaUser = 0; } if (IrmonControl->hWnd) { if (IconInTray) { UpdateTray(&GlobalIrmonControl,ICON_ST_NOICON, 0, NULL, 0); } DestroyWindow(IrmonControl->hWnd); IrmonControl->hWnd = 0; } } VOID SetLogonStatus(BOOL LoggedOn) { MySetLogonStatus(LoggedOn); } VOID MySetLogonStatus(BOOL LoggedOn) { if (LoggedOn) { if (UserLoggedIn) { DEBUGMSG(("IRMON: SetLogonStatus(TRUE) && UserLoggedIn==TRUE (OK)\n")); return; } else { DEBUGMSG(("IRMON: User logged in\n")); UserLoggedIn = TRUE; SetEvent(hIrmonEvents[EV_LOGON_EVENT]); } } else { SetEvent(hIrmonEvents[EV_LOGOFF_EVENT]); } } VOID SetSoundStatus( PVOID Context, BOOL SoundOn ) { PIRMON_CONTROL IrmonControl=(PIRMON_CONTROL)Context; // DbgPrint("Irmon: sound %d\n",SoundOn); IrmonControl->SoundOn=SoundOn; return; } VOID SetTrayStatus( PVOID Context, BOOL lTrayEnabled ) { PIRMON_CONTROL IrmonControl=(PIRMON_CONTROL)Context; if (lTrayEnabled) { DEBUGMSG(("IRMON: Tray enabled\n")); TrayEnabled = TRUE; } else { DEBUGMSG(("IRMON: 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: 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: 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: Systray other %d\n", lParam)); } break; } case WM_TIMER: if (wParam == ConnAnimationTimerId) { ConnAnimationTimerExp(IrmonControl); } else if (wParam == RetryTrayUpdateTimerId) { DEBUGMSG(("IRMON: 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_IP_DEVICE_CHANGE: { ULONG BufferSize=sizeof(FoundIpListBuffer); ULONG i; LONG lResult; LONG Count; EnterCriticalSection(&IrmonControl->Lock); Count=InterlockedIncrement(&UpdatingIpAddressList); if (Count > 1) { // // re-eneter, just skip // DbgPrint("irmon: re-entered device notify message %d\n",Count); } else { // // first one in, up date the list // #ifdef IP_OBEX if (IrmonControl->SsdpContext != NULL) { lResult=GetSsdpDevices( IrmonControl->SsdpContext, IpDeviceList, &BufferSize ); if (lResult == ERROR_SUCCESS) { for (i=0; iDeviceCount; i++) { DbgPrint( "IRMON: ip device %ws, addr=%08lx, port=%d\n",\ IpDeviceList->DeviceList[i].DeviceName, IpDeviceList->DeviceList[i].DeviceSpecific.s.Ip.IpAddress, IpDeviceList->DeviceList[i].DeviceSpecific.s.Ip.Port ); } DeviceListUpdated = TRUE; DevListChangeOrUpdatedLinkStatus(IrmonControl); } else { DbgPrint("IRMON: GetSsdpDevices() failed\n"); } } else { DbgPrint("irmon: ssdp context == null\n"); } #endif //IP_OBEX } InterlockedDecrement(&UpdatingIpAddressList); LeaveCriticalSection(&IrmonControl->Lock); break; } case WM_IR_DEVICE_CHANGE: { ULONG BufferSize=sizeof(FoundDevListBuf); GetDeviceList( IrmonControl->DiscoveryObject, pDeviceList, &BufferSize ); DeviceListUpdated = TRUE; DEBUGMSG(("IRMON: %d IR device(s) found:\n", pDeviceList->DeviceCount)); DevListChangeOrUpdatedLinkStatus(IrmonControl); } break; case WM_IR_LINK_CHANGE: { GetLinkStatus( IrmonControl->DiscoveryObject, &LinkStatus ); DEBUGMSG(("IRMON: link state change\n")); DevListChangeOrUpdatedLinkStatus(IrmonControl); } break; default: #if 0 if (message == gTaskbarCreated) { DevListChangeOrUpdatedLinkStatus(IrmonControl); } #endif //DEBUGMSG(("Msg %X, wParam %d, lParam %d\n", message, wParam, lParam)); return (DefWindowProc(hWnd, message, wParam, lParam)); } return 0; } DWORD IrmonReportServiceStatus() { #ifdef BUILD_SERVICE_EXE if (!SetServiceStatus(IrmonStatusHandle, &IrmonServiceStatus)) { DEBUGMSG(("IRMON: SetServiceStatus failed %d\n", GetLastError())); return GetLastError(); } #endif return NO_ERROR; } DWORD IrmonUpdateServiceStatus( DWORD State, DWORD Win32ExitCode, DWORD CheckPoint, DWORD WaitHint ) { DWORD Error = NO_ERROR; #ifdef BUILD_SERVICE_EXE IrmonServiceStatus.dwCurrentState = State; IrmonServiceStatus.dwWin32ExitCode = Win32ExitCode; IrmonServiceStatus.dwCheckPoint = CheckPoint; IrmonServiceStatus.dwWaitHint = WaitHint; Error = IrmonReportServiceStatus(); if (Error != NO_ERROR) { DEBUGMSG(("IRMON: IrmonUpdateServiceStatus failed %d\n", GetLastError())); } #endif return Error; } VOID AdhocNotworkNotification( PVOID Context, BOOL Availible ) { PIRMON_CONTROL IrmonControl=(PIRMON_CONTROL)Context; #ifdef IP_OBEX if (Availible) { // // there is an adhok network availible // EnterCriticalSection(&IrmonControl->Lock); DbgPrint("irmon: new adhoc networks\n"); IrmonControl->SsdpContext=CreateSsdpDiscoveryObject( "OBEX", IrmonControl->hWnd, WM_IP_DEVICE_CHANGE ); LeaveCriticalSection(&IrmonControl->Lock); } else { DbgPrint("irmon: no adhoc networks\n"); EnterCriticalSection(&IrmonControl->Lock); if (IrmonControl->SsdpContext != NULL) { CloseSsdpDiscoveryObject(IrmonControl->SsdpContext); IrmonControl->SsdpContext=NULL; } IpDeviceList->DeviceCount=0; DeviceListUpdated = TRUE; LeaveCriticalSection(&IrmonControl->Lock); DevListChangeOrUpdatedLinkStatus(IrmonControl); } #endif return; } #ifdef BUILD_SERVICE_EXE VOID ServiceHandler( DWORD OpCode) { switch( OpCode ) { case SERVICE_CONTROL_STOP : DEBUGMSG(("IRMON: SERVICE_CONTROL_STOP received\n")); IrmonServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; IrmonReportServiceStatus(); SetEvent(hIrmonEvents[EV_STOP_EVENT]); return; case SERVICE_CONTROL_PAUSE : DEBUGMSG(("IRMON: SERVICE_CONTROL_PAUSE received\n")); IrmonServiceStatus.dwCurrentState = SERVICE_PAUSED; break; case SERVICE_CONTROL_CONTINUE : DEBUGMSG(("IRMON: SERVICE_CONTROL_CONTINUE received\n")); IrmonServiceStatus.dwCurrentState = SERVICE_RUNNING; break; default : break; } IrmonReportServiceStatus(); } #endif 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_LOGON_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL); hIrmonEvents[EV_LOGOFF_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; WaveNumDev = NULL; RtlZeroMemory(&LinkStatus, sizeof(LinkStatus)); ZeroMemory(&GlobalIrmonControl,sizeof(GlobalIrmonControl)); InitializeCriticalSection(&GlobalIrmonControl.Lock); #ifdef BUILD_SERVICE_EXE IrmonServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; IrmonServiceStatus.dwCurrentState = SERVICE_STOPPED; IrmonServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; IrmonServiceStatus.dwWin32ExitCode = NO_ERROR; IrmonServiceStatus.dwServiceSpecificExitCode = NO_ERROR; IrmonServiceStatus.dwCheckPoint = 0; IrmonServiceStatus.dwWaitHint = 0; IrmonStatusHandle = RegisterServiceCtrlHandler(IRMON_SERVICE_NAME, ServiceHandler); if (!IrmonStatusHandle) { DEBUGMSG(("IRMON: RegisterServiceCtrlHandler failed %d\n", GetLastError())); goto done; } DEBUGMSG(("IRMON: Start pending\n")); Error = IrmonUpdateServiceStatus(SERVICE_START_PENDING, NO_ERROR, 1, 25000); if (Error != NO_ERROR) { goto done; } #endif LoadSoundApis(); if (WSAStartup(WSAVerReq, &WSAData) != 0) { DEBUGMSG(("IRMON: WSAStartup failed\n")); Error = 1; goto done; } // Initialize OBEX and IrTran-P: bResult=InitializeIrxfer( &GlobalIrmonControl, AdhocNotworkNotification, SetLogonStatus, SetTrayStatus, SetSoundStatus, &GlobalIrmonControl.IrxferContext ); if (bResult) { DEBUGMSG(("IRMON: Irxfer initialized\n")); } else { DEBUGMSG(("IRMON: Irxfer initializtion failed\n")); goto done; } // gTaskbarCreated = RegisterWindowMessage(TASK_BAR_CREATED); 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: failed to register class\n")); } IrmonStopped = FALSE; Error = IrmonUpdateServiceStatus(SERVICE_RUNNING, NO_ERROR, 0, 0); DEBUGMSG(("IRMON: Service running\n")); 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_LOGON_EVENT: UserLogonEvent(&GlobalIrmonControl); break; case WAIT_OBJECT_0 + EV_LOGOFF_EVENT: UserLogoffEvent(&GlobalIrmonControl); 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: Failed to unitialize irxfer!!\n")); IrmonStopped = FALSE; } else { DEBUGMSG(("IRMON: irxfer unitialized\n")); } UpdateTray(&GlobalIrmonControl,ICON_ST_NOICON, 0, NULL, 0); done: DeleteCriticalSection(&GlobalIrmonControl.Lock); if (IrmonStatusHandle) { DEBUGMSG(("IRMON: Service stopped\n")); IrmonUpdateServiceStatus(SERVICE_STOPPED, Error, 0, 0); } } BOOL WINAPI DllMain ( HINSTANCE hinst, DWORD dwReason, LPVOID pvReserved) { if (DLL_PROCESS_ATTACH == dwReason) { ghInstance = hinst; DisableThreadLibraryCalls (hinst); } return TRUE; }