/******************************************************************************* * SPUnicode.H * *--------------* * Description: * This is the header file for core helper functions implementation. * It is internal to Microsoft and is NOT shipped with the SDK since * many of the functions contatined in this file have not been fully * tested and therefore should not be exposed in the SDK. *------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. *******************************************************************************/ #ifndef __SPUNICODE_H__ #define __SPUNICODE_H__ #ifndef SPHelper_h #include #endif template class CSpToAnsiString { private: CHAR * m_pStr; CHAR m_aString[i]; public: CSpToAnsiString(const WCHAR * psz) { if (psz) { m_pStr = m_aString; ::WideCharToMultiByte(CP_ACP, 0, psz, -1, m_aString, i, NULL, NULL); } else { m_pStr = NULL; } } operator CHAR *() { return m_pStr; } CHAR * operator =(const WCHAR * psz) { if (psz) { m_pStr = m_aString; ::WideCharToMultiByte(CP_ACP, 0, psz, -1, m_aString, i, NULL, NULL); } else { m_pStr = NULL; } return m_pStr; } }; #ifndef _WIN32_WCE // // The compiler will automatically throw out the inline functions if _UNICODE is defined and simply // directly call the Win32 function. Unfortunately, this requires two classes since simply defining // const m_bUnicodeSupport does not force the functions to be inlined when built with _UNICODE. // template class CSpUnicodeSupportT { BOOL m_bUnicodeSupport; public: CSpUnicodeSupportT() { if (!bUnicodeOnly) { m_bUnicodeSupport = ::IsWindowUnicode(::GetDesktopWindow()); } } CSpUnicodeSupportT(BOOL bUnicodeSupport) { if (bUnicodeOnly) { SPDBG_ASSERT(bUnicodeSupport); } else { m_bUnicodeSupport = bUnicodeSupport; } } BOOL UnicodeSystem(void) const { if (bUnicodeOnly) { return TRUE; } else { return m_bUnicodeSupport; } } HANDLE CreateFile(const WCHAR * lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) const { if (UnicodeSystem()) { return ::CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } else { return ::CreateFileA(CSpToAnsiString<>(lpFileName), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } } DWORD GetFullPathName(WCHAR *lpFileName, // file name DWORD nBufferLength, // size of path buffer WCHAR *lpBuffer, // path buffer WCHAR **lpFilePart // address of file name in path ) { if (UnicodeSystem()) { return ::GetFullPathNameW(lpFileName, nBufferLength, lpBuffer, lpFilePart); } else { CHAR szTemp[MAX_PATH]; CHAR *szTempFilePart; DWORD tmp = ::GetFullPathNameA(CSpToAnsiString<>(lpFileName), sp_countof(szTemp), szTemp, &szTempFilePart); if (tmp) { tmp = ::MultiByteToWideChar(CP_ACP, 0, szTemp, -1, lpBuffer, nBufferLength); lpBuffer[tmp] = 0; *lpFilePart = lpBuffer + (szTempFilePart - szTemp); } return tmp; } } BOOL DeleteFile(LPCWSTR lpFileName) { if (UnicodeSystem()) { return ::DeleteFileW(lpFileName); } else { return ::DeleteFileA(CSpToAnsiString<>(lpFileName)); } } BOOL MoveFile(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName) { if (UnicodeSystem()) { return ::MoveFileW(lpExistingFileName, lpNewFileName); } else { return ::MoveFileA(CSpToAnsiString<>(lpExistingFileName), CSpToAnsiString<>(lpNewFileName)); } } BOOL CopyFile(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, BOOL bFailIfExists) { if (UnicodeSystem()) { return ::CopyFileW(lpExistingFileName, lpNewFileName, bFailIfExists); } else { return ::CopyFileA(CSpToAnsiString<>(lpExistingFileName), CSpToAnsiString<>(lpNewFileName), bFailIfExists); } } BOOL CreateDirectory(const WCHAR * lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes) const { if (UnicodeSystem()) { return ::CreateDirectoryW(lpPathName, lpSecurityAttributes); } else { return ::CreateDirectoryA(CSpToAnsiString<>(lpPathName), lpSecurityAttributes); } } BOOL RemoveDirectory(const WCHAR * lpPathName) const { if (UnicodeSystem()) { return ::RemoveDirectoryW(lpPathName); } else { return ::RemoveDirectoryA(CSpToAnsiString<>(lpPathName)); } } HANDLE CreateFileMapping(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, const WCHAR *lpName) { if (UnicodeSystem()) { return ::CreateFileMappingW(hFile, lpFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, lpName); } else { return ::CreateFileMappingA(hFile, lpFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, CSpToAnsiString<>(lpName)); } } BOOL SetFileAttributes(LPCWSTR lpFileName, DWORD dwFileAttributes) { if (UnicodeSystem()) { return ::SetFileAttributesW(lpFileName, dwFileAttributes); } else { return ::SetFileAttributesA(CSpToAnsiString<>(lpFileName), dwFileAttributes); } } DWORD GetFileAttributes(LPCWSTR lpFileName) { if (UnicodeSystem()) { return ::GetFileAttributesW(lpFileName); } else { return ::GetFileAttributesA(CSpToAnsiString<>(lpFileName)); } } LONG RegOpenKeyEx(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) const { if (UnicodeSystem()) { return ::RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult); } else { return ::RegOpenKeyExA(hKey, CSpToAnsiString<>(lpSubKey), ulOptions, samDesired, phkResult); } } LONG RegCreateKeyEx(HKEY hk, LPCWSTR lpSubKey, DWORD dwReserved, LPCWSTR lpClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition) const { if (UnicodeSystem()) { return ::RegCreateKeyExW(hk, lpSubKey, dwReserved, const_cast(lpClass), dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition); } else { return ::RegCreateKeyExA(hk, CSpToAnsiString<>(lpSubKey), dwReserved, CSpToAnsiString<>(lpClass), dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition); } } LONG RegDeleteKey(HKEY hKey, LPCWSTR lpSubKey) const { if (UnicodeSystem()) { return ::RegDeleteKeyW(hKey, lpSubKey); } else { return ::RegDeleteKeyA(hKey, CSpToAnsiString<>(lpSubKey)); } } LONG RegDeleteValue(HKEY hKey, LPCWSTR lpSubKey) const { if (UnicodeSystem()) { return ::RegDeleteValueW(hKey, lpSubKey); } else { return ::RegDeleteValueA(hKey, CSpToAnsiString<>(lpSubKey)); } } // // Use RegQueryStringValue for strings. Use this for binary data. // LONG RegQueryValueEx(HKEY hk, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) const { if (UnicodeSystem()) { return ::RegQueryValueExW(hk, lpValueName, NULL, lpType, lpData, lpcbData); } else { return ::RegQueryValueExA(hk, CSpToAnsiString<>(lpValueName), NULL, lpType, lpData, lpcbData); } } // // NOTE: The size parameter is in CHARACTERS! Even though the registry API sizes are // in bytes, this function uses character counts. // LONG RegQueryStringValue(HKEY hKey, LPCWSTR lpValueName, LPWSTR lpData, LPDWORD lpcchData) const { DWORD dwType; LONG rr; if (UnicodeSystem()) { *lpcchData *= sizeof(WCHAR); rr = ::RegQueryValueExW(hKey, lpValueName, NULL, &dwType, (BYTE *)lpData, lpcchData); *lpcchData /= sizeof(WCHAR); } else { DWORD dwOrigCharCount = *lpcchData; char * pszScratch = lpData ? (char *)_alloca(dwOrigCharCount) : NULL; rr = ::RegQueryValueExA(hKey, CSpToAnsiString<>(lpValueName), NULL, &dwType, (BYTE *)pszScratch, lpcchData); if (lpData) { if (rr == ERROR_SUCCESS) { DWORD dwReturnedChars = *lpcchData; *lpcchData = ::MultiByteToWideChar(CP_ACP, 0, pszScratch, dwReturnedChars, lpData, dwOrigCharCount); if (*lpcchData == 0) { rr = ::GetLastError(); *lpcchData = ::MultiByteToWideChar(CP_ACP, 0, pszScratch, dwReturnedChars, NULL, 0); } } } } if (rr == ERROR_SUCCESS && dwType == REG_MULTI_SZ && lpData && *lpcchData) { // This is used by Whistler setup to overcome string size limits for REG_SZ. // Unfortunately, leaves a zero-byte inbetween concatenated strings. // Must remove these entries. Can do this in situ. LPWSTR lpTo = lpData; LPWSTR lpFrom = lpData; while ( static_cast(lpFrom-lpData) < ((*lpcchData)-1) ) { if ( *lpFrom == 0 ) { lpFrom ++; } // This will copy the 2nd zero of a double null-terminated string. *lpTo = *lpFrom; lpTo ++; lpFrom ++; } if ( static_cast(lpFrom-lpData) < (*lpcchData) ) { // This will copy the final null-terminating byte of a single-zero terminated string. *lpTo = *lpFrom; } // Update character count to match new string including null-terminator. *lpcchData = static_cast(lpTo-lpData) + 1; } SPDBG_ASSERT((rr != ERROR_SUCCESS) || (dwType == REG_SZ) || (dwType == REG_MULTI_SZ)); return rr; } // // NOTES: Size is in Characters for lpcchName. Although this function uses RegEnumKeyEx, we chose to simply // implement the ReqEnumKey functionality since the Ex functionality is not used // by most programs (this saves a bunch of string conversion code). // LONG RegEnumKey(HKEY hk, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcchName) const { if (UnicodeSystem()) { return ::RegEnumKeyExW(hk, dwIndex, lpName, lpcchName, NULL, NULL, NULL, NULL); } else { DWORD dwSize = *lpcchName; char * pszScratch = lpName ? (char *)_alloca(dwSize) : NULL; LONG rr = ::RegEnumKeyExA(hk, dwIndex, pszScratch, &dwSize, NULL, NULL, NULL, NULL); if (lpName) { if (rr == ERROR_SUCCESS) { *lpcchName = ::MultiByteToWideChar(CP_ACP, 0, pszScratch, -1, lpName, *lpcchName); if (*lpcchName == 0) { *lpcchName = ::MultiByteToWideChar(CP_ACP, 0, pszScratch, -1, NULL, 0); rr = ::GetLastError(); } *lpcchName *= sizeof(WCHAR); } } else { *lpcchName = dwSize; } return rr; } } // // NOTES: Size is in Characters for lpcchName. Although this function uses RegEnumValue // it will only return the names, not the data. cbValueName is the count of characters // LONG RegEnumValueName(HKEY hk, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcchName) const { if (UnicodeSystem()) { return ::RegEnumValueW(hk, dwIndex, lpName, lpcchName, NULL, NULL, NULL, NULL); } else { DWORD dwSize = *lpcchName; char * pszScratch = lpName ? (char *)_alloca(dwSize) : NULL; LONG rr = ::RegEnumValueA(hk, dwIndex, pszScratch, &dwSize, NULL, NULL, NULL, NULL); if (lpName) { if (rr == ERROR_SUCCESS) { *lpcchName = ::MultiByteToWideChar(CP_ACP, 0, pszScratch, -1, lpName, *lpcchName); if (*lpcchName == 0) { *lpcchName = ::MultiByteToWideChar(CP_ACP, 0, pszScratch, -1, NULL, 0); rr = ::GetLastError(); } *lpcchName *= sizeof(WCHAR); } } else { *lpcchName = dwSize; } return rr; } } // // Don't use this for strings. Use RegSetStringValue instead. // LONG RegSetValueEx(HKEY hKey, LPCWSTR lpValueName, DWORD Reserved, DWORD dwType, const BYTE * lpData, DWORD cbData) const { if (UnicodeSystem()) { return ::RegSetValueExW(hKey, lpValueName, Reserved, dwType, lpData, cbData); } else { return ::RegSetValueExA(hKey, CSpToAnsiString<>(lpValueName), Reserved, dwType, lpData, cbData); } } LONG RegSetStringValue(HKEY hKey, LPCWSTR lpValueName, LPCWSTR lpData) const { LONG rr; DWORD dwSize = (wcslen(lpData)+1) * sizeof(WCHAR); if (UnicodeSystem()) { rr = ::RegSetValueExW(hKey, lpValueName, NULL, REG_SZ, (const BYTE *)lpData, dwSize); } else { char * pszScratch = (char *)_alloca(dwSize); dwSize = ::WideCharToMultiByte(CP_ACP, 0, lpData, -1, pszScratch, dwSize, NULL, NULL); rr = ::RegSetValueExA(hKey, CSpToAnsiString<>(lpValueName), NULL, REG_SZ, (BYTE *)pszScratch, dwSize); } return rr; } HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName) const { if (UnicodeSystem()) { return ::CreateEventW(lpEventAttributes, bManualReset, bInitialState, lpName); } else { return ::CreateEventA(lpEventAttributes, bManualReset, bInitialState, CSpToAnsiString<>(lpName)); } } HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCWSTR lpName) const { if (UnicodeSystem()) { return ::CreateMutexW(lpMutexAttributes, bInitialOwner, lpName); } else { return ::CreateMutexA(lpMutexAttributes, bInitialOwner, CSpToAnsiString<>(lpName)); } } int LoadString(HINSTANCE hInstance, UINT uID, LPWSTR lpBuffer, int nBuffer) const { if (bUnicodeOnly) // NOTE: If the DLL is built ANSI then use ANSI load! { return ::LoadStringW(hInstance, uID, lpBuffer, nBuffer); } else { char * pszScratch = (char *)_alloca(nBuffer * 2); int r = ::LoadStringA(hInstance, uID, pszScratch, nBuffer * 2); if (r) { r = ::MultiByteToWideChar(CP_ACP, 0, pszScratch, -1, lpBuffer, nBuffer); } else { *lpBuffer = 0; } return r; } } HMODULE LoadLibrary( LPCWSTR lpLibFileName ) { if ( UnicodeSystem() ) { return ::LoadLibraryW( lpLibFileName ); } else { return ::LoadLibraryA( CSpToAnsiString<>(lpLibFileName) ); } } HMODULE LoadLibraryEx(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) { if (UnicodeSystem()) { return ::LoadLibraryExW(lpLibFileName, hFile, dwFlags); } else { return ::LoadLibraryExA(CSpToAnsiString<>(lpLibFileName), hFile, dwFlags); } } HRSRC FindResourceEx(HMODULE hModule, LPCWSTR lpType, LPCWSTR lpName, WORD wLanguage) { if (UnicodeSystem()) { return ::FindResourceExW(hModule, lpType, lpName, wLanguage); } else { return ::FindResourceExA(hModule, HIWORD(lpType) ? CSpToAnsiString<>(lpType) : (const CHAR *) lpType, HIWORD(lpName) ? CSpToAnsiString<>(lpName) : (const CHAR *) lpName, wLanguage); } } DWORD GetModuleFileName(HMODULE hModule, LPWSTR lpFileName, DWORD nSize) const { if (UnicodeSystem()) { return ::GetModuleFileNameW(hModule, lpFileName, nSize); } else { CHAR szFileName[MAX_PATH]; DWORD r = ::GetModuleFileNameA(hModule, szFileName, sp_countof(szFileName)); if (r) { r = ::MultiByteToWideChar(CP_ACP, 0, szFileName, r, lpFileName, nSize - 1); lpFileName[r] = 0; } return r; } } UINT GetSystemDirectory( LPWSTR lpBuffer, UINT uSize ) { if (UnicodeSystem()) { return ::GetSystemDirectoryW( lpBuffer, uSize ); } else { CHAR szSystemDirectory[ MAX_PATH ]; DWORD r = ::GetSystemDirectoryA(szSystemDirectory, sp_countof( szSystemDirectory )); if ( r ) { r = ::MultiByteToWideChar( CP_ACP, 0, szSystemDirectory, r, lpBuffer, uSize - 1 ); lpBuffer[r] = 0; } return r; } } DWORD SearchPath( LPCWSTR lpPath, LPCWSTR lpFileName, LPCWSTR lpExtension, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR *lpFilePart ) { if (UnicodeSystem()) { return ::SearchPathW( lpPath, lpFileName, lpExtension, nBufferLength, lpBuffer, lpFilePart ); } else { CHAR szFoundFile[ MAX_PATH ]; LPSTR lpaFilePart = NULL; LPSTR lpaPath = strdup( CSpToAnsiString<>(lpPath) ); LPSTR lpaFileName = strdup( CSpToAnsiString<>(lpFileName) ); DWORD r = ::SearchPathA( CSpToAnsiString<>(lpPath), CSpToAnsiString<>(lpFileName), CSpToAnsiString<>(lpExtension), sp_countof( szFoundFile ), szFoundFile, &lpaFilePart ); if ( r ) { r = ::MultiByteToWideChar( CP_ACP, 0, szFoundFile, r, lpBuffer, nBufferLength - 1 ); lpBuffer[r] = 0; } if ( r ) { // Find out how many wide characters are in the file part int cchFilePartW = ::MultiByteToWideChar( CP_ACP, 0, lpaFilePart, strlen( szFoundFile ) - (lpaFilePart - szFoundFile), NULL, 0 ); *lpFilePart = lpBuffer + wcslen( lpBuffer ) - cchFilePartW; } if ( lpaPath ) { free( lpaPath ); } if ( lpaFileName ) { free( lpaFileName ); } return r; } } int CompareString(LCID Locale, DWORD dwCmpFlags, LPCWSTR lpString1, int cchCount1, LPCWSTR lpString2, int cchCount2) { if (UnicodeSystem()) { return ::CompareStringW(Locale, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2); } else { return ::CompareStringA(Locale, dwCmpFlags, CSpToAnsiString<>(lpString1), cchCount1, CSpToAnsiString<>(lpString2), cchCount2); } } BOOL SetWindowText( HWND hWnd, LPCWSTR lpString ) { if ( UnicodeSystem() ) { return ::SetWindowTextW( hWnd, lpString ); } else { return ::SetWindowTextA( hWnd, CSpToAnsiString<>(lpString) ); } } BOOL SetDlgItemText(HWND hDlg, int nIDDlgItem, LPCWSTR lpString ) { if ( UnicodeSystem() ) { return ::SetDlgItemTextW( hDlg, nIDDlgItem, lpString ); } else { return ::SetDlgItemTextA( hDlg, nIDDlgItem, CSpToAnsiString<>(lpString) ); } } int MessageBox( HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType ) { if ( UnicodeSystem() ) { return ::MessageBoxW( hWnd, lpText, lpCaption, uType ); } else { return ::MessageBoxA( hWnd, CSpToAnsiString<>(lpText), CSpToAnsiString<>(lpCaption), uType ); } } int GetLocaleInfo( LCID Locale, LCTYPE LCType, LPWSTR lpLCData, int cchData ) { if ( UnicodeSystem() ) { return ::GetLocaleInfoW( Locale, LCType, lpLCData, cchData ); } else { int cchNeeded = ::GetLocaleInfoA( Locale, LCType, NULL, 0 ); CHAR *pszLCData = new CHAR[ cchNeeded ]; int r = ::GetLocaleInfoA( Locale, LCType, pszLCData, cchNeeded ); if ( r ) { if ( lpLCData ) { r = ::MultiByteToWideChar(CP_ACP, 0, pszLCData, r, lpLCData, cchData - 1); lpLCData[r] = 0; } else { // User wants to know how much space is needed r = ::MultiByteToWideChar(CP_ACP, 0, pszLCData, r, NULL, 0 ) + 1; } } delete[] pszLCData; return r; } } int GetTimeFormat( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME *lpTime, LPCWSTR lpFormat, LPWSTR lpTimeStr, int cchTime ) { if ( UnicodeSystem() ) { return ::GetTimeFormatW( Locale, dwFlags, lpTime, lpFormat, lpTimeStr, cchTime ); } else { LPSTR lpaFormat = strdup( CSpToAnsiString<>(lpFormat) ); int cchNeeded = ::GetTimeFormatA( Locale, dwFlags, lpTime, lpaFormat, NULL, 0 ); CHAR *pszTime = new CHAR[ cchNeeded ]; int r = ::GetTimeFormatA( Locale, dwFlags, lpTime, lpaFormat, pszTime, cchNeeded ); if ( r ) { if ( lpTimeStr ) { r = ::MultiByteToWideChar(CP_ACP, 0, pszTime, r, lpTimeStr, cchTime - 1); lpTimeStr[r] = 0; } else { // User wants to know how much space is needed r = ::MultiByteToWideChar(CP_ACP, 0, pszTime, r, NULL, 0 ) + 1; } } delete[] pszTime; if ( lpaFormat ) { free( lpaFormat ); } return r; } } int GetNumberFormat( LCID Locale, DWORD dwFlags, LPCWSTR lpValue, CONST NUMBERFMTW *lpFormat, LPWSTR lpNumberStr, int cchNumber ) { if ( UnicodeSystem() ) { return ::GetNumberFormatW( Locale, dwFlags, lpValue, lpFormat, lpNumberStr, cchNumber ); } else { // Convert the NUMBERFMTW into a NUMBERFMTA NUMBERFMTA nmfmtA; nmfmtA.NumDigits = lpFormat->NumDigits; nmfmtA.LeadingZero = lpFormat->LeadingZero; nmfmtA.Grouping = lpFormat->Grouping; nmfmtA.NegativeOrder = lpFormat->NegativeOrder; nmfmtA.lpDecimalSep = strdup( CSpToAnsiString<>(lpFormat->lpDecimalSep) ); nmfmtA.lpThousandSep = strdup( CSpToAnsiString<>(lpFormat->lpThousandSep) ); LPSTR lpaValue = strdup( CSpToAnsiString<>(lpValue) ); int cchNeeded = ::GetNumberFormatA( Locale, dwFlags, lpaValue, &nmfmtA, NULL, 0 ); CHAR *pszNumber = new CHAR[ cchNeeded ]; int r = ::GetNumberFormatA( Locale, dwFlags, lpaValue, &nmfmtA, pszNumber, cchNeeded ); if ( r ) { if ( lpNumberStr ) { r = ::MultiByteToWideChar(CP_ACP, 0, pszNumber, r, lpNumberStr, cchNumber - 1); lpNumberStr[r] = 0; } else { // User wants to know how much space is needed r = ::MultiByteToWideChar(CP_ACP, 0, pszNumber, r, NULL, 0 ) + 1; } } delete[] pszNumber; if ( nmfmtA.lpDecimalSep ) { free( nmfmtA.lpDecimalSep ); } if ( nmfmtA.lpThousandSep ) { free( nmfmtA.lpThousandSep ); } if ( lpaValue ) { free( lpaValue ); } return r; } } int GetCurrencyFormat( LCID Locale, DWORD dwFlags, LPCWSTR lpValue, CONST CURRENCYFMTW *lpFormat, LPWSTR lpCurrencyStr, int cchCurrency ) { if ( UnicodeSystem() ) { return ::GetCurrencyFormatW( Locale, dwFlags, lpValue, lpFormat, lpCurrencyStr, cchCurrency ); } else { // Convert the CURRENCYFMTW into a CURRENCYFMTA CURRENCYFMTA cyfmtA; cyfmtA.NumDigits = lpFormat->NumDigits; cyfmtA.LeadingZero = lpFormat->LeadingZero; cyfmtA.Grouping = lpFormat->Grouping; cyfmtA.NegativeOrder = lpFormat->NegativeOrder; cyfmtA.PositiveOrder = lpFormat->PositiveOrder; cyfmtA.lpDecimalSep = strdup( CSpToAnsiString<>(lpFormat->lpDecimalSep) ); cyfmtA.lpThousandSep = strdup( CSpToAnsiString<>(lpFormat->lpThousandSep) ); cyfmtA.lpCurrencySymbol = strdup( CSpToAnsiString<>(lpFormat->lpCurrencySymbol) ); LPSTR lpaValue = strdup( CSpToAnsiString<>(lpValue) ); int cchNeeded = ::GetCurrencyFormatA( Locale, dwFlags, lpaValue, &cyfmtA, NULL, 0 ); CHAR *pszCurrency = new CHAR[ cchNeeded ]; int r = ::GetCurrencyFormatA( Locale, dwFlags, lpaValue, &cyfmtA, pszCurrency, cchNeeded ); if ( r ) { if ( lpCurrencyStr ) { r = ::MultiByteToWideChar(CP_ACP, 0, pszCurrency, r, lpCurrencyStr, cchCurrency - 1); lpCurrencyStr[r] = 0; } else { // User wants to know how much space is needed r = ::MultiByteToWideChar(CP_ACP, 0, pszCurrency, r, NULL, 0 ) + 1; } } delete[] pszCurrency; if ( cyfmtA.lpDecimalSep ) { free( cyfmtA.lpDecimalSep ); } if ( cyfmtA.lpThousandSep ) { free( cyfmtA.lpThousandSep ); } if ( cyfmtA.lpCurrencySymbol ) { free( cyfmtA.lpCurrencySymbol ); } if ( lpaValue ) { free( lpaValue ); } return r; } } LONG_PTR GetWindowLongPtr( HWND hWnd, int nIndex ) { if ( UnicodeSystem() ) { return ::GetWindowLongPtrW( hWnd, nIndex ); } else { return ::GetWindowLongPtrA( hWnd, nIndex ); } } LONG_PTR SetWindowLongPtr( HWND hWnd, int nIndex, LONG_PTR dwNewLong ) { if ( UnicodeSystem() ) { return ::SetWindowLongPtrW( hWnd, nIndex, dwNewLong ); } else { return ::SetWindowLongPtrA( hWnd, nIndex, dwNewLong ); } } INT_PTR DialogBoxParam( HINSTANCE hInstance, LPCWSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam ) { if ( UnicodeSystem() ) { return ::DialogBoxParamW( hInstance, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam ); } else { return ::DialogBoxParamA( hInstance, (LPCTSTR) lpTemplateName, hWndParent, lpDialogFunc, dwInitParam ); } } LRESULT SendDlgItemMessage(HWND hDlg, int nIDDlgItem, UINT Msg, WPARAM wParam, LPARAM lParam ) { if ( UnicodeSystem() ) { return ::SendDlgItemMessageW(hDlg, nIDDlgItem, Msg, wParam, lParam ); } else { return ::SendDlgItemMessageA(hDlg, nIDDlgItem, Msg, wParam, lParam ); } } #ifdef __HTMLHELP_H__ HWND WINAPI HtmlHelp( HWND hwndCaller, LPCWSTR pszFile, UINT uCommand, DWORD_PTR dwData ) { if ( UnicodeSystem() ) { return ::HtmlHelpW( hwndCaller, pszFile, uCommand, dwData ); } else { return ::HtmlHelpA( hwndCaller, CSpToAnsiString<> (pszFile), uCommand, dwData ); } } #endif // __HTMLHELP_H__ BOOL GetUserName(LPWSTR lpBuffer, LPDWORD pnSize) { if (UnicodeSystem()) { return ::GetUserNameW(lpBuffer, pnSize); } else { DWORD cchWideCharBuff = *pnSize; CHAR * psz = (CHAR *)_alloca(cchWideCharBuff * sizeof(CHAR)); BOOL fWorked = ::GetUserNameA(psz, pnSize); if (fWorked) { *pnSize = ::MultiByteToWideChar(CP_ACP, 0, psz, -1, lpBuffer, cchWideCharBuff); if (*pnSize == 0) { fWorked = FALSE; *pnSize = ::MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0); } } return fWorked; } } #if defined(mmioOpen) HMMIO mmioOpen(LPCWSTR szFileName, LPMMIOINFO lpmmioinfo, DWORD dwOpenFlags) const { if (UnicodeSystem()) { return ::mmioOpenW((WCHAR *)szFileName, lpmmioinfo, dwOpenFlags); } else { return ::mmioOpenA(CSpToAnsiString<>(szFileName), lpmmioinfo, dwOpenFlags); } } MMRESULT waveOutGetDevCaps(UINT uDeviceId, LPWAVEOUTCAPSW pwoc, UINT cbwoc) const { // Some drivers overwrite the WAVEINCAPS buffer by a DWORD. So they probably do it for // WAVEOUTCAPS too MMRESULT mmr = MMSYSERR_NOERROR; if (UnicodeSystem()) { BYTE *pBuffer = new BYTE[sizeof(WAVEOUTCAPSW) + sizeof(DWORD)]; WAVEOUTCAPSW *pwocw = reinterpret_cast(pBuffer); if (pwocw) { mmr = ::waveOutGetDevCapsW(uDeviceId, pwocw, cbwoc); if (mmr == MMSYSERR_NOERROR) { *pwoc = *pwocw; } delete [] pBuffer; } else { mmr = MMSYSERR_ERROR; } } else { BYTE *pBuffer = new BYTE[sizeof(WAVEOUTCAPSA) + sizeof(DWORD)]; WAVEOUTCAPSA *pwoca = reinterpret_cast(pBuffer); if (pwoca) { mmr = ::waveOutGetDevCapsA(uDeviceId, pwoca, sizeof(*pwoca)); if (mmr == MMSYSERR_NOERROR) { pwoc->wMid = pwoca->wMid; pwoc->wPid = pwoca->wPid; pwoc->vDriverVersion = pwoca->vDriverVersion; pwoc->dwFormats = pwoca->dwFormats; pwoc->wChannels = pwoca->wChannels; pwoc->wReserved1 = pwoca->wReserved1; pwoc->dwSupport = pwoca->dwSupport; ::MultiByteToWideChar(CP_ACP, 0, pwoca->szPname, -1, pwoc->szPname, sp_countof(pwoc->szPname)); } else { mmr = MMSYSERR_ERROR; } } else { mmr = MMSYSERR_ERROR; } } return mmr; } MMRESULT waveInGetDevCaps(UINT uDeviceId, LPWAVEINCAPSW pwic, UINT cbwic) const { // Some drivers overwrite the WAVEINCAPS buffer by a DWORD MMRESULT mmr = MMSYSERR_NOERROR; if (UnicodeSystem()) { BYTE *pBuffer = new BYTE[sizeof(WAVEINCAPSW) + sizeof(DWORD)]; WAVEINCAPSW *pwicw = reinterpret_cast(pBuffer); if (pwicw) { mmr = ::waveInGetDevCapsW(uDeviceId, pwicw, cbwic); if (mmr == MMSYSERR_NOERROR) { *pwic = *pwicw; } delete [] pBuffer; } else { mmr = MMSYSERR_ERROR; } } else { BYTE *pBuffer = new BYTE[sizeof(WAVEINCAPSA) + sizeof(DWORD)]; WAVEINCAPSA *pwica = reinterpret_cast(pBuffer); if (pwica) { mmr = ::waveInGetDevCapsA(uDeviceId, pwica, sizeof(*pwica)); if (mmr == MMSYSERR_NOERROR) { pwic->wMid = pwica->wMid; pwic->wPid = pwica->wPid; pwic->vDriverVersion = pwica->vDriverVersion; pwic->dwFormats = pwica->dwFormats; pwic->wChannels = pwica->wChannels; pwic->wReserved1 = pwica->wReserved1; ::MultiByteToWideChar(CP_ACP, 0, pwica->szPname, -1, pwic->szPname, sp_countof(pwic->szPname)); } delete [] pBuffer; } else { mmr = MMSYSERR_ERROR; } } return mmr; } #endif // defined(mmioOpen) }; #ifdef _UNICODE typedef CSpUnicodeSupportT CSpUnicodeSupport; #else typedef CSpUnicodeSupportT CSpUnicodeSupport; #endif #else //_WIN32_WCE class CSpUnicodeSupport { public: HANDLE CreateFile(const WCHAR * lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) const { return ::CreateFile( lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } HANDLE CreateFileForMapping(const WCHAR * lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) const { return ::CreateFileForMappingW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } DWORD GetFullPathName(WCHAR *lpFileName, // file name DWORD nBufferLength, // size of path buffer WCHAR *lpBuffer, // path buffer WCHAR **lpFilePart // address of file name in path ) { return ::GetFullPathName(lpFileName, nBufferLength, lpBuffer, lpFilePart); } BOOL DeleteFile(LPCWSTR lpFileName) { return ::DeleteFileW(lpFileName); } BOOL MoveFile(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName) { return ::MoveFileW(lpExistingFileName, lpNewFileName); } BOOL CopyFile(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, BOOL bFailIfExists) { return ::CopyFileW(lpExistingFileName, lpNewFileName, bFailIfExists); } BOOL CreateDirectory(const WCHAR * lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes) const { return ::CreateDirectoryW(lpPathName, lpSecurityAttributes); } BOOL RemoveDirectory(const WCHAR * lpPathName) const { return ::RemoveDirectoryW(lpPathName); } HANDLE CreateFileMapping(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, const WCHAR *lpName) { return ::CreateFileMappingW(hFile, lpFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, lpName); } BOOL SetFileAttributes(LPCWSTR lpFileName, DWORD dwFileAttributes) { return ::SetFileAttributesW(lpFileName, dwFileAttributes); } DWORD GetFileAttributes(LPCWSTR lpFileName) { return ::GetFileAttributesW(lpFileName); } LONG RegOpenKeyEx(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) const { #ifdef _WIN32_WCE_BUG_10655 BOOL bValid = (hKey != INVALID_HANDLE_VALUE) && phkResult; LONG lRet = ::RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult); return (lRet == ERROR_INVALID_PARAMETER && bValid)? ERROR_FILE_NOT_FOUND : lRet; //WCE bug #else return ::RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult); #endif } LONG RegCreateKeyEx(HKEY hk, LPCWSTR lpSubKey, DWORD dwReserved, LPCWSTR lpClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition) const { return ::RegCreateKeyExW(hk, lpSubKey, dwReserved, (WCHAR *)lpClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition); } LONG RegDeleteKey(HKEY hKey, LPCWSTR lpSubKey) const { #ifdef _WIN32_WCE_BUG_10655 BOOL bValid = (hKey != INVALID_HANDLE_VALUE) && lpSubKey; LONG lRet = ::RegDeleteKeyW(hKey, lpSubKey); return (lRet == ERROR_INVALID_PARAMETER && bValid)? ERROR_FILE_NOT_FOUND : lRet; //WCE bug #else return ::RegDeleteKeyW(hKey, lpSubKey); #endif } LONG RegDeleteValue(HKEY hKey, LPCWSTR lpSubKey) const { #ifdef _WIN32_WCE_BUG_10655 BOOL bValid = (hKey != INVALID_HANDLE_VALUE); LONG lRet = ::RegDeleteValueW(hKey, lpSubKey); return (lRet == ERROR_INVALID_PARAMETER && bValid)? ERROR_FILE_NOT_FOUND : lRet; //WCE bug #else return ::RegDeleteValueW(hKey, lpSubKey); #endif } LONG RegQueryValueEx(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) const { #ifdef _WIN32_WCE_BUG_10655 BOOL bValid = (hKey != INVALID_HANDLE_VALUE) && ((lpData && lpcbData) || (!lpData && !lpcbData)); LONG lRet = ::RegQueryValueExW(hKey, lpValueName, NULL, lpType, lpData, lpcbData); return (lRet == ERROR_INVALID_PARAMETER && bValid)? ERROR_FILE_NOT_FOUND : lRet; //WCE bug #else return ::RegQueryValueExW(hKey, lpValueName, NULL, lpType, lpData, lpcbData); #endif } // // NOTE: The size parameter is in CHARACTERS! Even though the registry API sizes are // in bytes, this function uses character counts. // LONG RegQueryStringValue(HKEY hKey, LPCWSTR lpValueName, LPWSTR lpData, LPDWORD lpcchData) const { DWORD dwType; *lpcchData *= sizeof(WCHAR); #ifdef _WIN32_WCE_BUG_10655 BOOL bValid = (hKey != INVALID_HANDLE_VALUE) && lpData; #endif LONG lRet = ::RegQueryValueExW(hKey, lpValueName, NULL, &dwType, (BYTE *)lpData, lpcchData); *lpcchData /= sizeof(WCHAR); #ifdef _WIN32_WCE_BUG_10655 return (lRet == ERROR_INVALID_PARAMETER && bValid)? ERROR_FILE_NOT_FOUND : lRet; //WCE bug #else return lRet; #endif } // // NOTES: Size is in bytes. Although this function uses RegEnumKeyEx, we chose to simply // implement the ReqEnumKey functionality since the Ex functionality is not used // by most programs (this saves a bunch of string conversion code). // LONG RegEnumKey(HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcbName) const { #ifdef _WIN32_WCE_BUG_10655 BOOL bValid = (hKey != INVALID_HANDLE_VALUE) && lpName && lpcbName; LONG lRet = ::RegEnumKeyExW(hKey, dwIndex, lpName, lpcbName, NULL, NULL, NULL, NULL); return (lRet == ERROR_INVALID_PARAMETER && bValid)? ERROR_FILE_NOT_FOUND : lRet; //WCE bug #else return ::RegEnumKeyExW(hKey, dwIndex, lpName, lpcbName, NULL, NULL, NULL, NULL); #endif } // // NOTES: Size is in Characters for lpcchName. Although this function uses RegEnumValue // it will only return the names, not the data. cbValueName is the count of characters // LONG RegEnumValueName(HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcchName) const { #ifdef _WIN32_WCE_BUG_10655 BOOL bValid = (hKey != INVALID_HANDLE_VALUE) && lpName && lpcchName; LONG lRet = ::RegEnumValueW(hKey, dwIndex, lpName, lpcchName, NULL, NULL, NULL, NULL); return (lRet == ERROR_INVALID_PARAMETER && bValid)? ERROR_FILE_NOT_FOUND : lRet; //WCE bug #else return ::RegEnumValueW(hKey, dwIndex, lpName, lpcchName, NULL, NULL, NULL, NULL); #endif } LONG RegSetValueEx(HKEY hKey, LPCWSTR lpValueName, DWORD Reserved, DWORD dwType, const BYTE * lpData, DWORD cbData) const { #ifdef _WIN32_WCE_BUG_10655 BOOL bValid = (hKey != INVALID_HANDLE_VALUE) && lpData; LONG lRet = ::RegSetValueExW(hKey, lpValueName, Reserved, dwType, lpData, cbData); return (lRet == ERROR_INVALID_PARAMETER && bValid)? ERROR_FILE_NOT_FOUND : lRet; //WCE bug #else return ::RegSetValueExW(hKey, lpValueName, Reserved, dwType, lpData, cbData); #endif } LONG RegSetStringValue(HKEY hKey, LPCWSTR lpValueName, LPCWSTR lpData) const { DWORD dwSize = (wcslen(lpData)+1) * sizeof(WCHAR); #ifdef _WIN32_WCE_BUG_10655 BOOL bValid = (hKey != INVALID_HANDLE_VALUE) && lpData; LONG lRet = ::RegSetValueExW(hKey, lpValueName, NULL, REG_SZ, (const BYTE *)lpData, dwSize); return (lRet == ERROR_INVALID_PARAMETER && bValid)? ERROR_FILE_NOT_FOUND : lRet; //WCE bug #else return ::RegSetValueExW(hKey, lpValueName, NULL, REG_SZ, (const BYTE *)lpData, dwSize); #endif } HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName) const { return ::CreateEventW(lpEventAttributes, bManualReset, bInitialState, lpName); } HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCWSTR lpName) const { return ::CreateMutexW(lpMutexAttributes, bInitialOwner, lpName); } int LoadString(HINSTANCE hInstance, UINT uID, LPWSTR lpBuffer, int nBuffer) const { return ::LoadStringW(hInstance, uID, lpBuffer, nBuffer); } HMODULE LoadLibrary(LPCWSTR lpLibFileName) { return ::LoadLibraryW(lpLibFileName); } HMODULE LoadLibraryEx(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) { return ::LoadLibraryExW(lpLibFileName, hFile, dwFlags); } HRSRC FindResource(HMODULE hModule, LPCWSTR lpName, LPCWSTR lpType) { return ::FindResource(hModule, lpName, lpType); } DWORD GetModuleFileName(HMODULE hModule, LPWSTR lpFileName, DWORD nSize) const { return ::GetModuleFileNameW(hModule, lpFileName, nSize); } // WCE does not support GetSystemDirectory #if 0 UINT GetSystemDirectory( LPWSTR lpBuffer, UINT uSize ) { return ::GetSystemDirectoryW( lpBuffer, uSize ); } #endif int CompareString(LCID Locale, DWORD dwCmpFlags, LPCWSTR lpString1, int cchCount1, LPCWSTR lpString2, int cchCount2) { return ::CompareStringW(Locale, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2); } BOOL SetWindowText( HWND hWnd, LPCWSTR lpString ) { return ::SetWindowTextW( hWnd, lpString ); } BOOL SetDlgItemText( HWND hDlg, int nIDDlgItem, LPCWSTR lpString ) { return ::SetDlgItemTextW( hDlg, nIDDlgItem, lpString ); } int MessageBox( HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType ) { return ::MessageBoxW( hWnd, lpText, lpCaption, uType ); } int GetLocaleInfo( LCID Locale, LCTYPE LCType, LPWSTR lpLCData, int cchData ) { return ::GetLocaleInfoW( Locale, LCType, lpLCData, cchData ); } int GetTimeFormat( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME *lpTime, LPCWSTR lpFormat, LPWSTR lpTimeStr, int cchTime ) { return ::GetTimeFormatW( Locale, dwFlags, lpTime, lpFormat, lpTimeStr, cchTime ); } int GetNumberFormat( LCID Locale, DWORD dwFlags, LPCWSTR lpValue, CONST NUMBERFMTW *lpFormat, LPWSTR lpNumberStr, int cchNumber ) { return ::GetNumberFormatW( Locale, dwFlags, lpValue, lpFormat, lpNumberStr, cchNumber ); int GetCurrencyFormat( LCID Locale, DWORD dwFlags, LPCWSTR lpValue, CONST CURRENCYFMTW *lpFormat, LPWSTR lpCurrencyStr, int cchCurrency ) { return ::GetCurrencyFormatW( Locale, dwFlags, lpValue, lpFormat, lpCurrencyStr, cchCurrency ); } LONG_PTR GetWindowLongPtr( HWND hWnd, int nIndex ) { return ::GetWindowLongPtr( hWnd, nIndex ); } LONG_PTR SetWindowLongPtr( HWND hWnd, int nIndex, LONG_PTR dwNewLong ) { return ::SetWindowLongPtr( hWnd, nIndex, dwNewLong ); } INT_PTR DialogBoxParamCE( HINSTANCE hInstance, LPCWSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam ) { return ::DialogBoxParamW( hInstance, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam ); } LRESULT SendDlgItemMessage(HWND hDlg, int nIDDlgItem, UINT Msg, WPARAM wParam, LPARAM lParam ) { return ::SendDlgItemMessageW(hDlg, nIDDlgItem, Msg, wParam, lParam ); } #ifdef __HTMLHELP_H__ HWND WINAPI HtmlHelp( HWND hwndCaller, LPCWSTR pszFile, UINT uCommand, DWORD_PTR dwData ) { return HtmlHelpW( hwndCaller, pszFile, uCommand, dwData ); } #endif // __HTMLHELP_H__ HMMIO mmioOpen(LPCWSTR szFileName, LPMMIOINFO lpmmioinfo, DWORD dwOpenFlags) const { return ::mmioOpenW((WCHAR *)szFileName, lpmmioinfo, dwOpenFlags); } MMRESULT waveOutGetDevCaps(UINT uDeviceId, LPWAVEOUTCAPS pwoc, UINT cbwoc) const { return ::waveOutGetDevCaps(uDeviceId, pwoc, cbwoc); } MMRESULT waveInGetDevCaps(UINT uDeviceId, LPWAVEINCAPS pwic, UINT cbwic) const { return ::waveInGetDevCaps(uDeviceId, pwic, cbwic); } }; #endif // // Assume a global named g_Unicode // extern CSpUnicodeSupport g_Unicode; #endif // Must be the last line of file. (#ifdef __SPUNICODE_H__)