Author: cfinck Date: Tue May 9 15:44:42 2017 New Revision: 74513
URL: http://svn.reactos.org/svn/reactos?rev=74513&view=rev Log: [PRINTING] - Implement GetDefaultPrinterA/W and SetDefaultPrinterA/W in winspool.drv. Also add tests for these functions. - Set our "Dummy Printer on LPT1" as the default printer in the user registry. - Return meaningful values for DeviceNotSelectedTimeout and TransmissionRetryTimeout in PRINTER_INFO_5 in localspl.
The Print dialog now preselects "Dummy Printer on LPT1" in all applications. One more task done from the list at https://reactos.org/wiki/Printing :)
Added: trunk/rostests/apitests/winspool/GetDefaultPrinter.c (with props) Modified: trunk/reactos/boot/bootdata/hivedef.inf trunk/reactos/win32ss/printing/base/winspool/CMakeLists.txt trunk/reactos/win32ss/printing/base/winspool/printers.c trunk/reactos/win32ss/printing/base/winspool/winspool.spec trunk/reactos/win32ss/printing/include/spoolss.h trunk/reactos/win32ss/printing/providers/localspl/precomp.h trunk/reactos/win32ss/printing/providers/localspl/printers.c trunk/rostests/apitests/winspool/CMakeLists.txt trunk/rostests/apitests/winspool/testlist.c
Modified: trunk/reactos/boot/bootdata/hivedef.inf URL: http://svn.reactos.org/svn/reactos/trunk/reactos/boot/bootdata/hivedef.inf?r... ============================================================================== --- trunk/reactos/boot/bootdata/hivedef.inf [iso-8859-1] (original) +++ trunk/reactos/boot/bootdata/hivedef.inf [iso-8859-1] Tue May 9 15:44:42 2017 @@ -1837,13 +1837,13 @@
HKCU,"SOFTWARE\Microsoft\Windows NT",,0x00000012 HKCU,"SOFTWARE\Microsoft\Windows NT\CurrentVersion",,0x00000012 -HKCU,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Devices",,0x00000012 +HKCU,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Devices","Dummy Printer On LPT1",2,"winspool,LPT1:" HKCU,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Network",,0x00000012 -HKCU,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\PrinterPorts",,0x00000012 +HKCU,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\PrinterPorts","Dummy Printer On LPT1",2,"winspool,LPT1:,15,45" HKCU,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Program Manager",,0x00000012
HKCU,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows","DebugOptions",2,"2048" -HKCU,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows","device",2,"" +HKCU,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows","Device",2,"Dummy Printer On LPT1,winspool,LPT1:" HKCU,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows","Documents",2,"" HKCU,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows","DosPrint",2,"no" HKCU,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows","load",2,""
Modified: trunk/reactos/win32ss/printing/base/winspool/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/printing/base/winsp... ============================================================================== --- trunk/reactos/win32ss/printing/base/winspool/CMakeLists.txt [iso-8859-1] (original) +++ trunk/reactos/win32ss/printing/base/winspool/CMakeLists.txt [iso-8859-1] Tue May 9 15:44:42 2017 @@ -26,6 +26,6 @@ set_target_properties(winspool PROPERTIES SUFFIX ".drv") set_module_type(winspool win32dll UNICODE) target_link_libraries(winspool wine ${PSEH_LIB}) -add_importlibs(winspool gdi32 rpcrt4 msvcrt kernel32 ntdll) +add_importlibs(winspool advapi32 gdi32 rpcrt4 msvcrt kernel32 ntdll) add_pch(winspool precomp.h SOURCE) add_cd_file(TARGET winspool DESTINATION reactos/system32 FOR all)
Modified: trunk/reactos/win32ss/printing/base/winspool/printers.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/printing/base/winsp... ============================================================================== --- trunk/reactos/win32ss/printing/base/winspool/printers.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/printing/base/winspool/printers.c [iso-8859-1] Tue May 9 15:44:42 2017 @@ -6,6 +6,13 @@ */
#include "precomp.h" + +// Local Constants + +/** And the award for the most confusingly named setting goes to "Device", for storing the default printer of the current user. + Ok, I admit that this has historical reasons. It's still not straightforward in any way though! */ +static const WCHAR wszWindowsKey[] = L"Software\Microsoft\Windows NT\CurrentVersion\Windows"; +static const WCHAR wszDeviceValue[] = L"Device";
static void _MarshallUpPrinterInfo(PBYTE* ppPrinterInfo, DWORD Level) @@ -415,13 +422,131 @@ BOOL WINAPI GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer) { - return FALSE; + DWORD dwErrorCode; + PWSTR pwszBuffer = NULL; + + // Sanity check. + if (!pcchBuffer) + { + dwErrorCode = ERROR_INVALID_PARAMETER; + goto Cleanup; + } + + // Check if an ANSI buffer was given and if so, allocate a Unicode buffer of the same size. + if (pszBuffer && *pcchBuffer) + { + pwszBuffer = HeapAlloc(hProcessHeap, 0, *pcchBuffer * sizeof(WCHAR)); + if (!pwszBuffer) + { + dwErrorCode = GetLastError(); + ERR("HeapAlloc failed with error %lu!\n", dwErrorCode); + goto Cleanup; + } + } + + if (!GetDefaultPrinterW(pwszBuffer, pcchBuffer)) + { + dwErrorCode = GetLastError(); + goto Cleanup; + } + + dwErrorCode = ERROR_SUCCESS; + +Cleanup: + if (pwszBuffer) + HeapFree(hProcessHeap, 0, pwszBuffer); + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); }
BOOL WINAPI GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer) { - return FALSE; + DWORD cbNeeded; + DWORD cchInputBuffer; + DWORD dwErrorCode; + HKEY hWindowsKey = NULL; + PWSTR pwszDevice = NULL; + PWSTR pwszComma; + + // Sanity check. + if (!pcchBuffer) + { + dwErrorCode = ERROR_INVALID_PARAMETER; + goto Cleanup; + } + + cchInputBuffer = *pcchBuffer; + + // Open the registry key where the default printer for the current user is stored. + dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_READ, &hWindowsKey); + if (dwErrorCode != ERROR_SUCCESS) + { + ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode); + goto Cleanup; + } + + // Determine the size of the required buffer. + dwErrorCode = (DWORD)RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, NULL, &cbNeeded); + if (dwErrorCode != ERROR_SUCCESS) + { + ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode); + goto Cleanup; + } + + // Allocate it. + pwszDevice = HeapAlloc(hProcessHeap, 0, cbNeeded); + if (!pwszDevice) + { + dwErrorCode = GetLastError(); + ERR("HeapAlloc failed with error %lu!\n", dwErrorCode); + goto Cleanup; + } + + // Now get the actual value. + dwErrorCode = RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, (PBYTE)pwszDevice, &cbNeeded); + if (dwErrorCode != ERROR_SUCCESS) + { + ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode); + goto Cleanup; + } + + // We get a string "<Printer Name>,winspool,<Port>:". + // Extract the printer name from it. + pwszComma = wcschr(pwszDevice, L','); + if (!pwszComma) + { + ERR("Found no or invalid default printer: %S!\n", pwszDevice); + dwErrorCode = ERROR_INVALID_NAME; + goto Cleanup; + } + + // Store the length of the Printer Name (including the terminating NUL character!) in *pcchBuffer. + *pcchBuffer = pwszComma - pwszDevice + 1; + + // Check if the supplied buffer is large enough. + if (cchInputBuffer < *pcchBuffer) + { + dwErrorCode = ERROR_INSUFFICIENT_BUFFER; + goto Cleanup; + } + + // Copy the default printer. + *pwszComma = 0; + CopyMemory(pszBuffer, pwszDevice, *pcchBuffer * sizeof(WCHAR)); + + dwErrorCode = ERROR_SUCCESS; + +Cleanup: + if (hWindowsKey) + RegCloseKey(hWindowsKey); + + if (pwszDevice) + HeapFree(hProcessHeap, 0, pwszDevice); + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); }
BOOL WINAPI @@ -633,6 +758,147 @@ }
BOOL WINAPI +SetDefaultPrinterA(LPCSTR pszPrinter) +{ + BOOL bReturnValue = FALSE; + DWORD cch; + PWSTR pwszPrinter = NULL; + + if (pszPrinter) + { + // Convert pszPrinter to a Unicode string pwszPrinter + cch = strlen(pszPrinter); + + pwszPrinter = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); + if (!pwszPrinter) + { + ERR("HeapAlloc failed for pwszPrinter with last error %lu!\n", GetLastError()); + goto Cleanup; + } + + MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, pwszPrinter, cch + 1); + } + + bReturnValue = SetDefaultPrinterW(pwszPrinter); + +Cleanup: + if (pwszPrinter) + HeapFree(hProcessHeap, 0, pwszPrinter); + + return bReturnValue; +} + +BOOL WINAPI +SetDefaultPrinterW(LPCWSTR pszPrinter) +{ + const WCHAR wszDevicesKey[] = L"Software\Microsoft\Windows NT\CurrentVersion\Devices"; + + DWORD cbDeviceValueData; + DWORD cbPrinterValueData = 0; + DWORD cchPrinter; + DWORD dwErrorCode; + HKEY hDevicesKey = NULL; + HKEY hWindowsKey = NULL; + PWSTR pwszDeviceValueData = NULL; + WCHAR wszPrinter[MAX_PRINTER_NAME + 1]; + + // Open the Devices registry key. + dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszDevicesKey, 0, KEY_READ, &hDevicesKey); + if (dwErrorCode != ERROR_SUCCESS) + { + ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode); + goto Cleanup; + } + + // Did the caller give us a printer to set as default? + if (pszPrinter && *pszPrinter) + { + // Check if the given printer exists and query the value data size. + dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, NULL, &cbPrinterValueData); + if (dwErrorCode == ERROR_FILE_NOT_FOUND) + { + // The caller gave us an invalid printer name, return with ERROR_FILE_NOT_FOUND. + goto Cleanup; + } + else if (dwErrorCode != ERROR_SUCCESS) + { + ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode); + goto Cleanup; + } + + cchPrinter = wcslen(pszPrinter); + } + else + { + // If there is already a default printer, we're done! + cchPrinter = _countof(wszPrinter); + if (GetDefaultPrinterW(wszPrinter, &cchPrinter)) + { + dwErrorCode = ERROR_SUCCESS; + goto Cleanup; + } + + // Otherwise, get us the first printer from the "Devices" key to later set it as default and query the value data size. + cchPrinter = _countof(wszPrinter); + dwErrorCode = (DWORD)RegEnumValueW(hDevicesKey, 0, wszPrinter, &cchPrinter, NULL, NULL, NULL, &cbPrinterValueData); + if (dwErrorCode != ERROR_MORE_DATA) + goto Cleanup; + + pszPrinter = wszPrinter; + } + + // We now need to query the value data, which has the format "winspool,<Port>:" + // and make "<Printer Name>,winspool,<Port>:" out of it. + // Allocate a buffer large enough for the final data. + cbDeviceValueData = (cchPrinter + 1) * sizeof(WCHAR) + cbPrinterValueData; + pwszDeviceValueData = HeapAlloc(hProcessHeap, 0, cbDeviceValueData); + if (!pwszDeviceValueData) + { + dwErrorCode = GetLastError(); + ERR("HeapAlloc failed with error %lu\n", dwErrorCode); + goto Cleanup; + } + + // Copy the Printer Name and a comma into it. + CopyMemory(pwszDeviceValueData, pszPrinter, cchPrinter * sizeof(WCHAR)); + pwszDeviceValueData[cchPrinter] = L','; + + // Append the value data, which has the format "winspool,<Port>:" + dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, (PBYTE)&pwszDeviceValueData[cchPrinter + 1], &cbPrinterValueData); + if (dwErrorCode != ERROR_SUCCESS) + goto Cleanup; + + // Open the Windows registry key. + dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_SET_VALUE, &hWindowsKey); + if (dwErrorCode != ERROR_SUCCESS) + { + ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode); + goto Cleanup; + } + + // Store our new default printer. + dwErrorCode = (DWORD)RegSetValueExW(hWindowsKey, wszDeviceValue, 0, REG_SZ, (PBYTE)pwszDeviceValueData, cbDeviceValueData); + if (dwErrorCode != ERROR_SUCCESS) + { + ERR("RegSetValueExW failed with status %lu!\n", dwErrorCode); + goto Cleanup; + } + +Cleanup: + if (hDevicesKey) + RegCloseKey(hDevicesKey); + + if (hWindowsKey) + RegCloseKey(hWindowsKey); + + if (pwszDeviceValueData) + HeapFree(hProcessHeap, 0, pwszDeviceValueData); + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); +} + +BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command) { UNIMPLEMENTED;
Modified: trunk/reactos/win32ss/printing/base/winspool/winspool.spec URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/printing/base/winsp... ============================================================================== --- trunk/reactos/win32ss/printing/base/winspool/winspool.spec [iso-8859-1] (original) +++ trunk/reactos/win32ss/printing/base/winspool/winspool.spec [iso-8859-1] Tue May 9 15:44:42 2017 @@ -100,9 +100,9 @@ 199 stub EnumPrinterDriversA 200 stdcall EnumPrinterDriversW(wstr wstr long ptr long ptr ptr) 201 stdcall GetDefaultPrinterA(ptr ptr) -202 stub SetDefaultPrinterA +202 stdcall SetDefaultPrinterA(str) 203 stdcall GetDefaultPrinterW(ptr ptr) -204 stub SetDefaultPrinterW +204 stdcall SetDefaultPrinterW(wstr) 205 stub -noname SplReadPrinter 206 stub -noname AddPerMachineConnectionA 207 stub -noname AddPerMachineConnectionW
Modified: trunk/reactos/win32ss/printing/include/spoolss.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/printing/include/sp... ============================================================================== --- trunk/reactos/win32ss/printing/include/spoolss.h [iso-8859-1] (original) +++ trunk/reactos/win32ss/printing/include/spoolss.h [iso-8859-1] Tue May 9 15:44:42 2017 @@ -1,12 +1,15 @@ /* * PROJECT: ReactOS Printing Include files * LICENSE: GNU LGPLv2 or any later version as published by the Free Software Foundation - * PURPOSE: Undocumented APIs of the Spooler Router "spoolss.dll" + * PURPOSE: Undocumented APIs of the Spooler Router "spoolss.dll" and internally shared interfaces * COPYRIGHT: Copyright 2015-2017 Colin Finck colin@reactos.org */
#ifndef _REACTOS_SPOOLSS_H #define _REACTOS_SPOOLSS_H + +// Constants +#define MAX_PRINTER_NAME 220
typedef struct _MARSHALL_DOWN_INFO {
Modified: trunk/reactos/win32ss/printing/providers/localspl/precomp.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/printing/providers/... ============================================================================== --- trunk/reactos/win32ss/printing/providers/localspl/precomp.h [iso-8859-1] (original) +++ trunk/reactos/win32ss/printing/providers/localspl/precomp.h [iso-8859-1] Tue May 9 15:44:42 2017 @@ -36,7 +36,6 @@ #define IS_VALID_PRIORITY(P) (P >= MIN_PRIORITY && P <= MAX_PRIORITY)
// Constants -#define MAX_PRINTER_NAME 220 #define SHD_WIN2003_SIGNATURE 0x4968
// Function pointers
Modified: trunk/reactos/win32ss/printing/providers/localspl/printers.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/printing/providers/... ============================================================================== --- trunk/reactos/win32ss/printing/providers/localspl/printers.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/printing/providers/localspl/printers.c [iso-8859-1] Tue May 9 15:44:42 2017 @@ -74,6 +74,12 @@ FIELD_OFFSET(PRINTER_INFO_5W, pPortName), MAXDWORD }; + +/** These values serve no purpose anymore, but are still used in PRINTER_INFO_5 and + HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\PrinterPorts */ +static const DWORD dwDeviceNotSelectedTimeout = 15000; +static const DWORD dwTransmissionRetryTimeout = 45000; +
/** * @name _PrinterListCompareRoutine @@ -765,8 +771,8 @@
// Set the general fields. (*ppPrinterInfo)->Attributes = pPrinter->dwAttributes; - (*ppPrinterInfo)->DeviceNotSelectedTimeout = 0; - (*ppPrinterInfo)->TransmissionRetryTimeout = 0; + (*ppPrinterInfo)->DeviceNotSelectedTimeout = dwDeviceNotSelectedTimeout; + (*ppPrinterInfo)->TransmissionRetryTimeout = dwTransmissionRetryTimeout;
// Set the pPrinterName field. pwszStrings[0] = DllAllocSplMem(cbPrinterName);
Modified: trunk/rostests/apitests/winspool/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/winspool/CMakeLis... ============================================================================== --- trunk/rostests/apitests/winspool/CMakeLists.txt [iso-8859-1] (original) +++ trunk/rostests/apitests/winspool/CMakeLists.txt [iso-8859-1] Tue May 9 15:44:42 2017 @@ -3,6 +3,7 @@ ClosePrinter.c EnumPrinters.c EnumPrintProcessorDatatypes.c + GetDefaultPrinter.c GetPrintProcessorDirectory.c IsValidDevmode.c OpenPrinter.c
Added: trunk/rostests/apitests/winspool/GetDefaultPrinter.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/winspool/GetDefau... ============================================================================== --- trunk/rostests/apitests/winspool/GetDefaultPrinter.c (added) +++ trunk/rostests/apitests/winspool/GetDefaultPrinter.c [iso-8859-1] Tue May 9 15:44:42 2017 @@ -0,0 +1,49 @@ +/* + * PROJECT: ReactOS Print Spooler DLL API Tests + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Tests for GetDefaultPrinterA/GetDefaultPrinterW/SetDefaultPrinterA/SetDefaultPrinterW + * COPYRIGHT: Copyright 2017 Colin Finck colin@reactos.org + */ + +#include <apitest.h> + +#define WIN32_NO_STATUS +#include <windef.h> +#include <winbase.h> +#include <wingdi.h> +#include <winspool.h> + +START_TEST(GetDefaultPrinter) +{ + DWORD cchDefaultPrinter; + PWSTR pwszDefaultPrinter; + + // Don't supply any parameters, this has to fail with ERROR_INVALID_PARAMETER. + SetLastError(0xDEADBEEF); + ok(!GetDefaultPrinterW(NULL, NULL), "GetDefaultPrinterW returns TRUE!\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetDefaultPrinterW returns error %lu!\n", GetLastError()); + + // Determine the size of the required buffer. This has to bail out with ERROR_INSUFFICIENT_BUFFER. + cchDefaultPrinter = 0; + SetLastError(0xDEADBEEF); + ok(!GetDefaultPrinterW(NULL, &cchDefaultPrinter), "GetDefaultPrinterW returns TRUE!\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetDefaultPrinterW returns error %lu!\n", GetLastError()); + + // Try with a buffer large enough. + pwszDefaultPrinter = HeapAlloc(GetProcessHeap(), 0, cchDefaultPrinter * sizeof(WCHAR)); + SetLastError(0xDEADBEEF); + ok(GetDefaultPrinterW(pwszDefaultPrinter, &cchDefaultPrinter), "GetDefaultPrinterW returns FALSE!\n"); + ok(GetLastError() == ERROR_SUCCESS, "GetDefaultPrinterW returns error %lu!\n", GetLastError()); + + // SetDefaultPrinterW with NULL needs to succeed and leave the default printer unchanged. + SetLastError(0xDEADBEEF); + ok(SetDefaultPrinterW(NULL), "SetDefaultPrinterW returns FALSE!\n"); + ok(GetLastError() == ERROR_SUCCESS, "SetDefaultPrinterW returns error %lu!\n", GetLastError()); + + // SetDefaultPrinterW with the previous default printer also needs to succeed. + SetLastError(0xDEADBEEF); + ok(SetDefaultPrinterW(pwszDefaultPrinter), "SetDefaultPrinterW returns FALSE!\n"); + ok(GetLastError() == ERROR_SUCCESS, "SetDefaultPrinterW returns error %lu!\n", GetLastError()); + + HeapFree(GetProcessHeap(), 0, pwszDefaultPrinter); +}
Propchange: trunk/rostests/apitests/winspool/GetDefaultPrinter.c ------------------------------------------------------------------------------ svn:eol-style = native
Modified: trunk/rostests/apitests/winspool/testlist.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/winspool/testlist... ============================================================================== --- trunk/rostests/apitests/winspool/testlist.c [iso-8859-1] (original) +++ trunk/rostests/apitests/winspool/testlist.c [iso-8859-1] Tue May 9 15:44:42 2017 @@ -13,6 +13,7 @@ extern void func_ClosePrinter(void); extern void func_EnumPrinters(void); extern void func_EnumPrintProcessorDatatypes(void); +extern void func_GetDefaultPrinter(void); extern void func_GetPrintProcessorDirectoryA(void); extern void func_GetPrintProcessorDirectoryW(void); extern void func_IsValidDevmodeA(void); @@ -25,6 +26,7 @@ { "ClosePrinter", func_ClosePrinter }, { "EnumPrinters", func_EnumPrinters }, { "EnumPrintProcessorDatatypes", func_EnumPrintProcessorDatatypes }, + { "GetDefaultPrinter", func_GetDefaultPrinter }, { "GetPrintProcessorDirectoryA", func_GetPrintProcessorDirectoryA }, { "GetPrintProcessorDirectoryW", func_GetPrintProcessorDirectoryW }, { "IsValidDevmodeA", func_IsValidDevmodeA },