/*++ Copyright (c) 1999 Microsoft Corporation Module Name: smbrdr.c Abstract: This module implements the functios to load and unload the smb monolithic minirdr. Also explicit start/stop control is provided This module also populates the registry entries for the driver, and the network provider. --*/ //#ifndef UNICODE //#define UNICODE //#endif #include #include #include #include "srfunc.h" #ifdef DBG #define DbgP(_x_) DbgPrint _x_ #else #define DbgP(_x_) #endif ULONG _cdecl DbgPrint( LPTSTR Format, ... ); #define TRACE_TAG L"SMBRDR: " TCHAR* SmbMrxDriverName = TEXT("SmbMRx"); // load action states ULONG_PTR LoadActionStates[] = { RDR_NULL_STATE, RDR_LOADING, RDR_NULL_STATE, RDR_NULL_STATE, RDR_NULL_STATE, RDR_NULL_STATE, RDR_NULL_STATE, RDR_NULL_STATE, RDR_NULL_STATE }; // unload action states ULONG_PTR UnloadActionStates[] = { RDR_NULL_STATE, RDR_NULL_STATE, RDR_NULL_STATE, RDR_NULL_STATE, RDR_UNLOADING, RDR_UNLOADING, RDR_NULL_STATE, RDR_NULL_STATE, RDR_NULL_STATE }; // Start action states ULONG_PTR StartActionStates[] = { RDR_NULL_STATE, RDR_NULL_STATE, RDR_NULL_STATE, RDR_NULL_STATE, RDR_STARTING, RDR_STARTING, RDR_NULL_STATE, RDR_NULL_STATE, RDR_NULL_STATE }; // Stop action states ULONG_PTR StopActionStates[] = { RDR_NULL_STATE, RDR_NULL_STATE, RDR_NULL_STATE, RDR_NULL_STATE, RDR_NULL_STATE, RDR_NULL_STATE, RDR_NULL_STATE, RDR_NULL_STATE, RDR_STOPPING }; ULONG_PTR TransitionActionStates[] = { RDR_NULL_STATE, RDR_NULL_STATE, RDR_UNLOADED, RDR_LOADED, RDR_NULL_STATE, RDR_NULL_STATE, RDR_STOPPED, RDR_STARTED, RDR_NULL_STATE }; ULONG_PTR ErrorActionStates[] = { RDR_NULL_STATE, RDR_NULL_STATE, RDR_LOADED, RDR_UNLOADED, RDR_NULL_STATE, RDR_NULL_STATE, RDR_STARTED, RDR_STOPPED, RDR_NULL_STATE }; ULONG_PTR NoneActionStates[] = { RDR_NULL_STATE, RDR_UNLOADED, RDR_UNLOADING, RDR_LOADING, RDR_LOADED, RDR_STOPPED, RDR_STOPPING, RDR_STARTING, RDR_STARTED }; ULONG_PTR *ActionsStatesArray[] = { LoadActionStates, UnloadActionStates, StartActionStates, StopActionStates, TransitionActionStates, ErrorActionStates, NoneActionStates }; ACTIONVECTOR ActionProcs[] = { RdrLoad, RdrUnload, RdrStart, RdrStop, RdrDoNothing, RdrDoNothing, RdrDoNothing }; typedef enum _INSTALLCHECKS { installcheck_start, installcheck_driverfile, installcheck_providerfile, installcheck_serviceentry, installcheck_providerorder, installcheck_stop, installcheck_done }; ULONG_PTR RdrInstallCheck( void ) { TCHAR tszTestPath[_MAX_PATH]; ULONG_PTR teststep; ULONG len = 0; ULONG_PTR tc = SETUP_COMPLETE; HANDLE th; for ( teststep = installcheck_start; teststep < installcheck_done; teststep++ ) { switch ( teststep ) { case installcheck_start: { len = GetWindowsDirectory( tszTestPath, _MAX_PATH ); } break; case installcheck_driverfile: { lstrcpyn( &tszTestPath[len], DRIVER_FILE_PATH, _MAX_PATH - len ); th = CreateFile( tszTestPath, 0, 0, NULL, OPEN_EXISTING, 0, NULL ); if ( th == INVALID_HANDLE_VALUE ) { tc = SETUP_MISSING_FILE; teststep = installcheck_stop; } else { CloseHandle( th ); } } break; case installcheck_providerfile: { lstrcpyn( &tszTestPath[len], PROVIDER_FILE_PATH, _MAX_PATH - len ); th = CreateFile( tszTestPath, 0, 0, NULL, OPEN_EXISTING, 0, NULL ); if ( th == INVALID_HANDLE_VALUE ) { tc = SETUP_MISSING_FILE; teststep = installcheck_stop; } else { CloseHandle( th ); } } break; case installcheck_serviceentry: { HKEY hTestKey; if ( OpenKey( RDRSERVICE_KEY, &hTestKey ) ) { RegCloseKey( hTestKey ); } else { tc = SETUP_INCOMPLETE; teststep = installcheck_stop; } } break; case installcheck_providerorder: { LPTSTR pOrder; RdrGetProviderOrderString( &pOrder ); if ( pOrder ) { if ( !RdrFindProviderInOrder( pOrder, PROVIDER_NAME ) ) { tc = SETUP_INCOMPLETE; teststep = installcheck_stop; } free( pOrder ); } } break; case installcheck_stop: break; } } return tc; } BOOL RdrCompleteSetup( void ) { return RdrSetupServiceEntry( ) && RdrSetupProviderOrder( ); } // These handles are retained HANDLE hSharedMemory; HANDLE hMutex; BOOL RdrStart(void) /*++ Routine Description: This routine starts the SMB sample mini redirector. Notes: The start is distinguished from Load. During this phase the appropriate FSCTL is issued and the shared memory/mutex data structures required for the Network provider DLL are initialized. --*/ { HANDLE DeviceHandle; // The mini rdr device handle DWORD BytesRet; BOOL started = FALSE; // Grab a handle to the redirector device object DbgP((TEXT("Opening Rdr Device Object for Start Ioctl\n"))); DeviceHandle = CreateFile( DD_SMBMRX_USERMODE_DEV_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); DbgP((TEXT("returned from rdr device open\n"))); if ( DeviceHandle != INVALID_HANDLE_VALUE ) { DbgP(( TEXT("Issueing Rdr Start Ioctl\n") )); started = DeviceIoControl( DeviceHandle, IOCTL_SMBMRX_START, NULL, 0, NULL, 0, &BytesRet, NULL ); // Create a section of shared memory to serve as the connection database if ( started ) { DWORD Status; hSharedMemory = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(SMBMRXNP_SHARED_MEMORY), SMBMRXNP_SHARED_MEMORY_NAME); if (hSharedMemory == NULL) { Status = GetLastError(); DbgP((TEXT("SMB MRx Net Provider shared memory Creation status %lx\n"),Status)); } else { PSMBMRXNP_SHARED_MEMORY pSharedMemory; pSharedMemory = MapViewOfFile(hSharedMemory, FILE_MAP_WRITE, 0, 0, 0); if (pSharedMemory != NULL) { pSharedMemory->HighestIndexInUse = -1; pSharedMemory->NumberOfResourcesInUse = 0; } UnmapViewOfFile(pSharedMemory); } hMutex = CreateMutex( NULL, FALSE, SMBMRXNP_MUTEX_NAME); if (hMutex == NULL) { Status = GetLastError(); DbgP(( TEXT("SMB MRx Net Provider Mutex Creation status %lx\n"), Status)); } } else { DbgP(( TEXT("The DeviceIoctl for Starting Redirector returned %lx\n"), GetLastError() )); } } else { DbgP(( TEXT("The CreateFile for opening device failed with error 0x%lx\n"), GetLastError() )); DbgP(( TEXT("Device is %s\n"),DD_SMBMRX_USERMODE_DEV_NAME )); } //DbgP((TEXT("SMB MRx sample mini redirector start status %lx\n"),ntstatus)); CloseHandle(DeviceHandle); return started; } BOOL RdrStop( void ) /*++ Routine Description: This routine stops the SMB sample mini redirector. Notes: The stop is distinguished from unload. During this phase the appropriate FSCTL is issued and the shared memory/mutex data structures required for the Network provider DLL are torn down. --*/ { HANDLE DeviceHandle; // The mini rdr device handle DWORD BytesRet; BOOL stopped = FALSE; // Grab a handle to the redirector device object DeviceHandle = CreateFile( DD_SMBMRX_USERMODE_DEV_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); DbgP((TEXT("Doing Stop DeviceIoControl\n"))); if ( DeviceHandle != INVALID_HANDLE_VALUE ) { stopped = DeviceIoControl( DeviceHandle, IOCTL_SMBMRX_STOP, NULL, 0, NULL, 0, &BytesRet, NULL ); CloseHandle( DeviceHandle ); } else { DbgP(( TEXT("The CreateFile for opening device failed\n") )); } CloseHandle(hMutex); CloseHandle(hSharedMemory); // DbgP(( TEXT("SMB MRx sample mini redirector start status %lx\n"),ntstatus )); return stopped; } BOOL RdrLoad( void ) { SC_HANDLE sch, service; BOOL loaded = FALSE; DbgP((TEXT("Loading SMB sample minirdr.......\n"))); sch = OpenSCManager( NULL, NULL, GENERIC_EXECUTE ); if ( sch ) { service = OpenService( sch, RDRSERVICE, GENERIC_EXECUTE ); if ( service ) { loaded = StartService( service, 0, NULL ); CloseServiceHandle( service ); } CloseServiceHandle( sch ); } return loaded; } BOOL RdrUnload( void ) { SC_HANDLE sch, service; BOOL unloaded = FALSE; DbgP((TEXT("Unloading SMB sample minirdr.......\n"))); sch = OpenSCManager( NULL, NULL, GENERIC_EXECUTE ); if ( sch ) { service = OpenService( sch, RDRSERVICE, GENERIC_EXECUTE ); if ( service ) { SERVICE_STATUS ss; unloaded = ControlService( service, SERVICE_CONTROL_STOP, &ss ); CloseServiceHandle( service ); } CloseServiceHandle( sch ); } return unloaded; } BOOL RdrDoNothing( void ) { return TRUE; } BOOL RdrDoAction( ULONG_PTR action ) { return (*ActionProcs[action])( ); } ULONG_PTR RdrGetInitialState(void) { ULONG_PTR state = RDR_UNLOADED; SC_HANDLE sch, service; sch = OpenSCManager( NULL, NULL, GENERIC_READ ); if ( sch ) { service = OpenService( sch, RDRSERVICE, GENERIC_READ ); if ( service ) { SERVICE_STATUS ss; if ( QueryServiceStatus( service, &ss ) ) { switch ( ss.dwCurrentState ) { case SERVICE_STOPPED: state = RDR_UNLOADED; break; case SERVICE_START_PENDING: state = RDR_LOADING; break; case SERVICE_STOP_PENDING: state = RDR_UNLOADING; break; case SERVICE_RUNNING: state = RDR_LOADED; break; case SERVICE_CONTINUE_PENDING: case SERVICE_PAUSE_PENDING: case SERVICE_PAUSED: default: state = RDR_UNLOADED; break; } #if 0 //just check for load/unload state for now // go check the start/stop state if ( state == RDR_LOADED ) { BOOL IsOk; HANDLE DeviceHandle; DWORD BytesRet; ULONG_PTR RdrStateValue; DeviceHandle = CreateFile( DD_SMBMRX_USERMODE_DEV_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if ( DeviceHandle != INVALID_HANDLE_VALUE ) { DbgP((TEXT("Doing Get State DeviceIoControl\n"))); IsOk = DeviceIoControl( DeviceHandle, IOCTL_SMBMRX_GETSTATE, NULL, 0, &RdrStateValue, sizeof(ULONG), &BytesRet, NULL ); CloseHandle( DeviceHandle ); } if ( IsOk ) { state = RdrStateValue; } } #endif } CloseServiceHandle( service ); } CloseServiceHandle( sch ); } return state; } ULONG_PTR RdrGetNextState( ULONG_PTR Action, ULONG_PTR CurrentState ) { return ActionsStatesArray[Action][CurrentState]; } REGENTRY LinkageKeyValues[] = { { TEXT("Bind"), REG_MULTI_SZ, 0, 0 }, { TEXT("Export"), REG_MULTI_SZ, 0, 0 }, { TEXT("Route"), REG_MULTI_SZ, 0, 0 } }; REGENTRY LinkageDisabledKeyValues[] = { { TEXT("Bind"), REG_MULTI_SZ, 0, 0 }, { TEXT("Export"), REG_MULTI_SZ, 0, 0 }, { TEXT("Route"), REG_MULTI_SZ, 0, 0 } }; REGENTRY NetworkProviderKeyValues[] = { { TEXT("Devicename"), REG_SZ, sizeof(SMBMRX_DEVICE_NAME), SMBMRX_DEVICE_NAME }, { TEXT("ProviderPath"), REG_EXPAND_SZ, sizeof(PROVIDER_PATH), PROVIDER_PATH }, { TEXT("Name"), REG_SZ, sizeof(SMBMRX_PROVIDER_NAME), SMBMRX_PROVIDER_NAME } }; REGENTRY ProviderOrderKeyValues[] = { { TEXT("ProviderOrder"), REG_SZ, 0, 0 } }; BOOL RdrSetupServiceEntry( void ) /*++ Routine Description: This routine initializes the registry entries for the smbmrx minirdr. This only needs to be done once. Arguments: None Return Value: None --*/ { HKEY hCurrentKey; SC_HANDLE sch, service; BOOL success = TRUE; DbgP(( TEXT( "Setting up ") RDRSERVICE TEXT(" registry Entries\n" ) )); sch = OpenSCManager( NULL, NULL, GENERIC_WRITE ); if ( sch ) { service = CreateService( sch, RDRSERVICE, RDRSERVICE, SERVICE_ALL_ACCESS, SERVICE_FILE_SYSTEM_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, TEXT("System32\\DRIVERS\\") RDRSERVICE TEXT(".sys"), TEXT("Network"), NULL, NULL, NULL, NULL ); if ( service ) { CloseServiceHandle( service ); } else if ( GetLastError( ) != ERROR_SERVICE_EXISTS ) { success = FALSE; } CloseServiceHandle( sch ); } else { success = FALSE; } // Read the linkage values associated with the Lanman workstation service. // This contains all the transports and the order in which they need to be used if ( success && OpenKey( WKSSERVICE_KEY TEXT("\\Linkage"), &hCurrentKey ) ) { ULONG i; ReadRegistryKeyValues( hCurrentKey, sizeof(LinkageKeyValues) / sizeof(REGENTRY), LinkageKeyValues); RegCloseKey(hCurrentKey); // Update the SMB MRx linkage values if ( CreateKey( RDRSERVICE_KEY TEXT("\\Linkage"), &hCurrentKey ) ) { WriteRegistryKeyValues( hCurrentKey, sizeof(LinkageKeyValues) / sizeof(REGENTRY), LinkageKeyValues); RegCloseKey(hCurrentKey); } else { success = FALSE; } for ( i = 0; i < ( sizeof(LinkageKeyValues) / sizeof(REGENTRY) ); i++ ) { if ( LinkageKeyValues[i].pvValue ) { free( LinkageKeyValues[i].pvValue ); LinkageKeyValues[i].pvValue = NULL; } } } else { success = FALSE; } //if ( OpenKey( WKSSERVICE_KEY TEXT("\\Linkage\\Disabled",&hCurrentKey)) //{ // ReadRegistryKeyValues( hCurrentKey, // sizeof(LinkageDisabledKeyValues) / sizeof(REGENTRY), // LinkageDisabledKeyValues); // RegCloseKey(hCurrentKey); //} //else //{ // DbgP(( TEXT("Error Opening Key %s Status %d\n"),WKSSERVICE_KEY TEXT("\\Linkage\\Disabled"),GetLastError() )); // return; //} // Update the SMB MRx linkage disabled values //if ( CreateKey( RDRSERVICE_KEY TEXT("\\Linkage\\Disabled") ,&hCurrentKey)) //{ // WriteRegistryKeyValues( hCurrentKey, // sizeof(LinkageDisabledKeyValues)/sizeof(REGENTRY), // LinkageDisabledKeyValues ); // RegCloseKey(hCurrentKey); //} //else //{ // DbgP(( TEXT("Error Creating Key %s Status %d\n"),RDRSERVICE_KEY TEXT("\\linkage\\disabled",GetLastError() )); // return; //} // Update the SMBmrx network provider section if ( success && CreateKey( RDRSERVICE_KEY TEXT("\\NetworkProvider"), &hCurrentKey ) ) { WriteRegistryKeyValues( hCurrentKey, sizeof(NetworkProviderKeyValues)/sizeof(REGENTRY), NetworkProviderKeyValues); RegCloseKey(hCurrentKey); } else { success = FALSE; } if ( success && CreateKey( RDRSERVICE_KEY TEXT("\\Parameters"), &hCurrentKey ) ) { RegCloseKey( hCurrentKey ); } else { success = FALSE; } return success; } BOOL RdrSetupProviderOrder( void ) { LPTSTR pOrderString = NULL; ULONG_PTR len; BOOL success = TRUE; len = RdrGetProviderOrderString( &pOrderString ) * sizeof(TCHAR); if ( len > 0 && pOrderString ) { if ( !RdrFindProviderInOrder( pOrderString, PROVIDER_NAME ) ) { LPTSTR pNewOrderString; len += sizeof( PROVIDER_NAME ) + (2 * sizeof(TCHAR)); // add 2 for comma delimeter and null pNewOrderString = malloc( len ); if ( pNewOrderString ) { lstrcpy( pNewOrderString, pOrderString ); lstrcat( pNewOrderString, TEXT(",") ); lstrcat( pNewOrderString, PROVIDER_NAME ); success = RdrSetProviderOrderString( pNewOrderString ); free( pNewOrderString ); } } } else { success = RdrSetProviderOrderString( PROVIDER_NAME ); } if ( pOrderString ) { free( pOrderString ); } return success; } ULONG_PTR RdrGetProviderOrderString( LPTSTR *OrderString ) { HKEY hOrderKey; ULONG_PTR len = 0; if ( OpenKey( PROVIDER_ORDER_KEY, &hOrderKey ) ) { ReadRegistryKeyValues( hOrderKey, sizeof(ProviderOrderKeyValues) / sizeof(REGENTRY), ProviderOrderKeyValues); RegCloseKey(hOrderKey); len = ProviderOrderKeyValues[0].dwLength / sizeof( TCHAR ) - 1; *OrderString = (LPTSTR) ProviderOrderKeyValues[0].pvValue; } return len; } BOOL RdrSetProviderOrderString( LPTSTR OrderString ) { HKEY hOrderKey; ULONG len = 0; BOOL rc = FALSE; if ( CreateKey( PROVIDER_ORDER_KEY, &hOrderKey ) ) { ProviderOrderKeyValues[0].dwLength = ( lstrlen( OrderString ) + 1 ) * sizeof( TCHAR ); ProviderOrderKeyValues[0].pvValue = OrderString; WriteRegistryKeyValues( hOrderKey, sizeof(ProviderOrderKeyValues) / sizeof(REGENTRY), ProviderOrderKeyValues); RegCloseKey(hOrderKey); rc = TRUE; } return rc; } BOOL RdrFindProviderInOrder( LPTSTR OrderString, LPTSTR Provider ) { LPTSTR pCompare; BOOL match = FALSE; if ( OrderString && Provider && *Provider ) { pCompare = Provider; while ( *OrderString ) { if ( toupper(*OrderString++) != toupper(*pCompare++) ) { pCompare = Provider; } if ( *pCompare == TEXT('\0') ) { if ( ( *OrderString == TEXT(',') ) || ( *OrderString == TEXT('\0') ) ) { match = TRUE; break; } else // hmm, it's a substring of another provider name { while ( ( *OrderString != TEXT(',') ) && ( *OrderString != TEXT('\0') ) ) { OrderString++; } pCompare = Provider; } } } } return match; } void ReadRegistryKeyValues( HKEY hCurrentKey, DWORD NumberOfValues, PREGENTRY pValues) /*++ Routine Description: This routine reads a bunch of values associated with a given key. Arguments: hCurrentKey - the key NumberOfValues - the number of values pValues - the array of values Return Value: None --*/ { // // Iterate through table reading the values along the way // DWORD i; for (i = 0; i < NumberOfValues; i++) { DWORD dwType; LPTSTR pszKey; dwType = pValues[i].dwType; pszKey = pValues[i].pszKey; switch (dwType) { case REG_SZ: GetRegsz(hCurrentKey, pszKey, &pValues[i].pvValue, &pValues[i].dwLength); break; case REG_DWORD: GetRegdw(hCurrentKey, pszKey, &pValues[i].pvValue, &pValues[i].dwLength); break; case REG_EXPAND_SZ: GetRegesz(hCurrentKey, pszKey, &pValues[i].pvValue, &pValues[i].dwLength); break; case REG_MULTI_SZ: GetRegmsz(hCurrentKey, pszKey, &pValues[i].pvValue, &pValues[i].dwLength); break; case REG_BINARY: DbgP(( TEXT("%s is a REG_BINARY and won't be duplicated\n"), pszKey )); break; default: DbgP(( TEXT("%s is an unknown type; %d (decimal)\n"), pszKey, dwType )); break; } } } // // Get a REG_SZ value and stick it in the table entry, along with the // length // BOOL GetRegsz(HKEY hKey, LPTSTR pszKey, PVOID * ppvValue, DWORD *pdwLength) { BYTE achValue[1024]; DWORD dwLength; LONG Status; DWORD dwType = REG_SZ; PBYTE pszValue = NULL; if ( (NULL == pszKey) || (NULL == ppvValue) || (NULL == hKey) || (NULL == pdwLength)) { return FALSE; } #ifdef _DEBUG FillMemory(achValue, sizeof(achValue), 0xcd); #endif dwLength = sizeof(achValue); Status = RegQueryValueEx( hKey, pszKey, NULL, &dwType, (PUCHAR) &achValue[0], &dwLength); if ((ERROR_SUCCESS != Status) || (REG_SZ != dwType) ) { return FALSE; } pszValue = malloc(dwLength); if (NULL == pszValue) { return FALSE; } CopyMemory(pszValue, achValue, dwLength); *ppvValue = pszValue; *pdwLength = dwLength; return TRUE; } // // Get the value of a REG_EXPAND_SZ and its length // BOOL GetRegesz(HKEY hKey, LPTSTR pszKey, PVOID * ppvValue, DWORD * pdwLength) { BYTE achValue[1024]; DWORD dwLength; LONG Status; DWORD dwType = REG_EXPAND_SZ; PBYTE pszValue = NULL; if ( (NULL == pszKey) || (NULL == ppvValue) || (NULL == hKey) || (NULL == pdwLength)) { return FALSE; } #ifdef _DEBUG FillMemory(achValue, sizeof(achValue), 0xcd); #endif dwLength = sizeof(achValue); Status = RegQueryValueEx( hKey, pszKey, NULL, &dwType, (PUCHAR) &achValue[0], &dwLength); if ((ERROR_SUCCESS != Status) || (REG_EXPAND_SZ != dwType)) { return FALSE; } pszValue = malloc(dwLength); if (NULL == pszValue) { return FALSE; } CopyMemory(pszValue, achValue, dwLength); *ppvValue = pszValue; *pdwLength = dwLength; return TRUE; } // // Get value and length of REG_MULTI_SZ // BOOL GetRegmsz(HKEY hKey, LPTSTR pszKey, PVOID * ppvValue, DWORD * pdwLength) { //BYTE achValue[1024]; BYTE achValue[2048]; // careful, some of these strings are quite long DWORD dwLength; LONG Status; DWORD dwType = REG_MULTI_SZ; PBYTE pszValue = NULL; if ( (NULL == pszKey) || (NULL == ppvValue) || (NULL == hKey) || (NULL == pdwLength)) { return FALSE; } #ifdef _DEBUG FillMemory(achValue, sizeof(achValue), 0xcd); #endif dwLength = sizeof(achValue); Status = RegQueryValueEx( hKey, pszKey, NULL, &dwType, (PUCHAR) &achValue[0], &dwLength); if ((ERROR_SUCCESS != Status) || (REG_MULTI_SZ != dwType)) { return FALSE; } pszValue = malloc(dwLength); if (NULL == pszValue) { return FALSE; } CopyMemory(pszValue, achValue, dwLength); *ppvValue = pszValue; *pdwLength = dwLength; return TRUE; } // // Get value and length of REG_DWORD // BOOL GetRegdw(HKEY hKey, LPTSTR pszKey, PVOID * ppvValue, DWORD * pdwLength) { DWORD dwValue = 0; DWORD dwLength; LONG Status; DWORD dwType = REG_DWORD; if ( (NULL == pszKey) || (NULL == ppvValue) || (NULL == hKey) || (NULL == pdwLength) ) { return FALSE; } dwLength = sizeof(dwValue); Status = RegQueryValueEx( hKey, pszKey, NULL, &dwType, (PUCHAR) &dwValue, &dwLength); if ((ERROR_SUCCESS != Status) || (REG_DWORD != dwType)) { return FALSE; } *ppvValue = (PVOID) (ULONG_PTR) dwValue; *pdwLength = dwLength; return TRUE; } void WriteRegistryKeyValues( HKEY hCurrentKey, DWORD NumberOfValues, PREGENTRY pValues) /*++ Routine Description: This routine reads a bunch of values associated with a given key. Arguments: hCurrentKey - the key NumberOfValues - the number of values pValues - the array of values Return Value: None --*/ { DWORD i; for (i = 0; i < NumberOfValues; i++) { DWORD dwType; PVOID pvValue; DWORD dwLength; LPTSTR pszKey; pszKey = pValues[i].pszKey; dwType = pValues[i].dwType; dwLength = pValues[i].dwLength; pvValue = pValues[i].pvValue; switch (dwType) { case REG_SZ: AddValue(hCurrentKey, pszKey, dwType, dwLength, pvValue); break; case REG_DWORD: AddValue(hCurrentKey, pszKey, dwType, dwLength, &pvValue); break; case REG_EXPAND_SZ: AddValue(hCurrentKey, pszKey, dwType, dwLength, pvValue); break; case REG_MULTI_SZ: AddValue(hCurrentKey, pszKey, dwType, dwLength, pvValue); break; case REG_BINARY: // // There are no binary values we need to copy. If we did, we'd // put something here // break; default: DbgP(( TEXT("%s is an unknown type; %d (decimal)\n"), pszKey, dwType )); break; } } } // // Open a key so we can read the values // BOOL OpenKey( LPTSTR pszKey, PHKEY phKey) /*++ Routine Description: This routine opens a registry key. Arguments: pszKey - the name of the key relative to HKEY_LOCAL_MACHINE phKey - the key handlle Return Value: TRUE if successful, otherwise FALSE --*/ { HKEY hNewKey = 0; DWORD Status; Status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, pszKey, 0, KEY_QUERY_VALUE, &hNewKey); if (ERROR_SUCCESS != Status) { *phKey = NULL; return FALSE; } else { *phKey = hNewKey; return TRUE; } } BOOL CreateKey(LPTSTR pszKey, PHKEY phKey) /*++ Routine Description: This routine creates a registry key. Arguments: pszKey - the name of the key relative to HKEY_LOCAL_MACHINE phKey - the key handlle Return Value: TRUE if successful, otherwise FALSE --*/ { LONG Status; DWORD Disposition; Status = RegCreateKeyEx( HKEY_LOCAL_MACHINE, pszKey, 0, REG_NONE, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, phKey, &Disposition); if ( ERROR_SUCCESS == Status) { return TRUE; } else { DbgP(( TEXT("error creating key %s Status %d\n"), pszKey, Status )); return FALSE; } } // // Add a value to the registry // BOOL AddValue(HKEY hKey, LPTSTR pszKey, DWORD dwType, DWORD dwLength, PVOID pvValue) { BOOL fSuccess = TRUE; LONG Status = ERROR_SUCCESS; HANDLE th; Status = RegSetValueEx( hKey, pszKey, 0, dwType, pvValue, dwLength); if (Status != ERROR_SUCCESS) { fSuccess = FALSE; //RegCloseKey(hKey); } return fSuccess; } int _cdecl _vsnwprintf( wchar_t *buffer, size_t count, wchar_t *format, va_list arg_ptr); // Format and write debug information to OutputDebugString ULONG _cdecl DbgPrint( LPTSTR Format, ... ) { ULONG rc = 0; TCHAR szbuffer[256]; va_list marker; va_start( marker, Format ); { rc = _vsnwprintf( szbuffer, 254, Format, marker ); szbuffer[255] = (TCHAR)0; OutputDebugString( TRACE_TAG ); OutputDebugString( szbuffer ); } return rc; }