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.
1216 lines
30 KiB
1216 lines
30 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>
|
|
#include <wtsapi32.h>
|
|
#include <strsafe.h>
|
|
|
|
#include <userenv.h>
|
|
#include <sddl.h>
|
|
|
|
#include "internal.h"
|
|
|
|
#include <devlist.h>
|
|
#include <irtypes.h>
|
|
#include <irmon.h>
|
|
|
|
#include "irdisc.h"
|
|
|
|
|
|
|
|
#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 IRMON_SERVICE_NAME TEXT("irmon")
|
|
#define EV_STOP_EVENT 0
|
|
#define WAIT_EVENT_CNT 1
|
|
|
|
|
|
#define NO_SESSION_ID (0xffffffff)
|
|
|
|
#define MAX_SESSIONS (32)
|
|
|
|
|
|
typedef struct _IRMON_CONTROL {
|
|
|
|
CRITICAL_SECTION Lock;
|
|
|
|
|
|
HWND hWnd;
|
|
|
|
WSAOVERLAPPED Overlapped;
|
|
|
|
HANDLE DiscoveryObject;
|
|
|
|
BOOL IrmonStopped;
|
|
BOOL ThreadExit;
|
|
|
|
|
|
HANDLE hIrmonEvents[WAIT_EVENT_CNT];
|
|
|
|
SERVICE_STATUS_HANDLE IrmonStatusHandle;
|
|
SERVICE_STATUS IrmonServiceStatus;
|
|
|
|
BOOL LoggedOn;
|
|
BOOL NewLogon;
|
|
ULONG TimeOfLastLogon;
|
|
DWORD ConnectedConsoleId;
|
|
DWORD LoggedOnId[MAX_SESSIONS];
|
|
|
|
HANDLE ThreadBlockEvent;
|
|
HANDLE ThreadHandle;
|
|
|
|
ULONG PreviousDeviceCount;
|
|
|
|
HANDLE FileMapping;
|
|
PVOID ViewOfFile;
|
|
|
|
SOCKET Obex1;
|
|
SOCKET Obex2;
|
|
|
|
} IRMON_CONTROL, *PIRMON_CONTROL;
|
|
|
|
IRMON_CONTROL GlobalIrmonControl;
|
|
|
|
|
|
BOOL
|
|
StartThread(
|
|
PIRMON_CONTROL IrmonControl
|
|
);
|
|
|
|
|
|
|
|
|
|
BYTE FoundDevListBuf[ sizeof(OBEX_DEVICE_LIST) + sizeof(OBEX_DEVICE)*MAX_OBEX_DEVICES];
|
|
OBEX_DEVICE_LIST * const pDeviceList=(POBEX_DEVICE_LIST)FoundDevListBuf;
|
|
|
|
|
|
wchar_t * WSZ_SHOW_NOTHING = L"irftp.exe /z";
|
|
|
|
WCHAR CommandLine[MAX_PATH];
|
|
|
|
|
|
TCHAR IrmonClassName[] = TEXT("NewIrmonClass");
|
|
IRLINK_STATUS LinkStatus;
|
|
|
|
HINSTANCE ghInstance;
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
InitiateLazyDscv(
|
|
PIRMON_CONTROL IrmonControl
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
InitiateLinkStatusQuery(
|
|
PIRMON_CONTROL IrmonControl
|
|
);
|
|
|
|
|
|
|
|
#if DBG
|
|
TCHAR *
|
|
GetLastErrorText()
|
|
{
|
|
switch (WSAGetLastError())
|
|
{
|
|
case WSAEINTR:
|
|
return (TEXT("WSAEINTR"));
|
|
break;
|
|
|
|
case WSAEBADF:
|
|
return(TEXT("WSAEBADF"));
|
|
break;
|
|
|
|
case WSAEACCES:
|
|
return(TEXT("WSAEACCES"));
|
|
break;
|
|
|
|
case WSAEFAULT:
|
|
return(TEXT("WSAEFAULT"));
|
|
break;
|
|
|
|
case WSAEINVAL:
|
|
return(TEXT("WSAEINVAL"));
|
|
break;
|
|
|
|
case WSAEMFILE:
|
|
return(TEXT("WSAEMFILE"));
|
|
break;
|
|
|
|
case WSAEWOULDBLOCK:
|
|
return(TEXT("WSAEWOULDBLOCK"));
|
|
break;
|
|
|
|
case WSAEINPROGRESS:
|
|
return(TEXT("WSAEINPROGRESS"));
|
|
break;
|
|
|
|
case WSAEALREADY:
|
|
return(TEXT("WSAEALREADY"));
|
|
break;
|
|
|
|
case WSAENOTSOCK:
|
|
return(TEXT("WSAENOTSOCK"));
|
|
break;
|
|
|
|
case WSAEDESTADDRREQ:
|
|
return(TEXT("WSAEDESTADDRREQ"));
|
|
break;
|
|
|
|
case WSAEMSGSIZE:
|
|
return(TEXT("WSAEMSGSIZE"));
|
|
break;
|
|
|
|
case WSAEPROTOTYPE:
|
|
return(TEXT("WSAEPROTOTYPE"));
|
|
break;
|
|
|
|
case WSAENOPROTOOPT:
|
|
return(TEXT("WSAENOPROTOOPT"));
|
|
break;
|
|
|
|
case WSAEPROTONOSUPPORT:
|
|
return(TEXT("WSAEPROTONOSUPPORT"));
|
|
break;
|
|
|
|
case WSAESOCKTNOSUPPORT:
|
|
return(TEXT("WSAESOCKTNOSUPPORT"));
|
|
break;
|
|
|
|
case WSAEOPNOTSUPP:
|
|
return(TEXT("WSAEOPNOTSUPP"));
|
|
break;
|
|
|
|
case WSAEPFNOSUPPORT:
|
|
return(TEXT("WSAEPFNOSUPPORT"));
|
|
break;
|
|
|
|
case WSAEAFNOSUPPORT:
|
|
return(TEXT("WSAEAFNOSUPPORT"));
|
|
break;
|
|
|
|
case WSAEADDRINUSE:
|
|
return(TEXT("WSAEADDRINUSE"));
|
|
break;
|
|
|
|
case WSAEADDRNOTAVAIL:
|
|
return(TEXT("WSAEADDRNOTAVAIL"));
|
|
break;
|
|
|
|
case WSAENETDOWN:
|
|
return(TEXT("WSAENETDOWN"));
|
|
break;
|
|
|
|
case WSAENETUNREACH:
|
|
return(TEXT("WSAENETUNREACH"));
|
|
break;
|
|
|
|
case WSAENETRESET:
|
|
return(TEXT("WSAENETRESET"));
|
|
break;
|
|
|
|
case WSAECONNABORTED:
|
|
return(TEXT("WSAECONNABORTED"));
|
|
break;
|
|
|
|
case WSAECONNRESET:
|
|
return(TEXT("WSAECONNRESET"));
|
|
break;
|
|
|
|
case WSAENOBUFS:
|
|
return(TEXT("WSAENOBUFS"));
|
|
break;
|
|
|
|
case WSAEISCONN:
|
|
return(TEXT("WSAEISCONN"));
|
|
break;
|
|
|
|
case WSAENOTCONN:
|
|
return(TEXT("WSAENOTCONN"));
|
|
break;
|
|
|
|
case WSAESHUTDOWN:
|
|
return(TEXT("WSAESHUTDOWN"));
|
|
break;
|
|
|
|
case WSAETOOMANYREFS:
|
|
return(TEXT("WSAETOOMANYREFS"));
|
|
break;
|
|
|
|
case WSAETIMEDOUT:
|
|
return(TEXT("WSAETIMEDOUT"));
|
|
break;
|
|
|
|
case WSAECONNREFUSED:
|
|
return(TEXT("WSAECONNREFUSED"));
|
|
break;
|
|
|
|
case WSAELOOP:
|
|
return(TEXT("WSAELOOP"));
|
|
break;
|
|
|
|
case WSAENAMETOOLONG:
|
|
return(TEXT("WSAENAMETOOLONG"));
|
|
break;
|
|
|
|
case WSAEHOSTDOWN:
|
|
return(TEXT("WSAEHOSTDOWN"));
|
|
break;
|
|
|
|
case WSAEHOSTUNREACH:
|
|
return(TEXT("WSAEHOSTUNREACH"));
|
|
break;
|
|
|
|
case WSAENOTEMPTY:
|
|
return(TEXT("WSAENOTEMPTY"));
|
|
break;
|
|
|
|
case WSAEPROCLIM:
|
|
return(TEXT("WSAEPROCLIM"));
|
|
break;
|
|
|
|
case WSAEUSERS:
|
|
return(TEXT("WSAEUSERS"));
|
|
break;
|
|
|
|
case WSAEDQUOT:
|
|
return(TEXT("WSAEDQUOT"));
|
|
break;
|
|
|
|
case WSAESTALE:
|
|
return(TEXT("WSAESTALE"));
|
|
break;
|
|
|
|
case WSAEREMOTE:
|
|
return(TEXT("WSAEREMOTE"));
|
|
break;
|
|
|
|
case WSAEDISCON:
|
|
return(TEXT("WSAEDISCON"));
|
|
break;
|
|
|
|
case WSASYSNOTREADY:
|
|
return(TEXT("WSASYSNOTREADY"));
|
|
break;
|
|
|
|
case WSAVERNOTSUPPORTED:
|
|
return(TEXT("WSAVERNOTSUPPORTED"));
|
|
break;
|
|
|
|
case WSANOTINITIALISED:
|
|
return(TEXT("WSANOTINITIALISED"));
|
|
break;
|
|
|
|
/*
|
|
case WSAHOST:
|
|
return(TEXT("WSAHOST"));
|
|
break;
|
|
|
|
case WSATRY:
|
|
return(TEXT("WSATRY"));
|
|
break;
|
|
|
|
case WSANO:
|
|
return(TEXT("WSANO"));
|
|
break;
|
|
*/
|
|
|
|
default:
|
|
return(TEXT("Unknown Error"));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
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_IR_DEVICE_CHANGE: {
|
|
|
|
ULONG BufferSize=sizeof(FoundDevListBuf);
|
|
|
|
IrmonControl->PreviousDeviceCount=pDeviceList->DeviceCount;
|
|
|
|
GetDeviceList(
|
|
IrmonControl->DiscoveryObject,
|
|
pDeviceList,
|
|
&BufferSize
|
|
);
|
|
|
|
if ((IrmonControl->PreviousDeviceCount != pDeviceList->DeviceCount)
|
|
&&
|
|
(pDeviceList->DeviceCount > 0)) {
|
|
|
|
SetEvent(IrmonControl->ThreadBlockEvent);
|
|
}
|
|
|
|
|
|
DEBUGMSG(("IRMON2: %d IR device(s) found:\n", pDeviceList->DeviceCount));
|
|
|
|
// DevListChangeOrUpdatedLinkStatus(IrmonControl);
|
|
|
|
|
|
}
|
|
break;
|
|
|
|
case WM_IR_LINK_CHANGE: {
|
|
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
//DEBUGMSG(("Msg %X, wParam %d, lParam %d\n", message, wParam, lParam));
|
|
return (DefWindowProc(hWnd, message, wParam, lParam));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
DWORD
|
|
IrmonReportServiceStatus()
|
|
{
|
|
if (!SetServiceStatus(GlobalIrmonControl.IrmonStatusHandle, &GlobalIrmonControl.IrmonServiceStatus))
|
|
{
|
|
DEBUGMSG(("IRMON2: SetServiceStatus failed %d\n", GetLastError()));
|
|
return GetLastError();
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
DWORD
|
|
IrmonUpdateServiceStatus(
|
|
DWORD State,
|
|
DWORD Win32ExitCode,
|
|
DWORD CheckPoint,
|
|
DWORD WaitHint
|
|
)
|
|
{
|
|
DWORD Error = NO_ERROR;
|
|
|
|
GlobalIrmonControl.IrmonServiceStatus.dwCurrentState = State;
|
|
GlobalIrmonControl.IrmonServiceStatus.dwWin32ExitCode = Win32ExitCode;
|
|
GlobalIrmonControl.IrmonServiceStatus.dwCheckPoint = CheckPoint;
|
|
GlobalIrmonControl.IrmonServiceStatus.dwWaitHint = WaitHint;
|
|
|
|
Error = IrmonReportServiceStatus();
|
|
|
|
if (Error != NO_ERROR)
|
|
{
|
|
DEBUGMSG(("IRMON2: IrmonUpdateServiceStatus failed %d\n", GetLastError()));
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
|
|
|
|
VOID
|
|
NotifyUserChange(
|
|
PIRMON_CONTROL IrmonControl
|
|
)
|
|
|
|
{
|
|
ULONG i;
|
|
|
|
if (IrmonControl->ConnectedConsoleId != NO_SESSION_ID) {
|
|
//
|
|
// The console is currently connected
|
|
//
|
|
for (i=0; i< MAX_SESSIONS; i++) {
|
|
|
|
if (IrmonControl->LoggedOnId[i] == IrmonControl->ConnectedConsoleId) {
|
|
//
|
|
// there is a user logged on for this session
|
|
//
|
|
if (!IrmonControl->LoggedOn) {
|
|
|
|
IrmonControl->LoggedOn=TRUE;
|
|
|
|
if (pDeviceList->DeviceCount > 0) {
|
|
|
|
SetEvent(IrmonControl->ThreadBlockEvent);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
//
|
|
// user not logged on for this session
|
|
//
|
|
if (IrmonControl->LoggedOn) {
|
|
|
|
IrmonControl->LoggedOn=FALSE;
|
|
}
|
|
} else {
|
|
//
|
|
// The console is not currently connected
|
|
//
|
|
if (IrmonControl->LoggedOn) {
|
|
|
|
IrmonControl->LoggedOn=FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
ServiceHandler(
|
|
DWORD OpCode,
|
|
DWORD EventType,
|
|
LPVOID EventData,
|
|
LPVOID Context
|
|
)
|
|
{
|
|
|
|
WTSSESSION_NOTIFICATION *Notify=(WTSSESSION_NOTIFICATION*) EventData;
|
|
ULONG i;
|
|
|
|
switch( OpCode )
|
|
{
|
|
case SERVICE_CONTROL_STOP :
|
|
|
|
DEBUGMSG(("IRMON2: SERVICE_CONTROL_STOP received\n"));
|
|
GlobalIrmonControl.IrmonServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
|
IrmonReportServiceStatus();
|
|
SetEvent(GlobalIrmonControl.hIrmonEvents[EV_STOP_EVENT]);
|
|
return NO_ERROR;;
|
|
|
|
case SERVICE_CONTROL_PAUSE :
|
|
|
|
DEBUGMSG(("IRMON2: SERVICE_CONTROL_PAUSE received\n"));
|
|
GlobalIrmonControl.IrmonServiceStatus.dwCurrentState = SERVICE_PAUSED;
|
|
break;
|
|
|
|
case SERVICE_CONTROL_CONTINUE :
|
|
|
|
DEBUGMSG(("IRMON2: SERVICE_CONTROL_CONTINUE received\n"));
|
|
GlobalIrmonControl.IrmonServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
|
break;
|
|
|
|
case SERVICE_CONTROL_SESSIONCHANGE:
|
|
|
|
EnterCriticalSection(&GlobalIrmonControl.Lock);
|
|
|
|
// DbgPrint("IRMON2: SERVICE_CONTROL_SESSIONCHANGE %d\n",EventType);
|
|
|
|
switch (EventType) {
|
|
|
|
case WTS_CONSOLE_CONNECT:
|
|
// DbgPrint("IRMON2: WTS_CONSOLE_CONNECT: old=%d, new=%d\n",GlobalIrmonControl.ConnectedConsoleId,Notify->dwSessionId);
|
|
|
|
GlobalIrmonControl.ConnectedConsoleId=Notify->dwSessionId;
|
|
|
|
NotifyUserChange(&GlobalIrmonControl);
|
|
|
|
break;
|
|
|
|
case WTS_CONSOLE_DISCONNECT:
|
|
// DbgPrint("IRMON2: WTS_CONSOLE_DISCONNECT Session=%d\n",Notify->dwSessionId);
|
|
|
|
GlobalIrmonControl.ConnectedConsoleId=NO_SESSION_ID;
|
|
|
|
NotifyUserChange(&GlobalIrmonControl);
|
|
|
|
break;
|
|
|
|
case WTS_SESSION_LOGON:
|
|
// DbgPrint("IRMON2: WTS_SESSION_LOGON new=%d\n",Notify->dwSessionId);
|
|
|
|
for (i=0; i < MAX_SESSIONS; i++) {
|
|
|
|
if (GlobalIrmonControl.LoggedOnId[i] == NO_SESSION_ID) {
|
|
|
|
GlobalIrmonControl.LoggedOnId[i]=Notify->dwSessionId;
|
|
//
|
|
//
|
|
//
|
|
GlobalIrmonControl.NewLogon=TRUE;
|
|
GlobalIrmonControl.TimeOfLastLogon=GetTickCount();
|
|
NotifyUserChange(&GlobalIrmonControl);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
case WTS_SESSION_LOGOFF:
|
|
// DbgPrint("IRMON2: WTS_SESSION_LOGOFF Session=%d\n",Notify->dwSessionId);
|
|
|
|
for (i=0; i < MAX_SESSIONS; i++) {
|
|
|
|
if (GlobalIrmonControl.LoggedOnId[i] == Notify->dwSessionId) {
|
|
|
|
GlobalIrmonControl.LoggedOnId[i]=NO_SESSION_ID;
|
|
|
|
NotifyUserChange(&GlobalIrmonControl);
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
// DbgPrint("IRMON2: \n");
|
|
}
|
|
|
|
LeaveCriticalSection(&GlobalIrmonControl.Lock);
|
|
|
|
break;
|
|
|
|
|
|
default :
|
|
break;
|
|
}
|
|
|
|
IrmonReportServiceStatus();
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
LONG i;
|
|
DWORD CurrentConsoleSession;
|
|
|
|
|
|
// Initialize all necessary globals to 0, FALSE, or NULL because
|
|
// we might be restarting within the same services process
|
|
pDeviceList->DeviceCount = 0;
|
|
|
|
RtlZeroMemory(&LinkStatus, sizeof(LinkStatus));
|
|
|
|
ZeroMemory(&GlobalIrmonControl,sizeof(GlobalIrmonControl));
|
|
|
|
bResult=InitializeCriticalSectionAndSpinCount(&GlobalIrmonControl.Lock,0x8000000);
|
|
|
|
if (!bResult) {
|
|
|
|
return;
|
|
}
|
|
|
|
GlobalIrmonControl.hIrmonEvents[EV_STOP_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
if (GlobalIrmonControl.hIrmonEvents[EV_STOP_EVENT] == NULL) {
|
|
|
|
goto done;
|
|
}
|
|
|
|
GlobalIrmonControl.ThreadBlockEvent=CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
if (GlobalIrmonControl.ThreadBlockEvent == NULL) {
|
|
|
|
goto done;
|
|
}
|
|
|
|
GlobalIrmonControl.ConnectedConsoleId=NO_SESSION_ID;
|
|
|
|
for (i=0; i < MAX_SESSIONS; i++) {
|
|
|
|
GlobalIrmonControl.LoggedOnId[i] = NO_SESSION_ID;
|
|
}
|
|
|
|
EnterCriticalSection(&GlobalIrmonControl.Lock);
|
|
|
|
CurrentConsoleSession=WTSGetActiveConsoleSessionId();
|
|
|
|
if (CurrentConsoleSession != 0xffffffff) {
|
|
//
|
|
// We have a current session
|
|
//
|
|
HANDLE UserToken;
|
|
|
|
bResult=WTSQueryUserToken(CurrentConsoleSession,&UserToken);
|
|
|
|
if (bResult) {
|
|
//
|
|
// there is a user logged on to this session
|
|
//
|
|
CloseHandle(UserToken);
|
|
|
|
GlobalIrmonControl.LoggedOnId[0]=CurrentConsoleSession;
|
|
|
|
GlobalIrmonControl.ConnectedConsoleId=CurrentConsoleSession;
|
|
|
|
NotifyUserChange(&GlobalIrmonControl);
|
|
}
|
|
}
|
|
LeaveCriticalSection(&GlobalIrmonControl.Lock);
|
|
|
|
|
|
GlobalIrmonControl.IrmonServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
|
|
GlobalIrmonControl.IrmonServiceStatus.dwCurrentState = SERVICE_STOPPED;
|
|
GlobalIrmonControl.IrmonServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP
|
|
| SERVICE_ACCEPT_PAUSE_CONTINUE
|
|
| SERVICE_ACCEPT_SESSIONCHANGE;
|
|
|
|
GlobalIrmonControl.IrmonServiceStatus.dwWin32ExitCode = NO_ERROR;
|
|
GlobalIrmonControl.IrmonServiceStatus.dwServiceSpecificExitCode = NO_ERROR;
|
|
GlobalIrmonControl.IrmonServiceStatus.dwCheckPoint = 0;
|
|
GlobalIrmonControl.IrmonServiceStatus.dwWaitHint = 0;
|
|
|
|
|
|
GlobalIrmonControl.IrmonStatusHandle = RegisterServiceCtrlHandlerEx(IRMON_SERVICE_NAME,
|
|
ServiceHandler,NULL);
|
|
|
|
if (!GlobalIrmonControl.IrmonStatusHandle)
|
|
{
|
|
DEBUGMSG(("IRMON2: RegisterServiceCtrlHandler failed %d\n",
|
|
GetLastError()));
|
|
goto done;
|
|
}
|
|
|
|
DEBUGMSG(("IRMON2: Start pending\n"));
|
|
|
|
Error = IrmonUpdateServiceStatus(SERVICE_START_PENDING,
|
|
NO_ERROR, 1, 25000);
|
|
|
|
if (Error != NO_ERROR)
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
|
|
|
|
|
|
if (WSAStartup(WSAVerReq, &WSAData) != 0)
|
|
{
|
|
DEBUGMSG(("IRMON2: WSAStartup failed\n"));
|
|
Error = 1;
|
|
goto done;
|
|
}
|
|
|
|
|
|
Wc.style = CS_NOCLOSE;
|
|
Wc.cbClsExtra = 0;
|
|
Wc.cbWndExtra = 0;
|
|
Wc.hInstance = ghInstance;
|
|
Wc.hIcon = NULL;
|
|
Wc.hCursor = NULL;
|
|
Wc.hbrBackground = NULL;
|
|
Wc.lpszMenuName = NULL;
|
|
Wc.lpfnWndProc = WndProc;
|
|
Wc.lpszClassName = IrmonClassName;
|
|
|
|
if (!RegisterClass(&Wc))
|
|
{
|
|
DEBUGMSG(("IRMON2: failed to register class\n"));
|
|
}
|
|
|
|
GlobalIrmonControl.hWnd = CreateWindow(
|
|
IrmonClassName,
|
|
NULL,
|
|
WS_OVERLAPPEDWINDOW,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
NULL,
|
|
NULL,
|
|
ghInstance,
|
|
&GlobalIrmonControl
|
|
);
|
|
|
|
|
|
if (GlobalIrmonControl.hWnd == NULL) {
|
|
DEBUGMSG(("IRMON2: failed to create window class\n"));
|
|
goto done;
|
|
}
|
|
|
|
GlobalIrmonControl.DiscoveryObject=CreateIrDiscoveryObject(
|
|
GlobalIrmonControl.hWnd,
|
|
WM_IR_DEVICE_CHANGE,
|
|
WM_IR_LINK_CHANGE
|
|
);
|
|
|
|
if (GlobalIrmonControl.DiscoveryObject == NULL) {
|
|
|
|
DbgPrint("IRMON2: could not create ir discovery object\n");
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
Error = IrmonUpdateServiceStatus(SERVICE_RUNNING,
|
|
NO_ERROR, 0, 0);
|
|
|
|
DEBUGMSG(("IRMON2: Service running\n"));
|
|
|
|
|
|
bResult=StartThread(&GlobalIrmonControl);
|
|
|
|
if (bResult) {
|
|
//
|
|
// thread started and memory mapped
|
|
//
|
|
while (!GlobalIrmonControl.IrmonStopped)
|
|
{
|
|
Status = MsgWaitForMultipleObjectsEx(WAIT_EVENT_CNT, GlobalIrmonControl.hIrmonEvents, INFINITE,
|
|
QS_ALLINPUT | QS_ALLEVENTS | QS_ALLPOSTMESSAGE,
|
|
MWMO_ALERTABLE);
|
|
|
|
switch (Status)
|
|
{
|
|
case WAIT_OBJECT_0 + EV_STOP_EVENT:
|
|
GlobalIrmonControl.IrmonStopped = TRUE;
|
|
break;
|
|
|
|
|
|
case WAIT_IO_COMPLETION:
|
|
break;
|
|
|
|
default:
|
|
while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
if (Msg.message == WM_QUIT)
|
|
{
|
|
GlobalIrmonControl.IrmonStopped = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (!IsDialogMessage(GlobalIrmonControl.hWnd, &Msg))
|
|
{
|
|
TranslateMessage(&Msg);
|
|
DispatchMessage(&Msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
done:
|
|
|
|
GlobalIrmonControl.ThreadExit=TRUE;
|
|
|
|
SetEvent(GlobalIrmonControl.ThreadBlockEvent);
|
|
|
|
if (GlobalIrmonControl.ThreadHandle != NULL) {
|
|
|
|
WaitForSingleObject(GlobalIrmonControl.ThreadHandle,60*1000);
|
|
CloseHandle(GlobalIrmonControl.ThreadHandle);
|
|
}
|
|
|
|
if (GlobalIrmonControl.FileMapping != NULL) {
|
|
|
|
CloseHandle(GlobalIrmonControl.FileMapping);
|
|
}
|
|
|
|
if (GlobalIrmonControl.ViewOfFile != NULL) {
|
|
|
|
CloseHandle(GlobalIrmonControl.ViewOfFile);
|
|
}
|
|
|
|
|
|
|
|
if (GlobalIrmonControl.DiscoveryObject != NULL) {
|
|
|
|
CloseIrDiscoveryObject(GlobalIrmonControl.DiscoveryObject);
|
|
|
|
GlobalIrmonControl.DiscoveryObject = NULL;
|
|
}
|
|
|
|
if (GlobalIrmonControl.hWnd != NULL) {
|
|
|
|
DestroyWindow(GlobalIrmonControl.hWnd);
|
|
GlobalIrmonControl.hWnd = 0;
|
|
}
|
|
|
|
UnregisterClass(IrmonClassName,ghInstance);
|
|
|
|
DeleteCriticalSection(&GlobalIrmonControl.Lock);
|
|
|
|
DEBUGMSG(("IRMON2: Service stopped\n"));
|
|
IrmonUpdateServiceStatus(SERVICE_STOPPED, Error, 0, 0);
|
|
}
|
|
|
|
|
|
SOCKET
|
|
CreateListenSocket(
|
|
char* ServiceName
|
|
)
|
|
|
|
{
|
|
|
|
WSADATA wsadata;
|
|
SOCKET listenSocket;
|
|
SOCKADDR_IRDA saListen;
|
|
int nRet;
|
|
|
|
|
|
listenSocket = socket( AF_IRDA, SOCK_STREAM, 0 );
|
|
|
|
if( INVALID_SOCKET == listenSocket ) {
|
|
|
|
UINT uErr = (UINT)WSAGetLastError();
|
|
// DbgLog3( SEV_ERROR, "listen on %s socket() failed with %d [0x%x]", ServiceName, uErr, uErr);
|
|
goto lErr;
|
|
}
|
|
|
|
// DbgLog2( SEV_INFO, "listen on %s socket ID: %ld", ServiceName, (DWORD)listenSocket );
|
|
|
|
saListen.irdaAddressFamily = AF_IRDA;
|
|
*(UINT *)saListen.irdaDeviceID = 0;
|
|
StringCbCopyA(saListen.irdaServiceName, sizeof(saListen.irdaServiceName), ServiceName);
|
|
|
|
nRet = bind( listenSocket, (const struct sockaddr *)&saListen, sizeof(saListen) );
|
|
|
|
if( SOCKET_ERROR == nRet ) {
|
|
|
|
UINT uErr = (UINT)WSAGetLastError();
|
|
// DbgLog3( SEV_ERROR, "listen on %s setsockopt failed with %d [0x%x]", ServiceName, uErr, uErr);
|
|
goto lErr;
|
|
}
|
|
|
|
nRet = listen( listenSocket, 2 );
|
|
lErr:
|
|
return listenSocket;
|
|
|
|
}
|
|
|
|
#define LOGON_WAIT_TIME (5000)
|
|
|
|
DWORD
|
|
IrmonThreadStart(
|
|
PVOID Context
|
|
)
|
|
|
|
{
|
|
PIRMON_CONTROL IrmonControl=Context;
|
|
|
|
|
|
// DbgPrint("irmon2: thread start\n");
|
|
|
|
|
|
|
|
while (!IrmonControl->ThreadExit) {
|
|
|
|
WaitForSingleObject(IrmonControl->ThreadBlockEvent,INFINITE);
|
|
|
|
EnterCriticalSection(&IrmonControl->Lock);
|
|
|
|
// DbgPrint("irmon2: thread session=%d, Device=%d\n",IrmonControl->ConnectedConsoleId,pDeviceList->DeviceCount);
|
|
|
|
if (IrmonControl->ConnectedConsoleId != NO_SESSION_ID) {
|
|
|
|
if (pDeviceList->DeviceCount > 0) {
|
|
|
|
BOOL bResult;
|
|
HANDLE UserToken;
|
|
|
|
PVOID EnvironmentBlock;
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION ProcessInformation;
|
|
DWORD UiProcessId;
|
|
|
|
|
|
si.cb = sizeof(STARTUPINFO);
|
|
si.lpReserved = NULL;
|
|
si.lpTitle = NULL;
|
|
si.lpDesktop = L"WinSta0\\Default";
|
|
si.dwX = si.dwY = si.dwXSize = si.dwYSize = 0L;
|
|
si.dwFlags = 0;;
|
|
si.wShowWindow = SW_SHOW;
|
|
si.lpReserved2 = NULL;
|
|
si.cbReserved2 = 0;
|
|
|
|
if (IrmonControl->NewLogon) {
|
|
//
|
|
// new user logging on, system time to set user context corrently
|
|
//
|
|
ULONG CurrentTime=GetTickCount();
|
|
ULONG TimeDifference;
|
|
|
|
IrmonControl->NewLogon=FALSE;
|
|
|
|
if (CurrentTime >= IrmonControl->TimeOfLastLogon) {
|
|
//
|
|
// No rollover
|
|
//
|
|
TimeDifference=CurrentTime - IrmonControl->TimeOfLastLogon;
|
|
|
|
} else {
|
|
//
|
|
// seem to have rolled over
|
|
//
|
|
TimeDifference=CurrentTime + (0xffffffff - IrmonControl->TimeOfLastLogon);
|
|
|
|
}
|
|
|
|
if ( LOGON_WAIT_TIME > TimeDifference ) {
|
|
#if DBG
|
|
DbgPrint("irmon2: New user, waiting %d ms...\n",LOGON_WAIT_TIME - TimeDifference);
|
|
#endif
|
|
Sleep(LOGON_WAIT_TIME - TimeDifference);
|
|
}
|
|
}
|
|
|
|
|
|
bResult=WTSQueryUserToken(IrmonControl->ConnectedConsoleId,&UserToken);
|
|
|
|
if (bResult) {
|
|
|
|
bResult=CreateEnvironmentBlock(
|
|
&EnvironmentBlock,
|
|
UserToken,
|
|
FALSE
|
|
);
|
|
|
|
if (bResult) {
|
|
|
|
LONG RetryCount=10;
|
|
|
|
|
|
while (RetryCount > 0) {
|
|
|
|
// DbgPrint("irmon2: Start irftp\n");
|
|
|
|
StringCbCopyW(CommandLine, sizeof(CommandLine), WSZ_SHOW_NOTHING);
|
|
|
|
bResult=CreateProcessAsUser(
|
|
UserToken,
|
|
NULL, // just use the cmd line parm
|
|
CommandLine,
|
|
NULL, // default process ACL
|
|
NULL, // default thread ACL
|
|
FALSE, // don't inherit my handles
|
|
CREATE_NEW_PROCESS_GROUP | CREATE_UNICODE_ENVIRONMENT |CREATE_SUSPENDED,
|
|
EnvironmentBlock,
|
|
NULL, // same working directory
|
|
&si,
|
|
&ProcessInformation
|
|
);
|
|
|
|
|
|
|
|
if (bResult) {
|
|
|
|
LPWSAPROTOCOL_INFO ProtocolInfo=IrmonControl->ViewOfFile;
|
|
|
|
WSADuplicateSocket(
|
|
IrmonControl->Obex1,
|
|
ProcessInformation.dwProcessId,
|
|
ProtocolInfo
|
|
);
|
|
|
|
ProtocolInfo++;
|
|
|
|
WSADuplicateSocket(
|
|
IrmonControl->Obex2,
|
|
ProcessInformation.dwProcessId,
|
|
ProtocolInfo
|
|
);
|
|
|
|
|
|
ResumeThread(ProcessInformation.hThread);
|
|
|
|
LeaveCriticalSection(&IrmonControl->Lock);
|
|
|
|
WaitForInputIdle( ProcessInformation.hProcess, 10 * 1000 );
|
|
|
|
WaitForSingleObject(ProcessInformation.hProcess,INFINITE);
|
|
|
|
EnterCriticalSection(&IrmonControl->Lock);
|
|
|
|
// DbgPrint("irmon2: irftp exited\n");
|
|
|
|
CloseHandle(ProcessInformation.hProcess);
|
|
|
|
CloseHandle(ProcessInformation.hThread);
|
|
|
|
RetryCount=0;
|
|
|
|
} else {
|
|
|
|
// DbgPrint("irmon2: irftp failed to start %d\n",GetLastError());
|
|
RetryCount--;
|
|
Sleep(1000);
|
|
}
|
|
}
|
|
|
|
DestroyEnvironmentBlock( EnvironmentBlock );
|
|
}
|
|
CloseHandle(UserToken);
|
|
}
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&IrmonControl->Lock);
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#define SERVICE_NAME_1 "OBEX:IrXfer"
|
|
#define SERVICE_NAME_2 "OBEX"
|
|
|
|
|
|
BOOL
|
|
StartThread(
|
|
PIRMON_CONTROL IrmonControl
|
|
)
|
|
|
|
{
|
|
DWORD ThreadId;
|
|
SECURITY_ATTRIBUTES SA;
|
|
WCHAR* SD=L"D:(A;OICI;GA;;;SY) (A;OICI;GR;;;IU)";
|
|
BOOL bResult;
|
|
SA.nLength=sizeof(SECURITY_ATTRIBUTES);
|
|
SA.bInheritHandle=FALSE;
|
|
|
|
IrmonControl->FileMapping=NULL;
|
|
IrmonControl->ViewOfFile=NULL;
|
|
|
|
IrmonControl->Obex1=CreateListenSocket(SERVICE_NAME_1);
|
|
|
|
IrmonControl->Obex2=CreateListenSocket(SERVICE_NAME_2);
|
|
|
|
|
|
bResult=ConvertStringSecurityDescriptorToSecurityDescriptor(
|
|
SD,
|
|
SDDL_REVISION_1,
|
|
&SA.lpSecurityDescriptor,
|
|
NULL
|
|
);
|
|
|
|
if (bResult) {
|
|
|
|
IrmonControl->FileMapping=CreateFileMapping(
|
|
NULL,
|
|
&SA,
|
|
PAGE_READWRITE,
|
|
0,
|
|
sizeof(WSAPROTOCOL_INFO)*2,
|
|
TEXT("Global\\Irmon-shared-memory")
|
|
);
|
|
|
|
if (IrmonControl->FileMapping != NULL) {
|
|
|
|
IrmonControl->ViewOfFile=MapViewOfFile(
|
|
IrmonControl->FileMapping,
|
|
FILE_MAP_ALL_ACCESS,
|
|
0,
|
|
0,
|
|
0
|
|
);
|
|
|
|
if (IrmonControl->ViewOfFile != NULL) {
|
|
|
|
IrmonControl->ThreadHandle=CreateThread(
|
|
NULL,
|
|
0,
|
|
IrmonThreadStart,
|
|
IrmonControl,
|
|
0,
|
|
&ThreadId
|
|
);
|
|
|
|
if (IrmonControl->ThreadHandle != NULL) {
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
|
|
// DbgPrint("irmon2: failed to create SD %d\n",GetLastError());
|
|
}
|
|
|
|
CloseHandle(IrmonControl->FileMapping);
|
|
CloseHandle(IrmonControl->ViewOfFile);
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
DllMain (
|
|
HINSTANCE hinst,
|
|
DWORD dwReason,
|
|
LPVOID pvReserved)
|
|
{
|
|
if (DLL_PROCESS_ATTACH == dwReason)
|
|
{
|
|
ghInstance = hinst;
|
|
DisableThreadLibraryCalls (hinst);
|
|
}
|
|
return TRUE;
|
|
}
|