1 /*
2  * PROJECT:     ReactOS API tests
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Close windows after tests
5  * COPYRIGHT:   Copyright 2024 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
6  */
7 
8 #include "shelltest.h"
9 #include "closewnd.h"
10 
FreeWindowList(PWINDOW_LIST pList)11 void FreeWindowList(PWINDOW_LIST pList)
12 {
13     free(pList->m_phWnds);
14     pList->m_phWnds = NULL;
15     pList->m_chWnds = 0;
16 }
17 
EnumWindowsProc(HWND hwnd,LPARAM lParam)18 static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
19 {
20     if (!IsWindowVisible(hwnd))
21         return TRUE;
22 
23     PWINDOW_LIST pList = (PWINDOW_LIST)lParam;
24     SIZE_T cb = (pList->m_chWnds + 1) * sizeof(HWND);
25     HWND *phWnds = (HWND *)realloc(pList->m_phWnds, cb);
26     if (!phWnds)
27         return FALSE;
28     phWnds[pList->m_chWnds++] = hwnd;
29     pList->m_phWnds = phWnds;
30     return TRUE;
31 }
32 
GetWindowList(PWINDOW_LIST pList)33 void GetWindowList(PWINDOW_LIST pList)
34 {
35     pList->m_phWnds = NULL;
36     pList->m_chWnds = 0;
37     EnumWindows(EnumWindowsProc, (LPARAM)pList);
38 }
39 
GetWindowListForClose(PWINDOW_LIST pList)40 void GetWindowListForClose(PWINDOW_LIST pList)
41 {
42     for (UINT tries = 5; tries--;)
43     {
44         if (tries)
45             FreeWindowList(pList);
46         GetWindowList(pList);
47         Sleep(500);
48         WINDOW_LIST list;
49         GetWindowList(&list);
50         SIZE_T count = list.m_chWnds;
51         FreeWindowList(&list);
52         if (count == pList->m_chWnds)
53             break;
54     }
55 }
56 
FindInWindowList(const WINDOW_LIST & list,HWND hWnd)57 static HWND FindInWindowList(const WINDOW_LIST &list, HWND hWnd)
58 {
59     for (SIZE_T i = 0; i < list.m_chWnds; ++i)
60     {
61         if (list.m_phWnds[i] == hWnd)
62             return hWnd;
63     }
64     return NULL;
65 }
66 
FindNewWindow(PWINDOW_LIST List1,PWINDOW_LIST List2)67 HWND FindNewWindow(PWINDOW_LIST List1, PWINDOW_LIST List2)
68 {
69     for (SIZE_T i2 = 0; i2 < List2->m_chWnds; ++i2)
70     {
71         HWND hWnd = List2->m_phWnds[i2];
72         if (!IsWindowEnabled(hWnd) || !IsWindowVisible(hWnd))
73             continue;
74 
75         BOOL bFoundInList1 = FALSE;
76         for (SIZE_T i1 = 0; i1 < List1->m_chWnds; ++i1)
77         {
78             if (hWnd == List1->m_phWnds[i1])
79             {
80                 bFoundInList1 = TRUE;
81                 break;
82             }
83         }
84 
85         if (!bFoundInList1)
86             return hWnd;
87     }
88     return NULL;
89 }
90 
WaitForForegroundWindow(HWND hWnd,UINT wait=250)91 static void WaitForForegroundWindow(HWND hWnd, UINT wait = 250)
92 {
93     for (UINT waited = 0, interval = 50; waited < wait; waited += interval)
94     {
95         if (GetForegroundWindow() == hWnd || !IsWindowVisible(hWnd))
96             return;
97         Sleep(interval);
98     }
99 }
100 
CloseNewWindows(PWINDOW_LIST List1,PWINDOW_LIST List2)101 void CloseNewWindows(PWINDOW_LIST List1, PWINDOW_LIST List2)
102 {
103     for (SIZE_T i = 0; i < List2->m_chWnds; ++i)
104     {
105         HWND hWnd = List2->m_phWnds[i];
106         if (!IsWindow(hWnd) || FindInWindowList(*List1, hWnd))
107             continue;
108 
109         SwitchToThisWindow(hWnd, TRUE);
110         WaitForForegroundWindow(hWnd);
111 
112         if (!PostMessageW(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0))
113         {
114             DWORD_PTR result;
115             SendMessageTimeoutW(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0, 0, 3000, &result);
116         }
117     }
118 }
119