1 /*
2  * PROJECT:     ReactOS Local Spooler API Tests Injected DLL
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Main functions
5  * COPYRIGHT:   Copyright 2015-2017 Colin Finck (colin@reactos.org)
6  */
7 
8 #define __ROS_LONG64__
9 
10 #define STANDALONE
11 #include <apitest.h>
12 
13 #define WIN32_NO_STATUS
14 #include <io.h>
15 #include <windef.h>
16 #include <winbase.h>
17 #include <wingdi.h>
18 #include <winreg.h>
19 #include <winspool.h>
20 #include <winsplp.h>
21 
22 #include "../localspl_apitest.h"
23 
24 //#define NDEBUG
25 #include <debug.h>
26 
27 // Test list
28 extern void func_fpEnumPrinters(void);
29 extern void func_fpGetPrintProcessorDirectory(void);
30 extern void func_fpSetJob(void);
31 
32 const struct test winetest_testlist[] =
33 {
34     { "fpEnumPrinters", func_fpEnumPrinters },
35     { "fpGetPrintProcessorDirectory", func_fpGetPrintProcessorDirectory },
36     { "fpSetJob", func_fpSetJob },
37     { 0, 0 }
38 };
39 
40 /**
41  * We don't link against winspool, so we don't have GetDefaultPrinterW.
42  * We can easily implement a similar function ourselves though.
43  */
44 PWSTR
45 GetDefaultPrinterFromRegistry(VOID)
46 {
47     static const WCHAR wszWindowsKey[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows";
48     static const WCHAR wszDeviceValue[] = L"Device";
49 
50     DWORD cbNeeded;
51     DWORD dwErrorCode;
52     HKEY hWindowsKey = NULL;
53     PWSTR pwszDevice;
54     PWSTR pwszComma;
55     PWSTR pwszReturnValue = NULL;
56 
57     // Open the registry key where the default printer for the current user is stored.
58     dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_READ, &hWindowsKey);
59     if (dwErrorCode != ERROR_SUCCESS)
60     {
61         skip("RegOpenKeyExW failed with status %u!\n", dwErrorCode);
62         goto Cleanup;
63     }
64 
65     // Determine the size of the required buffer.
66     dwErrorCode = (DWORD)RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, NULL, &cbNeeded);
67     if (dwErrorCode != ERROR_SUCCESS)
68     {
69         skip("RegQueryValueExW failed with status %u!\n", dwErrorCode);
70         goto Cleanup;
71     }
72 
73     // Allocate it.
74     pwszDevice = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
75     if (!pwszDevice)
76     {
77         skip("HeapAlloc failed!\n");
78         goto Cleanup;
79     }
80 
81     // Now get the actual value.
82     dwErrorCode = RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, (PBYTE)pwszDevice, &cbNeeded);
83     if (dwErrorCode != ERROR_SUCCESS)
84     {
85         skip("RegQueryValueExW failed with status %u!\n", dwErrorCode);
86         goto Cleanup;
87     }
88 
89     // We get a string "<Printer Name>,winspool,<Port>:".
90     // Extract the printer name from it.
91     pwszComma = wcschr(pwszDevice, L',');
92     if (!pwszComma)
93     {
94         skip("Found no or invalid default printer: %S!\n", pwszDevice);
95         goto Cleanup;
96     }
97 
98     // Return the default printer.
99     *pwszComma = 0;
100     pwszReturnValue = pwszDevice;
101 
102 Cleanup:
103     if (hWindowsKey)
104         RegCloseKey(hWindowsKey);
105 
106     return pwszReturnValue;
107 }
108 
109 BOOL
110 GetLocalsplFuncs(LPPRINTPROVIDOR pp)
111 {
112     HMODULE hLocalspl;
113     PInitializePrintProvidor pfnInitializePrintProvidor;
114 
115     // Get us a handle to the loaded localspl.dll.
116     hLocalspl = GetModuleHandleW(L"localspl");
117     if (!hLocalspl)
118     {
119         skip("GetModuleHandleW failed with error %u!\n", GetLastError());
120         return FALSE;
121     }
122 
123     // Get a pointer to its InitializePrintProvidor function.
124     pfnInitializePrintProvidor = (PInitializePrintProvidor)GetProcAddress(hLocalspl, "InitializePrintProvidor");
125     if (!pfnInitializePrintProvidor)
126     {
127         skip("GetProcAddress failed with error %u!\n", GetLastError());
128         return FALSE;
129     }
130 
131     // Get localspl's function pointers.
132     if (!pfnInitializePrintProvidor(pp, sizeof(PRINTPROVIDOR), NULL))
133     {
134         skip("pfnInitializePrintProvidor failed with error %u!\n", GetLastError());
135         return FALSE;
136     }
137 
138     return TRUE;
139 }
140 
141 PVOID
142 GetSpoolssFunc(const char* FunctionName)
143 {
144     HMODULE hSpoolss;
145 
146     // Get us a handle to the loaded spoolss.dll.
147     hSpoolss = GetModuleHandleW(L"spoolss");
148     if (!hSpoolss)
149     {
150         skip("GetModuleHandleW failed with error %u!\n", GetLastError());
151         return FALSE;
152     }
153 
154     return GetProcAddress(hSpoolss, FunctionName);
155 }
156 
157 // Running the tests from the injected DLL and redirecting their output to the pipe.
158 BOOL WINAPI
159 DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
160 {
161     char szTestName[150];
162     DWORD cbRead;
163     FILE* fpStdout;
164     HANDLE hCommandPipe;
165     int iOldStdout;
166 
167     // We only want to run our test once when the DLL is injected to the process.
168     if (fdwReason != DLL_PROCESS_ATTACH)
169         return TRUE;
170 
171     // Read the test to run from the command pipe.
172     hCommandPipe = CreateFileW(COMMAND_PIPE_NAME, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
173     if (hCommandPipe == INVALID_HANDLE_VALUE)
174     {
175         DPRINT("DLL: CreateFileW failed for the command pipe with error %lu!\n", GetLastError());
176         return FALSE;
177     }
178 
179     if (!ReadFile(hCommandPipe, szTestName, sizeof(szTestName), &cbRead, NULL))
180     {
181         DPRINT("DLL: ReadFile failed for the command pipe with error %lu!\n", GetLastError());
182         return FALSE;
183     }
184 
185     CloseHandle(hCommandPipe);
186 
187     // Check if the test name is valid.
188     if (!find_test(szTestName))
189     {
190         DPRINT("DLL: Got invalid test name \"%s\"!\n", szTestName);
191         return FALSE;
192     }
193 
194     // Backup our current stdout and set it to the output pipe.
195     iOldStdout = _dup(_fileno(stdout));
196     fpStdout = _wfreopen(OUTPUT_PIPE_NAME, L"w", stdout);
197     setbuf(stdout, NULL);
198 
199     // Run the test.
200     run_test(szTestName);
201 
202     // Restore stdout to the previous value.
203     fclose(fpStdout);
204     _dup2(iOldStdout, _fileno(stdout));
205 
206     // Return FALSE so that our DLL is immediately unloaded.
207     return FALSE;
208 }
209