windows-nt/Source/XPSP1/NT/net/irda/irtranp/irtranp.cpp
2020-09-26 16:20:57 +08:00

800 lines
22 KiB
C++

//---------------------------------------------------------------------
// Copyright (C)1998 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.
//
//---------------------------------------------------------------------
#include "precomp.h"
#include <mbstring.h>
#include "irrecv.h"
#include "eventlog.h"
#define WSZ_REG_KEY_IRTRANP L"Control Panel\\Infrared\\IrTranP"
#define WSZ_REG_DISABLE_IRCOMM L"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
{IRTRANP_SERVICE, FALSE, STATUS_STOPPED },
{IRCOMM_9WIRE, TRUE, STATUS_STOPPED },
// {IR_TEST_SERVICE, FALSE, STATUS_STOPPED }, 2nd test listen port.
{0, FALSE, STATUS_STOPPED }
};
#define INDEX_IRTRANPV1 0
#define INDEX_IRCOMM 1
CCONNECTION_MAP *g_pConnectionMap = 0;
CIOSTATUS *g_pIoStatus = 0;
HANDLE g_hShutdownEvent;
//
// The following globals and functions are defined in ..\irxfer\irxfer.cxx
//
extern "C" HINSTANCE ghInstance;
extern "C" HANDLE g_UserToken;
extern HKEY g_hUserKey;
extern BOOL g_fDisableIrTranPv1;
extern BOOL g_fDisableIrCOMM;
extern BOOL g_fExploreOnCompletion;
extern BOOL g_fSaveAsUPF;
extern wchar_t g_DefaultPicturesFolder[];
extern wchar_t g_SpecifiedPicturesFolder[];
extern BOOL g_fAllowReceives;
extern BOOL IrTranPFlagChanged( IN const WCHAR *pwszDisabledValueName,
IN BOOL NotPresentValue,
IN OUT BOOL *pfDisabled );
//---------------------------------------------------------------------
// 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 ghInstance;
}
//---------------------------------------------------------------------
// GetRpcBinding()
//
//---------------------------------------------------------------------
handle_t GetRpcBinding()
{
if (g_pIoStatus)
{
return g_pIoStatus->GetRpcBinding();
}
else
{
return 0;
}
}
//---------------------------------------------------------------------
// 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;
}
//---------------------------------------------------------------------
// GetUserDirectory();
//
// The "main" part of irxfer.dll (in ..\irxfer) maintains the path
// for My Documents\My Pictures for the currently logged in user.
//
// The path is set when the user first logs on.
//---------------------------------------------------------------------
WCHAR *GetUserDirectory()
{
WCHAR *pwszPicturesFolder;
if (g_SpecifiedPicturesFolder[0])
{
pwszPicturesFolder = g_SpecifiedPicturesFolder;
}
else if (g_DefaultPicturesFolder[0])
{
pwszPicturesFolder = g_DefaultPicturesFolder;
}
else
{
DWORD dwLen;
if ( ((dwLen=GetWindowsDirectory(g_DefaultPicturesFolder,MAX_PATH)) > 0)
&& (dwLen < MAX_PATH) && (dwLen > 0) )
{
g_DefaultPicturesFolder[2] = 0; // Just want "C:"...
wcscat(g_DefaultPicturesFolder,WSZ_BACKUP_MY_PICTURES);
}
else
{
wcscpy(g_DefaultPicturesFolder,WSZ_BACKUP_DRIVE);
wcscat(g_DefaultPicturesFolder,WSZ_BACKUP_MY_PICTURES);
}
pwszPicturesFolder = g_DefaultPicturesFolder;
}
return pwszPicturesFolder;
}
//---------------------------------------------------------------------
// 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;
BOOL fDisabled = FALSE;
if (g_pConnectionMap == NULL) {
return NO_ERROR;
}
// See if the connection already exists:
if (g_pConnectionMap->LookupByServiceName(pszService))
{
return NO_ERROR;
}
#if 0
// Check the registry to see if IrTran-P on this service port is
// enabled. If its disabled, the quit now...
DWORD dwLen = strlen(pszService);
WCHAR wszService[255];
ASSERT(dwLen < 255);
if (0 == MultiByteToWideChar( CP_ACP,
MB_PRECOMPOSED,
pszService,
1+dwLen,
wszService,
1+dwLen ))
{
dwStatus = GetLastError();
#ifdef DBG_ERROR
DbgPrint("SetupForListen(): InitializeForListen(%s): MultiByteToWideChar() Failed: %d\n", pszService, dwStatus);
#endif
// Ignore this error and continue on...
}
else
{
IrTranPFlagChanged( wszService, fIsIrCOMM,&fDisabled );
if (fDisabled)
{
return NO_ERROR;
}
}
#endif
// Makeup and initialize a new connection object:
pConnection = new CCONNECTION;
if (!pConnection)
{
return E_OUTOFMEMORY;
}
dwStatus = pConnection->InitializeForListen( pszService,
fIsIrCOMM,
hIoCompletionPort );
if (dwStatus)
{
#ifdef DBG_ERROR
DbgPrint("SetupForListen(): InitializeForListen(%s) failed: %d\n",
pszService, dwStatus );
#endif
return dwStatus;
}
pIoPacket = new CIOPACKET;
if (!pIoPacket)
{
#ifdef DBG_ERROR
DbgPrint("SetupForListen(): new CIOPACKET failed.\n");
#endif
return E_OUTOFMEMORY;
}
// Setup the IO packet:
dwStatus = pIoPacket->Initialize( PACKET_KIND_LISTEN,
pConnection->GetListenSocket(),
INVALID_SOCKET,
hIoCompletionPort );
if (dwStatus != NO_ERROR)
{
return dwStatus;
}
// Post the listen packet on the IO completion port:
dwStatus = pConnection->PostMoreIos(pIoPacket);
if (dwStatus != NO_ERROR)
{
return dwStatus;
}
pConnection->SetSocket(pIoPacket->GetSocket());
if (!g_pConnectionMap->Add(pConnection,pIoPacket->GetListenSocket()))
{
#ifdef DBG_ERROR
DbgPrint("SetupForListen(): Add(pConnection) ConnectionMap Failed.\n");
#endif
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:
if (!g_pConnectionMap)
{
// nothing to tear down...
return dwStatus;
}
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;
DWORD dwEventStatus = 0;
EVENT_LOG EventLog(WS_EVENT_SOURCE,&dwEventStatus);
#ifdef DBG_ERROR
if (dwEventStatus)
{
DbgPrint("IrTranP: Open EventLog failed: %d\n",dwEventStatus);
}
#endif
if (g_pIoStatus == NULL) {
return 0;
}
if (fDisable)
{
dwStatus = TeardownListenConnection(
aListenPorts[INDEX_IRCOMM].pszService);
#ifdef DBG_REGISTRY
DbgPrint("IrTranP: TeardownListenConnection(%s): %d\n",
aListenPorts[INDEX_IRCOMM].pszService,dwStatus);
#endif
if ((dwStatus == 0) && (dwEventStatus == 0))
{
EventLog.ReportInfo(CAT_IRTRANP,
MC_IRTRANP_STOPPED_IRCOMM);
}
}
else
{
dwStatus = SetupListenConnection(
aListenPorts[INDEX_IRCOMM].pszService,
aListenPorts[INDEX_IRCOMM].fIsIrCOMM,
g_pIoStatus->GetIoCompletionPort() );
#ifdef DBG_REGISTRY
DbgPrint("IrTranP: SetupListenConnection(%s): %d\n",
aListenPorts[INDEX_IRCOMM].pszService, dwStatus);
#endif
if (dwEventStatus == 0)
{
if (dwStatus)
{
EventLog.ReportError(CAT_IRTRANP,
MC_IRTRANP_IRCOM_FAILED,
dwStatus);
}
#ifdef DBG
else
{
EventLog.ReportInfo(CAT_IRTRANP,
MC_IRTRANP_STARTED_IRCOMM);
}
#endif
}
}
return dwStatus;
}
//---------------------------------------------------------------------
// EnableDisableIrTranPv1()
//
//---------------------------------------------------------------------
DWORD EnableDisableIrTranPv1( IN BOOL fDisable )
{
DWORD dwStatus;
if (g_pIoStatus == NULL) {
return 0;
}
if (fDisable)
{
dwStatus = TeardownListenConnection(
aListenPorts[INDEX_IRTRANPV1].pszService);
#ifdef DBG_REGISTRY
DbgPrint("IrTranP: TeardownListenConnection(%s): %d\n",
aListenPorts[INDEX_IRCOMM].pszService,dwStatus);
#endif
}
else
{
dwStatus = SetupListenConnection(
aListenPorts[INDEX_IRTRANPV1].pszService,
aListenPorts[INDEX_IRTRANPV1].fIsIrCOMM,
g_pIoStatus->GetIoCompletionPort() );
#ifdef DBG_REGISTRY
DbgPrint("IrTranP: SetupListenConnection(%s): %d\n",
aListenPorts[INDEX_IRCOMM].pszService, dwStatus);
#endif
}
return dwStatus;
}
//---------------------------------------------------------------------
// IrTranp()
//
// Thread function for the IrTran-P service. pvRpcBinding is the RPC
// connection to the IR user interface and is used to display the
// "transmission in progress" dialog when pictures are being received.
//---------------------------------------------------------------------
DWORD WINAPI IrTranP( IN void *pvRpcBinding )
{
int i = 0;
WSADATA wsaData;
WORD wVersion = MAKEWORD(1,1);
DWORD dwStatus;
DWORD dwEventStatus;
CCONNECTION *pConnection;
// Initialize Memory Management:
dwStatus = InitializeMemory();
if (dwStatus)
{
return dwStatus;
}
// Initialize Winsock2:
if (WSAStartup(wVersion,&wsaData) == SOCKET_ERROR)
{
dwStatus = WSAGetLastError();
#ifdef DBG_ERROR
DbgPrint("WSAStartup(0x%x) failed with error %d\n",
wVersion, dwStatus );
#endif
return dwStatus;
}
// Event used to signal back to "main" thread that the
// IrTran-P thread is exiting.
g_hShutdownEvent = CreateEvent( NULL, // No security.
FALSE, // Auto-reset.
FALSE, // Initially not signaled.
NULL ); // No name.
if (!g_hShutdownEvent)
{
dwStatus = GetLastError();
return dwStatus;
}
// Create/initialize a object to keep track of the threading...
g_pIoStatus = new CIOSTATUS;
if (!g_pIoStatus)
{
#ifdef DBG_ERROR
DbgPrint("new CIOSTATUS failed.\n");
#endif
WSACleanup();
return E_OUTOFMEMORY;
}
g_pIoStatus->SaveRpcBinding( (handle_t*)pvRpcBinding );
dwStatus = g_pIoStatus->Initialize();
if (dwStatus != NO_ERROR)
{
#ifdef DBG_ERROR
DbgPrint("g_pIoStatus->Initialize(): Failed: %d\n",dwStatus);
#endif
WSACleanup();
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)
{
WSACleanup();
return E_OUTOFMEMORY;
}
if (!g_pConnectionMap->Initialize())
{
delete g_pConnectionMap;
g_pConnectionMap = 0;
return 1;
}
#if 0
// Create a CIOPACKET for each defined listen port. These are
// what we will listen on.
while (aListenPorts[i].pszService)
{
dwStatus = SetupListenConnection( aListenPorts[i].pszService,
aListenPorts[i].fIsIrCOMM,
g_pIoStatus->GetIoCompletionPort() );
if (dwStatus)
{
delete g_pConnectionMap;
g_pConnectionMap = 0;
return dwStatus;
}
aListenPorts[i++].dwListenStatus = STATUS_RUNNING;
}
#else
//
// just irtanpv1
//
i=INDEX_IRTRANPV1;
dwStatus = SetupListenConnection( aListenPorts[i].pszService,
aListenPorts[i].fIsIrCOMM,
g_pIoStatus->GetIoCompletionPort() );
if (dwStatus) {
delete g_pConnectionMap;
g_pConnectionMap = 0;
return dwStatus;
}
aListenPorts[i].dwListenStatus = STATUS_RUNNING;
#endif
//
// IrTran-P started, log it to the system log...
//
#ifdef DBG
{
EVENT_LOG EventLog(WS_EVENT_SOURCE,&dwEventStatus);
if (dwEventStatus == 0)
{
EventLog.ReportInfo(CAT_IRTRANP,MC_IRTRANP_STARTED);
}
}
#endif
//
// Wait on incomming connections and data, then process it.
//
dwStatus = ProcessIoPackets(g_pIoStatus);
// 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 (RegCreateKeyExW(hUserKey,
WSZ_REG_KEY_IRTRANP,
0, // reserved MBZ
0, // class name
REG_OPTION_NON_VOLATILE,
KEY_SET_VALUE,
0, // security attributes
&hKey,
&dwDisposition))
{
#ifdef DBG_ERROR
DbgPrint("IrTranP: RegCreateKeyEx(): '%S' failed %d",
WSZ_REG_KEY_IRTRANP, GetLastError());
#endif
}
if ( (hKey)
&& (hUserToken)
&& (::ImpersonateLoggedOnUser(hUserToken)))
{
DWORD dwDisableIrCOMM = TRUE;
dwStatus = RegSetValueExW(hKey,
WSZ_REG_DISABLE_IRCOMM,
0,
REG_DWORD,
(UCHAR*)&dwDisableIrCOMM,
sizeof(dwDisableIrCOMM) );
#ifdef DBG_ERROR
if (dwStatus != ERROR_SUCCESS)
{
DbgPrint("IrTranP: Can't set DisableIrCOMM to TRUE in registry. Error: %d\n",dwStatus);
}
#endif
::RevertToSelf();
}
if (hKey)
{
RegCloseKey(hKey);
}
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);
}
}
//---------------------------------------------------------------------
// UninitializeIrTranP()
//
//---------------------------------------------------------------------
BOOL UninitializeIrTranP( HANDLE hThread )
{
BOOL fSuccess = TRUE;
DWORD dwStatus;
HANDLE hIoCP = g_pIoStatus->GetIoCompletionPort();
if (hIoCP != INVALID_HANDLE_VALUE)
{
if (!PostQueuedCompletionStatus(hIoCP,0,IOKEY_SHUTDOWN,0))
{
// Unexpected error...
dwStatus = GetLastError();
#ifdef DBG_IO
DbgPrint("UninitializeIrTranP(): PostQueuedCompletionStatus() Failed: %d\n",dwStatus);
#endif
}
while (WAIT_TIMEOUT == WaitForSingleObject(g_hShutdownEvent,0))
{
Sleep(100);
}
CloseHandle(g_hShutdownEvent);
}
// Shutdown memory management:
dwStatus = UninitializeMemory();
return fSuccess;
}
#if FALSE
//---------------------------------------------------------------------
// main()
//
//---------------------------------------------------------------------
int __cdecl main( int argc, char **argv )
{
DWORD dwStatus;
dwStatus = IrTranP( NULL );
return 0;
}
#endif