2011-11-13 20:53:23 +00:00
|
|
|
/*
|
|
|
|
* MSAPI_UTF8: Common API calls using UTF-8 strings
|
2021-01-06 19:27:31 +00:00
|
|
|
* Compensating for what Microsoft should have done a long long time ago, that they
|
|
|
|
* ONLY started to do in mid-2019 (What the £%^& took them so long?!?), as per:
|
|
|
|
* https://docs.microsoft.com/en-us/windows/uwp/design/globalizing/use-utf8-code-page
|
|
|
|
*
|
|
|
|
* See also: https://utf8everywhere.org
|
2011-11-13 20:53:23 +00:00
|
|
|
*
|
[wue] add automatic local account creation and regional settings duplication
* Local account is created with the same name as the current user along with an *empty* password
(which we force the user to change on next logon). This is done to assuage users who might be
weary of entering a password in a third party application, and has the benefit of enabling
autologon when the install is complete.
* Note that the creation of a local account through an answer file prevents Windows 11 22H2
from bugging users about MSA *even with an active network connection*.
* For convenience reasons, only duplication of the current username is enabled. We *may* add a
dialog to enter any random username in a future version, but for 3.20, this is all you get.
* Likewise, the locale duplication is only carried out during OOBE and *not* WinPE (which means
that you still get the initial "Windows setup language and user preferences" prompt). This is
intentional as otherwise the default screen and "Repair Windows" options are not presented.
* It's not my fault that the Windows password change screen is super ill conceived, whereas it
doesn't hide the current password field as it should when the current password is blank, and
one needs to click on a very small arrow to get the changes applied, instead of a PROMINENT
button that should intuitively have been positioned right next to "Cancel".
* If you want to complain that we should just "present the user with XYZ and be done with it",
please bear in mind that we can't add new dialogs to Rufus as willy-nilly as you believe we
can. *ANY* new UI interface requires major planning, which is the reason why, for the time
being, we are limited to reusing a simple dissociated list of checkboxes for all WUE options.
2022-07-19 18:06:42 +00:00
|
|
|
* Copyright © 2010-2022 Pete Batard <pete@akeo.ie>
|
2011-11-13 20:53:23 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 3 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
#include <windows.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <shlobj.h>
|
2013-10-16 19:45:34 +00:00
|
|
|
#include <ctype.h>
|
2011-11-13 20:53:23 +00:00
|
|
|
#include <commdlg.h>
|
|
|
|
#include <shellapi.h>
|
2014-08-08 23:10:12 +00:00
|
|
|
#include <shlwapi.h>
|
2011-11-13 20:53:23 +00:00
|
|
|
#include <setupapi.h>
|
2012-03-03 23:12:48 +00:00
|
|
|
#include <direct.h>
|
2015-08-26 12:49:35 +00:00
|
|
|
#include <share.h>
|
2020-05-17 21:53:48 +00:00
|
|
|
#include <errno.h>
|
2015-08-26 12:49:35 +00:00
|
|
|
#include <fcntl.h>
|
2014-12-29 20:34:41 +00:00
|
|
|
#include <io.h>
|
2017-06-24 16:23:06 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2017-04-27 22:06:42 +00:00
|
|
|
#include <psapi.h>
|
2011-11-13 20:53:23 +00:00
|
|
|
|
2011-12-01 17:20:52 +00:00
|
|
|
#pragma once
|
2013-01-09 21:54:28 +00:00
|
|
|
#if defined(_MSC_VER)
|
|
|
|
// disable VS2012 Code Analysis warnings that are intentional
|
|
|
|
#pragma warning(disable: 6387) // Don't care about bad params
|
|
|
|
#endif
|
2011-12-01 17:20:52 +00:00
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
2012-02-21 19:46:28 +00:00
|
|
|
#define _LTEXT(txt) L##txt
|
|
|
|
#define LTEXT(txt) _LTEXT(txt)
|
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
#define wchar_to_utf8_no_alloc(wsrc, dest, dest_size) \
|
|
|
|
WideCharToMultiByte(CP_UTF8, 0, wsrc, -1, dest, dest_size, NULL, NULL)
|
|
|
|
#define utf8_to_wchar_no_alloc(src, wdest, wdest_size) \
|
|
|
|
MultiByteToWideChar(CP_UTF8, 0, src, -1, wdest, wdest_size)
|
|
|
|
#define Edit_ReplaceSelU(hCtrl, str) ((void)SendMessageLU(hCtrl, EM_REPLACESEL, (WPARAM)FALSE, str))
|
|
|
|
#define ComboBox_AddStringU(hCtrl, str) ((int)(DWORD)SendMessageLU(hCtrl, CB_ADDSTRING, (WPARAM)FALSE, str))
|
2013-07-05 22:58:04 +00:00
|
|
|
#define ComboBox_InsertStringU(hCtrl, index, str) ((int)(DWORD)SendMessageLU(hCtrl, CB_INSERTSTRING, (WPARAM)index, str))
|
2011-11-13 20:53:23 +00:00
|
|
|
#define ComboBox_GetTextU(hCtrl, str, max_str) GetWindowTextU(hCtrl, str, max_str)
|
|
|
|
#define GetSaveFileNameU(p) GetOpenSaveFileNameU(p, TRUE)
|
|
|
|
#define GetOpenFileNameU(p) GetOpenSaveFileNameU(p, FALSE)
|
|
|
|
#define ListView_SetItemTextU(hwndLV,i,iSubItem_,pszText_) { LVITEMW _ms_wlvi; _ms_wlvi.iSubItem = iSubItem_; \
|
|
|
|
_ms_wlvi.pszText = utf8_to_wchar(pszText_); \
|
|
|
|
SNDMSG((hwndLV),LVM_SETITEMTEXTW,(WPARAM)(i),(LPARAM)&_ms_wlvi); sfree(_ms_wlvi.pszText);}
|
|
|
|
|
2013-10-15 21:58:27 +00:00
|
|
|
// Never ever use isdigit() or isspace(), etc. on UTF-8 strings!
|
|
|
|
// These calls take an int and char is signed so MS compilers will produce an assert error on anything that's > 0x80
|
|
|
|
#define isasciiU(c) isascii((unsigned char)(c))
|
|
|
|
#define iscntrlU(c) iscntrl((unsigned char)(c))
|
|
|
|
#define isdigitU(c) isdigit((unsigned char)(c))
|
|
|
|
#define isspaceU(c) isspace((unsigned char)(c))
|
|
|
|
#define isxdigitU(c) isxdigit((unsigned char)(c))
|
2015-10-18 20:31:47 +00:00
|
|
|
// NB: other issomething() calls are not implemented as they may require multibyte UTF-8 sequences to be converted
|
2013-10-15 21:58:27 +00:00
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
#define sfree(p) do {if (p != NULL) {free((void*)(p)); p = NULL;}} while(0)
|
|
|
|
#define wconvert(p) wchar_t* w ## p = utf8_to_wchar(p)
|
2016-06-26 20:24:16 +00:00
|
|
|
#define walloc(p, size) wchar_t* w ## p = (p == NULL)?NULL:(wchar_t*)calloc(size, sizeof(wchar_t))
|
2011-11-13 20:53:23 +00:00
|
|
|
#define wfree(p) sfree(w ## p)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Converts an UTF-16 string to UTF8 (allocate returned string)
|
|
|
|
* Returns NULL on error
|
|
|
|
*/
|
|
|
|
static __inline char* wchar_to_utf8(const wchar_t* wstr)
|
|
|
|
{
|
|
|
|
int size = 0;
|
|
|
|
char* str = NULL;
|
|
|
|
|
2019-04-25 17:58:55 +00:00
|
|
|
// Convert the empty string too
|
|
|
|
if (wstr[0] == 0)
|
2020-03-31 16:26:34 +00:00
|
|
|
return (char*)calloc(1, 1);
|
2019-04-25 17:58:55 +00:00
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
// Find out the size we need to allocate for our converted string
|
|
|
|
size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
|
|
|
|
if (size <= 1) // An empty string would be size 1
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if ((str = (char*)calloc(size, 1)) == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (wchar_to_utf8_no_alloc(wstr, str, size) != size) {
|
|
|
|
sfree(str);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Converts an UTF8 string to UTF-16 (allocate returned string)
|
|
|
|
* Returns NULL on error
|
|
|
|
*/
|
|
|
|
static __inline wchar_t* utf8_to_wchar(const char* str)
|
|
|
|
{
|
|
|
|
int size = 0;
|
|
|
|
wchar_t* wstr = NULL;
|
|
|
|
|
2016-06-26 20:24:16 +00:00
|
|
|
if (str == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2019-04-25 17:58:55 +00:00
|
|
|
// Convert the empty string too
|
|
|
|
if (str[0] == 0)
|
2020-03-31 16:26:34 +00:00
|
|
|
return (wchar_t*)calloc(1, sizeof(wchar_t));
|
2019-04-25 17:58:55 +00:00
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
// Find out the size we need to allocate for our converted string
|
|
|
|
size = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
|
|
|
|
if (size <= 1) // An empty string would be size 1
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if ((wstr = (wchar_t*)calloc(size, sizeof(wchar_t))) == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (utf8_to_wchar_no_alloc(str, wstr, size) != size) {
|
|
|
|
sfree(wstr);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return wstr;
|
|
|
|
}
|
|
|
|
|
2017-04-27 22:06:42 +00:00
|
|
|
/*
|
|
|
|
* Converts an non NUL-terminated UTF-16 string of length len to UTF8 (allocate returned string)
|
|
|
|
* Returns NULL on error
|
|
|
|
*/
|
|
|
|
static __inline char* wchar_len_to_utf8(const wchar_t* wstr, int wlen)
|
|
|
|
{
|
|
|
|
int size = 0;
|
|
|
|
char* str = NULL;
|
|
|
|
|
|
|
|
// Find out the size we need to allocate for our converted string
|
|
|
|
size = WideCharToMultiByte(CP_UTF8, 0, wstr, wlen, NULL, 0, NULL, NULL);
|
|
|
|
if (size <= 1) // An empty string would be size 1
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if ((str = (char*)calloc(size, 1)) == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (WideCharToMultiByte(CP_UTF8, 0, wstr, wlen, str, size, NULL, NULL) != size) {
|
|
|
|
sfree(str);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
static __inline DWORD FormatMessageU(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId,
|
|
|
|
DWORD dwLanguageId, char* lpBuffer, DWORD nSize, va_list *Arguments)
|
|
|
|
{
|
|
|
|
DWORD ret = 0, err = ERROR_INVALID_DATA;
|
2017-04-25 13:32:19 +00:00
|
|
|
// coverity[returned_null]
|
2011-11-13 20:53:23 +00:00
|
|
|
walloc(lpBuffer, nSize);
|
|
|
|
ret = FormatMessageW(dwFlags, lpSource, dwMessageId, dwLanguageId, wlpBuffer, nSize, Arguments);
|
|
|
|
err = GetLastError();
|
|
|
|
if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, nSize)) == 0)) {
|
|
|
|
err = GetLastError();
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
wfree(lpBuffer);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// SendMessage, with LPARAM as UTF-8 string
|
|
|
|
static __inline LRESULT SendMessageLU(HWND hWnd, UINT Msg, WPARAM wParam, const char* lParam)
|
|
|
|
{
|
|
|
|
LRESULT ret = FALSE;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lParam);
|
|
|
|
ret = SendMessageW(hWnd, Msg, wParam, (LPARAM)wlParam);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lParam);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-02-15 00:52:40 +00:00
|
|
|
static __inline int DrawTextExU(HDC hDC, LPCSTR lpchText, int nCount, LPRECT lpRect, UINT uFormat, LPDRAWTEXTPARAMS lpDTParams)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpchText);
|
|
|
|
ret = DrawTextExW(hDC, wlpchText, nCount, lpRect, uFormat, lpDTParams);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpchText);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
static __inline BOOL SHGetPathFromIDListU(LPCITEMIDLIST pidl, char* pszPath)
|
|
|
|
{
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
2017-04-25 13:32:19 +00:00
|
|
|
// coverity[returned_null]
|
2011-11-13 20:53:23 +00:00
|
|
|
walloc(pszPath, MAX_PATH);
|
|
|
|
ret = SHGetPathFromIDListW(pidl, wpszPath);
|
|
|
|
err = GetLastError();
|
|
|
|
if ((ret) && (wchar_to_utf8_no_alloc(wpszPath, pszPath, MAX_PATH) == 0)) {
|
|
|
|
err = GetLastError();
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
wfree(pszPath);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __inline HWND CreateWindowU(char* lpClassName, char* lpWindowName,
|
|
|
|
DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent,
|
|
|
|
HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam)
|
|
|
|
{
|
|
|
|
HWND ret = NULL;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpClassName);
|
|
|
|
wconvert(lpWindowName);
|
|
|
|
ret = CreateWindowW(wlpClassName, wlpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpClassName);
|
|
|
|
wfree(lpWindowName);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-04-04 16:26:45 +00:00
|
|
|
static __inline HWND CreateWindowExU(DWORD dwExStyle, char* lpClassName, char* lpWindowName,
|
|
|
|
DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu,
|
|
|
|
HINSTANCE hInstance, LPVOID lpParam)
|
|
|
|
{
|
|
|
|
HWND ret = NULL;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpClassName);
|
|
|
|
wconvert(lpWindowName);
|
|
|
|
ret = CreateWindowExW(dwExStyle, wlpClassName, wlpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpClassName);
|
|
|
|
wfree(lpWindowName);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-12-30 21:23:13 +00:00
|
|
|
static __inline int MessageBoxU(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpText);
|
|
|
|
wconvert(lpCaption);
|
|
|
|
ret = MessageBoxW(hWnd, wlpText, wlpCaption, uType);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpText);
|
|
|
|
wfree(lpCaption);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-10-18 20:31:47 +00:00
|
|
|
static __inline int MessageBoxExU(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType, WORD wLanguageId)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpText);
|
|
|
|
wconvert(lpCaption);
|
|
|
|
ret = MessageBoxExW(hWnd, wlpText, wlpCaption, uType, wLanguageId);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpText);
|
|
|
|
wfree(lpCaption);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-07-09 15:20:58 +00:00
|
|
|
static __inline int LoadStringU(HINSTANCE hInstance, UINT uID, LPSTR lpBuffer, int nBufferMax)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
2017-07-16 21:42:19 +00:00
|
|
|
if (nBufferMax == 0) {
|
|
|
|
// read-only pointer to resource mode is not supported
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-25 13:32:19 +00:00
|
|
|
// coverity[returned_null]
|
2016-07-09 15:20:58 +00:00
|
|
|
walloc(lpBuffer, nBufferMax);
|
|
|
|
ret = LoadStringW(hInstance, uID, wlpBuffer, nBufferMax);
|
|
|
|
err = GetLastError();
|
|
|
|
if ((ret > 0) && ((ret = wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, nBufferMax)) == 0)) {
|
|
|
|
err = GetLastError();
|
|
|
|
}
|
|
|
|
wfree(lpBuffer);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-08-09 15:27:11 +00:00
|
|
|
static __inline HMODULE LoadLibraryU(LPCSTR lpFileName)
|
|
|
|
{
|
|
|
|
HMODULE ret;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpFileName);
|
|
|
|
ret = LoadLibraryW(wlpFileName);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpFileName);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-04-09 10:31:52 +00:00
|
|
|
static __inline HMODULE LoadLibraryExU(LPCSTR lpFileName, HANDLE hFile, DWORD dwFlags)
|
|
|
|
{
|
|
|
|
HMODULE ret;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpFileName);
|
|
|
|
ret = LoadLibraryExW(wlpFileName, hFile, dwFlags);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpFileName);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-08-22 14:18:25 +00:00
|
|
|
static __inline int DrawTextU(HDC hDC, LPCSTR lpText, int nCount, LPRECT lpRect, UINT uFormat)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpText);
|
|
|
|
ret = DrawTextW(hDC, wlpText, nCount, lpRect, uFormat);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpText);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
static __inline int GetWindowTextU(HWND hWnd, char* lpString, int nMaxCount)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
2019-08-01 17:07:44 +00:00
|
|
|
// Handle the empty string as GetWindowTextW() returns 0 then
|
|
|
|
if ((lpString != NULL) && (nMaxCount > 0))
|
|
|
|
lpString[0] = 0;
|
2017-04-25 13:32:19 +00:00
|
|
|
// coverity[returned_null]
|
2011-11-13 20:53:23 +00:00
|
|
|
walloc(lpString, nMaxCount);
|
|
|
|
ret = GetWindowTextW(hWnd, wlpString, nMaxCount);
|
|
|
|
err = GetLastError();
|
2019-08-05 19:18:34 +00:00
|
|
|
// coverity[var_deref_model]
|
2011-11-13 20:53:23 +00:00
|
|
|
if ( (ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpString, lpString, nMaxCount)) == 0) ) {
|
|
|
|
err = GetLastError();
|
|
|
|
}
|
|
|
|
wfree(lpString);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __inline BOOL SetWindowTextU(HWND hWnd, const char* lpString)
|
|
|
|
{
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpString);
|
|
|
|
ret = SetWindowTextW(hWnd, wlpString);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpString);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __inline int GetWindowTextLengthU(HWND hWnd)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wchar_t* wbuf = NULL;
|
|
|
|
char* buf = NULL;
|
|
|
|
|
|
|
|
ret = GetWindowTextLengthW(hWnd);
|
|
|
|
err = GetLastError();
|
|
|
|
if (ret == 0) goto out;
|
2020-03-31 16:26:34 +00:00
|
|
|
wbuf = (wchar_t* )calloc(ret, sizeof(wchar_t));
|
2011-11-13 20:53:23 +00:00
|
|
|
err = GetLastError();
|
|
|
|
if (wbuf == NULL) {
|
|
|
|
err = ERROR_OUTOFMEMORY; ret = 0; goto out;
|
|
|
|
}
|
|
|
|
ret = GetWindowTextW(hWnd, wbuf, ret);
|
|
|
|
err = GetLastError();
|
|
|
|
if (ret == 0) goto out;
|
|
|
|
buf = wchar_to_utf8(wbuf);
|
|
|
|
err = GetLastError();
|
|
|
|
if (buf == NULL) {
|
|
|
|
err = ERROR_OUTOFMEMORY; ret = 0; goto out;
|
|
|
|
}
|
|
|
|
ret = (int)strlen(buf) + 2; // GetDlgItemText seems to add a character
|
|
|
|
err = GetLastError();
|
|
|
|
out:
|
|
|
|
sfree(wbuf);
|
|
|
|
sfree(buf);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __inline UINT GetDlgItemTextU(HWND hDlg, int nIDDlgItem, char* lpString, int nMaxCount)
|
|
|
|
{
|
|
|
|
UINT ret = 0;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
2017-04-25 13:32:19 +00:00
|
|
|
// coverity[returned_null]
|
2011-11-13 20:53:23 +00:00
|
|
|
walloc(lpString, nMaxCount);
|
|
|
|
ret = GetDlgItemTextW(hDlg, nIDDlgItem, wlpString, nMaxCount);
|
|
|
|
err = GetLastError();
|
|
|
|
if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpString, lpString, nMaxCount)) == 0)) {
|
|
|
|
err = GetLastError();
|
|
|
|
}
|
|
|
|
wfree(lpString);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __inline BOOL SetDlgItemTextU(HWND hDlg, int nIDDlgItem, const char* lpString)
|
|
|
|
{
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpString);
|
|
|
|
ret = SetDlgItemTextW(hDlg, nIDDlgItem, wlpString);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpString);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-10-24 21:57:34 +00:00
|
|
|
static __inline BOOL InsertMenuU(HMENU hMenu, UINT uPosition, UINT uFlags, UINT_PTR uIDNewItem, const char* lpNewItem)
|
|
|
|
{
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpNewItem);
|
|
|
|
ret = InsertMenuW(hMenu, uPosition, uFlags, uIDNewItem, wlpNewItem);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpNewItem);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-11-24 23:42:53 +00:00
|
|
|
static __inline int ComboBox_GetLBTextU(HWND hCtrl, int index, char* lpString)
|
|
|
|
{
|
|
|
|
int size;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wchar_t* wlpString;
|
|
|
|
if (lpString == NULL)
|
|
|
|
return CB_ERR;
|
|
|
|
size = (int)SendMessageW(hCtrl, CB_GETLBTEXTLEN, (WPARAM)index, (LPARAM)0);
|
|
|
|
if (size < 0)
|
|
|
|
return size;
|
2020-04-10 12:16:57 +00:00
|
|
|
wlpString = (wchar_t*)calloc((size_t)size + 1, sizeof(wchar_t));
|
2011-11-24 23:42:53 +00:00
|
|
|
size = (int)SendMessageW(hCtrl, CB_GETLBTEXT, (WPARAM)index, (LPARAM)wlpString);
|
|
|
|
err = GetLastError();
|
|
|
|
if (size > 0)
|
|
|
|
wchar_to_utf8_no_alloc(wlpString, lpString, size+1);
|
|
|
|
wfree(lpString);
|
|
|
|
SetLastError(err);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2018-03-22 23:14:20 +00:00
|
|
|
static __inline DWORD CharUpperBuffU(char* lpString, DWORD len)
|
|
|
|
{
|
|
|
|
DWORD ret;
|
2020-03-31 16:26:34 +00:00
|
|
|
wchar_t *wlpString = (wchar_t*)calloc(len, sizeof(wchar_t));
|
2018-03-22 23:14:20 +00:00
|
|
|
if (wlpString == NULL)
|
|
|
|
return 0;
|
|
|
|
utf8_to_wchar_no_alloc(lpString, wlpString, len);
|
|
|
|
ret = CharUpperBuffW(wlpString, len);
|
|
|
|
wchar_to_utf8_no_alloc(wlpString, lpString, len);
|
|
|
|
free(wlpString);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
static __inline HANDLE CreateFileU(const char* lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
|
|
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
|
2019-04-04 18:12:48 +00:00
|
|
|
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
|
2011-11-13 20:53:23 +00:00
|
|
|
{
|
|
|
|
HANDLE ret = INVALID_HANDLE_VALUE;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpFileName);
|
|
|
|
ret = CreateFileW(wlpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
|
|
|
|
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpFileName);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-04-04 18:12:48 +00:00
|
|
|
static __inline BOOL CreateDirectoryU(const char* lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
|
|
|
|
{
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpPathName);
|
|
|
|
ret = CreateDirectoryW(wlpPathName, lpSecurityAttributes);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpPathName);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-11-14 23:40:00 +00:00
|
|
|
static __inline BOOL CopyFileU(const char* lpExistingFileName, const char* lpNewFileName, BOOL bFailIfExists)
|
|
|
|
{
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpExistingFileName);
|
|
|
|
wconvert(lpNewFileName);
|
|
|
|
ret = CopyFileW(wlpExistingFileName, wlpNewFileName, bFailIfExists);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpExistingFileName);
|
|
|
|
wfree(lpNewFileName);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
static __inline BOOL DeleteFileU(const char* lpFileName)
|
|
|
|
{
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpFileName);
|
|
|
|
ret = DeleteFileW(wlpFileName);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpFileName);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-07-16 21:42:19 +00:00
|
|
|
static __inline BOOL PathFileExistsU(char* szPath)
|
|
|
|
{
|
|
|
|
BOOL ret;
|
|
|
|
wconvert(szPath);
|
|
|
|
ret = PathFileExistsW(wszPath);
|
|
|
|
wfree(szPath);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-08-08 23:10:12 +00:00
|
|
|
static __inline int PathGetDriveNumberU(char* lpPath)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpPath);
|
|
|
|
ret = PathGetDriveNumberW(wlpPath);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpPath);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-06-29 17:19:05 +00:00
|
|
|
// This one is tricky since we can't blindly convert a
|
|
|
|
// UTF-16 position to a UTF-8 one. So we do it manually.
|
|
|
|
static __inline const char* PathFindFileNameU(const char* szPath)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
if (szPath == NULL)
|
|
|
|
return NULL;
|
|
|
|
for (i = strlen(szPath); i != 0; i--) {
|
|
|
|
if ((szPath[i] == '/') || (szPath[i] == '\\')) {
|
|
|
|
i++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return &szPath[i];
|
|
|
|
}
|
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
// This function differs from regular GetTextExtentPoint in that it uses a zero terminated string
|
|
|
|
static __inline BOOL GetTextExtentPointU(HDC hdc, const char* lpString, LPSIZE lpSize)
|
|
|
|
{
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpString);
|
2014-12-03 18:44:00 +00:00
|
|
|
if (wlpString == NULL)
|
|
|
|
return FALSE;
|
|
|
|
ret = GetTextExtentPoint32W(hdc, wlpString, (int)wcslen(wlpString), lpSize);
|
2011-11-13 20:53:23 +00:00
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpString);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-02-07 20:25:21 +00:00
|
|
|
// A UTF-8 alternative to MS GetCurrentDirectory() since the latter is useless for
|
|
|
|
// apps installed from the App Store...
|
2011-11-13 20:53:23 +00:00
|
|
|
static __inline DWORD GetCurrentDirectoryU(DWORD nBufferLength, char* lpBuffer)
|
|
|
|
{
|
2021-02-07 20:25:21 +00:00
|
|
|
DWORD i, ret = 0, err = ERROR_INVALID_DATA;
|
2017-04-25 13:32:19 +00:00
|
|
|
// coverity[returned_null]
|
2011-11-13 20:53:23 +00:00
|
|
|
walloc(lpBuffer, nBufferLength);
|
2021-03-25 19:27:27 +00:00
|
|
|
if (wlpBuffer == NULL) {
|
|
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
|
|
return 0;
|
|
|
|
}
|
2021-02-07 20:25:21 +00:00
|
|
|
ret = GetModuleFileNameW(NULL, wlpBuffer, nBufferLength);
|
2011-11-13 20:53:23 +00:00
|
|
|
err = GetLastError();
|
2021-02-07 20:25:21 +00:00
|
|
|
if (ret > 0) {
|
|
|
|
for (i = ret - 1; i > 0; i--) {
|
|
|
|
if (wlpBuffer[i] == L'\\') {
|
|
|
|
wlpBuffer[i] = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-11-13 20:53:23 +00:00
|
|
|
if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, nBufferLength)) == 0)) {
|
|
|
|
err = GetLastError();
|
|
|
|
}
|
|
|
|
wfree(lpBuffer);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-06-27 21:12:30 +00:00
|
|
|
static __inline UINT GetSystemDirectoryU(char* lpBuffer, UINT uSize)
|
|
|
|
{
|
|
|
|
UINT ret = 0, err = ERROR_INVALID_DATA;
|
2017-04-25 13:32:19 +00:00
|
|
|
// coverity[returned_null]
|
2015-06-27 21:12:30 +00:00
|
|
|
walloc(lpBuffer, uSize);
|
|
|
|
ret = GetSystemDirectoryW(wlpBuffer, uSize);
|
|
|
|
err = GetLastError();
|
|
|
|
if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, uSize)) == 0)) {
|
|
|
|
err = GetLastError();
|
|
|
|
}
|
|
|
|
wfree(lpBuffer);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-08-22 22:23:08 +00:00
|
|
|
static __inline UINT GetSystemWindowsDirectoryU(char* lpBuffer, UINT uSize)
|
|
|
|
{
|
|
|
|
UINT ret = 0, err = ERROR_INVALID_DATA;
|
2017-04-25 13:32:19 +00:00
|
|
|
// coverity[returned_null]
|
2015-08-22 22:23:08 +00:00
|
|
|
walloc(lpBuffer, uSize);
|
|
|
|
ret = GetSystemWindowsDirectoryW(wlpBuffer, uSize);
|
|
|
|
err = GetLastError();
|
|
|
|
if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, uSize)) == 0)) {
|
|
|
|
err = GetLastError();
|
|
|
|
}
|
|
|
|
wfree(lpBuffer);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-05-31 15:54:11 +00:00
|
|
|
static __inline BOOL SHGetSpecialFolderPathU(HWND hwnd, char* pszPath, int csidl, BOOL fCreate)
|
|
|
|
{
|
|
|
|
BOOL ret;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
// pszPath is at least MAX_PATH characters in size
|
|
|
|
WCHAR wpszPath[MAX_PATH] = { 0 };
|
|
|
|
ret = SHGetSpecialFolderPathW(hwnd, wpszPath, csidl, fCreate);
|
|
|
|
err = GetLastError();
|
|
|
|
wchar_to_utf8_no_alloc(wpszPath, pszPath, MAX_PATH);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-10-15 21:58:27 +00:00
|
|
|
static __inline DWORD GetTempPathU(DWORD nBufferLength, char* lpBuffer)
|
|
|
|
{
|
|
|
|
DWORD ret = 0, err = ERROR_INVALID_DATA;
|
2017-04-25 13:32:19 +00:00
|
|
|
// coverity[returned_null]
|
2013-10-15 21:58:27 +00:00
|
|
|
walloc(lpBuffer, nBufferLength);
|
|
|
|
ret = GetTempPathW(nBufferLength, wlpBuffer);
|
|
|
|
err = GetLastError();
|
|
|
|
if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, nBufferLength)) == 0)) {
|
|
|
|
err = GetLastError();
|
|
|
|
}
|
|
|
|
wfree(lpBuffer);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __inline DWORD GetTempFileNameU(char* lpPathName, char* lpPrefixString, UINT uUnique, char* lpTempFileName)
|
|
|
|
{
|
|
|
|
DWORD ret = 0, err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpPathName);
|
|
|
|
wconvert(lpPrefixString);
|
2017-04-25 13:32:19 +00:00
|
|
|
// coverity[returned_null]
|
2013-10-15 21:58:27 +00:00
|
|
|
walloc(lpTempFileName, MAX_PATH);
|
2014-12-30 19:46:13 +00:00
|
|
|
ret = GetTempFileNameW(wlpPathName, wlpPrefixString, uUnique, wlpTempFileName);
|
2013-10-15 21:58:27 +00:00
|
|
|
err = GetLastError();
|
|
|
|
if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpTempFileName, lpTempFileName, MAX_PATH)) == 0)) {
|
|
|
|
err = GetLastError();
|
|
|
|
}
|
|
|
|
wfree(lpTempFileName);
|
|
|
|
wfree(lpPrefixString);
|
|
|
|
wfree(lpPathName);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-12-16 22:42:30 +00:00
|
|
|
static __inline DWORD GetModuleFileNameU(HMODULE hModule, char* lpFilename, DWORD nSize)
|
|
|
|
{
|
|
|
|
DWORD ret = 0, err = ERROR_INVALID_DATA;
|
2017-04-25 13:32:19 +00:00
|
|
|
// coverity[returned_null]
|
2012-12-16 22:42:30 +00:00
|
|
|
walloc(lpFilename, nSize);
|
|
|
|
ret = GetModuleFileNameW(hModule, wlpFilename, nSize);
|
|
|
|
err = GetLastError();
|
|
|
|
if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpFilename, lpFilename, nSize)) == 0)) {
|
|
|
|
err = GetLastError();
|
|
|
|
}
|
|
|
|
wfree(lpFilename);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-04-27 22:06:42 +00:00
|
|
|
static __inline DWORD GetModuleFileNameExU(HANDLE hProcess, HMODULE hModule, char* lpFilename, DWORD nSize)
|
|
|
|
{
|
|
|
|
DWORD ret = 0, err = ERROR_INVALID_DATA;
|
|
|
|
// coverity[returned_null]
|
|
|
|
walloc(lpFilename, nSize);
|
|
|
|
ret = GetModuleFileNameExW(hProcess, hModule, wlpFilename, nSize);
|
|
|
|
err = GetLastError();
|
|
|
|
if ((ret != 0)
|
|
|
|
&& ((ret = wchar_to_utf8_no_alloc(wlpFilename, lpFilename, nSize)) == 0)) {
|
|
|
|
err = GetLastError();
|
|
|
|
}
|
|
|
|
wfree(lpFilename);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-10-08 10:14:29 +00:00
|
|
|
static __inline DWORD GetFileVersionInfoSizeU(const char* lpFileName, LPDWORD lpdwHandle)
|
|
|
|
{
|
|
|
|
DWORD ret = 0, err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpFileName);
|
|
|
|
ret = GetFileVersionInfoSizeW(wlpFileName, lpdwHandle);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpFileName);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __inline BOOL GetFileVersionInfoU(const char* lpFileName, DWORD dwHandle, DWORD dwLen, LPVOID lpData)
|
|
|
|
{
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpFileName);
|
|
|
|
if (dwHandle != 0)
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
else
|
|
|
|
ret = GetFileVersionInfoW(wlpFileName, dwHandle, dwLen, lpData);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpFileName);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
static __inline DWORD GetFullPathNameU(const char* lpFileName, DWORD nBufferLength, char* lpBuffer, char** lpFilePart)
|
|
|
|
{
|
|
|
|
DWORD ret = 0, err = ERROR_INVALID_DATA;
|
|
|
|
wchar_t* wlpFilePart;
|
|
|
|
wconvert(lpFileName);
|
2017-04-25 13:32:19 +00:00
|
|
|
// coverity[returned_null]
|
2011-11-13 20:53:23 +00:00
|
|
|
walloc(lpBuffer, nBufferLength);
|
|
|
|
|
|
|
|
// lpFilePart is not supported
|
|
|
|
if (lpFilePart != NULL) goto out;
|
|
|
|
|
|
|
|
ret = GetFullPathNameW(wlpFileName, nBufferLength, wlpBuffer, &wlpFilePart);
|
|
|
|
err = GetLastError();
|
|
|
|
if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, nBufferLength)) == 0)) {
|
|
|
|
err = GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
wfree(lpBuffer);
|
|
|
|
wfree(lpFileName);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __inline DWORD GetFileAttributesU(const char* lpFileName)
|
|
|
|
{
|
|
|
|
DWORD ret = 0xFFFFFFFF, err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpFileName);
|
2018-07-28 10:59:44 +00:00
|
|
|
// Unlike Microsoft's version, ours doesn't fail if the string is quoted
|
|
|
|
if ((wlpFileName[0] == L'"') && (wlpFileName[wcslen(wlpFileName) - 1] == L'"')) {
|
|
|
|
wlpFileName[wcslen(wlpFileName) - 1] = 0;
|
|
|
|
ret = GetFileAttributesW(&wlpFileName[1]);
|
|
|
|
} else {
|
|
|
|
ret = GetFileAttributesW(wlpFileName);
|
|
|
|
}
|
2011-11-13 20:53:23 +00:00
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpFileName);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-03-27 12:21:41 +00:00
|
|
|
static __inline BOOL SetFileAttributesU(const char* lpFileName, DWORD dwFileAttributes)
|
|
|
|
{
|
|
|
|
BOOL ret = FALSE, err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpFileName);
|
|
|
|
// Unlike Microsoft's version, ours doesn't fail if the string is quoted
|
|
|
|
if ((wlpFileName[0] == L'"') && (wlpFileName[wcslen(wlpFileName) - 1] == L'"')) {
|
|
|
|
wlpFileName[wcslen(wlpFileName) - 1] = 0;
|
|
|
|
ret = SetFileAttributesW(&wlpFileName[1], dwFileAttributes);
|
|
|
|
} else {
|
|
|
|
ret = SetFileAttributesW(wlpFileName, dwFileAttributes);
|
|
|
|
}
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(lpFileName);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
static __inline int SHCreateDirectoryExU(HWND hwnd, const char* pszPath, SECURITY_ATTRIBUTES *psa)
|
|
|
|
{
|
|
|
|
int ret = ERROR_INVALID_DATA;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(pszPath);
|
|
|
|
ret = SHCreateDirectoryExW(hwnd, wpszPath, psa);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(pszPath);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-01-08 00:22:56 +00:00
|
|
|
static __inline int SHDeleteDirectoryExU(HWND hwnd, const char* pszPath, FILEOP_FLAGS fFlags)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
// String needs to be double NULL terminated, so we just use the length of the UTF-8 string
|
|
|
|
// which is always expected to be larger than our UTF-16 one, and add 2 chars for good measure.
|
2022-01-05 11:57:26 +00:00
|
|
|
size_t wpszPath_len = (pszPath == NULL) ? 0 : strlen(pszPath) + 2;
|
2017-04-25 13:32:19 +00:00
|
|
|
// coverity[returned_null]
|
2016-06-08 15:32:31 +00:00
|
|
|
walloc(pszPath, wpszPath_len);
|
2015-01-16 01:51:24 +00:00
|
|
|
SHFILEOPSTRUCTW shfo = { hwnd, FO_DELETE, wpszPath, NULL, fFlags, FALSE, NULL, NULL };
|
2015-01-23 02:26:41 +00:00
|
|
|
utf8_to_wchar_no_alloc(pszPath, wpszPath, (int)wpszPath_len);
|
2015-01-08 00:22:56 +00:00
|
|
|
// FOF_SILENT | FOF_NOERRORUI | FOF_NOCONFIRMATION,
|
|
|
|
ret = SHFileOperationW(&shfo);
|
|
|
|
wfree(pszPath);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
static __inline BOOL ShellExecuteExU(SHELLEXECUTEINFOA* lpExecInfo)
|
|
|
|
{
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
SHELLEXECUTEINFOW wExecInfo;
|
|
|
|
|
|
|
|
// Because we're lazy, we'll assume that the A and W structs inherently have the same size
|
|
|
|
if (lpExecInfo->cbSize != sizeof(SHELLEXECUTEINFOW)) {
|
|
|
|
SetLastError(ERROR_BAD_LENGTH); return FALSE;
|
|
|
|
}
|
|
|
|
memcpy(&wExecInfo, lpExecInfo, lpExecInfo->cbSize);
|
|
|
|
wExecInfo.lpVerb = utf8_to_wchar(lpExecInfo->lpVerb);
|
|
|
|
wExecInfo.lpFile = utf8_to_wchar(lpExecInfo->lpFile);
|
|
|
|
wExecInfo.lpParameters = utf8_to_wchar(lpExecInfo->lpParameters);
|
|
|
|
wExecInfo.lpDirectory = utf8_to_wchar(lpExecInfo->lpDirectory);
|
|
|
|
if (wExecInfo.fMask & SEE_MASK_CLASSNAME) {
|
|
|
|
wExecInfo.lpClass = utf8_to_wchar(lpExecInfo->lpClass);
|
|
|
|
} else {
|
|
|
|
wExecInfo.lpClass = NULL;
|
|
|
|
}
|
|
|
|
ret = ShellExecuteExW(&wExecInfo);
|
|
|
|
err = GetLastError();
|
|
|
|
// Copy the returned values back
|
|
|
|
lpExecInfo->hInstApp = wExecInfo.hInstApp;
|
|
|
|
lpExecInfo->hProcess = wExecInfo.hProcess;
|
|
|
|
sfree(wExecInfo.lpVerb);
|
|
|
|
sfree(wExecInfo.lpFile);
|
|
|
|
sfree(wExecInfo.lpParameters);
|
|
|
|
sfree(wExecInfo.lpDirectory);
|
|
|
|
sfree(wExecInfo.lpClass);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Doesn't support LPSTARTUPINFOEX struct
|
|
|
|
static __inline BOOL CreateProcessU(const char* lpApplicationName, const char* lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
|
|
|
LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags,
|
|
|
|
LPVOID lpEnvironment, const char* lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo,
|
|
|
|
LPPROCESS_INFORMATION lpProcessInformation)
|
|
|
|
{
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
STARTUPINFOW wStartupInfo;
|
|
|
|
wconvert(lpApplicationName);
|
|
|
|
wconvert(lpCommandLine);
|
|
|
|
wconvert(lpCurrentDirectory);
|
|
|
|
|
|
|
|
// Because we're lazy, we'll assume that the A and W structs inherently have the same size
|
|
|
|
// Also prevents the use of STARTUPINFOEX
|
|
|
|
if (lpStartupInfo->cb != sizeof(STARTUPINFOW)) {
|
|
|
|
err = ERROR_BAD_LENGTH; goto out;
|
|
|
|
}
|
|
|
|
memcpy(&wStartupInfo, lpStartupInfo, lpStartupInfo->cb);
|
|
|
|
wStartupInfo.lpDesktop = utf8_to_wchar(lpStartupInfo->lpDesktop);
|
|
|
|
wStartupInfo.lpTitle = utf8_to_wchar(lpStartupInfo->lpTitle);
|
|
|
|
ret = CreateProcessW(wlpApplicationName, wlpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles,
|
|
|
|
dwCreationFlags, lpEnvironment, wlpCurrentDirectory, &wStartupInfo, lpProcessInformation);
|
|
|
|
err = GetLastError();
|
|
|
|
sfree(wStartupInfo.lpDesktop);
|
|
|
|
sfree(wStartupInfo.lpTitle);
|
|
|
|
out:
|
|
|
|
wfree(lpApplicationName);
|
|
|
|
wfree(lpCommandLine);
|
|
|
|
wfree(lpCurrentDirectory);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: when used, nFileOffset & nFileExtension MUST be provided
|
|
|
|
// in number of Unicode characters, NOT number of UTF-8 bytes
|
|
|
|
static __inline BOOL WINAPI GetOpenSaveFileNameU(LPOPENFILENAMEA lpofn, BOOL save)
|
|
|
|
{
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
size_t i, len;
|
|
|
|
OPENFILENAMEW wofn;
|
|
|
|
memset(&wofn, 0, sizeof(wofn));
|
|
|
|
wofn.lStructSize = sizeof(wofn);
|
|
|
|
wofn.hwndOwner = lpofn->hwndOwner;
|
|
|
|
wofn.hInstance = lpofn->hInstance;
|
|
|
|
|
|
|
|
// No support for custom filters
|
|
|
|
if (lpofn->lpstrCustomFilter != NULL) goto out;
|
|
|
|
|
|
|
|
// Count on Microsoft to use an moronic scheme for filters
|
|
|
|
// that relies on NULL separators and double NULL terminators
|
|
|
|
if (lpofn->lpstrFilter != NULL) {
|
|
|
|
// Replace the NULLs by something that can be converted
|
|
|
|
for (i=0; ; i++) {
|
|
|
|
if (lpofn->lpstrFilter[i] == 0) {
|
|
|
|
((char*)lpofn->lpstrFilter)[i] = '\r';
|
|
|
|
if (lpofn->lpstrFilter[i+1] == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
wofn.lpstrFilter = utf8_to_wchar(lpofn->lpstrFilter);
|
|
|
|
// And revert
|
|
|
|
len = wcslen(wofn.lpstrFilter); // don't use in the loop as it would be reevaluated
|
|
|
|
for (i=0; i<len; i++) {
|
|
|
|
if (wofn.lpstrFilter[i] == '\r') {
|
|
|
|
((wchar_t*)wofn.lpstrFilter)[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
len = strlen(lpofn->lpstrFilter);
|
|
|
|
for (i=0; i<len; i++) {
|
|
|
|
if (lpofn->lpstrFilter[i] == '\r') {
|
|
|
|
((char*)lpofn->lpstrFilter)[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
wofn.lpstrFilter = NULL;
|
|
|
|
}
|
|
|
|
wofn.nMaxCustFilter = lpofn->nMaxCustFilter;
|
|
|
|
wofn.nFilterIndex = lpofn->nFilterIndex;
|
2020-03-31 16:26:34 +00:00
|
|
|
wofn.lpstrFile = (LPWSTR)calloc(lpofn->nMaxFile, sizeof(wchar_t));
|
2011-11-13 20:53:23 +00:00
|
|
|
utf8_to_wchar_no_alloc(lpofn->lpstrFile, wofn.lpstrFile, lpofn->nMaxFile);
|
|
|
|
wofn.nMaxFile = lpofn->nMaxFile;
|
2020-03-31 16:26:34 +00:00
|
|
|
wofn.lpstrFileTitle = (LPWSTR)calloc(lpofn->nMaxFileTitle, sizeof(wchar_t));
|
2011-11-13 20:53:23 +00:00
|
|
|
utf8_to_wchar_no_alloc(lpofn->lpstrFileTitle, wofn.lpstrFileTitle, lpofn->nMaxFileTitle);
|
|
|
|
wofn.nMaxFileTitle = lpofn->nMaxFileTitle;
|
|
|
|
wofn.lpstrInitialDir = utf8_to_wchar(lpofn->lpstrInitialDir);
|
|
|
|
wofn.lpstrTitle = utf8_to_wchar(lpofn->lpstrTitle);
|
|
|
|
wofn.Flags = lpofn->Flags;
|
|
|
|
wofn.nFileOffset = lpofn->nFileOffset;
|
|
|
|
wofn.nFileExtension = lpofn->nFileExtension;
|
|
|
|
wofn.lpstrDefExt = utf8_to_wchar(lpofn->lpstrDefExt);
|
|
|
|
wofn.lCustData = lpofn->lCustData;
|
|
|
|
wofn.lpfnHook = lpofn->lpfnHook;
|
|
|
|
wofn.lpTemplateName = utf8_to_wchar(lpofn->lpTemplateName);
|
|
|
|
wofn.pvReserved = lpofn->pvReserved;
|
|
|
|
wofn.dwReserved = lpofn->dwReserved;
|
|
|
|
wofn.FlagsEx = lpofn->FlagsEx;
|
|
|
|
|
|
|
|
if (save) {
|
|
|
|
ret = GetSaveFileNameW(&wofn);
|
|
|
|
} else {
|
|
|
|
ret = GetOpenFileNameW(&wofn);
|
|
|
|
}
|
|
|
|
err = GetLastError();
|
|
|
|
if ( (ret)
|
|
|
|
&& ( (wchar_to_utf8_no_alloc(wofn.lpstrFile, lpofn->lpstrFile, lpofn->nMaxFile) == 0)
|
|
|
|
|| (wchar_to_utf8_no_alloc(wofn.lpstrFileTitle, lpofn->lpstrFileTitle, lpofn->nMaxFileTitle) == 0) ) ) {
|
|
|
|
err = GetLastError();
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
sfree(wofn.lpstrDefExt);
|
|
|
|
sfree(wofn.lpstrFile);
|
|
|
|
sfree(wofn.lpstrFileTitle);
|
|
|
|
sfree(wofn.lpstrFilter);
|
|
|
|
sfree(wofn.lpstrInitialDir);
|
|
|
|
sfree(wofn.lpstrTitle);
|
|
|
|
sfree(wofn.lpTemplateName);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern BOOL WINAPI UpdateDriverForPlugAndPlayDevicesW(HWND hwndParent, LPCWSTR HardwareId,
|
|
|
|
LPCWSTR FullInfPath, DWORD InstallFlags, PBOOL bRebootRequired);
|
|
|
|
|
|
|
|
static __inline BOOL UpdateDriverForPlugAndPlayDevicesU(HWND hwndParent, const char* HardwareId, const char* FullInfPath,
|
|
|
|
DWORD InstallFlags, PBOOL bRebootRequired)
|
|
|
|
{
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(HardwareId);
|
|
|
|
wconvert(FullInfPath);
|
|
|
|
ret = UpdateDriverForPlugAndPlayDevicesW(hwndParent, wHardwareId, wFullInfPath, InstallFlags, bRebootRequired);
|
|
|
|
err = GetLastError();
|
|
|
|
wfree(HardwareId);
|
|
|
|
wfree(FullInfPath);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __inline BOOL SetupCopyOEMInfU(const char* SourceInfFileName, const char* OEMSourceMediaLocation, DWORD OEMSourceMediaType,
|
|
|
|
DWORD CopyStyle, char* DestinationInfFileName, DWORD DestinationInfFileNameSize,
|
|
|
|
PDWORD RequiredSize, PTSTR DestinationInfFileNameComponent)
|
|
|
|
{
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(SourceInfFileName);
|
|
|
|
wconvert(OEMSourceMediaLocation);
|
2017-04-25 13:32:19 +00:00
|
|
|
// coverity[returned_null]
|
2011-11-13 20:53:23 +00:00
|
|
|
walloc(DestinationInfFileName, DestinationInfFileNameSize);
|
|
|
|
|
|
|
|
// DestinationInfFileNameComponent is not supported
|
|
|
|
if (DestinationInfFileNameComponent != NULL) goto out;
|
|
|
|
|
|
|
|
ret = SetupCopyOEMInfW(wSourceInfFileName, wOEMSourceMediaLocation, OEMSourceMediaType, CopyStyle,
|
|
|
|
wDestinationInfFileName, DestinationInfFileNameSize, RequiredSize, NULL);
|
|
|
|
err = GetLastError();
|
|
|
|
if ((ret != FALSE) && ((ret = wchar_to_utf8_no_alloc(wDestinationInfFileName, DestinationInfFileName, DestinationInfFileNameSize)) == 0)) {
|
|
|
|
err = GetLastError();
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
wfree(SourceInfFileName);
|
|
|
|
wfree(OEMSourceMediaLocation);
|
|
|
|
wfree(DestinationInfFileName);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-07-01 23:45:47 +00:00
|
|
|
static __inline int _chdirU(const char *dirname)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
wconvert(dirname);
|
|
|
|
ret = _wchdir(wdirname);
|
|
|
|
wfree(dirname);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-09-28 01:32:11 +00:00
|
|
|
#if defined(_WIN32_WINNT) && (_WIN32_WINNT <= 0x501)
|
|
|
|
static __inline FILE* fopenU(const char* filename, const char* mode)
|
|
|
|
{
|
|
|
|
FILE* ret = NULL;
|
|
|
|
wconvert(filename);
|
|
|
|
wconvert(mode);
|
|
|
|
ret = _wfopen(wfilename, wmode);
|
|
|
|
wfree(filename);
|
|
|
|
wfree(mode);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __inline int _openU(const char *filename, int oflag, int pmode)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
wconvert(filename);
|
|
|
|
ret = _wopen(wfilename, oflag, pmode);
|
|
|
|
wfree(filename);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
2011-11-13 20:53:23 +00:00
|
|
|
static __inline FILE* fopenU(const char* filename, const char* mode)
|
|
|
|
{
|
|
|
|
FILE* ret = NULL;
|
|
|
|
wconvert(filename);
|
|
|
|
wconvert(mode);
|
2015-08-26 12:49:35 +00:00
|
|
|
_wfopen_s(&ret, wfilename, wmode);
|
2011-11-13 20:53:23 +00:00
|
|
|
wfree(filename);
|
|
|
|
wfree(mode);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-12-29 20:34:41 +00:00
|
|
|
static __inline int _openU(const char *filename, int oflag , int pmode)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
2015-08-26 12:49:35 +00:00
|
|
|
int shflag = _SH_DENYNO;
|
2014-12-29 20:34:41 +00:00
|
|
|
wconvert(filename);
|
2015-08-26 12:49:35 +00:00
|
|
|
// Try to match the share flag to the oflag
|
2015-09-28 00:28:29 +00:00
|
|
|
if ((oflag & 0x03) == _O_RDONLY)
|
2015-08-26 12:49:35 +00:00
|
|
|
shflag = _SH_DENYWR;
|
2015-09-28 00:28:29 +00:00
|
|
|
else if ((oflag & 0x03) == _O_WRONLY)
|
2015-08-26 12:49:35 +00:00
|
|
|
shflag = _SH_DENYRD;
|
|
|
|
_wsopen_s(&ret, wfilename, oflag, shflag, pmode);
|
2014-12-29 20:34:41 +00:00
|
|
|
wfree(filename);
|
|
|
|
return ret;
|
|
|
|
}
|
2017-04-19 10:16:20 +00:00
|
|
|
#endif
|
2014-12-29 20:34:41 +00:00
|
|
|
|
2020-03-30 10:09:03 +00:00
|
|
|
static __inline int _unlinkU(const char* path)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
wconvert(path);
|
|
|
|
ret = _wunlink(wpath);
|
|
|
|
wfree(path);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-06-24 16:23:06 +00:00
|
|
|
static __inline int _stat64U(const char *path, struct __stat64 *buffer)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
wconvert(path);
|
|
|
|
ret = _wstat64(wpath, buffer);
|
|
|
|
wfree(path);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-06-10 19:00:47 +00:00
|
|
|
static __inline int _accessU(const char* path, int mode)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
wconvert(path);
|
|
|
|
ret = _waccess(wpath, mode);
|
|
|
|
wfree(path);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-06-10 20:25:33 +00:00
|
|
|
static __inline const char* _filenameU(const char* path)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
if (path == NULL)
|
|
|
|
return NULL;
|
2020-06-18 10:42:57 +00:00
|
|
|
for (i = (int)strlen(path) - 1; i >= 0; i--)
|
2020-06-10 20:25:33 +00:00
|
|
|
if ((path[i] == '/') || (path[i] == '\\'))
|
|
|
|
return &path[i + 1];
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
2011-12-30 21:23:13 +00:00
|
|
|
// returned UTF-8 string must be freed
|
|
|
|
static __inline char* getenvU(const char* varname)
|
|
|
|
{
|
|
|
|
wconvert(varname);
|
2017-04-19 10:16:20 +00:00
|
|
|
char* ret = NULL;
|
|
|
|
wchar_t* wbuf = NULL;
|
|
|
|
// _wgetenv() is *BROKEN* in MS compilers => use GetEnvironmentVariableW()
|
|
|
|
DWORD dwSize = GetEnvironmentVariableW(wvarname, wbuf, 0);
|
2020-03-31 16:26:34 +00:00
|
|
|
wbuf = (wchar_t*)calloc(dwSize, sizeof(wchar_t));
|
2019-04-27 15:04:47 +00:00
|
|
|
if (wbuf == NULL) {
|
|
|
|
wfree(varname);
|
2017-04-19 10:16:20 +00:00
|
|
|
return NULL;
|
2019-04-27 15:04:47 +00:00
|
|
|
}
|
2017-04-19 10:16:20 +00:00
|
|
|
dwSize = GetEnvironmentVariableW(wvarname, wbuf, dwSize);
|
|
|
|
if (dwSize != 0)
|
|
|
|
ret = wchar_to_utf8(wbuf);
|
|
|
|
free(wbuf);
|
2011-12-30 21:23:13 +00:00
|
|
|
wfree(varname);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-03 23:12:48 +00:00
|
|
|
static __inline int _mkdirU(const char* dirname)
|
|
|
|
{
|
|
|
|
wconvert(dirname);
|
|
|
|
int ret;
|
|
|
|
ret = _wmkdir(wdirname);
|
|
|
|
wfree(dirname);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-05-17 21:53:48 +00:00
|
|
|
// This version of _mkdirU creates all needed directories along the way
|
|
|
|
static __inline int _mkdirExU(const char* dirname)
|
|
|
|
{
|
|
|
|
int ret = -1, trailing_slash = -1;
|
|
|
|
size_t i, len;
|
|
|
|
wconvert(dirname);
|
|
|
|
len = wcslen(wdirname);
|
|
|
|
while (trailing_slash && (len > 0)) {
|
|
|
|
if ((wdirname[len - 1] == '\\') || (wdirname[len - 1] == '/'))
|
|
|
|
wdirname[--len] = 0;
|
|
|
|
else
|
|
|
|
trailing_slash = 0;
|
|
|
|
}
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
if ((wdirname[i] == '\\') || (wdirname[i] == '/'))
|
|
|
|
wdirname[i] = 0;
|
|
|
|
for (i = 0; i < len; ) {
|
|
|
|
if ((_wmkdir(wdirname) < 0) && (errno != EEXIST) && (errno != EACCES))
|
|
|
|
goto out;
|
|
|
|
i = wcslen(wdirname);
|
|
|
|
wdirname[i] = '\\';
|
|
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
out:
|
|
|
|
wfree(dirname);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __inline int _rmdirU(const char* dirname)
|
|
|
|
{
|
|
|
|
wconvert(dirname);
|
|
|
|
int ret;
|
|
|
|
ret = _wrmdir(wdirname);
|
|
|
|
wfree(dirname);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-07-19 21:35:30 +00:00
|
|
|
static __inline BOOL MoveFileU(const char* lpExistingFileName, const char* lpNewFileName)
|
|
|
|
{
|
|
|
|
wconvert(lpExistingFileName);
|
|
|
|
wconvert(lpNewFileName);
|
|
|
|
BOOL ret = MoveFileW(wlpExistingFileName, wlpNewFileName);
|
|
|
|
wfree(lpNewFileName);
|
|
|
|
wfree(lpExistingFileName);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __inline BOOL MoveFileExU(const char* lpExistingFileName, const char* lpNewFileName, DWORD dwFlags)
|
|
|
|
{
|
|
|
|
wconvert(lpExistingFileName);
|
|
|
|
wconvert(lpNewFileName);
|
|
|
|
BOOL ret = MoveFileExW(wlpExistingFileName, wlpNewFileName, dwFlags);
|
|
|
|
wfree(lpNewFileName);
|
|
|
|
wfree(lpExistingFileName);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-06-05 19:21:16 +00:00
|
|
|
// The following expects PropertyBuffer to contain a single Unicode string
|
|
|
|
static __inline BOOL SetupDiGetDeviceRegistryPropertyU(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData,
|
|
|
|
DWORD Property, PDWORD PropertyRegDataType, PBYTE PropertyBuffer, DWORD PropertyBufferSize, PDWORD RequiredSize)
|
|
|
|
{
|
2016-06-26 20:24:16 +00:00
|
|
|
BOOL ret = FALSE;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
2017-04-25 13:32:19 +00:00
|
|
|
// coverity[returned_null]
|
2016-06-05 19:21:16 +00:00
|
|
|
walloc(PropertyBuffer, PropertyBufferSize);
|
|
|
|
|
|
|
|
ret = SetupDiGetDeviceRegistryPropertyW(DeviceInfoSet, DeviceInfoData, Property,
|
|
|
|
PropertyRegDataType, (PBYTE)wPropertyBuffer, PropertyBufferSize, RequiredSize);
|
|
|
|
err = GetLastError();
|
|
|
|
if ((ret != 0) && (wchar_to_utf8_no_alloc(wPropertyBuffer,
|
|
|
|
(char*)(uintptr_t)PropertyBuffer, PropertyBufferSize) == 0)) {
|
|
|
|
err = GetLastError();
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
wfree(PropertyBuffer);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
[wue] add automatic local account creation and regional settings duplication
* Local account is created with the same name as the current user along with an *empty* password
(which we force the user to change on next logon). This is done to assuage users who might be
weary of entering a password in a third party application, and has the benefit of enabling
autologon when the install is complete.
* Note that the creation of a local account through an answer file prevents Windows 11 22H2
from bugging users about MSA *even with an active network connection*.
* For convenience reasons, only duplication of the current username is enabled. We *may* add a
dialog to enter any random username in a future version, but for 3.20, this is all you get.
* Likewise, the locale duplication is only carried out during OOBE and *not* WinPE (which means
that you still get the initial "Windows setup language and user preferences" prompt). This is
intentional as otherwise the default screen and "Repair Windows" options are not presented.
* It's not my fault that the Windows password change screen is super ill conceived, whereas it
doesn't hide the current password field as it should when the current password is blank, and
one needs to click on a very small arrow to get the changes applied, instead of a PROMINENT
button that should intuitively have been positioned right next to "Cancel".
* If you want to complain that we should just "present the user with XYZ and be done with it",
please bear in mind that we can't add new dialogs to Rufus as willy-nilly as you believe we
can. *ANY* new UI interface requires major planning, which is the reason why, for the time
being, we are limited to reusing a simple dissociated list of checkboxes for all WUE options.
2022-07-19 18:06:42 +00:00
|
|
|
// NB: This does not support the ERROR_INSUFFICIENT_BUFFER dance to retrieve the required buffer size
|
|
|
|
static __inline BOOL GetUserNameU(LPSTR lpBuffer, LPDWORD pcbBuffer)
|
|
|
|
{
|
|
|
|
BOOL ret;
|
|
|
|
DWORD err, size;
|
|
|
|
if (lpBuffer == NULL || pcbBuffer == NULL) {
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
size = *pcbBuffer;
|
|
|
|
// coverity[returned_null]
|
|
|
|
walloc(lpBuffer, size);
|
|
|
|
ret = GetUserNameW(wlpBuffer, &size);
|
|
|
|
err = GetLastError();
|
|
|
|
if (ret) {
|
|
|
|
*pcbBuffer = (DWORD)wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, size);
|
|
|
|
if (*pcbBuffer == 0)
|
|
|
|
err = GetLastError();
|
|
|
|
else
|
|
|
|
// Reported size includes the NUL terminator
|
|
|
|
(*pcbBuffer)++;
|
|
|
|
}
|
|
|
|
wfree(lpBuffer);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-06-26 20:24:16 +00:00
|
|
|
static __inline BOOL GetVolumeInformationU(LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffer,
|
|
|
|
DWORD nVolumeNameSize, LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength,
|
|
|
|
LPDWORD lpFileSystemFlags, LPSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize)
|
|
|
|
{
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
DWORD err = ERROR_INVALID_DATA;
|
|
|
|
wconvert(lpRootPathName);
|
2017-04-25 13:32:19 +00:00
|
|
|
// coverity[returned_null]
|
2016-06-26 20:24:16 +00:00
|
|
|
walloc(lpVolumeNameBuffer, nVolumeNameSize);
|
2017-04-25 13:32:19 +00:00
|
|
|
// coverity[returned_null]
|
2016-06-26 20:24:16 +00:00
|
|
|
walloc(lpFileSystemNameBuffer, nFileSystemNameSize);
|
|
|
|
|
|
|
|
ret = GetVolumeInformationW(wlpRootPathName, wlpVolumeNameBuffer, nVolumeNameSize,
|
|
|
|
lpVolumeSerialNumber, lpMaximumComponentLength, lpFileSystemFlags,
|
|
|
|
wlpFileSystemNameBuffer, nFileSystemNameSize);
|
|
|
|
err = GetLastError();
|
|
|
|
if (ret) {
|
|
|
|
if ( ((lpVolumeNameBuffer != NULL) && (wchar_to_utf8_no_alloc(wlpVolumeNameBuffer,
|
|
|
|
lpVolumeNameBuffer, nVolumeNameSize) == 0))
|
|
|
|
|| ((lpFileSystemNameBuffer != NULL) && (wchar_to_utf8_no_alloc(wlpFileSystemNameBuffer,
|
|
|
|
lpFileSystemNameBuffer, nFileSystemNameSize) == 0)) ) {
|
|
|
|
err = GetLastError();
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
wfree(lpVolumeNameBuffer);
|
|
|
|
wfree(lpFileSystemNameBuffer);
|
|
|
|
wfree(lpRootPathName);
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|