Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

590 lines
19 KiB

  1. /*++
  2. Copyright (c) 2000-2001, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. convert.c
  5. Abstract:
  6. These functions make A->W and W->A translations of all types
  7. easier.
  8. StackAllocCheck
  9. DevModeAfromW
  10. DevModeWfromA
  11. LogFontAfromW
  12. Win32FindDataWfromA
  13. TextMetricWfromA
  14. NewTextMetricWfromA
  15. NewTextMetricExWfromA
  16. MenuItemInfoAfromW
  17. CpgFromLocale
  18. CbPerChOfCpg
  19. GrszToGrwz
  20. GrwzToGrsz
  21. SzToWzCch
  22. Revision History:
  23. 17 Mar 2001 v-michka Created.
  24. --*/
  25. #include "precomp.h"
  26. /*-------------------------------
  27. StackAllocCheck
  28. Verify there is room on the stack for the allocation
  29. -------------------------------*/
  30. BOOL StackAllocCheck(size_t size)
  31. {
  32. BOOL RetVal;
  33. PVOID mem;
  34. __try
  35. {
  36. mem = (void *)((size)?(_alloca(size)):NULL);
  37. RetVal = TRUE;
  38. }
  39. __except (GetExceptionCode() == EXCEPTION_STACK_OVERFLOW ? EXCEPTION_EXECUTE_HANDLER :
  40. EXCEPTION_CONTINUE_SEARCH )
  41. {
  42. gresetstkoflw();
  43. mem = NULL;
  44. SetLastError(ERROR_STACK_OVERFLOW);
  45. RetVal = FALSE;
  46. }
  47. return(RetVal);
  48. }
  49. /*-------------------------------
  50. GodotToCpgCchOnHeap
  51. Converts the given string to Ansi.
  52. -------------------------------*/
  53. ALLOCRETURN GodotToCpgCchOnHeap(LPCWSTR lpwz, int cchMax, LPSTR * lpsz, UINT cpg, UINT mcs)
  54. {
  55. // Parameter check
  56. if(!lpsz)
  57. return(arBadParam);
  58. if(FSTRING_VALID(lpwz))
  59. {
  60. int cch = gwcslen(lpwz);
  61. if(cchMax !=-1 && cchMax < cch)
  62. cch = cchMax;
  63. *lpsz = GodotHeapAlloc((cch+1)*mcs);
  64. if(! *lpsz)
  65. {
  66. SetLastError(ERROR_OUTOFMEMORY);
  67. return(arFailed);
  68. }
  69. WideCharToMultiByte(cpg, 0, lpwz, cch, *lpsz, cch*mcs, NULL, NULL);
  70. return(arAlloc);
  71. }
  72. else
  73. {
  74. // Copy the NULL or the ATOM. No alloc needed
  75. *lpsz = (LPSTR)lpwz;
  76. return(arNoAlloc);
  77. }
  78. }
  79. /*-------------------------------
  80. GodotToUnicodeCpgCchOnHeap
  81. Converts the given string to Unicode.
  82. -------------------------------*/
  83. ALLOCRETURN GodotToUnicodeCpgCchOnHeap(LPCSTR lpsz, int cchMax, LPWSTR * lpwz, UINT cpg)
  84. {
  85. // Parameter check
  86. if(!lpwz)
  87. return(arBadParam);
  88. if(FSTRING_VALID(lpsz))
  89. {
  90. int cch = lstrlenA(lpsz);
  91. if(cchMax !=-1 && cchMax < cch)
  92. cch = cchMax;
  93. *lpwz = GodotHeapAlloc((cch + 1)*sizeof(WCHAR));
  94. if(! *lpwz)
  95. {
  96. SetLastError(ERROR_OUTOFMEMORY);
  97. return(arFailed);
  98. }
  99. MultiByteToWideChar(cpg, 0, lpsz, cch, *lpwz, cch*sizeof(WCHAR));
  100. return(arAlloc);
  101. }
  102. else
  103. {
  104. // Copy the NULL or the ATOM. No alloc needed
  105. *lpwz = (LPWSTR)lpsz;
  106. return(arNoAlloc);
  107. }
  108. }
  109. /*-------------------------------
  110. DevModeAfromW
  111. The name says it all. Assumes that it is being passed already alloc'ed parameters
  112. -------------------------------*/
  113. void DevModeAfromW(LPDEVMODEA lpdma, LPDEVMODEW lpdmw)
  114. {
  115. WideCharToMultiByte(g_acp, 0,
  116. (LPWSTR)(lpdmw->dmDeviceName), CCHDEVICENAME,
  117. (LPSTR)(lpdma->dmDeviceName), CCHDEVICENAME*g_mcs,
  118. NULL, NULL);
  119. memcpy(&lpdma->dmSpecVersion,
  120. &lpdmw->dmSpecVersion,
  121. (4*sizeof(WORD) + sizeof(DWORD) + (13*sizeof(short))));
  122. WideCharToMultiByte(g_acp, 0,
  123. (LPWSTR)(lpdmw->dmFormName), CCHFORMNAME,
  124. (LPSTR)(lpdma->dmFormName), CCHFORMNAME*g_mcs,
  125. NULL, NULL);
  126. memcpy(&lpdma->dmLogPixels, &lpdmw->dmLogPixels, (sizeof(WORD) + (11*sizeof(DWORD))));
  127. lpdma->dmSize = CDSIZEOF_STRUCT(DEVMODEA, dmReserved2);
  128. // Make sure we copy the extra driver bytes.
  129. if (lpdmw->dmDriverExtra)
  130. memcpy((char*)lpdma + lpdma->dmSize, (char*)lpdmw + lpdmw->dmSize, lpdmw->dmDriverExtra);
  131. return;
  132. }
  133. /*-------------------------------
  134. DevModeWfromA
  135. The name says it all. Assumes that it is being passed already alloc'ed parameters
  136. -------------------------------*/
  137. void DevModeWfromA(LPDEVMODEW lpdmw, LPDEVMODEA lpdma)
  138. {
  139. MultiByteToWideChar(g_acp, 0,
  140. (LPSTR)(lpdma->dmDeviceName), CCHDEVICENAME,
  141. (LPWSTR)(lpdmw->dmDeviceName), CCHDEVICENAME);
  142. memcpy(&lpdmw->dmSpecVersion,
  143. &lpdma->dmSpecVersion,
  144. 4*sizeof(WORD) + sizeof(DWORD) + (13*sizeof(short)));
  145. MultiByteToWideChar(g_acp, 0,
  146. (LPSTR)(lpdma->dmFormName), CCHFORMNAME,
  147. (LPWSTR)(lpdmw->dmFormName), CCHFORMNAME);
  148. memcpy(&lpdmw->dmLogPixels, &lpdma->dmLogPixels, sizeof(WORD) + (11*sizeof(DWORD)));
  149. lpdmw->dmSize = CDSIZEOF_STRUCT(DEVMODEW, dmReserved2);
  150. // Make sure we copy the extra driver bytes.
  151. if (lpdma->dmDriverExtra)
  152. memcpy((char*)lpdmw + lpdmw->dmSize, (char*)lpdma + lpdma->dmSize, lpdma->dmDriverExtra);
  153. return;
  154. }
  155. /*-------------------------------
  156. HDevModeAfromW
  157. Wrapper around DevModeAfromW that does the right thing with global
  158. memory. Does not require that hdmw be set (but will not touch hdma
  159. unless it is).
  160. -------------------------------*/
  161. HGLOBAL HDevModeAfromW(HGLOBAL * lphdmw, BOOL fFree)
  162. {
  163. HGLOBAL hdma = NULL;
  164. if(lphdmw && *lphdmw)
  165. {
  166. LPDEVMODEW lpdmw = (LPDEVMODEW)GlobalLock(*lphdmw);
  167. if(lpdmw)
  168. {
  169. if(hdma = GlobalAlloc(GHND, sizeof(DEVMODEA) + lpdmw->dmDriverExtra))
  170. {
  171. LPDEVMODEA lpdma = (LPDEVMODEA)GlobalLock(hdma);
  172. if(lpdma)
  173. {
  174. DevModeAfromW(lpdma, lpdmw);
  175. GlobalUnlock(hdma);
  176. }
  177. else
  178. GlobalFree(hdma);
  179. }
  180. GlobalUnlock(*lphdmw);
  181. if(fFree)
  182. {
  183. GlobalFree(*lphdmw);
  184. *lphdmw = NULL;
  185. }
  186. }
  187. }
  188. return(hdma);
  189. }
  190. /*-------------------------------
  191. HDevModeWfromA
  192. Wrapper around DevModeWfromA that does the right thing with global
  193. memory. Does not require that hdma be set (but will not touch hdma
  194. unless it is).
  195. -------------------------------*/
  196. HGLOBAL HDevModeWfromA(HGLOBAL * lphdma, BOOL fFree)
  197. {
  198. HGLOBAL hdmw = NULL;
  199. if(lphdma && *lphdma)
  200. {
  201. LPDEVMODEA lpdma = (LPDEVMODEA)GlobalLock(*lphdma);
  202. if(lpdma)
  203. {
  204. if(hdmw = GlobalAlloc(GHND, sizeof(DEVMODEW) + lpdma->dmDriverExtra))
  205. {
  206. LPDEVMODEW lpdmw = (LPDEVMODEW)GlobalLock(hdmw);
  207. if(lpdmw)
  208. {
  209. DevModeWfromA(lpdmw, lpdma);
  210. GlobalUnlock(hdmw);
  211. }
  212. else
  213. GlobalFree(hdmw);
  214. }
  215. GlobalUnlock(*lphdma);
  216. if(fFree)
  217. {
  218. GlobalFree(*lphdma);
  219. *lphdma = NULL;
  220. }
  221. }
  222. }
  223. return(hdmw);
  224. }
  225. /*-------------------------------
  226. HDevNamesAfromW
  227. The name says it all. Does not require hdnw to be set (but will not
  228. touch hdma unless it is).
  229. -------------------------------*/
  230. HGLOBAL HDevNamesAfromW(HGLOBAL * lphdnw, BOOL fFree)
  231. {
  232. HGLOBAL hdna = NULL;
  233. if(lphdnw && *lphdnw)
  234. {
  235. LPDEVNAMES lpdnw = (LPDEVNAMES)GlobalLock(*lphdnw);
  236. if(lpdnw)
  237. {
  238. int cchDriver = gwcslen((LPCWSTR)lpdnw + lpdnw->wDriverOffset) + 1;
  239. int cchDevice = gwcslen((LPCWSTR)lpdnw + lpdnw->wDeviceOffset) + 1;
  240. int cchOutput = gwcslen((LPCWSTR)lpdnw + lpdnw->wOutputOffset) + 1;
  241. if(hdna = GlobalAlloc(GHND, sizeof(DEVNAMES) +
  242. (g_mcs * (cchDriver + cchDevice + cchOutput))))
  243. {
  244. LPDEVNAMES lpdna = (LPDEVNAMES)GlobalLock(hdna);
  245. if(!lpdna)
  246. GlobalFree(hdna);
  247. else
  248. {
  249. lpdna->wDriverOffset = sizeof(DEVNAMES);
  250. lpdna->wDeviceOffset = lpdna->wDriverOffset + cchDriver;
  251. lpdna->wOutputOffset = lpdna->wDeviceOffset + cchDevice;
  252. lpdna->wDefault = lpdna->wDefault;
  253. WideCharToMultiByte(g_acp, 0,
  254. (LPWSTR)lpdnw + lpdnw->wDriverOffset, cchDriver*g_mcs,
  255. (LPSTR)lpdna + lpdna->wDriverOffset, cchDriver,
  256. NULL, NULL);
  257. WideCharToMultiByte(g_acp, 0,
  258. (LPWSTR)lpdnw + lpdnw->wDeviceOffset, cchDevice*g_mcs,
  259. (LPSTR)lpdna + lpdna->wDeviceOffset, cchDevice,
  260. NULL, NULL);
  261. WideCharToMultiByte(g_acp, 0,
  262. (LPWSTR)lpdnw + lpdnw->wOutputOffset, cchOutput*g_mcs,
  263. (LPSTR)lpdna + lpdna->wOutputOffset, cchOutput,
  264. NULL, NULL);
  265. GlobalUnlock(hdna);
  266. }
  267. }
  268. GlobalUnlock(*lphdnw);
  269. if(fFree)
  270. {
  271. GlobalFree(*lphdnw);
  272. *lphdnw = NULL;
  273. }
  274. }
  275. }
  276. return(hdna);
  277. }
  278. /*-------------------------------
  279. HDevNamesWfromA
  280. The name says it all. Does not require hdna to be set (but does
  281. not touch hdnw unless it is).
  282. -------------------------------*/
  283. HGLOBAL HDevNamesWfromA(HGLOBAL * lphdna, BOOL fFree)
  284. {
  285. HGLOBAL hdnw = NULL;
  286. if(lphdna && *lphdna)
  287. {
  288. LPDEVNAMES lpdna = (LPDEVNAMES)GlobalLock(*lphdna);
  289. if(lpdna)
  290. {
  291. int cchDriver = lstrlenA((LPCSTR)lpdna + lpdna->wDriverOffset) + 1;
  292. int cchDevice = lstrlenA((LPCSTR)lpdna + lpdna->wDeviceOffset) + 1;
  293. int cchOutput = lstrlenA((LPCSTR)lpdna + lpdna->wOutputOffset) + 1;
  294. if(hdnw = GlobalAlloc(GHND, sizeof(DEVNAMES) +
  295. (sizeof(WCHAR) * (cchDriver + cchDevice + cchOutput))))
  296. {
  297. LPDEVNAMES lpdnw = (LPDEVNAMES)GlobalLock(hdnw);
  298. if(!lpdnw)
  299. GlobalFree(hdnw);
  300. else
  301. {
  302. lpdnw->wDriverOffset = sizeof(DEVNAMES) / sizeof(WCHAR);
  303. lpdnw->wDeviceOffset = lpdnw->wDriverOffset + cchDriver;
  304. lpdnw->wOutputOffset = lpdnw->wDeviceOffset + cchDevice;
  305. lpdnw->wDefault = lpdna->wDefault;
  306. MultiByteToWideChar(g_acp, 0,
  307. (LPSTR)lpdna + lpdna->wDriverOffset, cchDriver,
  308. (LPWSTR)lpdnw + lpdnw->wDriverOffset, cchDriver);
  309. MultiByteToWideChar(g_acp, 0,
  310. (LPSTR)lpdna + lpdna->wDeviceOffset, cchDevice,
  311. (LPWSTR)lpdnw + lpdnw->wDeviceOffset, cchDevice);
  312. MultiByteToWideChar(g_acp, 0,
  313. (LPSTR)lpdna + lpdna->wOutputOffset, cchOutput,
  314. (LPWSTR)lpdnw + lpdnw->wOutputOffset, cchOutput);
  315. GlobalUnlock(hdnw);
  316. }
  317. }
  318. GlobalUnlock(*lphdna);
  319. if(fFree)
  320. {
  321. GlobalFree(*lphdna);
  322. *lphdna = NULL;
  323. }
  324. }
  325. }
  326. return(hdnw);
  327. }
  328. /*-------------------------------
  329. LogFontAfromW
  330. The name says it all. Assumes that it is being passed already alloc'ed parameters
  331. -------------------------------*/
  332. void LogFontAfromW(LPLOGFONTA lplfa, LPLOGFONTW lplfw)
  333. {
  334. memcpy(lplfa, lplfw, (5*sizeof(LONG)+8*sizeof(BYTE)));
  335. WideCharToMultiByte(g_acp, 0,
  336. lplfw->lfFaceName, LF_FACESIZE,
  337. lplfa->lfFaceName, LF_FACESIZE,
  338. NULL, NULL);
  339. return;
  340. }
  341. /*-------------------------------
  342. LogFontWfromA
  343. The name says it all. Assumes that it is being passed already alloc'ed parameters
  344. -------------------------------*/
  345. void LogFontWfromA(LPLOGFONTW lplfw, LPLOGFONTA lplfa)
  346. {
  347. memcpy(lplfw, lplfa, (5*sizeof(LONG)+8*sizeof(BYTE)));
  348. MultiByteToWideChar(g_acp, 0, lplfa->lfFaceName, LF_FACESIZE, lplfw->lfFaceName, LF_FACESIZE);
  349. return;
  350. }
  351. /*-------------------------------
  352. Win32FindDataWfromA
  353. The name says it all. Assumes that it is being passed already alloc'ed parameters
  354. -------------------------------*/
  355. void Win32FindDataWfromA(PWIN32_FIND_DATAW w32fdw, PWIN32_FIND_DATAA w32fda)
  356. {
  357. UINT cpg = FILES_CPG;
  358. memcpy(w32fdw, w32fda, (3*sizeof(FILETIME)+5*sizeof(DWORD)));
  359. MultiByteToWideChar(cpg, 0, w32fda->cFileName, MAX_PATH, w32fdw->cFileName, MAX_PATH);
  360. MultiByteToWideChar(cpg, 0, w32fda->cAlternateFileName, 14, w32fdw->cAlternateFileName, 14);
  361. return;
  362. }
  363. /*-------------------------------
  364. TextMetricWfromA
  365. The name says it all. Assumes that it is being passed already alloc'ed parameters
  366. -------------------------------*/
  367. void TextMetricWfromA(LPTEXTMETRICW lptmw, LPTEXTMETRICA lptma)
  368. {
  369. memcpy(lptmw, lptma, (11*sizeof(LONG)));
  370. MultiByteToWideChar(g_acp, 0, &lptma->tmFirstChar, sizeof(char), &lptmw->tmFirstChar, sizeof(WCHAR));
  371. MultiByteToWideChar(g_acp, 0, &lptma->tmLastChar, sizeof(char), &lptmw->tmLastChar, sizeof(WCHAR));
  372. MultiByteToWideChar(g_acp, 0, &lptma->tmDefaultChar, sizeof(char), &lptmw->tmDefaultChar, sizeof(WCHAR));
  373. MultiByteToWideChar(g_acp, 0, &lptma->tmBreakChar, sizeof(char), &lptmw->tmBreakChar, sizeof(WCHAR));
  374. memcpy(&lptmw->tmItalic, &lptma->tmItalic, 5*sizeof(BYTE));
  375. return;
  376. }
  377. /*-------------------------------
  378. NewTextMetricWfromA
  379. The name says it all. Assumes that it is being passed already alloc'ed parameters
  380. -------------------------------*/
  381. void NewTextMetricWfromA(LPNEWTEXTMETRICW lpntmw, LPNEWTEXTMETRICA lpntma)
  382. {
  383. TextMetricWfromA((LPTEXTMETRICW)lpntmw, (LPTEXTMETRICA)lpntma);
  384. memcpy(&lpntmw->ntmFlags, &lpntma->ntmFlags, (sizeof(DWORD) + 3*sizeof(UINT)));
  385. return;
  386. }
  387. /*-------------------------------
  388. NewTextMetricExWfromA
  389. The name says it all. Assumes that it is being passed already alloc'ed parameters
  390. -------------------------------*/
  391. void NewTextMetricExWfromA(NEWTEXTMETRICEXW * lpntmew, NEWTEXTMETRICEXA * lpntmea)
  392. {
  393. TextMetricWfromA((LPTEXTMETRICW)lpntmew, (LPTEXTMETRICA)lpntmea);
  394. memcpy(&lpntmew->ntmTm.ntmFlags, &lpntmea->ntmTm.ntmFlags, (sizeof(DWORD) + 3*sizeof(UINT)));
  395. memcpy(&lpntmew->ntmFontSig, &lpntmea->ntmFontSig, sizeof(FONTSIGNATURE));
  396. return;
  397. }
  398. /*-------------------------------
  399. MenuItemInfoAfromW
  400. The name says it all. Assumes that it is being passed already alloc'ed parameters
  401. If the return value is TRUE, then the dwTypeData is a heap pointer to free.
  402. -------------------------------*/
  403. BOOL MenuItemInfoAfromW(LPMENUITEMINFOA lpmiia, LPCMENUITEMINFOW lpmiiw)
  404. {
  405. DWORD RetVal = FALSE;
  406. ZeroMemory(lpmiia, sizeof(MENUITEMINFOA));
  407. lpmiia->cbSize = sizeof(MENUITEMINFOA);
  408. lpmiia->fMask = lpmiiw->fMask;
  409. lpmiia->fType = lpmiiw->fType;
  410. lpmiia->fState = lpmiiw->fState;
  411. lpmiia->wID = lpmiiw->wID;
  412. lpmiia->hSubMenu = lpmiiw->hSubMenu;
  413. lpmiia->hbmpChecked = lpmiiw->hbmpChecked;
  414. lpmiia->hbmpUnchecked = lpmiiw->hbmpUnchecked;
  415. lpmiia->dwItemData = lpmiiw->dwItemData;
  416. lpmiia->hbmpItem = lpmiiw->hbmpItem;
  417. // Ok, now lets take care of the "strings", though we
  418. // do need to find out if they are in fact strings, first!
  419. if(((FWIN95()) &&
  420. ((lpmiiw->fMask & MIIM_TYPE) && (lpmiiw->fType == MFT_STRING))) ||
  421. ((!FWIN95() &&
  422. ((lpmiiw->fMask & MIIM_STRING) ||
  423. ((lpmiiw->fMask & MIIM_FTYPE) && (lpmiiw->fType == MFT_STRING))))))
  424. {
  425. if (FSTRING_VALID(lpmiiw->dwTypeData))
  426. {
  427. // Ok, it looks like a string and they say its a string, so lets
  428. // treat it like one. Be sure not to copy more than cch.
  429. size_t cch = gwcslen(lpmiiw->dwTypeData)+1;
  430. if (cch > lpmiiw->cch)
  431. cch = lpmiiw->cch;
  432. if(arAlloc == GodotToCpgCchOnHeap(lpmiiw->dwTypeData,
  433. cch,
  434. &(LPSTR)(lpmiia->dwTypeData),
  435. g_acp,
  436. g_mcs))
  437. {
  438. RetVal = TRUE;
  439. }
  440. // Set the final length explicitly; don't set by the buffer,
  441. // which may be more than we actually needed on MBCS
  442. lpmiia->cch = lstrlenA( lpmiia->dwTypeData);
  443. }
  444. else
  445. {
  446. // Think its a string per flags but does not look like a string,
  447. // so copy like an atom but set cch just in case!
  448. lpmiia->dwTypeData = (LPSTR)lpmiiw->dwTypeData;
  449. lpmiia->cch = sizeof(lpmiia->dwTypeData);
  450. }
  451. }
  452. else
  453. {
  454. // This ain't a string, darn it! cch is 0 and that's that! Its gonna be
  455. // ignored anyway.
  456. lpmiia->dwTypeData = (LPSTR)lpmiiw->dwTypeData;
  457. lpmiia->cch = 0;
  458. }
  459. return(RetVal);
  460. }
  461. /*------------------------------------------------------------------------
  462. GrszToGrwz (stolen from Office!)
  463. Converts a group of ANSI strings into a group of Unicode strings.
  464. Each string in the group is terminated by a null. Returns
  465. resulting length of the Unicode string stored in wzTo as a cb
  466. If return value is greater than cchTo, wzTo is not written to.
  467. -------------------------------------------------------------- MIKEKELL -*/
  468. int GrszToGrwz(const CHAR* szFrom, WCHAR* wzTo, int cchTo)
  469. {
  470. int cchRet = 0;
  471. const char *szFromSav = szFrom;
  472. do
  473. {
  474. int cch = strlen(szFrom)+1;
  475. cchRet += MultiByteToWideChar(g_acp, 0, szFrom, cch, NULL, 0);
  476. szFrom += cch;
  477. }
  478. while (*szFrom);
  479. cchRet++;
  480. szFrom = szFromSav;
  481. if (wzTo && (cchRet <= cchTo))
  482. {
  483. do
  484. {
  485. int cchConv;
  486. int cch = strlen(szFrom)+1;
  487. cchConv = MultiByteToWideChar(g_acp, 0, szFrom, cch, wzTo, cchTo);
  488. szFrom += cch;
  489. wzTo += cchConv;
  490. cchTo -= cchConv;
  491. }
  492. while (*szFrom);
  493. *wzTo = 0; // add extra null terminator.
  494. };
  495. return cchRet;
  496. }
  497. /*-------------------------------
  498. SzToWzCch
  499. Returns the unicode length of the string (including the
  500. null terminator). If this length is <= cch, then it also
  501. converts the string storing it into wz (otherwise, wz is unchanged)
  502. -------------------------------*/
  503. int SzToWzCch(const CHAR *sz, WCHAR *wz, int cch)
  504. {
  505. int cchNeed;
  506. cchNeed = MultiByteToWideChar(g_acp, 0, sz, -1, NULL, 0);
  507. if (cchNeed <= cch)
  508. {
  509. MultiByteToWideChar(g_acp, 0, sz, -1, wz, cch);
  510. };
  511. return cchNeed;
  512. };