Leaked source code of windows server 2003
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

//---------------------------------------------------------------------
// 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