[LOCALSPL_APITEST]

- Add more tests for fpEnumPrinters.
  For some reason, using SEH here works only once. We experience a hang in the testing process when you run the test again for a second time without restarting spoolsv. Needs more investigation.
- Ensure that the spooler service is running before starting any testing.
- Do proper cleanup in every case.

[LOCALSPL]
- Implement LocalEnumPrinters level 1 based on the API-Tests.
- Use DllAllocSplMem/DllFreeSplMem instead of HeapAlloc/HeapFree.
- Use AllocSplStr with DllFreeSplStr now that DuplicateStringW is gone.
- Use _countof where applicable.

[SPOOLSS]
- Found out that I was not the only one needing a wcsdup equivalent. My DuplicateStringW from localspl is actually exported as AllocSplStr in spoolss.
  This is actually part of a range of undocumented memory functions in spoolss, so implement and document AllocSplStr, DllAllocSplMem, DllFreeSplMem, DllFreeSplStr, ReallocSplMem and ReallocSplStr.
  Information about some of them was gathered through black box testing and DDK samples (down to Win95 DDK), which at least contained prototypes of them.
- Implement SplInitializeWinSpoolDrv based on the API-Test and simply return FALSE for SplIsUpgrade.

[SPOOLSS_APITEST]
- Add a test for ReallocSplStr, which was actually the most undocumented function of spoolss' memory functions.

[WINSPOOL]
SplInitializeWinSpoolDrv shows that we can't just auto-assign an ordinal to all winspool.drv functions. We even need to export some nameless functions by ordinal only.
Redo the whole .spec file based on the ordinals found in Windows Server 2003's winspool.drv. Trust WINE for the nameless stubs.

svn path=/branches/colins-printing-for-freedom/; revision=68089
This commit is contained in:
Colin Finck 2015-06-09 13:22:25 +00:00
parent f2a66788f8
commit 1e363204d6
22 changed files with 952 additions and 337 deletions

View file

@ -4,6 +4,7 @@ spec2def(spoolss.dll spoolss.spec ADD_IMPORTLIB)
list(APPEND SOURCE
context.c
main.c
memory.c
precomp.h
tools.c)

View file

@ -7,6 +7,7 @@
#include "precomp.h"
HANDLE hProcessHeap;
PRINTPROVIDOR LocalSplFuncs;
@ -16,6 +17,20 @@ ClosePrinter(HANDLE hPrinter)
return FALSE;
}
BOOL WINAPI
DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinstDLL);
hProcessHeap = GetProcessHeap();
break;
}
return TRUE;
}
BOOL WINAPI
EndDocPrinter(HANDLE hPrinter)
{
@ -95,6 +110,44 @@ StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
return 0;
}
BOOL WINAPI
SplInitializeWinSpoolDrv(PVOID* pTable)
{
HINSTANCE hWinspool;
int i;
hWinspool = LoadLibraryW(L"winspool.drv");
if (!hWinspool)
{
ERR("Could not load winspool.drv, last error is %lu!\n", GetLastError());
return FALSE;
}
// Get the function pointers which are meant to be returned by this function.
pTable[0] = GetProcAddress(hWinspool, "OpenPrinterW");
pTable[1] = GetProcAddress(hWinspool, "ClosePrinter");
pTable[2] = GetProcAddress(hWinspool, "SpoolerDevQueryPrintW");
pTable[3] = GetProcAddress(hWinspool, "SpoolerPrinterEvent");
pTable[4] = GetProcAddress(hWinspool, "DocumentPropertiesW");
pTable[5] = GetProcAddress(hWinspool, (LPSTR)212);
pTable[6] = GetProcAddress(hWinspool, (LPSTR)213);
pTable[7] = GetProcAddress(hWinspool, (LPSTR)214);
pTable[8] = GetProcAddress(hWinspool, (LPSTR)215);
// Verify that all calls succeeded.
for (i = 0; i < 9; i++)
if (!pTable[i])
return FALSE;
return TRUE;
}
BOOL WINAPI
SplIsUpgrade()
{
return FALSE;
}
DWORD WINAPI
SpoolerInit()
{

View file

@ -0,0 +1,168 @@
/*
* PROJECT: ReactOS Spooler Router
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
* PURPOSE: Functions for allocating and freeing memory
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
*/
#include "precomp.h"
/**
* @name AllocSplStr
*
* Allocates memory for a Unicode string and copies the input string into it.
* Equivalent of wcsdup, but the returned buffer is allocated from the spooler heap and must be freed with DllFreeSplStr.
*
* @param pwszInput
* The input string to copy
*
* @return
* Pointer to the copied string or NULL if no memory could be allocated.
*/
PWSTR WINAPI
AllocSplStr(PCWSTR pwszInput)
{
DWORD cbInput;
PWSTR pwszOutput;
// Sanity check
if (!pwszInput)
return NULL;
// Get the length of the input string.
cbInput = (wcslen(pwszInput) + 1) * sizeof(WCHAR);
// Allocate it. We don't use DllAllocSplMem here, because it unnecessarily zeroes the memory.
pwszOutput = HeapAlloc(hProcessHeap, 0, cbInput);
if (!pwszOutput)
{
ERR("HeapAlloc failed with error %lu!\n", GetLastError());
return NULL;
}
// Copy the string and return it.
CopyMemory(pwszOutput, pwszInput, cbInput);
return pwszOutput;
}
/**
* @name DllAllocSplMem
*
* Allocate a block of zeroed memory.
* Windows allocates from a separate spooler heap here while we just use the process heap.
*
* @param dwBytes
* Number of bytes to allocate.
*
* @return
* A pointer to the allocated memory or NULL in case of an error.
* You have to free this memory using DllFreeSplMem.
*/
PVOID WINAPI
DllAllocSplMem(DWORD dwBytes)
{
return HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, dwBytes);
}
/**
* @name DllFreeSplMem
*
* Frees the memory allocated with DllAllocSplMem.
*
* @param pMem
* Pointer to the allocated memory.
*
* @return
* TRUE in case of success, FALSE otherwise.
*/
BOOL WINAPI
DllFreeSplMem(PVOID pMem)
{
return HeapFree(hProcessHeap, 0, pMem);
}
/**
* @name DllFreeSplStr
*
* Frees the string allocated with AllocSplStr.
*
* @param pwszString
* Pointer to the allocated string.
*
* @return
* TRUE in case of success, FALSE otherwise.
*/
BOOL WINAPI
DllFreeSplStr(PWSTR pwszString)
{
return HeapFree(hProcessHeap, 0, pwszString);
}
/**
* @name ReallocSplMem
*
* Allocates a new block of memory and copies the contents of the old block into the new one.
*
* @param pOldMem
* Pointer to the old block of memory.
* If this parameter is NULL, ReallocSplMem behaves exactly like DllAllocSplMem.
*
* @param cbOld
* Number of bytes to copy from the old block into the new one.
*
* @param cbNew
* Number of bytes to allocate for the new block.
*
* @return
* A pointer to the allocated new block or NULL in case of an error.
* You have to free this memory using DllFreeSplMem.
*/
PVOID WINAPI
ReallocSplMem(PVOID pOldMem, DWORD cbOld, DWORD cbNew)
{
PVOID pNewMem;
// Always allocate the new block of memory.
pNewMem = DllAllocSplMem(cbNew);
if (!pNewMem)
{
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
return NULL;
}
// Copy the old memory into the new block and free it.
if (pOldMem)
{
CopyMemory(pNewMem, pOldMem, min(cbOld, cbNew));
DllFreeSplMem(pOldMem);
}
return pNewMem;
}
/**
* @name ReallocSplStr
*
* Frees a string allocated by AllocSplStr and copies the given Unicode string into a newly allocated block of memory.
*
* @param ppwszString
* Pointer to the string pointer allocated by AllocSplStr.
* When the function returns, the variable receives the pointer to the copied string.
*
* @param pwszInput
* The Unicode string to copy into the new block of memory.
*
* @return
* Returns TRUE in any case.
*/
BOOL WINAPI
ReallocSplStr(PWSTR* ppwszString, PCWSTR pwszInput)
{
if (*ppwszString)
DllFreeSplStr(*ppwszString);
*ppwszString = AllocSplStr(pwszInput);
return TRUE;
}

View file

@ -16,10 +16,15 @@
#include <winspool.h>
#include <winsplp.h>
#include <spoolss.h>
#include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(spoolss);
// Function pointer to InitializePrintProvidor of a provider DLL
typedef BOOL (WINAPI *PInitializePrintProvidor)(LPPRINTPROVIDOR, DWORD, LPWSTR);
// main.c
extern HANDLE hProcessHeap;
#endif

View file

@ -17,7 +17,7 @@
@ stub AdjustPointersInStructuresArray
@ stub AlignKMPtr
@ stub AlignRpcPtr
@ stub AllocSplStr
@ stdcall AllocSplStr(ptr)
@ stub AllowRemoteCalls
@ stub AppendPrinterNotifyInfoData
@ stub bGetDevModePerUser
@ -53,9 +53,9 @@
@ stub DeletePrinterKeyW
@ stub DeletePrintProcessorW
@ stub DeletePrintProvidorW
@ stub DllAllocSplMem
@ stub DllFreeSplMem
@ stub DllFreeSplStr
@ stdcall DllAllocSplMem(long)
@ stdcall DllFreeSplMem(ptr)
@ stdcall DllFreeSplStr(ptr)
@ stdcall EndDocPrinter(long)
@ stdcall EndPagePrinter(long)
@ stub EnumFormsW
@ -115,8 +115,8 @@
@ stub ProvidorFindFirstPrinterChangeNotification
@ stub pszDbgAllocMsgA
@ stub ReadPrinter
@ stub ReallocSplMem
@ stub ReallocSplStr
@ stdcall ReallocSplMem(ptr long long)
@ stdcall ReallocSplStr(ptr ptr)
@ stub RemoteFindFirstPrinterChangeNotification
@ stub ReplyClosePrinter
@ stub ReplyOpenPrinter
@ -146,9 +146,9 @@
@ stub SplCommitSpoolData
@ stub SplDriverUnloadComplete
@ stub SplGetSpoolFileInfo
@ stub SplInitializeWinSpoolDrv
@ stdcall SplInitializeWinSpoolDrv(ptr)
@ stub SplIsSessionZero
@ stub SplIsUpgrade
@ stdcall SplIsUpgrade()
@ stub SplPowerEvent
@ stub SplProcessPnPEvent
@ stub SplPromptUIInUsersSession

View file

@ -1,169 +1,200 @@
@ stub AbortPrinter
@ stub AddFormA
@ stub AddFormW
@ stub AddJobA
@ stub AddJobW
@ stub AddMonitorA
@ stub AddMonitorW
@ stub AddPortA
@ stub AddPortExA
@ stub AddPortExW
@ stub AddPortW
@ stub AddPrinterA
@ stub AddPrinterConnectionA
@ stub AddPrinterConnectionW
@ stub AddPrinterDriverA
@ stub AddPrinterDriverExA
@ stub AddPrinterDriverExW
@ stub AddPrinterDriverW
@ stub AddPrinterW
@ stub AddPrintProcessorA
@ stub AddPrintProcessorW
@ stub AddPrintProvidorA
@ stub AddPrintProvidorW
@ stub AdvancedDocumentPropertiesA
@ stub AdvancedDocumentPropertiesW
@ stub ADVANCEDSETUPDIALOG
@ stub AdvancedSetupDialog
@ stdcall ClosePrinter(long)
@ stub CloseSpoolFileHandle
@ stub CommitSpoolData
@ stub ConfigurePortA
@ stub ConfigurePortW
@ stub ConnectToPrinterDlg
@ stub ConvertAnsiDevModeToUnicodeDevmode
@ stub ConvertUnicodeDevModeToAnsiDevmode
@ stub CreatePrinterIC
@ stub DeleteFormA
@ stub DeleteFormW
@ stub DeleteMonitorA
@ stub DeleteMonitorW
@ stub DeletePortA
@ stub DeletePortW
@ stub DeletePrinter
@ stub DeletePrinterConnectionA
@ stub DeletePrinterConnectionW
@ stub DeletePrinterDataA
@ stub DeletePrinterDataExA
@ stub DeletePrinterDataExW
@ stub DeletePrinterDataW
@ stub DeletePrinterDriverA
@ stub DeletePrinterDriverExA
@ stub DeletePrinterDriverExW
@ stub DeletePrinterDriverW
@ stub DeletePrinterIC
@ stub DeletePrinterKeyA
@ stub DeletePrinterKeyW
@ stub DeletePrintProcessorA
@ stub DeletePrintProcessorW
@ stub DeletePrintProvidorA
@ stub DeletePrintProvidorW
@ stub DEVICECAPABILITIES
@ stub DeviceCapabilities
@ stdcall DeviceCapabilitiesA(str str long ptr ptr)
@ stdcall DeviceCapabilitiesW(wstr wstr long ptr ptr)
@ stub DEVICEMODE
@ stub DeviceMode
@ stub DevicePropertySheets
@ stub DevQueryPrint
@ stub DevQueryPrintEx
@ stub DocumentEvent
@ stdcall DocumentPropertiesA(long long ptr ptr ptr long)
@ stdcall DocumentPropertiesW(long long ptr ptr ptr long)
@ stub DocumentPropertySheets
@ stdcall EndDocPrinter(long)
@ stdcall EndPagePrinter(long)
@ stub EnumFormsA
@ stub EnumFormsW
@ stub EnumJobsA
@ stub EnumJobsW
@ stub EnumMonitorsA
@ stub EnumMonitorsW
@ stub EnumPortsA
@ stub EnumPortsW
@ stub EnumPrinterDataA
@ stub EnumPrinterDataExA
@ stub EnumPrinterDataExW
@ stub EnumPrinterDataW
@ stub EnumPrinterDriversA
@ stub EnumPrinterDriversW
@ stub EnumPrinterKeyA
@ stub EnumPrinterKeyW
@ stdcall EnumPrintersA(long ptr long ptr long ptr ptr)
@ stdcall EnumPrintersW(long ptr long ptr long ptr ptr)
@ stdcall EnumPrintProcessorDatatypesA(ptr ptr long ptr long ptr ptr)
@ stdcall EnumPrintProcessorDatatypesW(ptr ptr long ptr long ptr ptr)
@ stub EnumPrintProcessorsA
@ stub EnumPrintProcessorsW
@ stub EXTDEVICEMODE
@ stub ExtDeviceMode
@ stub FindClosePrinterChangeNotification
@ stub FindFirstPrinterChangeNotification
@ stub FindNextPrinterChangeNotification
@ stub FlushPrinter
@ stub FreePrinterNotifyInfo
@ stdcall GetDefaultPrinterA(ptr ptr)
@ stdcall GetDefaultPrinterW(ptr ptr)
@ stub GetFormA
@ stub GetFormW
@ stub GetJobA
@ stub GetJobW
@ stdcall GetPrinterA(long long ptr long ptr)
@ stub GetPrinterDataA
@ stub GetPrinterDataExA
@ stub GetPrinterDataExW
@ stub GetPrinterDataW
@ stdcall GetPrinterDriverA(long str long ptr long ptr)
@ stub GetPrinterDriverDirectoryA
@ stub GetPrinterDriverDirectoryW
@ stdcall GetPrinterDriverW(long wstr long ptr long ptr)
@ stdcall GetPrinterW(long long ptr long ptr)
@ stub GetPrintProcessorDirectoryA
@ stdcall GetPrintProcessorDirectoryW(wstr wstr long ptr long ptr)
@ stub GetSpoolFileHandle
@ stub IsValidDevmodeA
@ stub IsValidDevmodeW
@ stdcall OpenPrinterA(str ptr ptr)
@ stdcall OpenPrinterW(wstr ptr ptr)
@ stub PerfClose
@ stub PerfCollect
@ stub PerfOpen
@ stub PlayGdiScriptOnPrinterIC
@ stub PrinterMessageBoxA
@ stub PrinterMessageBoxW
@ stub PrinterProperties
@ stub QueryColorProfile
@ stub QueryRemoteFonts
@ stub QuerySpoolMode
@ stub ReadPrinter
@ stub ResetPrinterA
@ stub ResetPrinterW
@ stub ScheduleJob
@ stub SeekPrinter
@ stub SetAllocFailCount
@ stub SetDefaultPrinterA
@ stub SetDefaultPrinterW
@ stub SetFormA
@ stub SetFormW
@ stub SetJobA
@ stub SetJobW
@ stub SetPortA
@ stub SetPortW
@ stub SetPrinterA
@ stub SetPrinterDataA
@ stub SetPrinterDataExA
@ stub SetPrinterDataExW
@ stub SetPrinterDataW
@ stub SetPrinterW
@ stub SplDriverUnloadComplete
@ stub SpoolerDevQueryPrintW
@ stdcall SpoolerInit()
@ stub SpoolerPrinterEvent
@ stub StartDocDlgA
@ stub StartDocDlgW
@ stub StartDocPrinterA
@ stdcall StartDocPrinterW(long long ptr)
@ stdcall StartPagePrinter(long)
@ stub WaitForPrinterChange
@ stdcall WritePrinter(long ptr long ptr)
@ stdcall XcvDataW(long wstr ptr long ptr long ptr ptr)
100 stub -noname EnumPrinterPropertySheets
101 stub -noname ClusterSplOpen
102 stub -noname ClusterSplClose
103 stub -noname ClusterSplIsAlive
104 stub PerfClose
105 stub PerfCollect
106 stub PerfOpen
107 stub ADVANCEDSETUPDIALOG
108 stub AbortPrinter
109 stub AddFormA
110 stub AddFormW
111 stub AddJobA
112 stub AddJobW
113 stub AddMonitorA
114 stub AddMonitorW
115 stub AddPortA
116 stub AddPortExA
117 stub AddPortExW
118 stub AddPortW
119 stub AddPrintProcessorA
120 stub AddPrintProcessorW
121 stub AddPrintProvidorA
122 stub AddPrintProvidorW
123 stub AddPrinterA
124 stub AddPrinterConnectionA
125 stub AddPrinterConnectionW
126 stub AddPrinterDriverA
127 stub AddPrinterDriverExA
128 stub AddPrinterDriverExW
129 stub AddPrinterDriverW
130 stub AddPrinterW
131 stub AdvancedDocumentPropertiesA
132 stub AdvancedDocumentPropertiesW
133 stub AdvancedSetupDialog
134 stdcall ClosePrinter(long)
135 stub CloseSpoolFileHandle
136 stub CommitSpoolData
137 stub ConfigurePortA
138 stub ConfigurePortW
139 stub ConnectToPrinterDlg
140 stub ConvertAnsiDevModeToUnicodeDevmode
141 stub ConvertUnicodeDevModeToAnsiDevmode
142 stub CreatePrinterIC
143 stub DEVICECAPABILITIES
144 stub DEVICEMODE
145 stub DeleteFormA
146 stub DeleteFormW
147 stub DeleteMonitorA
148 stub DeleteMonitorW
149 stub DeletePortA
150 stub DeletePortW
151 stub DeletePrintProcessorA
152 stub DeletePrintProcessorW
153 stub DeletePrintProvidorA
154 stub DeletePrintProvidorW
155 stub DeletePrinter
156 stub DeletePrinterConnectionA
157 stub DeletePrinterConnectionW
158 stub DeletePrinterDataA
159 stub DeletePrinterDataExA
160 stub DeletePrinterDataExW
161 stub DeletePrinterDataW
162 stub DeletePrinterDriverA
163 stub DeletePrinterDriverExA
164 stub DeletePrinterDriverExW
165 stub DeletePrinterDriverW
166 stub DeletePrinterIC
167 stub DeletePrinterKeyA
168 stub DeletePrinterKeyW
169 stub DevQueryPrint
170 stub DevQueryPrintEx
171 stub DeviceCapabilities
172 stdcall DeviceCapabilitiesA(str str long ptr ptr)
173 stdcall DeviceCapabilitiesW(wstr wstr long ptr ptr)
174 stub DeviceMode
175 stub DevicePropertySheets
176 stub DocumentEvent
177 stdcall DocumentPropertiesA(long long ptr ptr ptr long)
178 stdcall DocumentPropertiesW(long long ptr ptr ptr long)
179 stub DocumentPropertySheets
180 stub EXTDEVICEMODE
181 stdcall EndDocPrinter(long)
182 stdcall EndPagePrinter(long)
183 stub EnumFormsA
184 stub EnumFormsW
185 stub EnumJobsA
186 stub EnumJobsW
187 stub EnumMonitorsA
188 stub EnumMonitorsW
189 stub EnumPortsA
190 stub EnumPortsW
191 stdcall EnumPrintProcessorDatatypesA(ptr ptr long ptr long ptr ptr)
192 stdcall EnumPrintProcessorDatatypesW(ptr ptr long ptr long ptr ptr)
193 stub EnumPrintProcessorsA
194 stub EnumPrintProcessorsW
195 stub EnumPrinterDataA
196 stub EnumPrinterDataExA
197 stub EnumPrinterDataExW
198 stub EnumPrinterDataW
199 stub EnumPrinterDriversA
200 stub EnumPrinterDriversW
201 stdcall GetDefaultPrinterA(ptr ptr)
202 stub SetDefaultPrinterA
203 stdcall GetDefaultPrinterW(ptr ptr)
204 stub SetDefaultPrinterW
205 stub -noname SplReadPrinter
206 stub -noname AddPerMachineConnectionA
207 stub -noname AddPerMachineConnectionW
208 stub -noname DeletePerMachineConnectionA
209 stub -noname DeletePerMachineConnectionW
210 stub -noname EnumPerMachineConnectionsA
211 stub -noname EnumPerMachineConnectionsW
212 stub -noname LoadPrinterDriver
213 stub -noname RefCntLoadDriver
214 stub -noname RefCntUnloadDriver
215 stub -noname ForceUnloadDriver
216 stub -noname PublishPrinterA
217 stub -noname PublishPrinterW
218 stub -noname CallCommonPropertySheetUI
219 stub -noname PrintUIQueueCreate
220 stub -noname PrintUIPrinterPropPages
221 stub -noname PrintUIDocumentDefaults
222 stub -noname SendRecvBidiData
223 stub -noname RouterFreeBidiResponseContainer
224 stub -noname ExternalConnectToLd64In32Server
225 stub EnumPrinterKeyA
226 stub -noname PrintUIWebPnpEntry
227 stub -noname PrintUIWebPnpPostEntry
228 stub -noname PrintUICreateInstance
229 stub -noname PrintUIDocumentPropertiesWrap
230 stub -noname PrintUIPrinterSetup
231 stub -noname PrintUIServerPropPages
232 stub -noname AddDriverCatalog
233 stub EnumPrinterKeyW
234 stdcall EnumPrintersA(long ptr long ptr long ptr ptr)
235 stdcall EnumPrintersW(long ptr long ptr long ptr ptr)
236 stub ExtDeviceMode
237 stub FindClosePrinterChangeNotification
238 stub FindFirstPrinterChangeNotification
239 stub FindNextPrinterChangeNotification
240 stub FlushPrinter
241 stub FreePrinterNotifyInfo
242 stub GetFormA
243 stub GetFormW
244 stub GetJobA
245 stub GetJobW
246 stub GetPrintProcessorDirectoryA
247 stdcall GetPrintProcessorDirectoryW(wstr wstr long ptr long ptr)
248 stdcall GetPrinterA(long long ptr long ptr)
249 stub GetPrinterDataA
250 stub GetPrinterDataExA
251 stub GetPrinterDataExW
252 stub GetPrinterDataW
253 stdcall GetPrinterDriverA(long str long ptr long ptr)
254 stub GetPrinterDriverDirectoryA
255 stub GetPrinterDriverDirectoryW
256 stdcall GetPrinterDriverW(long wstr long ptr long ptr)
257 stdcall GetPrinterW(long long ptr long ptr)
258 stub GetSpoolFileHandle
259 stub IsValidDevmodeA
260 stub IsValidDevmodeW
261 stdcall OpenPrinterA(str ptr ptr)
262 stdcall OpenPrinterW(wstr ptr ptr)
263 stub PlayGdiScriptOnPrinterIC
264 stub PrinterMessageBoxA
265 stub PrinterMessageBoxW
266 stub PrinterProperties
267 stub QueryColorProfile
268 stub QueryRemoteFonts
269 stub QuerySpoolMode
270 stub ReadPrinter
271 stub ResetPrinterA
272 stub ResetPrinterW
273 stub ScheduleJob
274 stub SeekPrinter
275 stub SetAllocFailCount
276 stub SetFormA
277 stub SetFormW
278 stub SetJobA
279 stub SetJobW
280 stub SetPortA
281 stub SetPortW
282 stub SetPrinterA
283 stub SetPrinterDataA
284 stub SetPrinterDataExA
285 stub SetPrinterDataExW
286 stub SetPrinterDataW
287 stub SetPrinterW
288 stub SplDriverUnloadComplete
289 stub SpoolerDevQueryPrintW
290 stdcall SpoolerInit()
291 stub SpoolerPrinterEvent
292 stub StartDocDlgA
293 stub StartDocDlgW
294 stub StartDocPrinterA
295 stdcall StartDocPrinterW(long long ptr)
296 stdcall StartPagePrinter(long)
297 stub WaitForPrinterChange
298 stdcall WritePrinter(long ptr long ptr)
299 stdcall XcvDataW(long wstr ptr long ptr long ptr ptr)

View file

@ -8,7 +8,13 @@
#ifndef _REACTOS_SPOOLSS_H
#define _REACTOS_SPOOLSS_H
PBYTE WINAPI
PackStrings(PCWSTR* pSource, PBYTE pDest, PDWORD DestOffsets, PBYTE pEnd);
PWSTR WINAPI AllocSplStr(PCWSTR pwszInput);
PVOID WINAPI DllAllocSplMem(DWORD dwBytes);
BOOL WINAPI DllFreeSplMem(PVOID pMem);
BOOL WINAPI DllFreeSplStr(PWSTR pwszString);
PBYTE WINAPI PackStrings(PCWSTR* pSource, PBYTE pDest, PDWORD DestOffsets, PBYTE pEnd);
PVOID WINAPI ReallocSplMem(PVOID pOldMem, DWORD cbOld, DWORD cbNew);
BOOL WINAPI ReallocSplStr(PWSTR* ppwszString, PCWSTR pwszInput);
BOOL WINAPI SplInitializeWinSpoolDrv(PVOID* pTable);
#endif

View file

@ -17,6 +17,6 @@ add_library(localspl SHARED
set_module_type(localspl win32dll UNICODE)
target_link_libraries(localspl wine)
add_importlibs(localspl advapi32 msvcrt kernel32 ntdll)
add_importlibs(localspl advapi32 spoolss msvcrt kernel32 ntdll)
add_pch(localspl precomp.h SOURCE)
add_cd_file(TARGET localspl DESTINATION reactos/system32 FOR all)

View file

@ -13,7 +13,7 @@ void
InitializeJobQueue()
{
const WCHAR wszPath[] = L"\\PRINTERS\\?????.SHD";
const DWORD cchPath = sizeof(wszPath) / sizeof(WCHAR) - 1;
const DWORD cchPath = _countof(wszPath) - 1;
const DWORD cchFolders = sizeof("\\PRINTERS\\") - 1;
const DWORD cchPattern = sizeof("?????") - 1;
@ -86,10 +86,10 @@ ReadJobShadowFile(PCWSTR pwszFilePath)
// Get its file size (small enough for a single DWORD) and allocate memory for all of it.
cbFileSize = GetFileSize(hFile, NULL);
pShadowFile = HeapAlloc(hProcessHeap, 0, cbFileSize);
pShadowFile = DllAllocSplMem(cbFileSize);
if (!pShadowFile)
{
ERR("HeapAlloc failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
goto Cleanup;
}
@ -117,17 +117,17 @@ ReadJobShadowFile(PCWSTR pwszFilePath)
}
// Create a new job structure and copy over the relevant fields.
pJob = HeapAlloc(hProcessHeap, 0, sizeof(LOCAL_JOB));
pJob = DllAllocSplMem(sizeof(LOCAL_JOB));
if (!pJob)
{
ERR("HeapAlloc failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
goto Cleanup;
}
pJob->dwJobID = pShadowFile->dwJobID;
pJob->Printer = pPrinter;
pJob->pwszDatatype = DuplicateStringW((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offDatatype));
pJob->pwszDocumentName = DuplicateStringW((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offDocumentName));
pJob->pwszDatatype = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offDatatype));
pJob->pwszDocumentName = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offDocumentName));
pJob->pwszOutputFile = NULL;
CopyMemory(&pJob->DevMode, (PDEVMODEW)((ULONG_PTR)pShadowFile + pShadowFile->offDevMode), sizeof(DEVMODEW));
@ -135,7 +135,7 @@ ReadJobShadowFile(PCWSTR pwszFilePath)
Cleanup:
if (pShadowFile)
HeapFree(hProcessHeap, 0, pShadowFile);
DllFreeSplMem(pShadowFile);
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
@ -171,10 +171,10 @@ WriteJobShadowFile(PCWSTR pwszFilePath, const PLOCAL_JOB pJob)
cbFileSize = sizeof(SHD_HEADER) + cbDatatype + cbDocumentName + cbPrinterName;
// Allocate memory for it.
pShadowFile = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, cbFileSize);
pShadowFile = DllAllocSplMem(cbFileSize);
if (!pShadowFile)
{
ERR("HeapAlloc failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
goto Cleanup;
}
@ -210,7 +210,7 @@ WriteJobShadowFile(PCWSTR pwszFilePath, const PLOCAL_JOB pJob)
Cleanup:
if (pShadowFile)
HeapFree(hProcessHeap, 0, pShadowFile);
DllFreeSplMem(pShadowFile);
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
@ -223,10 +223,10 @@ FreeJob(PLOCAL_JOB pJob)
{
////////// TODO /////////
/// Add some checks
HeapFree(hProcessHeap, 0, pJob->pwszDatatype);
HeapFree(hProcessHeap, 0, pJob->pwszDocumentName);
HeapFree(hProcessHeap, 0, pJob->pwszOutputFile);
HeapFree(hProcessHeap, 0, pJob);
DllFreeSplStr(pJob->pwszDatatype);
DllFreeSplStr(pJob->pwszDocumentName);
DllFreeSplStr(pJob->pwszOutputFile);
DllFreeSplMem(pJob);
return TRUE;
}

View file

@ -8,7 +8,6 @@
#include "precomp.h"
// Global Variables
HANDLE hProcessHeap;
WCHAR wszSpoolDirectory[MAX_PATH];
DWORD cchSpoolDirectory;
@ -24,6 +23,12 @@ const WCHAR wszCurrentEnvironment[] =
#error Unsupported architecture
#endif
const WCHAR* wszPrintProviderInfo[3] = {
L"Windows NT Local Print Providor", // Name
L"Windows NT Local Printers", // Description
L"Locally connected Printers" // Comment
};
static const PRINTPROVIDOR PrintProviderFunctions = {
LocalOpenPrinter, // fpOpenPrinter
NULL, // fpSetJob
@ -117,7 +122,7 @@ static void
_GetSpoolDirectory()
{
const WCHAR wszSpoolPath[] = L"\\spool";
const DWORD cchSpoolPath = sizeof(wszSpoolPath) / sizeof(WCHAR) - 1;
const DWORD cchSpoolPath = _countof(wszSpoolPath) - 1;
// Get the system directory and append the "spool" subdirectory.
// Forget about length checks here. If this doesn't fit into MAX_PATH, our OS has more serious problems...
@ -133,7 +138,6 @@ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinstDLL);
hProcessHeap = GetProcessHeap();
_GetSpoolDirectory();
InitializePrintProcessorTable();
InitializePrinterTable();
@ -146,14 +150,7 @@ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor, DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
{
DWORD cbCopy;
if (cbPrintProvidor < sizeof(PRINTPROVIDOR))
cbCopy = cbPrintProvidor;
else
cbCopy = sizeof(PRINTPROVIDOR);
CopyMemory(pPrintProvidor, &PrintProviderFunctions, cbCopy);
CopyMemory(pPrintProvidor, &PrintProviderFunctions, min(cbPrintProvidor, sizeof(PRINTPROVIDOR)));
return TRUE;
}

View file

@ -10,6 +10,7 @@
#define WIN32_NO_STATUS
#include <limits.h>
#include <stdlib.h>
#include <wchar.h>
#include <windef.h>
@ -20,6 +21,8 @@
#include <winsplp.h>
#include <ndk/rtlfuncs.h>
#include <spoolss.h>
#include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(localspl);
@ -62,6 +65,8 @@ LOCAL_PRINT_PROCESSOR, *PLOCAL_PRINT_PROCESSOR;
typedef struct _LOCAL_PRINTER
{
PWSTR pwszPrinterName;
PWSTR pwszPrinterDriver;
PWSTR pwszDescription;
PWSTR pwszDefaultDatatype;
DEVMODEW DefaultDevMode;
PLOCAL_PRINT_PROCESSOR pPrintProcessor;
@ -157,7 +162,7 @@ BOOL WriteJobShadowFile(PCWSTR pwszFilePath, const PLOCAL_JOB pJob);
// main.c
extern const WCHAR wszCurrentEnvironment[];
extern HANDLE hProcessHeap;
extern const WCHAR* wszPrintProviderInfo[3];
extern WCHAR wszSpoolDirectory[MAX_PATH];
extern DWORD cchSpoolDirectory;
@ -182,7 +187,6 @@ BOOL WINAPI LocalGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, D
// tools.c
PWSTR AllocAndRegQueryWSZ(HKEY hKey, PCWSTR pwszValueName);
PWSTR DuplicateStringW(PCWSTR pwszInput);
PVOID NTAPI GenericTableAllocateRoutine(PRTL_GENERIC_TABLE Table, CLONG ByteSize);
VOID NTAPI GenericTableFreeRoutine(PRTL_GENERIC_TABLE Table, PVOID Buffer);

View file

@ -90,20 +90,20 @@ InitializePrinterTable()
if (pPrinter)
{
if (pPrinter->pwszDefaultDatatype)
HeapFree(hProcessHeap, 0, pPrinter->pwszDefaultDatatype);
DllFreeSplStr(pPrinter->pwszDefaultDatatype);
HeapFree(hProcessHeap, 0, pPrinter);
DllFreeSplMem(pPrinter);
pPrinter = NULL;
}
if (pwszPrintProcessor)
{
HeapFree(hProcessHeap, 0, pwszPrintProcessor);
DllFreeSplStr(pwszPrintProcessor);
pwszPrintProcessor = NULL;
}
// Get the name of this printer.
cchPrinterName = sizeof(wszPrinterName) / sizeof(WCHAR);
cchPrinterName = _countof(wszPrinterName);
lStatus = RegEnumKeyExW(hKey, i, wszPrinterName, &cchPrinterName, NULL, NULL, NULL, NULL);
if (lStatus == ERROR_MORE_DATA)
{
@ -138,17 +138,27 @@ InitializePrinterTable()
}
// Create a new LOCAL_PRINTER structure for it.
pPrinter = HeapAlloc(hProcessHeap, 0, sizeof(LOCAL_PRINTER));
pPrinter = DllAllocSplMem(sizeof(LOCAL_PRINTER));
if (!pPrinter)
{
ERR("HeapAlloc failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
goto Cleanup;
}
pPrinter->pwszPrinterName = DuplicateStringW(wszPrinterName);
pPrinter->pwszPrinterName = AllocSplStr(wszPrinterName);
pPrinter->pPrintProcessor = pPrintProcessor;
InitializeListHead(&pPrinter->JobQueue);
// Get the printer driver.
pPrinter->pwszPrinterDriver = AllocAndRegQueryWSZ(hSubKey, L"Printer Driver");
if (!pPrinter->pwszPrinterDriver)
continue;
// Get the description.
pPrinter->pwszDescription = AllocAndRegQueryWSZ(hSubKey, L"Description");
if (!pPrinter->pwszDescription)
continue;
// Get the default datatype.
pPrinter->pwszDefaultDatatype = AllocAndRegQueryWSZ(hSubKey, L"Datatype");
if (!pPrinter->pwszDefaultDatatype)
@ -183,14 +193,14 @@ InitializePrinterTable()
Cleanup:
if (pwszPrintProcessor)
HeapFree(hProcessHeap, 0, pwszPrintProcessor);
DllFreeSplStr(pwszPrintProcessor);
if (pPrinter)
{
if (pPrinter->pwszDefaultDatatype)
HeapFree(hProcessHeap, 0, pPrinter->pwszDefaultDatatype);
DllFreeSplStr(pPrinter->pwszDefaultDatatype);
HeapFree(hProcessHeap, 0, pPrinter);
DllFreeSplMem(pPrinter);
}
if (hSubKey)
@ -201,11 +211,189 @@ Cleanup:
}
BOOL
_LocalEnumPrintersLevel1(DWORD Flags, LPWSTR Name, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
{
const WCHAR wszComma[] = L",";
DWORD cbName;
DWORD cbComment;
DWORD cbDescription;
DWORD cchComputerName = 0;
DWORD i;
PBYTE pPrinterInfo;
PBYTE pPrinterString;
PLOCAL_PRINTER pPrinter;
PRINTER_INFO_1W PrinterInfo1;
PVOID pRestartKey = NULL;
WCHAR wszComputerName[2 + MAX_COMPUTERNAME_LENGTH + 1 + 1];
DWORD dwOffsets[] = {
FIELD_OFFSET(PRINTER_INFO_1W, pName),
FIELD_OFFSET(PRINTER_INFO_1W, pDescription),
FIELD_OFFSET(PRINTER_INFO_1W, pComment),
MAXDWORD
};
if (Flags & PRINTER_ENUM_NAME)
{
if (Name)
{
// The user supplied a Computer Name (with leading double backslashes) or Print Provider Name.
// Only process what's directed at us and dismiss every other request with ERROR_INVALID_NAME.
if (Name[0] == L'\\' && Name[1] == L'\\')
{
// Prepend slashes to the computer name.
wszComputerName[0] = L'\\';
wszComputerName[1] = L'\\';
// Get the local computer name for comparison.
cchComputerName = MAX_COMPUTERNAME_LENGTH + 1;
if (!GetComputerNameW(&wszComputerName[2], &cchComputerName))
{
ERR("GetComputerNameW failed with error %lu!\n", GetLastError());
return FALSE;
}
// Add the leading slashes to the total length.
cchComputerName += 2;
// Now compare this with the local computer name and reject if it doesn't match.
if (wcsicmp(&Name[2], &wszComputerName[2]) != 0)
{
SetLastError(ERROR_INVALID_NAME);
return FALSE;
}
// Add a trailing backslash to wszComputerName, which will later be prepended in front of the printer names.
wszComputerName[cchComputerName++] = L'\\';
wszComputerName[cchComputerName] = 0;
}
else if (wcsicmp(Name, wszPrintProviderInfo[0]) != 0)
{
// The user supplied a name that cannot be processed by the local print provider.
SetLastError(ERROR_INVALID_NAME);
return FALSE;
}
}
else
{
// The caller wants information about this Print Provider.
// spoolss packs this into an array of information about all Print Providers.
*pcbNeeded = sizeof(PRINTER_INFO_1W);
for (i = 0; i < 3; i++)
*pcbNeeded += (wcslen(wszPrintProviderInfo[i]) + 1) * sizeof(WCHAR);
*pcReturned = 1;
// Check if the supplied buffer is large enough.
if (cbBuf < *pcbNeeded)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
// Copy over the print processor information.
((PPRINTER_INFO_1W)pPrinterEnum)->Flags = 0;
PackStrings(wszPrintProviderInfo, pPrinterEnum, dwOffsets, &pPrinterEnum[*pcbNeeded]);
return TRUE;
}
}
// Count the required buffer size and the number of printers.
for (pPrinter = RtlEnumerateGenericTableWithoutSplaying(&PrinterTable, &pRestartKey); pPrinter; pPrinter = RtlEnumerateGenericTableWithoutSplaying(&PrinterTable, &pRestartKey))
{
// This looks wrong, but is totally right. PRINTER_INFO_1W has three members pName, pComment and pDescription.
// But pComment equals the "Description" registry value while pDescription is concatenated out of pName and pComment.
// On top of this, the computer name is prepended to the printer name if the user supplied the local computer name during the query.
cbName = (wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
cbComment = (wcslen(pPrinter->pwszDescription) + 1) * sizeof(WCHAR);
cbDescription = cchComputerName * sizeof(WCHAR) + cbName + cbComment + sizeof(WCHAR);
*pcbNeeded += sizeof(PRINTER_INFO_1W) + cchComputerName * sizeof(WCHAR) + cbName + cbComment + cbDescription;
*pcReturned++;
}
// Check if the supplied buffer is large enough.
if (cbBuf < *pcbNeeded)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
// Put the strings right after the last PRINTER_INFO_1W structure.
// Due to all the required string processing, we can't just use PackStrings here :(
pPrinterInfo = pPrinterEnum;
pPrinterString = pPrinterEnum + *pcReturned * sizeof(PRINTER_INFO_1W);
// Copy over the printer information.
for (pPrinter = RtlEnumerateGenericTableWithoutSplaying(&PrinterTable, &pRestartKey); pPrinter; pPrinter = RtlEnumerateGenericTableWithoutSplaying(&PrinterTable, &pRestartKey))
{
// FIXME: As for now, the Flags member returns no information.
PrinterInfo1.Flags = 0;
// Copy the printer name.
PrinterInfo1.pName = (PWSTR)pPrinterString;
CopyMemory(pPrinterString, wszComputerName, cchComputerName * sizeof(WCHAR));
pPrinterString += cchComputerName * sizeof(WCHAR);
cbName = (wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
CopyMemory(pPrinterString, pPrinter->pwszPrinterName, cbName);
pPrinterString += cbName;
// Copy the printer comment (equals the "Description" registry value).
PrinterInfo1.pComment = (PWSTR)pPrinterString;
cbComment = (wcslen(pPrinter->pwszDescription) + 1) * sizeof(WCHAR);
CopyMemory(pPrinterString, pPrinter->pwszDescription, cbComment);
pPrinterString += cbComment;
// Copy the description, which for PRINTER_INFO_1W has the form "Name,Comment,"
PrinterInfo1.pDescription = (PWSTR)pPrinterString;
CopyMemory(pPrinterString, wszComputerName, cchComputerName * sizeof(WCHAR));
pPrinterString += cchComputerName * sizeof(WCHAR);
CopyMemory(pPrinterString, pPrinter->pwszPrinterName, cbName - sizeof(WCHAR));
pPrinterString += cbName - sizeof(WCHAR);
CopyMemory(pPrinterString, wszComma, sizeof(WCHAR));
pPrinterString += sizeof(WCHAR);
CopyMemory(pPrinterString, pPrinter->pwszDescription, cbComment - sizeof(WCHAR));
pPrinterString += cbComment - sizeof(WCHAR);
CopyMemory(pPrinterString, wszComma, sizeof(wszComma));
pPrinterString += sizeof(wszComma);
// Finally copy the structure and advance to the next one in the output buffer.
CopyMemory(pPrinterInfo, &PrinterInfo1, sizeof(PRINTER_INFO_1W));
pPrinterInfo += sizeof(PRINTER_INFO_1W);
}
return TRUE;
}
BOOL WINAPI
LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
{
///////////// TODO /////////////////////
return FALSE;
// Do no sanity checks here. This is verified by localspl_apitest!
// Begin counting.
*pcbNeeded = 0;
*pcReturned = 0;
// Think positive :)
SetLastError(ERROR_SUCCESS);
if (Flags & PRINTER_ENUM_LOCAL)
{
// The function behaves quite differently for each level.
if (Level == 1)
return _LocalEnumPrintersLevel1(Flags, Name, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
// TODO: Handle other levels.
// The caller supplied an invalid level.
return FALSE;
}
// Treat it as success if the caller queried no information and we don't need to return any.
return TRUE;
}
BOOL WINAPI
@ -250,7 +438,7 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
*p = 0;
// Get the local computer name for comparison.
cchComputerName = sizeof(wszComputerName) / sizeof(WCHAR);
cchComputerName = _countof(wszComputerName);
if (!GetComputerNameW(wszComputerName, &cchComputerName))
{
ERR("GetComputerNameW failed with error %lu!\n", GetLastError());
@ -286,7 +474,7 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
if (cchPrinterName)
{
// Yes, extract it.
pwszPrinterName = HeapAlloc(hProcessHeap, 0, (cchPrinterName + 1) * sizeof(WCHAR));
pwszPrinterName = DllAllocSplMem((cchPrinterName + 1) * sizeof(WCHAR));
CopyMemory(pwszPrinterName, lpPrinterName, cchPrinterName * sizeof(WCHAR));
pwszPrinterName[cchPrinterName] = 0;
@ -300,7 +488,7 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
}
// Create a new printer handle.
pPrinterHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(LOCAL_PRINTER_HANDLE));
pPrinterHandle = DllAllocSplMem(sizeof(LOCAL_PRINTER_HANDLE));
pPrinterHandle->Printer = pPrinter;
// Check if a datatype was given.
@ -313,12 +501,12 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
goto Cleanup;
}
pPrinterHandle->pwszDatatype = DuplicateStringW(pDefault->pDatatype);
pPrinterHandle->pwszDatatype = AllocSplStr(pDefault->pDatatype);
}
else
{
// Use the default datatype.
pPrinterHandle->pwszDatatype = DuplicateStringW(pPrinter->pwszDefaultDatatype);
pPrinterHandle->pwszDatatype = AllocSplStr(pPrinter->pwszDefaultDatatype);
}
// Check if a DevMode was given, otherwise use the default.
@ -389,7 +577,7 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
}
// Create a new handle that references a printer.
pHandle = HeapAlloc(hProcessHeap, 0, sizeof(LOCAL_HANDLE));
pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE));
pHandle->HandleType = Printer;
pHandle->SpecificHandle = pPrinterHandle;
}
@ -413,7 +601,7 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
p += sizeof("XcvMonitor ") - 1;
///////////// TODO /////////////////////
pHandle = HeapAlloc(hProcessHeap, 0, sizeof(LOCAL_HANDLE));
pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE));
pHandle->HandleType = Monitor;
//pHandle->SpecificHandle = pMonitorHandle;
}
@ -423,7 +611,7 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
p += sizeof("XcvPort ") - 1;
//////////// TODO //////////////////////
pHandle = HeapAlloc(hProcessHeap, 0, sizeof(LOCAL_HANDLE));
pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE));
pHandle->HandleType = Port;
//pHandle->SpecificHandle = pPortHandle;
}
@ -445,13 +633,13 @@ Cleanup:
if (pPrinterHandle)
{
if (pPrinterHandle->pwszDatatype)
HeapFree(hProcessHeap, 0, pPrinterHandle->pwszDatatype);
DllFreeSplStr(pPrinterHandle->pwszDatatype);
HeapFree(hProcessHeap, 0, pPrinterHandle);
DllFreeSplMem(pPrinterHandle);
}
if (pwszPrinterName)
HeapFree(hProcessHeap, 0, pwszPrinterName);
DllFreeSplMem(pwszPrinterName);
return bReturnValue;
}
@ -498,7 +686,7 @@ LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
pDocumentInfo1 = (PDOC_INFO_1W)pDocInfo;
// Create a new job.
pJob = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(LOCAL_JOB));
pJob = DllAllocSplMem(sizeof(LOCAL_JOB));
pJob->Printer = pPrinterHandle->Printer;
// Check if a datatype was given.
@ -511,12 +699,12 @@ LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
goto Cleanup;
}
pJob->pwszDatatype = DuplicateStringW(pDocumentInfo1->pDatatype);
pJob->pwszDatatype = AllocSplStr(pDocumentInfo1->pDatatype);
}
else
{
// Use the printer handle datatype.
pJob->pwszDatatype = DuplicateStringW(pPrinterHandle->pwszDatatype);
pJob->pwszDatatype = AllocSplStr(pPrinterHandle->pwszDatatype);
}
// Copy over printer defaults.
@ -524,17 +712,17 @@ LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
// Copy over supplied information.
if (pDocumentInfo1->pDocName)
pJob->pwszDocumentName = DuplicateStringW(pDocumentInfo1->pDocName);
pJob->pwszDocumentName = AllocSplStr(pDocumentInfo1->pDocName);
if (pDocumentInfo1->pOutputFile)
pJob->pwszOutputFile = DuplicateStringW(pDocumentInfo1->pOutputFile);
pJob->pwszOutputFile = AllocSplStr(pDocumentInfo1->pOutputFile);
// Enqueue the job.
///////////// TODO /////////////////////
Cleanup:
if (pJob)
HeapFree(hProcessHeap, 0, pJob);
DllFreeSplMem(pJob);
return dwReturnValue;
}
@ -584,7 +772,7 @@ LocalClosePrinter(HANDLE hPrinter)
/// Check the handle type, do thoroughful checks on all data fields and clean them.
////////////////////////////////////////
HeapFree(hProcessHeap, 0, pHandle);
DllFreeSplMem(pHandle);
return TRUE;
}

View file

@ -31,7 +31,7 @@ static BOOL
_OpenEnvironment(PCWSTR pEnvironment, PHKEY hKey)
{
const WCHAR wszEnvironmentsKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Environments\\";
const DWORD cchEnvironmentsKey = sizeof(wszEnvironmentsKey) / sizeof(WCHAR) - 1;
const DWORD cchEnvironmentsKey = _countof(wszEnvironmentsKey) - 1;
BOOL bReturnValue = FALSE;
DWORD cchEnvironment;
@ -44,10 +44,10 @@ _OpenEnvironment(PCWSTR pEnvironment, PHKEY hKey)
// Construct the registry key of the demanded environment.
cchEnvironment = wcslen(pEnvironment);
pwszEnvironmentKey = HeapAlloc(hProcessHeap, 0, (cchEnvironmentsKey + cchEnvironment + 1) * sizeof(WCHAR));
pwszEnvironmentKey = DllAllocSplMem((cchEnvironmentsKey + cchEnvironment + 1) * sizeof(WCHAR));
if (!pwszEnvironmentKey)
{
ERR("HeapAlloc failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
goto Cleanup;
}
@ -71,7 +71,7 @@ _OpenEnvironment(PCWSTR pEnvironment, PHKEY hKey)
Cleanup:
if (pwszEnvironmentKey)
HeapFree(hProcessHeap, 0, pwszEnvironmentKey);
DllFreeSplMem(pwszEnvironmentKey);
return bReturnValue;
}
@ -182,10 +182,10 @@ InitializePrintProcessorTable()
}
// Allocate a temporary buffer for the Print Processor names.
pwszPrintProcessorName = HeapAlloc(hProcessHeap, 0, (cchMaxSubKey + 1) * sizeof(WCHAR));
pwszPrintProcessorName = DllAllocSplMem((cchMaxSubKey + 1) * sizeof(WCHAR));
if (!pwszPrintProcessorName)
{
ERR("HeapAlloc failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
goto Cleanup;
}
@ -202,15 +202,15 @@ InitializePrintProcessorTable()
if (pPrintProcessor)
{
if (pPrintProcessor->pwszName)
HeapFree(hProcessHeap, 0, pPrintProcessor->pwszName);
DllFreeSplStr(pPrintProcessor->pwszName);
HeapFree(hProcessHeap, 0, pPrintProcessor);
DllFreeSplMem(pPrintProcessor);
pPrintProcessor = NULL;
}
if (pDatatypesInfo1)
{
HeapFree(hProcessHeap, 0, pDatatypesInfo1);
DllFreeSplMem(pDatatypesInfo1);
pDatatypesInfo1 = NULL;
}
@ -259,8 +259,8 @@ InitializePrintProcessorTable()
}
// Create a new LOCAL_PRINT_PROCESSOR structure for it.
pPrintProcessor = HeapAlloc(hProcessHeap, 0, sizeof(LOCAL_PRINT_PROCESSOR));
pPrintProcessor->pwszName = DuplicateStringW(pwszPrintProcessorName);
pPrintProcessor = DllAllocSplMem(sizeof(LOCAL_PRINT_PROCESSOR));
pPrintProcessor->pwszName = AllocSplStr(pwszPrintProcessorName);
// Get and verify all its function pointers.
pPrintProcessor->pfnClosePrintProcessor = (PClosePrintProcessor)GetProcAddress(hinstPrintProcessor, "ClosePrintProcessor");
@ -307,10 +307,10 @@ InitializePrintProcessorTable()
// Get all supported datatypes.
pPrintProcessor->pfnEnumPrintProcessorDatatypesW(NULL, NULL, 1, NULL, 0, &cbDatatypes, &dwDatatypes);
pDatatypesInfo1 = HeapAlloc(hProcessHeap, 0, cbDatatypes);
pDatatypesInfo1 = DllAllocSplMem(cbDatatypes);
if (!pDatatypesInfo1)
{
ERR("HeapAlloc failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
goto Cleanup;
}
@ -325,7 +325,7 @@ InitializePrintProcessorTable()
for (j = 0; j < dwDatatypes; j++)
{
pwszDatatype = DuplicateStringW(pDatatypesInfo1->pName);
pwszDatatype = AllocSplStr(pDatatypesInfo1->pName);
if (!RtlInsertElementGenericTable(&pPrintProcessor->DatatypeTable, pDatatypesInfo1->pName, sizeof(PWSTR), NULL))
{
@ -350,21 +350,21 @@ InitializePrintProcessorTable()
Cleanup:
if (pwszDatatype)
HeapFree(hProcessHeap, 0, pwszDatatype);
DllFreeSplStr(pwszDatatype);
if (pDatatypesInfo1)
HeapFree(hProcessHeap, 0, pDatatypesInfo1);
DllFreeSplMem(pDatatypesInfo1);
if (pPrintProcessor)
{
if (pPrintProcessor->pwszName)
HeapFree(hProcessHeap, 0, pPrintProcessor->pwszName);
DllFreeSplStr(pPrintProcessor->pwszName);
HeapFree(hProcessHeap, 0, pPrintProcessor);
DllFreeSplMem(pPrintProcessor);
}
if (pwszPrintProcessorName)
HeapFree(hProcessHeap, 0, pwszPrintProcessorName);
DllFreeSplStr(pwszPrintProcessorName);
if (hSubSubKey)
RegCloseKey(hSubSubKey);
@ -482,7 +482,6 @@ LocalEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE
PBYTE pCurrentOutputPrintProcessor;
PBYTE pCurrentOutputPrintProcessorInfo;
PRINTPROCESSOR_INFO_1W PrintProcessorInfo1;
PWSTR pwszEnvironmentKey = NULL;
PWSTR pwszTemp = NULL;
// Sanity checks
@ -520,10 +519,10 @@ LocalEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE
}
// Allocate a temporary buffer to let RegEnumKeyExW succeed.
pwszTemp = HeapAlloc(hProcessHeap, 0, (cchMaxSubKey + 1) * sizeof(WCHAR));
pwszTemp = DllAllocSplMem((cchMaxSubKey + 1) * sizeof(WCHAR));
if (!pwszTemp)
{
ERR("HeapAlloc failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
goto Cleanup;
}
@ -585,10 +584,7 @@ LocalEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE
Cleanup:
if (pwszTemp)
HeapFree(hProcessHeap, 0, pwszTemp);
if (pwszEnvironmentKey)
HeapFree(hProcessHeap, 0, pwszEnvironmentKey);
DllFreeSplMem(pwszTemp);
if (hSubKey)
RegCloseKey(hSubKey);
@ -634,13 +630,12 @@ BOOL WINAPI
LocalGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded)
{
const WCHAR wszPath[] = L"\\PRTPROCS\\";
const DWORD cchPath = sizeof(wszPath) / sizeof(WCHAR) - 1;
const DWORD cchPath = _countof(wszPath) - 1;
BOOL bReturnValue = FALSE;
DWORD cbDataWritten;
HKEY hKey = NULL;
LONG lStatus;
PWSTR pwszEnvironmentKey = NULL;
// Sanity checks
if (Level != 1)
@ -695,9 +690,6 @@ LocalGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
bReturnValue = TRUE;
Cleanup:
if (pwszEnvironmentKey)
HeapFree(hProcessHeap, 0, pwszEnvironmentKey);
if (hKey)
RegCloseKey(hKey);

View file

@ -11,7 +11,7 @@
* @name AllocAndRegQueryWSZ
*
* Queries a REG_SZ value in the registry, allocates memory for it and returns a buffer containing the value.
* You have to free this buffer using HeapFree.
* You have to free this buffer using DllFreeSplMem.
*
* @param hKey
* HKEY variable of the key opened with RegOpenKeyExW.
@ -38,10 +38,10 @@ AllocAndRegQueryWSZ(HKEY hKey, PCWSTR pwszValueName)
}
// Allocate it.
pwszValue = HeapAlloc(hProcessHeap, 0, cbNeeded);
pwszValue = DllAllocSplMem(cbNeeded);
if (!pwszValue)
{
ERR("HeapAlloc failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
return NULL;
}
@ -50,63 +50,31 @@ AllocAndRegQueryWSZ(HKEY hKey, PCWSTR pwszValueName)
if (lStatus != ERROR_SUCCESS)
{
ERR("RegQueryValueExW failed with status %ld!\n", lStatus);
HeapFree(hProcessHeap, 0, pwszValue);
DllFreeSplMem(pwszValue);
return NULL;
}
return pwszValue;
}
/**
* @name DuplicateStringW
*
* Allocates memory for a Unicode string and copies the input string into it.
* Equivalent of wcsdup, but the returned buffer must be freed with HeapFree instead of free.
*
* @param pwszInput
* The input string to copy
*
* @return
* Pointer to the copied string or NULL if no memory could be allocated.
*/
PWSTR
DuplicateStringW(PCWSTR pwszInput)
{
DWORD cchInput;
PWSTR pwszOutput;
cchInput = wcslen(pwszInput);
pwszOutput = HeapAlloc(hProcessHeap, 0, (cchInput + 1) * sizeof(WCHAR));
if (!pwszOutput)
{
ERR("HeapAlloc failed with error %lu!\n", GetLastError());
return NULL;
}
CopyMemory(pwszOutput, pwszInput, (cchInput + 1) * sizeof(WCHAR));
return pwszOutput;
}
/**
* @name GenericTableAllocateRoutine
*
* RTL_GENERIC_ALLOCATE_ROUTINE for all our RTL_GENERIC_TABLEs, using HeapAlloc.
* RTL_GENERIC_ALLOCATE_ROUTINE for all our RTL_GENERIC_TABLEs, using DllAllocSplMem.
*/
PVOID NTAPI
GenericTableAllocateRoutine(PRTL_GENERIC_TABLE Table, CLONG ByteSize)
{
return HeapAlloc(hProcessHeap, 0, ByteSize);
return DllAllocSplMem(ByteSize);
}
/**
* @name GenericTableFreeRoutine
*
* RTL_GENERIC_FREE_ROUTINE for all our RTL_GENERIC_TABLEs, using HeapFree.
* RTL_GENERIC_FREE_ROUTINE for all our RTL_GENERIC_TABLEs, using DllFreeSplMem.
*/
VOID NTAPI
GenericTableFreeRoutine(PRTL_GENERIC_TABLE Table, PVOID Buffer)
{
HeapFree(hProcessHeap, 0, Buffer);
DllFreeSplMem(Buffer);
}

View file

@ -1,4 +1,6 @@
include_directories(${REACTOS_SOURCE_DIR}/win32ss/printing/include)
list(APPEND SOURCE
fpEnumPrinters.c
main.c)
@ -6,6 +8,6 @@ list(APPEND SOURCE
add_library(localspl_apitest.dll SHARED ${SOURCE})
target_link_libraries(localspl_apitest.dll wine ${PSEH_LIB})
set_module_type(localspl_apitest.dll win32dll)
add_importlibs(localspl_apitest.dll msvcrt kernel32 ntdll)
add_importlibs(localspl_apitest.dll spoolss msvcrt kernel32 ntdll)
set_target_properties(localspl_apitest.dll PROPERTIES SUFFIX "")
add_cd_file(TARGET localspl_apitest.dll DESTINATION reactos/bin FOR all)

View file

@ -16,15 +16,19 @@
#include <winsplp.h>
#include "../localspl_apitest.h"
#include <spoolss.h>
START_TEST(fpEnumPrinters)
{
DWORD cbNeeded;
DWORD cbTemp;
DWORD dwReturned;
DWORD i;
HMODULE hLocalspl;
PInitializePrintProvidor pfnInitializePrintProvidor;
PRINTPROVIDOR pp;
PPRINTER_INFO_1W pPrinterInfo1;
PVOID pMem;
// Get us a handle to the loaded localspl.dll.
hLocalspl = GetModuleHandleW(L"localspl");
@ -69,4 +73,88 @@ START_TEST(fpEnumPrinters)
ok(wcscmp(pPrinterInfo1->pName, L"Windows NT Local Print Providor") == 0, "pPrinterInfo1->pName is \"%S\"!\n", pPrinterInfo1->pName);
ok(wcscmp(pPrinterInfo1->pDescription, L"Windows NT Local Printers") == 0, "pPrinterInfo1->pDescription is \"%S\"!\n", pPrinterInfo1->pDescription);
ok(wcscmp(pPrinterInfo1->pComment, L"Locally connected Printers") == 0, "pPrinterInfo1->pComment is \"%S\"!\n", pPrinterInfo1->pComment);
// Level 7 is the highest supported for localspl under Windows Server 2003.
// Higher levels need to fail, but they don't set an error code, just cbNeeded to 0.
cbNeeded = 0xDEADBEEF;
dwReturned = 0xDEADBEEF;
SetLastError(0xDEADBEEF);
ok(!pp.fpEnumPrinters(PRINTER_ENUM_LOCAL, NULL, 8, NULL, 0, &cbNeeded, &dwReturned), "fpEnumPrinters returns TRUE!\n");
ok(GetLastError() == ERROR_SUCCESS, "fpEnumPrinters returns error %lu!\n", GetLastError());
ok(cbNeeded == 0, "cbNeeded is %lu!\n", cbNeeded);
ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
// Verify that all valid levels work.
// In contrast to EnumPrintersW, which only accepts levels 0, 1, 2, 4 and 5, localspl returns information for level 0 to 7.
for (i = 0; i <= 7; i++)
{
// FIXME: For some reason, using SEH here works only once.
// We experience a hang in the testing process when you run the test again for a second time without restarting spoolsv.
#if 0
// Try with no valid arguments at all.
// This scenario is usually caugt by RPC, so it just raises an exception here.
_SEH2_TRY
{
dwReturned = 0;
pp.fpEnumPrinters(PRINTER_ENUM_LOCAL, NULL, i, NULL, 0, NULL, NULL);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
dwReturned = _SEH2_GetExceptionCode();
}
_SEH2_END;
ok(dwReturned == EXCEPTION_ACCESS_VIOLATION, "dwReturned is %lu for Level %lu!\n", dwReturned, i);
#endif
// Now get the required buffer size.
cbNeeded = 0xDEADBEEF;
dwReturned = 0xDEADBEEF;
SetLastError(0xDEADBEEF);
ok(!pp.fpEnumPrinters(PRINTER_ENUM_LOCAL, NULL, i, NULL, 0, &cbNeeded, &dwReturned), "fpEnumPrinters returns TRUE for Level %lu!\n", i);
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "fpEnumPrinters returns error %lu for Level %lu!\n", GetLastError(), i);
ok(cbNeeded > 0, "cbNeeded is 0 for Level %lu!\n", i);
ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, i);
#if 0
// Now provide the demanded size, but no buffer. This also mustn't touch cbNeeded.
// This scenario is also caught by RPC and we just have an exception here.
_SEH2_TRY
{
dwReturned = 0;
pp.fpEnumPrinters(PRINTER_ENUM_LOCAL, NULL, i, NULL, cbNeeded, &cbTemp, &dwReturned);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
dwReturned = _SEH2_GetExceptionCode();
}
_SEH2_END;
ok(dwReturned == EXCEPTION_ACCESS_VIOLATION, "dwReturned is %lu for Level %lu!\n", dwReturned, i);
ok(cbNeeded == cbTemp, "cbNeeded is %lu, cbTemp is %lu for Level %lu!\n", cbNeeded, cbTemp, i);
#endif
// Finally use the function as intended and aim for success!
pMem = DllAllocSplMem(cbNeeded);
SetLastError(0xDEADBEEF);
ok(pp.fpEnumPrinters(PRINTER_ENUM_LOCAL, NULL, i, pMem, cbNeeded, &cbTemp, &dwReturned), "fpEnumPrinters returns FALSE for Level %lu!\n", i);
// This is crazy. For level 3, fpEnumPrinters always returns ERROR_INSUFFICIENT_BUFFER even if we supply a buffer large enough.
if (i == 3)
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "fpEnumPrinters returns error %lu for Level %lu!\n", GetLastError(), i);
else
ok(GetLastError() == ERROR_SUCCESS, "fpEnumPrinters returns error %lu for Level %lu!\n", GetLastError(), i);
DllFreeSplMem(pMem);
}
// fpEnumPrinters has to succeed independent of the level (valid or not) if we query no information.
for (i = 0; i < 10; i++)
{
SetLastError(0xDEADBEEF);
ok(pp.fpEnumPrinters(0, NULL, i, NULL, 0, &cbNeeded, &dwReturned), "fpEnumPrinters returns FALSE for Level %lu!\n", i);
ok(GetLastError() == ERROR_SUCCESS, "fpEnumPrinters returns error %lu for Level %lu!\n", GetLastError(), i);
ok(cbNeeded == 0, "cbNeeded is %lu for Level %lu!\n", cbNeeded, i);
ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, i);
}
}

View file

@ -19,7 +19,6 @@
#include <winspool.h>
#include <winsplp.h>
#include "../localspl_apitest.h"
//#define NDEBUG

View file

@ -40,14 +40,17 @@
static void
_RunRemoteTest(const char* szTestName)
{
BOOL bSuccessful = FALSE;
char szBuffer[1024];
DWORD cbRead;
DWORD cbWritten;
HANDLE hCommandPipe;
HANDLE hOutputPipe;
HANDLE hCommandPipe = INVALID_HANDLE_VALUE;
HANDLE hFind = NULL;
HANDLE hOutputPipe = INVALID_HANDLE_VALUE;
PWSTR p;
SC_HANDLE hSC;
SC_HANDLE hService;
SC_HANDLE hSC = NULL;
SC_HANDLE hService = NULL;
SERVICE_STATUS ServiceStatus;
WCHAR wszFilePath[MAX_PATH + 20];
WIN32_FIND_DATAW fd;
@ -59,7 +62,7 @@ _RunRemoteTest(const char* szTestName)
if (!GetModuleFileNameW(NULL, wszFilePath, MAX_PATH))
{
skip("GetModuleFileNameW failed with error %lu!\n", GetLastError());
return;
goto Cleanup;
}
// Replace the extension.
@ -67,16 +70,17 @@ _RunRemoteTest(const char* szTestName)
if (!p)
{
skip("File path has no file extension: %S\n", wszFilePath);
return;
goto Cleanup;
}
wcscpy(p, L".dll");
// Check if the corresponding DLL file exists.
if (!FindFirstFileW(wszFilePath, &fd))
hFind = FindFirstFileW(wszFilePath, &fd);
if (!hFind)
{
skip("My DLL file \"%S\" does not exist!\n", wszFilePath);
return;
goto Cleanup;
}
// Change the extension back to .exe and add the parameters.
@ -87,9 +91,31 @@ _RunRemoteTest(const char* szTestName)
if (!hSC)
{
skip("OpenSCManagerW failed with error %lu!\n", GetLastError());
return;
goto Cleanup;
}
// Ensure that the spooler service is running.
hService = OpenServiceW(hSC, L"spooler", SERVICE_QUERY_STATUS);
if (!hService)
{
skip("OpenServiceW failed for the spooler service with error %lu!\n", GetLastError());
goto Cleanup;
}
if (!QueryServiceStatus(hService, &ServiceStatus))
{
skip("QueryServiceStatus failed for the spooler service with error %lu!\n", GetLastError());
goto Cleanup;
}
if (ServiceStatus.dwCurrentState != SERVICE_RUNNING)
{
skip("Spooler Service is not running!\n");
goto Cleanup;
}
CloseServiceHandle(hService);
// Try to open the service if we've created it in a previous run.
hService = OpenServiceW(hSC, SERVICE_NAME, SERVICE_ALL_ACCESS);
if (!hService)
@ -101,13 +127,13 @@ _RunRemoteTest(const char* szTestName)
if (!hService)
{
skip("CreateServiceW failed with error %lu!\n", GetLastError());
return;
goto Cleanup;
}
}
else
{
skip("OpenServiceW failed with error %lu!\n", GetLastError());
return;
goto Cleanup;
}
}
@ -116,57 +142,70 @@ _RunRemoteTest(const char* szTestName)
if (hCommandPipe == INVALID_HANDLE_VALUE)
{
skip("CreateNamedPipeW failed for the command pipe with error %lu!\n", GetLastError());
return;
goto Cleanup;
}
hOutputPipe = CreateNamedPipeW(OUTPUT_PIPE_NAME, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 1024, 1024, 10000, NULL);
if (hOutputPipe == INVALID_HANDLE_VALUE)
{
skip("CreateNamedPipeW failed for the output pipe with error %lu!\n", GetLastError());
return;
goto Cleanup;
}
// Start the service with "service" and a dummy parameter (to distinguish it from a call by rosautotest to localspl_apitest:service)
if (!StartServiceW(hService, 0, NULL))
{
skip("StartServiceW failed with error %lu!\n", GetLastError());
return;
goto Cleanup;
}
CloseServiceHandle(hService);
CloseServiceHandle(hSC);
// Wait till it has injected the DLL and the DLL expects its test name.
if (!ConnectNamedPipe(hCommandPipe, NULL) && GetLastError() != ERROR_PIPE_CONNECTED)
{
skip("ConnectNamedPipe failed for the command pipe with error %lu!\n", GetLastError());
return;
goto Cleanup;
}
// Send the test name.
if (!WriteFile(hCommandPipe, szTestName, strlen(szTestName) + sizeof(char), &cbWritten, NULL))
{
skip("WriteFile failed with error %lu!\n", GetLastError());
return;
goto Cleanup;
}
CloseHandle(hCommandPipe);
// Now wait for the DLL to connect to the output pipe.
if (!ConnectNamedPipe(hOutputPipe, NULL))
{
skip("ConnectNamedPipe failed for the output pipe with error %lu!\n", GetLastError());
return;
goto Cleanup;
}
// Get all testing messages from the pipe and output them on stdout.
while (ReadFile(hOutputPipe, szBuffer, sizeof(szBuffer), &cbRead, NULL) && cbRead)
fwrite(szBuffer, sizeof(char), cbRead, stdout);
CloseHandle(hOutputPipe);
bSuccessful = TRUE;
// Prevent the testing framework from outputting a "0 tests executed" line here.
ExitProcess(0);
Cleanup:
if (hCommandPipe)
CloseHandle(hCommandPipe);
if (hOutputPipe)
CloseHandle(hOutputPipe);
if (hFind)
FindClose(hFind);
if (hService)
CloseServiceHandle(hService);
if (hSC)
CloseServiceHandle(hSC);
// If we successfully received test output through the named pipe, we have also output a summary line already.
// Prevent the testing framework from outputting another "0 tests executed" line in this case.
if (bSuccessful)
ExitProcess(0);
}
START_TEST(fpEnumPrinters)

View file

@ -3,6 +3,7 @@ include_directories(${REACTOS_SOURCE_DIR}/win32ss/printing/include)
list(APPEND SOURCE
PackStrings.c
ReallocSplStr.c
SplInitializeWinSpoolDrv.c
testlist.c)

View file

@ -0,0 +1,66 @@
/*
* PROJECT: ReactOS Spooler Router API Tests
* LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
* PURPOSE: Tests for ReallocSplStr
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
*/
#include <apitest.h>
#define WIN32_NO_STATUS
#include <windef.h>
#include <winbase.h>
#include <spoolss.h>
START_TEST(ReallocSplStr)
{
const WCHAR wszTestString1[] = L"Test";
const WCHAR wszTestString2[] = L"New";
DWORD dwResult;
PWSTR pwszBackup;
PWSTR pwszTest;
// Verify that ReallocSplStr raises an exception if all parameters are NULL.
_SEH2_TRY
{
dwResult = 0;
ReallocSplStr(NULL, NULL);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
dwResult = _SEH2_GetExceptionCode();
}
_SEH2_END;
ok(dwResult == EXCEPTION_ACCESS_VIOLATION, "dwResult is %lx!\n", dwResult);
// Allocate a string for testing.
pwszTest = AllocSplStr(wszTestString1);
if (!pwszTest)
{
skip("AllocSplStr failed with error %lu!\n", GetLastError());
return;
}
// Verify that ReallocSplStr frees the old string even if pwszInput is NULL.
ok(ReallocSplStr(&pwszTest, NULL), "ReallocSplStr is FALSE!\n");
ok(pwszTest == NULL, "pwszTest is %p\n", pwszTest);
// Now verify that ReallocSplStr copies the new string into a new block and frees the old one.
pwszBackup = pwszTest;
ok(ReallocSplStr(&pwszTest, wszTestString2), "ReallocSplStr is FALSE!\n");
ok(wcscmp(pwszTest, wszTestString2) == 0, "New string was not copied into pwszTest!\n");
_SEH2_TRY
{
dwResult = (DWORD)wcscmp(pwszBackup, wszTestString1);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
dwResult = _SEH2_GetExceptionCode();
}
_SEH2_END;
ok(dwResult == EXCEPTION_ACCESS_VIOLATION, "dwResult is %lx!\n", dwResult);
}

View file

@ -15,9 +15,14 @@
START_TEST(SplInitializeWinSpoolDrv)
{
HINSTANCE hWinspool;
void* Table[9];
PVOID Table[9];
hWinspool = LoadLibraryW(L"winspool.drv");
if (!hWinspool)
{
skip("Could not load winspool.drv, last error is %lu!\n", GetLastError());
return;
}
ok(SplInitializeWinSpoolDrv(Table), "SplInitializeWinSpoolDrv returns FALSE!\n");
ok(Table[0] == GetProcAddress(hWinspool, "OpenPrinterW"), "Table[0] is %p\n", Table[0]);

View file

@ -11,11 +11,13 @@
#include <apitest.h>
extern void func_PackStrings(void);
extern void func_ReallocSplStr(void);
extern void func_SplInitializeWinSpoolDrv(void);
const struct test winetest_testlist[] =
{
{ "PackStrings", func_PackStrings },
{ "ReallocSplStr", func_ReallocSplStr },
{ "SplInitializeWinSpoolDrv", func_SplInitializeWinSpoolDrv },
{ 0, 0 }