diff --git a/reactos/win32ss/printing/base/spoolss/CMakeLists.txt b/reactos/win32ss/printing/base/spoolss/CMakeLists.txt index fbf989587a2..5a68b768685 100644 --- a/reactos/win32ss/printing/base/spoolss/CMakeLists.txt +++ b/reactos/win32ss/printing/base/spoolss/CMakeLists.txt @@ -4,6 +4,7 @@ spec2def(spoolss.dll spoolss.spec ADD_IMPORTLIB) list(APPEND SOURCE context.c main.c + memory.c precomp.h tools.c) diff --git a/reactos/win32ss/printing/base/spoolss/main.c b/reactos/win32ss/printing/base/spoolss/main.c index 39a45855209..2a83055c4f0 100644 --- a/reactos/win32ss/printing/base/spoolss/main.c +++ b/reactos/win32ss/printing/base/spoolss/main.c @@ -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() { diff --git a/reactos/win32ss/printing/base/spoolss/memory.c b/reactos/win32ss/printing/base/spoolss/memory.c new file mode 100644 index 00000000000..d16a8a3055d --- /dev/null +++ b/reactos/win32ss/printing/base/spoolss/memory.c @@ -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 + */ + +#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; +} diff --git a/reactos/win32ss/printing/base/spoolss/precomp.h b/reactos/win32ss/printing/base/spoolss/precomp.h index 25f43d72505..4c0cd28beca 100644 --- a/reactos/win32ss/printing/base/spoolss/precomp.h +++ b/reactos/win32ss/printing/base/spoolss/precomp.h @@ -16,10 +16,15 @@ #include #include +#include + #include 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 diff --git a/reactos/win32ss/printing/base/spoolss/spoolss.spec b/reactos/win32ss/printing/base/spoolss/spoolss.spec index 16e4b153499..847f8a727b9 100644 --- a/reactos/win32ss/printing/base/spoolss/spoolss.spec +++ b/reactos/win32ss/printing/base/spoolss/spoolss.spec @@ -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 diff --git a/reactos/win32ss/printing/base/winspool/winspool.spec b/reactos/win32ss/printing/base/winspool/winspool.spec index 8b48c113ff5..4a450e35887 100644 --- a/reactos/win32ss/printing/base/winspool/winspool.spec +++ b/reactos/win32ss/printing/base/winspool/winspool.spec @@ -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) diff --git a/reactos/win32ss/printing/include/spoolss.h b/reactos/win32ss/printing/include/spoolss.h index ad8157dd217..7981f5f67d4 100644 --- a/reactos/win32ss/printing/include/spoolss.h +++ b/reactos/win32ss/printing/include/spoolss.h @@ -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 diff --git a/reactos/win32ss/printing/providers/localspl/CMakeLists.txt b/reactos/win32ss/printing/providers/localspl/CMakeLists.txt index 1280f6d4e84..11a52a8cf86 100644 --- a/reactos/win32ss/printing/providers/localspl/CMakeLists.txt +++ b/reactos/win32ss/printing/providers/localspl/CMakeLists.txt @@ -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) diff --git a/reactos/win32ss/printing/providers/localspl/jobs.c b/reactos/win32ss/printing/providers/localspl/jobs.c index 7e36f83677b..7cce869c28f 100644 --- a/reactos/win32ss/printing/providers/localspl/jobs.c +++ b/reactos/win32ss/printing/providers/localspl/jobs.c @@ -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; } diff --git a/reactos/win32ss/printing/providers/localspl/main.c b/reactos/win32ss/printing/providers/localspl/main.c index a0bd9235718..2565b1c27d4 100644 --- a/reactos/win32ss/printing/providers/localspl/main.c +++ b/reactos/win32ss/printing/providers/localspl/main.c @@ -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; } diff --git a/reactos/win32ss/printing/providers/localspl/precomp.h b/reactos/win32ss/printing/providers/localspl/precomp.h index 6af7e4e1220..cb08315bbb3 100644 --- a/reactos/win32ss/printing/providers/localspl/precomp.h +++ b/reactos/win32ss/printing/providers/localspl/precomp.h @@ -10,6 +10,7 @@ #define WIN32_NO_STATUS #include +#include #include #include @@ -20,6 +21,8 @@ #include #include +#include + #include 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); diff --git a/reactos/win32ss/printing/providers/localspl/printers.c b/reactos/win32ss/printing/providers/localspl/printers.c index 9149f52fd04..4d8891c3ff3 100644 --- a/reactos/win32ss/printing/providers/localspl/printers.c +++ b/reactos/win32ss/printing/providers/localspl/printers.c @@ -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; } diff --git a/reactos/win32ss/printing/providers/localspl/printprocessors.c b/reactos/win32ss/printing/providers/localspl/printprocessors.c index ea29a00e7f3..602dd830d4a 100644 --- a/reactos/win32ss/printing/providers/localspl/printprocessors.c +++ b/reactos/win32ss/printing/providers/localspl/printprocessors.c @@ -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); diff --git a/reactos/win32ss/printing/providers/localspl/tools.c b/reactos/win32ss/printing/providers/localspl/tools.c index fa0b7338d71..10515dbfd34 100644 --- a/reactos/win32ss/printing/providers/localspl/tools.c +++ b/reactos/win32ss/printing/providers/localspl/tools.c @@ -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); } diff --git a/rostests/apitests/localspl/dll/CMakeLists.txt b/rostests/apitests/localspl/dll/CMakeLists.txt index 08b50d8d8e3..76e6a434075 100644 --- a/rostests/apitests/localspl/dll/CMakeLists.txt +++ b/rostests/apitests/localspl/dll/CMakeLists.txt @@ -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) diff --git a/rostests/apitests/localspl/dll/fpEnumPrinters.c b/rostests/apitests/localspl/dll/fpEnumPrinters.c index 657dbd7a85e..897261691ad 100644 --- a/rostests/apitests/localspl/dll/fpEnumPrinters.c +++ b/rostests/apitests/localspl/dll/fpEnumPrinters.c @@ -16,15 +16,19 @@ #include #include "../localspl_apitest.h" +#include 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); + } } diff --git a/rostests/apitests/localspl/dll/main.c b/rostests/apitests/localspl/dll/main.c index 4a558e592bb..0a0e1b1c62d 100644 --- a/rostests/apitests/localspl/dll/main.c +++ b/rostests/apitests/localspl/dll/main.c @@ -19,7 +19,6 @@ #include #include - #include "../localspl_apitest.h" //#define NDEBUG diff --git a/rostests/apitests/localspl/tests.c b/rostests/apitests/localspl/tests.c index d733ea0a15c..9dd93245722 100644 --- a/rostests/apitests/localspl/tests.c +++ b/rostests/apitests/localspl/tests.c @@ -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) diff --git a/rostests/apitests/spoolss/CMakeLists.txt b/rostests/apitests/spoolss/CMakeLists.txt index 4e70a16650f..35e37f71867 100644 --- a/rostests/apitests/spoolss/CMakeLists.txt +++ b/rostests/apitests/spoolss/CMakeLists.txt @@ -3,6 +3,7 @@ include_directories(${REACTOS_SOURCE_DIR}/win32ss/printing/include) list(APPEND SOURCE PackStrings.c + ReallocSplStr.c SplInitializeWinSpoolDrv.c testlist.c) diff --git a/rostests/apitests/spoolss/ReallocSplStr.c b/rostests/apitests/spoolss/ReallocSplStr.c new file mode 100644 index 00000000000..d6827ffdaca --- /dev/null +++ b/rostests/apitests/spoolss/ReallocSplStr.c @@ -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 + */ + +#include + +#define WIN32_NO_STATUS +#include +#include +#include + +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); +} diff --git a/rostests/apitests/spoolss/SplInitializeWinSpoolDrv.c b/rostests/apitests/spoolss/SplInitializeWinSpoolDrv.c index 6415aac052e..c94ade8499a 100644 --- a/rostests/apitests/spoolss/SplInitializeWinSpoolDrv.c +++ b/rostests/apitests/spoolss/SplInitializeWinSpoolDrv.c @@ -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]); diff --git a/rostests/apitests/spoolss/testlist.c b/rostests/apitests/spoolss/testlist.c index b35127fa4fc..82f57b5afb3 100644 --- a/rostests/apitests/spoolss/testlist.c +++ b/rostests/apitests/spoolss/testlist.c @@ -11,11 +11,13 @@ #include 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 }