//----------------------------------------------------------------------------- // File: MultiDI.cpp // // Desc: DirectInput framework class using semantic mapping with multiplayer // device ownership. Feel free to use this class as a starting point // for adding extra functionality. // // Copyright (C) Microsoft Corporation. All Rights Reserved. //----------------------------------------------------------------------------- #define STRICT #define DIRECTINPUT_VERSION 0x0800 #include "stdafx.h" #include #include #include #include #include #include // included to get the D3DCOLOR_RGBA macro. #include "MultiDI.h" #include //----------------------------------------------------------------------------- // Name: CMultiplayerInputDeviceManager // Desc: Constructor // Args: strRegKey - A location in the registry where device ownership // information should be stored //----------------------------------------------------------------------------- CMultiplayerInputDeviceManager::CMultiplayerInputDeviceManager( TCHAR* strRegKey ) { HRESULT hr = CoInitialize(NULL); m_bCleanupCOM = SUCCEEDED(hr); LONG nResult; // Initialize members m_pDI = NULL; m_hWnd = NULL; m_pdiaf = NULL; m_pUsers = NULL; m_pDeviceList = NULL; m_AddDeviceCallback = NULL; m_AddDeviceCallbackParam = NULL; m_hKey = NULL; m_dwNumDevices = 0; m_dwMaxDevices = 0; // Duplicate the registry location string since we'll need this again later m_strKey = _tcsdup( strRegKey ); if( m_strKey == NULL ) return; // Create a reg key to store device ownership data nResult = RegCreateKeyEx( HKEY_CURRENT_USER, strRegKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &m_hKey, NULL ); if(nResult != ERROR_SUCCESS) m_hKey = NULL; } //----------------------------------------------------------------------------- // Name: ~CMultiplayerInputDeviceManager // Desc: Destructor //----------------------------------------------------------------------------- CMultiplayerInputDeviceManager::~CMultiplayerInputDeviceManager() { Cleanup(); if( m_bCleanupCOM ) CoUninitialize(); RegCloseKey( m_hKey ); free( m_strKey ); } //----------------------------------------------------------------------------- // Name: Create // Desc: Initializes the class, and enums the devices. See MultiMapper sample // for how to use this class. // It might fail if there are too many players for the // number of devices availible, or if one player owns too many // devices preventing others from having a device. Its up the app // to prevent this or respond to this. // Note: strUserName should be a array of sz strings //----------------------------------------------------------------------------- HRESULT CMultiplayerInputDeviceManager::Create( HWND hWnd, TCHAR* strUserNames[], DWORD dwNumUsers, DIACTIONFORMAT* pdiaf, LPDIMANAGERCALLBACK AddDeviceCallback, LPVOID pCallbackParam, BOOL bResetOwnership, BOOL bResetMappings ) { HRESULT hr; if( strUserNames == NULL || dwNumUsers == 0 ) return E_INVALIDARG; Cleanup(); // Store data m_hWnd = hWnd; // Create and init the m_pUsers array m_dwNumUsers = dwNumUsers; m_pUsers = new PlayerInfo*[dwNumUsers]; for( DWORD i=0; idwPlayerIndex = i; // set the 0-based player index (for easy referencing) lstrcpyn( m_pUsers[i]->strPlayerName, strUserNames[i], MAX_PATH-1 ); } m_AddDeviceCallback = AddDeviceCallback; m_AddDeviceCallbackParam = pCallbackParam; // Create the base DirectInput object if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&m_pDI, NULL ) ) ) return DXTRACE_ERR( TEXT("DirectInput8Create"), hr ); if( FAILED( hr = SetActionFormat( pdiaf, TRUE, bResetOwnership, bResetMappings ) ) ) return DXTRACE_ERR( TEXT("SetActionFormat"), hr ); return S_OK; } //----------------------------------------------------------------------------- // Name: SetActionFormat // Desc: Sets a new action format. // It re-enumerates the devices if bReenumerate // It resets the ownership of the devices if bResetOwnership // It resets the mapper actions of the devices if bResetMappings // This function may fail if there are too many players for the // number of devices availible, or if one player owns too many // devices preventing others from having a device. Its up the app // to prevent this or respond to this. //----------------------------------------------------------------------------- HRESULT CMultiplayerInputDeviceManager::SetActionFormat( DIACTIONFORMAT* pdiaf, BOOL bReenumerate, BOOL bResetOwnership, BOOL bResetMappings ) { HRESULT hr; DWORD iPlayer; DWORD iDevice; // Store the new action format m_pdiaf = pdiaf; // Only destroy and re-enumerate devices if the caller explicitly wants to. // This isn't thread safe, so be sure not to have any other threads using // this data unless you redesign this class if( bReenumerate ) { // Set all players to not have a device yet for( iPlayer=0; iPlayerbFoundDeviceForPlayer = FALSE; if( bResetOwnership ) { // Set all devices as not assigned to a player for( iDevice=0; iDeviceBuildActionMap( m_pdiaf, pPlayerInfo->strPlayerName, DIDBAM_DEFAULT ) ) ) return DXTRACE_ERR( TEXT("BuildActionMap"), hr ); if( FAILED( hr = pdidDevice->SetActionMap( m_pdiaf, pPlayerInfo->strPlayerName, DIDSAM_DEFAULT ) ) ) return DXTRACE_ERR( TEXT("SetActionMap"), hr ); } } return S_OK; } //----------------------------------------------------------------------------- // Name: BuildDeviceList // Desc: //----------------------------------------------------------------------------- HRESULT CMultiplayerInputDeviceManager::BuildDeviceList() { // Cleanup any previously enumerated devices CleanupDeviceList(); // Build a simple list of all devices currently attached to the machine. This // array will be used to reassign devices to each user. m_dwMaxDevices = 5; m_dwNumDevices = 0; m_pDeviceList = NULL; DeviceInfo* pListNew = NULL; pListNew = (DeviceInfo*) realloc( m_pDeviceList, m_dwMaxDevices*sizeof(DeviceInfo) ); // Verify allocation if( NULL == pListNew ) return DXTRACE_ERR( TEXT("BuildDeviceList"), E_OUTOFMEMORY ); else m_pDeviceList = pListNew; ZeroMemory( m_pDeviceList, m_dwMaxDevices*sizeof(DeviceInfo) ); // Enumerate available devices for any user. HRESULT rs = m_pDI->EnumDevicesBySemantics( NULL, m_pdiaf, StaticEnumSuitableDevicesCB, this, DIEDBSFL_ATTACHEDONLY ); return S_OK; } //----------------------------------------------------------------------------- // Name: EnumSuitableDevicesCB // Desc: DirectInput device enumeratation callback. Calls AddDevice() // on each device enumerated. //----------------------------------------------------------------------------- BOOL CALLBACK CMultiplayerInputDeviceManager::StaticEnumSuitableDevicesCB( LPCDIDEVICEINSTANCE pdidi, LPDIRECTINPUTDEVICE8 pdidDevice, DWORD dwFlags, DWORD dwDeviceRemaining, VOID* pContext ) { // Add the device to the device manager's internal list CMultiplayerInputDeviceManager* pInputDeviceManager = (CMultiplayerInputDeviceManager*)pContext; return pInputDeviceManager->EnumDevice( pdidi, pdidDevice, dwFlags, dwDeviceRemaining ); } //----------------------------------------------------------------------------- // Name: EnumDevice // Desc: Enums each device to see if its suitable to add //----------------------------------------------------------------------------- BOOL CMultiplayerInputDeviceManager::EnumDevice( const DIDEVICEINSTANCE* pdidi, const LPDIRECTINPUTDEVICE8 pdidDevice, DWORD dwFlags, DWORD dwRemainingDevices ) { TCHAR strPlayerName[MAX_PATH]; TCHAR strDeviceGuid[40]; // Devices of type DI8DEVTYPE_DEVICECTRL are specialized devices not generally // considered appropriate to control game actions. We just ignore these. if( GET_DIDEVICE_TYPE(pdidi->dwDevType) != DI8DEVTYPE_DEVICECTRL ) { // We're only interested in devices that map the pri 1 actions if( dwFlags & DIEDBS_MAPPEDPRI1 ) { // Add new pdidDevice struct to array, and resize array if needed m_dwNumDevices++; if( m_dwNumDevices > m_dwMaxDevices ) { m_dwMaxDevices += 5; DeviceInfo* pListNew = NULL; pListNew = (DeviceInfo*) realloc( m_pDeviceList, m_dwMaxDevices*sizeof(DeviceInfo) ); // Verify allocation if( NULL == pListNew ) { DXTRACE_ERR( TEXT("EnumDevice"), E_OUTOFMEMORY ); return DIENUM_STOP; } else m_pDeviceList = pListNew; ZeroMemory( m_pDeviceList + m_dwMaxDevices - 5, 5*sizeof(DeviceInfo) ); } DXUtil_ConvertGUIDToStringCch( &pdidi->guidInstance, strDeviceGuid, 40 ); DXUtil_ReadStringRegKeyCch( m_hKey, strDeviceGuid, strPlayerName, MAX_PATH, TEXT("") ); // Add the device to the array m_pDeviceList DWORD dwCurrentDevice = m_dwNumDevices-1; ZeroMemory( &m_pDeviceList[dwCurrentDevice], sizeof(DeviceInfo) ); m_pDeviceList[dwCurrentDevice].didi = *pdidi; m_pDeviceList[dwCurrentDevice].pdidDevice = pdidDevice; m_pDeviceList[dwCurrentDevice].pdidDevice->AddRef(); m_pDeviceList[dwCurrentDevice].bMapsPri1Actions = ((dwFlags & DIEDBS_MAPPEDPRI1) == DIEDBS_MAPPEDPRI1); m_pDeviceList[dwCurrentDevice].bMapsPri2Actions = ((dwFlags & DIEDBS_MAPPEDPRI2) == DIEDBS_MAPPEDPRI2); if( lstrcmp( strPlayerName, TEXT("") ) != 0 ) { m_pDeviceList[dwCurrentDevice].pPlayerInfo = LookupPlayer( strPlayerName ); if( m_pDeviceList[dwCurrentDevice].pPlayerInfo ) m_pDeviceList[dwCurrentDevice].pPlayerInfo->bFoundDeviceForPlayer = TRUE; } } } // Continue enumerating return DIENUM_CONTINUE; } //----------------------------------------------------------------------------- // Name: AssignDevices // Desc: //----------------------------------------------------------------------------- HRESULT CMultiplayerInputDeviceManager::AssignDevices() { DWORD iDevice; DWORD iPlayer; // For any device that doesn't have a user assigned to it, // then assign it to the first user that needs a device for( iDevice=0; iDevicebFoundDeviceForPlayer ) { m_pDeviceList[iDevice].pPlayerInfo = m_pUsers[iPlayer]; m_pUsers[iPlayer]->bFoundDeviceForPlayer = TRUE; break; } } } } return S_OK; } //----------------------------------------------------------------------------- // Name: VerifyAssignment // Desc: //----------------------------------------------------------------------------- HRESULT CMultiplayerInputDeviceManager::VerifyAssignment() { DWORD iPlayer; DWORD iDevice; // For each player, make sure that a device was found for this // player, otherwise return failure. for( iPlayer=0; iPlayerbFoundDeviceForPlayer ) { if( GetNumDevices() < m_dwNumUsers ) return E_DIUTILERR_TOOMANYUSERS; else { // Check to see if there's a device that isn't already // assigned to a player. If there is return // E_DIUTILERR_PLAYERWITHOUTDEVICE otherwise return // E_DIUTILERR_DEVICESTAKEN for( iDevice=0; iDevicedwNumActions]; // Verify memory allocation and collect DIA_APPFIXED settings if( pdwAppFixed ) { for( iAction=0; iAction < m_pdiaf->dwNumActions; iAction++ ) pdwAppFixed[iAction] = m_pdiaf->rgoAction[iAction].dwFlags & DIA_APPFIXED; } } // For every device that's assigned to a player, // set it action map, and add it to the game for( iDevice=0; iDeviceSetCooperativeLevel( m_hWnd, DISCL_NONEXCLUSIVE|DISCL_FOREGROUND ); if( FAILED(hr) ) break; // Build and set the action map on this device. This will also remove // it from DirectInput's internal list of available devices. DWORD dwBuildFlags = bResetMappings ? DIDBAM_HWDEFAULTS : DIDBAM_DEFAULT; DWORD dwSetFlags = bResetMappings ? DIDSAM_FORCESAVE : DIDSAM_DEFAULT; hr = pdidDevice->BuildActionMap( m_pdiaf, pPlayerInfo->strPlayerName, dwBuildFlags ); if( FAILED( hr ) ) { // just print out a debug message and keep going DXTRACE_ERR( TEXT("BuildActionMap"), hr ); hr = S_OK; continue; } hr = pdidDevice->SetActionMap( m_pdiaf, pPlayerInfo->strPlayerName, dwSetFlags ); if( FAILED( hr ) ) { // just print out a debug message and keep going DXTRACE_ERR( TEXT("SetActionMap"), hr ); hr = S_OK; continue; } // Callback into the app so it can adjust the device and set // the m_pDeviceList[iDevice].pParam field with a device state struct if( m_AddDeviceCallback ) m_AddDeviceCallback( pPlayerInfo, &m_pDeviceList[iDevice], &m_pDeviceList[iDevice].didi, m_AddDeviceCallbackParam ); // Check to see if the device is using relative axis -- sometimes app code // might want to know this. DIPROPDWORD dipdw; dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwObj = 0; dipdw.diph.dwHow = DIPH_DEVICE; dipdw.dwData = 0; pdidDevice->GetProperty( DIPROP_AXISMODE, &dipdw.diph ); if( dipdw.dwData == DIPROPAXISMODE_REL ) m_pDeviceList[iDevice].bRelativeAxis = TRUE; // We made it through this iteration without breaking out do to errors hr = S_OK; } else { if( FAILED( hr = pdidDevice->BuildActionMap( m_pdiaf, NULL, DIDBAM_DEFAULT ) ) ) { DXTRACE_ERR( TEXT("BuildActionMap"), hr ); break; } if( FAILED( hr = pdidDevice->SetActionMap( m_pdiaf, NULL, DIDSAM_NOUSER ) ) ) { DXTRACE_ERR( TEXT("SetActionMap"), hr ); break; } } } // If we stored DIA_APPFIXED flags earlier, we need to reapply those flags and // free the allocated memory if( bResetMappings && pdwAppFixed ) { for( iAction=0; iAction < m_pdiaf->dwNumActions; iAction++ ) m_pdiaf->rgoAction[iAction].dwFlags |= pdwAppFixed[iAction]; delete [] pdwAppFixed; } return hr; } //----------------------------------------------------------------------------- // Name: ConfigureDevices // Desc: //----------------------------------------------------------------------------- HRESULT CMultiplayerInputDeviceManager::ConfigureDevices( HWND hWnd, IUnknown* pSurface, VOID* ConfigureDevicesCB, DWORD dwFlags, LPVOID pvCBParam ) { HRESULT hr; DWORD iPlayer; // Determine how large of a string we'll need to hold all user names DWORD dwNamesSize = 0; for( iPlayer=0; iPlayer < m_dwNumUsers; iPlayer++ ) dwNamesSize += lstrlen( m_pUsers[iPlayer]->strPlayerName ) +1; // Build multi-sz list of user names TCHAR* strUserNames = new TCHAR[dwNamesSize+1]; // Verify allocation and cycle through user names if( strUserNames ) { TCHAR* strTemp = strUserNames; for( iPlayer=0; iPlayerstrPlayerName ); strTemp += lstrlen(strTemp) + 1; } lstrcpy( strTemp, TEXT("\0") ); } // Fill in all the params DICONFIGUREDEVICESPARAMS dicdp; ZeroMemory(&dicdp, sizeof(dicdp)); dicdp.dwSize = sizeof(dicdp); dicdp.dwcFormats = 1; dicdp.lprgFormats = m_pdiaf; dicdp.hwnd = hWnd; dicdp.lpUnkDDSTarget = pSurface; dicdp.dwcUsers = m_dwNumUsers; dicdp.lptszUserNames = strUserNames; // Initialize all the colors here DICOLORSET dics; ZeroMemory(&dics, sizeof(DICOLORSET)); dics.dwSize = sizeof(DICOLORSET); // Set UI color scheme (if not specified it uses defaults) dicdp.dics.dwSize = sizeof(dics); dicdp.dics.cTextFore = D3DCOLOR_RGBA(255,255,255,255); dicdp.dics.cTextHighlight = D3DCOLOR_RGBA(204,204,255,255); dicdp.dics.cCalloutLine = D3DCOLOR_RGBA(255,255,255,128); // dicdp.dics.cCalloutHighlight= D3DCOLOR_RGBA(204,204,255,255); dicdp.dics.cBorder = D3DCOLOR_RGBA(153,153,204,128); dicdp.dics.cControlFill = D3DCOLOR_RGBA( 51, 51, 102, 128); // dicdp.dics.cHighlightFill = D3DCOLOR_RGBA(0,0,0,128); dicdp.dics.cAreaFill = D3DCOLOR_RGBA(0,0,50,128); if( dwFlags & DICD_EDIT ) { // Re-enum so we can catch any new devices that have been recently attached for( iPlayer=0; iPlayerbFoundDeviceForPlayer = FALSE; if( FAILED( hr = BuildDeviceList() ) ) { DXTRACE_ERR( TEXT("BuildDeviceList"), hr ); goto LCleanup; } } // Unacquire the devices so that mouse doesn't // control the game while in control panel UnacquireDevices(); if( FAILED( hr = m_pDI->ConfigureDevices( (LPDICONFIGUREDEVICESCALLBACK)ConfigureDevicesCB, &dicdp, dwFlags, pvCBParam ) ) ) { DXTRACE_ERR( TEXT("ConfigureDevices"), hr ); goto LCleanup; } if( dwFlags & DICD_EDIT ) { // Update the device ownership if( FAILED( hr = UpdateDeviceOwnership() ) ) { DXTRACE_ERR( TEXT("UpdateDeviceOwnership"), hr ); goto LCleanup; } // Now save the device keys that are assigned players to registry, if( FAILED( hr = SaveDeviceOwnershipKeys() ) ) { DXTRACE_ERR( TEXT("SaveDeviceOwnershipKeys"), hr ); goto LCleanup; } // Report an error if there is a player that doesn't not // have a device assigned if( FAILED( hr = VerifyAssignment() ) ) goto LCleanup; // Now that every player has at least one device, build and set // the action map, and use callback into the app to tell the // app of the device assignment. if( FAILED( hr = AddAssignedDevices( FALSE ) ) ) { DXTRACE_ERR( TEXT("AddAssignedDevices"), hr ); goto LCleanup; } } hr = S_OK; LCleanup: if( strUserNames ) delete [] strUserNames; return hr; } //----------------------------------------------------------------------------- // Name: UpdateDeviceOwnership // Desc: //----------------------------------------------------------------------------- HRESULT CMultiplayerInputDeviceManager::UpdateDeviceOwnership() { DWORD iPlayer; DWORD iDevice; // Set all players to not have a device yet for( iPlayer=0; iPlayerbFoundDeviceForPlayer = FALSE; // Set all devices as not assigned to a player for( iDevice=0; iDeviceGetProperty( DIPROP_USERNAME, &dips.diph ); DXUtil_ConvertWideStringToGenericCch( strPlayerName, dips.wsz, MAX_PATH ); if( lstrcmp( strPlayerName, TEXT("") ) != 0 ) { m_pDeviceList[iDevice].pPlayerInfo = LookupPlayer( strPlayerName ); if( m_pDeviceList[iDevice].pPlayerInfo ) m_pDeviceList[iDevice].pPlayerInfo->bFoundDeviceForPlayer = TRUE; } } return S_OK; } //----------------------------------------------------------------------------- // Name: UnacquireDevices // Desc: //----------------------------------------------------------------------------- VOID CMultiplayerInputDeviceManager::UnacquireDevices() { // Unacquire every device if( m_pDeviceList ) { // All devices have been assigned a to a user in // the new array, so clean up the local array for( DWORD iDevice=0; iDeviceUnacquire(); } } } //----------------------------------------------------------------------------- // Name: SetFocus // Desc: Sets the DirectInput focus to a new HWND //----------------------------------------------------------------------------- VOID CMultiplayerInputDeviceManager::SetFocus( HWND hWnd ) { m_hWnd = hWnd; if( m_pDeviceList ) { // All devices have been assigned a to a user in // the new array, so clean up the local array for( DWORD iDevice=0; iDeviceUnacquire(); pdidDevice->SetCooperativeLevel( m_hWnd, DISCL_NONEXCLUSIVE|DISCL_FOREGROUND ); } } } //----------------------------------------------------------------------------- // Name: GetDevices // Desc: returns an array of DeviceInfo*'s //----------------------------------------------------------------------------- HRESULT CMultiplayerInputDeviceManager::GetDevices( DeviceInfo** ppDeviceInfo, DWORD* pdwCount ) { if( NULL==ppDeviceInfo || NULL==pdwCount ) return E_INVALIDARG; (*ppDeviceInfo) = m_pDeviceList; (*pdwCount) = m_dwNumDevices; return S_OK; } //----------------------------------------------------------------------------- // Name: LookupPlayer // Desc: searchs m_pUsers by player name //----------------------------------------------------------------------------- CMultiplayerInputDeviceManager::PlayerInfo* CMultiplayerInputDeviceManager::LookupPlayer( TCHAR* strPlayerName ) { for( DWORD iPlayer=0; iPlayerstrPlayerName, strPlayerName ) == 0 ) return pCurPlayer; } return NULL; } //----------------------------------------------------------------------------- // Name: SaveDeviceOwnershipKeys // Desc: For every device that's assigned to a player, save its device key // and assigned player to registry. //----------------------------------------------------------------------------- HRESULT CMultiplayerInputDeviceManager::SaveDeviceOwnershipKeys() { TCHAR strDeviceGuid[40]; DWORD iDevice; for( iDevice=0; iDevicestrPlayerName ); else RegDeleteValue( m_hKey, strDeviceGuid ); } return S_OK; } //----------------------------------------------------------------------------- // Name: DeleteDeviceOwnershipKeys // Desc: Delete all the ownership keys //----------------------------------------------------------------------------- VOID CMultiplayerInputDeviceManager::DeleteDeviceOwnershipKeys() { HKEY hKey; TCHAR *strRegKey; // Prepare strings to delete the key strRegKey = _tcsdup( m_strKey ); if( strRegKey == NULL ) return; TCHAR* strTemp = _tcsrchr( strRegKey, TEXT('\\') ); // Unless the registry path string was malformed, we're ready to delete // and recreate the key if( strTemp ) { *strTemp = 0; strTemp++; RegCloseKey( m_hKey ); // Delete the reg key RegOpenKey( HKEY_CURRENT_USER, strRegKey, &hKey ); RegDeleteKey( hKey, strTemp ); RegCloseKey( hKey ); // Create the key again now that all the subkeys have been deleted RegCreateKeyEx( HKEY_CURRENT_USER, m_strKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &m_hKey, NULL ); } // Clean up memory allocation free( strRegKey ); } //----------------------------------------------------------------------------- // Name: Cleanup // Desc: //----------------------------------------------------------------------------- VOID CMultiplayerInputDeviceManager::Cleanup() { CleanupDeviceList(); if( m_pUsers ) { for( DWORD iPlayer=0; iPlayerData1, pGuidSrc->Data2, pGuidSrc->Data3, pGuidSrc->Data4[0], pGuidSrc->Data4[1], pGuidSrc->Data4[2], pGuidSrc->Data4[3], pGuidSrc->Data4[4], pGuidSrc->Data4[5], pGuidSrc->Data4[6], pGuidSrc->Data4[7] ); if( nResult < 0 ) return E_FAIL; return S_OK; } //----------------------------------------------------------------------------- // Name: DXUtil_ConvertWideStringToAnsi() // Desc: This is a UNICODE conversion utility to convert a WCHAR string into a // CHAR string. // cchDestChar is the size in TCHARs of strDestination //----------------------------------------------------------------------------- HRESULT DXUtil_ConvertWideStringToAnsiCch( CHAR* strDestination, const WCHAR* wstrSource, int cchDestChar ) { if( strDestination==NULL || wstrSource==NULL || cchDestChar < 1 ) return E_INVALIDARG; int nResult = WideCharToMultiByte( CP_ACP, 0, wstrSource, -1, strDestination, cchDestChar*sizeof(CHAR), NULL, NULL ); strDestination[cchDestChar-1] = 0; if( nResult == 0 ) return E_FAIL; return S_OK; } //----------------------------------------------------------------------------- // Name: DXUtil_ConvertAnsiStringToGeneric() // Desc: This is a UNICODE conversion utility to convert a WCHAR string into a // TCHAR string. // cchDestChar is the size in TCHARs of tstrDestination. Be careful not to // pass in sizeof(strDest) on UNICODE builds //----------------------------------------------------------------------------- HRESULT DXUtil_ConvertWideStringToGenericCch( TCHAR* tstrDestination, const WCHAR* wstrSource, int cchDestChar ) { if( tstrDestination==NULL || wstrSource==NULL || cchDestChar < 1 ) return E_INVALIDARG; #ifdef _UNICODE wcsncpy( tstrDestination, wstrSource, cchDestChar ); tstrDestination[cchDestChar-1] = L'\0'; return S_OK; #else return DXUtil_ConvertWideStringToAnsiCch( tstrDestination, wstrSource, cchDestChar ); #endif } //----------------------------------------------------------------------------- // Name: DXUtil_ReadStringRegKeyCch() // Desc: Helper function to read a registry key string // cchDest is the size in TCHARs of strDest. Be careful not to // pass in sizeof(strDest) on UNICODE builds. //----------------------------------------------------------------------------- HRESULT DXUtil_ReadStringRegKeyCch( HKEY hKey, LPCTSTR strRegName, TCHAR* strDest, DWORD cchDest, LPCTSTR strDefault ) { DWORD dwType; DWORD cbDest = cchDest * sizeof(TCHAR); if( ERROR_SUCCESS != RegQueryValueEx( hKey, strRegName, 0, &dwType, (BYTE*)strDest, &cbDest ) ) { _tcsncpy( strDest, strDefault, cchDest ); strDest[cchDest-1] = 0; return S_FALSE; } else { if( dwType != REG_SZ ) { _tcsncpy( strDest, strDefault, cchDest ); strDest[cchDest-1] = 0; return S_FALSE; } } return S_OK; } //----------------------------------------------------------------------------- // Name: DXUtil_WriteStringRegKey() // Desc: Helper function to write a registry key string //----------------------------------------------------------------------------- HRESULT DXUtil_WriteStringRegKey( HKEY hKey, LPCTSTR strRegName, LPCTSTR strValue ) { if( NULL == strValue ) return E_INVALIDARG; DWORD cbValue = ((DWORD)_tcslen(strValue)+1) * sizeof(TCHAR); if( ERROR_SUCCESS != RegSetValueEx( hKey, strRegName, 0, REG_SZ, (BYTE*)strValue, cbValue ) ) return E_FAIL; return S_OK; }