/*++ Copyright (c) 2000-2001, Microsoft Corporation All rights reserved. Module Name: convert.c Abstract: These functions make A->W and W->A translations of all types easier. StackAllocCheck DevModeAfromW DevModeWfromA LogFontAfromW Win32FindDataWfromA TextMetricWfromA NewTextMetricWfromA NewTextMetricExWfromA MenuItemInfoAfromW CpgFromLocale CbPerChOfCpg GrszToGrwz GrwzToGrsz SzToWzCch Revision History: 17 Mar 2001 v-michka Created. --*/ #include "precomp.h" /*------------------------------- StackAllocCheck Verify there is room on the stack for the allocation -------------------------------*/ BOOL StackAllocCheck(size_t size) { BOOL RetVal; PVOID mem; __try { mem = (void *)((size)?(_alloca(size)):NULL); RetVal = TRUE; } __except (GetExceptionCode() == EXCEPTION_STACK_OVERFLOW ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) { gresetstkoflw(); mem = NULL; SetLastError(ERROR_STACK_OVERFLOW); RetVal = FALSE; } return(RetVal); } /*------------------------------- GodotToCpgCchOnHeap Converts the given string to Ansi. -------------------------------*/ ALLOCRETURN GodotToCpgCchOnHeap(LPCWSTR lpwz, int cchMax, LPSTR * lpsz, UINT cpg, UINT mcs) { // Parameter check if(!lpsz) return(arBadParam); if(FSTRING_VALID(lpwz)) { int cch = gwcslen(lpwz); if(cchMax !=-1 && cchMax < cch) cch = cchMax; *lpsz = GodotHeapAlloc((cch+1)*mcs); if(! *lpsz) { SetLastError(ERROR_OUTOFMEMORY); return(arFailed); } WideCharToMultiByte(cpg, 0, lpwz, cch, *lpsz, cch*mcs, NULL, NULL); return(arAlloc); } else { // Copy the NULL or the ATOM. No alloc needed *lpsz = (LPSTR)lpwz; return(arNoAlloc); } } /*------------------------------- GodotToUnicodeCpgCchOnHeap Converts the given string to Unicode. -------------------------------*/ ALLOCRETURN GodotToUnicodeCpgCchOnHeap(LPCSTR lpsz, int cchMax, LPWSTR * lpwz, UINT cpg) { // Parameter check if(!lpwz) return(arBadParam); if(FSTRING_VALID(lpsz)) { int cch = lstrlenA(lpsz); if(cchMax !=-1 && cchMax < cch) cch = cchMax; *lpwz = GodotHeapAlloc((cch + 1)*sizeof(WCHAR)); if(! *lpwz) { SetLastError(ERROR_OUTOFMEMORY); return(arFailed); } MultiByteToWideChar(cpg, 0, lpsz, cch, *lpwz, cch*sizeof(WCHAR)); return(arAlloc); } else { // Copy the NULL or the ATOM. No alloc needed *lpwz = (LPWSTR)lpsz; return(arNoAlloc); } } /*------------------------------- DevModeAfromW The name says it all. Assumes that it is being passed already alloc'ed parameters -------------------------------*/ void DevModeAfromW(LPDEVMODEA lpdma, LPDEVMODEW lpdmw) { WideCharToMultiByte(g_acp, 0, (LPWSTR)(lpdmw->dmDeviceName), CCHDEVICENAME, (LPSTR)(lpdma->dmDeviceName), CCHDEVICENAME*g_mcs, NULL, NULL); memcpy(&lpdma->dmSpecVersion, &lpdmw->dmSpecVersion, (4*sizeof(WORD) + sizeof(DWORD) + (13*sizeof(short)))); WideCharToMultiByte(g_acp, 0, (LPWSTR)(lpdmw->dmFormName), CCHFORMNAME, (LPSTR)(lpdma->dmFormName), CCHFORMNAME*g_mcs, NULL, NULL); memcpy(&lpdma->dmLogPixels, &lpdmw->dmLogPixels, (sizeof(WORD) + (11*sizeof(DWORD)))); lpdma->dmSize = CDSIZEOF_STRUCT(DEVMODEA, dmReserved2); // Make sure we copy the extra driver bytes. if (lpdmw->dmDriverExtra) memcpy((char*)lpdma + lpdma->dmSize, (char*)lpdmw + lpdmw->dmSize, lpdmw->dmDriverExtra); return; } /*------------------------------- DevModeWfromA The name says it all. Assumes that it is being passed already alloc'ed parameters -------------------------------*/ void DevModeWfromA(LPDEVMODEW lpdmw, LPDEVMODEA lpdma) { MultiByteToWideChar(g_acp, 0, (LPSTR)(lpdma->dmDeviceName), CCHDEVICENAME, (LPWSTR)(lpdmw->dmDeviceName), CCHDEVICENAME); memcpy(&lpdmw->dmSpecVersion, &lpdma->dmSpecVersion, 4*sizeof(WORD) + sizeof(DWORD) + (13*sizeof(short))); MultiByteToWideChar(g_acp, 0, (LPSTR)(lpdma->dmFormName), CCHFORMNAME, (LPWSTR)(lpdmw->dmFormName), CCHFORMNAME); memcpy(&lpdmw->dmLogPixels, &lpdma->dmLogPixels, sizeof(WORD) + (11*sizeof(DWORD))); lpdmw->dmSize = CDSIZEOF_STRUCT(DEVMODEW, dmReserved2); // Make sure we copy the extra driver bytes. if (lpdma->dmDriverExtra) memcpy((char*)lpdmw + lpdmw->dmSize, (char*)lpdma + lpdma->dmSize, lpdma->dmDriverExtra); return; } /*------------------------------- HDevModeAfromW Wrapper around DevModeAfromW that does the right thing with global memory. Does not require that hdmw be set (but will not touch hdma unless it is). -------------------------------*/ HGLOBAL HDevModeAfromW(HGLOBAL * lphdmw, BOOL fFree) { HGLOBAL hdma = NULL; if(lphdmw && *lphdmw) { LPDEVMODEW lpdmw = (LPDEVMODEW)GlobalLock(*lphdmw); if(lpdmw) { if(hdma = GlobalAlloc(GHND, sizeof(DEVMODEA) + lpdmw->dmDriverExtra)) { LPDEVMODEA lpdma = (LPDEVMODEA)GlobalLock(hdma); if(lpdma) { DevModeAfromW(lpdma, lpdmw); GlobalUnlock(hdma); } else GlobalFree(hdma); } GlobalUnlock(*lphdmw); if(fFree) { GlobalFree(*lphdmw); *lphdmw = NULL; } } } return(hdma); } /*------------------------------- HDevModeWfromA Wrapper around DevModeWfromA that does the right thing with global memory. Does not require that hdma be set (but will not touch hdma unless it is). -------------------------------*/ HGLOBAL HDevModeWfromA(HGLOBAL * lphdma, BOOL fFree) { HGLOBAL hdmw = NULL; if(lphdma && *lphdma) { LPDEVMODEA lpdma = (LPDEVMODEA)GlobalLock(*lphdma); if(lpdma) { if(hdmw = GlobalAlloc(GHND, sizeof(DEVMODEW) + lpdma->dmDriverExtra)) { LPDEVMODEW lpdmw = (LPDEVMODEW)GlobalLock(hdmw); if(lpdmw) { DevModeWfromA(lpdmw, lpdma); GlobalUnlock(hdmw); } else GlobalFree(hdmw); } GlobalUnlock(*lphdma); if(fFree) { GlobalFree(*lphdma); *lphdma = NULL; } } } return(hdmw); } /*------------------------------- HDevNamesAfromW The name says it all. Does not require hdnw to be set (but will not touch hdma unless it is). -------------------------------*/ HGLOBAL HDevNamesAfromW(HGLOBAL * lphdnw, BOOL fFree) { HGLOBAL hdna = NULL; if(lphdnw && *lphdnw) { LPDEVNAMES lpdnw = (LPDEVNAMES)GlobalLock(*lphdnw); if(lpdnw) { int cchDriver = gwcslen((LPCWSTR)lpdnw + lpdnw->wDriverOffset) + 1; int cchDevice = gwcslen((LPCWSTR)lpdnw + lpdnw->wDeviceOffset) + 1; int cchOutput = gwcslen((LPCWSTR)lpdnw + lpdnw->wOutputOffset) + 1; if(hdna = GlobalAlloc(GHND, sizeof(DEVNAMES) + (g_mcs * (cchDriver + cchDevice + cchOutput)))) { LPDEVNAMES lpdna = (LPDEVNAMES)GlobalLock(hdna); if(!lpdna) GlobalFree(hdna); else { lpdna->wDriverOffset = sizeof(DEVNAMES); lpdna->wDeviceOffset = lpdna->wDriverOffset + cchDriver; lpdna->wOutputOffset = lpdna->wDeviceOffset + cchDevice; lpdna->wDefault = lpdna->wDefault; WideCharToMultiByte(g_acp, 0, (LPWSTR)lpdnw + lpdnw->wDriverOffset, cchDriver*g_mcs, (LPSTR)lpdna + lpdna->wDriverOffset, cchDriver, NULL, NULL); WideCharToMultiByte(g_acp, 0, (LPWSTR)lpdnw + lpdnw->wDeviceOffset, cchDevice*g_mcs, (LPSTR)lpdna + lpdna->wDeviceOffset, cchDevice, NULL, NULL); WideCharToMultiByte(g_acp, 0, (LPWSTR)lpdnw + lpdnw->wOutputOffset, cchOutput*g_mcs, (LPSTR)lpdna + lpdna->wOutputOffset, cchOutput, NULL, NULL); GlobalUnlock(hdna); } } GlobalUnlock(*lphdnw); if(fFree) { GlobalFree(*lphdnw); *lphdnw = NULL; } } } return(hdna); } /*------------------------------- HDevNamesWfromA The name says it all. Does not require hdna to be set (but does not touch hdnw unless it is). -------------------------------*/ HGLOBAL HDevNamesWfromA(HGLOBAL * lphdna, BOOL fFree) { HGLOBAL hdnw = NULL; if(lphdna && *lphdna) { LPDEVNAMES lpdna = (LPDEVNAMES)GlobalLock(*lphdna); if(lpdna) { int cchDriver = lstrlenA((LPCSTR)lpdna + lpdna->wDriverOffset) + 1; int cchDevice = lstrlenA((LPCSTR)lpdna + lpdna->wDeviceOffset) + 1; int cchOutput = lstrlenA((LPCSTR)lpdna + lpdna->wOutputOffset) + 1; if(hdnw = GlobalAlloc(GHND, sizeof(DEVNAMES) + (sizeof(WCHAR) * (cchDriver + cchDevice + cchOutput)))) { LPDEVNAMES lpdnw = (LPDEVNAMES)GlobalLock(hdnw); if(!lpdnw) GlobalFree(hdnw); else { lpdnw->wDriverOffset = sizeof(DEVNAMES) / sizeof(WCHAR); lpdnw->wDeviceOffset = lpdnw->wDriverOffset + cchDriver; lpdnw->wOutputOffset = lpdnw->wDeviceOffset + cchDevice; lpdnw->wDefault = lpdna->wDefault; MultiByteToWideChar(g_acp, 0, (LPSTR)lpdna + lpdna->wDriverOffset, cchDriver, (LPWSTR)lpdnw + lpdnw->wDriverOffset, cchDriver); MultiByteToWideChar(g_acp, 0, (LPSTR)lpdna + lpdna->wDeviceOffset, cchDevice, (LPWSTR)lpdnw + lpdnw->wDeviceOffset, cchDevice); MultiByteToWideChar(g_acp, 0, (LPSTR)lpdna + lpdna->wOutputOffset, cchOutput, (LPWSTR)lpdnw + lpdnw->wOutputOffset, cchOutput); GlobalUnlock(hdnw); } } GlobalUnlock(*lphdna); if(fFree) { GlobalFree(*lphdna); *lphdna = NULL; } } } return(hdnw); } /*------------------------------- LogFontAfromW The name says it all. Assumes that it is being passed already alloc'ed parameters -------------------------------*/ void LogFontAfromW(LPLOGFONTA lplfa, LPLOGFONTW lplfw) { memcpy(lplfa, lplfw, (5*sizeof(LONG)+8*sizeof(BYTE))); WideCharToMultiByte(g_acp, 0, lplfw->lfFaceName, LF_FACESIZE, lplfa->lfFaceName, LF_FACESIZE, NULL, NULL); return; } /*------------------------------- LogFontWfromA The name says it all. Assumes that it is being passed already alloc'ed parameters -------------------------------*/ void LogFontWfromA(LPLOGFONTW lplfw, LPLOGFONTA lplfa) { memcpy(lplfw, lplfa, (5*sizeof(LONG)+8*sizeof(BYTE))); MultiByteToWideChar(g_acp, 0, lplfa->lfFaceName, LF_FACESIZE, lplfw->lfFaceName, LF_FACESIZE); return; } /*------------------------------- Win32FindDataWfromA The name says it all. Assumes that it is being passed already alloc'ed parameters -------------------------------*/ void Win32FindDataWfromA(PWIN32_FIND_DATAW w32fdw, PWIN32_FIND_DATAA w32fda) { UINT cpg = FILES_CPG; memcpy(w32fdw, w32fda, (3*sizeof(FILETIME)+5*sizeof(DWORD))); MultiByteToWideChar(cpg, 0, w32fda->cFileName, MAX_PATH, w32fdw->cFileName, MAX_PATH); MultiByteToWideChar(cpg, 0, w32fda->cAlternateFileName, 14, w32fdw->cAlternateFileName, 14); return; } /*------------------------------- TextMetricWfromA The name says it all. Assumes that it is being passed already alloc'ed parameters -------------------------------*/ void TextMetricWfromA(LPTEXTMETRICW lptmw, LPTEXTMETRICA lptma) { memcpy(lptmw, lptma, (11*sizeof(LONG))); MultiByteToWideChar(g_acp, 0, &lptma->tmFirstChar, sizeof(char), &lptmw->tmFirstChar, sizeof(WCHAR)); MultiByteToWideChar(g_acp, 0, &lptma->tmLastChar, sizeof(char), &lptmw->tmLastChar, sizeof(WCHAR)); MultiByteToWideChar(g_acp, 0, &lptma->tmDefaultChar, sizeof(char), &lptmw->tmDefaultChar, sizeof(WCHAR)); MultiByteToWideChar(g_acp, 0, &lptma->tmBreakChar, sizeof(char), &lptmw->tmBreakChar, sizeof(WCHAR)); memcpy(&lptmw->tmItalic, &lptma->tmItalic, 5*sizeof(BYTE)); return; } /*------------------------------- NewTextMetricWfromA The name says it all. Assumes that it is being passed already alloc'ed parameters -------------------------------*/ void NewTextMetricWfromA(LPNEWTEXTMETRICW lpntmw, LPNEWTEXTMETRICA lpntma) { TextMetricWfromA((LPTEXTMETRICW)lpntmw, (LPTEXTMETRICA)lpntma); memcpy(&lpntmw->ntmFlags, &lpntma->ntmFlags, (sizeof(DWORD) + 3*sizeof(UINT))); return; } /*------------------------------- NewTextMetricExWfromA The name says it all. Assumes that it is being passed already alloc'ed parameters -------------------------------*/ void NewTextMetricExWfromA(NEWTEXTMETRICEXW * lpntmew, NEWTEXTMETRICEXA * lpntmea) { TextMetricWfromA((LPTEXTMETRICW)lpntmew, (LPTEXTMETRICA)lpntmea); memcpy(&lpntmew->ntmTm.ntmFlags, &lpntmea->ntmTm.ntmFlags, (sizeof(DWORD) + 3*sizeof(UINT))); memcpy(&lpntmew->ntmFontSig, &lpntmea->ntmFontSig, sizeof(FONTSIGNATURE)); return; } /*------------------------------- MenuItemInfoAfromW The name says it all. Assumes that it is being passed already alloc'ed parameters If the return value is TRUE, then the dwTypeData is a heap pointer to free. -------------------------------*/ BOOL MenuItemInfoAfromW(LPMENUITEMINFOA lpmiia, LPCMENUITEMINFOW lpmiiw) { DWORD RetVal = FALSE; ZeroMemory(lpmiia, sizeof(MENUITEMINFOA)); lpmiia->cbSize = sizeof(MENUITEMINFOA); lpmiia->fMask = lpmiiw->fMask; lpmiia->fType = lpmiiw->fType; lpmiia->fState = lpmiiw->fState; lpmiia->wID = lpmiiw->wID; lpmiia->hSubMenu = lpmiiw->hSubMenu; lpmiia->hbmpChecked = lpmiiw->hbmpChecked; lpmiia->hbmpUnchecked = lpmiiw->hbmpUnchecked; lpmiia->dwItemData = lpmiiw->dwItemData; lpmiia->hbmpItem = lpmiiw->hbmpItem; // Ok, now lets take care of the "strings", though we // do need to find out if they are in fact strings, first! if(((FWIN95()) && ((lpmiiw->fMask & MIIM_TYPE) && (lpmiiw->fType == MFT_STRING))) || ((!FWIN95() && ((lpmiiw->fMask & MIIM_STRING) || ((lpmiiw->fMask & MIIM_FTYPE) && (lpmiiw->fType == MFT_STRING)))))) { if (FSTRING_VALID(lpmiiw->dwTypeData)) { // Ok, it looks like a string and they say its a string, so lets // treat it like one. Be sure not to copy more than cch. size_t cch = gwcslen(lpmiiw->dwTypeData)+1; if (cch > lpmiiw->cch) cch = lpmiiw->cch; if(arAlloc == GodotToCpgCchOnHeap(lpmiiw->dwTypeData, cch, &(LPSTR)(lpmiia->dwTypeData), g_acp, g_mcs)) { RetVal = TRUE; } // Set the final length explicitly; don't set by the buffer, // which may be more than we actually needed on MBCS lpmiia->cch = lstrlenA( lpmiia->dwTypeData); } else { // Think its a string per flags but does not look like a string, // so copy like an atom but set cch just in case! lpmiia->dwTypeData = (LPSTR)lpmiiw->dwTypeData; lpmiia->cch = sizeof(lpmiia->dwTypeData); } } else { // This ain't a string, darn it! cch is 0 and that's that! Its gonna be // ignored anyway. lpmiia->dwTypeData = (LPSTR)lpmiiw->dwTypeData; lpmiia->cch = 0; } return(RetVal); } /*------------------------------------------------------------------------ GrszToGrwz (stolen from Office!) Converts a group of ANSI strings into a group of Unicode strings. Each string in the group is terminated by a null. Returns resulting length of the Unicode string stored in wzTo as a cb If return value is greater than cchTo, wzTo is not written to. -------------------------------------------------------------- MIKEKELL -*/ int GrszToGrwz(const CHAR* szFrom, WCHAR* wzTo, int cchTo) { int cchRet = 0; const char *szFromSav = szFrom; do { int cch = strlen(szFrom)+1; cchRet += MultiByteToWideChar(g_acp, 0, szFrom, cch, NULL, 0); szFrom += cch; } while (*szFrom); cchRet++; szFrom = szFromSav; if (wzTo && (cchRet <= cchTo)) { do { int cchConv; int cch = strlen(szFrom)+1; cchConv = MultiByteToWideChar(g_acp, 0, szFrom, cch, wzTo, cchTo); szFrom += cch; wzTo += cchConv; cchTo -= cchConv; } while (*szFrom); *wzTo = 0; // add extra null terminator. }; return cchRet; } /*------------------------------- SzToWzCch Returns the unicode length of the string (including the null terminator). If this length is <= cch, then it also converts the string storing it into wz (otherwise, wz is unchanged) -------------------------------*/ int SzToWzCch(const CHAR *sz, WCHAR *wz, int cch) { int cchNeed; cchNeed = MultiByteToWideChar(g_acp, 0, sz, -1, NULL, 0); if (cchNeed <= cch) { MultiByteToWideChar(g_acp, 0, sz, -1, wz, cch); }; return cchNeed; };