|
|
/*****************************************************************************
* * Copyright (C) Microsoft Corporation, 1995 - 1999 * * File: irmon.c * * Description: Infrared monitor * * Author: mbert/mikezin * * Date: 3/1/98 * */ #define UNICODE
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winsock2.h>
#include <af_irda.h>
#include <shellapi.h>
#include <resource.h>
#include <resrc1.h>
#include <irioctl.h>
// allocate storage! and initialize the GUIDS
#include <initguid.h>
#include <devguid.h>
#include <setupapi.h>
#include <cfgmgr32.h>
#include <mmsystem.h>
#include "internal.h"
#include <devlist.h>
#include <irtypes.h>
#include <ssdp.h>
#include <irmon.h>
#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; i<IpDeviceList->DeviceCount; 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; }
|