PageRenderTime 59ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/msapi_utf8.h

https://gitlab.com/adam.lukaitis/rufus
C Header | 868 lines | 740 code | 70 blank | 58 comment | 111 complexity | 3486fce786e845ca8f0dd2dbc7953716 MD5 | raw file
  1. /*
  2. * MSAPI_UTF8: Common API calls using UTF-8 strings
  3. * Compensating for what Microsoft should have done a long long time ago.
  4. * Also see http://utf8everywhere.org/
  5. *
  6. * Copyright © 2010-2015 Pete Batard <pete@akeo.ie>
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 3 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. */
  22. #include <windows.h>
  23. #include <stdio.h>
  24. #include <shlobj.h>
  25. #include <ctype.h>
  26. #include <commdlg.h>
  27. #include <shellapi.h>
  28. #include <shlwapi.h>
  29. #include <setupapi.h>
  30. #include <direct.h>
  31. #include <share.h>
  32. #include <fcntl.h>
  33. #include <io.h>
  34. #pragma once
  35. #if defined(_MSC_VER)
  36. // disable VS2012 Code Analysis warnings that are intentional
  37. #pragma warning(disable: 6387) // Don't care about bad params
  38. #endif
  39. #ifdef __cplusplus
  40. extern "C" {
  41. #endif
  42. #define _LTEXT(txt) L##txt
  43. #define LTEXT(txt) _LTEXT(txt)
  44. #define wchar_to_utf8_no_alloc(wsrc, dest, dest_size) \
  45. WideCharToMultiByte(CP_UTF8, 0, wsrc, -1, dest, dest_size, NULL, NULL)
  46. #define utf8_to_wchar_no_alloc(src, wdest, wdest_size) \
  47. MultiByteToWideChar(CP_UTF8, 0, src, -1, wdest, wdest_size)
  48. #define Edit_ReplaceSelU(hCtrl, str) ((void)SendMessageLU(hCtrl, EM_REPLACESEL, (WPARAM)FALSE, str))
  49. #define ComboBox_AddStringU(hCtrl, str) ((int)(DWORD)SendMessageLU(hCtrl, CB_ADDSTRING, (WPARAM)FALSE, str))
  50. #define ComboBox_InsertStringU(hCtrl, index, str) ((int)(DWORD)SendMessageLU(hCtrl, CB_INSERTSTRING, (WPARAM)index, str))
  51. #define ComboBox_GetTextU(hCtrl, str, max_str) GetWindowTextU(hCtrl, str, max_str)
  52. #define GetSaveFileNameU(p) GetOpenSaveFileNameU(p, TRUE)
  53. #define GetOpenFileNameU(p) GetOpenSaveFileNameU(p, FALSE)
  54. #define ListView_SetItemTextU(hwndLV,i,iSubItem_,pszText_) { LVITEMW _ms_wlvi; _ms_wlvi.iSubItem = iSubItem_; \
  55. _ms_wlvi.pszText = utf8_to_wchar(pszText_); \
  56. SNDMSG((hwndLV),LVM_SETITEMTEXTW,(WPARAM)(i),(LPARAM)&_ms_wlvi); sfree(_ms_wlvi.pszText);}
  57. // Never ever use isdigit() or isspace(), etc. on UTF-8 strings!
  58. // These calls take an int and char is signed so MS compilers will produce an assert error on anything that's > 0x80
  59. #define isasciiU(c) isascii((unsigned char)(c))
  60. #define iscntrlU(c) iscntrl((unsigned char)(c))
  61. #define isdigitU(c) isdigit((unsigned char)(c))
  62. #define isspaceU(c) isspace((unsigned char)(c))
  63. #define isxdigitU(c) isxdigit((unsigned char)(c))
  64. // NB: other issomething() calls are not implemented as they may require multibyte UTF-8 sequences to be converted
  65. #define sfree(p) do {if (p != NULL) {free((void*)(p)); p = NULL;}} while(0)
  66. #define wconvert(p) wchar_t* w ## p = utf8_to_wchar(p)
  67. #define walloc(p, size) wchar_t* w ## p = (wchar_t*)calloc(size, sizeof(wchar_t))
  68. #define wfree(p) sfree(w ## p)
  69. /*
  70. * Converts an UTF-16 string to UTF8 (allocate returned string)
  71. * Returns NULL on error
  72. */
  73. static __inline char* wchar_to_utf8(const wchar_t* wstr)
  74. {
  75. int size = 0;
  76. char* str = NULL;
  77. // Find out the size we need to allocate for our converted string
  78. size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
  79. if (size <= 1) // An empty string would be size 1
  80. return NULL;
  81. if ((str = (char*)calloc(size, 1)) == NULL)
  82. return NULL;
  83. if (wchar_to_utf8_no_alloc(wstr, str, size) != size) {
  84. sfree(str);
  85. return NULL;
  86. }
  87. return str;
  88. }
  89. /*
  90. * Converts an UTF8 string to UTF-16 (allocate returned string)
  91. * Returns NULL on error
  92. */
  93. static __inline wchar_t* utf8_to_wchar(const char* str)
  94. {
  95. int size = 0;
  96. wchar_t* wstr = NULL;
  97. // Find out the size we need to allocate for our converted string
  98. size = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
  99. if (size <= 1) // An empty string would be size 1
  100. return NULL;
  101. if ((wstr = (wchar_t*)calloc(size, sizeof(wchar_t))) == NULL)
  102. return NULL;
  103. if (utf8_to_wchar_no_alloc(str, wstr, size) != size) {
  104. sfree(wstr);
  105. return NULL;
  106. }
  107. return wstr;
  108. }
  109. static __inline DWORD FormatMessageU(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId,
  110. DWORD dwLanguageId, char* lpBuffer, DWORD nSize, va_list *Arguments)
  111. {
  112. DWORD ret = 0, err = ERROR_INVALID_DATA;
  113. walloc(lpBuffer, nSize);
  114. ret = FormatMessageW(dwFlags, lpSource, dwMessageId, dwLanguageId, wlpBuffer, nSize, Arguments);
  115. err = GetLastError();
  116. if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, nSize)) == 0)) {
  117. err = GetLastError();
  118. ret = 0;
  119. }
  120. wfree(lpBuffer);
  121. SetLastError(err);
  122. return ret;
  123. }
  124. // SendMessage, with LPARAM as UTF-8 string
  125. static __inline LRESULT SendMessageLU(HWND hWnd, UINT Msg, WPARAM wParam, const char* lParam)
  126. {
  127. LRESULT ret = FALSE;
  128. DWORD err = ERROR_INVALID_DATA;
  129. wconvert(lParam);
  130. ret = SendMessageW(hWnd, Msg, wParam, (LPARAM)wlParam);
  131. err = GetLastError();
  132. wfree(lParam);
  133. SetLastError(err);
  134. return ret;
  135. }
  136. static __inline int DrawTextExU(HDC hDC, LPCSTR lpchText, int nCount, LPRECT lpRect, UINT uFormat, LPDRAWTEXTPARAMS lpDTParams)
  137. {
  138. int ret;
  139. DWORD err = ERROR_INVALID_DATA;
  140. wconvert(lpchText);
  141. ret = DrawTextExW(hDC, wlpchText, nCount, lpRect, uFormat, lpDTParams);
  142. err = GetLastError();
  143. wfree(lpchText);
  144. SetLastError(err);
  145. return ret;
  146. }
  147. static __inline BOOL SHGetPathFromIDListU(LPCITEMIDLIST pidl, char* pszPath)
  148. {
  149. BOOL ret = FALSE;
  150. DWORD err = ERROR_INVALID_DATA;
  151. walloc(pszPath, MAX_PATH);
  152. ret = SHGetPathFromIDListW(pidl, wpszPath);
  153. err = GetLastError();
  154. if ((ret) && (wchar_to_utf8_no_alloc(wpszPath, pszPath, MAX_PATH) == 0)) {
  155. err = GetLastError();
  156. ret = FALSE;
  157. }
  158. wfree(pszPath);
  159. SetLastError(err);
  160. return ret;
  161. }
  162. static __inline HWND CreateWindowU(char* lpClassName, char* lpWindowName,
  163. DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent,
  164. HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam)
  165. {
  166. HWND ret = NULL;
  167. DWORD err = ERROR_INVALID_DATA;
  168. wconvert(lpClassName);
  169. wconvert(lpWindowName);
  170. ret = CreateWindowW(wlpClassName, wlpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
  171. err = GetLastError();
  172. wfree(lpClassName);
  173. wfree(lpWindowName);
  174. SetLastError(err);
  175. return ret;
  176. }
  177. static __inline int MessageBoxU(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
  178. {
  179. int ret;
  180. DWORD err = ERROR_INVALID_DATA;
  181. wconvert(lpText);
  182. wconvert(lpCaption);
  183. ret = MessageBoxW(hWnd, wlpText, wlpCaption, uType);
  184. err = GetLastError();
  185. wfree(lpText);
  186. wfree(lpCaption);
  187. SetLastError(err);
  188. return ret;
  189. }
  190. static __inline int MessageBoxExU(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType, WORD wLanguageId)
  191. {
  192. int ret;
  193. DWORD err = ERROR_INVALID_DATA;
  194. wconvert(lpText);
  195. wconvert(lpCaption);
  196. ret = MessageBoxExW(hWnd, wlpText, wlpCaption, uType, wLanguageId);
  197. err = GetLastError();
  198. wfree(lpText);
  199. wfree(lpCaption);
  200. SetLastError(err);
  201. return ret;
  202. }
  203. static __inline int DrawTextU(HDC hDC, LPCSTR lpText, int nCount, LPRECT lpRect, UINT uFormat)
  204. {
  205. int ret;
  206. DWORD err = ERROR_INVALID_DATA;
  207. wconvert(lpText);
  208. ret = DrawTextW(hDC, wlpText, nCount, lpRect, uFormat);
  209. err = GetLastError();
  210. wfree(lpText);
  211. SetLastError(err);
  212. return ret;
  213. }
  214. static __inline int GetWindowTextU(HWND hWnd, char* lpString, int nMaxCount)
  215. {
  216. int ret = 0;
  217. DWORD err = ERROR_INVALID_DATA;
  218. walloc(lpString, nMaxCount);
  219. ret = GetWindowTextW(hWnd, wlpString, nMaxCount);
  220. err = GetLastError();
  221. if ( (ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpString, lpString, nMaxCount)) == 0) ) {
  222. err = GetLastError();
  223. }
  224. wfree(lpString);
  225. SetLastError(err);
  226. return ret;
  227. }
  228. static __inline BOOL SetWindowTextU(HWND hWnd, const char* lpString)
  229. {
  230. BOOL ret = FALSE;
  231. DWORD err = ERROR_INVALID_DATA;
  232. wconvert(lpString);
  233. ret = SetWindowTextW(hWnd, wlpString);
  234. err = GetLastError();
  235. wfree(lpString);
  236. SetLastError(err);
  237. return ret;
  238. }
  239. static __inline int GetWindowTextLengthU(HWND hWnd)
  240. {
  241. int ret = 0;
  242. DWORD err = ERROR_INVALID_DATA;
  243. wchar_t* wbuf = NULL;
  244. char* buf = NULL;
  245. ret = GetWindowTextLengthW(hWnd);
  246. err = GetLastError();
  247. if (ret == 0) goto out;
  248. wbuf = calloc(ret, sizeof(wchar_t));
  249. err = GetLastError();
  250. if (wbuf == NULL) {
  251. err = ERROR_OUTOFMEMORY; ret = 0; goto out;
  252. }
  253. ret = GetWindowTextW(hWnd, wbuf, ret);
  254. err = GetLastError();
  255. if (ret == 0) goto out;
  256. buf = wchar_to_utf8(wbuf);
  257. err = GetLastError();
  258. if (buf == NULL) {
  259. err = ERROR_OUTOFMEMORY; ret = 0; goto out;
  260. }
  261. ret = (int)strlen(buf) + 2; // GetDlgItemText seems to add a character
  262. err = GetLastError();
  263. out:
  264. sfree(wbuf);
  265. sfree(buf);
  266. SetLastError(err);
  267. return ret;
  268. }
  269. static __inline UINT GetDlgItemTextU(HWND hDlg, int nIDDlgItem, char* lpString, int nMaxCount)
  270. {
  271. UINT ret = 0;
  272. DWORD err = ERROR_INVALID_DATA;
  273. walloc(lpString, nMaxCount);
  274. ret = GetDlgItemTextW(hDlg, nIDDlgItem, wlpString, nMaxCount);
  275. err = GetLastError();
  276. if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpString, lpString, nMaxCount)) == 0)) {
  277. err = GetLastError();
  278. }
  279. wfree(lpString);
  280. SetLastError(err);
  281. return ret;
  282. }
  283. static __inline BOOL SetDlgItemTextU(HWND hDlg, int nIDDlgItem, const char* lpString)
  284. {
  285. BOOL ret = FALSE;
  286. DWORD err = ERROR_INVALID_DATA;
  287. wconvert(lpString);
  288. ret = SetDlgItemTextW(hDlg, nIDDlgItem, wlpString);
  289. err = GetLastError();
  290. wfree(lpString);
  291. SetLastError(err);
  292. return ret;
  293. }
  294. static __inline BOOL InsertMenuU(HMENU hMenu, UINT uPosition, UINT uFlags, UINT_PTR uIDNewItem, const char* lpNewItem)
  295. {
  296. BOOL ret = FALSE;
  297. DWORD err = ERROR_INVALID_DATA;
  298. wconvert(lpNewItem);
  299. ret = InsertMenuW(hMenu, uPosition, uFlags, uIDNewItem, wlpNewItem);
  300. err = GetLastError();
  301. wfree(lpNewItem);
  302. SetLastError(err);
  303. return ret;
  304. }
  305. static __inline int ComboBox_GetLBTextU(HWND hCtrl, int index, char* lpString)
  306. {
  307. int size;
  308. DWORD err = ERROR_INVALID_DATA;
  309. wchar_t* wlpString;
  310. if (lpString == NULL)
  311. return CB_ERR;
  312. size = (int)SendMessageW(hCtrl, CB_GETLBTEXTLEN, (WPARAM)index, (LPARAM)0);
  313. if (size < 0)
  314. return size;
  315. wlpString = (wchar_t*)calloc(size+1, sizeof(wchar_t));
  316. size = (int)SendMessageW(hCtrl, CB_GETLBTEXT, (WPARAM)index, (LPARAM)wlpString);
  317. err = GetLastError();
  318. if (size > 0)
  319. wchar_to_utf8_no_alloc(wlpString, lpString, size+1);
  320. wfree(lpString);
  321. SetLastError(err);
  322. return size;
  323. }
  324. static __inline HANDLE CreateFileU(const char* lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
  325. LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
  326. DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
  327. {
  328. HANDLE ret = INVALID_HANDLE_VALUE;
  329. DWORD err = ERROR_INVALID_DATA;
  330. wconvert(lpFileName);
  331. ret = CreateFileW(wlpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
  332. dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
  333. err = GetLastError();
  334. wfree(lpFileName);
  335. SetLastError(err);
  336. return ret;
  337. }
  338. static __inline BOOL CopyFileU(const char* lpExistingFileName, const char* lpNewFileName, BOOL bFailIfExists)
  339. {
  340. BOOL ret = FALSE;
  341. DWORD err = ERROR_INVALID_DATA;
  342. wconvert(lpExistingFileName);
  343. wconvert(lpNewFileName);
  344. ret = CopyFileW(wlpExistingFileName, wlpNewFileName, bFailIfExists);
  345. err = GetLastError();
  346. wfree(lpExistingFileName);
  347. wfree(lpNewFileName);
  348. SetLastError(err);
  349. return ret;
  350. }
  351. static __inline BOOL DeleteFileU(const char* lpFileName)
  352. {
  353. BOOL ret = FALSE;
  354. DWORD err = ERROR_INVALID_DATA;
  355. wconvert(lpFileName);
  356. ret = DeleteFileW(wlpFileName);
  357. err = GetLastError();
  358. wfree(lpFileName);
  359. SetLastError(err);
  360. return ret;
  361. }
  362. static __inline int PathGetDriveNumberU(char* lpPath)
  363. {
  364. int ret = 0;
  365. DWORD err = ERROR_INVALID_DATA;
  366. wconvert(lpPath);
  367. ret = PathGetDriveNumberW(wlpPath);
  368. err = GetLastError();
  369. wfree(lpPath);
  370. SetLastError(err);
  371. return ret;
  372. }
  373. // This function differs from regular GetTextExtentPoint in that it uses a zero terminated string
  374. static __inline BOOL GetTextExtentPointU(HDC hdc, const char* lpString, LPSIZE lpSize)
  375. {
  376. BOOL ret = FALSE;
  377. DWORD err = ERROR_INVALID_DATA;
  378. wconvert(lpString);
  379. if (wlpString == NULL)
  380. return FALSE;
  381. ret = GetTextExtentPoint32W(hdc, wlpString, (int)wcslen(wlpString), lpSize);
  382. err = GetLastError();
  383. wfree(lpString);
  384. SetLastError(err);
  385. return ret;
  386. }
  387. static __inline DWORD GetCurrentDirectoryU(DWORD nBufferLength, char* lpBuffer)
  388. {
  389. DWORD ret = 0, err = ERROR_INVALID_DATA;
  390. walloc(lpBuffer, nBufferLength);
  391. ret = GetCurrentDirectoryW(nBufferLength, wlpBuffer);
  392. err = GetLastError();
  393. if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, nBufferLength)) == 0)) {
  394. err = GetLastError();
  395. }
  396. wfree(lpBuffer);
  397. SetLastError(err);
  398. return ret;
  399. }
  400. static __inline UINT GetSystemDirectoryU(char* lpBuffer, UINT uSize)
  401. {
  402. UINT ret = 0, err = ERROR_INVALID_DATA;
  403. walloc(lpBuffer, uSize);
  404. ret = GetSystemDirectoryW(wlpBuffer, uSize);
  405. err = GetLastError();
  406. if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, uSize)) == 0)) {
  407. err = GetLastError();
  408. }
  409. wfree(lpBuffer);
  410. SetLastError(err);
  411. return ret;
  412. }
  413. static __inline UINT GetSystemWindowsDirectoryU(char* lpBuffer, UINT uSize)
  414. {
  415. UINT ret = 0, err = ERROR_INVALID_DATA;
  416. walloc(lpBuffer, uSize);
  417. ret = GetSystemWindowsDirectoryW(wlpBuffer, uSize);
  418. err = GetLastError();
  419. if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, uSize)) == 0)) {
  420. err = GetLastError();
  421. }
  422. wfree(lpBuffer);
  423. SetLastError(err);
  424. return ret;
  425. }
  426. static __inline DWORD GetTempPathU(DWORD nBufferLength, char* lpBuffer)
  427. {
  428. DWORD ret = 0, err = ERROR_INVALID_DATA;
  429. walloc(lpBuffer, nBufferLength);
  430. ret = GetTempPathW(nBufferLength, wlpBuffer);
  431. err = GetLastError();
  432. if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, nBufferLength)) == 0)) {
  433. err = GetLastError();
  434. }
  435. wfree(lpBuffer);
  436. SetLastError(err);
  437. return ret;
  438. }
  439. static __inline DWORD GetTempFileNameU(char* lpPathName, char* lpPrefixString, UINT uUnique, char* lpTempFileName)
  440. {
  441. DWORD ret = 0, err = ERROR_INVALID_DATA;
  442. wconvert(lpPathName);
  443. wconvert(lpPrefixString);
  444. walloc(lpTempFileName, MAX_PATH);
  445. ret = GetTempFileNameW(wlpPathName, wlpPrefixString, uUnique, wlpTempFileName);
  446. err = GetLastError();
  447. if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpTempFileName, lpTempFileName, MAX_PATH)) == 0)) {
  448. err = GetLastError();
  449. }
  450. wfree(lpTempFileName);
  451. wfree(lpPrefixString);
  452. wfree(lpPathName);
  453. SetLastError(err);
  454. return ret;
  455. }
  456. static __inline DWORD GetModuleFileNameU(HMODULE hModule, char* lpFilename, DWORD nSize)
  457. {
  458. DWORD ret = 0, err = ERROR_INVALID_DATA;
  459. walloc(lpFilename, nSize);
  460. ret = GetModuleFileNameW(hModule, wlpFilename, nSize);
  461. err = GetLastError();
  462. if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpFilename, lpFilename, nSize)) == 0)) {
  463. err = GetLastError();
  464. }
  465. wfree(lpFilename);
  466. SetLastError(err);
  467. return ret;
  468. }
  469. static __inline DWORD GetFullPathNameU(const char* lpFileName, DWORD nBufferLength, char* lpBuffer, char** lpFilePart)
  470. {
  471. DWORD ret = 0, err = ERROR_INVALID_DATA;
  472. wchar_t* wlpFilePart;
  473. wconvert(lpFileName);
  474. walloc(lpBuffer, nBufferLength);
  475. // lpFilePart is not supported
  476. if (lpFilePart != NULL) goto out;
  477. ret = GetFullPathNameW(wlpFileName, nBufferLength, wlpBuffer, &wlpFilePart);
  478. err = GetLastError();
  479. if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, nBufferLength)) == 0)) {
  480. err = GetLastError();
  481. }
  482. out:
  483. wfree(lpBuffer);
  484. wfree(lpFileName);
  485. SetLastError(err);
  486. return ret;
  487. }
  488. static __inline DWORD GetFileAttributesU(const char* lpFileName)
  489. {
  490. DWORD ret = 0xFFFFFFFF, err = ERROR_INVALID_DATA;
  491. wconvert(lpFileName);
  492. ret = GetFileAttributesW(wlpFileName);
  493. err = GetLastError();
  494. wfree(lpFileName);
  495. SetLastError(err);
  496. return ret;
  497. }
  498. static __inline int SHCreateDirectoryExU(HWND hwnd, const char* pszPath, SECURITY_ATTRIBUTES *psa)
  499. {
  500. int ret = ERROR_INVALID_DATA;
  501. DWORD err = ERROR_INVALID_DATA;
  502. wconvert(pszPath);
  503. ret = SHCreateDirectoryExW(hwnd, wpszPath, psa);
  504. err = GetLastError();
  505. wfree(pszPath);
  506. SetLastError(err);
  507. return ret;
  508. }
  509. static __inline int SHDeleteDirectoryExU(HWND hwnd, const char* pszPath, FILEOP_FLAGS fFlags)
  510. {
  511. int ret;
  512. // String needs to be double NULL terminated, so we just use the length of the UTF-8 string
  513. // which is always expected to be larger than our UTF-16 one, and add 2 chars for good measure.
  514. size_t wpszPath_len = strlen(pszPath) + 2;
  515. wchar_t* wpszPath = (wchar_t*)calloc(wpszPath_len, sizeof(wchar_t));
  516. SHFILEOPSTRUCTW shfo = { hwnd, FO_DELETE, wpszPath, NULL, fFlags, FALSE, NULL, NULL };
  517. utf8_to_wchar_no_alloc(pszPath, wpszPath, (int)wpszPath_len);
  518. // FOF_SILENT | FOF_NOERRORUI | FOF_NOCONFIRMATION,
  519. ret = SHFileOperationW(&shfo);
  520. wfree(pszPath);
  521. return ret;
  522. }
  523. static __inline BOOL ShellExecuteExU(SHELLEXECUTEINFOA* lpExecInfo)
  524. {
  525. BOOL ret = FALSE;
  526. DWORD err = ERROR_INVALID_DATA;
  527. SHELLEXECUTEINFOW wExecInfo;
  528. // Because we're lazy, we'll assume that the A and W structs inherently have the same size
  529. if (lpExecInfo->cbSize != sizeof(SHELLEXECUTEINFOW)) {
  530. SetLastError(ERROR_BAD_LENGTH); return FALSE;
  531. }
  532. memcpy(&wExecInfo, lpExecInfo, lpExecInfo->cbSize);
  533. wExecInfo.lpVerb = utf8_to_wchar(lpExecInfo->lpVerb);
  534. wExecInfo.lpFile = utf8_to_wchar(lpExecInfo->lpFile);
  535. wExecInfo.lpParameters = utf8_to_wchar(lpExecInfo->lpParameters);
  536. wExecInfo.lpDirectory = utf8_to_wchar(lpExecInfo->lpDirectory);
  537. if (wExecInfo.fMask & SEE_MASK_CLASSNAME) {
  538. wExecInfo.lpClass = utf8_to_wchar(lpExecInfo->lpClass);
  539. } else {
  540. wExecInfo.lpClass = NULL;
  541. }
  542. ret = ShellExecuteExW(&wExecInfo);
  543. err = GetLastError();
  544. // Copy the returned values back
  545. lpExecInfo->hInstApp = wExecInfo.hInstApp;
  546. lpExecInfo->hProcess = wExecInfo.hProcess;
  547. sfree(wExecInfo.lpVerb);
  548. sfree(wExecInfo.lpFile);
  549. sfree(wExecInfo.lpParameters);
  550. sfree(wExecInfo.lpDirectory);
  551. sfree(wExecInfo.lpClass);
  552. SetLastError(err);
  553. return ret;
  554. }
  555. // Doesn't support LPSTARTUPINFOEX struct
  556. static __inline BOOL CreateProcessU(const char* lpApplicationName, const char* lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,
  557. LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags,
  558. LPVOID lpEnvironment, const char* lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo,
  559. LPPROCESS_INFORMATION lpProcessInformation)
  560. {
  561. BOOL ret = FALSE;
  562. DWORD err = ERROR_INVALID_DATA;
  563. STARTUPINFOW wStartupInfo;
  564. wconvert(lpApplicationName);
  565. wconvert(lpCommandLine);
  566. wconvert(lpCurrentDirectory);
  567. // Because we're lazy, we'll assume that the A and W structs inherently have the same size
  568. // Also prevents the use of STARTUPINFOEX
  569. if (lpStartupInfo->cb != sizeof(STARTUPINFOW)) {
  570. err = ERROR_BAD_LENGTH; goto out;
  571. }
  572. memcpy(&wStartupInfo, lpStartupInfo, lpStartupInfo->cb);
  573. wStartupInfo.lpDesktop = utf8_to_wchar(lpStartupInfo->lpDesktop);
  574. wStartupInfo.lpTitle = utf8_to_wchar(lpStartupInfo->lpTitle);
  575. ret = CreateProcessW(wlpApplicationName, wlpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles,
  576. dwCreationFlags, lpEnvironment, wlpCurrentDirectory, &wStartupInfo, lpProcessInformation);
  577. err = GetLastError();
  578. sfree(wStartupInfo.lpDesktop);
  579. sfree(wStartupInfo.lpTitle);
  580. out:
  581. wfree(lpApplicationName);
  582. wfree(lpCommandLine);
  583. wfree(lpCurrentDirectory);
  584. SetLastError(err);
  585. return ret;
  586. }
  587. // NOTE: when used, nFileOffset & nFileExtension MUST be provided
  588. // in number of Unicode characters, NOT number of UTF-8 bytes
  589. static __inline BOOL WINAPI GetOpenSaveFileNameU(LPOPENFILENAMEA lpofn, BOOL save)
  590. {
  591. BOOL ret = FALSE;
  592. DWORD err = ERROR_INVALID_DATA;
  593. size_t i, len;
  594. OPENFILENAMEW wofn;
  595. memset(&wofn, 0, sizeof(wofn));
  596. wofn.lStructSize = sizeof(wofn);
  597. wofn.hwndOwner = lpofn->hwndOwner;
  598. wofn.hInstance = lpofn->hInstance;
  599. // No support for custom filters
  600. if (lpofn->lpstrCustomFilter != NULL) goto out;
  601. // Count on Microsoft to use an moronic scheme for filters
  602. // that relies on NULL separators and double NULL terminators
  603. if (lpofn->lpstrFilter != NULL) {
  604. // Replace the NULLs by something that can be converted
  605. for (i=0; ; i++) {
  606. if (lpofn->lpstrFilter[i] == 0) {
  607. ((char*)lpofn->lpstrFilter)[i] = '\r';
  608. if (lpofn->lpstrFilter[i+1] == 0) {
  609. break;
  610. }
  611. }
  612. }
  613. wofn.lpstrFilter = utf8_to_wchar(lpofn->lpstrFilter);
  614. // And revert
  615. len = wcslen(wofn.lpstrFilter); // don't use in the loop as it would be reevaluated
  616. for (i=0; i<len; i++) {
  617. if (wofn.lpstrFilter[i] == '\r') {
  618. ((wchar_t*)wofn.lpstrFilter)[i] = 0;
  619. }
  620. }
  621. len = strlen(lpofn->lpstrFilter);
  622. for (i=0; i<len; i++) {
  623. if (lpofn->lpstrFilter[i] == '\r') {
  624. ((char*)lpofn->lpstrFilter)[i] = 0;
  625. }
  626. }
  627. } else {
  628. wofn.lpstrFilter = NULL;
  629. }
  630. wofn.nMaxCustFilter = lpofn->nMaxCustFilter;
  631. wofn.nFilterIndex = lpofn->nFilterIndex;
  632. wofn.lpstrFile = calloc(lpofn->nMaxFile, sizeof(wchar_t));
  633. utf8_to_wchar_no_alloc(lpofn->lpstrFile, wofn.lpstrFile, lpofn->nMaxFile);
  634. wofn.nMaxFile = lpofn->nMaxFile;
  635. wofn.lpstrFileTitle = calloc(lpofn->nMaxFileTitle, sizeof(wchar_t));
  636. utf8_to_wchar_no_alloc(lpofn->lpstrFileTitle, wofn.lpstrFileTitle, lpofn->nMaxFileTitle);
  637. wofn.nMaxFileTitle = lpofn->nMaxFileTitle;
  638. wofn.lpstrInitialDir = utf8_to_wchar(lpofn->lpstrInitialDir);
  639. wofn.lpstrTitle = utf8_to_wchar(lpofn->lpstrTitle);
  640. wofn.Flags = lpofn->Flags;
  641. wofn.nFileOffset = lpofn->nFileOffset;
  642. wofn.nFileExtension = lpofn->nFileExtension;
  643. wofn.lpstrDefExt = utf8_to_wchar(lpofn->lpstrDefExt);
  644. wofn.lCustData = lpofn->lCustData;
  645. wofn.lpfnHook = lpofn->lpfnHook;
  646. wofn.lpTemplateName = utf8_to_wchar(lpofn->lpTemplateName);
  647. wofn.pvReserved = lpofn->pvReserved;
  648. wofn.dwReserved = lpofn->dwReserved;
  649. wofn.FlagsEx = lpofn->FlagsEx;
  650. if (save) {
  651. ret = GetSaveFileNameW(&wofn);
  652. } else {
  653. ret = GetOpenFileNameW(&wofn);
  654. }
  655. err = GetLastError();
  656. if ( (ret)
  657. && ( (wchar_to_utf8_no_alloc(wofn.lpstrFile, lpofn->lpstrFile, lpofn->nMaxFile) == 0)
  658. || (wchar_to_utf8_no_alloc(wofn.lpstrFileTitle, lpofn->lpstrFileTitle, lpofn->nMaxFileTitle) == 0) ) ) {
  659. err = GetLastError();
  660. ret = FALSE;
  661. }
  662. out:
  663. sfree(wofn.lpstrDefExt);
  664. sfree(wofn.lpstrFile);
  665. sfree(wofn.lpstrFileTitle);
  666. sfree(wofn.lpstrFilter);
  667. sfree(wofn.lpstrInitialDir);
  668. sfree(wofn.lpstrTitle);
  669. sfree(wofn.lpTemplateName);
  670. SetLastError(err);
  671. return ret;
  672. }
  673. extern BOOL WINAPI UpdateDriverForPlugAndPlayDevicesW(HWND hwndParent, LPCWSTR HardwareId,
  674. LPCWSTR FullInfPath, DWORD InstallFlags, PBOOL bRebootRequired);
  675. static __inline BOOL UpdateDriverForPlugAndPlayDevicesU(HWND hwndParent, const char* HardwareId, const char* FullInfPath,
  676. DWORD InstallFlags, PBOOL bRebootRequired)
  677. {
  678. BOOL ret = FALSE;
  679. DWORD err = ERROR_INVALID_DATA;
  680. wconvert(HardwareId);
  681. wconvert(FullInfPath);
  682. ret = UpdateDriverForPlugAndPlayDevicesW(hwndParent, wHardwareId, wFullInfPath, InstallFlags, bRebootRequired);
  683. err = GetLastError();
  684. wfree(HardwareId);
  685. wfree(FullInfPath);
  686. SetLastError(err);
  687. return ret;
  688. }
  689. static __inline BOOL SetupCopyOEMInfU(const char* SourceInfFileName, const char* OEMSourceMediaLocation, DWORD OEMSourceMediaType,
  690. DWORD CopyStyle, char* DestinationInfFileName, DWORD DestinationInfFileNameSize,
  691. PDWORD RequiredSize, PTSTR DestinationInfFileNameComponent)
  692. {
  693. BOOL ret = FALSE;
  694. DWORD err = ERROR_INVALID_DATA;
  695. wconvert(SourceInfFileName);
  696. wconvert(OEMSourceMediaLocation);
  697. walloc(DestinationInfFileName, DestinationInfFileNameSize);
  698. // DestinationInfFileNameComponent is not supported
  699. if (DestinationInfFileNameComponent != NULL) goto out;
  700. ret = SetupCopyOEMInfW(wSourceInfFileName, wOEMSourceMediaLocation, OEMSourceMediaType, CopyStyle,
  701. wDestinationInfFileName, DestinationInfFileNameSize, RequiredSize, NULL);
  702. err = GetLastError();
  703. if ((ret != FALSE) && ((ret = wchar_to_utf8_no_alloc(wDestinationInfFileName, DestinationInfFileName, DestinationInfFileNameSize)) == 0)) {
  704. err = GetLastError();
  705. }
  706. out:
  707. wfree(SourceInfFileName);
  708. wfree(OEMSourceMediaLocation);
  709. wfree(DestinationInfFileName);
  710. SetLastError(err);
  711. return ret;
  712. }
  713. static __inline int _chdirU(const char *dirname)
  714. {
  715. int ret;
  716. wconvert(dirname);
  717. ret = _wchdir(wdirname);
  718. wfree(dirname);
  719. return ret;
  720. }
  721. #if defined(_WIN32_WINNT) && (_WIN32_WINNT <= 0x501)
  722. static __inline FILE* fopenU(const char* filename, const char* mode)
  723. {
  724. FILE* ret = NULL;
  725. wconvert(filename);
  726. wconvert(mode);
  727. ret = _wfopen(wfilename, wmode);
  728. wfree(filename);
  729. wfree(mode);
  730. return ret;
  731. }
  732. static __inline int _openU(const char *filename, int oflag, int pmode)
  733. {
  734. int ret = -1;
  735. wconvert(filename);
  736. ret = _wopen(wfilename, oflag, pmode);
  737. wfree(filename);
  738. return ret;
  739. }
  740. // returned UTF-8 string must be freed
  741. static __inline char* getenvU(const char* varname)
  742. {
  743. wconvert(varname);
  744. char* ret;
  745. ret = wchar_to_utf8(_wgetenv(wvarname));
  746. wfree(varname);
  747. return ret;
  748. }
  749. #else
  750. static __inline FILE* fopenU(const char* filename, const char* mode)
  751. {
  752. FILE* ret = NULL;
  753. wconvert(filename);
  754. wconvert(mode);
  755. _wfopen_s(&ret, wfilename, wmode);
  756. wfree(filename);
  757. wfree(mode);
  758. return ret;
  759. }
  760. static __inline int _openU(const char *filename, int oflag , int pmode)
  761. {
  762. int ret = -1;
  763. int shflag = _SH_DENYNO;
  764. wconvert(filename);
  765. // Try to match the share flag to the oflag
  766. if ((oflag & 0x03) == _O_RDONLY)
  767. shflag = _SH_DENYWR;
  768. else if ((oflag & 0x03) == _O_WRONLY)
  769. shflag = _SH_DENYRD;
  770. _wsopen_s(&ret, wfilename, oflag, shflag, pmode);
  771. wfree(filename);
  772. return ret;
  773. }
  774. // returned UTF-8 string must be freed
  775. static __inline char* getenvU(const char* varname)
  776. {
  777. wconvert(varname);
  778. char *ret;
  779. wchar_t value[256];
  780. size_t value_size;
  781. // MinGW and WDK don't know wdupenv_s, so we use wgetenv_s
  782. _wgetenv_s(&value_size, value, ARRAYSIZE(value), wvarname);
  783. ret = wchar_to_utf8(value);
  784. wfree(varname);
  785. return ret;
  786. }
  787. #endif
  788. static __inline int _mkdirU(const char* dirname)
  789. {
  790. wconvert(dirname);
  791. int ret;
  792. ret = _wmkdir(wdirname);
  793. wfree(dirname);
  794. return ret;
  795. }
  796. #ifdef __cplusplus
  797. }
  798. #endif