/*++ Copyright (c) 1995-2000 Microsoft Corporation Module Name: pnpapi.c Abstract: This module contains the user-mode plug-and-play API stubs. Author: Paula Tomlinson (paulat) 9-18-1995 Environment: User-mode only. Revision History: 18-Sept-1995 paulat Creation and initial implementation. --*/ #ifndef UNICODE #define UNICODE #endif #ifndef _UNICODE #define _UNICODE #endif #define MAX_PROFILEID_LEN 5 #define MAX_UUID_LEN 39 // // includes // #include #include #include #include #include #include #include #include #include // // private prototypes // PSTR UnicodeToMultiByte( IN PCWSTR UnicodeString, IN UINT Codepage ); PWSTR MultiByteToUnicode( IN PCSTR String, IN UINT Codepage ); RPC_STATUS GuidToString( UUID *Uuid, LPTSTR StringGuid ); // // global data // WCHAR pszRegIDConfigDB[] = L"System\\CurrentControlSet\\Control\\IDConfigDB"; WCHAR pszRegKnownDockingStates[] = L"Hardware Profiles"; WCHAR pszRegCurrentConfig[] = L"CurrentConfig"; WCHAR pszRegDefaultFriendlyName[] = L"Noname Hardware Profile"; WCHAR pszRegHwProfileGuid[] = L"HwProfileGuid"; WCHAR pszRegFriendlyName[] = L"FriendlyName"; WCHAR pszRegDockState[] = L"DockState"; WCHAR pszRegDockingState[] = L"DockingState"; WCHAR pszCurrentDockInfo[] = L"CurrentDockInfo"; BOOL GetCurrentHwProfileW ( OUT LPHW_PROFILE_INFOW lpHwProfileInfo ) /*++ Routine Description: Arguments: lpHwProfileInfo Points to a HW_PROFILE_INFO structure that will receive the information for the current hardware profile. Return Value: If the function succeeds, the return value is TRUE. If the function fails, the return value is FALSE. To get extended error information, call GetLastError. --*/ { BOOL Status = TRUE; WCHAR RegStr[MAX_PATH]; HKEY hKey = NULL, hCfgKey = NULL; HKEY hCurrentDockInfoKey = NULL; ULONG ulCurrentConfig = 1, ulSize = 0; UUID NewGuid; try { // // validate parameter // if (lpHwProfileInfo == NULL) { SetLastError(ERROR_INVALID_PARAMETER); Status = FALSE; goto Clean0; } // // open the IDConfigDB key // if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, pszRegIDConfigDB, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) { SetLastError(ERROR_REGISTRY_CORRUPT); Status = FALSE; goto Clean0; } // // retrieve the current config id // ulSize = sizeof(ULONG); if (RegQueryValueEx(hKey, pszRegCurrentConfig, NULL, NULL, (LPBYTE)&ulCurrentConfig, &ulSize) != ERROR_SUCCESS) { SetLastError(ERROR_REGISTRY_CORRUPT); Status = FALSE; goto Clean0; } // // open the profile key for the current configuration // _snwprintf(RegStr, MAX_PATH, L"%s\\%04u", pszRegKnownDockingStates, ulCurrentConfig); if (RegOpenKeyEx(hKey, RegStr, 0, KEY_QUERY_VALUE, &hCfgKey) != ERROR_SUCCESS) { SetLastError(ERROR_REGISTRY_CORRUPT); Status = FALSE; goto Clean0; } // // retrieve the dock state for the current profile // if (RegOpenKeyEx(hKey, pszCurrentDockInfo, 0, KEY_QUERY_VALUE, &hCurrentDockInfoKey) != ERROR_SUCCESS) { // // No CurrentDockInfo Key, something's wrong. // SetLastError(ERROR_REGISTRY_CORRUPT); Status = FALSE; goto Clean0; } // // Look in CurrentDockInfo for // a hardware determined DockingState value. // ulSize = sizeof(ULONG); if ((RegQueryValueEx(hCurrentDockInfoKey, pszRegDockingState, NULL, NULL, (LPBYTE)&lpHwProfileInfo->dwDockInfo, &ulSize) != ERROR_SUCCESS) || (!lpHwProfileInfo->dwDockInfo) || ((lpHwProfileInfo->dwDockInfo & DOCKINFO_UNDOCKED) && (lpHwProfileInfo->dwDockInfo & DOCKINFO_DOCKED))) { // // If there's no such value, or the value was set to 0 (unspported), // or if the value is "unknown", resort to user supplied docking info. // Look under the IDConfigDB profile for a user set DockState value. // if ((RegQueryValueEx(hCfgKey, pszRegDockState, NULL, NULL, (LPBYTE)&lpHwProfileInfo->dwDockInfo, &ulSize) != ERROR_SUCCESS) || (!lpHwProfileInfo->dwDockInfo)) { // // If there's no such value, or the value was set to 0, // there is no user specified docking state to resort to; // return the "user-supplied unknown" docking state. // lpHwProfileInfo->dwDockInfo = DOCKINFO_USER_SUPPLIED | DOCKINFO_DOCKED | DOCKINFO_UNDOCKED; } } // // retrieve the profile guid. if we can't get one, set it to NULL // ulSize = HW_PROFILE_GUIDLEN * sizeof(WCHAR); if (RegQueryValueEx(hCfgKey, pszRegHwProfileGuid, NULL, NULL, (LPBYTE)&lpHwProfileInfo->szHwProfileGuid, &ulSize) != ERROR_SUCCESS) { lpHwProfileInfo->szHwProfileGuid[0] = '\0'; } // // retrieve the friendly name. if we can't get one, set it to NULL // ulSize = MAX_PROFILE_LEN * sizeof(WCHAR); if (RegQueryValueEx(hCfgKey, pszRegFriendlyName, NULL, NULL, (LPBYTE)&lpHwProfileInfo->szHwProfileName, &ulSize) != ERROR_SUCCESS) { lpHwProfileInfo->szHwProfileName[0] = '\0'; } Clean0: ; } except(EXCEPTION_EXECUTE_HANDLER) { SetLastError(ERROR_INVALID_PARAMETER); Status = FALSE; } if (hKey != NULL) RegCloseKey(hKey); if (hCfgKey != NULL) RegCloseKey(hCfgKey); if (hCurrentDockInfoKey != NULL) RegCloseKey(hCurrentDockInfoKey); return Status; } // GetCurrentHwProfileW BOOL GetCurrentHwProfileA ( OUT LPHW_PROFILE_INFOA lpHwProfileInfo ) /*++ Routine Description: Arguments: lpHwProfileInfo Points to a HW_PROFILE_INFO structure that will receive the information for the current hardware profile. Return Value: If the function succeeds, the return value is TRUE. If the function fails, the return value is FALSE. To get extended error information, call GetLastError. --*/ { BOOL Status = TRUE; HW_PROFILE_INFOW HwProfileInfoW; LPSTR pAnsiString; try { // // validate parameter // if (lpHwProfileInfo == NULL) { SetLastError(ERROR_INVALID_PARAMETER); Status = FALSE; goto Clean0; } // // call the Unicode version // if (!GetCurrentHwProfileW(&HwProfileInfoW)) { Status = FALSE; goto Clean0; } // // on successful return, convert unicode form of struct // to ANSI and copy struct members to callers struct // lpHwProfileInfo->dwDockInfo = HwProfileInfoW.dwDockInfo; pAnsiString = UnicodeToMultiByte( HwProfileInfoW.szHwProfileGuid, CP_ACP); if (!pAnsiString) { Status = FALSE; goto Clean0; } lstrcpyA(lpHwProfileInfo->szHwProfileGuid, pAnsiString); LocalFree(pAnsiString); pAnsiString = UnicodeToMultiByte( HwProfileInfoW.szHwProfileName, CP_ACP); if (!pAnsiString) { Status = FALSE; goto Clean0; } lstrcpyA(lpHwProfileInfo->szHwProfileName, pAnsiString); LocalFree(pAnsiString); Clean0: ; } except(EXCEPTION_EXECUTE_HANDLER) { SetLastError(ERROR_INTERNAL_ERROR); Status = FALSE; } return Status; } // GetCurrentHwProfileA PSTR UnicodeToMultiByte( IN PCWSTR UnicodeString, IN UINT Codepage ) /*++ Routine Description: Convert a string from unicode to ansi. Arguments: UnicodeString - supplies string to be converted. Codepage - supplies codepage to be used for the conversion. Return Value: NULL if out of memory or invalid codepage. Caller can free buffer with MyFree(). --*/ { UINT WideCharCount; PSTR String; UINT StringBufferSize; UINT BytesInString; PSTR p; WideCharCount = lstrlenW(UnicodeString) + 1; // // Allocate maximally sized buffer. // If every unicode character is a double-byte // character, then the buffer needs to be the same size // as the unicode string. Otherwise it might be smaller, // as some unicode characters will translate to // single-byte characters. // StringBufferSize = WideCharCount * sizeof(WCHAR); String = (PSTR)LocalAlloc(LPTR, StringBufferSize); if(String == NULL) { return(NULL); } // // Perform the conversion. // BytesInString = WideCharToMultiByte( Codepage, 0, // default composite char behavior UnicodeString, WideCharCount, String, StringBufferSize, NULL, NULL ); if(BytesInString == 0) { LocalFree(String); return(NULL); } // // Resize the string's buffer to its correct size. // If the realloc fails for some reason the original // buffer is not freed. // if(p = LocalReAlloc(String,BytesInString, LMEM_ZEROINIT | LMEM_MOVEABLE)) { String = p; } return(String); } // UnicodeToMultiByte PWSTR MultiByteToUnicode( IN PCSTR String, IN UINT Codepage ) /*++ Routine Description: Convert a string to unicode. Arguments: String - supplies string to be converted. Codepage - supplies codepage to be used for the conversion. Return Value: NULL if string could not be converted (out of memory or invalid cp) Caller can free buffer with MyFree(). --*/ { UINT BytesIn8BitString; UINT CharsInUnicodeString; PWSTR UnicodeString; PWSTR p; BytesIn8BitString = lstrlenA(String) + 1; // // Allocate maximally sized buffer. // If every character is a single-byte character, // then the buffer needs to be twice the size // as the 8bit string. Otherwise it might be smaller, // as some characters are 2 bytes in their unicode and // 8bit representations. // UnicodeString = (PWSTR)LocalAlloc(LPTR, BytesIn8BitString * sizeof(WCHAR)); if(UnicodeString == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return(NULL); } // // Perform the conversion. // CharsInUnicodeString = MultiByteToWideChar( Codepage, MB_PRECOMPOSED, String, BytesIn8BitString, UnicodeString, BytesIn8BitString ); if(CharsInUnicodeString == 0) { LocalFree(UnicodeString); return(NULL); } // // Resize the unicode string's buffer to its correct size. // If the realloc fails for some reason the original // buffer is not freed. // if(p = (PWSTR)LocalReAlloc(UnicodeString,CharsInUnicodeString*sizeof(WCHAR), LMEM_ZEROINIT | LMEM_MOVEABLE)) { UnicodeString = p; } return(UnicodeString); } // MultiByteToUnicode RPC_STATUS GuidToString( UUID *Uuid, LPTSTR StringGuid ) { RPC_STATUS Status; LPTSTR pTempStringGuid; UNICODE_STRING UnicodeStringGuid; Status = UuidToString(Uuid, &pTempStringGuid); if (Status == RPC_S_OK) { // // the form we want is all uppercase and with curly brackets around, // like what OLE does // lstrcpy(StringGuid, TEXT("{")); lstrcat(StringGuid, pTempStringGuid); lstrcat(StringGuid, TEXT("}")); RtlInitUnicodeString(&UnicodeStringGuid, StringGuid); RtlUpcaseUnicodeString(&UnicodeStringGuid, &UnicodeStringGuid, FALSE); RpcStringFree(&pTempStringGuid); } return Status; } // GuidToString