https://git.reactos.org/?p=reactos.git;a=commitdiff;h=7f766e94d4087b136f8a14...
commit 7f766e94d4087b136f8a142863a395cafd235868 Author: Katayama Hirofumi MZ katayama.hirofumi.mz@gmail.com AuthorDate: Sat Feb 29 08:13:52 2020 +0900 Commit: GitHub noreply@github.com CommitDate: Sat Feb 29 08:13:52 2020 +0900
[SHELL32_APITEST] Support multi-process of SHChangeNotify testcase (#2399)
The shell32!SHChangeNotify function must be tested on multiple processes. CORE-13950 --- modules/rostests/apitests/shell32/CMakeLists.txt | 6 + .../rostests/apitests/shell32/SHChangeNotify.cpp | 304 ++++----------------- modules/rostests/apitests/shell32/shell-notify.cpp | 256 +++++++++++++++++ 3 files changed, 317 insertions(+), 249 deletions(-)
diff --git a/modules/rostests/apitests/shell32/CMakeLists.txt b/modules/rostests/apitests/shell32/CMakeLists.txt index aab3e8bcfb8..1ef8819746c 100644 --- a/modules/rostests/apitests/shell32/CMakeLists.txt +++ b/modules/rostests/apitests/shell32/CMakeLists.txt @@ -46,3 +46,9 @@ set_module_type(shell32_apitest win32cui) add_importlibs(shell32_apitest user32 gdi32 shell32 ole32 oleaut32 advapi32 shlwapi msvcrt kernel32 ntdll) add_pch(shell32_apitest shelltest.h SOURCE) add_rostests_file(TARGET shell32_apitest) + +# shell-notify.exe +add_executable(shell-notify shell-notify.cpp) +set_module_type(shell-notify win32gui UNICODE) +add_importlibs(shell-notify msvcrt kernel32 user32 shell32 shlwapi ole32) +add_rostests_file(TARGET shell-notify SUBDIR testdata) diff --git a/modules/rostests/apitests/shell32/SHChangeNotify.cpp b/modules/rostests/apitests/shell32/SHChangeNotify.cpp index c4257b993ec..372696d24ec 100644 --- a/modules/rostests/apitests/shell32/SHChangeNotify.cpp +++ b/modules/rostests/apitests/shell32/SHChangeNotify.cpp @@ -10,8 +10,8 @@ #include <stdio.h>
#define WM_SHELL_NOTIFY (WM_USER + 100) - -#define ID_TEST 1000 +#define WM_GET_NOTIFY_FLAGS (WM_USER + 101) +#define WM_CLEAR_FLAGS (WM_USER + 102)
static WCHAR s_dir1[MAX_PATH]; // "%TEMP%\WatchDir1" static WCHAR s_dir2[MAX_PATH]; // "%TEMP%\WatchDir1\Dir2" @@ -20,12 +20,7 @@ static WCHAR s_file1[MAX_PATH]; // "%TEMP%\WatchDir1\File1.txt" static WCHAR s_file2[MAX_PATH]; // "%TEMP%\WatchDir1\File2.txt"
static HWND s_hwnd = NULL; -static WCHAR s_szName[] = L"SHChangeNotify testcase"; -static LPITEMIDLIST s_pidl = NULL; -static UINT s_uRegID = 0; -static SHChangeNotifyEntry s_entry; - -static CHAR s_path1[MAX_PATH], s_path2[MAX_PATH]; +static const WCHAR s_szName[] = L"SHChangeNotify testcase";
typedef enum TYPE { @@ -40,21 +35,6 @@ typedef enum TYPE TYPE_FREESPACE } TYPE;
-static BYTE s_counters[TYPE_FREESPACE + 1]; - -static LPCSTR -DoGetPattern(void) -{ - size_t i; - static char buf[TYPE_FREESPACE + 1 + 1]; - for (i = 0; i < TYPE_FREESPACE + 1; ++i) - { - buf[i] = (char)('0' + s_counters[i]); - } - buf[i] = 0; - return buf; -} - typedef void (*ACTION)(void);
typedef struct TEST_ENTRY @@ -134,13 +114,10 @@ static const TEST_ENTRY s_TestEntries[] = { {__LINE__, SHCNE_RMDIR, s_dir2, NULL, "000010000", DoAction2}, {__LINE__, SHCNE_MKDIR, s_dir2, NULL, "000100000", DoAction1}, {__LINE__, SHCNE_RENAMEFOLDER, s_dir2, s_dir3, "000000010", NULL}, - {__LINE__, SHCNE_RENAMEFOLDER, s_dir2, NULL, "000000010", NULL}, {__LINE__, SHCNE_RENAMEFOLDER, s_dir2, s_dir3, "000000010", DoAction3}, - {__LINE__, SHCNE_RENAMEFOLDER, s_dir2, NULL, "000000010", NULL}, {__LINE__, SHCNE_CREATE, s_file1, NULL, "010000000", NULL}, {__LINE__, SHCNE_CREATE, s_file1, s_file2, "010000000", NULL}, {__LINE__, SHCNE_CREATE, s_file1, NULL, "010000000", DoAction4}, - {__LINE__, SHCNE_RENAMEITEM, s_file1, NULL, "100000000", NULL}, {__LINE__, SHCNE_RENAMEITEM, s_file1, s_file2, "100000000", NULL}, {__LINE__, SHCNE_RENAMEITEM, s_file1, s_file2, "100000000", DoAction5}, {__LINE__, SHCNE_RENAMEITEM, s_file1, s_file2, "100000000", NULL}, @@ -175,11 +152,21 @@ static const TEST_ENTRY s_TestEntries[] = { {__LINE__, SHCNE_RMDIR, s_dir1, NULL, "000010000", NULL}, {__LINE__, SHCNE_RMDIR, s_dir1, NULL, "000010000", DoAction8}, }; -static const size_t s_nTestEntries = _countof(s_TestEntries); -static size_t s_iTest = 0; + +LPCSTR PatternFromFlags(DWORD flags) +{ + static char s_buf[TYPE_FREESPACE + 1 + 1]; + DWORD i; + for (i = 0; i <= TYPE_FREESPACE; ++i) + { + s_buf[i] = (char)('0' + !!(flags & (1 << i))); + } + s_buf[i] = 0; + return s_buf; +}
static void -DoTestEntry1(const TEST_ENTRY *entry) +DoTestEntry(const TEST_ENTRY *entry) { if (entry->action) { @@ -187,16 +174,13 @@ DoTestEntry1(const TEST_ENTRY *entry) }
SHChangeNotify(entry->event, SHCNF_PATHW | SHCNF_FLUSH, entry->item1, entry->item2); - SendMessageW(s_hwnd, WM_COMMAND, ID_TEST + s_iTest, 0);
- ZeroMemory(&s_counters, sizeof(s_counters)); -} + DWORD flags = SendMessageW(s_hwnd, WM_GET_NOTIFY_FLAGS, 0, 0); + LPCSTR pattern = PatternFromFlags(flags);
-static void -DoTestEntry2(const TEST_ENTRY *entry) -{ - LPCSTR pattern = DoGetPattern(); ok(lstrcmpA(pattern, entry->pattern) == 0, "Line %d: pattern mismatch '%s'\n", entry->line, pattern); + + SendMessageW(s_hwnd, WM_CLEAR_FLAGS, 0, 0); }
static BOOL @@ -223,252 +207,74 @@ DoInit(HWND hwnd) lstrcpyW(s_file2, s_dir1); PathAppendW(s_file2, L"File2.txt");
- s_pidl = ILCreateFromPathW(s_dir1); - - s_entry.pidl = s_pidl; - s_entry.fRecursive = TRUE; - LONG fEvents = SHCNE_ALLEVENTS; - s_uRegID = SHChangeNotifyRegister(hwnd, SHCNRF_ShellLevel, fEvents, WM_SHELL_NOTIFY, - 1, &s_entry); - return s_uRegID != 0; -} - -static DWORD WINAPI ThreadFunc(LPVOID) -{ - for (size_t i = 0; i < s_nTestEntries; ++i) - { - s_iTest = i; - DoTestEntry1(&s_TestEntries[i]); - } - - SendMessageW(s_hwnd, WM_COMMAND, IDOK, 0); - return 0; -} - -static BOOL -OnCreate(HWND hwnd) -{ - s_hwnd = hwnd; - - BOOL bOK = DoInit(hwnd); - if (!bOK) - { - skip("SHChangeNotifyRegister failed\n"); - return FALSE; - } - - DWORD tid; - HANDLE hThread = CreateThread(NULL, 0, ThreadFunc, NULL, 0, &tid); - if (hThread == NULL) - { - skip("CreateThread failed\n"); - return FALSE; - } - CloseHandle(hThread); - return TRUE; }
static void -OnCommand(HWND hwnd, UINT id) -{ - switch (id) - { - case IDOK: - case IDCANCEL: - DestroyWindow(hwnd); - break; - default: - if (ID_TEST <= id && id < ID_TEST + 1000) - { - DoTestEntry2(&s_TestEntries[s_iTest]); - } - break; - } -} - -static void -OnDestroy(HWND hwnd) +DoEnd(HWND hwnd) { - SHChangeNotifyDeregister(s_uRegID); - CoTaskMemFree(s_pidl); DeleteFileW(s_file1); DeleteFileW(s_file2); RemoveDirectoryW(s_dir3); RemoveDirectoryW(s_dir2); RemoveDirectoryW(s_dir1); - PostQuitMessage(0); - s_hwnd = NULL; + + SendMessageW(s_hwnd, WM_COMMAND, IDOK, 0); }
-static void -DoShellNotify(HWND hwnd, PIDLIST_ABSOLUTE pidl1, PIDLIST_ABSOLUTE pidl2, LONG lEvent) +START_TEST(SHChangeNotify) { - if (pidl1) - SHGetPathFromIDListA(pidl1, s_path1); - else - s_path1[0] = 0; - - if (pidl2) - SHGetPathFromIDListA(pidl2, s_path2); - else - s_path2[0] = 0; + WCHAR szPath[MAX_PATH]; + GetModuleFileNameW(NULL, szPath, _countof(szPath)); + PathRemoveFileSpecW(szPath); + PathAppendW(szPath, L"shell-notify.exe");
- switch (lEvent) + if (!PathFileExistsW(szPath)) { - case SHCNE_RENAMEITEM: - trace("SHCNE_RENAMEITEM('%s', '%s')\n", s_path1, s_path2); - s_counters[TYPE_RENAMEITEM] = 1; - break; - case SHCNE_CREATE: - trace("SHCNE_CREATE('%s', '%s')\n", s_path1, s_path2); - s_counters[TYPE_CREATE] = 1; - break; - case SHCNE_DELETE: - trace("SHCNE_DELETE('%s', '%s')\n", s_path1, s_path2); - s_counters[TYPE_DELETE] = 1; - break; - case SHCNE_MKDIR: - trace("SHCNE_MKDIR('%s', '%s')\n", s_path1, s_path2); - s_counters[TYPE_MKDIR] = 1; - break; - case SHCNE_RMDIR: - trace("SHCNE_RMDIR('%s', '%s')\n", s_path1, s_path2); - s_counters[TYPE_RMDIR] = 1; - break; - case SHCNE_MEDIAINSERTED: - trace("SHCNE_MEDIAINSERTED('%s', '%s')\n", s_path1, s_path2); - break; - case SHCNE_MEDIAREMOVED: - trace("SHCNE_MEDIAREMOVED('%s', '%s')\n", s_path1, s_path2); - break; - case SHCNE_DRIVEREMOVED: - trace("SHCNE_DRIVEREMOVED('%s', '%s')\n", s_path1, s_path2); - break; - case SHCNE_DRIVEADD: - trace("SHCNE_DRIVEADD('%s', '%s')\n", s_path1, s_path2); - break; - case SHCNE_NETSHARE: - trace("SHCNE_NETSHARE('%s', '%s')\n", s_path1, s_path2); - break; - case SHCNE_NETUNSHARE: - trace("SHCNE_NETUNSHARE('%s', '%s')\n", s_path1, s_path2); - break; - case SHCNE_ATTRIBUTES: - trace("SHCNE_ATTRIBUTES('%s', '%s')\n", s_path1, s_path2); - break; - case SHCNE_UPDATEDIR: - trace("SHCNE_UPDATEDIR('%s', '%s')\n", s_path1, s_path2); - s_counters[TYPE_UPDATEDIR] = 1; - break; - case SHCNE_UPDATEITEM: - trace("SHCNE_UPDATEITEM('%s', '%s')\n", s_path1, s_path2); - s_counters[TYPE_UPDATEITEM] = 1; - break; - case SHCNE_SERVERDISCONNECT: - trace("SHCNE_SERVERDISCONNECT('%s', '%s')\n", s_path1, s_path2); - break; - case SHCNE_UPDATEIMAGE: - trace("SHCNE_UPDATEIMAGE('%s', '%s')\n", s_path1, s_path2); - break; - case SHCNE_DRIVEADDGUI: - trace("SHCNE_DRIVEADDGUI('%s', '%s')\n", s_path1, s_path2); - break; - case SHCNE_RENAMEFOLDER: - trace("SHCNE_RENAMEFOLDER('%s', '%s')\n", s_path1, s_path2); - s_counters[TYPE_RENAMEFOLDER] = 1; - break; - case SHCNE_FREESPACE: - trace("SHCNE_FREESPACE('%s', '%s')\n", s_path1, s_path2); - s_counters[TYPE_FREESPACE] = 1; - break; - case SHCNE_EXTENDED_EVENT: - trace("SHCNE_EXTENDED_EVENT('%p', '%p')\n", pidl1, pidl2); - break; - case SHCNE_ASSOCCHANGED: - trace("SHCNE_ASSOCCHANGED('%s', '%s')\n", s_path1, s_path2); - break; - default: - trace("(lEvent:%08lX)('%s', '%s')\n", lEvent, s_path1, s_path2); - break; + trace("szPath: %S\n", szPath); + PathRemoveFileSpecW(szPath); + PathAppendW(szPath, L"testdata\shell-notify.exe"); + + if (!PathFileExistsW(szPath)) + { + trace("szPath: %S\n", szPath); + skip("shell-notify.exe not found\n"); + return; + } } -}
-static INT_PTR -OnShellNotify(HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - LONG lEvent; - PIDLIST_ABSOLUTE *pidlAbsolute; - HANDLE hLock = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &pidlAbsolute, &lEvent); - if (hLock) - { - DoShellNotify(hwnd, pidlAbsolute[0], pidlAbsolute[1], lEvent); - SHChangeNotification_Unlock(hLock); - } - else + HINSTANCE hinst = ShellExecuteW(NULL, NULL, szPath, NULL, NULL, SW_SHOWNORMAL); + if ((INT_PTR)hinst <= 32) { - pidlAbsolute = (PIDLIST_ABSOLUTE *)wParam; - DoShellNotify(hwnd, pidlAbsolute[0], pidlAbsolute[1], lParam); + skip("Unable to run shell-notify.exe.\n"); + return; } - return TRUE; -}
-static LRESULT CALLBACK -WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) + for (int i = 0; i < 10; ++i) { - case WM_CREATE: - return (OnCreate(hwnd) ? 0 : -1); - - case WM_COMMAND: - OnCommand(hwnd, LOWORD(wParam)); - break; - - case WM_SHELL_NOTIFY: - return OnShellNotify(hwnd, wParam, lParam); - - case WM_DESTROY: - OnDestroy(hwnd); + s_hwnd = FindWindowW(s_szName, s_szName); + if (s_hwnd) break;
- default: - return DefWindowProcW(hwnd, uMsg, wParam, lParam); + Sleep(100); } - return 0; -}
-START_TEST(SHChangeNotify) -{ - WNDCLASSW wc; - ZeroMemory(&wc, sizeof(wc)); - wc.lpfnWndProc = WindowProc; - wc.hInstance = GetModuleHandleW(NULL); - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); - wc.lpszClassName = s_szName; - if (!RegisterClassW(&wc)) + if (!s_hwnd) { - skip("RegisterClassW failed\n"); + skip("Unable to find window.\n"); return; }
- HWND hwnd = CreateWindowW(s_szName, s_szName, WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, - NULL, NULL, GetModuleHandleW(NULL), NULL); - if (!hwnd) + if (!DoInit(s_hwnd)) { - skip("CreateWindowW failed\n"); + skip("Unable to initialize.\n"); return; } - ShowWindow(hwnd, SW_SHOWNORMAL); - UpdateWindow(hwnd);
- MSG msg; - while (GetMessageW(&msg, NULL, 0, 0)) + for (size_t i = 0; i < _countof(s_TestEntries); ++i) { - TranslateMessage(&msg); - DispatchMessageW(&msg); + DoTestEntry(&s_TestEntries[i]); } + + DoEnd(s_hwnd); } diff --git a/modules/rostests/apitests/shell32/shell-notify.cpp b/modules/rostests/apitests/shell32/shell-notify.cpp new file mode 100644 index 00000000000..f6ac62e8a5d --- /dev/null +++ b/modules/rostests/apitests/shell32/shell-notify.cpp @@ -0,0 +1,256 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) + * PURPOSE: Test for SHChangeNotify + * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + */ + +#include "shelltest.h" +#include <shlwapi.h> +#include <stdio.h> + +#define WM_SHELL_NOTIFY (WM_USER + 100) +#define WM_GET_NOTIFY_FLAGS (WM_USER + 101) +#define WM_CLEAR_FLAGS (WM_USER + 102) + +static HWND s_hwnd = NULL; +static const WCHAR s_szName[] = L"SHChangeNotify testcase"; + +typedef enum TYPE +{ + TYPE_RENAMEITEM, + TYPE_CREATE, + TYPE_DELETE, + TYPE_MKDIR, + TYPE_RMDIR, + TYPE_UPDATEDIR, + TYPE_UPDATEITEM, + TYPE_RENAMEFOLDER, + TYPE_FREESPACE +} TYPE; + +static BYTE s_counters[TYPE_FREESPACE + 1]; +static UINT s_uRegID = 0; +static WCHAR s_dir1[MAX_PATH]; // "%TEMP%\WatchDir1" +static LPITEMIDLIST s_pidl = NULL; +static SHChangeNotifyEntry s_entry; + +static BOOL +OnCreate(HWND hwnd) +{ + s_hwnd = hwnd; + + WCHAR szTemp[MAX_PATH], szPath[MAX_PATH]; + + GetTempPathW(_countof(szTemp), szTemp); + GetLongPathNameW(szTemp, szPath, _countof(szPath)); + + lstrcpyW(s_dir1, szPath); + PathAppendW(s_dir1, L"WatchDir1"); + + s_pidl = ILCreateFromPathW(s_dir1); + + s_entry.pidl = s_pidl; + s_entry.fRecursive = TRUE; + LONG fEvents = SHCNE_ALLEVENTS; + s_uRegID = SHChangeNotifyRegister(hwnd, SHCNRF_ShellLevel, fEvents, WM_SHELL_NOTIFY, + 1, &s_entry); + return s_uRegID != 0; +} + +static void +OnCommand(HWND hwnd, UINT id) +{ + switch (id) + { + case IDOK: + case IDCANCEL: + DestroyWindow(hwnd); + break; + } +} + +static void +OnDestroy(HWND hwnd) +{ + SHChangeNotifyDeregister(s_uRegID); + s_uRegID = 0; + + CoTaskMemFree(s_pidl); + s_pidl = NULL; + + PostQuitMessage(0); + s_hwnd = NULL; +} + +static void +DoShellNotify(HWND hwnd, PIDLIST_ABSOLUTE pidl1, PIDLIST_ABSOLUTE pidl2, LONG lEvent) +{ + CHAR path1[MAX_PATH], path2[MAX_PATH]; + + if (pidl1) + SHGetPathFromIDListA(pidl1, path1); + else + path1[0] = 0; + + if (pidl2) + SHGetPathFromIDListA(pidl2, path2); + else + path2[0] = 0; + + switch (lEvent) + { + case SHCNE_RENAMEITEM: + s_counters[TYPE_RENAMEITEM] = 1; + break; + case SHCNE_CREATE: + s_counters[TYPE_CREATE] = 1; + break; + case SHCNE_DELETE: + s_counters[TYPE_DELETE] = 1; + break; + case SHCNE_MKDIR: + s_counters[TYPE_MKDIR] = 1; + break; + case SHCNE_RMDIR: + s_counters[TYPE_RMDIR] = 1; + break; + case SHCNE_MEDIAINSERTED: + break; + case SHCNE_MEDIAREMOVED: + break; + case SHCNE_DRIVEREMOVED: + break; + case SHCNE_DRIVEADD: + break; + case SHCNE_NETSHARE: + break; + case SHCNE_NETUNSHARE: + break; + case SHCNE_ATTRIBUTES: + break; + case SHCNE_UPDATEDIR: + s_counters[TYPE_UPDATEDIR] = 1; + break; + case SHCNE_UPDATEITEM: + s_counters[TYPE_UPDATEITEM] = 1; + break; + case SHCNE_SERVERDISCONNECT: + break; + case SHCNE_UPDATEIMAGE: + break; + case SHCNE_DRIVEADDGUI: + break; + case SHCNE_RENAMEFOLDER: + s_counters[TYPE_RENAMEFOLDER] = 1; + break; + case SHCNE_FREESPACE: + s_counters[TYPE_FREESPACE] = 1; + break; + case SHCNE_EXTENDED_EVENT: + break; + case SHCNE_ASSOCCHANGED: + break; + default: + break; + } +} + +static INT_PTR +OnShellNotify(HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + LONG lEvent; + PIDLIST_ABSOLUTE *pidlAbsolute; + HANDLE hLock = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &pidlAbsolute, &lEvent); + if (hLock) + { + DoShellNotify(hwnd, pidlAbsolute[0], pidlAbsolute[1], lEvent); + SHChangeNotification_Unlock(hLock); + } + else + { + pidlAbsolute = (PIDLIST_ABSOLUTE *)wParam; + DoShellNotify(hwnd, pidlAbsolute[0], pidlAbsolute[1], lParam); + } + return TRUE; +} + +static LRESULT +OnGetNotifyFlags(HWND hwnd) +{ + DWORD dwFlags = 0; + for (size_t i = 0; i < _countof(s_counters); ++i) + { + if (s_counters[i]) + dwFlags |= (1 << i); + } + return dwFlags; +} + +static LRESULT CALLBACK +WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_CREATE: + return (OnCreate(hwnd) ? 0 : -1); + + case WM_COMMAND: + OnCommand(hwnd, LOWORD(wParam)); + break; + + case WM_SHELL_NOTIFY: + return OnShellNotify(hwnd, wParam, lParam); + + case WM_DESTROY: + OnDestroy(hwnd); + break; + + case WM_GET_NOTIFY_FLAGS: + return OnGetNotifyFlags(hwnd); + + case WM_CLEAR_FLAGS: + ZeroMemory(&s_counters, sizeof(s_counters)); + break; + + default: + return DefWindowProcW(hwnd, uMsg, wParam, lParam); + } + return 0; +} + +INT APIENTRY +wWinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPWSTR lpCmdLine, + INT nCmdShow) +{ + WNDCLASSW wc; + ZeroMemory(&wc, sizeof(wc)); + wc.lpfnWndProc = WindowProc; + wc.hInstance = GetModuleHandleW(NULL); + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); + wc.lpszClassName = s_szName; + if (!RegisterClassW(&wc)) + return -1; + + HWND hwnd = CreateWindowW(s_szName, s_szName, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, + NULL, NULL, GetModuleHandleW(NULL), NULL); + if (!hwnd) + return -1; + + ShowWindow(hwnd, SW_SHOWNORMAL); + UpdateWindow(hwnd); + + MSG msg; + while (GetMessageW(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + return 0; +}