1 /*
2  * PROJECT:     ReactOS Local Spooler API Tests Injected DLL
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Tests for fpGetPrintProcessorDirectory
5  * COPYRIGHT:   Copyright 2016-2017 Colin Finck (colin@reactos.org)
6  */
7 
8 #include <apitest.h>
9 
10 #define WIN32_NO_STATUS
11 #include <windef.h>
12 #include <winbase.h>
13 #include <wingdi.h>
14 #include <winreg.h>
15 #include <winspool.h>
16 #include <winsplp.h>
17 
18 #include "../localspl_apitest.h"
19 #include <spoolss.h>
20 
21 typedef BOOL (WINAPI *PGetPrintProcessorDirectoryW)(LPWSTR, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD);
22 extern BOOL GetLocalsplFuncs(LPPRINTPROVIDOR pp);
23 extern PVOID GetSpoolssFunc(const char* FunctionName);
24 
25 START_TEST(fpGetPrintProcessorDirectory)
26 {
27     DWORD cbNeeded;
28     DWORD cbTemp;
29     //DWORD dwReturned;
30     PGetPrintProcessorDirectoryW pGetPrintProcessorDirectoryW;
31     PRINTPROVIDOR pp;
32     PWSTR pwszBuffer;
33 
34     if (!GetLocalsplFuncs(&pp))
35         return;
36 
37     pGetPrintProcessorDirectoryW = GetSpoolssFunc("GetPrintProcessorDirectoryW");
38     if (!pGetPrintProcessorDirectoryW)
39         return;
40 
41     // In contrast to GetPrintProcessorDirectoryW, fpGetPrintProcessorDirectory needs an environment and doesn't just accept NULL.
42     SetLastError(0xDEADBEEF);
43     ok(!pp.fpGetPrintProcessorDirectory(NULL, NULL, 0, NULL, 0, NULL), "fpGetPrintProcessorDirectory returns TRUE!\n");
44     ok(GetLastError() == ERROR_INVALID_ENVIRONMENT, "fpGetPrintProcessorDirectory returns error %lu!\n", GetLastError());
45 
46     // Try with an invalid environment as well.
47     SetLastError(0xDEADBEEF);
48     ok(!pp.fpGetPrintProcessorDirectory(NULL, L"invalid", 0, NULL, 0, NULL), "fpGetPrintProcessorDirectory returns TRUE!\n");
49     ok(GetLastError() == ERROR_INVALID_ENVIRONMENT, "fpGetPrintProcessorDirectory returns error %lu!\n", GetLastError());
50 
51 	// This test corrupts something inside spoolsv so that it's only runnable once without restarting spoolsv. Therefore it's disabled.
52 #if 0
53     // Now provide a valid environment and prove that it is checked case-insensitively.
54     // In contrast to GetPrintProcessorDirectoryW, the level isn't the next thing checked here, but fpGetPrintProcessorDirectory
55     // already tries to access the non-supplied pcbNeeded variable.
56     _SEH2_TRY
57     {
58         dwReturned = 0;
59         pp.fpGetPrintProcessorDirectory(NULL, L"wIndows nt x86", 0, NULL, 0, NULL);
60     }
61     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
62     {
63         dwReturned = _SEH2_GetExceptionCode();
64     }
65     _SEH2_END;
66 
67     ok(dwReturned == EXCEPTION_ACCESS_VIOLATION, "dwReturned is %lu!\n", dwReturned);
68 #endif
69 
70     // fpGetPrintProcessorDirectory doesn't care about the supplied level at all. Prove this here.
71     // With no buffer given, this needs to fail with ERROR_INSUFFICIENT_BUFFER.
72     SetLastError(0xDEADBEEF);
73     cbNeeded = 0;
74     ok(!pp.fpGetPrintProcessorDirectory(NULL, L"wIndows nt x86", 1337, NULL, 0, &cbNeeded), "fpGetPrintProcessorDirectory returns TRUE!\n");
75     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "fpGetPrintProcessorDirectory returns error %lu!\n", GetLastError());
76     ok(cbNeeded > 0, "cbNeeded is %lu!\n", cbNeeded);
77 
78 	// This test corrupts something inside spoolsv so that it's only runnable once without restarting spoolsv. Therefore it's disabled.
79 #if 0
80     // Now provide the demanded size, but no buffer.
81     // Unlike GetPrintProcessorDirectoryW, fpGetPrintProcessorDirectory doesn't check for this case and tries to access the buffer.
82     _SEH2_TRY
83     {
84         dwReturned = 0;
85         pp.fpGetPrintProcessorDirectory(NULL, L"wIndows nt x86", 1, NULL, cbNeeded, &cbTemp);
86     }
87     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
88     {
89         dwReturned = _SEH2_GetExceptionCode();
90     }
91     _SEH2_END;
92 
93     ok(dwReturned == EXCEPTION_ACCESS_VIOLATION, "dwReturned is %lu!\n", dwReturned);
94 #endif
95 
96     // Prove that this check is implemented in spoolss' GetPrintProcessorDirectoryW instead.
97     // In contrast to winspool's GetPrintProcessorDirectoryW, cbTemp is left untouched though. This comes from the fact that RPC isn't involved here.
98     SetLastError(0xDEADBEEF);
99     cbTemp = 0xDEADBEEF;
100     ok(!pGetPrintProcessorDirectoryW(NULL, L"wIndows nt x86", 1, NULL, cbNeeded, &cbTemp), "pGetPrintProcessorDirectoryW returns TRUE!\n");
101     ok(GetLastError() == ERROR_INVALID_USER_BUFFER, "pGetPrintProcessorDirectoryW returns error %lu!\n", GetLastError());
102     ok(cbTemp == 0xDEADBEEF, "cbTemp is %lu!\n", cbTemp);
103 
104     // Finally use the function as intended and aim for success!
105     // We only check success by the boolean return value though. GetLastError doesn't return anything meaningful here.
106     pwszBuffer = DllAllocSplMem(cbNeeded);
107     SetLastError(0xDEADBEEF);
108     ok(pp.fpGetPrintProcessorDirectory(NULL, L"wIndows nt x86", 1, (PBYTE)pwszBuffer, cbNeeded, &cbTemp), "fpGetPrintProcessorDirectory returns FALSE!\n");
109     ok(wcslen(pwszBuffer) == cbNeeded / sizeof(WCHAR) - 1, "fpGetPrintProcessorDirectory string is %Iu characters long, but %lu characters expected!\n", wcslen(pwszBuffer), cbNeeded / sizeof(WCHAR) - 1);
110     DllFreeSplMem(pwszBuffer);
111 }
112