1 /* ---------------------------------------------------------------------------------------------- */
3 /* Copyright(c) 2019 LoRd_MuldeR <mulder2@gmx.de> */
5 /* Permission is hereby granted, free of charge, to any person obtaining a copy of this software */
6 /* and associated documentation files (the "Software"), to deal in the Software without */
7 /* restriction, including without limitation the rights to use, copy, modify, merge, publish, */
8 /* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the */
9 /* Software is furnished to do so, subject to the following conditions: */
11 /* The above copyright notice and this permission notice shall be included in all copies or */
12 /* substantial portions of the Software. */
14 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING */
15 /* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
16 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, */
17 /* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
18 /* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
19 /* ---------------------------------------------------------------------------------------------- */
21 #define WIN32_LEAN_AND_MEAN 1
29 #define ENABLE_DEBUG_OUTPOUT 1
30 #define DEFAULT_TIMEOUT 30000U
31 #define DEFAULT_SOUND_LEVEL 1U
34 #define MUTEX_NAME L"{E19E5CE1-5EF2-4C10-843D-E79460920A4A}"
35 #define CLASS_NAME L"{6D6CB8E6-BFEE-40A1-A6B2-2FF34C43F3F8}"
36 #define TIMER_ID 0x5281CC36
37 #define ID_NOTIFYICON 0x8EF73CE1
38 #define WM_NOTIFYICON (WM_APP+101U)
39 #define MENU1_ID 0x1A5C
40 #define MENU2_ID 0x6810
41 #define MENU3_ID 0x46C3
42 #define MENU4_ID 0x38D6
45 #if defined(ENABLE_DEBUG_OUTPOUT) && ENABLE_DEBUG_OUTPOUT
46 #define PRINT(TEXT) do \
49 OutputDebugStringA("ClearClipboard -- " TEXT "\n"); \
53 #define PRINT(TEXT) __noop((X))
57 #define PLAY_SOUND(X) do \
59 if(g_sound_enabled >= (X)) \
60 play_sound_effect(); \
65 #define ERROR_EXIT(X) do \
67 result = (X); goto clean_up; \
71 // Wide string wrapper macro
72 #define _WTEXT_(X) L##X
73 #define WTEXT(X) _WTEXT_(X)
76 static UINT g_taskbar_created
= 0U;
77 static HICON g_app_icon
= NULL
;
78 static HMENU g_context_menu
= NULL
;
79 static UINT g_timeout
= DEFAULT_TIMEOUT
;
80 static UINT g_sound_enabled
= DEFAULT_SOUND_LEVEL
;
81 static BOOL g_suspended
= FALSE
;
82 static ULONGLONG g_tickCount
= 0U;
84 static BOOL g_debug
= FALSE
;
86 static const BOOL g_debug
= TRUE
;
89 // Forward declaration
90 static LRESULT CALLBACK
my_wnd_proc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
);
91 static BOOL
clear_clipboard(void);
92 static UINT
parse_arguments(const WCHAR
*const command_line
);
93 static BOOL
update_autorun_entry(const BOOL remove
);
94 static BOOL
create_shell_notify_icon(const HWND hwnd
, const BOOL remove
);
95 static BOOL
update_shell_notify_icon(const HWND hwnd
, const BOOL suspended
);
96 static BOOL
about_screen(const BOOL first_run
);
97 static BOOL
show_disclaimer(void);
98 static BOOL
play_sound_effect(void);
99 static WCHAR
*get_configuration_path(void);
100 static WCHAR
*get_executable_path(void);
101 static UINT
get_config_value(const WCHAR
*const path
, const WCHAR
*const name
, const UINT default_value
, const UINT min_value
, const UINT max_value
);
102 static DWORD
reg_read_value(const HKEY root
, const WCHAR
*const path
, const WCHAR
*const name
, const DWORD default_value
);
103 static WCHAR
*reg_read_string(const HKEY root
, const WCHAR
*const path
, const WCHAR
*const name
);
104 static BOOL
reg_write_value(const HKEY root
, const WCHAR
*const path
, const WCHAR
*const name
, const DWORD value
);
105 static BOOL
reg_write_string(const HKEY root
, const WCHAR
*const path
, const WCHAR
*const name
, const WCHAR
*const text
);
106 static BOOL
reg_delete_value(const HKEY root
, const WCHAR
*const path
, const WCHAR
*const name
);
108 // ==========================================================================
109 // Entry point function
110 // ==========================================================================
114 extern IMAGE_DOS_HEADER __ImageBase
;
115 int WINAPI
wWinMain(HINSTANCE hInstance
, HINSTANCE hPrevInstance
, LPWSTR lpCmdLine
, int nCmdShow
);
119 const int exit_code
= wWinMain((HINSTANCE
)&__ImageBase
, NULL
, GetCommandLineW(), SW_SHOWDEFAULT
);
120 ExitProcess((UINT
)exit_code
);
126 // ==========================================================================
128 // ==========================================================================
130 int WINAPI
wWinMain(HINSTANCE hInstance
, HINSTANCE hPrevInstance
, LPWSTR lpCmdLine
, int nCmdShow
)
132 int result
= 0, status
= -1;
136 BOOL have_listener
= FALSE
, have_timer
= FALSE
;
137 const WCHAR
*config_path
= NULL
;
141 // Initialize variables
142 SecureZeroMemory(&wcl
, sizeof(WNDCLASSW
));
143 SecureZeroMemory(&msg
, sizeof(MSG
));
145 // Parse CLI arguments
146 mode
= parse_arguments(lpCmdLine
);
147 PRINT("ClearClipboard v" VERSION_STR
" [" __DATE__
"]");
152 MessageBoxW(NULL
, L
"Invalid command-line argument(s). Exiting!", L
"ClearClipboard v" WTEXT(VERSION_STR
), MB_ICONERROR
| MB_TOPMOST
);
156 // Close running instances, if it was requested
157 if((mode
== 1U) || (mode
== 2U))
159 PRINT("closing all running instances...");
160 while(hwnd
= FindWindowExW(NULL
, hwnd
, CLASS_NAME
, NULL
))
162 PRINT("sending WM_CLOSE");
163 SendMessageW(hwnd
, WM_CLOSE
, 0U, 0U);
172 // Add or remove autorun entry, if it was requested
173 if((mode
== 3U) || (mode
== 4U))
175 const BOOL success
= update_autorun_entry(mode
> 3U);
177 return success
? 0 : 1;
180 // Lock single instance mutex
181 if(mutex
= CreateMutexW(NULL
, FALSE
, MUTEX_NAME
))
183 const DWORD ret
= WaitForSingleObject(mutex
, (mode
> 1U) ? 5000U : 250U);
184 if((ret
!= WAIT_OBJECT_0
) && (ret
!= WAIT_ABANDONED
))
186 PRINT("already running, exiting!");
191 // Show disclaimer message
192 if(!show_disclaimer())
198 PRINT("starting up...");
200 // Register "TaskbarCreated" window message
201 if(g_taskbar_created
= RegisterWindowMessageW(L
"TaskbarCreated"))
203 ChangeWindowMessageFilter(g_taskbar_created
, MSGFLT_ADD
);
206 // Read config from INI file
207 if(config_path
= get_configuration_path())
209 g_timeout
= get_config_value(config_path
, L
"Timeout", DEFAULT_TIMEOUT
, 1000U, USER_TIMER_MAXIMUM
);
210 g_sound_enabled
= get_config_value(config_path
, L
"SoundEnabled", DEFAULT_SOUND_LEVEL
, 0U, 2U);
211 LocalFree((HLOCAL
)config_path
);
214 // Load icon resources
215 if(!(g_app_icon
= LoadIconW(hInstance
, MAKEINTRESOURCEW(101))))
217 PRINT("failed to load icon resource!");
221 // Create context menu
222 if(g_context_menu
= CreatePopupMenu())
224 AppendMenuW(g_context_menu
, MF_STRING
, MENU1_ID
, L
"ClearClipboard v" WTEXT(VERSION_STR
));
225 AppendMenuW(g_context_menu
, MF_SEPARATOR
, 0, NULL
);
226 AppendMenuW(g_context_menu
, MF_STRING
, MENU2_ID
, L
"Clear now!");
227 AppendMenuW(g_context_menu
, MF_STRING
, MENU3_ID
, L
"Suspend auto-clearing");
228 AppendMenuW(g_context_menu
, MF_SEPARATOR
, 0, NULL
);
229 AppendMenuW(g_context_menu
, MF_STRING
, MENU4_ID
, L
"Quit");
230 SetMenuDefaultItem(g_context_menu
, MENU1_ID
, FALSE
);
234 PRINT("failed to create context menu!");
238 // Register window class
239 wcl
.lpfnWndProc
= my_wnd_proc
;
240 wcl
.hInstance
= hInstance
;
241 wcl
.hbrBackground
= (HBRUSH
)(COLOR_BACKGROUND
);
242 wcl
.lpszClassName
= CLASS_NAME
;
243 if(!RegisterClassW(&wcl
))
245 PRINT("failed to register window class!");
249 // Create the message-only window
250 if(!(hwnd
= CreateWindowExW(0L, CLASS_NAME
, L
"ClearClipboard window", WS_OVERLAPPEDWINDOW
/*|WS_VISIBLE*/, 0, 0, 0, 0, NULL
, 0, hInstance
, NULL
)))
252 PRINT("failed to create the window!");
256 // Create notification icon
257 create_shell_notify_icon(hwnd
, FALSE
);
258 update_shell_notify_icon(hwnd
, FALSE
);
260 // Add clipboard listener
261 if(!(have_listener
= AddClipboardFormatListener(hwnd
)))
263 PRINT("failed to install clipboard listener!");
267 // Set up window timer
268 g_tickCount
= GetTickCount64();
269 if(!(have_timer
= SetTimer(hwnd
, TIMER_ID
, min(max(g_timeout
/ 50U, USER_TIMER_MINIMUM
), USER_TIMER_MAXIMUM
), NULL
)))
271 PRINT("failed to install the window timer!");
275 PRINT("clipboard monitoring started.");
278 while(status
= GetMessageW(&msg
, NULL
, 0, 0) != 0)
282 PRINT("failed to fetch next message!");
285 TranslateMessage(&msg
);
286 DispatchMessage(&msg
);
289 PRINT("shutting down now...");
294 if(hwnd
&& have_timer
)
296 KillTimer(hwnd
, TIMER_ID
);
299 // Delete notification icon
302 create_shell_notify_icon(hwnd
, TRUE
);
305 // Remove clipboard listener
306 if(hwnd
&& have_listener
)
308 RemoveClipboardFormatListener(hwnd
);
311 // Free icon resource
314 DestroyMenu(g_context_menu
);
317 // Free icon resource
320 DestroyIcon(g_app_icon
);
333 // ==========================================================================
335 // ==========================================================================
337 static LRESULT CALLBACK
my_wnd_proc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
344 case WM_CLIPBOARDUPDATE
:
345 PRINT("WM_CLIPBOARDUPDATE");
346 g_tickCount
= GetTickCount64();
351 const ULONGLONG tickCount
= GetTickCount64();
352 if((tickCount
> g_tickCount
) && ((tickCount
- g_tickCount
) > g_timeout
))
356 if(clear_clipboard())
358 g_tickCount
= tickCount
;
365 g_tickCount
= tickCount
;
371 switch(LOWORD(lParam
))
374 PRINT("WM_NOTIFYICON --> WM_CONTEXTMENU");
377 SetForegroundWindow(hWnd
);
378 TrackPopupMenu(g_context_menu
, TPM_BOTTOMALIGN
| TPM_LEFTALIGN
, LOWORD(wParam
), HIWORD(wParam
), 0, hWnd
, NULL
);
381 case WM_LBUTTONDBLCLK
:
382 PRINT("WM_LBUTTONDBLCLK");
383 if(clear_clipboard())
385 g_tickCount
= GetTickCount64();
393 if(HIWORD(wParam
) == 0)
395 switch(LOWORD(wParam
))
398 PRINT("menu item #1 triggered");
402 PRINT("menu item #2 triggered");
403 if(clear_clipboard())
405 g_tickCount
= GetTickCount64();
410 PRINT("menu item #3 triggered");
411 g_suspended
= !g_suspended
;
412 CheckMenuItem(g_context_menu
, MENU3_ID
, g_suspended
? MF_CHECKED
: MF_UNCHECKED
);
413 update_shell_notify_icon(hWnd
, g_suspended
);
416 g_tickCount
= GetTickCount64();
420 PRINT("menu item #4 triggered");
421 PostMessageW(hWnd
, WM_CLOSE
, 0, 0);
427 if(message
== g_taskbar_created
)
429 PRINT("TaskbarCreated");
430 create_shell_notify_icon(hWnd
, FALSE
);
431 update_shell_notify_icon(hWnd
, g_suspended
);
435 return DefWindowProc(hWnd
, message
, wParam
, lParam
);
442 // ==========================================================================
444 // ==========================================================================
446 static BOOL
clear_clipboard(void)
449 BOOL success
= FALSE
;
451 PRINT("clearing clipboard...");
453 for(retry
= 0; retry
< 32; ++retry
)
460 if(OpenClipboard(NULL
))
462 success
= EmptyClipboard();
467 break; /*successful*/
477 PRINT("failed to clean clipboard!");
483 // ==========================================================================
484 // Process CLI arguments
485 // ==========================================================================
487 static UINT
parse_arguments(const WCHAR
*const command_line
)
493 argv
= CommandLineToArgvW(command_line
, &argc
);
496 for(i
= 1; i
< argc
; ++i
)
498 const WCHAR
*value
= argv
[i
];
499 while((*value
) && (*value
<= 0x20))
505 if(!lstrcmpiW(value
, L
"--close"))
509 else if(!lstrcmpiW(value
, L
"--restart"))
513 else if(!lstrcmpiW(value
, L
"--install"))
517 else if(!lstrcmpiW(value
, L
"--uninstall"))
522 else if(!lstrcmpiW(value
, L
"--debug"))
527 else if(!lstrcmpiW(value
, L
"--slunk"))
529 ShellExecuteW(NULL
, NULL
, L
"https://youtu.be/n4bply6Ibqw", NULL
, NULL
, SW_SHOW
);
534 break; /*bad argument*/
538 LocalFree((HLOCAL
)argv
);
544 // ==========================================================================
546 // ==========================================================================
548 static BOOL
update_autorun_entry(const BOOL remove
)
550 static const WCHAR
*const REG_VALUE_NAME
= L
"com.muldersoft.clear_clipboard";
551 static const WCHAR
*const REG_VALUE_PATH
= L
"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
553 BOOL success
= FALSE
;
557 const WCHAR
*const executable_path
= get_executable_path();
560 WCHAR
*const buffer
= (WCHAR
*) LocalAlloc(LPTR
, (lstrlenW(executable_path
) + 3U) * sizeof(WCHAR
));
563 PRINT("adding autorun entry to registry...");
564 lstrcpyW(buffer
, L
"\"");
565 lstrcatW(buffer
, executable_path
);
566 lstrcatW(buffer
, L
"\"");
567 if(reg_write_string(HKEY_CURRENT_USER
, REG_VALUE_PATH
, REG_VALUE_NAME
, buffer
))
574 PRINT("failed to add autorun entry to registry!");
576 LocalFree((HLOCAL
)buffer
);
580 PRINT("failed to allocate string buffer!");
582 LocalFree((HLOCAL
)executable_path
);
586 PRINT("failed to determine executable path!");
591 PRINT("removing autorun entry from registry...");
592 if(reg_delete_value(HKEY_CURRENT_USER
, REG_VALUE_PATH
, REG_VALUE_NAME
))
599 PRINT("failed to remove autorun entry from registry!");
606 // ==========================================================================
607 // Shell notification icon
608 // ==========================================================================
610 static BOOL
create_shell_notify_icon(const HWND hwnd
, const BOOL remove
)
612 NOTIFYICONDATAW shell_icon_data
;
613 SecureZeroMemory(&shell_icon_data
, sizeof(NOTIFYICONDATAW
));
615 shell_icon_data
.cbSize
= sizeof(NOTIFYICONDATAW
);
616 shell_icon_data
.hWnd
= hwnd
;
617 shell_icon_data
.uID
= ID_NOTIFYICON
;
621 shell_icon_data
.hIcon
= g_app_icon
;
622 shell_icon_data
.uCallbackMessage
= WM_NOTIFYICON
;
623 shell_icon_data
.uFlags
= NIF_ICON
| NIF_MESSAGE
;
626 if(Shell_NotifyIconW(remove
? NIM_DELETE
: NIM_ADD
, &shell_icon_data
))
630 shell_icon_data
.uVersion
= NOTIFYICON_VERSION_4
;
631 Shell_NotifyIconW(NIM_SETVERSION
, &shell_icon_data
);
636 PRINT("failed to create/remove shell notification icon!");
643 static BOOL
update_shell_notify_icon(const HWND hwnd
, const BOOL suspended
)
645 NOTIFYICONDATAW shell_icon_data
;
646 SecureZeroMemory(&shell_icon_data
, sizeof(NOTIFYICONDATAW
));
648 shell_icon_data
.cbSize
= sizeof(NOTIFYICONDATAW
);
649 shell_icon_data
.hWnd
= hwnd
;
650 shell_icon_data
.uID
= ID_NOTIFYICON
;
651 lstrcpyW(shell_icon_data
.szTip
, L
"ClearClipboard v" WTEXT(VERSION_STR
));
654 lstrcatW(shell_icon_data
.szTip
, L
" - suspended");
656 shell_icon_data
.uFlags
= NIF_TIP
| NIF_SHOWTIP
;
658 if(!Shell_NotifyIconW(NIM_MODIFY
, &shell_icon_data
))
660 PRINT("failed to modify shell notification icon!");
667 // ==========================================================================
669 // ==========================================================================
671 static BOOL
about_screen(const BOOL first_run
)
673 const int resut
= MessageBoxW(
675 L
"ClearClipboard v" WTEXT(VERSION_STR
) L
" [" WTEXT(__DATE__
) L
"]\n"
676 L
"Copyright(\x24B8) 2019 LoRd_MuldeR <mulder2@gmx.de>\n\n"
677 L
"This software is released under the MIT License.\n"
678 L
"(https://opensource.org/licenses/MIT)\n\n"
679 L
"For news and updates please check the website at:\n"
680 L
"\x2022 http://muldersoft.com/\n"
681 L
"\x2022 https://github.com/lordmulder/ClearClipboard\n\n"
683 L
"The software is provided \"as is\", without warranty of any kind, express or implied, including"
684 L
"but not limited to the warranties of merchantability, fitness for a particular purpose and"
685 L
"noninfringement. In no event shall the authors or copyright holders be liable for any claim,"
686 L
"damages or other liability, whether in an action of contract, tort or otherwise, arising from,"
687 L
"out of or in connection with the software or the use or other dealings in the software.",
689 MB_ICONINFORMATION
| MB_TOPMOST
| (first_run
? MB_OKCANCEL
|MB_DEFBUTTON2
: MB_OK
)
692 return (resut
== IDOK
);
695 static BOOL
show_disclaimer(void)
697 static const DWORD REG_VALUE_DATA
= (((DWORD
)VERSION_MAJOR
) << 16) | (((DWORD
)VERSION_MINOR_HI
) << 8) | ((DWORD
)VERSION_MINOR_LO
);
698 static const WCHAR
*const REG_VALUE_NAME
= L
"DisclaimerAccepted";
699 static const WCHAR
*const REG_VALUE_PATH
= L
"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{7816D5D9-5D9D-4B3A-B5A8-DD7A7F4C44A3}";
701 if(reg_read_value(HKEY_CURRENT_USER
, REG_VALUE_PATH
, REG_VALUE_NAME
, 0U) != REG_VALUE_DATA
)
703 if(about_screen(TRUE
))
705 reg_write_value(HKEY_CURRENT_USER
, REG_VALUE_PATH
, REG_VALUE_NAME
, REG_VALUE_DATA
);
709 return FALSE
; /*rejected*/
716 // ==========================================================================
718 // ==========================================================================
720 static BOOL
play_sound_effect(void)
722 BOOL success
= FALSE
;
724 const WCHAR
*const sound_file
= reg_read_string(HKEY_CURRENT_USER
, L
"AppEvents\\Schemes\\Apps\\Explorer\\EmptyRecycleBin\\.Current", L
"");
727 if(sound_file
[0] && (GetFileAttributesW(sound_file
) != INVALID_FILE_ATTRIBUTES
))
729 success
= PlaySoundW(sound_file
, NULL
, SND_ASYNC
);
731 LocalFree((HLOCAL
)sound_file
);
736 success
= PlaySoundW(L
"SystemAsterisk", NULL
, SND_ALIAS
| SND_ASYNC
);
742 // ==========================================================================
743 // File path routines
744 // ==========================================================================
746 static WCHAR
*get_configuration_path(void)
748 static const WCHAR
*const DEFAULT_PATH
= L
"ClearClipboard.ini";
749 WCHAR
*buffer
= NULL
;
750 WCHAR
*const path
= get_executable_path();
754 const DWORD path_len
= lstrlenW(path
);
757 DWORD pos
, last_sep
= 0U;
758 for(pos
= 0U; pos
< path_len
; ++pos
)
760 if((path
[pos
] == L
'/') || (path
[pos
] == L
'\\') || (path
[pos
] == L
'.'))
767 const DWORD copy_len
= (path
[last_sep
] == '.') ? last_sep
: path_len
;
768 buffer
= (WCHAR
*) LocalAlloc(LPTR
, (5U + copy_len
) * sizeof(WCHAR
));
771 lstrcpynW(buffer
, path
, last_sep
+ 1U);
772 lstrcatW(buffer
, L
".ini");
776 LocalFree((HLOCAL
)path
);
781 buffer
= (WCHAR
*) LocalAlloc(LPTR
, (1U + lstrlenW(DEFAULT_PATH
)) * sizeof(WCHAR
));
784 lstrcpyW(buffer
, DEFAULT_PATH
);
791 static WCHAR
*get_executable_path(void)
795 WCHAR
*buffer
= (WCHAR
*) LocalAlloc(LPTR
, size
* sizeof(WCHAR
));
798 return NULL
; /*malloc failed*/
803 const DWORD result
= GetModuleFileNameW(NULL
, buffer
, size
);
804 if((result
> 0) && (result
< size
))
808 if((size
< MAXWORD
) && (result
>= size
))
810 LocalFree((HLOCAL
)buffer
);
812 if(!(buffer
= (WCHAR
*) LocalAlloc(LPTR
, size
* sizeof(WCHAR
))))
814 return NULL
; /*malloc failed*/
819 break; /*something else went wrong*/
823 LocalFree((HLOCAL
)buffer
);
827 // ==========================================================================
828 // Configuration routines
829 // ==========================================================================
831 static UINT
get_config_value(const WCHAR
*const path
, const WCHAR
*const name
, const UINT default_value
, const UINT min_value
, const UINT max_value
)
833 static const WCHAR
*const SECTION_NAME
= L
"ClearClipboard";
834 const UINT value
= GetPrivateProfileIntW(SECTION_NAME
, name
, default_value
, path
);
835 return max(min_value
, min(max_value
, value
));
838 // ==========================================================================
840 // ==========================================================================
842 static DWORD
reg_read_value(const HKEY root
, const WCHAR
*const path
, const WCHAR
*const name
, const DWORD default_value
)
845 DWORD result
= 0U, type
= REG_NONE
, size
= sizeof(DWORD
);
847 if(RegOpenKeyExW(root
, path
, 0U, KEY_READ
, &hkey
) != ERROR_SUCCESS
)
849 PRINT("failed to open registry key for reading!");
850 return default_value
;
853 if(RegQueryValueExW(hkey
, name
, NULL
, &type
, (BYTE
*)&result
, &size
) == ERROR_SUCCESS
)
855 if((type
== REG_DWORD
) || (type
== REG_DWORD_BIG_ENDIAN
))
863 PRINT("failed to read registry value!");
864 return default_value
;
867 static WCHAR
*reg_read_string(const HKEY root
, const WCHAR
*const path
, const WCHAR
*const name
)
872 if(RegOpenKeyExW(root
, path
, 0U, KEY_READ
, &hkey
) != ERROR_SUCCESS
)
874 PRINT("failed to open registry key for reading!");
878 for(capacity
= 4096U; capacity
<= 65536U; capacity
*= 2U)
880 WCHAR
*const buffer
= (WCHAR
*) LocalAlloc(LPTR
, capacity
);
883 DWORD type
= REG_NONE
, size
= capacity
;
884 const LSTATUS error
= RegQueryValueExW(hkey
, name
, NULL
, &type
, (BYTE
*)buffer
, &size
);
885 if((error
== ERROR_SUCCESS
) && ((type
== REG_SZ
) || (type
== REG_EXPAND_SZ
)))
890 LocalFree((HLOCAL
)buffer
);
891 if(error
!= ERROR_MORE_DATA
)
899 PRINT("failed to allocate buffer!");
905 PRINT("failed to read registry value!");
909 static BOOL
reg_write_value(const HKEY root
, const WCHAR
*const path
, const WCHAR
*const name
, const DWORD value
)
913 if(RegCreateKeyExW(root
, path
, 0U, NULL
, 0U, KEY_WRITE
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
915 PRINT("failed to open registry key for writing!");
919 if(RegSetValueExW(hkey
, name
, 0U, REG_DWORD
, (BYTE
*)&value
, sizeof(DWORD
)) != ERROR_SUCCESS
)
922 PRINT("failed to write registry value!");
930 static BOOL
reg_write_string(const HKEY root
, const WCHAR
*const path
, const WCHAR
*const name
, const WCHAR
*const text
)
934 if(RegCreateKeyExW(root
, path
, 0U, NULL
, 0U, KEY_WRITE
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
937 PRINT("failed to open registry key for writing!");
941 if(RegSetValueExW(hkey
, name
, 0U, REG_SZ
, (BYTE
*)&text
, (lstrlenW(text
) + 1U) * sizeof(WCHAR
)) != ERROR_SUCCESS
)
944 PRINT("failed to write registry value!");
952 static BOOL
reg_delete_value(const HKEY root
, const WCHAR
*const path
, const WCHAR
*const name
)
957 if((error
= RegOpenKeyExW(root
, path
, 0U, KEY_WRITE
, &hkey
)) != ERROR_SUCCESS
)
959 if(error
!= ERROR_FILE_NOT_FOUND
)
961 PRINT("failed to open registry key for writing!");
967 if((error
= RegDeleteValueW(hkey
, name
)) != ERROR_SUCCESS
)
969 if(error
!= ERROR_FILE_NOT_FOUND
)
972 PRINT("failed to write registry value!");