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.
826 lines
25 KiB
826 lines
25 KiB
//---------------------------------------------------------------------
|
|
// Copyright (c)1998-1999 Microsoft Corporation, All Rights Reserved.
|
|
//
|
|
// irtranp.cpp
|
|
//
|
|
// This file holds the main entry points for the IrTran-P service.
|
|
// IrTranP() is the entry point that starts the listening, and
|
|
// UninitializeIrTranP() shuts it down (and cleans everything up).
|
|
//
|
|
// Author:
|
|
//
|
|
// Edward Reus (edwardr) 02-26-98 Initial coding.
|
|
//
|
|
// Edward Reus (edwardr) 08-27-99 Finish modifications for
|
|
// WIA Millennium port.
|
|
//
|
|
// Note: Currently the Millennium version will only listen on IrCOMM.
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
#include "precomp.h"
|
|
#include <mbstring.h>
|
|
|
|
#define SZ_REG_KEY_IRTRANP "Control Panel\\Infrared\\IrTranP"
|
|
#define SZ_REG_DISABLE_IRCOMM "DisableIrCOMM"
|
|
|
|
//---------------------------------------------------------------------
|
|
// Listen ports array:
|
|
//---------------------------------------------------------------------
|
|
|
|
typedef struct _LISTEN_PORT
|
|
{
|
|
char *pszService; // Service to start.
|
|
BOOL fIsIrCOMM; // TRUE iff IrCOMM 9-wire mode.
|
|
DWORD dwListenStatus; // Status for port.
|
|
} LISTEN_PORT;
|
|
|
|
static LISTEN_PORT aListenPorts[] =
|
|
{
|
|
// Service Name IrCOMM ListenStatus
|
|
{IRCOMM_9WIRE, TRUE, STATUS_STOPPED },
|
|
// {IRTRANP_SERVICE, FALSE, STATUS_STOPPED },
|
|
// {IR_TEST_SERVICE, FALSE, STATUS_STOPPED }, 2nd test listen port.
|
|
{0, FALSE, STATUS_STOPPED }
|
|
};
|
|
|
|
#define INDEX_IRCOMM 0
|
|
#define INDEX_IRTRANPV1 1
|
|
|
|
CCONNECTION_MAP *g_pConnectionMap = 0;
|
|
CIOSTATUS *g_pIoStatus = 0;
|
|
HANDLE g_hShutdownEvent;
|
|
|
|
BOOL g_fShuttingDownTRANPThread = FALSE;
|
|
DWORD g_dwTRANPThreadId = 0;
|
|
|
|
extern HINSTANCE g_hInst; // Handle to ircamera.dll USD
|
|
|
|
//---------------------------------------------------------------------
|
|
// Globals:
|
|
//---------------------------------------------------------------------
|
|
|
|
HANDLE g_UserToken = NULL;
|
|
HKEY g_hUserKey = NULL;
|
|
BOOL g_fDisableIrTranPv1 = FALSE;
|
|
BOOL g_fDisableIrCOMM = FALSE;
|
|
BOOL g_fExploreOnCompletion = TRUE;
|
|
BOOL g_fSaveAsUPF = FALSE;
|
|
BOOL g_fAllowReceives = TRUE;
|
|
|
|
char *g_pszTempPicturesFolder = 0;
|
|
|
|
BOOL g_fWSAStartupCalled = FALSE;
|
|
|
|
void *g_pvIrUsdDevice = 0; // WIA IrUsdDevice Object.
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
// GetUserToken()
|
|
//
|
|
// The "main" part of irxfer.dll (in ..\irxfer) maintains a token
|
|
// for user that is currently logged in (if any).
|
|
//---------------------------------------------------------------------
|
|
HANDLE GetUserToken()
|
|
{
|
|
return g_UserToken;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// GetUserKey()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
HKEY GetUserKey()
|
|
{
|
|
return g_hUserKey;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// GetModule()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
HINSTANCE GetModule()
|
|
{
|
|
return g_hInst;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// CheckSaveAsUPF()
|
|
//
|
|
// Return TRUE iff pictures need to be saved in .UPF (as opposed to
|
|
// .JPEG) format.
|
|
//---------------------------------------------------------------------
|
|
BOOL CheckSaveAsUPF()
|
|
{
|
|
return g_fSaveAsUPF;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// CheckExploreOnCompletion()
|
|
//
|
|
// Return TRUE iff we want to popup an explorer on the directory
|
|
// containing the newly transfered pictures.
|
|
//---------------------------------------------------------------------
|
|
BOOL CheckExploreOnCompletion()
|
|
{
|
|
return g_fExploreOnCompletion;
|
|
}
|
|
|
|
|
|
/* FlushInputQueue is a private routine to collect and dispatch all
|
|
* messages in the input queue. It returns TRUE if a WM_QUIT message
|
|
* was detected in the queue, FALSE otherwise.
|
|
*/
|
|
BOOL FlushInputQueue(VOID)
|
|
{
|
|
MSG msgTemp;
|
|
while (PeekMessage(&msgTemp, NULL, 0, 0, PM_REMOVE)) {
|
|
DispatchMessage(&msgTemp);
|
|
|
|
// If we see a WM_QUIT in the queue, we need to do the same
|
|
// sort of thing that a modal dialog does: break out of our
|
|
// waiting, and repost the WM_QUIT to the queue so that the
|
|
// next message loop up in the app will also see it.
|
|
if (msgTemp.message == WM_QUIT) {
|
|
PostQuitMessage((int)msgTemp.wParam);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/* WaitAndYield() waits for the specified object using
|
|
* MsgWaitForMultipleObjects. If messages are received,
|
|
* they are dispatched and waiting continues. The return
|
|
* value is the same as from MsgWaitForMultipleObjects.
|
|
*/
|
|
DWORD WaitAndYield(HANDLE hObject, DWORD dwTimeout)
|
|
{
|
|
DWORD dwTickCount, dwWakeReason, dwTemp;
|
|
|
|
do {
|
|
/* Flush any messages before we wait. This is because
|
|
* MsgWaitForMultipleObjects will only return when NEW
|
|
* messages are put in the queue.
|
|
*/
|
|
if (FlushInputQueue()) {
|
|
dwWakeReason = WAIT_TIMEOUT;
|
|
break;
|
|
}
|
|
|
|
// in case we handle messages, we want close to a true timeout
|
|
if ((dwTimeout != 0) &&
|
|
(dwTimeout != (DWORD)-1)) {
|
|
// if we can timeout, store the current tick count
|
|
// every time through
|
|
dwTickCount = GetTickCount();
|
|
}
|
|
dwWakeReason = MsgWaitForMultipleObjects(1,
|
|
&hObject,
|
|
FALSE,
|
|
dwTimeout,
|
|
QS_ALLINPUT);
|
|
// if we got a message, dispatch it, then try again
|
|
if (dwWakeReason == 1) {
|
|
// if we can timeout, see if we did before processing the message
|
|
// that way, if we haven't timed out yet, we'll get at least one
|
|
// more shot at the event
|
|
if ((dwTimeout != 0) &&
|
|
(dwTimeout != (DWORD)-1)) {
|
|
if ((dwTemp = (GetTickCount()-dwTickCount)) >= dwTimeout) {
|
|
// if we timed out, make us drop through
|
|
dwWakeReason = WAIT_TIMEOUT;
|
|
} else {
|
|
// subtract elapsed time from timeout and continue
|
|
// (we don't count time spent dispatching message)
|
|
dwTimeout -= dwTemp;
|
|
}
|
|
}
|
|
if (FlushInputQueue()) {
|
|
dwWakeReason = WAIT_TIMEOUT;
|
|
break;
|
|
}
|
|
}
|
|
} while (dwWakeReason == 1);
|
|
|
|
return dwWakeReason;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
// GetImageDirectory();
|
|
//
|
|
// This is the temporary directory where the pictures sent by the
|
|
// camera will be held. WIA will then "down load" these to their
|
|
// final destination (usually this will be My Pictures).
|
|
//
|
|
//---------------------------------------------------------------------
|
|
CHAR *GetImageDirectory()
|
|
{
|
|
char *pszPicturesFolder;
|
|
char szTempFolder[1+MAX_PATH];
|
|
DWORD dwPicturesFolderLen;
|
|
DWORD dwStatus = NO_ERROR;
|
|
DWORD dwLen;
|
|
|
|
|
|
if (!g_pszTempPicturesFolder)
|
|
{
|
|
dwLen = GetTempPath(MAX_PATH,szTempFolder);
|
|
|
|
if ((!dwLen)||(dwLen > MAX_PATH))
|
|
{
|
|
dwStatus = GetLastError();
|
|
WIAS_TRACE((g_hInst,"GetUserDirectroy(): GetTempPath() failed: %d",dwStatus));
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Make sure the directory exists:
|
|
//
|
|
if (!CreateDirectory(szTempFolder,0))
|
|
{
|
|
dwStatus = GetLastError();
|
|
if ( (dwStatus == ERROR_ALREADY_EXISTS)
|
|
|| (dwStatus == ERROR_ACCESS_DENIED) )
|
|
{
|
|
dwStatus = NO_ERROR;
|
|
}
|
|
else if (dwStatus != NO_ERROR)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Construct the subdirectory path string that will actually hold the pictures:
|
|
// This will be something like: C:\temp\irtranp
|
|
//
|
|
dwPicturesFolderLen = sizeof(CHAR)*( strlen(szTempFolder)
|
|
+ sizeof(SZ_SLASH)
|
|
+ sizeof(SZ_SUBDIRECTORY)
|
|
+ 1 );
|
|
|
|
g_pszTempPicturesFolder = (CHAR*)AllocateMemory(dwPicturesFolderLen);
|
|
|
|
if (!g_pszTempPicturesFolder)
|
|
{
|
|
return 0; // Memory allocation failed!
|
|
}
|
|
|
|
strcpy(g_pszTempPicturesFolder,szTempFolder);
|
|
if (szTempFolder[dwLen-1] != SLASH)
|
|
{
|
|
strcat(g_pszTempPicturesFolder,SZ_SLASH);
|
|
}
|
|
strcat(g_pszTempPicturesFolder,SZ_SUBDIRECTORY);
|
|
|
|
//
|
|
// Make sure the subdirectory exists:
|
|
//
|
|
if (!CreateDirectory(g_pszTempPicturesFolder,0))
|
|
{
|
|
dwStatus = GetLastError();
|
|
if (dwStatus == ERROR_ALREADY_EXISTS)
|
|
{
|
|
dwStatus = NO_ERROR;
|
|
}
|
|
else if (dwStatus != NO_ERROR)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
pszPicturesFolder = g_pszTempPicturesFolder;
|
|
|
|
return pszPicturesFolder;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// ReceivesAllowed()
|
|
//
|
|
// Using the IR configuration window (available from the wireless network
|
|
// icon in the control panel) you can disable communications with IR
|
|
// devices. This function returns the state of IR communications, FALSE
|
|
// is disabled, TRUE is enabled.
|
|
//---------------------------------------------------------------------
|
|
BOOL ReceivesAllowed()
|
|
{
|
|
return g_fAllowReceives;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// SetupListenConnection()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
DWORD SetupListenConnection( IN CHAR *pszService,
|
|
IN BOOL fIsIrCOMM,
|
|
IN HANDLE hIoCompletionPort )
|
|
{
|
|
DWORD dwStatus = NO_ERROR;
|
|
CIOPACKET *pIoPacket;
|
|
CCONNECTION *pConnection;
|
|
|
|
// See if the connection already exists:
|
|
if (g_pConnectionMap->LookupByServiceName(pszService))
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
|
|
// Makeup and initialize a new connection object:
|
|
pConnection = new CCONNECTION;
|
|
if (!pConnection)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
dwStatus = pConnection->InitializeForListen( pszService,
|
|
fIsIrCOMM,
|
|
hIoCompletionPort );
|
|
if (dwStatus)
|
|
{
|
|
WIAS_ERROR((g_hInst,"SetupForListen(): InitializeForListen(%s) failed: %d",pszService, dwStatus));
|
|
return dwStatus;
|
|
}
|
|
|
|
pIoPacket = new CIOPACKET;
|
|
if (!pIoPacket)
|
|
{
|
|
WIAS_ERROR((g_hInst,"SetupForListen(): new CIOPACKET failed"));
|
|
delete pConnection;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Setup the IO packet:
|
|
dwStatus = pIoPacket->Initialize( PACKET_KIND_LISTEN,
|
|
pConnection->GetListenSocket(),
|
|
INVALID_SOCKET,
|
|
hIoCompletionPort );
|
|
if (dwStatus != NO_ERROR)
|
|
{
|
|
return dwStatus;
|
|
}
|
|
|
|
pConnection->SetSocket(pIoPacket->GetSocket());
|
|
|
|
if (!g_pConnectionMap->Add(pConnection,pIoPacket->GetListenSocket()))
|
|
{
|
|
WIAS_ERROR((g_hInst,"SetupForListen(): Add(pConnection) ConnectionMap Failed."));
|
|
return 1;
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// TeardownListenConnection()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
DWORD TeardownListenConnection( IN char *pszService )
|
|
{
|
|
DWORD dwStatus = NO_ERROR;
|
|
CCONNECTION *pConnection;
|
|
|
|
// Look for the connection associated with the service name:
|
|
pConnection = g_pConnectionMap->LookupByServiceName(pszService);
|
|
|
|
if (pConnection)
|
|
{
|
|
g_pConnectionMap->RemoveConnection(pConnection);
|
|
pConnection->CloseSocket();
|
|
pConnection->CloseListenSocket();
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
// EnableDisableIrCOMM()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
DWORD EnableDisableIrCOMM( IN BOOL fDisable )
|
|
{
|
|
DWORD dwStatus;
|
|
|
|
|
|
if (fDisable)
|
|
{
|
|
dwStatus = TeardownListenConnection(
|
|
aListenPorts[INDEX_IRCOMM].pszService);
|
|
WIAS_ERROR((g_hInst,"IrTranP: TeardownListenConnection(%s): %d", aListenPorts[INDEX_IRCOMM].pszService,dwStatus));
|
|
}
|
|
else
|
|
{
|
|
dwStatus = SetupListenConnection(
|
|
aListenPorts[INDEX_IRCOMM].pszService,
|
|
aListenPorts[INDEX_IRCOMM].fIsIrCOMM,
|
|
g_pIoStatus->GetIoCompletionPort() );
|
|
|
|
WIAS_TRACE((g_hInst,"IrTranP: SetupListenConnection(%s): %d", aListenPorts[INDEX_IRCOMM].pszService, dwStatus));
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// EnableDisableIrTranPv1()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
DWORD EnableDisableIrTranPv1( IN BOOL fDisable )
|
|
{
|
|
DWORD dwStatus;
|
|
|
|
if (fDisable)
|
|
{
|
|
dwStatus = TeardownListenConnection(
|
|
aListenPorts[INDEX_IRTRANPV1].pszService);
|
|
}
|
|
else
|
|
{
|
|
dwStatus = SetupListenConnection(
|
|
aListenPorts[INDEX_IRTRANPV1].pszService,
|
|
aListenPorts[INDEX_IRTRANPV1].fIsIrCOMM,
|
|
g_pIoStatus->GetIoCompletionPort() );
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// IrTranp()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
DWORD WINAPI IrTranP( IN void *pvIrUsdDevice )
|
|
{
|
|
int i = 0;
|
|
WSADATA wsaData;
|
|
WORD wVersion = MAKEWORD(1,1);
|
|
DWORD dwStatus;
|
|
CCONNECTION *pConnection;
|
|
|
|
g_dwTRANPThreadId = ::GetCurrentThreadId();
|
|
|
|
//
|
|
// Initialize Memory Management:
|
|
//
|
|
dwStatus = InitializeMemory();
|
|
if (dwStatus)
|
|
{
|
|
WIAS_ERROR((g_hInst,"IrTranP(): InitializeMemory() failed: %d\n",dwStatus));
|
|
return dwStatus;
|
|
}
|
|
|
|
//
|
|
// This directory will be set as needed. It is only non-null in the case
|
|
// where we are re-starting the IrTran-P thread:
|
|
//
|
|
if (g_pszTempPicturesFolder)
|
|
{
|
|
FreeMemory(g_pszTempPicturesFolder);
|
|
g_pszTempPicturesFolder = 0;
|
|
}
|
|
|
|
//
|
|
// Initialize Winsock2 if neccessary:
|
|
//
|
|
if (!g_fWSAStartupCalled)
|
|
{
|
|
if (WSAStartup(wVersion,&wsaData) == SOCKET_ERROR)
|
|
{
|
|
dwStatus = WSAGetLastError();
|
|
WIAS_ERROR((g_hInst,"WSAStartup(0x%x) failed with error %d\n", wVersion, dwStatus ));
|
|
return dwStatus;
|
|
}
|
|
|
|
g_fWSAStartupCalled = TRUE;
|
|
}
|
|
|
|
// Event used to signal back to "main" thread that the
|
|
// IrTran-P thread is exiting.
|
|
//
|
|
// NoSecurity, Auto-Reset, Initially Not Signaled, No Name.
|
|
//
|
|
g_hShutdownEvent = CreateEventA( NULL, FALSE, FALSE, NULL );
|
|
|
|
if (!g_hShutdownEvent)
|
|
{
|
|
dwStatus = GetLastError();
|
|
WIAS_ERROR((g_hInst,"IrTranP(): CreateEvent() Failed: %d",dwStatus));
|
|
return dwStatus;
|
|
}
|
|
|
|
// Create/initialize a object to keep track of the threading...
|
|
g_pIoStatus = new CIOSTATUS;
|
|
if (!g_pIoStatus)
|
|
{
|
|
WIAS_ERROR((g_hInst,"new CIOSTATUS failed."));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
dwStatus = g_pIoStatus->Initialize();
|
|
if (dwStatus != NO_ERROR)
|
|
{
|
|
WIAS_ERROR((g_hInst,"g_pIoStatus->Initialize(): Failed: %d",dwStatus));
|
|
return dwStatus;
|
|
}
|
|
|
|
// Need to keep track of the open sockets and the number of
|
|
// pending IOs on each...
|
|
g_pConnectionMap = new CCONNECTION_MAP;
|
|
if (!g_pConnectionMap)
|
|
{
|
|
WIAS_ERROR((g_hInst,"new CCONNECTION_MAP failed."));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (!g_pConnectionMap->Initialize())
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
// Create a CIOPACKET for each defined listen port. These are
|
|
// what we will listen on.
|
|
|
|
//
|
|
// BUGBUG Should we really loop indefintely setting up connection or establish some limit on retries ? VS
|
|
//
|
|
while (!g_fShuttingDownTRANPThread )
|
|
{
|
|
dwStatus = SetupListenConnection(
|
|
aListenPorts[INDEX_IRCOMM].pszService,
|
|
aListenPorts[INDEX_IRCOMM].fIsIrCOMM,
|
|
g_pIoStatus->GetIoCompletionPort() );
|
|
|
|
if (dwStatus)
|
|
{
|
|
WIAS_TRACE((g_hInst,"SetupListenConnection(%s) Status: %d",aListenPorts[i].pszService,dwStatus));
|
|
//
|
|
// BUGBUG Analyze error and stop processing if it doesn't make sense !!! VS
|
|
//
|
|
}
|
|
else
|
|
{
|
|
WIAS_TRACE((g_hInst,"SetupListenConnection(%s) Ready",aListenPorts[i].pszService));
|
|
aListenPorts[INDEX_IRCOMM].dwListenStatus = STATUS_RUNNING;
|
|
break;
|
|
}
|
|
|
|
// Wait for timeout period, but wake up if we need to stop
|
|
// Sleep(5000);
|
|
WaitAndYield(g_hShutdownEvent,5000);
|
|
}
|
|
|
|
if (!g_fShuttingDownTRANPThread) {
|
|
|
|
//
|
|
// Wait on incomming connections and data, then process it.
|
|
//
|
|
g_pvIrUsdDevice = pvIrUsdDevice;
|
|
|
|
dwStatus = ProcessIoPackets(g_pIoStatus);
|
|
|
|
}
|
|
|
|
//
|
|
// Shutting down
|
|
//
|
|
g_pvIrUsdDevice = 0;
|
|
|
|
WIAS_TRACE((g_hInst,"ProcessIoPackets(): dwStatus: %d",dwStatus));
|
|
|
|
//
|
|
// Cleanup and close any open handles:
|
|
//
|
|
while (pConnection=g_pConnectionMap->RemoveNext())
|
|
{
|
|
delete pConnection;
|
|
}
|
|
|
|
delete g_pConnectionMap;
|
|
g_pConnectionMap = 0;
|
|
delete g_pIoStatus;
|
|
g_pIoStatus = 0;
|
|
|
|
// Signal the shutdown event that the IrTran-P thread is exiting:
|
|
if (g_hShutdownEvent)
|
|
{
|
|
SetEvent(g_hShutdownEvent);
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// IrTranPEnableIrCOMMFailed()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
void IrTranPEnableIrCOMMFailed( DWORD dwErrorCode )
|
|
{
|
|
DWORD dwStatus;
|
|
|
|
// An error occured on enable, make sure the registry value
|
|
// is set to disable (so UI will match the actual state).
|
|
HKEY hKey = 0;
|
|
HKEY hUserKey = GetUserKey();
|
|
HANDLE hUserToken = GetUserToken();
|
|
HINSTANCE hInstance = GetModule();
|
|
DWORD dwDisposition;
|
|
|
|
if (RegCreateKeyEx(hUserKey,
|
|
SZ_REG_KEY_IRTRANP,
|
|
0, // reserved MBZ
|
|
0, // class name
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_SET_VALUE,
|
|
0, // security attributes
|
|
&hKey,
|
|
&dwDisposition))
|
|
{
|
|
WIAS_TRACE((g_hInst,"IrTranP: RegCreateKeyEx(): '%' failed %d", SZ_REG_KEY_IRTRANP, GetLastError()));
|
|
}
|
|
|
|
if ( (hKey)
|
|
&& (hUserToken)
|
|
&& (::ImpersonateLoggedOnUser(hUserToken)))
|
|
{
|
|
DWORD dwDisableIrCOMM = TRUE;
|
|
dwStatus = RegSetValueEx(hKey,
|
|
SZ_REG_DISABLE_IRCOMM,
|
|
0,
|
|
REG_DWORD,
|
|
(UCHAR*)&dwDisableIrCOMM,
|
|
sizeof(dwDisableIrCOMM) );
|
|
if (dwStatus != ERROR_SUCCESS)
|
|
{
|
|
WIAS_TRACE((g_hInst,"IrTranP: Can't set DisableIrCOMM to TRUE in registry. Error: %d",dwStatus));
|
|
}
|
|
|
|
::RevertToSelf();
|
|
}
|
|
|
|
if (hKey)
|
|
{
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
#if FALSE
|
|
WCHAR *pwszMessage = NULL;
|
|
WCHAR *pwszCaption = NULL;
|
|
DWORD dwFlags = ( FORMAT_MESSAGE_ALLOCATE_BUFFER
|
|
| FORMAT_MESSAGE_IGNORE_INSERTS
|
|
| FORMAT_MESSAGE_FROM_HMODULE);
|
|
|
|
dwStatus = FormatMessageW(dwFlags,
|
|
hInstance,
|
|
CAT_IRTRANP,
|
|
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
|
|
(LPTSTR)(&pwszCaption),
|
|
0, // Minimum size to allocate.
|
|
NULL); // va_list args...
|
|
if (dwStatus == 0)
|
|
{
|
|
#ifdef DBG_ERROR
|
|
DbgPrint("IrTranP: FormatMessage() failed: %d\n",GetLastError() );
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Hack: Make sure the caption doesn't end with newline-formfeed...
|
|
//
|
|
WCHAR *pwsz = pwszCaption;
|
|
|
|
while (*pwsz)
|
|
{
|
|
if (*pwsz < 0x20) // 0x20 is always a space...
|
|
{
|
|
*pwsz = 0;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
pwsz++;
|
|
}
|
|
}
|
|
|
|
|
|
WCHAR wszErrorCode[20];
|
|
WCHAR *pwszErrorCode = (WCHAR*)wszErrorCode;
|
|
|
|
wsprintfW(wszErrorCode,L"%d",dwErrorCode);
|
|
|
|
dwFlags = ( FORMAT_MESSAGE_ALLOCATE_BUFFER
|
|
| FORMAT_MESSAGE_ARGUMENT_ARRAY
|
|
| FORMAT_MESSAGE_FROM_HMODULE);
|
|
|
|
dwStatus = FormatMessageW(dwFlags,
|
|
hInstance,
|
|
MC_IRTRANP_IRCOM_FAILED,
|
|
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
|
|
(LPTSTR)(&pwszMessage),
|
|
0, // Minimum size to allocate.
|
|
(va_list*)&pwszErrorCode);
|
|
if (dwStatus == 0)
|
|
{
|
|
#ifdef DBG_ERROR
|
|
DbgPrint("IrTranP: FormatMessage() failed: %d\n",GetLastError() );
|
|
#endif
|
|
|
|
if (pwszMessage)
|
|
{
|
|
LocalFree(pwszMessage);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
dwStatus = MessageBoxW( NULL,
|
|
pwszMessage,
|
|
pwszCaption,
|
|
(MB_OK|MB_ICONERROR|MB_SETFOREGROUND|MB_TOPMOST) );
|
|
|
|
if (pwszMessage)
|
|
{
|
|
LocalFree(pwszMessage);
|
|
}
|
|
|
|
if (pwszCaption)
|
|
{
|
|
LocalFree(pwszCaption);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// UninitializeIrTranP()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
BOOL UninitializeIrTranP( HANDLE hThread )
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
DWORD dwStatus;
|
|
HANDLE hIoCP = g_pIoStatus->GetIoCompletionPort();
|
|
|
|
g_fShuttingDownTRANPThread = TRUE;
|
|
|
|
// Inform TRANP thread it has to die
|
|
::PostThreadMessage(g_dwTRANPThreadId,WM_QUIT,0,0);
|
|
|
|
if (hIoCP != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (!PostQueuedCompletionStatus(hIoCP,0,IOKEY_SHUTDOWN,0))
|
|
{
|
|
// Unexpected error...
|
|
dwStatus = GetLastError();
|
|
}
|
|
|
|
while (WAIT_TIMEOUT == WaitForSingleObject(g_hShutdownEvent,0))
|
|
{
|
|
Sleep(100);
|
|
}
|
|
|
|
CloseHandle(g_hShutdownEvent);
|
|
}
|
|
|
|
//
|
|
// TRANP thread should be dead by now . In case it isn't wait on it's handle and terminate
|
|
// Otherwise we have a small chance of unloading DLL before thread is dead, shutting down WIA service
|
|
//
|
|
dwStatus = ::WaitForSingleObject(hThread,100);
|
|
if (dwStatus == WAIT_TIMEOUT) {
|
|
// Have to be rude
|
|
// BUGBUG Assert
|
|
::TerminateThread(hThread,NOERROR);
|
|
}
|
|
|
|
// Shutdown memory management:
|
|
dwStatus = UninitializeMemory();
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
#ifdef RUN_AS_EXE
|
|
|
|
//---------------------------------------------------------------------
|
|
// main()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
int __cdecl main( int argc, char **argv )
|
|
{
|
|
DWORD dwStatus;
|
|
|
|
printf("IrTran-P: Start\n");
|
|
|
|
dwStatus = IrTranP( NULL );
|
|
|
|
if (dwStatus)
|
|
{
|
|
printf("IrTran-P: Status: 0x%x (%d)\n",dwStatus,dwStatus);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|