[LOCALSPL_APITEST]
authorColin Finck <colin@reactos.org>
Tue, 9 Jun 2015 13:22:25 +0000 (13:22 +0000)
committerColin Finck <colin@reactos.org>
Tue, 9 Jun 2015 13:22:25 +0000 (13:22 +0000)
- 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

22 files changed:
reactos/win32ss/printing/base/spoolss/CMakeLists.txt
reactos/win32ss/printing/base/spoolss/main.c
reactos/win32ss/printing/base/spoolss/memory.c [new file with mode: 0644]
reactos/win32ss/printing/base/spoolss/precomp.h
reactos/win32ss/printing/base/spoolss/spoolss.spec
reactos/win32ss/printing/base/winspool/winspool.spec
reactos/win32ss/printing/include/spoolss.h
reactos/win32ss/printing/providers/localspl/CMakeLists.txt
reactos/win32ss/printing/providers/localspl/jobs.c
reactos/win32ss/printing/providers/localspl/main.c
reactos/win32ss/printing/providers/localspl/precomp.h
reactos/win32ss/printing/providers/localspl/printers.c
reactos/win32ss/printing/providers/localspl/printprocessors.c
reactos/win32ss/printing/providers/localspl/tools.c
rostests/apitests/localspl/dll/CMakeLists.txt
rostests/apitests/localspl/dll/fpEnumPrinters.c
rostests/apitests/localspl/dll/main.c
rostests/apitests/localspl/tests.c
rostests/apitests/spoolss/CMakeLists.txt
rostests/apitests/spoolss/ReallocSplStr.c [new file with mode: 0644]
rostests/apitests/spoolss/SplInitializeWinSpoolDrv.c
rostests/apitests/spoolss/testlist.c

index fbf9895..5a68b76 100644 (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)
 
index 39a4585..2a83055 100644 (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()
 {
diff --git a/reactos/win32ss/printing/base/spoolss/memory.c b/reactos/win32ss/printing/base/spoolss/memory.c
new file mode 100644 (file)
index 0000000..d16a8a3
--- /dev/null
@@ -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;
+}
index 25f43d7..4c0cd28 100644 (file)
 #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
index 16e4b15..847f8a7 100644 (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
 @ 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
 @ stub SplCommitSpoolData
 @ stub SplDriverUnloadComplete
 @ stub SplGetSpoolFileInfo
-@ stub SplInitializeWinSpoolDrv
+@ stdcall SplInitializeWinSpoolDrv(ptr)
 @ stub SplIsSessionZero
-@ stub SplIsUpgrade
+@ stdcall SplIsUpgrade()
 @ stub SplPowerEvent
 @ stub SplProcessPnPEvent
 @ stub SplPromptUIInUsersSession
index 8b48c11..4a450e3 100644 (file)
-@ 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)
index ad8157d..7981f5f 100644 (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
index 1280f6d..11a52a8 100644 (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)
index 7e36f83..7cce869 100644 (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;
 }
index a0bd923..2565b1c 100644 (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;
 }
index 6af7e4e..cb08315 100644 (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);
 
index 9149f52..4d8891c 100644 (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;
 }
index ea29a00..602dd83 100644 (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);
 
index fa0b733..10515db 100644 (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);
 }
index 08b50d8..76e6a43 100644 (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)
index 657dbd7..8972616 100644 (file)
 #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);
+    }
 }
index 4a558e5..0a0e1b1 100644 (file)
@@ -19,7 +19,6 @@
 #include <winspool.h>
 #include <winsplp.h>
 
-
 #include "../localspl_apitest.h"
 
 //#define NDEBUG
index d733ea0..9dd9324 100644 (file)
 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;
+
+Cleanup:
+    if (hCommandPipe)
+        CloseHandle(hCommandPipe);
+
+    if (hOutputPipe)
+        CloseHandle(hOutputPipe);
+
+    if (hFind)
+        FindClose(hFind);
+
+    if (hService)
+        CloseServiceHandle(hService);
+
+    if (hSC)
+        CloseServiceHandle(hSC);
 
-    // Prevent the testing framework from outputting a "0 tests executed" line here.
-    ExitProcess(0);
+    // 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)
index 4e70a16..35e37f7 100644 (file)
@@ -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 (file)
index 0000000..d6827ff
--- /dev/null
@@ -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);
+}
index 6415aac..c94ade8 100644 (file)
 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]);
index b35127f..82f57b5 100644 (file)
 #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 }