Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1809 lines
43 KiB

/*****************************************************************************
*
* 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;
}