C++ Code:
#define _UNICODE#include <windows.h>#include <stdlib.h>#include <vector>#include <iostream>using namespace std
;void ErrorExit
( const wchar_t *lpszFunction
);LRESULT CALLBACK WndProc
( _In_ HWND hWnd
, _In_ UINT uMsg
, _In_ WPARAM wParam
, _In_ LPARAM lParam
);// Window functions: [url]https://msdn.microsoft.com/en-us/library/windows/desktop/ms632595(v=vs.85).aspx[/url]BOOL CALLBACK EnumWindowsCallback
( _In_ HWND hWnd
, _In_ LPARAM lParam
);void CALLBACK WinEventCallback
( _In_ HWINEVENTHOOK hWinEventHook
, _In_ DWORD event
, _In_ HWND hWnd
, _In_ LONG idObject
, _In_ LONG idChild
, _In_ DWORD dwEventThread
, _In_ DWORD dwmsEventTime
);std
::vector<struct window
> windows
;HINSTANCE hInst
;WCHAR szTitle
[] = L
"Tile";WCHAR szMenuName
[] = L
"Tile";WCHAR szWindowClass
[] = L
"Tile";intmain
(int argc
, char *argv
[]){ LPWSTR
*szArgList
; int narg
; WNDCLASSEXW wcex
; HWND hWnd
; LONG lStyle
; HACCEL hAccelTable
; MSG msg
; FILE
*fConsole
; // Fake values for arguments passed to wWinMain. HINSTANCE hInstance
= 0; int nCmdShow
= 0; UNREFERENCED_PARAMETER
(lStyle
); UNREFERENCED_PARAMETER
(hAccelTable
); UNREFERENCED_PARAMETER
(fConsole
); szArgList
= CommandLineToArgvW
(GetCommandLineW
(), &narg
); if (!szArgList
) { ErrorExit
(L
"CommandLineToArgvW"); } // TODO: Add custom icon or use default Visual Studio icon. wcex.
cbSize = sizeof(WNDCLASSEX
); wcex.
style = CS_HREDRAW
| CS_VREDRAW
;; wcex.
lpfnWndProc = WndProc
; wcex.
cbClsExtra = 0; wcex.
cbWndExtra = 0; wcex.
hInstance = hInstance
; wcex.
hIcon = LoadIcon
(hInstance
, IDI_APPLICATION
); wcex.
hCursor = LoadCursor
(nullptr
, IDC_ARROW
); wcex.
hbrBackground = (HBRUSH
)(COLOR_WINDOW
+ 1); wcex.
lpszMenuName = szMenuName
; wcex.
lpszClassName = szWindowClass
; wcex.
hIconSm = LoadIcon
(wcex.
hInstance, IDI_APPLICATION
); if (!RegisterClassEx
(&wcex
)) { ErrorExit
(L
"RegisterClassExW"); } hWnd
= CreateWindowEx
(WS_EX_CLIENTEDGE
, szWindowClass
, szTitle
, WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, nullptr
, nullptr
, hInstance
, nullptr
); if (!hWnd
) { ErrorExit
(L
"CreateWindowExW"); } lStyle
= GetWindowLong
(hWnd
, GWL_STYLE
); if (!SetWindowLongPtr
(hWnd
, GWL_STYLE
, WS_BORDER
| WS_THICKFRAME
)) { ErrorExit
(L
"SetWindowLongPtr"); } // Necessary per API reference for SetWindowLong. If left out, // there will be a persistent rendering artifact after the first // window move if the window has not been resized. if (!SetWindowPos
(hWnd
, HWND_TOP
, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
| SWP_FRAMECHANGED
)) { ErrorExit
(L
"SetWindowPos"); } ShowWindow
(hWnd
, nCmdShow
); if (!UpdateWindow
(hWnd
)) { ErrorExit
(L
"UpdateWindow"); } //EnumWindows(EnumWindowsCallback, 0); HWINEVENTHOOK hWinEventHook
= SetWinEventHook
( EVENT_OBJECT_CREATE
, EVENT_OBJECT_DESTROY
, NULL
, WinEventCallback
, 0, 0, WINEVENT_OUTOFCONTEXT
); hAccelTable
= LoadAccelerators
(hInstance
, 0); while (GetMessage
(&msg
, nullptr
, 0, 0)) { if (!TranslateAccelerator
(hWnd
, nullptr
, &msg
)) { TranslateMessage
(&msg
); DispatchMessage
(&msg
); } } if (hWinEventHook
) UnhookWinEvent
(hWinEventHook
); return (int)msg.
wParam;}LRESULT CALLBACK
WndProc
( _In_ HWND hWnd
, _In_ UINT message
, _In_ WPARAM wParam
, _In_ LPARAM lParam
){ switch (message
) { case WM_DESTROY
: { PostQuitMessage
(0); break; } default: { return DefWindowProc
(hWnd
, message
, wParam
, lParam
); } } return 0;}BOOL CALLBACK
EnumWindowsCallback
( _In_ HWND hWnd
, _In_ LPARAM lParam
){ // TODO: Enumerate only windows that have a presence on the desktop. // // [url]https://blogs.msdn.microsoft.com/oldnewthing/20071008-00/?p=24863[/url] // Uses criteria similar to what the Alt+Tab menu uses. May not list allocate // windows in a process group. // Returns zero on error or no text. // TODO: Figure out if returned size being one less than expected is // normal. int nMax
= GetWindowTextLengthW
(hWnd
) + 1; LPWSTR lpStr
= new
wchar_t[nMax
]; // Skip to next window on error. // TODO: Skip if and only if there is an error. Per the documentation, the // window text may not exist and have zero length. if (!(nMax
- 1)) return TRUE
; if (!GetWindowTextW
(hWnd
, lpStr
, nMax
)) { // TODO: Call SetLastError. // TODO: Return FALSE to stop enumeration. } LONG lStyle
; if (!(lStyle
= GetWindowLong
(hWnd
, GWL_STYLE
))) { // TODO: Call SetLastError. // TODO: Return FALSE to stop enumeration. } // These conditions are fulfilled by windows with a desktop presence. if ((lStyle
& (WS_BORDER
| WS_VISIBLE
)) != (WS_BORDER
| WS_VISIBLE
)) return TRUE
; RECT rArea
; if (!GetClientRect
(hWnd
, &rArea
)) { // TODO: Check to see if this fails if application is cached. // TODO: Call SetLastError. // TODO: Return FALSE to stop enumeration. } wcout
<< lpStr
<< " " << rArea.
right << ", " << rArea.
bottom << " " << IsIconic
(hWnd
) << std
::endl; delete
[] lpStr
; return TRUE
;}void CALLBACK
WinEventCallback
( _In_ HWINEVENTHOOK hWinEventHook
, _In_ DWORD event
, _In_ HWND hWnd
, _In_ LONG idObject
, _In_ LONG idChild
, _In_ DWORD dwEventThread
, _In_ DWORD dwmsEventTime
){ if (!(event
== EVENT_OBJECT_CREATE
&& idObject
== OBJID_WINDOW
&& idChild
== INDEXID_CONTAINER
)) return; LONG lStyle
; if (!(lStyle
= GetWindowLong
(hWnd
, GWL_STYLE
))) return; // These conditions are fulfilled by windows with a desktop presence. if ((lStyle
& (WS_BORDER
| WS_VISIBLE
)) != (WS_BORDER
| WS_VISIBLE
)) return; cout
<< "WinEventCallback: EVENT_OBJECT_CREATE" << std
::endl;}voidErrorExit
( const wchar_t *lpszFunction
){ // Retrieve the system error message for the last error code. LPVOID lpMsgBuf
; LPVOID lpDisplayBuf
; DWORD lerr
= GetLastError
(); DWORD size
= FormatMessage
( FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
, NULL
, lerr
, MAKELANGID
(LANG_NEUTRAL
, SUBLANG_DEFAULT
), (LPTSTR
)&lpMsgBuf
, 0, NULL
); UNREFERENCED_PARAMETER
(lpDisplayBuf
); UNREFERENCED_PARAMETER
(size
); // Print the error message to the console. wprintf(L
"%s: %s", lpszFunction
, (wchar_t *)lpMsgBuf
); // Display the error message in a message box. /*
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, lerr, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
*/ ExitProcess
(lerr
);}