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.

699 lines
19 KiB

  1. //
  2. // Unicwrap.cpp
  3. //
  4. // Simple thunking layer for NT/9X.
  5. //
  6. //
  7. #include "stdafx.h"
  8. #define _NO_UNICWRAP_WRAPPERS_
  9. #include "theapp.h"
  10. #include "cstrinout.h"
  11. ///////////////////////////////////////////////////////////////////////////
  12. //
  13. // WNET
  14. //
  15. DWORD WNetOpenEnumWrapW(DWORD dwScope, DWORD dwType, DWORD dwUsage, LPNETRESOURCEW lpNetResource, LPHANDLE lphEnum)
  16. {
  17. ASSERT(sizeof(NETRESOURCEA)==sizeof(NETRESOURCEW));
  18. if (g_fRunningOnNT)
  19. {
  20. return WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetResource, lphEnum);
  21. }
  22. else
  23. {
  24. if (!lpNetResource)
  25. {
  26. return WNetOpenEnumA(dwScope, dwType, dwUsage, NULL, lphEnum);
  27. }
  28. else
  29. {
  30. CStrIn cstrLocalName(lpNetResource->lpLocalName);
  31. CStrIn cstrRemoteName(lpNetResource->lpRemoteName);
  32. CStrIn cstrComment(lpNetResource->lpComment);
  33. CStrIn cstrProvider(lpNetResource->lpProvider);
  34. NETRESOURCEA nrA;
  35. CopyMemory(&nrA, lpNetResource, sizeof(nrA));
  36. nrA.lpLocalName = cstrLocalName;
  37. nrA.lpRemoteName = cstrRemoteName;
  38. nrA.lpComment = cstrComment;
  39. nrA.lpProvider = cstrProvider;
  40. return WNetOpenEnumA(dwScope, dwType, dwUsage, &nrA, lphEnum);
  41. }
  42. }
  43. }
  44. DWORD WNetEnumResourceWrapW(HANDLE hEnum, LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
  45. {
  46. ASSERT((!*lpBufferSize && !lpBuffer) || (*lpBufferSize && lpBuffer));
  47. if (g_fRunningOnNT)
  48. {
  49. return WNetEnumResourceW(hEnum, lpcCount, lpBuffer, lpBufferSize);
  50. }
  51. else
  52. {
  53. DWORD dwRet;
  54. LPVOID lpBufferA = NULL;
  55. DWORD dwBufferSizeA = (*lpBufferSize) / 2;
  56. if (dwBufferSizeA)
  57. {
  58. lpBufferA = malloc(dwBufferSizeA);
  59. if (!lpBufferA)
  60. return ERROR_OUTOFMEMORY;
  61. }
  62. dwRet = WNetEnumResourceA(hEnum, lpcCount, lpBufferA, &dwBufferSizeA);
  63. if ((0 == dwRet) || (ERROR_MORE_DATA == dwRet))
  64. {
  65. if (lpBufferA)
  66. {
  67. LPNETRESOURCEW pnrW = (LPNETRESOURCEW)lpBuffer;
  68. LPNETRESOURCEA pnrA = (LPNETRESOURCEA)lpBufferA;
  69. LPWSTR pwszStrings = (LPWSTR)&pnrW[*lpcCount];
  70. DWORD cchStrings = (*lpBufferSize - (DWORD)((LPBYTE)pwszStrings - (LPBYTE)pnrW)) / sizeof(WCHAR);
  71. DWORD i;
  72. // if cchStrings goes to 0 before all strings are copied, pwszStrings points
  73. // one past the buffer length. this case shouldn't happen, but if it does
  74. // we don't want to fault - reduce cchStrings by one so we point to valid memory.
  75. //
  76. cchStrings --;
  77. for (i=0 ; i<*lpcCount ; i++)
  78. {
  79. ASSERT(sizeof(NETRESOURCEW) == sizeof(NETRESOURCEA));
  80. CopyMemory(pnrW, pnrA, sizeof(NETRESOURCEA));
  81. if (pnrA->lpLocalName)
  82. {
  83. DWORD cch = SHAnsiToUnicode(pnrA->lpLocalName, pwszStrings, cchStrings);
  84. pnrW->lpLocalName = pwszStrings;
  85. pwszStrings += cch;
  86. cchStrings -= cch;
  87. }
  88. if (pnrA->lpRemoteName)
  89. {
  90. DWORD cch = SHAnsiToUnicode(pnrA->lpRemoteName, pwszStrings, cchStrings);
  91. pnrW->lpRemoteName = pwszStrings;
  92. pwszStrings += cch;
  93. cchStrings -= cch;
  94. }
  95. if (pnrA->lpComment)
  96. {
  97. DWORD cch = SHAnsiToUnicode(pnrA->lpComment, pwszStrings, cchStrings);
  98. pnrW->lpComment = pwszStrings;
  99. pwszStrings += cch;
  100. cchStrings -= cch;
  101. }
  102. if (pnrA->lpProvider)
  103. {
  104. DWORD cch = SHAnsiToUnicode(pnrA->lpProvider, pwszStrings, cchStrings);
  105. pnrW->lpProvider = pwszStrings;
  106. pwszStrings += cch;
  107. cchStrings -= cch;
  108. }
  109. pnrW++;
  110. pnrA++;
  111. }
  112. // (and null out that memory for the overflow case)
  113. *pwszStrings = TEXTW('\0');
  114. }
  115. *lpBufferSize = dwBufferSizeA * 2 + 1;
  116. }
  117. if (lpBufferA)
  118. {
  119. free(lpBufferA);
  120. }
  121. return dwRet;
  122. }
  123. return WN_NOT_SUPPORTED;
  124. }
  125. DWORD WNetGetUserWrapW(LPCWSTR lpName, LPWSTR lpUserName, LPDWORD lpnLength)
  126. {
  127. if (g_fRunningOnNT)
  128. {
  129. return WNetGetUserW(lpName, lpUserName, lpnLength);
  130. }
  131. else
  132. {
  133. CStrIn cstrName(lpName);
  134. CStrOut cstrUserName(lpUserName, *lpnLength);
  135. // *lpnLength is character count, so no adjustment needed on ERROR_MORE_DATA
  136. return WNetGetUserA(cstrName, cstrUserName, lpnLength);
  137. }
  138. }
  139. ///////////////////////////////////////////////////////////////////////////
  140. //
  141. // RAS
  142. //
  143. // ras structure thunkers
  144. class CRasDialParamsIn
  145. {
  146. public:
  147. CRasDialParamsIn(LPRASDIALPARAMSW pRDP);
  148. void Convert();
  149. operator LPRASDIALPARAMSA() { return _pRDPW ? &_rdp : NULL; };
  150. private:
  151. RASDIALPARAMSA _rdp;
  152. LPRASDIALPARAMSW _pRDPW;
  153. };
  154. CRasDialParamsIn::CRasDialParamsIn(LPRASDIALPARAMSW pRDP)
  155. {
  156. _pRDPW = pRDP;
  157. _rdp.dwSize = sizeof(_rdp);
  158. }
  159. void CRasDialParamsIn::Convert()
  160. {
  161. if (_pRDPW)
  162. {
  163. _rdp.dwSize = sizeof(_rdp);
  164. SHUnicodeToAnsi(_pRDPW->szEntryName, _rdp.szEntryName, ARRAYSIZE(_rdp.szEntryName));
  165. SHUnicodeToAnsi(_pRDPW->szPhoneNumber, _rdp.szPhoneNumber, ARRAYSIZE(_rdp.szPhoneNumber));
  166. SHUnicodeToAnsi(_pRDPW->szCallbackNumber, _rdp.szCallbackNumber, ARRAYSIZE(_rdp.szCallbackNumber));
  167. SHUnicodeToAnsi(_pRDPW->szUserName, _rdp.szUserName, ARRAYSIZE(_rdp.szUserName));
  168. SHUnicodeToAnsi(_pRDPW->szPassword, _rdp.szPassword, ARRAYSIZE(_rdp.szPassword));
  169. SHUnicodeToAnsi(_pRDPW->szDomain, _rdp.szDomain, ARRAYSIZE(_rdp.szDomain));
  170. }
  171. }
  172. class CRasDialParamsOut
  173. {
  174. public:
  175. CRasDialParamsOut(LPRASDIALPARAMSW pRDP) { _pRDPW = pRDP; _rdp.dwSize = sizeof(_rdp); };
  176. void Convert();
  177. void NullOutBuffer();
  178. operator LPRASDIALPARAMSA() { return _pRDPW ? &_rdp : NULL; };
  179. private:
  180. RASDIALPARAMSA _rdp;
  181. LPRASDIALPARAMSW _pRDPW;
  182. };
  183. void CRasDialParamsOut::Convert()
  184. {
  185. if (_pRDPW)
  186. {
  187. ASSERT(_pRDPW->dwSize == sizeof(*_pRDPW));
  188. SHAnsiToUnicode(_rdp.szEntryName, _pRDPW->szEntryName, ARRAYSIZE(_pRDPW->szEntryName));
  189. SHAnsiToUnicode(_rdp.szPhoneNumber, _pRDPW->szPhoneNumber, ARRAYSIZE(_pRDPW->szPhoneNumber));
  190. SHAnsiToUnicode(_rdp.szCallbackNumber, _pRDPW->szCallbackNumber, ARRAYSIZE(_pRDPW->szCallbackNumber));
  191. SHAnsiToUnicode(_rdp.szUserName, _pRDPW->szUserName, ARRAYSIZE(_pRDPW->szUserName));
  192. SHAnsiToUnicode(_rdp.szPassword, _pRDPW->szPassword, ARRAYSIZE(_pRDPW->szPassword));
  193. SHAnsiToUnicode(_rdp.szDomain, _pRDPW->szDomain, ARRAYSIZE(_pRDPW->szDomain));
  194. }
  195. }
  196. void CRasDialParamsOut::NullOutBuffer()
  197. {
  198. if (_pRDPW)
  199. {
  200. _pRDPW->szEntryName[0] = '\0';
  201. _pRDPW->szPhoneNumber[0] = '\0';
  202. _pRDPW->szCallbackNumber[0] = '\0';
  203. _pRDPW->szUserName[0] = '\0';
  204. _pRDPW->szPassword[0] = '\0';
  205. _pRDPW->szDomain[0] = '\0';
  206. }
  207. }
  208. //
  209. // ras function wrappers
  210. //
  211. // Use old size so we work downlevel
  212. #define OLD_RASENTRYNAMEA_SIZE ((DWORD)(&((RASENTRYNAMEA*)NULL)->dwFlags))
  213. DWORD RasEnumEntriesWrapW(LPCWSTR reserved, LPCWSTR pszPhoneBookPath, LPRASENTRYNAMEW pRasEntryNameW, LPDWORD pcb, LPDWORD pcEntries)
  214. {
  215. ASSERT(NULL==reserved && NULL==pszPhoneBookPath); // we don't thunk these, so make sure we don't call with them
  216. ASSERT(!pRasEntryNameW || *pcb>0); // we're either requesting the size or we have a buffer
  217. if (g_fRunningOnNT)
  218. {
  219. return RasEnumEntriesW(reserved, pszPhoneBookPath, pRasEntryNameW, pcb, pcEntries);
  220. }
  221. else
  222. {
  223. DWORD dwRet = 0; // assume success
  224. DWORD cbA = *pcb / 2; // inverse of below
  225. LPRASENTRYNAMEA pRasEntryNameA = NULL;
  226. // if we're requesting info, allocate an ansi buffer
  227. if (pRasEntryNameW)
  228. {
  229. pRasEntryNameA = (LPRASENTRYNAMEA)malloc(cbA);
  230. if (pRasEntryNameA)
  231. {
  232. pRasEntryNameA->dwSize = OLD_RASENTRYNAMEA_SIZE;
  233. }
  234. else
  235. {
  236. dwRet = ERROR_NOT_ENOUGH_MEMORY;
  237. }
  238. }
  239. if (0==dwRet)
  240. {
  241. dwRet = RasEnumEntriesA(NULL, NULL, pRasEntryNameA, &cbA, pcEntries);
  242. // we successfully got info, thunk it back
  243. if (0 == dwRet && pRasEntryNameA)
  244. {
  245. UINT i;
  246. RASENTRYNAMEA* pRasEntryNameA2 = pRasEntryNameA;
  247. for (i=0 ; i<*pcEntries ; i++)
  248. {
  249. pRasEntryNameW[i].dwSize = sizeof(pRasEntryNameW[i]);
  250. SHAnsiToUnicode(pRasEntryNameA2->szEntryName, pRasEntryNameW[i].szEntryName, ARRAYSIZE(pRasEntryNameW[i].szEntryName));
  251. pRasEntryNameA2 = (RASENTRYNAMEA*)((BYTE*)pRasEntryNameA2 + OLD_RASENTRYNAMEA_SIZE);
  252. }
  253. }
  254. // allow room for thunking
  255. *pcb = *pcEntries * sizeof(RASENTRYNAMEW);
  256. }
  257. if (pRasEntryNameA)
  258. free(pRasEntryNameA);
  259. return dwRet;
  260. }
  261. }
  262. DWORD RasSetEntryDialParamsWrapW(LPCWSTR pszPhonebook, LPRASDIALPARAMSW lpRasDialParamsW, BOOL fRemovePassword)
  263. {
  264. ASSERT(NULL==pszPhonebook); // we don't thunk this
  265. if (g_fRunningOnNT)
  266. {
  267. return RasSetEntryDialParamsW(pszPhonebook, lpRasDialParamsW, fRemovePassword);
  268. }
  269. else
  270. {
  271. CRasDialParamsIn rdp(lpRasDialParamsW);
  272. rdp.Convert();
  273. return RasSetEntryDialParamsA(NULL, rdp, fRemovePassword);
  274. }
  275. }
  276. DWORD RasGetEntryDialParamsWrapW(LPCWSTR pszPhonebook, LPRASDIALPARAMSW lpRasDialParamsW, LPBOOL pfRemovePassword)
  277. {
  278. ASSERT(NULL==pszPhonebook); // we don't thunk this
  279. if (g_fRunningOnNT)
  280. {
  281. return RasGetEntryDialParamsW(pszPhonebook, lpRasDialParamsW, pfRemovePassword);
  282. }
  283. else
  284. {
  285. DWORD dwRet;
  286. CRasDialParamsOut rdp(lpRasDialParamsW);
  287. dwRet = RasGetEntryDialParamsA(NULL, rdp, pfRemovePassword);
  288. if (ERROR_SUCCESS == dwRet)
  289. {
  290. rdp.Convert();
  291. }
  292. else
  293. {
  294. rdp.NullOutBuffer();
  295. }
  296. return dwRet;
  297. }
  298. }
  299. DWORD RnaGetDefaultAutodialConnectionWrap(LPWSTR szBuffer, DWORD cchBuffer, LPDWORD lpdwOptions)
  300. {
  301. ASSERT(0 < cchBuffer);
  302. ASSERT(cchBuffer <= MAX_PATH); // largest string we thunk
  303. if (!g_fRunningOnNT)
  304. {
  305. DWORD dwRet;
  306. CStrOut cstroutBuffer(szBuffer, cchBuffer);
  307. dwRet = RnaGetDefaultAutodialConnection(cstroutBuffer, cstroutBuffer.BufSize(), lpdwOptions);
  308. cstroutBuffer.ConvertIncludingNul();
  309. return(dwRet);
  310. }
  311. // NT doesn't have an implementation of this function
  312. *lpdwOptions = 0;
  313. szBuffer[0] = TEXT('\0');
  314. return 0;
  315. }
  316. DWORD RnaSetDefaultAutodialConnectionWrap(LPWSTR szEntry, DWORD dwOptions)
  317. {
  318. ASSERT(lstrlen(szEntry) < MAX_PATH); // should be valid since we assert this on the Get...
  319. if (!g_fRunningOnNT)
  320. {
  321. CStrIn cstrinEntry(szEntry);
  322. return RnaSetDefaultAutodialConnection(cstrinEntry, dwOptions);
  323. }
  324. // NT doesn't have an implementation of this function
  325. return 0;
  326. }
  327. //
  328. // PropertySheet wrappers.
  329. //
  330. INT_PTR WINAPI PropertySheetWrapW(LPCPROPSHEETHEADERW ppshW)
  331. {
  332. INT_PTR iRet;
  333. if (g_fRunningOnNT)
  334. {
  335. iRet = PropertySheetW(ppshW);
  336. }
  337. else
  338. {
  339. //
  340. // Warning! Warning! Warning!
  341. //
  342. // This code assumes that none of the strings in this struct are being
  343. // used. If a string gets used then the structure will have to be
  344. // converted. It also assumes that PROPSHEETHEADERW and
  345. // PROPSHEETHEADERA are the same except for string types.
  346. //
  347. COMPILETIME_ASSERT(sizeof(PROPSHEETHEADERW) == sizeof(PROPSHEETHEADERA));
  348. ASSERT(NULL == ppshW->pszIcon || !(ppshW->dwFlags & PSH_USEICONID) || IS_INTRESOURCE(ppshW->pszIcon));
  349. ASSERT(NULL == ppshW->pszCaption || IS_INTRESOURCE(ppshW->pszCaption));
  350. ASSERT(NULL == ppshW->pStartPage || !(ppshW->dwFlags & PSH_USEPSTARTPAGE) || IS_INTRESOURCE(ppshW->pStartPage));
  351. ASSERT(NULL == ppshW->pszIcon || !(ppshW->dwFlags & PSH_USEICONID) || IS_INTRESOURCE(ppshW->pszIcon));
  352. ASSERT(NULL == ppshW->pszbmWatermark || !(ppshW->dwFlags & PSH_USEHBMWATERMARK) || IS_INTRESOURCE(ppshW->pszbmWatermark));
  353. ASSERT(NULL == ppshW->pszbmHeader || !(ppshW->dwFlags & PSH_USEHBMHEADER) || IS_INTRESOURCE(ppshW->pszbmHeader));
  354. iRet = PropertySheetA((LPCPROPSHEETHEADERA)ppshW);
  355. }
  356. return iRet;
  357. }
  358. HPROPSHEETPAGE WINAPI CreatePropertySheetPageWrapW(LPCPROPSHEETPAGEW ppspW)
  359. {
  360. HPROPSHEETPAGE hpspRet;
  361. if (g_fRunningOnNT)
  362. {
  363. hpspRet = CreatePropertySheetPageW(ppspW);
  364. }
  365. else
  366. {
  367. //
  368. // Warning! Warning! Warning!
  369. //
  370. // This code assumes that none of the strings in this struct are being
  371. // used. If a string gets used then the structure will have to be
  372. // converted. It also assumes that PROPSHEETPAGEW and
  373. // PROPSHEETPAGEA are the same except for string types.
  374. //
  375. COMPILETIME_ASSERT(sizeof(PROPSHEETPAGEW) == sizeof(PROPSHEETPAGEA));
  376. ASSERT(NULL == ppspW->pszTemplate || (ppspW->dwFlags & PSP_DLGINDIRECT) || IS_INTRESOURCE(ppspW->pszTemplate));
  377. ASSERT(NULL == ppspW->pszIcon || !(ppspW->dwFlags & PSP_USEICONID) || IS_INTRESOURCE(ppspW->pszIcon));
  378. ASSERT(NULL == ppspW->pszTitle || !(ppspW->dwFlags & PSP_USETITLE) || IS_INTRESOURCE(ppspW->pszTitle));
  379. ASSERT(NULL == ppspW->pszHeaderTitle || !(ppspW->dwFlags & PSP_USEHEADERTITLE) || IS_INTRESOURCE(ppspW->pszHeaderTitle));
  380. ASSERT(NULL == ppspW->pszHeaderSubTitle || !(ppspW->dwFlags & PSP_USEHEADERSUBTITLE) || IS_INTRESOURCE(ppspW->pszHeaderSubTitle));
  381. hpspRet = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)ppspW);
  382. }
  383. return hpspRet;
  384. }
  385. //
  386. // Miscelaneous APIs that aren't wrapped in shlwapi. Move to shlwapi?
  387. //
  388. UINT WINAPI GlobalGetAtomNameWrapW(ATOM nAtom, LPWSTR lpBuffer, int nSize)
  389. {
  390. UINT uRet;
  391. if (g_fRunningOnNT)
  392. {
  393. uRet = GlobalGetAtomNameW(nAtom, lpBuffer, nSize);
  394. }
  395. else
  396. {
  397. CStrOut csoBuffer(lpBuffer, nSize);
  398. uRet = GlobalGetAtomNameA(nAtom, csoBuffer, csoBuffer.BufSize());
  399. }
  400. return uRet;
  401. }
  402. BOOL WINAPI GetComputerNameWrapW(LPWSTR lpBuffer, LPDWORD pnSize)
  403. {
  404. BOOL fRet;
  405. if (g_fRunningOnNT)
  406. {
  407. fRet = GetComputerNameW(lpBuffer, pnSize);
  408. }
  409. else
  410. {
  411. CStrOut csoBuffer(lpBuffer, *pnSize);
  412. DWORD cch = csoBuffer.BufSize();
  413. fRet = GetComputerNameA(csoBuffer, &cch);
  414. if (fRet && pnSize)
  415. {
  416. *pnSize = csoBuffer.ConvertExcludingNul();
  417. }
  418. }
  419. return fRet;
  420. }
  421. BOOL WINAPI SetComputerNameWrapW(LPCWSTR lpComputerName)
  422. {
  423. BOOL fRet;
  424. if (g_fRunningOnNT)
  425. {
  426. fRet = SetComputerNameW(lpComputerName);
  427. }
  428. else
  429. {
  430. CStrIn csiComputerName(lpComputerName);
  431. fRet = SetComputerNameA(csiComputerName);
  432. }
  433. return fRet;
  434. }
  435. UINT WINAPI GetDriveTypeWrapW(LPCWSTR lpRootPathName)
  436. {
  437. UINT uRet;
  438. if (g_fRunningOnNT)
  439. {
  440. uRet = GetDriveTypeW(lpRootPathName);
  441. }
  442. else
  443. {
  444. CStrIn csiRootPathName(lpRootPathName);
  445. uRet = GetDriveTypeA(csiRootPathName);
  446. }
  447. return uRet;
  448. }
  449. //
  450. // Printer wrappers.
  451. //
  452. class CPrinterEnumIn
  453. {
  454. public:
  455. CPrinterEnumIn(DWORD dwLevel, BYTE* pPrinterEnum, DWORD cbPrinterEnum, DWORD* ppsbNeeded, DWORD* pcPrinters);
  456. ~CPrinterEnumIn();
  457. operator BYTE*() {return _pPrinterEnumA;}
  458. operator DWORD() {return _cbPrinterEnumA;}
  459. private:
  460. void Convert(void);
  461. void ConvertStruct(const PRINTER_INFO_5A* ppi5A, PRINTER_INFO_5W* ppi5W, LPWSTR* ppszCurrent, UINT* pcchCurrent);
  462. void ConvertStructString(LPCSTR pszA, LPWSTR* ppszDst, LPWSTR* ppszW, UINT* pcchW);
  463. private:
  464. BYTE* _pPrinterEnum;
  465. DWORD _cbPrinterEnum;
  466. DWORD* _pcbNeeded;
  467. DWORD* _pcPrinters;
  468. BYTE* _pPrinterEnumA;
  469. DWORD _cbPrinterEnumA;
  470. };
  471. CPrinterEnumIn::CPrinterEnumIn(DWORD dwLevel, BYTE* pPrinterEnum, DWORD cbPrinterEnum, DWORD* pcbNeeded, DWORD* pcPrinters)
  472. {
  473. ASSERT(5 == dwLevel); // only level supported.
  474. _pPrinterEnum = pPrinterEnum;
  475. _cbPrinterEnum = cbPrinterEnum;
  476. _pcbNeeded = pcbNeeded;
  477. _pcPrinters = pcPrinters;
  478. if (_cbPrinterEnum)
  479. {
  480. _pPrinterEnumA = (BYTE*)LocalAlloc(LPTR, _cbPrinterEnum);
  481. _cbPrinterEnumA = _pPrinterEnumA ? _cbPrinterEnum : 0;
  482. }
  483. else
  484. {
  485. _pPrinterEnumA = NULL;
  486. _cbPrinterEnumA = 0;
  487. }
  488. }
  489. CPrinterEnumIn::~CPrinterEnumIn()
  490. {
  491. Convert();
  492. if (_pPrinterEnumA)
  493. LocalFree(_pPrinterEnumA);
  494. }
  495. void CPrinterEnumIn::Convert()
  496. {
  497. if (!_pPrinterEnumA)
  498. {
  499. *_pcbNeeded *= 2;
  500. }
  501. else
  502. {
  503. UINT cchCurrent = _cbPrinterEnum > (sizeof(PRINTER_INFO_5) * *_pcPrinters) ?
  504. (_cbPrinterEnum - (sizeof(PRINTER_INFO_5) * *_pcPrinters)) / sizeof(WCHAR) :
  505. 0;
  506. LPWSTR pszCurrent = cchCurrent ? (LPWSTR)&(((PRINTER_INFO_5*)_pPrinterEnum)[*_pcPrinters]) : NULL;
  507. for (UINT i = 0; i < *_pcPrinters; i++)
  508. {
  509. ConvertStruct(&((const PRINTER_INFO_5A*)_pPrinterEnumA)[i], &((PRINTER_INFO_5W*)_pPrinterEnum)[i], &pszCurrent, &cchCurrent);
  510. }
  511. }
  512. return;
  513. }
  514. void CPrinterEnumIn::ConvertStruct(const PRINTER_INFO_5A* ppi5A, PRINTER_INFO_5W* ppi5W, LPWSTR* ppszCurrent, UINT* pcchCurrent)
  515. {
  516. if (ppi5A->pPrinterName && *pcchCurrent)
  517. {
  518. ConvertStructString(ppi5A->pPrinterName, &ppi5W->pPrinterName, ppszCurrent, pcchCurrent);
  519. }
  520. if (ppi5A->pPortName && *pcchCurrent)
  521. {
  522. ConvertStructString(ppi5A->pPortName, &ppi5W->pPortName, ppszCurrent, pcchCurrent);
  523. }
  524. ppi5W->Attributes = ppi5A->Attributes;
  525. ppi5W->DeviceNotSelectedTimeout = ppi5A->DeviceNotSelectedTimeout;
  526. ppi5W->TransmissionRetryTimeout = ppi5A->TransmissionRetryTimeout;
  527. return;
  528. }
  529. void CPrinterEnumIn::ConvertStructString(LPCSTR pszA, LPWSTR* ppszDst, LPWSTR* ppszW, UINT* pcchW)
  530. {
  531. UINT cch = MultiByteToWideChar(CP_ACP, 0, pszA, -1, *ppszW, *pcchW);
  532. if (cch)
  533. {
  534. *ppszDst = *ppszW;
  535. *pcchW -= cch;
  536. *ppszW += cch;
  537. }
  538. else
  539. {
  540. *ppszDst = NULL;
  541. *pcchW = 0;
  542. *ppszW = NULL;
  543. }
  544. return;
  545. }
  546. BOOL EnumPrintersWrapW(DWORD dwFlags, LPWSTR pszName, DWORD dwLevel, BYTE* pPrinterEnum, DWORD cbPrinterEnum, DWORD* pcbNeeded, DWORD* pcPrinters)
  547. {
  548. BOOL fRet;
  549. if (g_fRunningOnNT)
  550. {
  551. fRet = EnumPrintersW(dwFlags, pszName, dwLevel, pPrinterEnum, cbPrinterEnum, pcbNeeded, pcPrinters);
  552. }
  553. else
  554. {
  555. CStrIn strName(pszName);
  556. CPrinterEnumIn cpeiPrinterEnum(dwLevel, pPrinterEnum, cbPrinterEnum, pcbNeeded, pcPrinters);
  557. fRet = EnumPrintersA(dwFlags, strName, dwLevel, cpeiPrinterEnum, cpeiPrinterEnum, pcbNeeded, pcPrinters);
  558. }
  559. return fRet;
  560. }