1 /*
2  * PROJECT:     ReactOS Tests
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Tests some aspects of the Window Station API.
5  * COPYRIGHT:   Copyright 2018 Hermes Belusca-Maito
6  */
7 
8 #include <windef.h>
9 #include <winbase.h>
10 #include <wincon.h>
11 #include <winuser.h>
12 
13 #include <strsafe.h>
14 
15 #include "resource.h"
16 
17 
18 /*
19  * Logging facilities
20  */
21 
22 typedef struct _LOG_FILE
23 {
24     HANDLE  hLogFile;
25     PWCHAR  pBuffer;
26     size_t  cbBufferSize;
27 } LOG_FILE, *PLOG_FILE;
28 
29 BOOL
30 InitLog(
31     OUT PLOG_FILE LogFile,
32     IN LPCWSTR LogFileName,
33     IN PWCHAR pBuffer,
34     IN size_t cbBufferSize)
35 {
36     HANDLE hLogFile;
37 
38     ZeroMemory(LogFile, sizeof(*LogFile));
39 
40     hLogFile = CreateFileW(LogFileName,
41                            GENERIC_WRITE,
42                            FILE_SHARE_READ,
43                            NULL,
44                            OPEN_ALWAYS,
45                            FILE_ATTRIBUTE_NORMAL,
46                            NULL);
47     if (hLogFile == INVALID_HANDLE_VALUE)
48         return FALSE;
49 
50     LogFile->hLogFile = hLogFile;
51     LogFile->pBuffer  = pBuffer;
52     LogFile->cbBufferSize = cbBufferSize;
53 
54     return TRUE;
55 }
56 
57 VOID
58 CloseLog(
59     IN PLOG_FILE LogFile)
60 {
61     CloseHandle(LogFile->hLogFile);
62     ZeroMemory(LogFile, sizeof(*LogFile));
63 }
64 
65 BOOL
66 WriteToLog(
67     IN PLOG_FILE LogFile,
68     IN LPCVOID Buffer,
69     IN DWORD dwBufferSize)
70 {
71     return WriteFile(LogFile->hLogFile,
72                      Buffer,
73                      dwBufferSize,
74                      &dwBufferSize, NULL);
75 }
76 
77 BOOL
78 WriteToLogPuts(
79     IN PLOG_FILE LogFile,
80     IN LPCWSTR String)
81 {
82     return WriteToLog(LogFile,
83                       String,
84                       wcslen(String) * sizeof(WCHAR));
85 }
86 
87 BOOL
88 WriteToLogPrintfV(
89     IN PLOG_FILE LogFile,
90     IN LPCWSTR Format,
91     IN va_list args)
92 {
93     StringCbVPrintfW(LogFile->pBuffer,
94                      LogFile->cbBufferSize,
95                      Format, args);
96 
97     return WriteToLog(LogFile,
98                       LogFile->pBuffer,
99                       wcslen(LogFile->pBuffer) * sizeof(WCHAR));
100 }
101 
102 BOOL
103 WriteToLogPrintf(
104     IN PLOG_FILE LogFile,
105     IN LPCWSTR Format,
106     ...)
107 {
108     BOOL bRet;
109     va_list args;
110 
111     va_start(args, Format);
112     bRet = WriteToLogPrintfV(LogFile, Format, args);
113     va_end(args);
114 
115     return bRet;
116 }
117 
118 
119 /*
120  * Window Station tests
121  */
122 
123 BOOL
124 CALLBACK
125 EnumDesktopProc(
126     IN LPWSTR lpszDesktop,
127     IN LPARAM lParam)
128 {
129     PLOG_FILE LogFile = (PLOG_FILE)lParam;
130 
131     WriteToLogPrintf(LogFile, L" :: Found desktop '%s'\r\n", lpszDesktop);
132 
133     /* Continue the enumeration */
134     return TRUE;
135 }
136 
137 /*
138  * This test inspects the same window station aspects that are used in the
139  * Cygwin fhandler_console.cc!fhandler_console::create_invisible_console()
140  * function, see:
141  *   https://github.com/cygwin/cygwin/blob/7b9bfb4136f23655e243bab89fb62b04bdbacc7f/winsup/cygwin/fhandler_console.cc#L2494
142  */
143 VOID DoTest(HWND hWnd)
144 {
145     HWINSTA hWinSta;
146     LPCWSTR lpszWinSta = L"Test-WinSta";
147     BOOL bIsItOk;
148     LOG_FILE LogFile;
149     WCHAR szBuffer[2048];
150 
151     bIsItOk = InitLog(&LogFile, L"test_winsta.log", szBuffer, sizeof(szBuffer));
152     if (!bIsItOk)
153     {
154         MessageBoxW(hWnd, L"Could not create the log file, stopping test now...", L"Error", MB_ICONERROR | MB_OK);
155         return;
156     }
157 
158     /* Switch output to UTF-16 (little endian) */
159     WriteToLog(&LogFile, "\xFF\xFE", 2);
160 
161     WriteToLogPrintf(&LogFile, L"Creating Window Station '%s'\r\n", lpszWinSta);
162     hWinSta = CreateWindowStationW(lpszWinSta, 0, WINSTA_ALL_ACCESS, NULL);
163     WriteToLogPrintf(&LogFile, L"--> Returned handle 0x%p ; last error: %lu\r\n", hWinSta, GetLastError());
164 
165     if (!hWinSta)
166     {
167         WriteToLogPuts(&LogFile, L"\r\nHandle is NULL, cannot proceed further, stopping the test!\r\n\r\n");
168         return;
169     }
170 
171     WriteToLogPrintf(&LogFile, L"Enumerate desktops on Window Station '%s' (0x%p) (before process attach)\r\n", lpszWinSta, hWinSta);
172     bIsItOk = EnumDesktopsW(hWinSta, EnumDesktopProc, (LPARAM)&LogFile);
173     WriteToLogPrintf(&LogFile, L"--> Returned %s ; last error: %lu\r\n",
174                      (bIsItOk ? L"success" : L"failure"), GetLastError());
175 
176     WriteToLogPrintf(&LogFile, L"Setting current process to Window Station '%s' (0x%p)\r\n", lpszWinSta, hWinSta);
177     bIsItOk = SetProcessWindowStation(hWinSta);
178     WriteToLogPrintf(&LogFile, L"--> Returned %s ; last error: %lu\r\n",
179                      (bIsItOk ? L"success" : L"failure"), GetLastError());
180 
181     WriteToLogPrintf(&LogFile, L"Enumerate desktops on Window Station '%s' (0x%p) (after process attach, before allocating console)\r\n", lpszWinSta, hWinSta);
182     bIsItOk = EnumDesktopsW(hWinSta, EnumDesktopProc, (LPARAM)&LogFile);
183     WriteToLogPrintf(&LogFile, L"--> Returned %s ; last error: %lu\r\n",
184                      (bIsItOk ? L"success" : L"failure"), GetLastError());
185 
186     WriteToLogPrintf(&LogFile, L"Allocating a new console on Window Station '%s' (0x%p)\r\n", lpszWinSta, hWinSta);
187     bIsItOk = AllocConsole();
188     WriteToLogPrintf(&LogFile, L"--> Returned %s ; last error: %lu\r\n",
189                      (bIsItOk ? L"success" : L"failure"), GetLastError());
190 
191     WriteToLogPrintf(&LogFile, L"Enumerate desktops on Window Station '%s' (0x%p) (after allocating console)\r\n", lpszWinSta, hWinSta);
192     bIsItOk = EnumDesktopsW(hWinSta, EnumDesktopProc, (LPARAM)&LogFile);
193     WriteToLogPrintf(&LogFile, L"--> Returned %s ; last error: %lu\r\n",
194                      (bIsItOk ? L"success" : L"failure"), GetLastError());
195 
196     WriteToLogPrintf(&LogFile, L"Now closing Window Station '%s' (0x%p)\r\n", lpszWinSta, hWinSta);
197     bIsItOk = CloseWindowStation(hWinSta);
198     WriteToLogPrintf(&LogFile, L"--> Returned %s ; last error: %lu\r\n\r\n",
199                      (bIsItOk ? L"success" : L"failure"), GetLastError());
200 
201     CloseLog(&LogFile);
202 }
203 
204 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
205 {
206     UNREFERENCED_PARAMETER(lParam);
207     switch (message)
208     {
209     case WM_INITDIALOG:
210         return (INT_PTR)TRUE;
211 
212     case WM_COMMAND:
213         switch (LOWORD(wParam))
214         {
215             case IDOK:
216                 DoTest(hDlg);
217                 EndDialog(hDlg, LOWORD(wParam));
218                 break;
219 
220             case IDCANCEL:
221             default:
222                 EndDialog(hDlg, LOWORD(wParam));
223                 break;
224         }
225         return (INT_PTR)TRUE;
226     }
227     return (INT_PTR)FALSE;
228 }
229 
230 int APIENTRY wWinMain(HINSTANCE hInstance,
231                       HINSTANCE hPrevInstance,
232                       LPWSTR    lpCmdLine,
233                       int       nCmdShow)
234 {
235     UNREFERENCED_PARAMETER(hPrevInstance);
236     UNREFERENCED_PARAMETER(lpCmdLine);
237 
238     return DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_ABOUTBOX), NULL, About);
239 }
240