1 /* Copyright (c) Mark Harmstone 2016-17
3 * This file is part of WinBtrfs.
5 * WinBtrfs is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public Licence as published by
7 * the Free Software Foundation, either version 3 of the Licence, or
8 * (at your option) any later version.
10 * WinBtrfs is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public Licence for more details.
15 * You should have received a copy of the GNU Lesser General Public Licence
16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
27 static const GUID CLSID_ShellBtrfsIconHandler
= { 0x2690b74f, 0xf353, 0x422d, { 0xbb, 0x12, 0x40, 0x15, 0x81, 0xee, 0xf8, 0xf0 } };
28 static const GUID CLSID_ShellBtrfsContextMenu
= { 0x2690b74f, 0xf353, 0x422d, { 0xbb, 0x12, 0x40, 0x15, 0x81, 0xee, 0xf8, 0xf1 } };
29 static const GUID CLSID_ShellBtrfsPropSheet
= { 0x2690b74f, 0xf353, 0x422d, { 0xbb, 0x12, 0x40, 0x15, 0x81, 0xee, 0xf8, 0xf2 } };
30 static const GUID CLSID_ShellBtrfsVolPropSheet
= { 0x2690b74f, 0xf353, 0x422d, { 0xbb, 0x12, 0x40, 0x15, 0x81, 0xee, 0xf8, 0xf3 } };
32 #define COM_DESCRIPTION_ICON_HANDLER L"WinBtrfs shell extension (icon handler)"
33 #define COM_DESCRIPTION_CONTEXT_MENU L"WinBtrfs shell extension (context menu)"
34 #define COM_DESCRIPTION_PROP_SHEET L"WinBtrfs shell extension (property sheet)"
35 #define COM_DESCRIPTION_VOL_PROP_SHEET L"WinBtrfs shell extension (volume property sheet)"
36 #define ICON_OVERLAY_NAME L"WinBtrfs"
38 typedef enum _PROCESS_DPI_AWARENESS
{
40 PROCESS_SYSTEM_DPI_AWARE
,
41 PROCESS_PER_MONITOR_DPI_AWARE
42 } PROCESS_DPI_AWARENESS
;
44 typedef ULONG (WINAPI
*_RtlNtStatusToDosError
)(NTSTATUS Status
);
45 typedef HRESULT (WINAPI
*_SetProcessDpiAwareness
)(PROCESS_DPI_AWARENESS value
);
50 void set_dpi_aware() {
51 _SetProcessDpiAwareness SetProcessDpiAwareness
;
52 HMODULE shcore
= LoadLibraryW(L
"shcore.dll");
57 SetProcessDpiAwareness
= (_SetProcessDpiAwareness
)GetProcAddress(shcore
, "SetProcessDpiAwareness");
59 if (!SetProcessDpiAwareness
)
62 SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE
);
65 void format_size(uint64_t size
, wstring
& s
, bool show_bytes
) {
66 wstring t
, bytes
, kb
, nb
;
71 WCHAR dec
[2], thou
[4], grouping
[64], *c
;
77 nb
= to_wstring(size
);
79 swprintf(buffer
, L
"%I64d", size
);
83 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_STHOUSAND
, thou
, sizeof(thou
) / sizeof(WCHAR
));
85 dec
[0] = '.'; dec
[1] = 0; // not used, but silences gcc warning
89 fmt
.lpDecimalSep
= dec
;
90 fmt
.lpThousandSep
= thou
;
91 fmt
.NegativeOrder
= 0;
93 // Grouping code copied from dlls/shlwapi/string.c in Wine - thank you
96 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_SGROUPING
, grouping
, sizeof(grouping
) / sizeof(WCHAR
));
100 if (*c
>= '0' && *c
< '9') {
102 fmt
.Grouping
+= *c
- '0';
108 if (fmt
.Grouping
% 10 == 0)
113 GetNumberFormatW(LOCALE_USER_DEFAULT
, 0, nb
.c_str(), &fmt
, nb2
, sizeof(nb2
) / sizeof(WCHAR
));
116 if (!load_string(module
, size
== 1 ? IDS_SIZE_BYTE
: IDS_SIZE_BYTES
, t
))
117 throw last_error(GetLastError());
119 wstring_sprintf(s
, t
, nb2
);
124 if (!load_string(module
, IDS_SIZE_BYTES
, t
))
125 throw last_error(GetLastError());
127 wstring_sprintf(bytes
, t
, nb2
);
130 if (size
>= 1152921504606846976) {
132 f
= (float)size
/ 1152921504606846976.0f
;
133 } else if (size
>= 1125899906842624) {
135 f
= (float)size
/ 1125899906842624.0f
;
136 } else if (size
>= 1099511627776) {
138 f
= (float)size
/ 1099511627776.0f
;
139 } else if (size
>= 1073741824) {
141 f
= (float)size
/ 1073741824.0f
;
142 } else if (size
>= 1048576) {
144 f
= (float)size
/ 1048576.0f
;
147 f
= (float)size
/ 1024.0f
;
150 if (!load_string(module
, sr
, t
))
151 throw last_error(GetLastError());
154 wstring_sprintf(kb
, t
, f
);
156 if (!load_string(module
, IDS_SIZE_LARGE
, t
))
157 throw last_error(GetLastError());
159 wstring_sprintf(s
, t
, kb
.c_str(), bytes
.c_str());
161 wstring_sprintf(s
, t
, f
);
164 wstring
format_message(ULONG last_error
) {
168 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
, nullptr,
169 last_error
, 0, (WCHAR
*)&buf
, 0, nullptr) == 0) {
170 return L
"(error retrieving message)";
177 // remove trailing newline
178 while (s
.length() > 0 && (s
.substr(s
.length() - 1, 1) == L
"\r" || s
.substr(s
.length() - 1, 1) == L
"\n"))
179 s
= s
.substr(0, s
.length() - 1);
184 wstring
format_ntstatus(NTSTATUS Status
) {
185 _RtlNtStatusToDosError RtlNtStatusToDosError
;
187 HMODULE ntdll
= LoadLibraryW(L
"ntdll.dll");
190 return L
"(error loading ntdll.dll)";
192 RtlNtStatusToDosError
= (_RtlNtStatusToDosError
)GetProcAddress(ntdll
, "RtlNtStatusToDosError");
194 if (!RtlNtStatusToDosError
) {
196 return L
"(error loading RtlNtStatusToDosError)";
199 s
= format_message(RtlNtStatusToDosError(Status
));
206 bool load_string(HMODULE module
, UINT id
, wstring
& s
) {
208 LPWSTR retstr
= nullptr;
210 len
= LoadStringW(module
, id
, (LPWSTR
)&retstr
, 0);
215 s
= wstring(retstr
, len
);
221 #pragma warning(push)
222 #pragma warning(disable: 4996)
225 void wstring_sprintf(wstring
& s
, wstring fmt
, ...) {
230 len
= _vsnwprintf(nullptr, 0, fmt
.c_str(), args
);
236 _vsnwprintf((wchar_t*)s
.c_str(), len
, fmt
.c_str(), args
);
246 extern "C" STDAPI
DllCanUnloadNow(void) {
247 return objs_loaded
== 0 ? S_OK
: S_FALSE
;
250 extern "C" STDAPI
DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
* ppv
) {
251 if (rclsid
== CLSID_ShellBtrfsIconHandler
) {
252 Factory
* fact
= new Factory
;
254 return E_OUTOFMEMORY
;
256 fact
->type
= FactoryIconHandler
;
258 return fact
->QueryInterface(riid
, ppv
);
260 } else if (rclsid
== CLSID_ShellBtrfsContextMenu
) {
261 Factory
* fact
= new Factory
;
263 return E_OUTOFMEMORY
;
265 fact
->type
= FactoryContextMenu
;
267 return fact
->QueryInterface(riid
, ppv
);
269 } else if (rclsid
== CLSID_ShellBtrfsPropSheet
) {
270 Factory
* fact
= new Factory
;
272 return E_OUTOFMEMORY
;
274 fact
->type
= FactoryPropSheet
;
276 return fact
->QueryInterface(riid
, ppv
);
278 } else if (rclsid
== CLSID_ShellBtrfsVolPropSheet
) {
279 Factory
* fact
= new Factory
;
281 return E_OUTOFMEMORY
;
283 fact
->type
= FactoryVolPropSheet
;
285 return fact
->QueryInterface(riid
, ppv
);
289 return CLASS_E_CLASSNOTAVAILABLE
;
292 static void write_reg_key(HKEY root
, const wstring
& keyname
, const WCHAR
* val
, const wstring
& data
) {
297 l
= RegCreateKeyExW(root
, keyname
.c_str(), 0, nullptr, 0, KEY_ALL_ACCESS
, nullptr, &hk
, &dispos
);
298 if (l
!= ERROR_SUCCESS
)
299 throw string_error(IDS_REGCREATEKEY_FAILED
, l
);
301 l
= RegSetValueExW(hk
, val
, 0, REG_SZ
, (const BYTE
*)data
.c_str(), (DWORD
)((data
.length() + 1) * sizeof(WCHAR
)));
302 if (l
!= ERROR_SUCCESS
)
303 throw string_error(IDS_REGSETVALUEEX_FAILED
, l
);
306 if (l
!= ERROR_SUCCESS
)
307 throw string_error(IDS_REGCLOSEKEY_FAILED
, l
);
310 static void register_clsid(const GUID clsid
, const WCHAR
* description
) {
312 wstring inproc
, progid
, clsidkeyname
;
313 WCHAR dllpath
[MAX_PATH
];
315 StringFromCLSID(clsid
, &clsidstring
);
319 inproc
= L
"CLSID\\"s
+ clsidstring
+ L
"\\InprocServer32"s
;
320 progid
= L
"CLSID\\"s
+ clsidstring
+ L
"\\ProgId"s
;
321 clsidkeyname
= L
"CLSID\\"s
+ clsidstring
;
323 inproc
= wstring(L
"CLSID\\") + clsidstring
+ wstring(L
"\\InprocServer32");
324 progid
= wstring(L
"CLSID\\") + clsidstring
+ wstring(L
"\\ProgId");
325 clsidkeyname
= wstring(L
"CLSID\\") + clsidstring
;
328 write_reg_key(HKEY_CLASSES_ROOT
, clsidkeyname
, nullptr, description
);
330 GetModuleFileNameW(module
, dllpath
, sizeof(dllpath
));
332 write_reg_key(HKEY_CLASSES_ROOT
, inproc
, nullptr, dllpath
);
334 write_reg_key(HKEY_CLASSES_ROOT
, inproc
, L
"ThreadingModel", L
"Apartment");
336 CoTaskMemFree(clsidstring
);
340 CoTaskMemFree(clsidstring
);
343 // implementation of RegDeleteTreeW, only available from Vista on
344 static void reg_delete_tree(HKEY hkey
, const wstring
& keyname
) {
348 ret
= RegOpenKeyExW(hkey
, keyname
.c_str(), 0, KEY_READ
, &k
);
350 if (ret
!= ERROR_SUCCESS
)
351 throw last_error(ret
);
357 ret
= RegQueryInfoKeyW(k
, nullptr, nullptr, nullptr, nullptr, &bufsize
, nullptr,
358 nullptr, nullptr, nullptr, nullptr, nullptr);
359 if (ret
!= ERROR_SUCCESS
)
360 throw last_error(ret
);
363 buf
= new WCHAR
[bufsize
];
367 ULONG size
= bufsize
;
369 ret
= RegEnumKeyExW(k
, 0, buf
, &size
, nullptr, nullptr, nullptr, nullptr);
371 if (ret
== ERROR_NO_MORE_ITEMS
)
373 else if (ret
!= ERROR_SUCCESS
)
374 throw last_error(ret
);
376 reg_delete_tree(k
, buf
);
379 ret
= RegDeleteKeyW(hkey
, keyname
.c_str());
380 if (ret
!= ERROR_SUCCESS
)
381 throw last_error(ret
);
396 static void unregister_clsid(const GUID clsid
) {
399 StringFromCLSID(clsid
, &clsidstring
);
403 reg_delete_tree(HKEY_CLASSES_ROOT
, L
"CLSID\\"s
+ clsidstring
);
405 wstring path
= wstring(L
"CLSID\\") + clsidstring
;
406 reg_delete_tree(HKEY_CLASSES_ROOT
, path
);
409 CoTaskMemFree(clsidstring
);
413 CoTaskMemFree(clsidstring
);
416 static void reg_icon_overlay(const GUID clsid
, const wstring
& name
) {
419 StringFromCLSID(clsid
, &clsidstring
);
423 wstring path
= L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers\\"s
+ name
;
425 wstring path
= wstring(L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers\\") + name
;
428 write_reg_key(HKEY_LOCAL_MACHINE
, path
, nullptr, clsidstring
);
430 CoTaskMemFree(clsidstring
);
434 CoTaskMemFree(clsidstring
);
437 static void unreg_icon_overlay(const wstring
& name
) {
439 reg_delete_tree(HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers\\"s
+ name
);
441 wstring path
= wstring(L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers\\") + name
;
442 reg_delete_tree(HKEY_LOCAL_MACHINE
, path
);
446 static void reg_context_menu_handler(const GUID clsid
, const wstring
& filetype
, const wstring
& name
) {
449 StringFromCLSID(clsid
, &clsidstring
);
453 wstring path
= filetype
+ L
"\\ShellEx\\ContextMenuHandlers\\"s
+ name
;
455 wstring path
= filetype
+ wstring(L
"\\ShellEx\\ContextMenuHandlers\\") + name
;
458 write_reg_key(HKEY_CLASSES_ROOT
, path
, nullptr, clsidstring
);
460 CoTaskMemFree(clsidstring
);
465 static void unreg_context_menu_handler(const wstring
& filetype
, const wstring
& name
) {
467 reg_delete_tree(HKEY_CLASSES_ROOT
, filetype
+ L
"\\ShellEx\\ContextMenuHandlers\\"s
+ name
);
469 wstring path
= filetype
+ wstring(L
"\\ShellEx\\ContextMenuHandlers\\") + name
;
470 reg_delete_tree(HKEY_CLASSES_ROOT
, path
);
474 static void reg_prop_sheet_handler(const GUID clsid
, const wstring
& filetype
, const wstring
& name
) {
477 StringFromCLSID(clsid
, &clsidstring
);
481 wstring path
= filetype
+ L
"\\ShellEx\\PropertySheetHandlers\\"s
+ name
;
483 wstring path
= filetype
+ wstring(L
"\\ShellEx\\PropertySheetHandlers\\") + name
;
486 write_reg_key(HKEY_CLASSES_ROOT
, path
, nullptr, clsidstring
);
488 CoTaskMemFree(clsidstring
);
493 static void unreg_prop_sheet_handler(const wstring
& filetype
, const wstring
& name
) {
495 reg_delete_tree(HKEY_CLASSES_ROOT
, filetype
+ L
"\\ShellEx\\PropertySheetHandlers\\"s
+ name
);
497 wstring path
= filetype
+ wstring(L
"\\ShellEx\\PropertySheetHandlers\\") + name
;
498 reg_delete_tree(HKEY_CLASSES_ROOT
, path
);
502 extern "C" STDAPI
DllRegisterServer(void) {
504 register_clsid(CLSID_ShellBtrfsIconHandler
, COM_DESCRIPTION_ICON_HANDLER
);
505 register_clsid(CLSID_ShellBtrfsContextMenu
, COM_DESCRIPTION_CONTEXT_MENU
);
506 register_clsid(CLSID_ShellBtrfsPropSheet
, COM_DESCRIPTION_PROP_SHEET
);
507 register_clsid(CLSID_ShellBtrfsVolPropSheet
, COM_DESCRIPTION_VOL_PROP_SHEET
);
509 reg_icon_overlay(CLSID_ShellBtrfsIconHandler
, ICON_OVERLAY_NAME
);
511 reg_context_menu_handler(CLSID_ShellBtrfsContextMenu
, L
"Directory\\Background", ICON_OVERLAY_NAME
);
512 reg_context_menu_handler(CLSID_ShellBtrfsContextMenu
, L
"Folder", ICON_OVERLAY_NAME
);
514 reg_prop_sheet_handler(CLSID_ShellBtrfsPropSheet
, L
"Folder", ICON_OVERLAY_NAME
);
515 reg_prop_sheet_handler(CLSID_ShellBtrfsPropSheet
, L
"*", ICON_OVERLAY_NAME
);
516 reg_prop_sheet_handler(CLSID_ShellBtrfsVolPropSheet
, L
"Drive", ICON_OVERLAY_NAME
);
517 } catch (const exception
& e
) {
518 error_message(nullptr, e
.what());
525 extern "C" STDAPI
DllUnregisterServer(void) {
527 unreg_prop_sheet_handler(L
"Folder", ICON_OVERLAY_NAME
);
528 unreg_prop_sheet_handler(L
"*", ICON_OVERLAY_NAME
);
529 unreg_prop_sheet_handler(L
"Drive", ICON_OVERLAY_NAME
);
530 unreg_context_menu_handler(L
"Folder", ICON_OVERLAY_NAME
);
531 unreg_context_menu_handler(L
"Directory\\Background", ICON_OVERLAY_NAME
);
532 unreg_icon_overlay(ICON_OVERLAY_NAME
);
534 unregister_clsid(CLSID_ShellBtrfsVolPropSheet
);
535 unregister_clsid(CLSID_ShellBtrfsPropSheet
);
536 unregister_clsid(CLSID_ShellBtrfsContextMenu
);
537 unregister_clsid(CLSID_ShellBtrfsIconHandler
);
538 } catch (const exception
& e
) {
539 error_message(nullptr, e
.what());
546 extern "C" STDAPI
DllInstall(BOOL bInstall
, LPCWSTR pszCmdLine
) {
548 return DllRegisterServer();
550 return DllUnregisterServer();
553 extern "C" BOOL APIENTRY
DllMain(HANDLE hModule
, DWORD dwReason
, void* lpReserved
) {
554 if (dwReason
== DLL_PROCESS_ATTACH
)
555 module
= (HMODULE
)hModule
;
560 static void create_subvol(const wstring
& fn
) {
561 size_t found
= fn
.rfind(L
"\\");
564 btrfs_create_subvol
* bcs
;
565 IO_STATUS_BLOCK iosb
;
567 if (found
== wstring::npos
) {
571 path
= fn
.substr(0, found
);
572 file
= fn
.substr(found
+ 1);
576 h
= CreateFileW(path
.c_str(), FILE_ADD_SUBDIRECTORY
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, nullptr, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, nullptr);
578 if (h
== INVALID_HANDLE_VALUE
)
581 size_t bcslen
= offsetof(btrfs_create_subvol
, name
[0]) + (file
.length() * sizeof(WCHAR
));
582 bcs
= (btrfs_create_subvol
*)malloc(bcslen
);
584 bcs
->readonly
= false;
586 bcs
->namelen
= (uint16_t)(file
.length() * sizeof(WCHAR
));
587 memcpy(bcs
->name
, file
.c_str(), bcs
->namelen
);
589 NtFsControlFile(h
, nullptr, nullptr, nullptr, &iosb
, FSCTL_BTRFS_CREATE_SUBVOL
, bcs
, (ULONG
)bcslen
, nullptr, 0);
592 extern "C" void CALLBACK
CreateSubvolW(HWND hwnd
, HINSTANCE hinst
, LPWSTR lpszCmdLine
, int nCmdShow
) {
593 vector
<wstring
> args
;
595 command_line_to_args(lpszCmdLine
, args
);
597 if (args
.size() >= 1)
598 create_subvol(args
[0]);
601 static void create_snapshot2(const wstring
& source
, const wstring
& fn
) {
602 size_t found
= fn
.rfind(L
"\\");
605 btrfs_create_snapshot
* bcs
;
606 IO_STATUS_BLOCK iosb
;
608 if (found
== wstring::npos
) {
612 path
= fn
.substr(0, found
);
613 file
= fn
.substr(found
+ 1);
617 src
= CreateFileW(source
.c_str(), FILE_TRAVERSE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, nullptr, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, nullptr);
618 if (src
== INVALID_HANDLE_VALUE
)
621 h
= CreateFileW(path
.c_str(), FILE_ADD_SUBDIRECTORY
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, nullptr, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, nullptr);
623 if (h
== INVALID_HANDLE_VALUE
)
626 size_t bcslen
= offsetof(btrfs_create_snapshot
, name
[0]) + (file
.length() * sizeof(WCHAR
));
627 bcs
= (btrfs_create_snapshot
*)malloc(bcslen
);
629 bcs
->readonly
= false;
631 bcs
->namelen
= (uint16_t)(file
.length() * sizeof(WCHAR
));
632 memcpy(bcs
->name
, file
.c_str(), bcs
->namelen
);
635 NtFsControlFile(h
, nullptr, nullptr, nullptr, &iosb
, FSCTL_BTRFS_CREATE_SNAPSHOT
, bcs
, (ULONG
)bcslen
, nullptr, 0);
638 extern "C" void CALLBACK
CreateSnapshotW(HWND hwnd
, HINSTANCE hinst
, LPWSTR lpszCmdLine
, int nCmdShow
) {
639 vector
<wstring
> args
;
641 command_line_to_args(lpszCmdLine
, args
);
643 if (args
.size() >= 2)
644 create_snapshot2(args
[0], args
[1]);
647 void command_line_to_args(LPWSTR cmdline
, vector
<wstring
>& args
) {
653 l
= CommandLineToArgvW(cmdline
, &num_args
);
659 args
.reserve(num_args
);
661 for (unsigned int i
= 0; i
< (unsigned int)num_args
; i
++) {
662 args
.push_back(l
[i
]);
672 static string
utf16_to_utf8(const wstring_view
& utf16
) {
679 auto utf8len
= WideCharToMultiByte(CP_UTF8
, 0, utf16
.data(), static_cast<int>(utf16
.length()), nullptr, 0, nullptr, nullptr);
682 throw last_error(GetLastError());
684 buf
= (char*)malloc(utf8len
+ sizeof(char));
687 throw string_error(IDS_OUT_OF_MEMORY
);
689 if (WideCharToMultiByte(CP_UTF8
, 0, utf16
.data(), static_cast<int>(utf16
.length()), buf
, utf8len
, nullptr, nullptr) == 0) {
690 auto le
= GetLastError();
692 throw last_error(le
);
705 #pragma warning(push)
706 #pragma warning(disable: 4996)
709 string_error::string_error(int resno
, ...) {
714 if (!load_string(module
, resno
, fmt
))
715 throw runtime_error("LoadString failed."); // FIXME
717 va_start(args
, resno
);
718 len
= _vsnwprintf(nullptr, 0, fmt
.c_str(), args
);
724 _vsnwprintf((wchar_t*)s
.c_str(), len
, fmt
.c_str(), args
);
729 msg
= utf16_to_utf8(s
);
736 wstring
utf8_to_utf16(const string_view
& utf8
) {
743 auto utf16len
= MultiByteToWideChar(CP_UTF8
, 0, utf8
.data(), (int)utf8
.length(), nullptr, 0);
746 throw last_error(GetLastError());
748 buf
= (WCHAR
*)malloc((utf16len
+ 1) * sizeof(WCHAR
));
751 throw string_error(IDS_OUT_OF_MEMORY
);
753 if (MultiByteToWideChar(CP_UTF8
, 0, utf8
.data(), (int)utf8
.length(), buf
, utf16len
) == 0) {
754 auto le
= GetLastError();
756 throw last_error(le
);
768 last_error::last_error(DWORD errnum
) {
771 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
, nullptr,
772 errnum
, 0, (WCHAR
*)&buf
, 0, nullptr) == 0)
773 throw runtime_error("FormatMessage failed");
776 msg
= utf16_to_utf8(buf
);
785 void error_message(HWND hwnd
, const char* msg
) {
788 load_string(module
, IDS_ERROR
, title
);
790 auto wmsg
= utf8_to_utf16(msg
);
792 MessageBoxW(hwnd
, wmsg
.c_str(), title
.c_str(), MB_ICONERROR
);
795 ntstatus_error::ntstatus_error(NTSTATUS Status
) : Status(Status
) {
796 _RtlNtStatusToDosError RtlNtStatusToDosError
;
797 HMODULE ntdll
= LoadLibraryW(L
"ntdll.dll");
801 throw runtime_error("Error loading ntdll.dll.");
804 RtlNtStatusToDosError
= (_RtlNtStatusToDosError
)GetProcAddress(ntdll
, "RtlNtStatusToDosError");
806 if (!RtlNtStatusToDosError
)
807 throw runtime_error("Error loading RtlNtStatusToDosError in ntdll.dll.");
809 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
, nullptr,
810 RtlNtStatusToDosError(Status
), 0, (WCHAR
*)&buf
, 0, nullptr) == 0)
811 throw runtime_error("FormatMessage failed");
814 msg
= utf16_to_utf8(buf
);