Finally merge my branch "colins-printing-for-freedom", giving us an initial implementation of a Win32-compatible Printing Stack (localmon, localspl, spoolss, spoolsv, winspool)
You can now send raw data to parallel port printers using documented Win32 API. An example application is in my "winspool_print" commandline tool merged to rosapps.
ReactOS folks, thanks for your support during the development of this, making my bachelor's thesis a reality! :)
Documentation/Thesis: https://svn.reactos.org/reactos/trunk/documentation/articles/Printing%20Stack%20Thesis/thesis.pdf
Video: https://www.youtube.com/watch?v=cNzePucTOLY
CORE-10489
svn path=/trunk/; revision=73039
add_subdirectory(eventlog)
add_subdirectory(rpcss)
add_subdirectory(schedsvc)
-add_subdirectory(spoolsv)
add_subdirectory(srvsvc)
add_subdirectory(svchost)
add_subdirectory(tcpsvcs)
+++ /dev/null
-
-add_executable(spoolsv spoolsv.c spoolsv.rc)
-target_link_libraries(spoolsv wine)
-set_module_type(spoolsv win32cui UNICODE)
-add_importlibs(spoolsv advapi32 msvcrt kernel32 ntdll)
-add_cd_file(TARGET spoolsv DESTINATION reactos/system32 FOR all)
+++ /dev/null
-/*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
- * FILE: base/services/spoolsv/spoolsv.c
- * PURPOSE: Printer spooler
- * PROGRAMMER: Eric Kohl
- */
-
-/* INCLUDES *****************************************************************/
-
-#include <windef.h>
-#include <winsvc.h>
-#include <wine/debug.h>
-
-WINE_DEFAULT_DEBUG_CHANNEL(spoolsv);
-
-
-/* GLOBALS ******************************************************************/
-
-static VOID CALLBACK ServiceMain(DWORD argc, LPWSTR *argv);
-static WCHAR ServiceName[] = L"Spooler";
-static SERVICE_TABLE_ENTRYW ServiceTable[] =
-{
- {ServiceName, ServiceMain},
- {NULL, NULL}
-};
-
-SERVICE_STATUS_HANDLE ServiceStatusHandle;
-SERVICE_STATUS ServiceStatus;
-
-
-/* FUNCTIONS *****************************************************************/
-
-static VOID
-UpdateServiceStatus(DWORD dwState)
-{
- ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
- ServiceStatus.dwCurrentState = dwState;
-
- if (dwState == SERVICE_RUNNING)
- ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
- else
- ServiceStatus.dwControlsAccepted = 0;
-
- ServiceStatus.dwWin32ExitCode = 0;
- ServiceStatus.dwServiceSpecificExitCode = 0;
- ServiceStatus.dwCheckPoint = 0;
-
- if (dwState == SERVICE_START_PENDING ||
- dwState == SERVICE_STOP_PENDING)
- ServiceStatus.dwWaitHint = 10000;
- else
- ServiceStatus.dwWaitHint = 0;
-
- SetServiceStatus(ServiceStatusHandle,
- &ServiceStatus);
-}
-
-
-static DWORD WINAPI
-ServiceControlHandler(DWORD dwControl,
- DWORD dwEventType,
- LPVOID lpEventData,
- LPVOID lpContext)
-{
- TRACE("ServiceControlHandler() called\n");
-
- switch (dwControl)
- {
- case SERVICE_CONTROL_STOP:
- TRACE(" SERVICE_CONTROL_STOP received\n");
- UpdateServiceStatus(SERVICE_STOPPED);
- return ERROR_SUCCESS;
-
- case SERVICE_CONTROL_INTERROGATE:
- TRACE(" SERVICE_CONTROL_INTERROGATE received\n");
- SetServiceStatus(ServiceStatusHandle,
- &ServiceStatus);
- return ERROR_SUCCESS;
-
- case SERVICE_CONTROL_SHUTDOWN:
- TRACE(" SERVICE_CONTROL_SHUTDOWN received\n");
- UpdateServiceStatus(SERVICE_STOPPED);
- return ERROR_SUCCESS;
-
- default :
- TRACE(" Control %lu received\n");
- return ERROR_CALL_NOT_IMPLEMENTED;
- }
-}
-
-
-static VOID CALLBACK
-ServiceMain(DWORD argc, LPWSTR *argv)
-{
- UNREFERENCED_PARAMETER(argc);
- UNREFERENCED_PARAMETER(argv);
-
- TRACE("ServiceMain() called\n");
-
- ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
- ServiceControlHandler,
- NULL);
-
- TRACE("Calling SetServiceStatus()\n");
- UpdateServiceStatus(SERVICE_RUNNING);
- TRACE("SetServiceStatus() called\n");
-
-
- TRACE("ServiceMain() done\n");
-}
-
-
-int
-wmain(int argc, WCHAR *argv[])
-{
- UNREFERENCED_PARAMETER(argc);
- UNREFERENCED_PARAMETER(argv);
-
- TRACE("Spoolsv: main() started\n");
-
- StartServiceCtrlDispatcher(ServiceTable);
-
- TRACE("Spoolsv: main() done\n");
-
- return 0;
-}
-
-/* EOF */
+++ /dev/null
-#define REACTOS_STR_FILE_DESCRIPTION "Spooler-Service"
-#define REACTOS_STR_INTERNAL_NAME "Spoolsv"
-#define REACTOS_STR_ORIGINAL_FILENAME "Spoolsv.exe"
-#include <reactos/version.rc>
HKLM,"SYSTEM\CurrentControlSet\Control\PnP\Pci\CardList","Ali",0x00030003,\
01,00,00,00,b9,10,21,15,00,00,00,00,00,00,00,00
+
+; Printing
HKLM,"SYSTEM\CurrentControlSet\Control\Print","MajorVersion",0x00010001,2
-HKLM,"SYSTEM\CurrentControlSet\Control\Print","MinorVersion",0x00010003,0
-HKLM,"SYSTEM\CurrentControlSet\Control\Print","PriorityClass",0x00010003,0
-HKLM,"SYSTEM\CurrentControlSet\Control\Print\Environments",,0x00000012
-HKLM,"SYSTEM\CurrentControlSet\Control\Print\Monitors",,0x00000012
-HKLM,"SYSTEM\CurrentControlSet\Control\Print\Monitors\Local Port","Driver",2,"localspl.dll"
+HKLM,"SYSTEM\CurrentControlSet\Control\Print","MinorVersion",0x00010001,0
+HKLM,"SYSTEM\CurrentControlSet\Control\Print","PriorityClass",0x00010001,0
+
+HKLM,"SYSTEM\CurrentControlSet\Control\Print\Environments",,0x00000010
+HKLM,"SYSTEM\CurrentControlSet\Control\Print\Environments\Windows NT x86","Directory",,"W32X86"
+HKLM,"SYSTEM\CurrentControlSet\Control\Print\Environments\Windows NT x86\Print Processors",,0x00000010
+HKLM,"SYSTEM\CurrentControlSet\Control\Print\Environments\Windows NT x86\Print Processors\winprint","Driver",,"winprint.dll"
+
+HKLM,"SYSTEM\CurrentControlSet\Control\Print\Monitors",,0x00000010
+HKLM,"SYSTEM\CurrentControlSet\Control\Print\Monitors\Local Port","Driver",,"localmon.dll"
+
HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers",,0x00000012
+HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Attributes",0x00010001,0
+HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Datatype",,"RAW"
+HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Description",,""
+HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Default DevMode",1,\
+00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
+00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,dc,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
+00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
+00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
+00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
+HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Port",,"LPT1:"
+HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Print Processor",,"winprint"
+HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Printer Driver",,"Dummy Printer Driver"
+HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Status",0x00010001,0
+
+HKLM,"SYSTEM\CurrentControlSet\Control\Print\Providers",,0x00000010
+
HKLM,"SYSTEM\CurrentControlSet\Control\ProductOptions","ProductType",2,"ServerNT"
HKLM,"SYSTEM\CurrentControlSet\Control\ProductOptions","ProductSuite",0x00010002,"Terminal Server"
add_subdirectory(kernel32)
add_subdirectory(kernel32_vista)
add_subdirectory(loadperf)
-add_subdirectory(localspl)
-add_subdirectory(localui)
add_subdirectory(lpk)
add_subdirectory(lsasrv)
add_subdirectory(lz32)
add_subdirectory(ntdsapi)
add_subdirectory(ntlanman)
add_subdirectory(ntmarta)
-add_subdirectory(ntprint)
add_subdirectory(objsel)
add_subdirectory(odbc32)
add_subdirectory(odbccp32)
add_subdirectory(sndblst)
add_subdirectory(snmpapi)
add_subdirectory(softpub)
-add_subdirectory(spoolss)
add_subdirectory(srclient)
add_subdirectory(stdole2.tlb)
add_subdirectory(stdole32.tlb)
add_subdirectory(wininet)
add_subdirectory(winmm)
add_subdirectory(winscard)
-add_subdirectory(winspool)
add_subdirectory(winsta)
add_subdirectory(wintrust)
add_subdirectory(wlanapi)
+++ /dev/null
-
-remove_definitions(-D_WIN32_WINNT=0x502)
-add_definitions(-D_WIN32_WINNT=0x600)
-
-add_definitions(-D__WINESRC__)
-include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine)
-spec2def(localspl.dll localspl.spec)
-
-list(APPEND SOURCE
- localmon.c
- localspl_main.c
- provider.c
- localspl_private.h)
-
-add_library(localspl SHARED
- ${SOURCE}
- localspl.rc
- ${CMAKE_CURRENT_BINARY_DIR}/localspl_stubs.c
- ${CMAKE_CURRENT_BINARY_DIR}/localspl.def)
-
-set_module_type(localspl win32dll)
-target_link_libraries(localspl wine)
-add_importlibs(localspl spoolss user32 advapi32 advapi32_vista msvcrt kernel32 ntdll)
-add_pch(localspl localspl_private.h SOURCE)
-add_cd_file(TARGET localspl DESTINATION reactos/system32 FOR all)
+++ /dev/null
-/*
- * Cefnogaeth iaith Cymraeg
- * Welsh language support
- *
- * Copyright 2010 Ken Sharp
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-LANGUAGE LANG_WELSH, SUBLANG_DEFAULT
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Port Lleol"
- IDS_LOCALMONITOR "Monitor Lleol"
-}
+++ /dev/null
-/*
- * Danish resources for localspl
- *
- * Copyright 2008 Jens Albretsen <jens@albretsen.dk>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-LANGUAGE LANG_DANISH, SUBLANG_DEFAULT
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Lokal port"
- IDS_LOCALMONITOR "Lokal overvåger"
-}
+++ /dev/null
-/*
- * German resources for localspl
- *
- * Copyright 2005 Henning Gerhardt
- * Copyright 2006 Detlef Riekenberg
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#pragma code_page(65001)
-
-LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Lokaler Anschluss"
- IDS_LOCALMONITOR "Lokale Anzeige"
-}
+++ /dev/null
-/*
- * English resources for localspl
- *
- * Copyright 2005 Huw Davies
- * Copyright 2006 Detlef Riekenberg
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Local Port"
- IDS_LOCALMONITOR "Local Monitor"
-}
+++ /dev/null
-/*
- * Spanish resources for localspl
- *
- * Copyright 2010 José Manuel Ferrer Ortiz
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/* UTF-8 */
-#pragma code_page(65001)
-
-LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Puerto local"
- IDS_LOCALMONITOR "Monitor local"
-}
+++ /dev/null
-/*
- * French resources for localspl
- *
- * Copyright 2007 Jonathan Ernst
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Port local"
- IDS_LOCALMONITOR "Moniteur local"
-}
+++ /dev/null
-/*
- * Hebrew resources for localspl
- *
- * Copyright 2005 Huw Davies
- * Copyright 2006 Detlef Riekenberg
- *
- * Translated by Baruch Rutman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-LANGUAGE LANG_HEBREW, SUBLANG_DEFAULT
-
-STRINGTABLE
-{
- IDS_LOCALPORT "יציאה מקומית"
- IDS_LOCALMONITOR "ניטור מקומי"
-}
+++ /dev/null
-/*
- * Hungarian resources for localspl
- *
- * Copyright 2010 Andras Kovacs
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/* UTF-8 */
-#pragma code_page(65001)
-
-LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Helyi Port"
- IDS_LOCALMONITOR "Helyi figyelő"
-}
+++ /dev/null
-/*
- * Italian resources for localspl
- *
- * Copyright 2005 Huw Davies
- * Copyright 2006 Detlef Riekenberg
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/* UTF-8 */
-#pragma code_page(65001)
-
-LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Porta locale"
- IDS_LOCALMONITOR "Schermo locale"
-}
+++ /dev/null
-/*
- * Japanese resources for localspl
- *
- * Copyright 2005 Huw Davies
- * Copyright 2006 Detlef Riekenberg
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/* UTF-8 */
-#pragma code_page(65001)
-
-LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
-
-STRINGTABLE
-{
- IDS_LOCALPORT "ローカル ポート"
- IDS_LOCALMONITOR "ローカル モニタ"
-}
+++ /dev/null
-/*
- * Korean resources for localspl
- *
- * Copyright 2005 Huw Davies
- * Copyright 2006 Detlef Riekenberg
- * Copyright 2006 YunSong Hwang
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT
-
-STRINGTABLE
-{
- IDS_LOCALPORT "지역 포트"
- IDS_LOCALMONITOR "지역 모니터"
-}
+++ /dev/null
-/*
- * Lithuanian resources for localspl
- *
- * Copyright 2009 Aurimas Fišeras <aurimas@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/* UTF-8 */
-#pragma code_page(65001)
-
-LANGUAGE LANG_LITHUANIAN, SUBLANG_NEUTRAL
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Vietinis prievadas"
- IDS_LOCALMONITOR "Vietinis monitorius"
-}
+++ /dev/null
-/*
- * Dutch resources for localspl
- *
- * Copyright 2008 Frans Kool
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-LANGUAGE LANG_DUTCH, SUBLANG_NEUTRAL
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Lokale Poort"
- IDS_LOCALMONITOR "Lokale Monitor"
-}
+++ /dev/null
-/*
- * Norwegian Bokmål resources for localspl
- *
- * Copyright 2006 Alexander N. Sørnes <alex@thehandofagony.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Lokal port"
- IDS_LOCALMONITOR "Lokal overvåker"
-}
+++ /dev/null
-/*
- * Polish resources for localspl
- *
- * Copyright 2005 Huw Davies
- * Copyright 2006 Detlef Riekenberg
- * Copyright 2007 Mikolaj Zalewski
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-LANGUAGE LANG_POLISH, SUBLANG_DEFAULT
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Port lokalny"
- IDS_LOCALMONITOR "Monitor lokalny"
-}
+++ /dev/null
-/*
- * Portuguese resources for localspl
- *
- * Copyright 2008 Ricardo Filipe
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-LANGUAGE LANG_PORTUGUESE, SUBLANG_NEUTRAL
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Porta local"
- IDS_LOCALMONITOR "Monitor Local"
-}
+++ /dev/null
-/*
- * Copyright 2005 Huw Davies
- * Copyright 2006 Detlef Riekenberg
- * Copyright 2008 Michael Stefaniuc
- * 2011 Fulea Ștefan
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#pragma code_page(65001)
-
-LANGUAGE LANG_ROMANIAN, SUBLANG_NEUTRAL
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Port local"
- IDS_LOCALMONITOR "Ecran local"
-}
+++ /dev/null
-/*
- * Russian resources for localspl
- *
- * Copyright 2008 Vitaliy Margolen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/* UTF-8 */
-#pragma code_page(65001)
-
-LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Локальный порт"
- IDS_LOCALMONITOR "Локальный монитор"
-}
+++ /dev/null
-/*
- * Slovenian resources for localspl
- *
- * Copyright 2008 Rok Mandeljc
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#pragma code_page(65001)
-
-LANGUAGE LANG_SLOVENIAN, SUBLANG_DEFAULT
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Lokalna vrata"
- IDS_LOCALMONITOR "Lokalen monitor"
-}
+++ /dev/null
-/*
- * English resources for localspl
- *
- * Copyright 2005 Huw Davies
- * Copyright 2006 Detlef Riekenberg
- * Translation: Ardit Dani (ALbanian Translation Resource File)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-LANGUAGE LANG_ALBANIAN, SUBLANG_NEUTRAL
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Porti Vendor"
- IDS_LOCALMONITOR "Monitorim Vendor"
-}
+++ /dev/null
-/*
- * Swedish resources for localspl
- *
- * Copyright 2007 Daniel Nylander
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-LANGUAGE LANG_SWEDISH, SUBLANG_NEUTRAL
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Lokal port"
- IDS_LOCALMONITOR "Lokal skärm"
-}
+++ /dev/null
-/*
- * Turkish resources for localspl
- *
- * Copyright: 2014 Erdem Ersoy (eersoy93) (erdemersoy@live.com)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Yerli Giriş"
- IDS_LOCALMONITOR "Yerli İzleyici"
-}
+++ /dev/null
-/*
- * Ukrainian resources for localspl
- *
- * Copyright 2010 Igor Paliychuk
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/* UTF-8 */
-#pragma code_page(65001)
-
-LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT
-
-STRINGTABLE
-{
- IDS_LOCALPORT "Локальний порт"
- IDS_LOCALMONITOR "Локальний монітор"
-}
+++ /dev/null
-/*
- * localspl (Simplified and Traditional Chinese Resources)
- *
- * Copyright 2008 Hongbo Ni <hongbo.at.njstar.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/* Chinese text is encoded in UTF-8 */
-#pragma code_page(65001)
-
-LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
-
-STRINGTABLE
-{
- IDS_LOCALPORT "本地端口"
- IDS_LOCALMONITOR "本地监视器"
-}
-
-LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL
-
-STRINGTABLE
-{
- IDS_LOCALPORT "本地端口"
- IDS_LOCALMONITOR "本地監視器"
-}
+++ /dev/null
-/*
- * Implementation of the Local Printmonitor
- *
- * Copyright 2006 Detlef Riekenberg
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#include "localspl_private.h"
-
-#include "resource.h"
-
-/*****************************************************/
-
-static CRITICAL_SECTION port_handles_cs;
-static CRITICAL_SECTION_DEBUG port_handles_cs_debug =
-{
- 0, 0, &port_handles_cs,
- { &port_handles_cs_debug.ProcessLocksList, &port_handles_cs_debug.ProcessLocksList },
- 0, 0, { (DWORD_PTR)(__FILE__ ": port_handles_cs") }
-};
-static CRITICAL_SECTION port_handles_cs = { &port_handles_cs_debug, -1, 0, 0, 0, 0 };
-
-
-static CRITICAL_SECTION xcv_handles_cs;
-static CRITICAL_SECTION_DEBUG xcv_handles_cs_debug =
-{
- 0, 0, &xcv_handles_cs,
- { &xcv_handles_cs_debug.ProcessLocksList, &xcv_handles_cs_debug.ProcessLocksList },
- 0, 0, { (DWORD_PTR)(__FILE__ ": xcv_handles_cs") }
-};
-static CRITICAL_SECTION xcv_handles_cs = { &xcv_handles_cs_debug, -1, 0, 0, 0, 0 };
-
-/* ############################### */
-
-typedef struct {
- struct list entry;
- DWORD type;
- WCHAR nameW[1];
-} port_t;
-
-typedef struct {
- struct list entry;
- ACCESS_MASK GrantedAccess;
- WCHAR nameW[1];
-} xcv_t;
-
-static struct list port_handles = LIST_INIT( port_handles );
-static struct list xcv_handles = LIST_INIT( xcv_handles );
-
-/* ############################### */
-
-static const WCHAR cmd_AddPortW[] = {'A','d','d','P','o','r','t',0};
-static const WCHAR cmd_DeletePortW[] = {'D','e','l','e','t','e','P','o','r','t',0};
-static const WCHAR cmd_ConfigureLPTPortCommandOKW[] = {'C','o','n','f','i','g','u','r','e',
- 'L','P','T','P','o','r','t',
- 'C','o','m','m','a','n','d','O','K',0};
-
-static const WCHAR cmd_GetDefaultCommConfigW[] = {'G','e','t',
- 'D','e','f','a','u','l','t',
- 'C','o','m','m','C','o','n','f','i','g',0};
-
-static const WCHAR cmd_GetTransmissionRetryTimeoutW[] = {'G','e','t',
- 'T','r','a','n','s','m','i','s','s','i','o','n',
- 'R','e','t','r','y','T','i','m','e','o','u','t',0};
-
-static const WCHAR cmd_MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
-static const WCHAR cmd_PortIsValidW[] = {'P','o','r','t','I','s','V','a','l','i','d',0};
-static const WCHAR cmd_SetDefaultCommConfigW[] = {'S','e','t',
- 'D','e','f','a','u','l','t',
- 'C','o','m','m','C','o','n','f','i','g',0};
-
-static const WCHAR dllnameuiW[] = {'l','o','c','a','l','u','i','.','d','l','l',0};
-static const WCHAR emptyW[] = {0};
-static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
-
-static const WCHAR portname_LPT[] = {'L','P','T',0};
-static const WCHAR portname_COM[] = {'C','O','M',0};
-static const WCHAR portname_FILE[] = {'F','I','L','E',':',0};
-static const WCHAR portname_CUPS[] = {'C','U','P','S',':',0};
-static const WCHAR portname_LPR[] = {'L','P','R',':',0};
-
-static const WCHAR TransmissionRetryTimeoutW[] = {'T','r','a','n','s','m','i','s','s','i','o','n',
- 'R','e','t','r','y','T','i','m','e','o','u','t',0};
-
-static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
- 'M','i','c','r','o','s','o','f','t','\\',
- 'W','i','n','d','o','w','s',' ','N','T','\\',
- 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
- 'P','o','r','t','s',0};
-
-static const WCHAR WinNT_CV_WindowsW[] = {'S','o','f','t','w','a','r','e','\\',
- 'M','i','c','r','o','s','o','f','t','\\',
- 'W','i','n','d','o','w','s',' ','N','T','\\',
- 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
- 'W','i','n','d','o','w','s',0};
-
-
-/******************************************************************
- * does_port_exist (internal)
- *
- * returns TRUE, when the Port already exists
- *
- */
-static BOOL does_port_exist(LPCWSTR myname)
-{
-
- LPPORT_INFO_1W pi;
- DWORD needed = 0;
- DWORD returned;
- DWORD id;
-
- TRACE("(%s)\n", debugstr_w(myname));
-
- id = EnumPortsW(NULL, 1, NULL, 0, &needed, &returned);
- pi = heap_alloc(needed);
- returned = 0;
- if (pi)
- id = EnumPortsW(NULL, 1, (LPBYTE) pi, needed, &needed, &returned);
-
- if (id && returned > 0) {
- /* we got a number of valid names. */
- for (id = 0; id < returned; id++)
- {
- if (lstrcmpiW(myname, pi[id].pName) == 0) {
- TRACE("(%u) found %s\n", id, debugstr_w(pi[id].pName));
- heap_free(pi);
- return TRUE;
- }
- }
- }
-
- heap_free(pi);
- return FALSE;
-}
-
-/******************************************************************
- * enumerate the local Ports from the Registry (internal)
- *
- * See localmon_EnumPortsW.
- *
- * NOTES
- * returns the needed size (in bytes) for pPorts
- * and *lpreturned is set to number of entries returned in pPorts
- *
- */
-
-static DWORD get_ports_from_reg(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
-{
- HKEY hroot = 0;
- LPWSTR ptr;
- LPPORT_INFO_2W out;
- WCHAR portname[MAX_PATH];
- WCHAR res_PortW[IDS_LOCALPORT_MAXLEN];
- WCHAR res_MonitorW[IDS_LOCALMONITOR_MAXLEN];
- INT reslen_PortW;
- INT reslen_MonitorW;
- DWORD len;
- DWORD res;
- DWORD needed = 0;
- DWORD numentries;
- DWORD entrysize;
- DWORD id = 0;
-
- TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
-
- entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
-
- numentries = *lpreturned; /* this is 0, when we scan the registry */
- needed = entrysize * numentries;
- ptr = (LPWSTR) &pPorts[needed];
-
- if (needed > cbBuf) pPorts = NULL; /* No buffer for the structs */
-
- numentries = 0;
- needed = 0;
-
- /* we do not check more parameters as done in windows */
- if ((level < 1) || (level > 2)) {
- goto getports_cleanup;
- }
-
- /* "+1" for '\0' */
- reslen_MonitorW = LoadStringW(LOCALSPL_hInstance, IDS_LOCALMONITOR, res_MonitorW, IDS_LOCALMONITOR_MAXLEN) + 1;
- reslen_PortW = LoadStringW(LOCALSPL_hInstance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN) + 1;
-
- res = RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot);
- if (res == ERROR_SUCCESS) {
-
- /* Scan all Port-Names */
- while (res == ERROR_SUCCESS) {
- len = MAX_PATH;
- portname[0] = '\0';
- res = RegEnumValueW(hroot, id, portname, &len, NULL, NULL, NULL, NULL);
-
- if ((res == ERROR_SUCCESS) && (portname[0])) {
- numentries++;
- /* calculate the required size */
- needed += entrysize;
- needed += (len + 1) * sizeof(WCHAR);
- if (level > 1) {
- needed += (reslen_MonitorW + reslen_PortW) * sizeof(WCHAR);
- }
-
- /* Now fill the user-buffer, if available */
- if (pPorts && (cbBuf >= needed)){
- out = (LPPORT_INFO_2W) pPorts;
- pPorts += entrysize;
- TRACE("%p: writing PORT_INFO_%dW #%d (%s)\n", out, level, numentries, debugstr_w(portname));
- out->pPortName = ptr;
- lstrcpyW(ptr, portname); /* Name of the Port */
- ptr += (len + 1);
- if (level > 1) {
- out->pMonitorName = ptr;
- lstrcpyW(ptr, res_MonitorW); /* Name of the Monitor */
- ptr += reslen_MonitorW;
-
- out->pDescription = ptr;
- lstrcpyW(ptr, res_PortW); /* Port Description */
- ptr += reslen_PortW;
-
- out->fPortType = PORT_TYPE_WRITE;
- out->Reserved = 0;
- }
- }
- id++;
- }
- }
- RegCloseKey(hroot);
- }
- else
- {
- ERR("failed with %d for %s\n", res, debugstr_w(WinNT_CV_PortsW));
- SetLastError(res);
- }
-
-getports_cleanup:
- *lpreturned = numentries;
- TRACE("need %d byte for %d entries (%d)\n", needed, numentries, GetLastError());
- return needed;
-}
-
-/*****************************************************
- * get_type_from_name (internal)
- *
- */
-
-static DWORD get_type_from_name(LPCWSTR name)
-{
- HANDLE hfile;
-
- if (!strncmpW(name, portname_LPT, sizeof(portname_LPT) / sizeof(WCHAR) -1))
- return PORT_IS_LPT;
-
- if (!strncmpW(name, portname_COM, sizeof(portname_COM) / sizeof(WCHAR) -1))
- return PORT_IS_COM;
-
- if (!strcmpW(name, portname_FILE))
- return PORT_IS_FILE;
-
- if (name[0] == '/')
- return PORT_IS_UNIXNAME;
-
- if (name[0] == '|')
- return PORT_IS_PIPE;
-
- if (!strncmpW(name, portname_CUPS, sizeof(portname_CUPS) / sizeof(WCHAR) -1))
- return PORT_IS_CUPS;
-
- if (!strncmpW(name, portname_LPR, sizeof(portname_LPR) / sizeof(WCHAR) -1))
- return PORT_IS_LPR;
-
- /* Must be a file or a directory. Does the file exist ? */
- hfile = CreateFileW(name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- TRACE("%p for OPEN_EXISTING on %s\n", hfile, debugstr_w(name));
- if (hfile == INVALID_HANDLE_VALUE) {
- /* Can we create the file? */
- hfile = CreateFileW(name, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
- TRACE("%p for OPEN_ALWAYS\n", hfile);
- }
- if (hfile != INVALID_HANDLE_VALUE) {
- CloseHandle(hfile);
- return PORT_IS_FILENAME;
- }
- /* We can't use the name. use GetLastError() for the reason */
- return PORT_IS_UNKNOWN;
-}
-
-/*****************************************************
- * get_type_from_local_name (internal)
- *
- */
-
-static DWORD get_type_from_local_name(LPCWSTR nameW)
-{
- LPPORT_INFO_1W pi;
- LPWSTR myname = NULL;
- DWORD needed = 0;
- DWORD numentries = 0;
- DWORD id = 0;
-
- TRACE("(%s)\n", debugstr_w(myname));
-
- needed = get_ports_from_reg(1, NULL, 0, &numentries);
- pi = heap_alloc(needed);
- if (pi)
- needed = get_ports_from_reg(1, (LPBYTE) pi, needed, &numentries);
-
- if (pi && needed && numentries > 0) {
- /* we got a number of valid ports. */
-
- while ((myname == NULL) && (id < numentries))
- {
- if (lstrcmpiW(nameW, pi[id].pName) == 0) {
- TRACE("(%u) found %s\n", id, debugstr_w(pi[id].pName));
- myname = pi[id].pName;
- }
- id++;
- }
- }
-
- id = (myname) ? get_type_from_name(myname) : PORT_IS_UNKNOWN;
-
- heap_free(pi);
- return id;
-
-}
-/******************************************************************************
- * localmon_AddPortExW [exported through MONITOREX]
- *
- * Add a Port, without presenting a user interface
- *
- * PARAMS
- * pName [I] Servername or NULL (local Computer)
- * level [I] Structure-Level (1) for pBuffer
- * pBuffer [I] PTR to the Input-Data (PORT_INFO_1)
- * pMonitorName [I] Name of the Monitor that manage the Port
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- * NOTES
- * Level 2 is documented on MSDN for Portmonitors, but not supported by the
- * "Local Port" Portmonitor (localspl.dll / localmon.dll)
- */
-static BOOL WINAPI localmon_AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
-{
- PORT_INFO_1W * pi;
- HKEY hroot;
- DWORD res;
-
- pi = (PORT_INFO_1W *) pBuffer;
- TRACE("(%s, %d, %p, %s) => %s\n", debugstr_w(pName), level, pBuffer,
- debugstr_w(pMonitorName), debugstr_w(pi ? pi->pName : NULL));
-
-
- if ((pMonitorName == NULL) || (lstrcmpiW(pMonitorName, LocalPortW) != 0 ) ||
- (pi == NULL) || (pi->pName == NULL) || (pi->pName[0] == '\0') ) {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- if (level != 1) {
- SetLastError(ERROR_INVALID_LEVEL);
- return FALSE;
- }
-
- res = RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot);
- if (res == ERROR_SUCCESS) {
- if (does_port_exist(pi->pName)) {
- RegCloseKey(hroot);
- TRACE("=> FALSE with %u\n", ERROR_INVALID_PARAMETER);
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
- res = RegSetValueExW(hroot, pi->pName, 0, REG_SZ, (const BYTE *) emptyW, sizeof(emptyW));
- RegCloseKey(hroot);
- }
- if (res != ERROR_SUCCESS) SetLastError(ERROR_INVALID_PARAMETER);
- TRACE("=> %u with %u\n", (res == ERROR_SUCCESS), GetLastError());
- return (res == ERROR_SUCCESS);
-}
-
-/*****************************************************
- * localmon_ClosePort [exported through MONITOREX]
- *
- * Close a
- *
- * PARAMS
- * hPort [i] The Handle to close
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- */
-static BOOL WINAPI localmon_ClosePort(HANDLE hPort)
-{
- port_t * port = hPort;
-
- TRACE("(%p)\n", port);
- EnterCriticalSection(&port_handles_cs);
- list_remove(&port->entry);
- LeaveCriticalSection(&port_handles_cs);
- heap_free(port);
- return TRUE;
-}
-
-/*****************************************************
- * localmon_EnumPortsW [exported through MONITOREX]
- *
- * Enumerate all local Ports
- *
- * PARAMS
- * pName [I] Servername (ignored)
- * level [I] Structure-Level (1 or 2)
- * pPorts [O] PTR to Buffer that receives the Result
- * cbBuf [I] Size of Buffer at pPorts
- * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
- * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
- *
- * NOTES
- *| Windows ignores pName
- *| Windows crash the app, when pPorts, pcbNeeded or pcReturned are NULL
- *| Windows >NT4.0 does not check for illegal levels (TRUE is returned)
- *
- * ToDo
- * "HCU\Software\Wine\Spooler\<portname>" - redirection
- *
- */
-static BOOL WINAPI localmon_EnumPortsW(LPWSTR pName, DWORD level, LPBYTE pPorts,
- DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
-{
- BOOL res = FALSE;
- DWORD needed;
- DWORD numentries;
-
- TRACE("(%s, %d, %p, %d, %p, %p)\n",
- debugstr_w(pName), level, pPorts, cbBuf, pcbNeeded, pcReturned);
-
- numentries = 0;
- needed = get_ports_from_reg(level, NULL, 0, &numentries);
- /* we calculated the needed buffersize. now do the error-checks */
- if (cbBuf < needed) {
- SetLastError(ERROR_INSUFFICIENT_BUFFER);
- goto cleanup;
- }
-
- /* fill the buffer with the Port-Names */
- needed = get_ports_from_reg(level, pPorts, cbBuf, &numentries);
- res = TRUE;
-
- if (pcReturned) *pcReturned = numentries;
-
-cleanup:
- if (pcbNeeded) *pcbNeeded = needed;
-
- TRACE("returning %d with %d (%d byte for %d entries)\n",
- res, GetLastError(), needed, numentries);
-
- return (res);
-}
-
-/*****************************************************
- * localmon_OpenPort [exported through MONITOREX]
- *
- * Open a Data-Channel for a Port
- *
- * PARAMS
- * pName [i] Name of selected Object
- * phPort [o] The resulting Handle is stored here
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- */
-static BOOL WINAPI localmon_OpenPortW(LPWSTR pName, PHANDLE phPort)
-{
- port_t * port;
- DWORD type;
-
- TRACE("%s, %p)\n", debugstr_w(pName), phPort);
-
- /* an empty name is invalid */
- if (!pName[0]) return FALSE;
-
- /* does the port exist? */
- type = get_type_from_local_name(pName);
- if (!type) return FALSE;
-
- port = heap_alloc(FIELD_OFFSET(port_t, nameW[lstrlenW(pName) + 1]));
- if (!port) return FALSE;
-
- port->type = type;
- lstrcpyW(port->nameW, pName);
- *phPort = port;
-
- EnterCriticalSection(&port_handles_cs);
- list_add_tail(&port_handles, &port->entry);
- LeaveCriticalSection(&port_handles_cs);
-
- TRACE("=> %p\n", port);
- return TRUE;
-}
-
-/*****************************************************
- * localmon_XcvClosePort [exported through MONITOREX]
- *
- * Close a Communication-Channel
- *
- * PARAMS
- * hXcv [i] The Handle to close
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- */
-static BOOL WINAPI localmon_XcvClosePort(HANDLE hXcv)
-{
- xcv_t * xcv = hXcv;
-
- TRACE("(%p)\n", xcv);
- /* No checks are done in Windows */
- EnterCriticalSection(&xcv_handles_cs);
- list_remove(&xcv->entry);
- LeaveCriticalSection(&xcv_handles_cs);
- heap_free(xcv);
- return TRUE;
-}
-
-/*****************************************************
- * localmon_XcvDataPort [exported through MONITOREX]
- *
- * Execute command through a Communication-Channel
- *
- * PARAMS
- * hXcv [i] The Handle to work with
- * pszDataName [i] Name of the command to execute
- * pInputData [i] Buffer for extra Input Data (needed only for some commands)
- * cbInputData [i] Size in Bytes of Buffer at pInputData
- * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
- * cbOutputData [i] Size in Bytes of Buffer at pOutputData
- * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
- *
- * RETURNS
- * Success: ERROR_SUCCESS
- * Failure: win32 error code
- *
- * NOTES
- *
- * Minimal List of commands, that every Printmonitor DLL should support:
- *
- *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
- *| "AddPort" : Add a Port (Name as WSTR in pInputData)
- *| "DeletePort": Delete a Port (Name as WSTR in pInputData)
- *
- *
- */
-static DWORD WINAPI localmon_XcvDataPort(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData,
- PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded)
-{
- WCHAR buffer[16]; /* buffer for a decimal number */
- LPWSTR ptr;
- DWORD res;
- DWORD needed;
- HKEY hroot;
-
- TRACE("(%p, %s, %p, %d, %p, %d, %p)\n", hXcv, debugstr_w(pszDataName),
- pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
-
- if (!lstrcmpW(pszDataName, cmd_AddPortW)) {
- TRACE("InputData (%d): %s\n", cbInputData, debugstr_w( (LPWSTR) pInputData));
- res = RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot);
- if (res == ERROR_SUCCESS) {
- if (does_port_exist((LPWSTR) pInputData)) {
- RegCloseKey(hroot);
- TRACE("=> %u\n", ERROR_ALREADY_EXISTS);
- return ERROR_ALREADY_EXISTS;
- }
- res = RegSetValueExW(hroot, (LPWSTR) pInputData, 0, REG_SZ, (const BYTE *) emptyW, sizeof(emptyW));
- RegCloseKey(hroot);
- }
- TRACE("=> %u\n", res);
- return res;
- }
-
-
- if (!lstrcmpW(pszDataName, cmd_ConfigureLPTPortCommandOKW)) {
- TRACE("InputData (%d): %s\n", cbInputData, debugstr_w( (LPWSTR) pInputData));
- res = RegCreateKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_WindowsW, &hroot);
- if (res == ERROR_SUCCESS) {
- res = RegSetValueExW(hroot, TransmissionRetryTimeoutW, 0, REG_SZ, pInputData, cbInputData);
- RegCloseKey(hroot);
- }
- return res;
- }
-
- if (!lstrcmpW(pszDataName, cmd_DeletePortW)) {
- TRACE("InputData (%d): %s\n", cbInputData, debugstr_w( (LPWSTR) pInputData));
- res = RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot);
- if (res == ERROR_SUCCESS) {
- res = RegDeleteValueW(hroot, (LPWSTR) pInputData);
- RegCloseKey(hroot);
- TRACE("=> %u with %u\n", res, GetLastError() );
- return res;
- }
- return ERROR_FILE_NOT_FOUND;
- }
-
- if (!lstrcmpW(pszDataName, cmd_GetDefaultCommConfigW)) {
- TRACE("InputData (%d): %s\n", cbInputData, debugstr_w( (LPWSTR) pInputData));
- *pcbOutputNeeded = cbOutputData;
- res = GetDefaultCommConfigW((LPWSTR) pInputData, (LPCOMMCONFIG) pOutputData, pcbOutputNeeded);
- TRACE("got %u with %u\n", res, GetLastError() );
- return res ? ERROR_SUCCESS : GetLastError();
- }
-
- if (!lstrcmpW(pszDataName, cmd_GetTransmissionRetryTimeoutW)) {
- * pcbOutputNeeded = sizeof(DWORD);
- if (cbOutputData >= sizeof(DWORD)) {
- /* the w2k resource kit documented a default of 90, but that's wrong */
- *((LPDWORD) pOutputData) = 45;
-
- res = RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_WindowsW, &hroot);
- if (res == ERROR_SUCCESS) {
- needed = sizeof(buffer) - sizeof(WCHAR);
- res = RegQueryValueExW(hroot, TransmissionRetryTimeoutW, NULL, NULL, (LPBYTE) buffer, &needed);
- if ((res == ERROR_SUCCESS) && (buffer[0])) {
- *((LPDWORD) pOutputData) = strtoulW(buffer, NULL, 0);
- }
- RegCloseKey(hroot);
- }
- return ERROR_SUCCESS;
- }
- return ERROR_INSUFFICIENT_BUFFER;
- }
-
-
- if (!lstrcmpW(pszDataName, cmd_MonitorUIW)) {
- * pcbOutputNeeded = sizeof(dllnameuiW);
- if (cbOutputData >= sizeof(dllnameuiW)) {
- memcpy(pOutputData, dllnameuiW, sizeof(dllnameuiW));
- return ERROR_SUCCESS;
- }
- return ERROR_INSUFFICIENT_BUFFER;
- }
-
- if (!lstrcmpW(pszDataName, cmd_PortIsValidW)) {
- TRACE("InputData (%d): %s\n", cbInputData, debugstr_w( (LPWSTR) pInputData));
- res = get_type_from_name((LPCWSTR) pInputData);
- TRACE("detected as %u\n", res);
- /* names, that we have recognized, are valid */
- if (res) return ERROR_SUCCESS;
-
- /* ERROR_ACCESS_DENIED, ERROR_PATH_NOT_FOUND or something else */
- TRACE("=> %u\n", GetLastError());
- return GetLastError();
- }
-
- if (!lstrcmpW(pszDataName, cmd_SetDefaultCommConfigW)) {
- /* get the portname from the Handle */
- ptr = strchrW(((xcv_t *)hXcv)->nameW, ' ');
- if (ptr) {
- ptr++; /* skip the space */
- }
- else
- {
- ptr = ((xcv_t *)hXcv)->nameW;
- }
- lstrcpynW(buffer, ptr, sizeof(buffer)/sizeof(WCHAR));
- if (buffer[0]) buffer[lstrlenW(buffer)-1] = '\0'; /* remove the ':' */
- res = SetDefaultCommConfigW(buffer, (LPCOMMCONFIG) pInputData, cbInputData);
- TRACE("got %u with %u\n", res, GetLastError() );
- return res ? ERROR_SUCCESS : GetLastError();
- }
-
- FIXME("command not supported: %s\n", debugstr_w(pszDataName));
- return ERROR_INVALID_PARAMETER;
-}
-
-/*****************************************************
- * localmon_XcvOpenPort [exported through MONITOREX]
- *
- * Open a Communication-Channel
- *
- * PARAMS
- * pName [i] Name of selected Object
- * GrantedAccess [i] Access-Rights to use
- * phXcv [o] The resulting Handle is stored here
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- */
-static BOOL WINAPI localmon_XcvOpenPort(LPCWSTR pName, ACCESS_MASK GrantedAccess, PHANDLE phXcv)
-{
- xcv_t * xcv;
-
- TRACE("%s, 0x%x, %p)\n", debugstr_w(pName), GrantedAccess, phXcv);
- /* No checks for any field is done in Windows */
- xcv = heap_alloc(FIELD_OFFSET(xcv_t, nameW[lstrlenW(pName) + 1]));
- if (xcv) {
- xcv->GrantedAccess = GrantedAccess;
- lstrcpyW(xcv->nameW, pName);
- *phXcv = xcv;
- EnterCriticalSection(&xcv_handles_cs);
- list_add_tail(&xcv_handles, &xcv->entry);
- LeaveCriticalSection(&xcv_handles_cs);
- TRACE("=> %p\n", xcv);
- return TRUE;
- }
- else
- {
- *phXcv = NULL;
- return FALSE;
- }
-}
-
-/*****************************************************
- * InitializePrintMonitor (LOCALSPL.@)
- *
- * Initialize the Monitor for the Local Ports
- *
- * PARAMS
- * regroot [I] Registry-Path, where the settings are stored
- *
- * RETURNS
- * Success: Pointer to a MONITOREX Structure
- * Failure: NULL
- *
- * NOTES
- * The fixed location "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Ports"
- * is used to store the Ports (IniFileMapping from "win.ini", Section "Ports").
- * Native localspl.dll fails, when no valid Port-Entry is present.
- *
- */
-
-LPMONITOREX WINAPI InitializePrintMonitor(LPWSTR regroot)
-{
- static MONITOREX mymonitorex =
- {
- sizeof(MONITOREX) - sizeof(DWORD),
- {
- localmon_EnumPortsW,
- localmon_OpenPortW,
- NULL, /* localmon_OpenPortExW */
- NULL, /* localmon_StartDocPortW */
- NULL, /* localmon_WritePortW */
- NULL, /* localmon_ReadPortW */
- NULL, /* localmon_EndDocPortW */
- localmon_ClosePort,
- NULL, /* Use AddPortUI in localui.dll */
- localmon_AddPortExW,
- NULL, /* Use ConfigurePortUI in localui.dll */
- NULL, /* Use DeletePortUI in localui.dll */
- NULL, /* localmon_GetPrinterDataFromPort */
- NULL, /* localmon_SetPortTimeOuts */
- localmon_XcvOpenPort,
- localmon_XcvDataPort,
- localmon_XcvClosePort
- }
- };
-
- TRACE("(%s)\n", debugstr_w(regroot));
- /* Parameter "regroot" is ignored on NT4.0 (localmon.dll) */
- if (!regroot || !regroot[0]) {
- SetLastError(ERROR_INVALID_PARAMETER);
- return NULL;
- }
- TRACE("=> %p\n", &mymonitorex);
- /* Native windows returns always the same pointer on success */
- return &mymonitorex;
-}
+++ /dev/null
-@ stub ClosePrintProcessor
-@ stub ControlPrintProcessor
-@ stub EnumPrintProcessorDatatypesW
-@ stub GetPrintProcessorCapabilities
-@ stdcall InitializePrintMonitor(wstr)
-# "Providor" is no typo here
-@ stdcall InitializePrintProvidor(ptr long wstr)
-@ stub OpenPrintProcessor
-@ stub PrintDocumentOnPrintProcessor
-@ stub PrintProcLogEvent
-@ stub SplAddForm
-@ stub SplAddMonitor
-@ stub SplAddPort
-@ stub SplAddPortEx
-@ stub SplAddPrinter
-@ stub SplAddPrinterDriverEx
-@ stub SplAddPrintProcessor
-@ stub SplBroadcastChange
-@ stub SplClosePrinter
-@ stub SplCloseSpooler
-@ stub SplConfigChange
-@ stub SplCopyFileEvent
-@ stub SplCopyNumberOfFiles
-@ stub SplCreateSpooler
-@ stub SplDeleteForm
-@ stub SplDeleteMonitor
-@ stub SplDeletePort
-@ stub SplDeletePrinter
-@ stub SplDeletePrinterDriverEx
-@ stub SplDeletePrinterKey
-@ stub SplDeletePrintProcessor
-@ stub SplDeleteSpooler
-@ stub SplDriverEvent
-@ stub SplEnumForms
-@ stub SplEnumMonitors
-@ stub SplEnumPorts
-@ stub SplEnumPrinterDataEx
-@ stub SplEnumPrinterKey
-@ stub SplEnumPrinters
-@ stub SplEnumPrintProcessorDatatypes
-@ stub SplEnumPrintProcessors
-@ stub SplGetDriverDir
-@ stub SplGetForm
-@ stub SplGetPrinter
-@ stub SplGetPrinterData
-@ stub SplGetPrinterDataEx
-@ stub SplGetPrinterDriver
-@ stub SplGetPrinterDriverDirectory
-@ stub SplGetPrinterDriverEx
-@ stub SplGetPrinterExtra
-@ stub SplGetPrinterExtraEx
-@ stub SplGetPrintProcessorDirectory
-@ stub SplLoadLibraryTheCopyFileModule
-@ stub SplMonitorIsInstalled
-@ stub SplOpenPrinter
-@ stub SplReenumeratePorts
-@ stub SplResetPrinter
-@ stub SplSetForm
-@ stub SplSetPrinter
-@ stub SplSetPrinterData
-@ stub SplSetPrinterDataEx
-@ stub SplSetPrinterExtra
-@ stub SplSetPrinterExtraEx
-@ stub SplXcvData
+++ /dev/null
-/*
- * Implementation of the Local Printprovider/ Printmonitor/ Prontprocessor
- *
- * Copyright 2006-2009 Detlef Riekenberg
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#include "localspl_private.h"
-
-HINSTANCE LOCALSPL_hInstance = NULL;
-
-/*****************************************************
- * DllMain
- */
-BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
-{
- TRACE("(%p, %d, %p)\n",hinstDLL, fdwReason, lpvReserved);
-
- switch(fdwReason)
- {
- case DLL_WINE_PREATTACH:
- return FALSE; /* prefer native version */
-
- case DLL_PROCESS_ATTACH:
- DisableThreadLibraryCalls( hinstDLL );
- LOCALSPL_hInstance = hinstDLL;
- setup_provider();
- break;
- }
- return TRUE;
-}
+++ /dev/null
-/*
- * Implementation of the Local Printmonitor: internal include file
- *
- * Copyright 2006 Detlef Riekenberg
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#ifndef __WINE_LOCALSPL_PRIVATE__
-#define __WINE_LOCALSPL_PRIVATE__
-
-#include <stdarg.h>
-
-#define WIN32_NO_STATUS
-#define _INC_WINDOWS
-#define COM_NO_WINDOWS_H
-
-#define COBJMACROS
-#define NONAMELESSUNION
-
-#include <windef.h>
-#include <winbase.h>
-#include <wingdi.h>
-#include <winuser.h>
-#include <winreg.h>
-#include <winspool.h>
-
-#include <wine/list.h>
-#include <wine/unicode.h>
-#include <ddk/winsplp.h>
-
-#include <wine/debug.h>
-WINE_DEFAULT_DEBUG_CHANNEL(localspl);
-
-/* ## DLL-wide Globals ## */
-extern HINSTANCE LOCALSPL_hInstance DECLSPEC_HIDDEN;
-void setup_provider(void) DECLSPEC_HIDDEN;
-
-/* ## Type of Ports ## */
-/* windows types */
-#define PORT_IS_UNKNOWN 0
-#define PORT_IS_LPT 1
-#define PORT_IS_COM 2
-#define PORT_IS_FILE 3
-#define PORT_IS_FILENAME 4
-
-/* wine extensions */
-#define PORT_IS_WINE 5
-#define PORT_IS_UNIXNAME 5
-#define PORT_IS_PIPE 6
-#define PORT_IS_CUPS 7
-#define PORT_IS_LPR 8
-
-
-/* ## Memory allocation functions ## */
-
-static inline void * __WINE_ALLOC_SIZE(1) heap_alloc( size_t len )
-{
- return HeapAlloc( GetProcessHeap(), 0, len );
-}
-
-static inline void * __WINE_ALLOC_SIZE(1) heap_alloc_zero( size_t len )
-{
- return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len );
-}
-
-static inline void * __WINE_ALLOC_SIZE(2) heap_realloc_zero( void * mem, size_t len )
-{
- return HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, mem, len );
-}
-
-static inline BOOL heap_free( void *mem )
-{
- return HeapFree( GetProcessHeap(), 0, mem );
-}
-
-#endif /* __WINE_LOCALSPL_PRIVATE__ */
+++ /dev/null
-/*
- * Implementation of the Local Printprovider
- *
- * Copyright 2006-2009 Detlef Riekenberg
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#include "localspl_private.h"
-
-#include <shlwapi.h>
-#include <ddk/winddiui.h>
-
-/* ############################### */
-
-static CRITICAL_SECTION monitor_handles_cs;
-static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
-{
- 0, 0, &monitor_handles_cs,
- { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
- 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
-};
-static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
-
-/* ############################### */
-
-typedef struct {
- WCHAR src[MAX_PATH+MAX_PATH];
- WCHAR dst[MAX_PATH+MAX_PATH];
- DWORD srclen;
- DWORD dstlen;
- DWORD copyflags;
- BOOL lazy;
-} apd_data_t;
-
-typedef struct {
- struct list entry;
- LPWSTR name;
- LPWSTR dllname;
- PMONITORUI monitorUI;
- LPMONITOR monitor;
- HMODULE hdll;
- DWORD refcount;
- DWORD dwMonitorSize;
-} monitor_t;
-
-typedef struct {
- LPCWSTR envname;
- LPCWSTR subdir;
- DWORD driverversion;
- LPCWSTR versionregpath;
- LPCWSTR versionsubdir;
-} printenv_t;
-
-typedef struct {
- LPWSTR name;
- LPWSTR printername;
- monitor_t * pm;
- HANDLE hXcv;
-} printer_t;
-
-/* ############################### */
-
-static struct list monitor_handles = LIST_INIT( monitor_handles );
-static monitor_t * pm_localport;
-
-static const PRINTPROVIDOR * pprovider = NULL;
-
-static const WCHAR backslashW[] = {'\\',0};
-static const WCHAR bs_ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
-static const WCHAR configuration_fileW[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
-static const WCHAR datatypeW[] = {'D','a','t','a','t','y','p','e',0};
-static const WCHAR data_fileW[] = {'D','a','t','a',' ','F','i','l','e',0};
-static const WCHAR dependent_filesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
-static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
-static const WCHAR emptyW[] = {0};
-static const WCHAR fmt_driversW[] = { 'S','y','s','t','e','m','\\',
- 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
- 'c','o','n','t','r','o','l','\\',
- 'P','r','i','n','t','\\',
- 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
- '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
-static const WCHAR fmt_printprocessorsW[] = { 'S','y','s','t','e','m','\\',
- 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
- 'C','o','n','t','r','o','l','\\',
- 'P','r','i','n','t','\\',
- 'E','n','v','i','r','o','n','m','e','n','t','s','\\','%','s','\\',
- 'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r','s',0 };
-static const WCHAR help_fileW[] = {'H','e','l','p',' ','F','i','l','e',0};
-static const WCHAR ia64_envnameW[] = {'W','i','n','d','o','w','s',' ','I','A','6','4',0};
-static const WCHAR ia64_subdirW[] = {'i','a','6','4',0};
-static const WCHAR localportW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
-static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
-static const WCHAR monitorsW[] = {'S','y','s','t','e','m','\\',
- 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
- 'C','o','n','t','r','o','l','\\',
- 'P','r','i','n','t','\\',
- 'M','o','n','i','t','o','r','s','\\',0};
-static const WCHAR monitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
-static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
-static const WCHAR printersW[] = {'S','y','s','t','e','m','\\',
- 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
- 'C','o','n','t','r','o','l','\\',
- 'P','r','i','n','t','\\',
- 'P','r','i','n','t','e','r','s',0};
-static const WCHAR spoolW[] = {'\\','s','p','o','o','l',0};
-static const WCHAR driversW[] = {'\\','d','r','i','v','e','r','s','\\',0};
-static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
-static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
-static const WCHAR version0_subdirW[] = {'\\','0',0};
-static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
-static const WCHAR version3_subdirW[] = {'\\','3',0};
-static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
-static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
-static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
-static const WCHAR winnt_cv_portsW[] = {'S','o','f','t','w','a','r','e','\\',
- 'M','i','c','r','o','s','o','f','t','\\',
- 'W','i','n','d','o','w','s',' ','N','T','\\',
- 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
- 'P','o','r','t','s',0};
-static const WCHAR winprintW[] = {'w','i','n','p','r','i','n','t',0};
-static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
-static const WCHAR x64_subdirW[] = {'x','6','4',0};
-static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
-static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
-static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
-static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
-
-
-static const printenv_t env_ia64 = {ia64_envnameW, ia64_subdirW, 3,
- version3_regpathW, version3_subdirW};
-
-static const printenv_t env_x86 = {x86_envnameW, x86_subdirW, 3,
- version3_regpathW, version3_subdirW};
-
-static const printenv_t env_x64 = {x64_envnameW, x64_subdirW, 3,
- version3_regpathW, version3_subdirW};
-
-static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
- version0_regpathW, version0_subdirW};
-
-static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_ia64, &env_win40};
-
-
-static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
- sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
- sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
- 0, sizeof(DRIVER_INFO_8W)};
-
-
-/******************************************************************
- * strdupW [internal]
- *
- * create a copy of a unicode-string
- *
- */
-static LPWSTR strdupW(LPCWSTR p)
-{
- LPWSTR ret;
- DWORD len;
-
- if(!p) return NULL;
- len = (lstrlenW(p) + 1) * sizeof(WCHAR);
- ret = heap_alloc(len);
- if (ret) memcpy(ret, p, len);
- return ret;
-}
-
-/******************************************************************
- * apd_copyfile [internal]
- *
- * Copy a file from the driverdirectory to the versioned directory
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- */
-static BOOL apd_copyfile( WCHAR *pathname, WCHAR *file_part, apd_data_t *apd )
-{
- WCHAR *srcname;
- BOOL res;
-
- apd->src[apd->srclen] = '\0';
- apd->dst[apd->dstlen] = '\0';
-
- if (!pathname || !pathname[0]) {
- /* nothing to copy */
- return TRUE;
- }
-
- if (apd->copyflags & APD_COPY_FROM_DIRECTORY)
- srcname = pathname;
- else
- {
- srcname = apd->src;
- strcatW( srcname, file_part );
- }
- strcatW( apd->dst, file_part );
-
- TRACE("%s => %s\n", debugstr_w(srcname), debugstr_w(apd->dst));
-
- /* FIXME: handle APD_COPY_NEW_FILES */
- res = CopyFileW(srcname, apd->dst, FALSE);
- TRACE("got %d with %u\n", res, GetLastError());
-
- return apd->lazy || res;
-}
-
-/******************************************************************
- * copy_servername_from_name (internal)
- *
- * for an external server, the serverpart from the name is copied.
- *
- * RETURNS
- * the length (in WCHAR) of the serverpart (0 for the local computer)
- * (-length), when the name is too long
- *
- */
-static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
-{
- LPCWSTR server;
- LPWSTR ptr;
- WCHAR buffer[MAX_COMPUTERNAME_LENGTH +1];
- DWORD len;
- DWORD serverlen;
-
- if (target) *target = '\0';
-
- if (name == NULL) return 0;
- if ((name[0] != '\\') || (name[1] != '\\')) return 0;
-
- server = &name[2];
- /* skip over both backslash, find separator '\' */
- ptr = strchrW(server, '\\');
- serverlen = (ptr) ? ptr - server : lstrlenW(server);
-
- /* servername is empty */
- if (serverlen == 0) return 0;
-
- TRACE("found %s\n", debugstr_wn(server, serverlen));
-
- if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
-
- if (target) {
- memcpy(target, server, serverlen * sizeof(WCHAR));
- target[serverlen] = '\0';
- }
-
- len = sizeof(buffer) / sizeof(buffer[0]);
- if (GetComputerNameW(buffer, &len)) {
- if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
- /* The requested Servername is our computername */
- return 0;
- }
- }
- return serverlen;
-}
-
-/******************************************************************
- * get_basename_from_name (internal)
- *
- * skip over the serverpart from the full name
- *
- */
-static LPCWSTR get_basename_from_name(LPCWSTR name)
-{
- if (name == NULL) return NULL;
- if ((name[0] == '\\') && (name[1] == '\\')) {
- /* skip over the servername and search for the following '\' */
- name = strchrW(&name[2], '\\');
- if ((name) && (name[1])) {
- /* found a separator ('\') followed by a name:
- skip over the separator and return the rest */
- name++;
- }
- else
- {
- /* no basename present (we found only a servername) */
- return NULL;
- }
- }
- return name;
-}
-
-/******************************************************************
- * monitor_unload [internal]
- *
- * release a printmonitor and unload it from memory, when needed
- *
- */
-static void monitor_unload(monitor_t * pm)
-{
- if (pm == NULL) return;
- TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
-
- EnterCriticalSection(&monitor_handles_cs);
-
- if (pm->refcount) pm->refcount--;
-
- if (pm->refcount == 0) {
- list_remove(&pm->entry);
- FreeLibrary(pm->hdll);
- heap_free(pm->name);
- heap_free(pm->dllname);
- heap_free(pm);
- }
- LeaveCriticalSection(&monitor_handles_cs);
-}
-
-/******************************************************************
- * monitor_unloadall [internal]
- *
- * release all registered printmonitors and unload them from memory, when needed
- *
- */
-
-static void monitor_unloadall(void)
-{
- monitor_t * pm;
- monitor_t * next;
-
- EnterCriticalSection(&monitor_handles_cs);
- /* iterate through the list, with safety against removal */
- LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
- {
- /* skip monitorui dlls */
- if (pm->monitor) monitor_unload(pm);
- }
- LeaveCriticalSection(&monitor_handles_cs);
-}
-
-/******************************************************************
- * monitor_load [internal]
- *
- * load a printmonitor, get the dllname from the registry, when needed
- * initialize the monitor and dump found function-pointers
- *
- * On failure, SetLastError() is called and NULL is returned
- */
-
-static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
-{
- LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
- PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
- LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
- DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
- DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
-
- monitor_t * pm = NULL;
- monitor_t * cursor;
- LPWSTR regroot = NULL;
- LPWSTR driver = dllname;
-
- TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
- /* Is the Monitor already loaded? */
- EnterCriticalSection(&monitor_handles_cs);
-
- if (name) {
- LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
- {
- if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
- pm = cursor;
- break;
- }
- }
- }
-
- if (pm == NULL) {
- pm = heap_alloc_zero(sizeof(monitor_t));
- if (pm == NULL) goto cleanup;
- list_add_tail(&monitor_handles, &pm->entry);
- }
- pm->refcount++;
-
- if (pm->name == NULL) {
- /* Load the monitor */
- LPMONITOREX pmonitorEx;
- DWORD len;
-
- if (name) {
- len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
- regroot = heap_alloc(len * sizeof(WCHAR));
- }
-
- if (regroot) {
- lstrcpyW(regroot, monitorsW);
- lstrcatW(regroot, name);
- /* Get the Driver from the Registry */
- if (driver == NULL) {
- HKEY hroot;
- DWORD namesize;
- if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
- if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
- &namesize) == ERROR_SUCCESS) {
- driver = heap_alloc(namesize);
- RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
- }
- RegCloseKey(hroot);
- }
- }
- }
-
- pm->name = strdupW(name);
- pm->dllname = strdupW(driver);
-
- if ((name && (!regroot || !pm->name)) || !pm->dllname) {
- monitor_unload(pm);
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- pm = NULL;
- goto cleanup;
- }
-
- pm->hdll = LoadLibraryW(driver);
- TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
-
- if (pm->hdll == NULL) {
- monitor_unload(pm);
- SetLastError(ERROR_MOD_NOT_FOUND);
- pm = NULL;
- goto cleanup;
- }
-
- pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
- pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
- pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
- pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
- pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
-
-
- TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
- TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
- TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
- TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
- TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
-
- if (pInitializePrintMonitorUI != NULL) {
- pm->monitorUI = pInitializePrintMonitorUI();
- TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
- if (pm->monitorUI) {
- TRACE("0x%08x: dwMonitorSize (%d)\n",
- pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
-
- }
- }
-
- if (pInitializePrintMonitor && regroot) {
- pmonitorEx = pInitializePrintMonitor(regroot);
- TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
- pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
-
- if (pmonitorEx) {
- pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
- pm->monitor = &(pmonitorEx->Monitor);
- }
- }
-
- if (pm->monitor) {
- TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
-
- }
-
- if (!pm->monitor && regroot) {
- if (pInitializePrintMonitor2 != NULL) {
- FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
- }
- if (pInitializeMonitorEx != NULL) {
- FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
- }
- if (pInitializeMonitor != NULL) {
- FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
- }
- }
- if (!pm->monitor && !pm->monitorUI) {
- monitor_unload(pm);
- SetLastError(ERROR_PROC_NOT_FOUND);
- pm = NULL;
- }
- }
-cleanup:
- if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
- pm->refcount++;
- pm_localport = pm;
- }
- LeaveCriticalSection(&monitor_handles_cs);
- if (driver != dllname) heap_free(driver);
- heap_free(regroot);
- TRACE("=> %p\n", pm);
- return pm;
-}
-
-/******************************************************************
- * monitor_loadall [internal]
- *
- * Load all registered monitors
- *
- */
-static DWORD monitor_loadall(void)
-{
- monitor_t * pm;
- DWORD registered = 0;
- DWORD loaded = 0;
- HKEY hmonitors;
- WCHAR buffer[MAX_PATH];
- DWORD id = 0;
-
- if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
- RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, ®istered, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL);
-
- TRACE("%d monitors registered\n", registered);
-
- while (id < registered) {
- buffer[0] = '\0';
- RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
- pm = monitor_load(buffer, NULL);
- if (pm) loaded++;
- id++;
- }
- RegCloseKey(hmonitors);
- }
- TRACE("%d monitors loaded\n", loaded);
- return loaded;
-}
-
-/******************************************************************
- * monitor_loadui [internal]
- *
- * load the userinterface-dll for a given portmonitor
- *
- * On failure, NULL is returned
- */
-static monitor_t * monitor_loadui(monitor_t * pm)
-{
- monitor_t * pui = NULL;
- WCHAR buffer[MAX_PATH];
- HANDLE hXcv;
- DWORD len;
- DWORD res;
-
- if (pm == NULL) return NULL;
- TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
-
- /* Try the Portmonitor first; works for many monitors */
- if (pm->monitorUI) {
- EnterCriticalSection(&monitor_handles_cs);
- pm->refcount++;
- LeaveCriticalSection(&monitor_handles_cs);
- return pm;
- }
-
- /* query the userinterface-dllname from the Portmonitor */
- if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
- /* building (",XcvMonitor %s",pm->name) not needed yet */
- res = pm->monitor->pfnXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv);
- TRACE("got %u with %p\n", res, hXcv);
- if (res) {
- res = pm->monitor->pfnXcvDataPort(hXcv, monitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
- TRACE("got %u with %s\n", res, debugstr_w(buffer));
- if (res == ERROR_SUCCESS) pui = monitor_load(NULL, buffer);
- pm->monitor->pfnXcvClosePort(hXcv);
- }
- }
- return pui;
-}
-
-/******************************************************************
- * monitor_load_by_port [internal]
- *
- * load a printmonitor for a given port
- *
- * On failure, NULL is returned
- */
-
-static monitor_t * monitor_load_by_port(LPCWSTR portname)
-{
- HKEY hroot;
- HKEY hport;
- LPWSTR buffer;
- monitor_t * pm = NULL;
- DWORD registered = 0;
- DWORD id = 0;
- DWORD len;
-
- TRACE("(%s)\n", debugstr_w(portname));
-
- /* Try the Local Monitor first */
- if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
- if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
- /* found the portname */
- RegCloseKey(hroot);
- return monitor_load(localportW, NULL);
- }
- RegCloseKey(hroot);
- }
-
- len = MAX_PATH + lstrlenW(bs_ports_bsW) + lstrlenW(portname) + 1;
- buffer = heap_alloc(len * sizeof(WCHAR));
- if (buffer == NULL) return NULL;
-
- if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
- EnterCriticalSection(&monitor_handles_cs);
- RegQueryInfoKeyW(hroot, NULL, NULL, NULL, ®istered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
-
- while ((pm == NULL) && (id < registered)) {
- buffer[0] = '\0';
- RegEnumKeyW(hroot, id, buffer, MAX_PATH);
- TRACE("testing %s\n", debugstr_w(buffer));
- len = lstrlenW(buffer);
- lstrcatW(buffer, bs_ports_bsW);
- lstrcatW(buffer, portname);
- if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
- RegCloseKey(hport);
- buffer[len] = '\0'; /* use only the Monitor-Name */
- pm = monitor_load(buffer, NULL);
- }
- id++;
- }
- LeaveCriticalSection(&monitor_handles_cs);
- RegCloseKey(hroot);
- }
- heap_free(buffer);
- return pm;
-}
-
-/******************************************************************
- * Return the number of bytes for an multi_sz string.
- * The result includes all \0s
- * (specifically the extra \0, that is needed as multi_sz terminator).
- */
-static int multi_sz_lenW(const WCHAR *str)
-{
- const WCHAR *ptr = str;
- if (!str) return 0;
- do
- {
- ptr += lstrlenW(ptr) + 1;
- } while (*ptr);
-
- return (ptr - str + 1) * sizeof(WCHAR);
-}
-
-/******************************************************************
- * validate_envW [internal]
- *
- * validate the user-supplied printing-environment
- *
- * PARAMS
- * env [I] PTR to Environment-String or NULL
- *
- * RETURNS
- * Success: PTR to printenv_t
- * Failure: NULL and ERROR_INVALID_ENVIRONMENT
- *
- * NOTES
- * An empty string is handled the same way as NULL.
- *
- */
-
-static const printenv_t * validate_envW(LPCWSTR env)
-{
- const printenv_t *result = NULL;
- unsigned int i;
-
- TRACE("(%s)\n", debugstr_w(env));
- if (env && env[0])
- {
- for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
- {
- if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
- {
- result = all_printenv[i];
- break;
- }
- }
- if (result == NULL) {
- FIXME("unsupported Environment: %s\n", debugstr_w(env));
- SetLastError(ERROR_INVALID_ENVIRONMENT);
- }
- /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
- }
- else
- {
- result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
- }
-
- TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
- return result;
-}
-
-/*****************************************************************************
- * enumerate the local monitors (INTERNAL)
- *
- * returns the needed size (in bytes) for pMonitors
- * and *lpreturned is set to number of entries returned in pMonitors
- *
- * Language-Monitors are also installed in the same Registry-Location but
- * they are filtered in Windows (not returned by EnumMonitors).
- * We do no filtering to simplify our Code.
- *
- */
-static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
-{
- HKEY hroot = NULL;
- HKEY hentry = NULL;
- LPWSTR ptr;
- LPMONITOR_INFO_2W mi;
- WCHAR buffer[MAX_PATH];
- WCHAR dllname[MAX_PATH];
- DWORD dllsize;
- DWORD len;
- DWORD index = 0;
- DWORD needed = 0;
- DWORD numentries;
- DWORD entrysize;
-
- entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
-
- numentries = *lpreturned; /* this is 0, when we scan the registry */
- len = entrysize * numentries;
- ptr = (LPWSTR) &pMonitors[len];
-
- numentries = 0;
- len = sizeof(buffer)/sizeof(buffer[0]);
- buffer[0] = '\0';
-
- /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
- if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
- /* Scan all Monitor-Registry-Keys */
- while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
- TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
- dllsize = sizeof(dllname);
- dllname[0] = '\0';
-
- /* The Monitor must have a Driver-DLL */
- if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
- if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
- /* We found a valid DLL for this Monitor. */
- TRACE("using Driver: %s\n", debugstr_w(dllname));
- }
- RegCloseKey(hentry);
- }
-
- /* Windows returns only Port-Monitors here, but to simplify our code,
- we do no filtering for Language-Monitors */
- if (dllname[0]) {
- numentries++;
- needed += entrysize;
- needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
- if (level > 1) {
- /* we install and return only monitors for "Windows NT x86" */
- needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
- needed += dllsize;
- }
-
- /* required size is calculated. Now fill the user-buffer */
- if (pMonitors && (cbBuf >= needed)){
- mi = (LPMONITOR_INFO_2W) pMonitors;
- pMonitors += entrysize;
-
- TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
- mi->pName = ptr;
- lstrcpyW(ptr, buffer); /* Name of the Monitor */
- ptr += (len+1); /* len is lstrlenW(monitorname) */
- if (level > 1) {
- mi->pEnvironment = ptr;
- lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
- ptr += (lstrlenW(x86_envnameW)+1);
-
- mi->pDLLName = ptr;
- lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
- ptr += (dllsize / sizeof(WCHAR));
- }
- }
- }
- index++;
- len = sizeof(buffer)/sizeof(buffer[0]);
- buffer[0] = '\0';
- }
- RegCloseKey(hroot);
- }
- *lpreturned = numentries;
- TRACE("need %d byte for %d entries\n", needed, numentries);
- return needed;
-}
-
-/*****************************************************************************
- * enumerate the local print processors (INTERNAL)
- *
- * returns the needed size (in bytes) for pPPInfo
- * and *lpreturned is set to number of entries returned in pPPInfo
- *
- */
-static DWORD get_local_printprocessors(LPWSTR regpathW, LPBYTE pPPInfo, DWORD cbBuf, LPDWORD lpreturned)
-{
- HKEY hroot = NULL;
- HKEY hentry = NULL;
- LPWSTR ptr;
- PPRINTPROCESSOR_INFO_1W ppi;
- WCHAR buffer[MAX_PATH];
- WCHAR dllname[MAX_PATH];
- DWORD dllsize;
- DWORD len;
- DWORD index = 0;
- DWORD needed = 0;
- DWORD numentries;
-
- numentries = *lpreturned; /* this is 0, when we scan the registry */
- len = numentries * sizeof(PRINTPROCESSOR_INFO_1W);
- ptr = (LPWSTR) &pPPInfo[len];
-
- numentries = 0;
- len = sizeof(buffer)/sizeof(buffer[0]);
- buffer[0] = '\0';
-
- if (RegCreateKeyW(HKEY_LOCAL_MACHINE, regpathW, &hroot) == ERROR_SUCCESS) {
- /* add "winprint" first */
- numentries++;
- needed = sizeof(PRINTPROCESSOR_INFO_1W) + sizeof(winprintW);
- if (pPPInfo && (cbBuf >= needed)){
- ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
- pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
-
- TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
- ppi->pName = ptr;
- lstrcpyW(ptr, winprintW); /* Name of the Print Processor */
- ptr += sizeof(winprintW) / sizeof(WCHAR);
- }
-
- /* Scan all Printprocessor Keys */
- while ((RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) &&
- (lstrcmpiW(buffer, winprintW) != 0)) {
- TRACE("PrintProcessor_%d: %s\n", numentries, debugstr_w(buffer));
- dllsize = sizeof(dllname);
- dllname[0] = '\0';
-
- /* The Print Processor must have a Driver-DLL */
- if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
- if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
- /* We found a valid DLL for this Print Processor */
- TRACE("using Driver: %s\n", debugstr_w(dllname));
- }
- RegCloseKey(hentry);
- }
-
- if (dllname[0]) {
- numentries++;
- needed += sizeof(PRINTPROCESSOR_INFO_1W);
- needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(printprocessor name) */
-
- /* required size is calculated. Now fill the user-buffer */
- if (pPPInfo && (cbBuf >= needed)){
- ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
- pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
-
- TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
- ppi->pName = ptr;
- lstrcpyW(ptr, buffer); /* Name of the Print Processor */
- ptr += (len+1); /* len is lstrlenW(printprosessor name) */
- }
- }
- index++;
- len = sizeof(buffer)/sizeof(buffer[0]);
- buffer[0] = '\0';
- }
- RegCloseKey(hroot);
- }
- *lpreturned = numentries;
- TRACE("need %d byte for %d entries\n", needed, numentries);
- return needed;
-}
-
-/******************************************************************
- * enumerate the local Ports from all loaded monitors (internal)
- *
- * returns the needed size (in bytes) for pPorts
- * and *lpreturned is set to number of entries returned in pPorts
- *
- */
-static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
-{
- monitor_t * pm;
- LPWSTR ptr;
- LPPORT_INFO_2W cache;
- LPPORT_INFO_2W out;
- LPBYTE pi_buffer = NULL;
- DWORD pi_allocated = 0;
- DWORD pi_needed;
- DWORD pi_index;
- DWORD pi_returned;
- DWORD res;
- DWORD outindex = 0;
- DWORD needed;
- DWORD numentries;
- DWORD entrysize;
-
-
- TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
- entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
-
- numentries = *lpreturned; /* this is 0, when we scan the registry */
- needed = entrysize * numentries;
- ptr = (LPWSTR) &pPorts[needed];
-
- numentries = 0;
- needed = 0;
-
- LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
- {
- if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
- pi_needed = 0;
- pi_returned = 0;
- res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
- if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
- /* Do not use heap_realloc (we do not need the old data in the buffer) */
- heap_free(pi_buffer);
- pi_buffer = heap_alloc(pi_needed);
- pi_allocated = (pi_buffer) ? pi_needed : 0;
- res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
- }
- TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
- debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
-
- numentries += pi_returned;
- needed += pi_needed;
-
- /* fill the output-buffer (pPorts), if we have one */
- if (pPorts && (cbBuf >= needed ) && pi_buffer) {
- pi_index = 0;
- while (pi_returned > pi_index) {
- cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
- out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
- out->pPortName = ptr;
- lstrcpyW(ptr, cache->pPortName);
- ptr += (lstrlenW(ptr)+1);
- if (level > 1) {
- out->pMonitorName = ptr;
- lstrcpyW(ptr, cache->pMonitorName);
- ptr += (lstrlenW(ptr)+1);
-
- out->pDescription = ptr;
- lstrcpyW(ptr, cache->pDescription);
- ptr += (lstrlenW(ptr)+1);
- out->fPortType = cache->fPortType;
- out->Reserved = cache->Reserved;
- }
- pi_index++;
- outindex++;
- }
- }
- }
- }
- /* the temporary portinfo-buffer is no longer needed */
- heap_free(pi_buffer);
-
- *lpreturned = numentries;
- TRACE("need %d byte for %d entries\n", needed, numentries);
- return needed;
-}
-
-
-/*****************************************************************************
- * open_driver_reg [internal]
- *
- * opens the registry for the printer drivers depending on the given input
- * variable pEnvironment
- *
- * RETURNS:
- * Success: the opened hkey
- * Failure: NULL
- */
-static HKEY open_driver_reg(LPCWSTR pEnvironment)
-{
- HKEY retval = NULL;
- LPWSTR buffer;
- const printenv_t * env;
-
- TRACE("(%s)\n", debugstr_w(pEnvironment));
-
- env = validate_envW(pEnvironment);
- if (!env) return NULL;
-
- buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
- (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
-
- if (buffer) {
- wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
- RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
- HeapFree(GetProcessHeap(), 0, buffer);
- }
- return retval;
-}
-
-/*****************************************************************************
- * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
- *
- * Return the PATH for the Printer-Drivers
- *
- * PARAMS
- * pName [I] Servername (NT only) or NULL (local Computer)
- * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
- * Level [I] Structure-Level (must be 1)
- * pDriverDirectory [O] PTR to Buffer that receives the Result
- * cbBuf [I] Size of Buffer at pDriverDirectory
- * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
- * required for pDriverDirectory
- *
- * RETURNS
- * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
- * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
- * if cbBuf is too small
- *
- * Native Values returned in pDriverDirectory on Success:
- *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
- *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
- *| win9x(Windows 4.0): "%winsysdir%"
- *
- * "%winsysdir%" is the Value from GetSystemDirectoryW()
- *
- */
-static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
- DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
-{
- DWORD needed;
- const printenv_t * env;
- WCHAR * const dir = (WCHAR *)pDriverDirectory;
-
- TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
- debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
-
- if (pName != NULL && pName[0]) {
- FIXME("server %s not supported\n", debugstr_w(pName));
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- env = validate_envW(pEnvironment);
- if (!env) return FALSE; /* pEnvironment invalid or unsupported */
-
-
- /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
- needed = GetSystemDirectoryW(NULL, 0);
- /* add the Size for the Subdirectories */
- needed += lstrlenW(spoolW);
- needed += lstrlenW(driversW);
- needed += lstrlenW(env->subdir);
- needed *= sizeof(WCHAR); /* return-value is size in Bytes */
-
- *pcbNeeded = needed;
-
- if (needed > cbBuf) {
- SetLastError(ERROR_INSUFFICIENT_BUFFER);
- return FALSE;
- }
-
- if (dir == NULL) {
- /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
- SetLastError(ERROR_INVALID_USER_BUFFER);
- return FALSE;
- }
-
- GetSystemDirectoryW( dir, cbBuf / sizeof(WCHAR) );
- /* add the Subdirectories */
- lstrcatW( dir, spoolW );
- CreateDirectoryW( dir, NULL );
- lstrcatW( dir, driversW );
- CreateDirectoryW( dir, NULL );
- lstrcatW( dir, env->subdir );
- CreateDirectoryW( dir, NULL );
-
- TRACE( "=> %s\n", debugstr_w( dir ) );
- return TRUE;
-}
-
-/******************************************************************
- * driver_load [internal]
- *
- * load a driver user interface dll
- *
- * On failure, NULL is returned
- *
- */
-
-static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
-{
- WCHAR fullname[MAX_PATH];
- HMODULE hui;
- DWORD len;
-
- TRACE("(%p, %s)\n", env, debugstr_w(dllname));
-
- /* build the driverdir */
- len = sizeof(fullname) -
- (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
-
- if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
- (LPBYTE) fullname, len, &len)) {
- /* Should never fail */
- SetLastError(ERROR_BUFFER_OVERFLOW);
- return NULL;
- }
-
- lstrcatW(fullname, env->versionsubdir);
- lstrcatW(fullname, backslashW);
- lstrcatW(fullname, dllname);
-
- hui = LoadLibraryW(fullname);
- TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
-
- return hui;
-}
-
-/******************************************************************
- * printer_free
- * free the data pointer of an opened printer
- */
-static VOID printer_free(printer_t * printer)
-{
- if (printer->hXcv)
- printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
-
- monitor_unload(printer->pm);
-
- heap_free(printer->printername);
- heap_free(printer->name);
- heap_free(printer);
-}
-
-/******************************************************************
- * printer_alloc_handle
- * alloc a printer handle and remember the data pointer in the printer handle table
- *
- */
-static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
-{
- WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
- printer_t *printer = NULL;
- LPCWSTR printername;
- HKEY hkeyPrinters;
- HKEY hkeyPrinter;
- DWORD len;
-
- if (copy_servername_from_name(name, servername)) {
- FIXME("server %s not supported\n", debugstr_w(servername));
- SetLastError(ERROR_INVALID_PRINTER_NAME);
- return NULL;
- }
-
- printername = get_basename_from_name(name);
- if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
-
- /* an empty printername is invalid */
- if (printername && (!printername[0])) {
- SetLastError(ERROR_INVALID_PARAMETER);
- return NULL;
- }
-
- printer = heap_alloc_zero(sizeof(printer_t));
- if (!printer) goto end;
-
- /* clone the base name. This is NULL for the printserver */
- printer->printername = strdupW(printername);
-
- /* clone the full name */
- printer->name = strdupW(name);
- if (name && (!printer->name)) {
- printer_free(printer);
- printer = NULL;
- }
- if (printername) {
- len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
- if (strncmpW(printername, XcvMonitorW, len) == 0) {
- /* OpenPrinter(",XcvMonitor ", ...) detected */
- TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
- printer->pm = monitor_load(&printername[len], NULL);
- if (printer->pm == NULL) {
- printer_free(printer);
- SetLastError(ERROR_UNKNOWN_PORT);
- printer = NULL;
- goto end;
- }
- }
- else
- {
- len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
- if (strncmpW( printername, XcvPortW, len) == 0) {
- /* OpenPrinter(",XcvPort ", ...) detected */
- TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
- printer->pm = monitor_load_by_port(&printername[len]);
- if (printer->pm == NULL) {
- printer_free(printer);
- SetLastError(ERROR_UNKNOWN_PORT);
- printer = NULL;
- goto end;
- }
- }
- }
-
- if (printer->pm) {
- if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
- printer->pm->monitor->pfnXcvOpenPort(&printername[len],
- pDefault ? pDefault->DesiredAccess : 0,
- &printer->hXcv);
- }
- if (printer->hXcv == NULL) {
- printer_free(printer);
- SetLastError(ERROR_INVALID_PARAMETER);
- printer = NULL;
- goto end;
- }
- }
- else
- {
- /* Does the Printer exist? */
- if (RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkeyPrinters) != ERROR_SUCCESS) {
- ERR("Can't create Printers key\n");
- printer_free(printer);
- SetLastError(ERROR_INVALID_PRINTER_NAME);
- printer = NULL;
- goto end;
- }
- if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
- WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
- RegCloseKey(hkeyPrinters);
- printer_free(printer);
- SetLastError(ERROR_INVALID_PRINTER_NAME);
- printer = NULL;
- goto end;
- }
- RegCloseKey(hkeyPrinter);
- RegCloseKey(hkeyPrinters);
- }
- }
- else
- {
- TRACE("using the local printserver\n");
- }
-
-end:
-
- TRACE("==> %p\n", printer);
- return (HANDLE)printer;
-}
-
-static inline WCHAR *get_file_part( WCHAR *name )
-{
- WCHAR *ptr = strrchrW( name, '\\' );
- if (ptr) return ptr + 1;
- return name;
-}
-
-/******************************************************************************
- * myAddPrinterDriverEx [internal]
- *
- * Install a Printer Driver with the Option to upgrade / downgrade the Files
- * and a special mode with lazy error checking.
- *
- */
-static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
-{
- const printenv_t *env;
- apd_data_t apd;
- DRIVER_INFO_8W di;
- BOOL (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
- HMODULE hui;
- WCHAR *file;
- HKEY hroot;
- HKEY hdrv;
- DWORD disposition;
- DWORD len;
- LONG lres;
- BOOL res;
-
- /* we need to set all entries in the Registry, independent from the Level of
- DRIVER_INFO, that the caller supplied */
-
- ZeroMemory(&di, sizeof(di));
- if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
- memcpy(&di, pDriverInfo, di_sizeof[level]);
- }
-
- /* dump the most used infos */
- TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
- TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
- TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
- TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
- TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
- TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
- TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
- /* dump only the first of the additional Files */
- TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
-
-
- /* check environment */
- env = validate_envW(di.pEnvironment);
- if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
-
- /* fill the copy-data / get the driverdir */
- len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
- if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
- (LPBYTE) apd.src, len, &len)) {
- /* Should never fail */
- return FALSE;
- }
- memcpy(apd.dst, apd.src, len);
- lstrcatW(apd.src, backslashW);
- apd.srclen = lstrlenW(apd.src);
- lstrcatW(apd.dst, env->versionsubdir);
- lstrcatW(apd.dst, backslashW);
- apd.dstlen = lstrlenW(apd.dst);
- apd.copyflags = dwFileCopyFlags;
- apd.lazy = lazy;
- CreateDirectoryW(apd.src, NULL);
- CreateDirectoryW(apd.dst, NULL);
-
- hroot = open_driver_reg(env->envname);
- if (!hroot) {
- ERR("Can't create Drivers key\n");
- return FALSE;
- }
-
- /* Fill the Registry for the Driver */
- if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
- KEY_WRITE | KEY_QUERY_VALUE, NULL,
- &hdrv, &disposition)) != ERROR_SUCCESS) {
-
- ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
- RegCloseKey(hroot);
- SetLastError(lres);
- return FALSE;
- }
- RegCloseKey(hroot);
-
- /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
- RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (const BYTE*) &env->driverversion,
- sizeof(DWORD));
-
- file = get_file_part( di.pDriverPath );
- RegSetValueExW( hdrv, driverW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
- apd_copyfile( di.pDriverPath, file, &apd );
-
- file = get_file_part( di.pDataFile );
- RegSetValueExW( hdrv, data_fileW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
- apd_copyfile( di.pDataFile, file, &apd );
-
- file = get_file_part( di.pConfigFile );
- RegSetValueExW( hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
- apd_copyfile( di.pConfigFile, file, &apd );
-
- /* settings for level 3 */
- if (di.pHelpFile)
- {
- file = get_file_part( di.pHelpFile );
- RegSetValueExW( hdrv, help_fileW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
- apd_copyfile( di.pHelpFile, file, &apd );
- }
- else
- RegSetValueExW( hdrv, help_fileW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW) );
-
- if (di.pDependentFiles && *di.pDependentFiles)
- {
- WCHAR *reg, *reg_ptr, *in_ptr;
- reg = reg_ptr = HeapAlloc( GetProcessHeap(), 0, multi_sz_lenW( di.pDependentFiles ) );
-
- for (in_ptr = di.pDependentFiles; *in_ptr; in_ptr += strlenW( in_ptr ) + 1)
- {
- file = get_file_part( in_ptr );
- len = strlenW( file ) + 1;
- memcpy( reg_ptr, file, len * sizeof(WCHAR) );
- reg_ptr += len;
- apd_copyfile( in_ptr, file, &apd );
- }
- *reg_ptr = 0;
-
- RegSetValueExW( hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)reg, (reg_ptr - reg + 1) * sizeof(WCHAR) );
- HeapFree( GetProcessHeap(), 0, reg );
- }
- else
- RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
-
- /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
- if (di.pMonitorName)
- RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
- (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
- else
- RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
-
- if (di.pDefaultDataType)
- RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
- (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
- else
- RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
-
- /* settings for level 4 */
- if (di.pszzPreviousNames)
- RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
- multi_sz_lenW(di.pszzPreviousNames));
- else
- RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
-
- if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
-
- RegCloseKey(hdrv);
- hui = driver_load(env, di.pConfigFile);
- pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
- if (hui && pDrvDriverEvent) {
-
- /* Support for DrvDriverEvent is optional */
- TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
- /* MSDN: level for DRIVER_INFO is 1 to 3 */
- res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
- TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
- }
- FreeLibrary(hui);
-
- TRACE("=> TRUE with %u\n", GetLastError());
- return TRUE;
-
-}
-
-/******************************************************************************
- * fpAddMonitor [exported through PRINTPROVIDOR]
- *
- * Install a Printmonitor
- *
- * PARAMS
- * pName [I] Servername or NULL (local Computer)
- * Level [I] Structure-Level (Must be 2)
- * pMonitors [I] PTR to MONITOR_INFO_2
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- * NOTES
- * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
- *
- */
-static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
-{
- monitor_t * pm = NULL;
- LPMONITOR_INFO_2W mi2w;
- HKEY hroot = NULL;
- HKEY hentry = NULL;
- DWORD disposition;
- BOOL res = FALSE;
-
- mi2w = (LPMONITOR_INFO_2W) pMonitors;
- TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
- debugstr_w(mi2w ? mi2w->pName : NULL),
- debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
- debugstr_w(mi2w ? mi2w->pDLLName : NULL));
-
- if (copy_servername_from_name(pName, NULL)) {
- FIXME("server %s not supported\n", debugstr_w(pName));
- SetLastError(ERROR_ACCESS_DENIED);
- return FALSE;
- }
-
- if (!mi2w->pName || (! mi2w->pName[0])) {
- WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
- if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, x86_envnameW)) {
- WARN("Environment %s requested (we support only %s)\n",
- debugstr_w(mi2w->pEnvironment), debugstr_w(x86_envnameW));
- SetLastError(ERROR_INVALID_ENVIRONMENT);
- return FALSE;
- }
-
- if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
- WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- /* Load and initialize the monitor. SetLastError() is called on failure */
- if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
- return FALSE;
- }
- monitor_unload(pm);
-
- if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
- ERR("unable to create key %s\n", debugstr_w(monitorsW));
- return FALSE;
- }
-
- if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
- KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
- &disposition) == ERROR_SUCCESS) {
-
- /* Some installers set options for the port before calling AddMonitor.
- We query the "Driver" entry to verify that the monitor is installed,
- before we return an error.
- When a user installs two print monitors at the same time with the
- same name, a race condition is possible but silently ignored. */
-
- DWORD namesize = 0;
-
- if ((disposition == REG_OPENED_EXISTING_KEY) &&
- (RegQueryValueExW(hentry, driverW, NULL, NULL, NULL,
- &namesize) == ERROR_SUCCESS)) {
- TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
- /* 9x use ERROR_ALREADY_EXISTS */
- SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
- }
- else
- {
- INT len;
- len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
- res = (RegSetValueExW(hentry, driverW, 0, REG_SZ,
- (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
- }
- RegCloseKey(hentry);
- }
-
- RegCloseKey(hroot);
- return (res);
-}
-
-/******************************************************************************
- * fpAddPort [exported through PRINTPROVIDOR]
- *
- * Add a Port for a specific Monitor
- *
- * PARAMS
- * pName [I] Servername or NULL (local Computer)
- * hWnd [I] Handle to parent Window for the Dialog-Box
- * pMonitorName [I] Name of the Monitor that manage the Port
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- */
-static BOOL WINAPI fpAddPort(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
-{
- monitor_t * pm;
- monitor_t * pui;
- LONG lres;
- DWORD res;
-
- TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
-
- lres = copy_servername_from_name(pName, NULL);
- if (lres) {
- FIXME("server %s not supported\n", debugstr_w(pName));
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- /* an empty Monitorname is Invalid */
- if (!pMonitorName[0]) {
- SetLastError(ERROR_NOT_SUPPORTED);
- return FALSE;
- }
-
- pm = monitor_load(pMonitorName, NULL);
- if (pm && pm->monitor && pm->monitor->pfnAddPort) {
- res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
- TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
- }
- else
- {
- pui = monitor_loadui(pm);
- if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
- res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
- TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pui->dllname));
- }
- else
- {
- FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
- debugstr_w(pMonitorName), pm, debugstr_w(pm ? pm->dllname : NULL),
- pui, debugstr_w(pui ? pui->dllname : NULL));
-
- SetLastError(ERROR_NOT_SUPPORTED);
- res = FALSE;
- }
- monitor_unload(pui);
- }
- monitor_unload(pm);
-
- TRACE("returning %d with %u\n", res, GetLastError());
- return res;
-}
-
-/******************************************************************************
- * fpAddPortEx [exported through PRINTPROVIDOR]
- *
- * Add a Port for a specific Monitor, without presenting a user interface
- *
- * PARAMS
- * pName [I] Servername or NULL (local Computer)
- * level [I] Structure-Level (1 or 2) for pBuffer
- * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
- * pMonitorName [I] Name of the Monitor that manage the Port
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- */
-static BOOL WINAPI fpAddPortEx(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
-{
- PORT_INFO_2W * pi2;
- monitor_t * pm;
- DWORD lres;
- DWORD res;
-
- pi2 = (PORT_INFO_2W *) pBuffer;
-
- TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
- debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
- debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
- debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
-
- lres = copy_servername_from_name(pName, NULL);
- if (lres) {
- FIXME("server %s not supported\n", debugstr_w(pName));
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- if ((level < 1) || (level > 2)) {
- SetLastError(ERROR_INVALID_LEVEL);
- return FALSE;
- }
-
- if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- /* load the Monitor */
- pm = monitor_load(pMonitorName, NULL);
- if (pm && pm->monitor && pm->monitor->pfnAddPortEx) {
- res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
- TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
- }
- else
- {
- FIXME("not implemented for %s (monitor %p: %s)\n",
- debugstr_w(pMonitorName), pm, pm ? debugstr_w(pm->dllname) : "(null)");
- SetLastError(ERROR_INVALID_PARAMETER);
- res = FALSE;
- }
- monitor_unload(pm);
- return res;
-}
-
-/******************************************************************************
- * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
- *
- * Install a Printer Driver with the Option to upgrade / downgrade the Files
- *
- * PARAMS
- * pName [I] Servername or NULL (local Computer)
- * level [I] Level for the supplied DRIVER_INFO_*W struct
- * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
- * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
- *
- * RESULTS
- * Success: TRUE
- * Failure: FALSE
- *
- */
-static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
-{
- LONG lres;
-
- TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
- lres = copy_servername_from_name(pName, NULL);
- if (lres) {
- FIXME("server %s not supported\n", debugstr_w(pName));
- SetLastError(ERROR_ACCESS_DENIED);
- return FALSE;
- }
-
- if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
- TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
- }
-
- return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
-}
-
-/******************************************************************************
- * fpClosePrinter [exported through PRINTPROVIDOR]
- *
- * Close a printer handle and free associated resources
- *
- * PARAMS
- * hPrinter [I] Printerhandle to close
- *
- * RESULTS
- * Success: TRUE
- * Failure: FALSE
- *
- */
-static BOOL WINAPI fpClosePrinter(HANDLE hPrinter)
-{
- printer_t *printer = (printer_t *) hPrinter;
-
- TRACE("(%p)\n", hPrinter);
-
- if (printer) {
- printer_free(printer);
- return TRUE;
- }
- return FALSE;
-}
-
-/******************************************************************************
- * fpConfigurePort [exported through PRINTPROVIDOR]
- *
- * Display the Configuration-Dialog for a specific Port
- *
- * PARAMS
- * pName [I] Servername or NULL (local Computer)
- * hWnd [I] Handle to parent Window for the Dialog-Box
- * pPortName [I] Name of the Port, that should be configured
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- */
-static BOOL WINAPI fpConfigurePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
-{
- monitor_t * pm;
- monitor_t * pui;
- LONG lres;
- DWORD res;
-
- TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
-
- lres = copy_servername_from_name(pName, NULL);
- if (lres) {
- FIXME("server %s not supported\n", debugstr_w(pName));
- SetLastError(ERROR_INVALID_NAME);
- return FALSE;
- }
-
- /* an empty Portname is Invalid, but can popup a Dialog */
- if (!pPortName[0]) {
- SetLastError(ERROR_NOT_SUPPORTED);
- return FALSE;
- }
-
- pm = monitor_load_by_port(pPortName);
- if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
- TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
- debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
- res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
- TRACE("got %d with %u\n", res, GetLastError());
- }
- else
- {
- pui = monitor_loadui(pm);
- if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
- TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
- debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
- res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
- TRACE("got %d with %u\n", res, GetLastError());
- }
- else
- {
- FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
- debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
- pui, debugstr_w(pui ? pui->dllname : NULL));
-
- SetLastError(ERROR_NOT_SUPPORTED);
- res = FALSE;
- }
- monitor_unload(pui);
- }
- monitor_unload(pm);
-
- TRACE("returning %d with %u\n", res, GetLastError());
- return res;
-}
-
-/******************************************************************
- * fpDeleteMonitor [exported through PRINTPROVIDOR]
- *
- * Delete a specific Printmonitor from a Printing-Environment
- *
- * PARAMS
- * pName [I] Servername or NULL (local Computer)
- * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
- * pMonitorName [I] Name of the Monitor, that should be deleted
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- * NOTES
- * pEnvironment is ignored in Windows for the local Computer.
- *
- */
-
-static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
-{
- HKEY hroot = NULL;
- LONG lres;
-
- TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
- debugstr_w(pMonitorName));
-
- lres = copy_servername_from_name(pName, NULL);
- if (lres) {
- FIXME("server %s not supported\n", debugstr_w(pName));
- SetLastError(ERROR_INVALID_NAME);
- return FALSE;
- }
-
- /* pEnvironment is ignored in Windows for the local Computer */
- if (!pMonitorName || !pMonitorName[0]) {
- TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
- ERR("unable to create key %s\n", debugstr_w(monitorsW));
- return FALSE;
- }
-
- if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
- TRACE("%s deleted\n", debugstr_w(pMonitorName));
- RegCloseKey(hroot);
- return TRUE;
- }
-
- TRACE("%s does not exist\n", debugstr_w(pMonitorName));
- RegCloseKey(hroot);
-
- /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
- SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
- return FALSE;
-}
-
-/*****************************************************************************
- * fpDeletePort [exported through PRINTPROVIDOR]
- *
- * Delete a specific Port
- *
- * PARAMS
- * pName [I] Servername or NULL (local Computer)
- * hWnd [I] Handle to parent Window for the Dialog-Box
- * pPortName [I] Name of the Port, that should be deleted
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- */
-static BOOL WINAPI fpDeletePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
-{
- monitor_t * pm;
- monitor_t * pui;
- LONG lres;
- DWORD res;
-
- TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
-
- lres = copy_servername_from_name(pName, NULL);
- if (lres) {
- FIXME("server %s not supported\n", debugstr_w(pName));
- SetLastError(ERROR_INVALID_NAME);
- return FALSE;
- }
-
- /* an empty Portname is Invalid */
- if (!pPortName[0]) {
- SetLastError(ERROR_NOT_SUPPORTED);
- return FALSE;
- }
-
- pm = monitor_load_by_port(pPortName);
- if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
- TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
- debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
- res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
- TRACE("got %d with %u\n", res, GetLastError());
- }
- else
- {
- pui = monitor_loadui(pm);
- if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
- TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
- debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
- res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
- TRACE("got %d with %u\n", res, GetLastError());
- }
- else
- {
- FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
- debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
- pui, debugstr_w(pui ? pui->dllname : NULL));
-
- SetLastError(ERROR_NOT_SUPPORTED);
- res = FALSE;
- }
- monitor_unload(pui);
- }
- monitor_unload(pm);
-
- TRACE("returning %d with %u\n", res, GetLastError());
- return res;
-}
-
-/*****************************************************************************
- * fpEnumMonitors [exported through PRINTPROVIDOR]
- *
- * Enumerate available Port-Monitors
- *
- * PARAMS
- * pName [I] Servername or NULL (local Computer)
- * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
- * pMonitors [O] PTR to Buffer that receives the Result
- * cbBuf [I] Size of Buffer at pMonitors
- * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
- * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
- *
- * NOTES
- * Windows reads the Registry once and cache the Results.
- *
- */
-static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
- LPDWORD pcbNeeded, LPDWORD pcReturned)
-{
- DWORD numentries = 0;
- DWORD needed = 0;
- LONG lres;
- BOOL res = FALSE;
-
- TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
- cbBuf, pcbNeeded, pcReturned);
-
- lres = copy_servername_from_name(pName, NULL);
- if (lres) {
- FIXME("server %s not supported\n", debugstr_w(pName));
- SetLastError(ERROR_INVALID_NAME);
- goto em_cleanup;
- }
-
- if (!Level || (Level > 2)) {
- WARN("level (%d) is ignored in win9x\n", Level);
- SetLastError(ERROR_INVALID_LEVEL);
- return FALSE;
- }
-
- /* Scan all Monitor-Keys */
- numentries = 0;
- needed = get_local_monitors(Level, NULL, 0, &numentries);
-
- /* we calculated the needed buffersize. now do more error-checks */
- if (cbBuf < needed) {
- SetLastError(ERROR_INSUFFICIENT_BUFFER);
- goto em_cleanup;
- }
-
- /* fill the Buffer with the Monitor-Keys */
- needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
- res = TRUE;
-
-em_cleanup:
- if (pcbNeeded) *pcbNeeded = needed;
- if (pcReturned) *pcReturned = numentries;
-
- TRACE("returning %d with %d (%d byte for %d entries)\n",
- res, GetLastError(), needed, numentries);
-
- return (res);
-}
-
-/******************************************************************************
- * fpEnumPorts [exported through PRINTPROVIDOR]
- *
- * Enumerate available Ports
- *
- * PARAMS
- * pName [I] Servername or NULL (local Computer)
- * Level [I] Structure-Level (1 or 2)
- * pPorts [O] PTR to Buffer that receives the Result
- * cbBuf [I] Size of Buffer at pPorts
- * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
- * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
- *
- */
-static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
- LPDWORD pcbNeeded, LPDWORD pcReturned)
-{
- DWORD needed = 0;
- DWORD numentries = 0;
- LONG lres;
- BOOL res = FALSE;
-
- TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
- cbBuf, pcbNeeded, pcReturned);
-
- lres = copy_servername_from_name(pName, NULL);
- if (lres) {
- FIXME("server %s not supported\n", debugstr_w(pName));
- SetLastError(ERROR_INVALID_NAME);
- goto emP_cleanup;
- }
-
- if (!Level || (Level > 2)) {
- SetLastError(ERROR_INVALID_LEVEL);
- goto emP_cleanup;
- }
-
- if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
- SetLastError(RPC_X_NULL_REF_POINTER);
- goto emP_cleanup;
- }
-
- EnterCriticalSection(&monitor_handles_cs);
- monitor_loadall();
-
- /* Scan all local Ports */
- numentries = 0;
- needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
-
- /* we calculated the needed buffersize. now do the error-checks */
- if (cbBuf < needed) {
- monitor_unloadall();
- SetLastError(ERROR_INSUFFICIENT_BUFFER);
- goto emP_cleanup_cs;
- }
- else if (!pPorts || !pcReturned) {
- monitor_unloadall();
- SetLastError(RPC_X_NULL_REF_POINTER);
- goto emP_cleanup_cs;
- }
-
- /* Fill the Buffer */
- needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
- res = TRUE;
- monitor_unloadall();
-
-emP_cleanup_cs:
- LeaveCriticalSection(&monitor_handles_cs);
-
-emP_cleanup:
- if (pcbNeeded) *pcbNeeded = needed;
- if (pcReturned) *pcReturned = (res) ? numentries : 0;
-
- TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
- (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
-
- return (res);
-}
-
-/*****************************************************************************
- * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
- *
- * Enumerate available Print Processors
- *
- * PARAMS
- * pName [I] Servername or NULL (local Computer)
- * pEnvironment [I] Printing-Environment or NULL (Default)
- * Level [I] Structure-Level (Only 1 is allowed)
- * pPPInfo [O] PTR to Buffer that receives the Result
- * cbBuf [I] Size of Buffer at pMonitors
- * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
- * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
- *
- */
-static BOOL WINAPI fpEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
- LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
-{
- const printenv_t * env;
- LPWSTR regpathW = NULL;
- DWORD numentries = 0;
- DWORD needed = 0;
- LONG lres;
- BOOL res = FALSE;
-
- TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
- Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
-
- lres = copy_servername_from_name(pName, NULL);
- if (lres) {
- FIXME("server %s not supported\n", debugstr_w(pName));
- SetLastError(ERROR_INVALID_NAME);
- goto epp_cleanup;
- }
-
- if (Level != 1) {
- SetLastError(ERROR_INVALID_LEVEL);
- goto epp_cleanup;
- }
-
- env = validate_envW(pEnvironment);
- if (!env)
- goto epp_cleanup; /* ERROR_INVALID_ENVIRONMENT */
-
- regpathW = heap_alloc(sizeof(fmt_printprocessorsW) +
- (lstrlenW(env->envname) * sizeof(WCHAR)));
-
- if (!regpathW)
- goto epp_cleanup;
-
- wsprintfW(regpathW, fmt_printprocessorsW, env->envname);
-
- /* Scan all Printprocessor-Keys */
- numentries = 0;
- needed = get_local_printprocessors(regpathW, NULL, 0, &numentries);
-
- /* we calculated the needed buffersize. now do more error-checks */
- if (cbBuf < needed) {
- SetLastError(ERROR_INSUFFICIENT_BUFFER);
- goto epp_cleanup;
- }
-
- /* fill the Buffer with the Printprocessor Infos */
- needed = get_local_printprocessors(regpathW, pPPInfo, cbBuf, &numentries);
- res = TRUE;
-
-epp_cleanup:
- heap_free(regpathW);
- if (pcbNeeded) *pcbNeeded = needed;
- if (pcReturned) *pcReturned = numentries;
-
- TRACE("returning %d with %d (%d byte for %d entries)\n",
- res, GetLastError(), needed, numentries);
-
- return (res);
-}
-
-/******************************************************************************
- * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
- *
- * Return the PATH for the Print-Processors
- *
- * PARAMS
- * pName [I] Servername or NULL (this computer)
- * pEnvironment [I] Printing-Environment or NULL (Default)
- * level [I] Structure-Level (must be 1)
- * pPPInfo [O] PTR to Buffer that receives the Result
- * cbBuf [I] Size of Buffer at pPPInfo
- * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
- *
- * Native Values returned in pPPInfo on Success for this computer:
- *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
- *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
- *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
- *
- * "%winsysdir%" is the Value from GetSystemDirectoryW()
- *
- */
-static BOOL WINAPI fpGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD level,
- LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded)
-{
- const printenv_t * env;
- DWORD needed;
- LONG lres;
-
- TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
- level, pPPInfo, cbBuf, pcbNeeded);
-
- *pcbNeeded = 0;
- lres = copy_servername_from_name(pName, NULL);
- if (lres) {
- FIXME("server %s not supported\n", debugstr_w(pName));
- SetLastError(RPC_S_SERVER_UNAVAILABLE);
- return FALSE;
- }
-
- env = validate_envW(pEnvironment);
- if (!env)
- return FALSE; /* ERROR_INVALID_ENVIRONMENT */
-
- /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
- needed = GetSystemDirectoryW(NULL, 0);
- /* add the Size for the Subdirectories */
- needed += lstrlenW(spoolprtprocsW);
- needed += lstrlenW(env->subdir);
- needed *= sizeof(WCHAR); /* return-value is size in Bytes */
-
- *pcbNeeded = needed;
-
- if (needed > cbBuf) {
- SetLastError(ERROR_INSUFFICIENT_BUFFER);
- return FALSE;
- }
-
- GetSystemDirectoryW((LPWSTR) pPPInfo, cbBuf/sizeof(WCHAR));
- /* add the Subdirectories */
- lstrcatW((LPWSTR) pPPInfo, spoolprtprocsW);
- lstrcatW((LPWSTR) pPPInfo, env->subdir);
- TRACE("==> %s\n", debugstr_w((LPWSTR) pPPInfo));
- return TRUE;
-}
-
-/******************************************************************************
- * fpOpenPrinter [exported through PRINTPROVIDOR]
- *
- * Open a Printer / Printserver or a Printer-Object
- *
- * PARAMS
- * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
- * pPrinter [O] The resulting Handle is stored here
- * pDefaults [I] PTR to Default Printer Settings or NULL
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- * NOTES
- * lpPrinterName is one of:
- *| Printserver (NT only): "Servername" or NULL for the local Printserver
- *| Printer: "PrinterName"
- *| Printer-Object: "PrinterName,Job xxx"
- *| XcvMonitor: "Servername,XcvMonitor MonitorName"
- *| XcvPort: "Servername,XcvPort PortName"
- *
- *
- */
-static BOOL WINAPI fpOpenPrinter(LPWSTR lpPrinterName, HANDLE *pPrinter,
- LPPRINTER_DEFAULTSW pDefaults)
-{
-
- TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), pPrinter, pDefaults);
-
- *pPrinter = printer_alloc_handle(lpPrinterName, pDefaults);
-
- return (*pPrinter != 0);
-}
-
-/******************************************************************************
- * fpXcvData [exported through PRINTPROVIDOR]
- *
- * Execute commands in the Printmonitor DLL
- *
- * PARAMS
- * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
- * pszDataName [i] Name of the command to execute
- * pInputData [i] Buffer for extra Input Data (needed only for some commands)
- * cbInputData [i] Size in Bytes of Buffer at pInputData
- * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
- * cbOutputData [i] Size in Bytes of Buffer at pOutputData
- * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
- * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- * NOTES
- * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
- * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
- *
- * Minimal List of commands, that a Printmonitor DLL should support:
- *
- *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
- *| "AddPort" : Add a Port
- *| "DeletePort": Delete a Port
- *
- * Many Printmonitors support additional commands. Examples for localspl.dll:
- * "GetDefaultCommConfig", "SetDefaultCommConfig",
- * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
- *
- */
-static BOOL WINAPI fpXcvData(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
- DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
- PDWORD pcbOutputNeeded, PDWORD pdwStatus)
-{
- printer_t *printer = (printer_t * ) hXcv;
-
- TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
- pInputData, cbInputData, pOutputData,
- cbOutputData, pcbOutputNeeded, pdwStatus);
-
- if (!printer || (!printer->hXcv)) {
- SetLastError(ERROR_INVALID_HANDLE);
- return FALSE;
- }
-
- if (!pcbOutputNeeded) {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
- SetLastError(RPC_X_NULL_REF_POINTER);
- return FALSE;
- }
-
- *pcbOutputNeeded = 0;
-
- *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
- pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
-
- return TRUE;
-}
-
-/*****************************************************
- * setup_provider [internal]
- */
-void setup_provider(void)
-{
- static const PRINTPROVIDOR backend = {
- fpOpenPrinter,
- NULL, /* fpSetJob */
- NULL, /* fpGetJob */
- NULL, /* fpEnumJobs */
- NULL, /* fpAddPrinter */
- NULL, /* fpDeletePrinter */
- NULL, /* fpSetPrinter */
- NULL, /* fpGetPrinter */
- NULL, /* fpEnumPrinters */
- NULL, /* fpAddPrinterDriver */
- NULL, /* fpEnumPrinterDrivers */
- NULL, /* fpGetPrinterDriver */
- fpGetPrinterDriverDirectory,
- NULL, /* fpDeletePrinterDriver */
- NULL, /* fpAddPrintProcessor */
- fpEnumPrintProcessors,
- fpGetPrintProcessorDirectory,
- NULL, /* fpDeletePrintProcessor */
- NULL, /* fpEnumPrintProcessorDatatypes */
- NULL, /* fpStartDocPrinter */
- NULL, /* fpStartPagePrinter */
- NULL, /* fpWritePrinter */
- NULL, /* fpEndPagePrinter */
- NULL, /* fpAbortPrinter */
- NULL, /* fpReadPrinter */
- NULL, /* fpEndDocPrinter */
- NULL, /* fpAddJob */
- NULL, /* fpScheduleJob */
- NULL, /* fpGetPrinterData */
- NULL, /* fpSetPrinterData */
- NULL, /* fpWaitForPrinterChange */
- fpClosePrinter,
- NULL, /* fpAddForm */
- NULL, /* fpDeleteForm */
- NULL, /* fpGetForm */
- NULL, /* fpSetForm */
- NULL, /* fpEnumForms */
- fpEnumMonitors,
- fpEnumPorts,
- fpAddPort,
- fpConfigurePort,
- fpDeletePort,
- NULL, /* fpCreatePrinterIC */
- NULL, /* fpPlayGdiScriptOnPrinterIC */
- NULL, /* fpDeletePrinterIC */
- NULL, /* fpAddPrinterConnection */
- NULL, /* fpDeletePrinterConnection */
- NULL, /* fpPrinterMessageBox */
- fpAddMonitor,
- fpDeleteMonitor,
- NULL, /* fpResetPrinter */
- NULL, /* fpGetPrinterDriverEx */
- NULL, /* fpFindFirstPrinterChangeNotification */
- NULL, /* fpFindClosePrinterChangeNotification */
- fpAddPortEx,
- NULL, /* fpShutDown */
- NULL, /* fpRefreshPrinterChangeNotification */
- NULL, /* fpOpenPrinterEx */
- NULL, /* fpAddPrinterEx */
- NULL, /* fpSetPort */
- NULL, /* fpEnumPrinterData */
- NULL, /* fpDeletePrinterData */
- NULL, /* fpClusterSplOpen */
- NULL, /* fpClusterSplClose */
- NULL, /* fpClusterSplIsAlive */
- NULL, /* fpSetPrinterDataEx */
- NULL, /* fpGetPrinterDataEx */
- NULL, /* fpEnumPrinterDataEx */
- NULL, /* fpEnumPrinterKey */
- NULL, /* fpDeletePrinterDataEx */
- NULL, /* fpDeletePrinterKey */
- NULL, /* fpSeekPrinter */
- NULL, /* fpDeletePrinterDriverEx */
- NULL, /* fpAddPerMachineConnection */
- NULL, /* fpDeletePerMachineConnection */
- NULL, /* fpEnumPerMachineConnections */
- fpXcvData,
- fpAddPrinterDriverEx,
- NULL, /* fpSplReadPrinter */
- NULL, /* fpDriverUnloadComplete */
- NULL, /* fpGetSpoolFileInfo */
- NULL, /* fpCommitSpoolData */
- NULL, /* fpCloseSpoolFileHandle */
- NULL, /* fpFlushPrinter */
- NULL, /* fpSendRecvBidiData */
- NULL /* fpAddDriverCatalog */
- };
- pprovider = &backend;
-
-}
-
-/*****************************************************
- * InitializePrintProvidor (localspl.@)
- *
- * Initialize the Printprovider
- *
- * PARAMS
- * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
- * cbPrintProvidor [I] Size of Buffer in Bytes
- * pFullRegistryPath [I] Registry-Path for the Printprovidor
- *
- * RETURNS
- * Success: TRUE and pPrintProvidor filled
- * Failure: FALSE
- *
- * NOTES
- * The RegistryPath should be:
- * "System\CurrentControlSet\Control\Print\Providers\<providername>",
- * but this Parameter is ignored in "localspl.dll".
- *
- */
-
-BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
- DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
-{
-
- TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
- memcpy(pPrintProvidor, pprovider,
- (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
-
- return TRUE;
-}
+++ /dev/null
-#pragma once
-
-/* ## Resource-ID ## */
-#define IDS_LOCALPORT 500
-#define IDS_LOCALMONITOR 507
-
-/* ## Reserved memorysize for the strings (in WCHAR) ## */
-#define IDS_LOCALMONITOR_MAXLEN 64
-#define IDS_LOCALPORT_MAXLEN 32
+++ /dev/null
-
-include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine)
-add_definitions(-D__WINESRC__)
-spec2def(ntprint.dll ntprint.spec)
-
-list(APPEND SOURCE
- ntprint.c
- ntprint.rc
- ${CMAKE_CURRENT_BINARY_DIR}/ntprint_stubs.c
- ${CMAKE_CURRENT_BINARY_DIR}/ntprint.def)
-
-add_library(ntprint SHARED ${SOURCE})
-set_module_type(ntprint win32dll)
-target_link_libraries(ntprint wine)
-add_importlibs(ntprint winspool msvcrt kernel32 ntdll)
-add_cd_file(TARGET ntprint DESTINATION reactos/system32 FOR all)
+++ /dev/null
-/*
- * Implementation of the Spooler Setup API (Printing)
- *
- * Copyright 2007 Detlef Riekenberg
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#define WIN32_NO_STATUS
-
-#include <stdarg.h>
-
-#define COBJMACROS
-#define NONAMELESSUNION
-
-#include <windef.h>
-#include <winbase.h>
-//#include "winerror.h"
-#include <wingdi.h>
-//#include "winnls.h"
-//#include "winver.h"
-#include <winspool.h>
-
-//#include "wine/unicode.h"
-#include <wine/debug.h>
-
-WINE_DEFAULT_DEBUG_CHANNEL(ntprint);
-
-typedef struct {
- LPMONITOR_INFO_2W mi2; /* Buffer for installed Monitors */
- DWORD installed; /* Number of installed Monitors */
-} monitorinfo_t;
-
-/*****************************************************
- * DllMain
- */
-BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
-{
- TRACE("(%p, %d, %p)\n",hinstDLL, fdwReason, lpvReserved);
-
- switch(fdwReason)
- {
- case DLL_WINE_PREATTACH:
- return FALSE; /* prefer native version */
-
- case DLL_PROCESS_ATTACH:
- DisableThreadLibraryCalls( hinstDLL );
- break;
- }
- return TRUE;
-}
-
-/*****************************************************
- * PSetupCreateMonitorInfo [NTPRINT.@]
- *
- *
- */
-
-HANDLE WINAPI PSetupCreateMonitorInfo(LPVOID unknown1, LPVOID unknown2,LPVOID unknown3)
-{
- monitorinfo_t * mi=NULL;
- DWORD needed;
- DWORD res;
-
- TRACE("(%p, %p, %p)\n", unknown1, unknown2, unknown3);
-
- if ((unknown2 != NULL) || (unknown3 != NULL)) {
- FIXME("got unknown parameter: (%p, %p, %p)\n", unknown1, unknown2, unknown3);
- return NULL;
- }
-
- mi = HeapAlloc(GetProcessHeap(), 0, sizeof(monitorinfo_t));
- if (!mi) {
- /* FIXME: SetLastError() needed? */
- return NULL;
- }
-
- /* Get the needed size for all Monitors */
- res = EnumMonitorsW(NULL, 2, NULL, 0, &needed, &mi->installed);
- if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
- mi->mi2 = HeapAlloc(GetProcessHeap(), 0, needed);
- res = EnumMonitorsW(NULL, 2, (LPBYTE) mi->mi2, needed, &needed, &mi->installed);
- }
-
- if (!res) {
- HeapFree(GetProcessHeap(), 0, mi);
- /* FIXME: SetLastError() needed? */
- return NULL;
- }
-
- TRACE("=> %p (%u monitors installed)\n", mi, mi->installed);
- return mi;
-}
-
-/*****************************************************
- * PSetupDestroyMonitorInfo [NTPRINT.@]
- *
- */
-
-VOID WINAPI PSetupDestroyMonitorInfo(HANDLE monitorinfo)
-{
- monitorinfo_t * mi = monitorinfo;
-
- TRACE("(%p)\n", mi);
- if (mi) {
- if (mi->installed) HeapFree(GetProcessHeap(), 0, mi->mi2);
- HeapFree(GetProcessHeap(), 0, mi);
- }
-}
-
-/*****************************************************
- * PSetupEnumMonitor [NTPRINT.@]
- *
- * Copy the selected Monitorname to a buffer
- *
- * PARAMS
- * monitorinfo [I] HANDLE from PSetupCreateMonitorInfo
- * index [I] Nr. of the Monitorname to copy
- * buffer [I] Target, that receive the Monitorname
- * psize [IO] PTR to a DWORD that hold the size of the buffer and receive
- * the needed size, when the buffer is too small
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- * NOTES
- * size is in Bytes on w2k and WCHAR on XP
- *
- */
-
-BOOL WINAPI PSetupEnumMonitor(HANDLE monitorinfo, DWORD index, LPWSTR buffer, LPDWORD psize)
-{
- monitorinfo_t * mi = monitorinfo;
- LPWSTR nameW;
- DWORD len;
-
- TRACE("(%p, %u, %p, %p) => %d\n", mi, index, buffer, psize, psize ? *psize : 0);
-
- if (index < mi->installed) {
- nameW = mi->mi2[index].pName;
- len = lstrlenW(nameW) + 1;
- if (len <= *psize) {
- memcpy(buffer, nameW, len * sizeof(WCHAR));
- TRACE("#%u: %s\n", index, debugstr_w(buffer));
- return TRUE;
- }
- *psize = len;
- SetLastError(ERROR_INSUFFICIENT_BUFFER);
- return FALSE;
- }
- SetLastError(ERROR_NO_MORE_ITEMS);
- return FALSE;
-}
+++ /dev/null
-/*
- * Top level resource file for ntprint.dll
- *
- * Copyright 2007 Detlef Riekenberg
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
- */
-
-//#include "winver.h"
-
-#define WINE_FILENAME_STR "ntprint.dll"
-#define WINE_FILEDESCRIPTION_STR "Spooler Setup API (Printing)"
-
-/* Same Version as WinXP_sp2 */
-#define WINE_FILEVERSION 5,1,2600,2180
-#define WINE_FILEVERSION_STR "5.1.2600.2180"
-
-#define WINE_PRODUCTVERSION 5,1,2600,2180
-#define WINE_PRODUCTVERSION_STR "5.1.2600.2180"
-
-#include <wine/wine_common_ver.rc>
+++ /dev/null
-@ stub ClassInstall32
-@ stub PSetupAssociateICMProfiles
-@ stub PSetupBuildDriversFromPath
-@ stub PSetupCreateDrvSetupPage
-@ stdcall PSetupCreateMonitorInfo(long ptr ptr)
-@ stub PSetupCreatePrinterDeviceInfoList
-@ stub PSetupDestroyDriverInfo3
-@ stdcall PSetupDestroyMonitorInfo(long)
-@ stub PSetupDestroyPrinterDeviceInfoList
-@ stub PSetupDestroySelectedDriverInfo
-@ stub PSetupDriverInfoFromName
-@ stdcall PSetupEnumMonitor(long long ptr ptr)
-@ stub PSetupFreeDrvField
-@ stub PSetupGetDriverInfForPrinter
-@ stub PSetupGetDriverInfo3
-@ stub PSetupGetLocalDataField
-@ stub PSetupGetPathToSearch
-@ stub PSetupGetSelectedDriverInfo
-@ stub PSetupInstallICMProfiles
-@ stub PSetupInstallMonitor
-@ stub PSetupInstallPrinterDriver
-@ stub PSetupInstallPrinterDriverFromTheWeb
-@ stub PSetupIsCompatibleDriver
-@ stub PSetupIsDriverInstalled
-@ stub PSetupIsMonitorInstalled
-@ stub PSetupIsOemDriver
-@ stub PSetupIsTheDriverFoundInInfInstalled
-@ stub PSetupKillBadUserConnections
-@ stub PSetupPreSelectDriver
-@ stub PSetupProcessPrinterAdded
-@ stub PSetupRefreshDriverList
-@ stub PSetupSelectDeviceButtons
-@ stub PSetupSelectDriver
-@ stub PSetupSetSelectDevTitleAndInstructions
-@ stub PSetupThisPlatform
+++ /dev/null
-
-add_definitions(-D__WINESRC__)
-include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine)
-spec2def(spoolss.dll spoolss.spec ADD_IMPORTLIB)
-
-list(APPEND SOURCE
- spoolss_main.c
- router.c
- spoolss.h
- ${CMAKE_CURRENT_BINARY_DIR}/spoolss_stubs.c)
-
-add_library(spoolss SHARED
- ${SOURCE}
- ${CMAKE_CURRENT_BINARY_DIR}/spoolss.def)
-
-set_module_type(spoolss win32dll)
-target_link_libraries(spoolss wine)
-add_importlibs(spoolss msvcrt kernel32 ntdll)
-add_pch(spoolss spoolss.h SOURCE)
-add_cd_file(TARGET spoolss DESTINATION reactos/system32 FOR all)
+++ /dev/null
-/*
- * Routing for Spooler-Service helper DLL
- *
- * Copyright 2006-2009 Detlef Riekenberg
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#include "spoolss.h"
-
-#include <winreg.h>
-#include <wingdi.h>
-#include <winspool.h>
-
-#include <ddk/winsplp.h>
-
-/* ################################ */
-
-#define MAX_BACKEND 3
-
-typedef struct {
- /* PRINTPROVIDOR functions */
- DWORD (WINAPI *fpOpenPrinter)(LPWSTR, HANDLE *, LPPRINTER_DEFAULTSW);
- DWORD (WINAPI *fpSetJob)(HANDLE, DWORD, DWORD, LPBYTE, DWORD);
- DWORD (WINAPI *fpGetJob)(HANDLE, DWORD, DWORD, LPBYTE, DWORD, LPDWORD);
- DWORD (WINAPI *fpEnumJobs)(HANDLE, DWORD, DWORD, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
- HANDLE (WINAPI *fpAddPrinter)(LPWSTR, DWORD, LPBYTE);
- DWORD (WINAPI *fpDeletePrinter)(HANDLE);
- DWORD (WINAPI *fpSetPrinter)(HANDLE, DWORD, LPBYTE, DWORD);
- DWORD (WINAPI *fpGetPrinter)(HANDLE, DWORD, LPBYTE, DWORD, LPDWORD);
- DWORD (WINAPI *fpEnumPrinters)(DWORD, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
- DWORD (WINAPI *fpAddPrinterDriver)(LPWSTR, DWORD, LPBYTE);
- DWORD (WINAPI *fpEnumPrinterDrivers)(LPWSTR, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
- DWORD (WINAPI *fpGetPrinterDriver)(HANDLE, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD);
- DWORD (WINAPI *fpGetPrinterDriverDirectory)(LPWSTR, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD);
- DWORD (WINAPI *fpDeletePrinterDriver)(LPWSTR, LPWSTR, LPWSTR);
- DWORD (WINAPI *fpAddPrintProcessor)(LPWSTR, LPWSTR, LPWSTR, LPWSTR);
- DWORD (WINAPI *fpEnumPrintProcessors)(LPWSTR, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
- DWORD (WINAPI *fpGetPrintProcessorDirectory)(LPWSTR, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD);
- DWORD (WINAPI *fpDeletePrintProcessor)(LPWSTR, LPWSTR, LPWSTR);
- DWORD (WINAPI *fpEnumPrintProcessorDatatypes)(LPWSTR, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
- DWORD (WINAPI *fpStartDocPrinter)(HANDLE, DWORD, LPBYTE);
- DWORD (WINAPI *fpStartPagePrinter)(HANDLE);
- DWORD (WINAPI *fpWritePrinter)(HANDLE, LPVOID, DWORD, LPDWORD);
- DWORD (WINAPI *fpEndPagePrinter)(HANDLE);
- DWORD (WINAPI *fpAbortPrinter)(HANDLE);
- DWORD (WINAPI *fpReadPrinter)(HANDLE, LPVOID, DWORD, LPDWORD);
- DWORD (WINAPI *fpEndDocPrinter)(HANDLE);
- DWORD (WINAPI *fpAddJob)(HANDLE, DWORD, LPBYTE, DWORD, LPDWORD);
- DWORD (WINAPI *fpScheduleJob)(HANDLE, DWORD);
- DWORD (WINAPI *fpGetPrinterData)(HANDLE, LPWSTR, LPDWORD, LPBYTE, DWORD, LPDWORD);
- DWORD (WINAPI *fpSetPrinterData)(HANDLE, LPWSTR, DWORD, LPBYTE, DWORD);
- DWORD (WINAPI *fpWaitForPrinterChange)(HANDLE, DWORD);
- DWORD (WINAPI *fpClosePrinter)(HANDLE);
- DWORD (WINAPI *fpAddForm)(HANDLE, DWORD, LPBYTE);
- DWORD (WINAPI *fpDeleteForm)(HANDLE, LPWSTR);
- DWORD (WINAPI *fpGetForm)(HANDLE, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD);
- DWORD (WINAPI *fpSetForm)(HANDLE, LPWSTR, DWORD, LPBYTE);
- DWORD (WINAPI *fpEnumForms)(HANDLE, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
- DWORD (WINAPI *fpEnumMonitors)(LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
- DWORD (WINAPI *fpEnumPorts)(LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
- DWORD (WINAPI *fpAddPort)(LPWSTR, HWND, LPWSTR);
- DWORD (WINAPI *fpConfigurePort)(LPWSTR, HWND, LPWSTR);
- DWORD (WINAPI *fpDeletePort)(LPWSTR, HWND, LPWSTR);
- HANDLE (WINAPI *fpCreatePrinterIC)(HANDLE, LPDEVMODEW);
- DWORD (WINAPI *fpPlayGdiScriptOnPrinterIC)(HANDLE, LPBYTE, DWORD, LPBYTE, DWORD, DWORD);
- DWORD (WINAPI *fpDeletePrinterIC)(HANDLE);
- DWORD (WINAPI *fpAddPrinterConnection)(LPWSTR);
- DWORD (WINAPI *fpDeletePrinterConnection)(LPWSTR);
- DWORD (WINAPI *fpPrinterMessageBox)(HANDLE, DWORD, HWND, LPWSTR, LPWSTR, DWORD);
- DWORD (WINAPI *fpAddMonitor)(LPWSTR, DWORD, LPBYTE);
- DWORD (WINAPI *fpDeleteMonitor)(LPWSTR, LPWSTR, LPWSTR);
- DWORD (WINAPI *fpResetPrinter)(HANDLE, LPPRINTER_DEFAULTSW);
- DWORD (WINAPI *fpGetPrinterDriverEx)(HANDLE, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, DWORD, DWORD, PDWORD, PDWORD);
- HANDLE (WINAPI *fpFindFirstPrinterChangeNotification)(HANDLE, DWORD, DWORD, LPVOID);
- DWORD (WINAPI *fpFindClosePrinterChangeNotification)(HANDLE);
- DWORD (WINAPI *fpAddPortEx)(HANDLE, LPWSTR, DWORD, LPBYTE, LPWSTR);
- DWORD (WINAPI *fpShutDown)(LPVOID);
- DWORD (WINAPI *fpRefreshPrinterChangeNotification)(HANDLE, DWORD, PVOID, PVOID);
- DWORD (WINAPI *fpOpenPrinterEx)(LPWSTR, LPHANDLE, LPPRINTER_DEFAULTSW, LPBYTE, DWORD);
- HANDLE (WINAPI *fpAddPrinterEx)(LPWSTR, DWORD, LPBYTE, LPBYTE, DWORD);
- DWORD (WINAPI *fpSetPort)(LPWSTR, LPWSTR, DWORD, LPBYTE);
- DWORD (WINAPI *fpEnumPrinterData)(HANDLE, DWORD, LPWSTR, DWORD, LPDWORD, LPDWORD, LPBYTE, DWORD, LPDWORD);
- DWORD (WINAPI *fpDeletePrinterData)(HANDLE, LPWSTR);
- DWORD (WINAPI *fpClusterSplOpen)(LPCWSTR, LPCWSTR, PHANDLE, LPCWSTR, LPCWSTR);
- DWORD (WINAPI *fpClusterSplClose)(HANDLE);
- DWORD (WINAPI *fpClusterSplIsAlive)(HANDLE);
- DWORD (WINAPI *fpSetPrinterDataEx)(HANDLE, LPCWSTR, LPCWSTR, DWORD, LPBYTE, DWORD);
- DWORD (WINAPI *fpGetPrinterDataEx)(HANDLE, LPCWSTR, LPCWSTR, LPDWORD, LPBYTE, DWORD, LPDWORD);
- DWORD (WINAPI *fpEnumPrinterDataEx)(HANDLE, LPCWSTR, LPBYTE, DWORD, LPDWORD, LPDWORD);
- DWORD (WINAPI *fpEnumPrinterKey)(HANDLE, LPCWSTR, LPWSTR, DWORD, LPDWORD);
- DWORD (WINAPI *fpDeletePrinterDataEx)(HANDLE, LPCWSTR, LPCWSTR);
- DWORD (WINAPI *fpDeletePrinterKey)(HANDLE hPrinter, LPCWSTR pKeyName);
- DWORD (WINAPI *fpSeekPrinter)(HANDLE, LARGE_INTEGER, PLARGE_INTEGER, DWORD, BOOL);
- DWORD (WINAPI *fpDeletePrinterDriverEx)(LPWSTR, LPWSTR, LPWSTR, DWORD, DWORD);
- DWORD (WINAPI *fpAddPerMachineConnection)(LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR);
- DWORD (WINAPI *fpDeletePerMachineConnection)(LPCWSTR, LPCWSTR);
- DWORD (WINAPI *fpEnumPerMachineConnections)(LPCWSTR, LPBYTE, DWORD, LPDWORD, LPDWORD);
- DWORD (WINAPI *fpXcvData)(HANDLE, LPCWSTR, PBYTE, DWORD, PBYTE, DWORD, PDWORD, PDWORD);
- DWORD (WINAPI *fpAddPrinterDriverEx)(LPWSTR, DWORD, LPBYTE, DWORD);
- DWORD (WINAPI *fpSplReadPrinter)(HANDLE, LPBYTE *, DWORD);
- DWORD (WINAPI *fpDriverUnloadComplete)(LPWSTR);
- DWORD (WINAPI *fpGetSpoolFileInfo)(HANDLE, LPWSTR *, LPHANDLE, HANDLE, HANDLE);
- DWORD (WINAPI *fpCommitSpoolData)(HANDLE, DWORD);
- DWORD (WINAPI *fpCloseSpoolFileHandle)(HANDLE);
- DWORD (WINAPI *fpFlushPrinter)(HANDLE, LPBYTE, DWORD, LPDWORD, DWORD);
- DWORD (WINAPI *fpSendRecvBidiData)(HANDLE, LPCWSTR, LPBIDI_REQUEST_CONTAINER, LPBIDI_RESPONSE_CONTAINER *);
- DWORD (WINAPI *fpAddDriverCatalog)(HANDLE, DWORD, VOID *, DWORD);
- /* Private Data */
- HMODULE dll;
- LPWSTR dllname;
- LPWSTR name;
- LPWSTR regroot;
- DWORD index;
-} backend_t;
-
-/* ################################ */
-
-static backend_t *backend[MAX_BACKEND];
-static DWORD used_backends = 0;
-
-static CRITICAL_SECTION backend_cs;
-static CRITICAL_SECTION_DEBUG backend_cs_debug =
-{
- 0, 0, &backend_cs,
- { &backend_cs_debug.ProcessLocksList, &backend_cs_debug.ProcessLocksList },
- 0, 0, { (DWORD_PTR)(__FILE__ ": backend_cs") }
-};
-static CRITICAL_SECTION backend_cs = { &backend_cs_debug, -1, 0, 0, 0, 0 };
-
-/* ################################ */
-
-static WCHAR localsplW[] = {'l','o','c','a','l','s','p','l','.','d','l','l',0};
-
-/******************************************************************
- * strdupW [internal]
- *
- * create a copy of a unicode-string
- *
- */
-
-static LPWSTR strdupW(LPCWSTR p)
-{
- LPWSTR ret;
- DWORD len;
-
- if(!p) return NULL;
- len = (lstrlenW(p) + 1) * sizeof(WCHAR);
- ret = heap_alloc(len);
- memcpy(ret, p, len);
- return ret;
-}
-
-/******************************************************************
- * backend_unload_all [internal]
- *
- * unload all backends
- */
-void backend_unload_all(void)
-{
- EnterCriticalSection(&backend_cs);
- while (used_backends > 0) {
- used_backends--;
- FreeLibrary(backend[used_backends]->dll);
- heap_free(backend[used_backends]->dllname);
- heap_free(backend[used_backends]->name);
- heap_free(backend[used_backends]->regroot);
- heap_free(backend[used_backends]);
- backend[used_backends] = NULL;
- }
- LeaveCriticalSection(&backend_cs);
-}
-
-/******************************************************************************
- * backend_load [internal]
- *
- * load and init a backend
- *
- * PARAMS
- * name [I] Printprovider to use for the backend. NULL for the local print provider
- *
- * RETURNS
- * Success: PTR to the backend
- * Failure: NULL
- *
- */
-static backend_t * backend_load(LPWSTR dllname, LPWSTR name, LPWSTR regroot)
-{
-
- BOOL (WINAPI *pInitializePrintProvidor)(LPPRINTPROVIDOR, DWORD, LPWSTR);
- DWORD id;
- DWORD res;
-
- TRACE("(%s, %s, %s)\n", debugstr_w(dllname), debugstr_w(name), debugstr_w(regroot));
-
- EnterCriticalSection(&backend_cs);
- id = used_backends;
-
- backend[id] = heap_alloc_zero(sizeof(backend_t));
- if (!backend[id]) {
- LeaveCriticalSection(&backend_cs);
- return NULL;
- }
-
- backend[id]->dllname = strdupW(dllname);
- backend[id]->name = strdupW(name);
- backend[id]->regroot = strdupW(regroot);
-
- backend[id]->dll = LoadLibraryW(dllname);
- if (backend[id]->dll) {
- pInitializePrintProvidor = (void *) GetProcAddress(backend[id]->dll, "InitializePrintProvidor");
- if (pInitializePrintProvidor) {
-
- /* native localspl does not clear unused entries */
- res = pInitializePrintProvidor((PRINTPROVIDOR *) backend[id], sizeof(PRINTPROVIDOR), regroot);
- if (res) {
- used_backends++;
- backend[id]->index = used_backends;
- LeaveCriticalSection(&backend_cs);
- TRACE("--> backend #%d: %p (%s)\n", id, backend[id], debugstr_w(dllname));
- return backend[id];
- }
- }
- FreeLibrary(backend[id]->dll);
- }
- heap_free(backend[id]->dllname);
- heap_free(backend[id]->name);
- heap_free(backend[id]->regroot);
- heap_free(backend[id]);
- backend[id] = NULL;
- LeaveCriticalSection(&backend_cs);
- WARN("failed to init %s: %u\n", debugstr_w(dllname), GetLastError());
- return NULL;
-}
-
-/******************************************************************************
- * backend_load_all [internal]
- *
- * load and init all backends
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- */
-BOOL backend_load_all(void)
-{
- static BOOL failed = FALSE;
-
- EnterCriticalSection(&backend_cs);
-
- /* if we failed before, don't try again */
- if (!failed && (used_backends == 0)) {
- backend_load(localsplW, NULL, NULL);
-
- /* ToDo: parse the registry and load all other backends */
-
- failed = (used_backends == 0);
- }
- LeaveCriticalSection(&backend_cs);
- TRACE("-> %d\n", !failed);
- return (!failed);
-}
-
-/******************************************************************************
- * backend_first [internal]
- *
- * find the first usable backend
- *
- * RETURNS
- * Success: PTR to the backend
- * Failure: NULL
- *
- */
-static backend_t * backend_first(LPWSTR name)
-{
-
- EnterCriticalSection(&backend_cs);
- /* Load all backends, when not done yet */
- if (used_backends || backend_load_all()) {
-
- /* test for the local system first */
- if (!name || !name[0]) {
- LeaveCriticalSection(&backend_cs);
- return backend[0];
- }
- }
-
- FIXME("server %s not supported in %d backends\n", debugstr_w(name), used_backends);
- LeaveCriticalSection(&backend_cs);
- return NULL;
-}
-
-/******************************************************************
- * AddMonitorW (spoolss.@)
- *
- * Install a Printmonitor
- *
- * PARAMS
- * pName [I] Servername or NULL (local Computer)
- * Level [I] Structure-Level (Must be 2)
- * pMonitors [I] PTR to MONITOR_INFO_2
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- * NOTES
- * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
- *
- */
-BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
-{
- backend_t * pb;
- DWORD res = ROUTER_UNKNOWN;
-
- TRACE("(%s, %d, %p)\n", debugstr_w(pName), Level, pMonitors);
-
- if (Level != 2) {
- SetLastError(ERROR_INVALID_LEVEL);
- return FALSE;
- }
-
- pb = backend_first(pName);
- if (pb && pb->fpAddMonitor)
- res = pb->fpAddMonitor(pName, Level, pMonitors);
- else
- {
- SetLastError(ERROR_PROC_NOT_FOUND);
- }
-
- TRACE("got %u with %u\n", res, GetLastError());
- return (res == ROUTER_SUCCESS);
-}
-
-/******************************************************************
- * AddPrinterDriverExW (spoolss.@)
- *
- * Install a Printer Driver with the Option to upgrade / downgrade the Files
- *
- * PARAMS
- * pName [I] Servername or NULL (local Computer)
- * level [I] Level for the supplied DRIVER_INFO_*W struct
- * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
- * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
- *
- * RESULTS
- * Success: TRUE
- * Failure: FALSE
- *
- */
-BOOL WINAPI AddPrinterDriverExW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
-{
- backend_t * pb;
- DWORD res = ROUTER_UNKNOWN;
-
- TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
-
- if (!pDriverInfo) {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- pb = backend_first(pName);
- if (pb && pb->fpAddPrinterDriverEx)
- res = pb->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
- else
- {
- SetLastError(ERROR_PROC_NOT_FOUND);
- }
-
- TRACE("got %u with %u\n", res, GetLastError());
- return (res == ROUTER_SUCCESS);
-}
-
-/******************************************************************
- * DeleteMonitorW (spoolss.@)
- *
- * Delete a specific Printmonitor from a Printing-Environment
- *
- * PARAMS
- * pName [I] Servername or NULL (local Computer)
- * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
- * pMonitorName [I] Name of the Monitor, that should be deleted
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- */
-BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
-{
- backend_t * pb;
- DWORD res = ROUTER_UNKNOWN;
-
- TRACE("(%s, %s, %s)\n", debugstr_w(pName), debugstr_w(pEnvironment), debugstr_w(pMonitorName));
-
- pb = backend_first(pName);
- if (pb && pb->fpDeleteMonitor)
- res = pb->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
- else
- {
- SetLastError(ERROR_PROC_NOT_FOUND);
- }
-
- TRACE("got %u with %u\n", res, GetLastError());
- return (res == ROUTER_SUCCESS);
-}
-
-/******************************************************************
- * EnumMonitorsW (spoolss.@)
- *
- * Enumerate available Port-Monitors
- *
- * PARAMS
- * pName [I] Servername or NULL (local Computer)
- * Level [I] Structure-Level
- * pMonitors [O] PTR to Buffer that receives the Result
- * cbBuf [I] Size of Buffer at pMonitors
- * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
- * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
- *
- */
-BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
- LPDWORD pcbNeeded, LPDWORD pcReturned)
-{
- backend_t * pb;
- DWORD res = ROUTER_UNKNOWN;
-
- TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
- cbBuf, pcbNeeded, pcReturned);
-
- if (pcbNeeded) *pcbNeeded = 0;
- if (pcReturned) *pcReturned = 0;
-
- pb = backend_first(pName);
- if (pb && pb->fpEnumMonitors)
- res = pb->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
- else
- {
- SetLastError(ERROR_PROC_NOT_FOUND);
- }
-
- TRACE("got %u with %u (%u byte for %u entries)\n\n", res, GetLastError(),
- pcbNeeded ? *pcbNeeded : 0, pcReturned ? *pcReturned : 0);
-
- return (res == ROUTER_SUCCESS);
-}
-
-/******************************************************************
- * EnumPortsW (spoolss.@)
- *
- * Enumerate available Ports
- *
- * PARAMS
- * pName [I] Servername or NULL (local Computer)
- * Level [I] Structure-Level (1 or 2)
- * pPorts [O] PTR to Buffer that receives the Result
- * cbBuf [I] Size of Buffer at pPorts
- * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
- * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
- *
- */
-BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
- LPDWORD pcbNeeded, LPDWORD pcReturned)
-{
- backend_t * pb;
- DWORD res = ROUTER_UNKNOWN;
-
- TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts, cbBuf,
- pcbNeeded, pcReturned);
-
- if (pcbNeeded) *pcbNeeded = 0;
- if (pcReturned) *pcReturned = 0;
-
- pb = backend_first(pName);
- if (pb && pb->fpEnumPorts)
- res = pb->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
- else
- {
- SetLastError(ERROR_PROC_NOT_FOUND);
- }
-
- TRACE("got %u with %u (%u byte for %u entries)\n", res, GetLastError(),
- pcbNeeded ? *pcbNeeded : 0, pcReturned ? *pcReturned : 0);
-
- return (res == ROUTER_SUCCESS);
-}
-
-/******************************************************************
- * GetPrinterDriverDirectoryW (spoolss.@)
- *
- * Return the PATH for the Printer-Drivers
- *
- * PARAMS
- * pName [I] Servername or NULL (local Computer)
- * pEnvironment [I] Printing-Environment or NULL (Default)
- * Level [I] Structure-Level (must be 1)
- * pDriverDirectory [O] PTR to Buffer that receives the Result
- * cbBuf [I] Size of Buffer at pDriverDirectory
- * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
- * required for pDriverDirectory
- *
- * RETURNS
- * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
- * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
- * if cbBuf is too small
- *
- * Native Values returned in pDriverDirectory on Success:
- *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
- *| NT(Windows x64): "%winsysdir%\\spool\\DRIVERS\\x64"
- *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
- *| win9x(Windows 4.0): "%winsysdir%"
- *
- * "%winsysdir%" is the Value from GetSystemDirectoryW()
- *
- */
-BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
- DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
-{
- backend_t * pb;
- DWORD res = ROUTER_UNKNOWN;
-
- TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
- debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
-
- if (pcbNeeded) *pcbNeeded = 0;
-
- pb = backend_first(pName);
- if (pb && pb->fpGetPrinterDriverDirectory)
- res = pb->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
- pDriverDirectory, cbBuf, pcbNeeded);
- else
- {
- SetLastError(ERROR_PROC_NOT_FOUND);
- }
-
- TRACE("got %u with %u (%u byte)\n",
- res, GetLastError(), pcbNeeded ? *pcbNeeded : 0);
-
- return (res == ROUTER_SUCCESS);
-
-}
+++ /dev/null
-/*
- * Copyright 2006-2009 Detlef Riekenberg
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#ifndef _SPOOLSS_H_
-#define _SPOOLSS_H_
-
-#include <stdarg.h>
-
-#define WIN32_NO_STATUS
-#include <windef.h>
-#include <winbase.h>
-
-#include <wine/debug.h>
-WINE_DEFAULT_DEBUG_CHANNEL(spoolss);
-
-/* ################################ */
-
-BOOL backend_load_all(void) DECLSPEC_HIDDEN;
-void backend_unload_all(void) DECLSPEC_HIDDEN;
-
-/* ## Memory allocation functions ## */
-
-static inline void * __WINE_ALLOC_SIZE(1) heap_alloc( size_t len )
-{
- return HeapAlloc( GetProcessHeap(), 0, len );
-}
-
-static inline void * __WINE_ALLOC_SIZE(1) heap_alloc_zero( size_t len )
-{
- return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len );
-}
-
-static inline BOOL heap_free( void *mem )
-{
- return HeapFree( GetProcessHeap(), 0, mem );
-}
-
-#endif /* _SPOOLSS_H_ */
+++ /dev/null
-/*
- * Implementation of the Spooler-Service helper DLL
- *
- * Copyright 2006 Detlef Riekenberg
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#include "spoolss.h"
-
-/* ################################ */
-
-static HMODULE hwinspool;
-
-static const WCHAR winspooldrvW[] = {'w','i','n','s','p','o','o','l','.','d','r','v',0};
-
-/******************************************************************************
- *
- */
-BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
-{
- TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
-
- switch (fdwReason) {
- case DLL_WINE_PREATTACH:
- return FALSE; /* prefer native version */
- case DLL_PROCESS_ATTACH: {
- DisableThreadLibraryCalls(hinstDLL);
- break;
-
- case DLL_PROCESS_DETACH:
- if (lpvReserved) break;
- backend_unload_all();
- break;
- }
- }
- return TRUE;
-}
-
-/******************************************************************
- * AllocSplStr [SPOOLSS.@]
- *
- * Create a copy from the String on the Spooler-Heap
- *
- * PARAMS
- * pwstr [I] PTR to the String to copy
- *
- * RETURNS
- * Failure: NULL
- * Success: PTR to the copied String
- *
- */
-LPWSTR WINAPI AllocSplStr(LPCWSTR pwstr)
-{
- LPWSTR res = NULL;
- DWORD len;
-
- TRACE("(%s)\n", debugstr_w(pwstr));
- if (!pwstr) return NULL;
-
- len = (lstrlenW(pwstr) + 1) * sizeof(WCHAR);
- res = HeapAlloc(GetProcessHeap(), 0, len);
- if (res) lstrcpyW(res, pwstr);
-
- TRACE("returning %p\n", res);
- return res;
-}
-
-/******************************************************************
- * BuildOtherNamesFromMachineName [SPOOLSS.@]
- */
-BOOL WINAPI BuildOtherNamesFromMachineName(LPVOID * ptr1, LPVOID * ptr2)
-{
- FIXME("(%p, %p) stub\n", ptr1, ptr2);
-
- *ptr1 = NULL;
- *ptr2 = NULL;
- return FALSE;
-}
-
-/******************************************************************
- * DllAllocSplMem [SPOOLSS.@]
- *
- * Allocate cleared memory from the spooler heap
- *
- * PARAMS
- * size [I] Number of bytes to allocate
- *
- * RETURNS
- * Failure: NULL
- * Success: PTR to the allocated memory
- *
- * NOTES
- * We use the process heap (Windows use a separate spooler heap)
- *
- */
-LPVOID WINAPI DllAllocSplMem(DWORD size)
-{
- LPVOID res;
-
- res = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
- TRACE("(%d) => %p\n", size, res);
- return res;
-}
-
-/******************************************************************
- * DllFreeSplMem [SPOOLSS.@]
- *
- * Free the allocated spooler memory
- *
- * PARAMS
- * memory [I] PTR to the memory allocated by DllAllocSplMem
- *
- * RETURNS
- * Failure: FALSE
- * Success: TRUE
- *
- * NOTES
- * We use the process heap (Windows use a separate spooler heap)
- *
- */
-
-BOOL WINAPI DllFreeSplMem(LPBYTE memory)
-{
- TRACE("(%p)\n", memory);
- return HeapFree(GetProcessHeap(), 0, memory);
-}
-
-/******************************************************************
- * DllFreeSplStr [SPOOLSS.@]
- *
- * Free the allocated Spooler-String
- *
- * PARAMS
- * pwstr [I] PTR to the WSTR, allocated by AllocSplStr
- *
- * RETURNS
- * Failure: FALSE
- * Success: TRUE
- *
- */
-
-BOOL WINAPI DllFreeSplStr(LPWSTR pwstr)
-{
- TRACE("(%s) PTR: %p\n", debugstr_w(pwstr), pwstr);
- return HeapFree(GetProcessHeap(), 0, pwstr);
-}
-
-
-/******************************************************************
- * ImpersonatePrinterClient [SPOOLSS.@]
- */
-BOOL WINAPI ImpersonatePrinterClient(HANDLE hToken)
-{
- FIXME("(%p) stub\n", hToken);
- return TRUE;
-}
-
-/******************************************************************
- * InitializeRouter [SPOOLSS.@]
- */
-BOOL WINAPI InitializeRouter(void)
-{
- TRACE("()\n");
- return backend_load_all();
-}
-
-/******************************************************************
- * IsLocalCall [SPOOLSS.@]
- */
-BOOL WINAPI IsLocalCall(void)
-{
- FIXME("() stub\n");
- return TRUE;
-}
-
-/******************************************************************
- * RevertToPrinterSelf [SPOOLSS.@]
- */
-HANDLE WINAPI RevertToPrinterSelf(void)
-{
- FIXME("() stub\n");
- return (HANDLE) 0xdead0947;
-}
-
-/******************************************************************
- * SplInitializeWinSpoolDrv [SPOOLSS.@]
- *
- * Dynamic load "winspool.drv" and fill an array with some function-pointer
- *
- * PARAMS
- * table [I] array of function-pointer to fill
- *
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
- *
- * NOTES
- * Native "spoolss.dll" from w2k fill the table with 11 Function-Pointer.
- * We implement the XP-Version (The table has only 9 Pointer)
- *
- */
-BOOL WINAPI SplInitializeWinSpoolDrv(LPVOID * table)
-{
- DWORD res;
-
- TRACE("(%p)\n", table);
-
- hwinspool = LoadLibraryW(winspooldrvW);
- if (!hwinspool) return FALSE;
-
- table[0] = (void *) GetProcAddress(hwinspool, "OpenPrinterW");
- table[1] = (void *) GetProcAddress(hwinspool, "ClosePrinter");
- table[2] = (void *) GetProcAddress(hwinspool, "SpoolerDevQueryPrintW");
- table[3] = (void *) GetProcAddress(hwinspool, "SpoolerPrinterEvent");
- table[4] = (void *) GetProcAddress(hwinspool, "DocumentPropertiesW");
- table[5] = (void *) GetProcAddress(hwinspool, (LPSTR) 212); /* LoadPrinterDriver */
- table[6] = (void *) GetProcAddress(hwinspool, (LPSTR) 213); /* RefCntLoadDriver */
- table[7] = (void *) GetProcAddress(hwinspool, (LPSTR) 214); /* RefCntUnloadDriver */
- table[8] = (void *) GetProcAddress(hwinspool, (LPSTR) 215); /* ForceUnloadDriver */
-
- for (res = 0; res < 9; res++) {
- if (table[res] == NULL) return FALSE;
- }
-
- return TRUE;
-
-}
-
-/******************************************************************
- * SplIsUpgrade [SPOOLSS.@]
- */
-BOOL WINAPI SplIsUpgrade(void)
-{
- FIXME("() stub\n");
- return FALSE;
-}
-
-/******************************************************************
- * SpoolerHasInitialized [SPOOLSS.@]
- */
-BOOL WINAPI SpoolerHasInitialized(void)
-{
- FIXME("() stub\n");
- return TRUE;
-}
-
-/******************************************************************
- * SpoolerInit [SPOOLSS.@]
- */
-BOOL WINAPI SpoolerInit(void)
-{
- FIXME("() stub\n");
- return TRUE;
-}
-
-/******************************************************************
- * WaitForSpoolerInitialization [SPOOLSS.@]
- */
-BOOL WINAPI WaitForSpoolerInitialization(void)
-{
- FIXME("() stub\n");
- return TRUE;
-}
+++ /dev/null
-
-include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine)
-spec2def(winspool.drv winspool.spec ADD_IMPORTLIB)
-
-list(APPEND SOURCE
- info.c
- stubs.c
- precomp.h)
-
-add_library(winspool.drv SHARED
- ${SOURCE}
- winspool.rc
- ${CMAKE_CURRENT_BINARY_DIR}/winspool_stubs.c
- ${CMAKE_CURRENT_BINARY_DIR}/winspool.def)
-
-set_target_properties(winspool.drv PROPERTIES SUFFIX "")
-set_module_type(winspool.drv win32dll UNICODE)
-target_link_libraries(winspool.drv wine)
-add_importlibs(winspool.drv advapi32 shlwapi msvcrt kernel32 ntdll)
-add_pch(winspool.drv precomp.h SOURCE)
-add_cd_file(TARGET winspool.drv DESTINATION reactos/system32 FOR all)
+++ /dev/null
-/*
- * WINSPOOL functions
- *
- * Copyright 1996 John Harvey
- * Copyright 1998 Andreas Mohr
- * Copyright 1999 Klaas van Gend
- * Copyright 1999, 2000 Huw D M Davies
- * Copyright 2001 Marcus Meissner
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "precomp.h"
-
-#include <winreg.h>
-#include <winnls.h>
-#include <shlwapi.h>
-
-/******************************************************************************
- * GetDefaultPrinterA (WINSPOOL.@)
- */
-BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
-{
- char *ptr;
-
- if (*namesize < 1)
- {
- SetLastError (ERROR_INSUFFICIENT_BUFFER);
- return FALSE;
- }
-
- if (!GetProfileStringA ("windows", "device", "", name, *namesize))
- {
- SetLastError (ERROR_FILE_NOT_FOUND);
- return FALSE;
- }
-
- if ((ptr = strchr (name, ',')) == NULL)
- {
- SetLastError (ERROR_FILE_NOT_FOUND);
- return FALSE;
- }
-
- *ptr = '\0';
- *namesize = strlen (name) + 1;
- return TRUE;
-}
-
-
-/******************************************************************************
- * GetDefaultPrinterW (WINSPOOL.@)
- */
-BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
-{
- char *buf;
- BOOL ret;
-
- if (*namesize < 1)
- {
- SetLastError (ERROR_INSUFFICIENT_BUFFER);
- return FALSE;
- }
-
- buf = HeapAlloc (GetProcessHeap (), 0, *namesize);
- ret = GetDefaultPrinterA (buf, namesize);
- if (ret)
- {
- DWORD len = MultiByteToWideChar (CP_ACP, 0, buf, -1, name, *namesize);
- if (!len)
- {
- SetLastError (ERROR_INSUFFICIENT_BUFFER);
- ret = FALSE;
- }
- else *namesize = len;
- }
-
- HeapFree (GetProcessHeap (), 0, buf);
- return ret;
-}
-
-/******************************************************************************
- * AddPrintProvidorA (WINSPOOL.@)
- */
-BOOL
-WINAPI
-AddPrintProvidorA(LPSTR Name, DWORD Level, PBYTE Buffer)
-{
- if (Name || Level > 2 || Buffer == NULL)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- if (Level == 1)
- {
- BOOL bRet;
- PROVIDOR_INFO_1W Provider;
- PROVIDOR_INFO_1A *Prov = (PROVIDOR_INFO_1A*)Buffer;
-
- if (Prov->pName == NULL || Prov->pDLLName == NULL || Prov->pEnvironment == NULL)
- {
- return FALSE;
- }
-
- Provider.pDLLName = HeapAlloc(GetProcessHeap(), 0, (strlen(Prov->pDLLName)+1) * sizeof(WCHAR));
- if (Provider.pDLLName)
- {
- MultiByteToWideChar(CP_ACP, 0, Prov->pDLLName, -1, Provider.pDLLName, strlen(Prov->pDLLName)+1);
- Provider.pDLLName[strlen(Prov->pDLLName)] = L'\0';
- }
-
- Provider.pEnvironment = HeapAlloc(GetProcessHeap(), 0, (strlen(Prov->pEnvironment)+1) * sizeof(WCHAR));
- if (Provider.pEnvironment)
- {
- MultiByteToWideChar(CP_ACP, 0, Prov->pEnvironment, -1, Provider.pEnvironment, strlen(Prov->pEnvironment)+1);
- Provider.pEnvironment[strlen(Prov->pEnvironment)] = L'\0';
- }
-
- Provider.pName = HeapAlloc(GetProcessHeap(), 0, (strlen(Prov->pName)+1) * sizeof(WCHAR));
- if (Provider.pName)
- {
- MultiByteToWideChar(CP_ACP, 0, Prov->pName, -1, Provider.pName, strlen(Prov->pName)+1);
- Provider.pName[strlen(Prov->pName)] = L'\0';
- }
-
- bRet = AddPrintProvidorW(NULL, Level, (LPBYTE)&Provider);
-
- if (Provider.pDLLName)
- HeapFree(GetProcessHeap(), 0, Provider.pDLLName);
-
- if (Provider.pEnvironment)
- HeapFree(GetProcessHeap(), 0, Provider.pEnvironment);
-
- if (Provider.pName)
- HeapFree(GetProcessHeap(), 0, Provider.pName);
-
- return bRet;
- }
- else
- {
- PROVIDOR_INFO_2W Provider;
- PROVIDOR_INFO_2A *Prov = (PROVIDOR_INFO_2A*)Buffer;
-
- Provider.pOrder = HeapAlloc(GetProcessHeap(), 0, (strlen(Prov->pOrder)+1) * sizeof(WCHAR));
- if (Provider.pOrder)
- {
- BOOL bRet;
- MultiByteToWideChar(CP_ACP, 0, Prov->pOrder, -1, Provider.pOrder, strlen(Prov->pOrder)+1);
- Provider.pOrder[strlen(Prov->pOrder)] = L'\0';
-
- bRet = AddPrintProvidorW(NULL, Level, (LPBYTE)&Provider);
- HeapFree(GetProcessHeap(), 0, Provider.pOrder);
- return bRet;
- }
- }
-
- return FALSE;
-}
-
-
-/******************************************************************************
- * AddPrintProvidorW (WINSPOOL.@)
- */
-BOOL
-WINAPI
-AddPrintProvidorW(LPWSTR Name, DWORD Level, PBYTE Buffer)
-{
- HKEY hKey;
- LPWSTR pOrder;
- DWORD dwSize, dwType;
- BOOL bRet = FALSE;
-
- if (Name || Level > 2 || Buffer == NULL)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
-
- if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Print\\Providers", 0, KEY_READ | KEY_WRITE, &hKey) != ERROR_SUCCESS)
- {
- return FALSE;
- }
-
- if (RegQueryValueExW(hKey, L"Order", NULL, &dwType, NULL, &dwSize) != ERROR_SUCCESS || dwType != REG_MULTI_SZ)
- {
- RegCloseKey(hKey);
- return FALSE;
- }
-
- pOrder = HeapAlloc(GetProcessHeap(), 0, dwSize);
- if (!pOrder)
- {
- RegCloseKey(hKey);
- return FALSE;
- }
-
- if (RegQueryValueExW(hKey, L"Order", NULL, &dwType, (LPBYTE)pOrder, &dwSize) != ERROR_SUCCESS || dwType != REG_MULTI_SZ)
- {
- RegCloseKey(hKey);
- return FALSE;
- }
-
- if (Level == 1)
- {
- LPWSTR pBuffer;
- BOOL bFound = FALSE;
- PROVIDOR_INFO_1W * Prov = (PROVIDOR_INFO_1W*)Buffer;
-
- if (Prov->pName == NULL || Prov->pDLLName == NULL || Prov->pEnvironment == NULL)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- RegCloseKey(hKey);
- return FALSE;
- }
-
- pBuffer = pOrder;
-
- while(pBuffer[0])
- {
- if (!wcsicmp(pBuffer, Prov->pName))
- {
- bFound = TRUE;
- break;
- }
- pBuffer += wcslen(pBuffer) + 1;
- }
-
- if (!bFound)
- {
- HKEY hSubKey;
- DWORD dwFullSize = dwSize + (wcslen(Prov->pName)+1) * sizeof(WCHAR);
-
- if (RegCreateKeyExW(hKey, Prov->pName, 0, NULL, 0, KEY_WRITE, NULL, &hSubKey, NULL) == ERROR_SUCCESS)
- {
- RegSetValueExW(hSubKey, L"Name", 0, REG_SZ, (LPBYTE)Prov->pDLLName, (wcslen(Prov->pDLLName)+1) * sizeof(WCHAR));
- RegCloseKey(hSubKey);
- }
-
- pBuffer = HeapAlloc(GetProcessHeap(), 0, dwFullSize);
- if (pBuffer)
- {
- CopyMemory(pBuffer, pOrder, dwSize);
- wcscpy(&pBuffer[(dwSize/sizeof(WCHAR))-1], Prov->pName);
- pBuffer[(dwSize/sizeof(WCHAR)) + wcslen(Prov->pName)] = L'\0';
- RegSetValueExW(hKey, L"Order", 0, REG_MULTI_SZ, (LPBYTE)pBuffer, dwFullSize);
- HeapFree(GetProcessHeap(), 0, pBuffer);
- }
- bRet = TRUE;
- }
-
- }
-
- RegCloseKey(hKey);
- HeapFree(GetProcessHeap(), 0, pOrder);
-
- return bRet;
-}
-
-/******************************************************************************
- * DeletePrintProvidorA (WINSPOOL.@)
- */
-BOOL
-WINAPI
-DeletePrintProvidorA(LPSTR Name, LPSTR Environment, LPSTR PrintProvidor)
-{
- BOOL bRet;
- LPWSTR Env, Prov;
-
- if (Name || !Environment || !PrintProvidor)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- Env = HeapAlloc(GetProcessHeap(), 0, (strlen(Environment)+1) * sizeof(WCHAR));
- if (!Env)
- {
- return FALSE;
- }
-
- MultiByteToWideChar(CP_ACP, 0, Environment, -1, Env, strlen(Environment)+1);
- Env[strlen(Environment)] = L'\0';
-
- Prov = HeapAlloc(GetProcessHeap(), 0, (strlen(PrintProvidor)+1) * sizeof(WCHAR));
- if (!Prov)
- {
- HeapFree(GetProcessHeap(), 0, Env);
- return FALSE;
- }
-
- MultiByteToWideChar(CP_ACP, 0, PrintProvidor, -1, Prov, strlen(PrintProvidor)+1);
- Prov[strlen(PrintProvidor)] = L'\0';
-
- bRet = DeletePrintProvidorW(NULL, Env, Prov);
- HeapFree(GetProcessHeap(), 0, Env);
- HeapFree(GetProcessHeap(), 0, Prov);
-
- return bRet;
-}
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-DeletePrintProvidorW(LPWSTR Name, LPWSTR Environment, LPWSTR PrintProvidor)
-{
- HKEY hKey;
- BOOL bFound;
- DWORD dwType, dwSize, dwOffset, dwLength;
- LPWSTR pOrder, pBuffer, pNew;
-
- if (Name || !Environment || !PrintProvidor)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Print\\Providers", 0, KEY_READ | KEY_WRITE, &hKey) != ERROR_SUCCESS)
- {
- return FALSE;
- }
-
- if (RegQueryValueExW(hKey, L"Order", NULL, &dwType, NULL, &dwSize) != ERROR_SUCCESS || dwType != REG_MULTI_SZ)
- {
- RegCloseKey(hKey);
- return FALSE;
- }
-
- pOrder = HeapAlloc(GetProcessHeap(), 0, dwSize);
- if (!pOrder)
- {
- RegCloseKey(hKey);
- return FALSE;
- }
-
- if (RegQueryValueExW(hKey, L"Order", NULL, &dwType, (LPBYTE)pOrder, &dwSize) != ERROR_SUCCESS || dwType != REG_MULTI_SZ)
- {
- RegCloseKey(hKey);
- return FALSE;
- }
-
-
- pBuffer = pOrder;
- bFound = FALSE;
- while(pBuffer[0])
- {
- if (!wcsicmp(pBuffer, PrintProvidor))
- {
- bFound = TRUE;
- break;
- }
- pBuffer += wcslen(pBuffer) + 1;
- }
-
- if (!bFound)
- {
- RegCloseKey(hKey);
- HeapFree(GetProcessHeap(), 0, pOrder);
- return FALSE;
- }
-
- pNew = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
- if (!pNew)
- {
- RegCloseKey(hKey);
- HeapFree(GetProcessHeap(), 0, pOrder);
- return FALSE;
- }
-
- dwOffset = pBuffer - pOrder;
- dwLength = (dwSize / sizeof(WCHAR)) - (dwOffset + wcslen(pBuffer) + 1);
- CopyMemory(pNew, pOrder, dwOffset * sizeof(WCHAR));
- CopyMemory(&pNew[dwOffset], pBuffer + wcslen(pBuffer) + 1, dwLength);
-
- RegSetValueExW(hKey, L"Order", 0, REG_MULTI_SZ, (LPBYTE)pNew, (dwOffset + dwLength) * sizeof(WCHAR));
- RegDeleteKey(hKey, PrintProvidor);
-
- HeapFree(GetProcessHeap(), 0, pOrder);
- HeapFree(GetProcessHeap(), 0, pNew);
- RegCloseKey(hKey);
-
- return TRUE;
-}
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AddMonitorA(LPSTR Name, DWORD Level, PBYTE Monitors)
-{
- LPWSTR szName = NULL;
- MONITOR_INFO_2W Monitor;
- MONITOR_INFO_2A *pMonitor;
- BOOL bRet = FALSE;
-
- if (Level != 2 || !Monitors)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- pMonitor = (MONITOR_INFO_2A*)Monitors;
- if (pMonitor->pDLLName == NULL || pMonitor->pName == NULL)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- ZeroMemory(&Monitor, sizeof(Monitor));
-
- if (Name)
- {
- szName = HeapAlloc(GetProcessHeap(), 0, (strlen(Name) + 1) * sizeof(WCHAR));
- if (!szName)
- {
- return FALSE;
- }
- MultiByteToWideChar(CP_ACP, 0, Name, -1, szName, strlen(Name)+1);
- szName[strlen(Name)] = L'\0';
- }
-
- Monitor.pDLLName = HeapAlloc(GetProcessHeap(), 0, (strlen(pMonitor->pDLLName)+1) * sizeof(WCHAR));
- if (!Monitor.pDLLName)
- {
- goto cleanup;
- }
- MultiByteToWideChar(CP_ACP, 0, pMonitor->pDLLName, -1, Monitor.pDLLName, strlen(pMonitor->pDLLName)+1);
- pMonitor->pDLLName[strlen(pMonitor->pDLLName)] = L'\0';
-
- Monitor.pName = HeapAlloc(GetProcessHeap(), 0, (strlen(pMonitor->pName)+1) * sizeof(WCHAR));
- if (!Monitor.pName)
- {
- goto cleanup;
- }
- MultiByteToWideChar(CP_ACP, 0, pMonitor->pName, -1, Monitor.pName, strlen(pMonitor->pName)+1);
- pMonitor->pName[strlen(pMonitor->pName)] = L'\0';
-
-
- if (pMonitor->pEnvironment)
- {
- Monitor.pEnvironment = HeapAlloc(GetProcessHeap(), 0, (strlen(pMonitor->pEnvironment)+1) * sizeof(WCHAR));
- if (!Monitor.pEnvironment)
- {
- goto cleanup;
- }
- MultiByteToWideChar(CP_ACP, 0, pMonitor->pEnvironment, -1, Monitor.pEnvironment, strlen(pMonitor->pEnvironment)+1);
- pMonitor->pEnvironment[strlen(pMonitor->pEnvironment)] = L'\0';
- }
-
- bRet = AddMonitorW(szName, Level, (LPBYTE)&Monitor);
-
-cleanup:
-
- if (szName)
- HeapFree(GetProcessHeap(), 0, szName);
-
- if (Monitor.pDLLName)
- HeapFree(GetProcessHeap(), 0, Monitor.pDLLName);
-
- if (Monitor.pEnvironment)
- HeapFree(GetProcessHeap(), 0, Monitor.pEnvironment);
-
- if (Monitor.pName)
- HeapFree(GetProcessHeap(), 0, Monitor.pName);
-
- return bRet;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AddMonitorW(LPWSTR Name, DWORD Level, PBYTE Monitors)
-{
- WCHAR szPath[MAX_PATH];
- HMODULE hLibrary = NULL;
- FARPROC InitProc;
- HKEY hKey, hSubKey;
- MONITOR_INFO_2W * pMonitor;
-
-
- if (Level != 2 || !Monitors)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- pMonitor = (MONITOR_INFO_2W*)Monitors;
-
- if (pMonitor->pDLLName == NULL || pMonitor->pName == NULL)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- if (wcschr(pMonitor->pDLLName, L'\\'))
- {
- hLibrary = LoadLibraryExW(pMonitor->pDLLName, NULL, 0);
- }
- else if (GetSystemDirectoryW(szPath, MAX_PATH) && PathAddBackslashW(szPath))
- {
- wcscat(szPath, pMonitor->pDLLName);
- hLibrary = LoadLibraryExW(szPath, NULL, 0);
- }
-
- if (!hLibrary)
- {
- return FALSE;
- }
-
- InitProc = GetProcAddress(hLibrary, "InitializePrintMonitor");
- if (!InitProc)
- {
- InitProc = GetProcAddress(hLibrary, "InitializePrintMonitor2");
- if (!InitProc)
- {
- FreeLibrary(hLibrary);
- SetLastError(ERROR_PROC_NOT_FOUND);
- return FALSE;
- }
- }
-
- // FIXME
- // Initialize monitor
- FreeLibrary(hLibrary);
-
- if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors", 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
- {
- if (RegCreateKeyExW(hKey, pMonitor->pName, 0, NULL, 0, KEY_WRITE, NULL, &hSubKey, NULL) == ERROR_SUCCESS)
- {
- RegSetValueExW(hSubKey, L"Driver", 0, REG_SZ, (LPBYTE)pMonitor->pDLLName, (wcslen(pMonitor->pDLLName)+1)*sizeof(WCHAR));
- RegCloseKey(hSubKey);
- }
- RegCloseKey(hKey);
- }
- return TRUE;
-}
-
+++ /dev/null
-#ifndef _WINSPOOL_DRV_PCH_
-#define _WINSPOOL_DRV_PCH_
-
-#include <wine/config.h>
-
-#include <stdarg.h>
-
-#define WIN32_NO_STATUS
-#define _INC_WINDOWS
-#define COM_NO_WINDOWS_H
-
-#include <windef.h>
-#include <winbase.h>
-#include <wingdi.h>
-#include <winspool.h>
-
-#endif /* _WINSPOOL_DRV_PCH_ */
+++ /dev/null
-/*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS winspool DRV
- * FILE: stubs.c
- * PURPOSE: Stub functions
- * PROGRAMMERS: Ge van Geldorp (ge@gse.nl)
- * REVISIONS:
- */
-
-#include "precomp.h"
-
-#include <winuser.h>
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-DllMain(HINSTANCE InstDLL,
- DWORD Reason,
- LPVOID Reserved)
-{
- return TRUE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AbortPrinter(HANDLE Printer)
-{
- OutputDebugStringW(L"winspool AbortPrinter stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AddFormA(HANDLE Printer, DWORD Level, PBYTE Form)
-{
- OutputDebugStringW(L"winspool AddFormA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AddFormW(HANDLE Printer, DWORD Level, PBYTE Form)
-{
- OutputDebugStringW(L"winspool AddFormW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AddJobA(HANDLE Printer, DWORD Level, PBYTE Data, DWORD BufSize, PDWORD Needed)
-{
- OutputDebugStringW(L"winspool AddJobA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AddJobW(HANDLE Printer, DWORD Level, PBYTE Data, DWORD BufSize, PDWORD Needed)
-{
- OutputDebugStringW(L"winspool AddJobW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AddPortA(LPSTR Name, HWND Wnd, LPSTR MonitorName)
-{
- OutputDebugStringW(L"winspool stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AddPortW(LPWSTR Name, HWND Wnd, LPWSTR MonitorName)
-{
- OutputDebugStringW(L"winspool AddPortW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-HANDLE
-WINAPI
-AddPrinterA(LPSTR Name, DWORD Level, PBYTE Buffer)
-{
- OutputDebugStringW(L"winspool AddPrinterA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return NULL;
-}
-
-
-/*
- * @unimplemented
- */
-HANDLE
-WINAPI
-AddPrinterW(LPWSTR Name, DWORD Level, PBYTE Buffer)
-{
- OutputDebugStringW(L"winspool AddPrinterW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return NULL;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AddPrinterConnectionA(LPSTR Name)
-{
- OutputDebugStringW(L"winspool AddPrinterConnectionA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AddPrinterConnectionW(LPWSTR Name)
-{
- OutputDebugStringW(L"winspool AddPrinterConnectionW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AddPrinterDriverA(LPSTR Name, DWORD Level, PBYTE Buffer)
-{
- OutputDebugStringW(L"winspool AddPrinterDriverA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AddPrinterDriverW(LPWSTR Name, DWORD Level, PBYTE Buffer)
-{
- OutputDebugStringW(L"winspool AddPrinterDriverW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AddPrintProcessorA(LPSTR Name, LPSTR Environment, LPSTR PathName, LPSTR PrintProcessorName)
-{
- OutputDebugStringW(L"winspool AddPrintProcessorA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AddPrintProcessorW(LPWSTR Name, LPWSTR Environment, LPWSTR PathName, LPWSTR PrintProcessorName)
-{
- OutputDebugStringW(L"winspool AddPrintProcessorW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-/*
- * @unimplemented
- */
-LONG
-WINAPI
-AdvancedDocumentPropertiesA(HWND Wnd, HANDLE Printer, LPSTR DeviceName, PDEVMODEA DevModeOut, PDEVMODEA DevModeIn)
-{
- OutputDebugStringW(L"winspool AdvancedDocumentPropertiesA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return 0;
-}
-
-
-/*
- * @unimplemented
- */
-LONG
-WINAPI
-AdvancedDocumentPropertiesW(HWND Wnd, HANDLE Printer, LPWSTR DeviceName, PDEVMODEW DevModeOut, PDEVMODEW DevModeIn)
-{
- OutputDebugStringW(L"winspool AdvancedDocumentPropertiesW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return 0;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-ClosePrinter(HANDLE Printer)
-{
- OutputDebugStringW(L"winspool ClosePrinter stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-ConfigurePortA(LPSTR Name, HWND Wnd, LPSTR PortName)
-{
- OutputDebugStringW(L"winspool ConfigurePortA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-ConfigurePortW(LPWSTR Name, HWND Wnd, LPWSTR PortName)
-{
- OutputDebugStringW(L"winspool ConfigurePortW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-HANDLE
-WINAPI
-ConnectToPrinterDlg(HWND Wnd, DWORD Flags)
-{
- OutputDebugStringW(L"winspool ConnectToPrinterDlg stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return NULL;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-DeleteFormA(HANDLE Printer, LPSTR Name)
-{
- OutputDebugStringW(L"winspool DeleteFormA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-DeleteFormW(HANDLE Printer, LPWSTR Name)
-{
- OutputDebugStringW(L"winspool DeleteFormW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-DeleteMonitorA(LPSTR Name, LPSTR Environment, LPSTR MonitorName)
-{
- OutputDebugStringW(L"winspool DeleteMonitorA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-DeleteMonitorW(LPWSTR Name, LPWSTR Environment, LPWSTR MonitorName)
-{
- OutputDebugStringW(L"winspool DeleteMonitorW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-DeletePortA(LPSTR Name, HWND Wnd, LPSTR PortName)
-{
- OutputDebugStringW(L"winspool DeletePortA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-DeletePortW(LPWSTR Name, HWND Wnd, LPWSTR PortName)
-{
- OutputDebugStringW(L"winspool DeletePortW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-DeletePrinter(HANDLE Printer)
-{
- OutputDebugStringW(L"winspool DeletePrinter stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-DeletePrinterConnectionA(LPSTR Name)
-{
- OutputDebugStringW(L"winspool DeletePrinterConnectionA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-DeletePrinterConnectionW(LPWSTR Name)
-{
- OutputDebugStringW(L"winspool DeletePrinterConnectionW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-DeletePrinterDataA(HANDLE Printer, LPSTR Name)
-{
- OutputDebugStringW(L"winspool DeletePrinterDataA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-DeletePrinterDataW(HANDLE Printer, LPWSTR Name)
-{
- OutputDebugStringW(L"winspool DeletePrinterDataW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-DeletePrinterDriverA(LPSTR Name, LPSTR Environment, LPSTR Driver)
-{
- OutputDebugStringW(L"winspool DeletePrinterDriverA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-DeletePrinterDriverW(LPWSTR Name, LPWSTR Environment, LPWSTR Driver)
-{
- OutputDebugStringW(L"winspool DeletePrinterDriverW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-DeletePrintProcessorA(LPSTR Name, LPSTR Environment, LPSTR PrintProcessor)
-{
- OutputDebugStringW(L"winspool DeletePrintProcessorA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-DeletePrintProcessorW(LPWSTR Name, LPWSTR Environment, LPWSTR PrintProcessor)
-{
- OutputDebugStringW(L"winspool DeletePrintProcessorW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-DeviceCapabilitiesA(LPCSTR Device, LPCSTR Port, WORD Capability, LPSTR Buffer, CONST DEVMODEA *DevMode)
-{
- OutputDebugStringW(L"winspool DeviceCapabilitiesA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return -1;
-}
-
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-DeviceCapabilitiesW(LPCWSTR Device, LPCWSTR Port, WORD Capability, LPWSTR Buffer, CONST DEVMODEW *DevMode)
-{
- OutputDebugStringW(L"winspool DeviceCapabilitiesW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return -1;
-}
-
-
-/*
- * @unimplemented
- */
-LONG
-WINAPI
-DocumentPropertiesA(HWND Wnd, HANDLE Printer, LPSTR Device, PDEVMODEA DevModeOut, PDEVMODEA DevModeIn, DWORD Mode)
-{
- OutputDebugStringW(L"winspool DocumentPropertiesA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return -1L;
-}
-
-
-/*
- * @unimplemented
- */
-LONG
-WINAPI
-DocumentPropertiesW(HWND Wnd, HANDLE Printer, LPWSTR Device, PDEVMODEW DevModeOut, PDEVMODEW DevModeIn, DWORD Mode)
-{
- OutputDebugStringW(L"winspool DocumentPropertiesW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-EndDocPrinter(HANDLE Printer)
-{
- OutputDebugStringW(L"winspool EndDocPrinter stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-EndPagePrinter(HANDLE Printer)
-{
- OutputDebugStringW(L"winspool EndPagePrinter stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-EnumFormsA(HANDLE Printer, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed, PDWORD Returned)
-{
- OutputDebugStringW(L"winspool EnumFormsA stub called\n");
- *Needed = 0;
- *Returned = 0;
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-EnumFormsW(HANDLE Printer, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed, PDWORD Returned)
-{
- OutputDebugStringW(L"winspool EnumFormsW stub called\n");
- *Needed = 0;
- *Returned = 0;
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-EnumJobsA(HANDLE Printer, DWORD First, DWORD NoJobs, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed, PDWORD Returned)
-{
- OutputDebugStringW(L"winspool EnumJobsA stub called\n");
- *Needed = 0;
- *Returned = 0;
-
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-EnumJobsW(HANDLE Printer, DWORD First, DWORD NoJobs, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed, PDWORD Returned)
-{
- OutputDebugStringW(L"winspool EnumJobsW stub called\n");
- *Needed = 0;
- *Returned = 0;
-
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-EnumMonitorsA(LPSTR Name, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed, PDWORD Returned)
-{
- OutputDebugStringW(L"winspool EnumMonitorsA stub called\n");
- *Needed = 0;
- *Returned = 0;
-
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-EnumMonitorsW(LPWSTR Name, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed, PDWORD Returned)
-{
- OutputDebugStringW(L"winspool EnumMonitorsW stub called\n");
- *Needed = 0;
- *Returned = 0;
-
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-EnumPortsA(LPSTR Name, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed, PDWORD Returned)
-{
- OutputDebugStringW(L"winspool EnumPortsA stub called\n");
- *Needed = 0;
- *Returned = 0;
-
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-EnumPortsW(LPWSTR Name, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed, PDWORD Returned)
-{
- OutputDebugStringW(L"winspool EnumPortsW stub called\n");
- *Needed = 0;
- *Returned = 0;
-
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-EnumPrinterDataA(HANDLE Printer, DWORD Index, LPSTR Name, DWORD NameSize, PDWORD NameReturned, PDWORD Type, PBYTE Buffer, DWORD BufSize, PDWORD BufReturned)
-{
- OutputDebugStringW(L"winspool EnumPrinterDataA stub called\n");
-
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-EnumPrinterDataW(HANDLE Printer, DWORD Index, LPWSTR Name, DWORD NameSize, PDWORD NameReturned, PDWORD Type, PBYTE Buffer, DWORD BufSize, PDWORD BufReturned)
-{
- OutputDebugStringW(L"winspool EnumPrinterDataW stub called\n");
-
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-EnumPrinterDriversA(LPSTR Name, LPSTR Environment, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed, PDWORD Returned)
-{
- OutputDebugStringW(L"winspool EnumPrinterDriversA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- *Needed = 0;
- *Returned = 0;
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-EnumPrinterDriversW(LPWSTR Name, LPWSTR Environment, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed, PDWORD Returned)
-{
- OutputDebugStringW(L"winspool EnumPrinterDriversW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- *Needed = 0;
- *Returned = 0;
-
- return FALSE;
-}
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-EnumPrinterKeyA(HANDLE Printer, LPSTR KeyName, LPTSTR Subkey, DWORD SubkeySize, PDWORD SubkeyReturned)
-{
- OutputDebugStringW(L"winspool EnumPrinterKeyA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- *SubkeyReturned = 0;
-
- return ERROR_FILE_NOT_FOUND;
-}
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-EnumPrinterKeyW(HANDLE Printer, LPWSTR KeyName, LPTSTR Subkey, DWORD SubkeySize, PDWORD SubkeyReturned)
-{
- OutputDebugStringW(L"winspool EnumPrinterKeyW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- *SubkeyReturned = 0;
-
- return ERROR_FILE_NOT_FOUND;
-}
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-EnumPrintersA(DWORD Flags, LPSTR Name, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed, PDWORD Returned)
-{
- OutputDebugStringW(L"winspool EnumPrintersA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- *Needed = 0;
- *Returned = 0;
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-EnumPrintersW(DWORD Flags, LPWSTR Name, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed, PDWORD Returned)
-{
- OutputDebugStringW(L"winspool EnumPrintersW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- *Needed = 0;
- *Returned = 0;
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-EnumPrintProcessorDatatypesA(LPSTR Name, LPSTR PrintProcessor, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed, PDWORD Returned)
-{
- OutputDebugStringW(L"winspool EnumPrintProcessorDatatypesA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- *Needed = 0;
- *Returned = 0;
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-EnumPrintProcessorDatatypesW(LPWSTR Name, LPWSTR PrintProcessor, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed, PDWORD Returned)
-{
- OutputDebugStringW(L"winspool EnumPrintProcessorDatatypesW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- *Needed = 0;
- *Returned = 0;
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-EnumPrintProcessorsA(LPSTR Name, LPSTR Environment, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed, PDWORD Returned)
-{
- OutputDebugStringW(L"winspool EnumPrintProcessorsA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- *Needed = 0;
- *Returned = 0;
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-EnumPrintProcessorsW(LPWSTR Name, LPWSTR Environment, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed, PDWORD Returned)
-{
- OutputDebugStringW(L"winspool EnumPrintProcessorsW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- *Needed = 0;
- *Returned = 0;
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-FindClosePrinterChangeNotification(HANDLE Printer)
-{
- OutputDebugStringW(L"winspool FindClosePrinterChangeNotification stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-HANDLE
-WINAPI
-FindFirstPrinterChangeNotification(HANDLE Printer, DWORD Flags, DWORD Options, PVOID NotifyOptions)
-{
- OutputDebugStringW(L"winspool FindFirstPrinterChangeNotification stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return INVALID_HANDLE_VALUE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-FindNextPrinterChangeNotification(HANDLE Printer, PDWORD Change, LPVOID NotifyOptions, LPVOID* NotifyInfo)
-{
- OutputDebugStringW(L"winspool FindNextPrinterChangeNotification stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-FreePrinterNotifyInfo(PPRINTER_NOTIFY_INFO NotifyInfo)
-{
- OutputDebugStringW(L"winspool FreePrinterNotifyInfo stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-GetFormA(HANDLE Printer, LPSTR Name, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed)
-{
- OutputDebugStringW(L"winspool GetFormA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-GetFormW(HANDLE Printer, LPWSTR Name, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed)
-{
- OutputDebugStringW(L"winspool GetFormW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-GetJobA(HANDLE Printer, DWORD Job, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed)
-{
- OutputDebugStringW(L"winspool GetJobA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-GetJobW(HANDLE Printer, DWORD Job, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed)
-{
- OutputDebugStringW(L"winspool GetJobW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-GetPrinterA(HANDLE Printer, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed)
-{
- OutputDebugStringW(L"winspool GetPrinterA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-GetPrinterW(HANDLE Printer, DWORD Level, PBYTE Buffer, DWORD BufSize, PDWORD Needed)
-{
- OutputDebugStringW(L"winspool GetPrinterW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-GetPrinterDataA(HANDLE Printer, LPSTR Name, PDWORD Type, PBYTE Buffer, DWORD BufSize, PDWORD Needed)
-{
- OutputDebugStringW(L"winspool GetPrinterDataA stub called\n");
-
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-GetPrinterDataW(HANDLE Printer, LPWSTR Name, PDWORD Type, PBYTE Buffer, DWORD BufSize, PDWORD Needed)
-{
- OutputDebugStringW(L"winspool GetPrinterDataW stub called\n");
-
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-GetPrinterDriverA(HANDLE Printer, LPSTR Environment, DWORD Level, LPBYTE Buffer, DWORD BufSize, LPDWORD Needed)
-{
- OutputDebugStringW(L"winspool GetPrinterDriverA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return 0;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-GetPrinterDriverW(HANDLE Printer, LPWSTR Environment, DWORD Level, LPBYTE Buffer, DWORD BufSize, LPDWORD Needed)
-{
- OutputDebugStringW(L"winspool GetPrinterDriverW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return 0;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-GetPrinterDriverDirectoryA(LPSTR Name, LPSTR Environment, DWORD Level, LPBYTE Buffer, DWORD BufSize, LPDWORD Needed)
-{
- OutputDebugStringW(L"winspool GetPrinterDriverDirectoryA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return 0;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-GetPrinterDriverDirectoryW(LPWSTR Name, LPWSTR Environment, DWORD Level, LPBYTE Buffer, DWORD BufSize, LPDWORD Needed)
-{
- OutputDebugStringW(L"winspool GetPrinterDriverDirectoryW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return 0;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-GetPrintProcessorDirectoryA(LPSTR Name, LPSTR Environment, DWORD Level, LPBYTE Buffer, DWORD BufSize, LPDWORD Needed)
-{
- OutputDebugStringW(L"winspool GetPrintProcessorDirectoryA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return 0;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-GetPrintProcessorDirectoryW(LPWSTR Name, LPWSTR Environment, DWORD Level, LPBYTE Buffer, DWORD BufSize, LPDWORD Needed)
-{
- OutputDebugStringW(L"winspool GetPrintProcessorDirectoryW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return 0;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-OpenPrinterA(LPSTR Name, PHANDLE Printer, LPPRINTER_DEFAULTSA Defaults)
-{
- OutputDebugStringW(L"winspool OpenPrinterA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-OpenPrinterW(LPWSTR Name, PHANDLE Printer, LPPRINTER_DEFAULTSW Defaults)
-{
- OutputDebugStringW(L"winspool OpenPrinterW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-PrinterMessageBoxA(HANDLE Printer, DWORD Error, HWND Wnd, LPSTR Text, LPSTR Caption, DWORD Type)
-{
- OutputDebugStringW(L"winspool PrinterMessageBoxA stub called\n");
-
- return IDCANCEL;
-}
-
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-PrinterMessageBoxW(HANDLE Printer, DWORD Error, HWND Wnd, LPWSTR Text, LPWSTR Caption, DWORD Type)
-{
- OutputDebugStringW(L"winspool PrinterMessageBoxW stub called\n");
-
- return IDCANCEL;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-PrinterProperties(HWND Wnd, HANDLE Printer)
-{
- OutputDebugStringW(L"winspool PrinterProperties stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-ReadPrinter(HANDLE Printer, PVOID Buffer, DWORD BufSize, PDWORD Received)
-{
- OutputDebugStringW(L"winspool ReadPrinter stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-ResetPrinterA(HANDLE Printer, LPPRINTER_DEFAULTSA Defaults)
-{
- OutputDebugStringW(L"winspool ResetPrinterA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-ResetPrinterW(HANDLE Printer, LPPRINTER_DEFAULTSW Defaults)
-{
- OutputDebugStringW(L"winspool ResetPrinterW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-ScheduleJob(HANDLE Printer, DWORD Job)
-{
- OutputDebugStringW(L"winspool ScheduleJob stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-SetFormA(HANDLE Printer, LPSTR Form, DWORD Level, PBYTE Buffer)
-{
- OutputDebugStringW(L"winspool SetFormA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-SetFormW(HANDLE Printer, LPWSTR Form, DWORD Level, PBYTE Buffer)
-{
- OutputDebugStringW(L"winspool SetFormW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-SetJobA(HANDLE Printer, DWORD Job, DWORD Level, PBYTE Buffer, DWORD Command)
-{
- OutputDebugStringW(L"winspool SetJobA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-SetJobW(HANDLE Printer, DWORD Job, DWORD Level, PBYTE Buffer, DWORD Command)
-{
- OutputDebugStringW(L"winspool SetJobW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-SetPrinterA(HANDLE Printer, DWORD Level, PBYTE Buffer, DWORD Command)
-{
- OutputDebugStringW(L"winspool SetPrinterA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-SetPrinterW(HANDLE Printer, DWORD Level, PBYTE Buffer, DWORD Command)
-{
- OutputDebugStringW(L"winspool SetPrinterW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-SetPrinterDataA(HANDLE Printer, LPSTR Name, DWORD Type, PBYTE Buffer, DWORD BufSize)
-{
- OutputDebugStringW(L"winspool SetPrinterDataA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-SetPrinterDataW(HANDLE Printer, LPWSTR Name, DWORD Type, PBYTE Buffer, DWORD BufSize)
-{
- OutputDebugStringW(L"winspool SetPrinterDataW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-StartDocPrinterA(HANDLE Printer, DWORD Level, PBYTE Buffer)
-{
- OutputDebugStringW(L"winspool StartDocPrinterA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return 0;
-}
-
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-StartDocPrinterW(HANDLE Printer, DWORD Level, PBYTE Buffer)
-{
- OutputDebugStringW(L"winspool StartDocPrinterW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return 0;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-StartPagePrinter(HANDLE Printer)
-{
- OutputDebugStringW(L"winspool StartPagePrinter stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-WaitForPrinterChange(HANDLE Printer, DWORD Flags)
-{
- OutputDebugStringW(L"winspool WaitForPrinterChange stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return 0;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-WritePrinter(HANDLE Printer, PVOID Buffer, DWORD BufSize, PDWORD Written)
-{
- OutputDebugStringW(L"winspool WritePrinter stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-
- return FALSE;
-}
-
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-XcvDataW(HANDLE hXcv,
- LPCWSTR pszDataName,
- PBYTE pInputData,
- DWORD cbInputData,
- PBYTE pOutputData,
- DWORD cbOutputData,
- PDWORD pcbOutputNeeded,
- PDWORD pdwStatus)
-{
- OutputDebugStringW(L"winspool XcvDataW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
-}
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-SetDefaultPrinterA(LPCSTR pszPrinter)
-{
- OutputDebugStringW(L"winspool SetDefaultPrinterA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
-}
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-SetDefaultPrinterW(LPCWSTR pszPrinter)
-{
- OutputDebugStringW(L"winspool SetDefaultPrinterW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
-}
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AddPortExA(LPSTR pName,
- DWORD dwLevel,
- LPBYTE pBuffer,
- LPSTR pMonitorName)
-{
- OutputDebugStringW(L"winspool AddPortExA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
-}
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AddPortExW(LPWSTR pName,
- DWORD dwLevel,
- LPBYTE pBuffer,
- LPWSTR pMonitorName)
-{
- OutputDebugStringW(L"winspool AddPortExW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
-}
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AddPrinterDriverExA(LPSTR pName,
- DWORD dwLevel,
- LPBYTE pDriverInfo,
- DWORD dwFileCopyFlags)
-{
- OutputDebugStringW(L"winspool AddPrinterDriverExA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
-}
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-AddPrinterDriverExW(LPWSTR pName,
- DWORD dwLevel,
- LPBYTE pDriverInfo,
- DWORD dwFileCopyFlags)
-{
- OutputDebugStringW(L"winspool AddPrinterDriverExW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
-}
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-DeletePrinterDataExA(HANDLE hPrinter,
- LPCSTR pKeyName,
- LPCSTR pValueName)
-{
- OutputDebugStringW(L"winspool DeletePrinterDataExA stub called\n");
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-DeletePrinterDataExW(HANDLE hPrinter,
- LPCWSTR pKeyName,
- LPCWSTR pValueName)
-{
- OutputDebugStringW(L"winspool DeletePrinterDataExW stub called\n");
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-DeletePrinterDriverExA(LPSTR pName,
- LPSTR pEnvironment,
- LPSTR pDriverName,
- DWORD dwDeleteFlag,
- DWORD dwVersionFlag)
-{
- OutputDebugStringW(L"winspool DeletePrinterDriverExA stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
-}
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-DeletePrinterDriverExW(LPWSTR pName,
- LPWSTR pEnvironment,
- LPWSTR pDriverName,
- DWORD dwDeleteFlag,
- DWORD dwVersionFlag)
-{
- OutputDebugStringW(L"winspool DeletePrinterDriverExW stub called\n");
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
-}
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-EnumPrinterDataExA(HANDLE hPrinter,
- LPCSTR pKeyName,
- LPBYTE pEnumValues,
- DWORD cbEnumValues,
- LPDWORD pcbEnumValues,
- LPDWORD pnEnumValues)
-{
- OutputDebugStringW(L"winspool EnumPrinterDataExA stub called\n");
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-EnumPrinterDataExW(HANDLE hPrinter,
- LPCWSTR pKeyName,
- LPBYTE pEnumValues,
- DWORD cbEnumValues,
- LPDWORD pcbEnumValues,
- LPDWORD pnEnumValues)
-{
- OutputDebugStringW(L"winspool EnumPrinterDataExW stub called\n");
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
-/*
- * @unimplemented
- */
-LONG
-WINAPI
-ExtDeviceMode(HWND hWnd,
- HANDLE hInst,
- LPDEVMODEA pDevModeOutput,
- LPSTR pDeviceName,
- LPSTR pPort,
- LPDEVMODEA pDevModeInput,
- LPSTR pProfile,
- DWORD fMode)
-{
- OutputDebugStringW(L"winspool ExtDeviceMode stub called\n");
- return -1;
-}
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-GetPrinterDataExA(HANDLE hPrinter,
- LPCSTR pKeyName,
- LPCSTR pValueName,
- LPDWORD pType,
- LPBYTE pData,
- DWORD nSize,
- LPDWORD pcbNeeded)
-{
- OutputDebugStringW(L"winspool GetPrinterDataExA stub called\n");
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-GetPrinterDataExW(HANDLE hPrinter,
- LPCWSTR pKeyName,
- LPCWSTR pValueName,
- LPDWORD pType,
- LPBYTE pData,
- DWORD nSize,
- LPDWORD pcbNeeded)
-{
- OutputDebugStringW(L"winspool GetPrinterDataExW stub called\n");
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-SetPrinterDataExA(HANDLE hPrinter,
- LPCSTR pKeyName,
- LPCSTR pValueName,
- DWORD dwType,
- LPBYTE pData,
- DWORD cbData)
-{
- OutputDebugStringW(L"winspool SetPrinterDataExA stub called\n");
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
-/*
- * @unimplemented
- */
-DWORD
-WINAPI
-SetPrinterDataExW(HANDLE hPrinter,
- LPCWSTR pKeyName,
- LPCWSTR pValueName,
- DWORD dwType,
- LPBYTE pData,
- DWORD cbData)
-{
- OutputDebugStringW(L"winspool SetPrinterDataExW stub called\n");
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
-/*
- * @unimplemented
- */
-BOOL
-WINAPI
-SpoolerInit(VOID)
-{
- OutputDebugStringW(L"winspool SpoolerInit stub called\n");
- return FALSE;
-}
+++ /dev/null
-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
-201 stdcall GetDefaultPrinterA(ptr ptr)
-202 stdcall SetDefaultPrinterA(str)
-203 stdcall GetDefaultPrinterW(ptr ptr)
-204 stdcall SetDefaultPrinterW(wstr)
-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
-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
-
-@ stub ADVANCEDSETUPDIALOG
-@ stdcall AbortPrinter(long)
-@ stdcall AddFormA(long long ptr)
-@ stdcall AddFormW(long long ptr)
-@ stdcall AddJobA(long long ptr long ptr)
-@ stdcall AddJobW(long long ptr long ptr)
-@ stdcall AddMonitorA(str long ptr)
-@ stdcall AddMonitorW(wstr long ptr)
-@ stdcall AddPortA(str ptr str)
-@ stdcall AddPortExA(str long ptr str)
-@ stdcall AddPortExW(wstr long ptr wstr)
-@ stdcall AddPortW(wstr long wstr)
-@ stdcall AddPrinterA(str long ptr)
-@ stdcall AddPrinterConnectionA(str)
-@ stdcall AddPrinterConnectionW(wstr)
-@ stdcall AddPrinterDriverA(str long ptr)
-@ stdcall AddPrinterDriverExA(str long ptr long)
-@ stdcall AddPrinterDriverExW(wstr long ptr long)
-@ stdcall AddPrinterDriverW(wstr long ptr)
-@ stdcall AddPrinterW(wstr long ptr)
-@ stdcall AddPrintProcessorA(str str str str)
-@ stdcall AddPrintProcessorW(wstr wstr wstr wstr)
-@ stdcall AddPrintProvidorA(str long ptr)
-@ stdcall AddPrintProvidorW(wstr long ptr)
-@ stdcall AdvancedDocumentPropertiesA(long long str ptr ptr)
-@ stdcall AdvancedDocumentPropertiesW(long long wstr ptr ptr)
-@ stub AdvancedSetupDialog
-@ stdcall ClosePrinter(long)
-@ stub CloseSpoolFileHandle
-@ stdcall ConfigurePortA(str long str)
-@ stdcall ConfigurePortW(wstr long wstr)
-@ stdcall ConnectToPrinterDlg(long long)
-@ stub ConvertAnsiDevModeToUnicodeDevMode
-@ stub ConvertUnicodeDevModeToAnsiDevMode
-@ stub CommitSpoolData
-@ stub CreatePrinterIC
-@ stub DEVICECAPABILITIES
-@ stub DEVICEMODE
-@ stdcall DeleteFormA(long str)
-@ stdcall DeleteFormW(long wstr)
-@ stdcall DeleteMonitorA(str str str)
-@ stdcall DeleteMonitorW(wstr wstr wstr)
-@ stdcall DeletePortA(str long str)
-@ stdcall DeletePortW(wstr long wstr)
-@ stdcall DeletePrinter(long)
-@ stdcall DeletePrinterConnectionA(str)
-@ stdcall DeletePrinterConnectionW(wstr)
-@ stdcall DeletePrinterDataExA(long str str)
-@ stdcall DeletePrinterDataExW(long wstr wstr)
-@ stdcall DeletePrinterDataA(ptr str)
-@ stdcall DeletePrinterDataW(ptr wstr)
-@ stdcall DeletePrinterDriverA(str str str)
-@ stdcall DeletePrinterDriverExA(str str str long long)
-@ stdcall DeletePrinterDriverExW(wstr wstr wstr long long)
-@ stdcall DeletePrinterDriverW(wstr wstr wstr)
-@ stub DeletePrinterIC
-@ stub DevQueryPrint
-@ stdcall DeletePrintProcessorA(str str str)
-@ stdcall DeletePrintProcessorW(wstr wstr wstr)
-@ stdcall DeletePrintProvidorA(str str str)
-@ stdcall DeletePrintProvidorW(wstr wstr wstr)
-@ stdcall DeviceCapabilitiesA(str str long ptr ptr)
-@ stdcall DeviceCapabilitiesW(wstr wstr long ptr ptr)
-@ stub DeviceMode
-@ stub DocumentEvent
-@ stdcall DllMain(ptr long ptr)
-@ stdcall DocumentPropertiesA(long long ptr ptr ptr long)
-@ stdcall DocumentPropertiesW(long long ptr ptr ptr long)
-@ stub EXTDEVICEMODE
-@ stdcall EndDocPrinter(long)
-@ stdcall EndPagePrinter(long)
-@ stdcall EnumFormsA(long long ptr long ptr ptr)
-@ stdcall EnumFormsW(long long ptr long ptr ptr)
-@ stdcall EnumJobsA(long long long long ptr long ptr ptr)
-@ stdcall EnumJobsW(long long long long ptr long ptr ptr)
-@ stdcall EnumMonitorsA(str long ptr long long long)
-@ stdcall EnumMonitorsW(wstr long ptr long long long)
-@ stdcall EnumPortsA(str long ptr ptr ptr ptr)
-@ stdcall EnumPortsW(wstr long ptr ptr ptr ptr)
-@ stdcall EnumPrinterDataA(long long ptr long ptr ptr ptr long ptr)
-@ stdcall EnumPrinterDataExA(long str ptr long ptr ptr)
-@ stdcall EnumPrinterDataExW(long wstr ptr long ptr ptr)
-@ stdcall EnumPrinterDataW(long long ptr long ptr ptr ptr long ptr)
-@ stdcall EnumPrinterDriversA(str str long ptr long ptr ptr)
-@ stdcall EnumPrinterDriversW(wstr wstr long ptr long ptr ptr)
-@ stdcall EnumPrintersA(long ptr long ptr long ptr ptr)
-@ stdcall EnumPrintersW(long ptr long ptr long ptr ptr)
-@ stdcall EnumPrinterKeyA(long str str long ptr)
-@ stdcall EnumPrinterKeyW(long wstr wstr long ptr)
-@ stdcall ExtDeviceMode(long long ptr str str ptr str long)
-@ stdcall EnumPrintProcessorDatatypesA(str str long ptr long ptr ptr)
-@ stdcall EnumPrintProcessorDatatypesW(wstr wstr long ptr long ptr ptr)
-@ stdcall EnumPrintProcessorsA(str str long ptr long ptr ptr)
-@ stdcall EnumPrintProcessorsW(wstr wstr long ptr long ptr ptr)
-@ stdcall FindClosePrinterChangeNotification(long)
-@ stdcall FindFirstPrinterChangeNotification(long long long ptr)
-@ stdcall FindNextPrinterChangeNotification(long ptr ptr ptr)
-@ stdcall FreePrinterNotifyInfo(ptr)
-@ stdcall GetFormA(long str long ptr long ptr)
-@ stdcall GetFormW(long wstr long ptr long ptr)
-@ stdcall GetJobA(long long long ptr long ptr)
-@ stdcall GetJobW(long long long ptr long ptr)
-@ stdcall GetPrinterA(long long ptr long ptr)
-@ stdcall GetPrinterDataA(long str ptr ptr long ptr)
-@ stdcall GetPrinterDataExA(long str str ptr ptr long ptr)
-@ stdcall GetPrinterDataExW(long wstr wstr ptr ptr long ptr)
-@ stdcall GetPrinterDataW(long wstr ptr ptr long ptr)
-@ stdcall GetPrinterDriverA(long str long ptr long ptr)
-@ stdcall GetPrinterDriverDirectoryA(str str long ptr long ptr)
-@ stdcall GetPrinterDriverDirectoryW(wstr wstr long ptr long ptr)
-@ stdcall GetPrinterDriverW(long str long ptr long ptr)
-@ stdcall GetPrinterW(long long ptr long ptr)
-@ stdcall GetPrintProcessorDirectoryA(str str long ptr long ptr)
-@ stdcall GetPrintProcessorDirectoryW(wstr wstr long ptr long ptr)
-@ stub GetSpoolFileHandle
-@ stub IsValidDevmodeA
-@ stdcall -stub IsValidDevmodeW(ptr long)
-@ stdcall OpenPrinterA(str ptr ptr)
-@ stdcall OpenPrinterW(wstr ptr ptr)
-@ stub PlayGdiScriptOnPrinterIC
-@ stdcall PrinterMessageBoxA(ptr long ptr str str long)
-@ stdcall PrinterMessageBoxW(ptr long ptr wstr wstr long)
-@ stdcall PrinterProperties(long long)
-@ stub QueryColorProfile
-@ stub QuerySpoolMode
-@ stub QueryRemoteFonts
-@ stdcall ReadPrinter(long ptr long ptr)
-@ stdcall ResetPrinterA(long ptr)
-@ stdcall ResetPrinterW(long ptr)
-@ stdcall ScheduleJob(long long)
-@ stub SeekPrinter
-@ stub SetAllocFailCount
-@ stdcall SetFormA(long str long ptr)
-@ stdcall SetFormW(long wstr long ptr)
-@ stdcall SetJobA(long long long ptr long)
-@ stdcall SetJobW(long long long ptr long)
-@ stdcall SetPrinterA(long long ptr long)
-@ stdcall SetPrinterDataA(long str long ptr long)
-@ stdcall SetPrinterDataExA(long str str long ptr long)
-@ stdcall SetPrinterDataExW(long wstr wstr long ptr long)
-@ stdcall SetPrinterDataW(long wstr long ptr long)
-@ stdcall SetPrinterW(long long ptr long)
-@ stub SplDriverUnloadComplete
-@ stub SpoolerDevQueryPrintW
-@ stdcall SpoolerInit()
-@ stub SpoolerPrinterEvent
-@ stub StartDocDlgA
-@ stub StartDocDlgW
-@ stdcall StartDocPrinterA(long long ptr)
-@ stdcall StartDocPrinterW(long long ptr)
-@ stdcall StartPagePrinter(long)
-@ stdcall WaitForPrinterChange(ptr long)
-@ stdcall WritePrinter(long ptr long ptr)
-@ stdcall XcvDataW(long wstr ptr long ptr long ptr ptr)
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
#ifndef _WINSPOOL_
#define _WINSPOOL_
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include <_mingw_unicode.h>
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable:4820)
+#ifdef _WINUSER_
+#include <prsht.h>
#endif
-#define DI_CHANNEL 1
-#define DI_CHANNEL_WRITE 2
-#define DI_READ_SPOOL_JOB 3
-
-#define FORM_BUILTIN 1
-
-#define JOB_CONTROL_PAUSE 1
-#define JOB_CONTROL_RESUME 2
-#define JOB_CONTROL_CANCEL 3
-#define JOB_CONTROL_RESTART 4
-#define JOB_CONTROL_DELETE 5
-
-#define JOB_STATUS_PAUSED 1
-#define JOB_STATUS_ERROR 2
-#define JOB_STATUS_DELETING 4
-#define JOB_STATUS_SPOOLING 8
-#define JOB_STATUS_PRINTING 16
-#define JOB_STATUS_OFFLINE 32
-#define JOB_STATUS_PAPEROUT 0x40
-#define JOB_STATUS_PRINTED 0x80
-#define JOB_STATUS_DELETED 0x100
-#define JOB_STATUS_BLOCKED_DEVQ 0x200
-#define JOB_STATUS_USER_INTERVENTION 0x400
-
-#define JOB_POSITION_UNSPECIFIED 0
-
-#define JOB_NOTIFY_TYPE 1
-
-#define JOB_NOTIFY_FIELD_PRINTER_NAME 0
-#define JOB_NOTIFY_FIELD_MACHINE_NAME 1
-#define JOB_NOTIFY_FIELD_PORT_NAME 2
-#define JOB_NOTIFY_FIELD_USER_NAME 3
-#define JOB_NOTIFY_FIELD_NOTIFY_NAME 4
-#define JOB_NOTIFY_FIELD_DATATYPE 5
-#define JOB_NOTIFY_FIELD_PRINT_PROCESSOR 6
-#define JOB_NOTIFY_FIELD_PARAMETERS 7
-#define JOB_NOTIFY_FIELD_DRIVER_NAME 8
-#define JOB_NOTIFY_FIELD_DEVMODE 9
-#define JOB_NOTIFY_FIELD_STATUS 10
-#define JOB_NOTIFY_FIELD_STATUS_STRING 11
-#define JOB_NOTIFY_FIELD_SECURITY_DESCRIPTOR 12
-#define JOB_NOTIFY_FIELD_DOCUMENT 13
-#define JOB_NOTIFY_FIELD_PRIORITY 14
-#define JOB_NOTIFY_FIELD_POSITION 15
-#define JOB_NOTIFY_FIELD_SUBMITTED 16
-#define JOB_NOTIFY_FIELD_START_TIME 17
-#define JOB_NOTIFY_FIELD_UNTIL_TIME 18
-#define JOB_NOTIFY_FIELD_TIME 19
-#define JOB_NOTIFY_FIELD_TOTAL_PAGES 20
-#define JOB_NOTIFY_FIELD_PAGES_PRINTED 21
-#define JOB_NOTIFY_FIELD_TOTAL_BYTES 22
-#define JOB_NOTIFY_FIELD_BYTES_PRINTED 23
-
-#define JOB_ACCESS_ADMINISTER 16
-#define JOB_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|JOB_ACCESS_ADMINISTER)
-#define JOB_READ (STANDARD_RIGHTS_READ|JOB_ACCESS_ADMINISTER)
-#define JOB_WRITE (STANDARD_RIGHTS_WRITE|JOB_ACCESS_ADMINISTER)
-#define JOB_EXECUTE (STANDARD_RIGHTS_EXECUTE|JOB_ACCESS_ADMINISTER)
-
-#define PRINTER_NOTIFY_OPTIONS_REFRESH 1
-#define PRINTER_ACCESS_ADMINISTER 4
-#define PRINTER_ACCESS_USE 8
+#ifdef __cplusplus
+extern "C" {
+#endif
-#define PRINTER_ERROR_INFORMATION 0x80000000
-#define PRINTER_ERROR_WARNING 0x40000000
-#define PRINTER_ERROR_SEVERE 0x20000000
-#define PRINTER_ERROR_OUTOFPAPER 1
-#define PRINTER_ERROR_JAM 2
-#define PRINTER_ERROR_OUTOFTONER 4
-
-#define PRINTER_CONTROL_PAUSE 1
-#define PRINTER_CONTROL_RESUME 2
-#define PRINTER_CONTROL_PURGE 3
+ typedef struct _PRINTER_INFO_1A {
+ DWORD Flags;
+ LPSTR pDescription;
+ LPSTR pName;
+ LPSTR pComment;
+ } PRINTER_INFO_1A,*PPRINTER_INFO_1A,*LPPRINTER_INFO_1A;
+
+ typedef struct _PRINTER_INFO_1W {
+ DWORD Flags;
+ LPWSTR pDescription;
+ LPWSTR pName;
+ LPWSTR pComment;
+ } PRINTER_INFO_1W,*PPRINTER_INFO_1W,*LPPRINTER_INFO_1W;
+
+ __MINGW_TYPEDEF_AW(PRINTER_INFO_1)
+ __MINGW_TYPEDEF_AW(PPRINTER_INFO_1)
+ __MINGW_TYPEDEF_AW(LPPRINTER_INFO_1)
+
+ typedef struct _PRINTER_INFO_2A {
+ LPSTR pServerName;
+ LPSTR pPrinterName;
+ LPSTR pShareName;
+ LPSTR pPortName;
+ LPSTR pDriverName;
+ LPSTR pComment;
+ LPSTR pLocation;
+ LPDEVMODEA pDevMode;
+ LPSTR pSepFile;
+ LPSTR pPrintProcessor;
+ LPSTR pDatatype;
+ LPSTR pParameters;
+ PSECURITY_DESCRIPTOR pSecurityDescriptor;
+ DWORD Attributes;
+ DWORD Priority;
+ DWORD DefaultPriority;
+ DWORD StartTime;
+ DWORD UntilTime;
+ DWORD Status;
+ DWORD cJobs;
+ DWORD AveragePPM;
+ } PRINTER_INFO_2A,*PPRINTER_INFO_2A,*LPPRINTER_INFO_2A;
+
+ typedef struct _PRINTER_INFO_2W {
+ LPWSTR pServerName;
+ LPWSTR pPrinterName;
+ LPWSTR pShareName;
+ LPWSTR pPortName;
+ LPWSTR pDriverName;
+ LPWSTR pComment;
+ LPWSTR pLocation;
+ LPDEVMODEW pDevMode;
+ LPWSTR pSepFile;
+ LPWSTR pPrintProcessor;
+ LPWSTR pDatatype;
+ LPWSTR pParameters;
+ PSECURITY_DESCRIPTOR pSecurityDescriptor;
+ DWORD Attributes;
+ DWORD Priority;
+ DWORD DefaultPriority;
+ DWORD StartTime;
+ DWORD UntilTime;
+ DWORD Status;
+ DWORD cJobs;
+ DWORD AveragePPM;
+ } PRINTER_INFO_2W,*PPRINTER_INFO_2W,*LPPRINTER_INFO_2W;
+
+ __MINGW_TYPEDEF_AW(PRINTER_INFO_2)
+ __MINGW_TYPEDEF_AW(PPRINTER_INFO_2)
+ __MINGW_TYPEDEF_AW(LPPRINTER_INFO_2)
+
+ typedef struct _PRINTER_INFO_3 {
+ PSECURITY_DESCRIPTOR pSecurityDescriptor;
+ } PRINTER_INFO_3,*PPRINTER_INFO_3,*LPPRINTER_INFO_3;
+
+ typedef struct _PRINTER_INFO_4A {
+ LPSTR pPrinterName;
+ LPSTR pServerName;
+ DWORD Attributes;
+ } PRINTER_INFO_4A,*PPRINTER_INFO_4A,*LPPRINTER_INFO_4A;
+
+ typedef struct _PRINTER_INFO_4W {
+ LPWSTR pPrinterName;
+ LPWSTR pServerName;
+ DWORD Attributes;
+ } PRINTER_INFO_4W,*PPRINTER_INFO_4W,*LPPRINTER_INFO_4W;
+
+ __MINGW_TYPEDEF_AW(PRINTER_INFO_4)
+ __MINGW_TYPEDEF_AW(PPRINTER_INFO_4)
+ __MINGW_TYPEDEF_AW(LPPRINTER_INFO_4)
+
+ typedef struct _PRINTER_INFO_5A {
+ LPSTR pPrinterName;
+ LPSTR pPortName;
+ DWORD Attributes;
+ DWORD DeviceNotSelectedTimeout;
+ DWORD TransmissionRetryTimeout;
+ } PRINTER_INFO_5A,*PPRINTER_INFO_5A,*LPPRINTER_INFO_5A;
+
+ typedef struct _PRINTER_INFO_5W {
+ LPWSTR pPrinterName;
+ LPWSTR pPortName;
+ DWORD Attributes;
+ DWORD DeviceNotSelectedTimeout;
+ DWORD TransmissionRetryTimeout;
+ } PRINTER_INFO_5W,*PPRINTER_INFO_5W,*LPPRINTER_INFO_5W;
+
+ __MINGW_TYPEDEF_AW(PRINTER_INFO_5)
+ __MINGW_TYPEDEF_AW(PPRINTER_INFO_5)
+ __MINGW_TYPEDEF_AW(LPPRINTER_INFO_5)
+
+ typedef struct _PRINTER_INFO_6 {
+ DWORD dwStatus;
+ } PRINTER_INFO_6,*PPRINTER_INFO_6,*LPPRINTER_INFO_6;
+
+ typedef struct _PRINTER_INFO_7A {
+ LPSTR pszObjectGUID;
+ DWORD dwAction;
+ } PRINTER_INFO_7A,*PPRINTER_INFO_7A,*LPPRINTER_INFO_7A;
+
+ typedef struct _PRINTER_INFO_7W {
+ LPWSTR pszObjectGUID;
+ DWORD dwAction;
+ } PRINTER_INFO_7W,*PPRINTER_INFO_7W,*LPPRINTER_INFO_7W;
+
+ __MINGW_TYPEDEF_AW(PRINTER_INFO_7)
+ __MINGW_TYPEDEF_AW(PPRINTER_INFO_7)
+ __MINGW_TYPEDEF_AW(LPPRINTER_INFO_7)
+
+#define DSPRINT_PUBLISH 0x00000001
+#define DSPRINT_UPDATE 0x00000002
+#define DSPRINT_UNPUBLISH 0x00000004
+#define DSPRINT_REPUBLISH 0x00000008
+#define DSPRINT_PENDING 0x80000000
+
+ typedef struct _PRINTER_INFO_8A {
+ LPDEVMODEA pDevMode;
+ } PRINTER_INFO_8A,*PPRINTER_INFO_8A,*LPPRINTER_INFO_8A;
+
+ typedef struct _PRINTER_INFO_8W {
+ LPDEVMODEW pDevMode;
+ } PRINTER_INFO_8W,*PPRINTER_INFO_8W,*LPPRINTER_INFO_8W;
+
+ __MINGW_TYPEDEF_AW(PRINTER_INFO_8)
+ __MINGW_TYPEDEF_AW(PPRINTER_INFO_8)
+ __MINGW_TYPEDEF_AW(LPPRINTER_INFO_8)
+
+ typedef struct _PRINTER_INFO_9A {
+ LPDEVMODEA pDevMode;
+ } PRINTER_INFO_9A,*PPRINTER_INFO_9A,*LPPRINTER_INFO_9A;
+
+ typedef struct _PRINTER_INFO_9W {
+ LPDEVMODEW pDevMode;
+ } PRINTER_INFO_9W,*PPRINTER_INFO_9W,*LPPRINTER_INFO_9W;
+
+ __MINGW_TYPEDEF_AW(PRINTER_INFO_9)
+ __MINGW_TYPEDEF_AW(PPRINTER_INFO_9)
+ __MINGW_TYPEDEF_AW(LPPRINTER_INFO_9)
+
+#define PRINTER_CONTROL_PAUSE 1
+#define PRINTER_CONTROL_RESUME 2
+#define PRINTER_CONTROL_PURGE 3
#define PRINTER_CONTROL_SET_STATUS 4
-#define PRINTER_STATUS_PAUSED 1
-#define PRINTER_STATUS_ERROR 2
-#define PRINTER_STATUS_PENDING_DELETION 4
-#define PRINTER_STATUS_PAPER_JAM 8
-#define PRINTER_STATUS_PAPER_OUT 0x10
-#define PRINTER_STATUS_MANUAL_FEED 0x20
-#define PRINTER_STATUS_PAPER_PROBLEM 0x40
-#define PRINTER_STATUS_OFFLINE 0x80
-#define PRINTER_STATUS_IO_ACTIVE 0x100
-#define PRINTER_STATUS_BUSY 0x200
-#define PRINTER_STATUS_PRINTING 0x400
-#define PRINTER_STATUS_OUTPUT_BIN_FULL 0x800
-#define PRINTER_STATUS_NOT_AVAILABLE 0x1000
-#define PRINTER_STATUS_WAITING 0x2000
-#define PRINTER_STATUS_PROCESSING 0x4000
-#define PRINTER_STATUS_INITIALIZING 0x8000
-#define PRINTER_STATUS_WARMING_UP 0x10000
-#define PRINTER_STATUS_TONER_LOW 0x20000
-#define PRINTER_STATUS_NO_TONER 0x40000
-#define PRINTER_STATUS_PAGE_PUNT 0x80000
-#define PRINTER_STATUS_USER_INTERVENTION 0x100000
-#define PRINTER_STATUS_OUT_OF_MEMORY 0x200000
-#define PRINTER_STATUS_DOOR_OPEN 0x400000
-#define PRINTER_STATUS_SERVER_UNKNOWN 0x800000
-#define PRINTER_STATUS_POWER_SAVE 0x1000000
-
-#define PRINTER_ATTRIBUTE_QUEUED 1
-#define PRINTER_ATTRIBUTE_DIRECT 2
-#define PRINTER_ATTRIBUTE_DEFAULT 4
-#define PRINTER_ATTRIBUTE_SHARED 8
-#define PRINTER_ATTRIBUTE_NETWORK 0x10
-#define PRINTER_ATTRIBUTE_HIDDEN 0x20
-#define PRINTER_ATTRIBUTE_LOCAL 0x40
-#define PRINTER_ATTRIBUTE_ENABLE_DEVQ 0x80
-#define PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS 0x100
-#define PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST 0x200
-#define PRINTER_ATTRIBUTE_WORK_OFFLINE 0x400
-#define PRINTER_ATTRIBUTE_ENABLE_BIDI 0x800
-#define PRINTER_ATTRIBUTE_RAW_ONLY 0x1000
-#define PRINTER_ATTRIBUTE_PUBLISHED 0x2000
-
-#define PRINTER_ENUM_DEFAULT 1
-#define PRINTER_ENUM_LOCAL 2
-#define PRINTER_ENUM_CONNECTIONS 4
-#define PRINTER_ENUM_FAVORITE 4
-#define PRINTER_ENUM_NAME 8
-#define PRINTER_ENUM_REMOTE 16
-#define PRINTER_ENUM_SHARED 32
-#define PRINTER_ENUM_NETWORK 0x40
-#define PRINTER_ENUM_EXPAND 0x4000
-#define PRINTER_ENUM_CONTAINER 0x8000
-#define PRINTER_ENUM_ICONMASK 0xff0000
-#define PRINTER_ENUM_ICON1 0x10000
-#define PRINTER_ENUM_ICON2 0x20000
-#define PRINTER_ENUM_ICON3 0x40000
-#define PRINTER_ENUM_ICON4 0x80000
-#define PRINTER_ENUM_ICON5 0x100000
-#define PRINTER_ENUM_ICON6 0x200000
-#define PRINTER_ENUM_ICON7 0x400000
-#define PRINTER_ENUM_ICON8 0x800000
-
-#define PRINTER_NOTIFY_TYPE 0
-#define PRINTER_NOTIFY_FIELD_SERVER_NAME 0
-#define PRINTER_NOTIFY_FIELD_PRINTER_NAME 1
-#define PRINTER_NOTIFY_FIELD_SHARE_NAME 2
-#define PRINTER_NOTIFY_FIELD_PORT_NAME 3
-#define PRINTER_NOTIFY_FIELD_DRIVER_NAME 4
-#define PRINTER_NOTIFY_FIELD_COMMENT 5
-#define PRINTER_NOTIFY_FIELD_LOCATION 6
-#define PRINTER_NOTIFY_FIELD_DEVMODE 7
-#define PRINTER_NOTIFY_FIELD_SEPFILE 8
-#define PRINTER_NOTIFY_FIELD_PRINT_PROCESSOR 9
-#define PRINTER_NOTIFY_FIELD_PARAMETERS 10
-#define PRINTER_NOTIFY_FIELD_DATATYPE 11
-#define PRINTER_NOTIFY_FIELD_SECURITY_DESCRIPTOR 12
-#define PRINTER_NOTIFY_FIELD_ATTRIBUTES 13
-#define PRINTER_NOTIFY_FIELD_PRIORITY 14
-#define PRINTER_NOTIFY_FIELD_DEFAULT_PRIORITY 15
-#define PRINTER_NOTIFY_FIELD_START_TIME 16
-#define PRINTER_NOTIFY_FIELD_UNTIL_TIME 17
-#define PRINTER_NOTIFY_FIELD_STATUS 18
-#define PRINTER_NOTIFY_FIELD_STATUS_STRING 19
-#define PRINTER_NOTIFY_FIELD_CJOBS 20
-#define PRINTER_NOTIFY_FIELD_AVERAGE_PPM 21
-#define PRINTER_NOTIFY_FIELD_TOTAL_PAGES 22
-#define PRINTER_NOTIFY_FIELD_PAGES_PRINTED 23
-#define PRINTER_NOTIFY_FIELD_TOTAL_BYTES 24
-#define PRINTER_NOTIFY_FIELD_BYTES_PRINTED 25
-
-#define PRINTER_CHANGE_ADD_PRINTER 1
-#define PRINTER_CHANGE_SET_PRINTER 2
-#define PRINTER_CHANGE_DELETE_PRINTER 4
-#define PRINTER_CHANGE_FAILED_CONNECTION_PRINTER 8
-#define PRINTER_CHANGE_PRINTER 0xFF
-#define PRINTER_CHANGE_ADD_JOB 0x100
-#define PRINTER_CHANGE_SET_JOB 0x200
-#define PRINTER_CHANGE_DELETE_JOB 0x400
-#define PRINTER_CHANGE_WRITE_JOB 0x800
-#define PRINTER_CHANGE_JOB 0xFF00
-#define PRINTER_CHANGE_ADD_FORM 0x10000
-#define PRINTER_CHANGE_SET_FORM 0x20000
-#define PRINTER_CHANGE_DELETE_FORM 0x40000
-#define PRINTER_CHANGE_FORM 0x70000
-#define PRINTER_CHANGE_ADD_PORT 0x100000
-#define PRINTER_CHANGE_CONFIGURE_PORT 0x200000
-#define PRINTER_CHANGE_DELETE_PORT 0x400000
-#define PRINTER_CHANGE_PORT 0x700000
-#define PRINTER_CHANGE_ADD_PRINT_PROCESSOR 0x1000000
-#define PRINTER_CHANGE_DELETE_PRINT_PROCESSOR 0x4000000
-#define PRINTER_CHANGE_PRINT_PROCESSOR 0x7000000
-#define PRINTER_CHANGE_ADD_PRINTER_DRIVER 0x10000000
-#define PRINTER_CHANGE_SET_PRINTER_DRIVER 0x20000000
-#define PRINTER_CHANGE_DELETE_PRINTER_DRIVER 0x40000000
-#define PRINTER_CHANGE_PRINTER_DRIVER 0x70000000
-#define PRINTER_CHANGE_TIMEOUT 0x80000000
-#define PRINTER_CHANGE_ALL 0x7777FFFF
-
-#define PRINTER_NOTIFY_INFO_DISCARDED 1
-#define PRINTER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|PRINTER_ACCESS_ADMINISTER|PRINTER_ACCESS_USE)
-#define PRINTER_READ (STANDARD_RIGHTS_READ|PRINTER_ACCESS_USE)
-#define PRINTER_WRITE (STANDARD_RIGHTS_WRITE|PRINTER_ACCESS_USE)
-#define PRINTER_EXECUTE (STANDARD_RIGHTS_EXECUTE|PRINTER_ACCESS_USE)
-
-#define NO_PRIORITY 0
+#define PRINTER_STATUS_PAUSED 0x00000001
+#define PRINTER_STATUS_ERROR 0x00000002
+#define PRINTER_STATUS_PENDING_DELETION 0x00000004
+#define PRINTER_STATUS_PAPER_JAM 0x00000008
+#define PRINTER_STATUS_PAPER_OUT 0x00000010
+#define PRINTER_STATUS_MANUAL_FEED 0x00000020
+#define PRINTER_STATUS_PAPER_PROBLEM 0x00000040
+#define PRINTER_STATUS_OFFLINE 0x00000080
+#define PRINTER_STATUS_IO_ACTIVE 0x00000100
+#define PRINTER_STATUS_BUSY 0x00000200
+#define PRINTER_STATUS_PRINTING 0x00000400
+#define PRINTER_STATUS_OUTPUT_BIN_FULL 0x00000800
+#define PRINTER_STATUS_NOT_AVAILABLE 0x00001000
+#define PRINTER_STATUS_WAITING 0x00002000
+#define PRINTER_STATUS_PROCESSING 0x00004000
+#define PRINTER_STATUS_INITIALIZING 0x00008000
+#define PRINTER_STATUS_WARMING_UP 0x00010000
+#define PRINTER_STATUS_TONER_LOW 0x00020000
+#define PRINTER_STATUS_NO_TONER 0x00040000
+#define PRINTER_STATUS_PAGE_PUNT 0x00080000
+#define PRINTER_STATUS_USER_INTERVENTION 0x00100000
+#define PRINTER_STATUS_OUT_OF_MEMORY 0x00200000
+#define PRINTER_STATUS_DOOR_OPEN 0x00400000
+#define PRINTER_STATUS_SERVER_UNKNOWN 0x00800000
+#define PRINTER_STATUS_POWER_SAVE 0x01000000
+
+#define PRINTER_ATTRIBUTE_QUEUED 0x00000001
+#define PRINTER_ATTRIBUTE_DIRECT 0x00000002
+#define PRINTER_ATTRIBUTE_DEFAULT 0x00000004
+#define PRINTER_ATTRIBUTE_SHARED 0x00000008
+#define PRINTER_ATTRIBUTE_NETWORK 0x00000010
+#define PRINTER_ATTRIBUTE_HIDDEN 0x00000020
+#define PRINTER_ATTRIBUTE_LOCAL 0x00000040
+
+#define PRINTER_ATTRIBUTE_ENABLE_DEVQ 0x00000080
+#define PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS 0x00000100
+#define PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST 0x00000200
+
+#define PRINTER_ATTRIBUTE_WORK_OFFLINE 0x00000400
+#define PRINTER_ATTRIBUTE_ENABLE_BIDI 0x00000800
+#define PRINTER_ATTRIBUTE_RAW_ONLY 0x00001000
+#define PRINTER_ATTRIBUTE_PUBLISHED 0x00002000
+#define PRINTER_ATTRIBUTE_FAX 0x00004000
+#define PRINTER_ATTRIBUTE_TS 0x00008000
+
+#define NO_PRIORITY 0
#define MAX_PRIORITY 99
#define MIN_PRIORITY 1
#define DEF_PRIORITY 1
-#define PORT_TYPE_WRITE 1
-#define PORT_TYPE_READ 2
-#define PORT_TYPE_REDIRECTED 4
-#define PORT_TYPE_NET_ATTACHED 8
-
-#define SERVER_ACCESS_ADMINISTER 1
-#define SERVER_ACCESS_ENUMERATE 2
-#define SERVER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SERVER_ACCESS_ADMINISTER|SERVER_ACCESS_ENUMERATE)
-#define SERVER_READ (STANDARD_RIGHTS_READ|SERVER_ACCESS_ENUMERATE)
-#define SERVER_WRITE (STANDARD_RIGHTS_WRITE|SERVER_ACCESS_ADMINISTER|SERVER_ACCESS_ENUMERATE)
-#define SERVER_EXECUTE (STANDARD_RIGHTS_EXECUTE|SERVER_ACCESS_ENUMERATE)
-
-#define PORT_STATUS_TYPE_ERROR 1
-#define PORT_STATUS_TYPE_WARNING 2
-#define PORT_STATUS_TYPE_INFO 3
-#define PORT_STATUS_OFFLINE 1
-#define PORT_STATUS_PAPER_JAM 2
-#define PORT_STATUS_PAPER_OUT 3
-#define PORT_STATUS_OUTPUT_BIN_FULL 4
-#define PORT_STATUS_PAPER_PROBLEM 5
-#define PORT_STATUS_NO_TONER 6
-#define PORT_STATUS_DOOR_OPEN 7
-#define PORT_STATUS_USER_INTERVENTION 8
-#define PORT_STATUS_OUT_OF_MEMORY 9
-#define PORT_STATUS_TONER_LOW 10
-#define PORT_STATUS_WARMING_UP 11
-#define PORT_STATUS_POWER_SAVE 12
-
-typedef struct _PRINTER_NOTIFY_OPTIONS_TYPE {
- WORD Type;
- WORD Reserved0;
- DWORD Reserved1;
- DWORD Reserved2;
- DWORD Count;
- PWORD pFields;
-} PRINTER_NOTIFY_OPTIONS_TYPE, *PPRINTER_NOTIFY_OPTIONS_TYPE, *LPPRINTER_NOTIFY_OPTIONS_TYPE;
-
-typedef struct _PRINTER_NOTIFY_OPTIONS {
- DWORD Version;
- DWORD Flags;
- DWORD Count;
- PPRINTER_NOTIFY_OPTIONS_TYPE pTypes;
-} PRINTER_NOTIFY_OPTIONS, *PPRINTER_NOTIFY_OPTIONS, *LPPRINTER_NOTIFY_OPTIONS;
-
-#ifndef RC_INVOKED
-
-typedef struct _ADDJOB_INFO_1A {
- LPSTR Path;
- DWORD JobId;
-} ADDJOB_INFO_1A, *PADDJOB_INFO_1A, *LPADDJOB_INFO_1A;
-
-typedef struct _ADDJOB_INFO_1W {
- LPWSTR Path;
- DWORD JobId;
-} ADDJOB_INFO_1W, *PADDJOB_INFO_1W, *LPADDJOB_INFO_1W;
-
-typedef struct _DATATYPES_INFO_1A {
- LPSTR pName;
-} DATATYPES_INFO_1A, *PDATATYPES_INFO_1A, *LPDATATYPES_INFO_1A;
-
-typedef struct _DATATYPES_INFO_1W {
- LPWSTR pName;
-} DATATYPES_INFO_1W, *PDATATYPES_INFO_1W, *LPDATATYPES_INFO_1W;
-
-typedef struct _JOB_INFO_1A {
- DWORD JobId;
- LPSTR pPrinterName;
- LPSTR pMachineName;
- LPSTR pUserName;
- LPSTR pDocument;
- LPSTR pDatatype;
- LPSTR pStatus;
- DWORD Status;
- DWORD Priority;
- DWORD Position;
- DWORD TotalPages;
- DWORD PagesPrinted;
- SYSTEMTIME Submitted;
-} JOB_INFO_1A, *PJOB_INFO_1A, *LPJOB_INFO_1A;
-
-typedef struct _JOB_INFO_1W {
- DWORD JobId;
- LPWSTR pPrinterName;
- LPWSTR pMachineName;
- LPWSTR pUserName;
- LPWSTR pDocument;
- LPWSTR pDatatype;
- LPWSTR pStatus;
- DWORD Status;
- DWORD Priority;
- DWORD Position;
- DWORD TotalPages;
- DWORD PagesPrinted;
- SYSTEMTIME Submitted;
-} JOB_INFO_1W, *PJOB_INFO_1W, *LPJOB_INFO_1W;
-
-typedef struct _JOB_INFO_2A {
- DWORD JobId;
- LPSTR pPrinterName;
- LPSTR pMachineName;
- LPSTR pUserName;
- LPSTR pDocument;
- LPSTR pNotifyName;
- LPSTR pDatatype;
- LPSTR pPrintProcessor;
- LPSTR pParameters;
- LPSTR pDriverName;
- LPDEVMODEA pDevMode;
- LPSTR pStatus;
- PSECURITY_DESCRIPTOR pSecurityDescriptor;
- DWORD Status;
- DWORD Priority;
- DWORD Position;
- DWORD StartTime;
- DWORD UntilTime;
- DWORD TotalPages;
- DWORD Size;
- SYSTEMTIME Submitted;
- DWORD Time;
- DWORD PagesPrinted;
-} JOB_INFO_2A, *PJOB_INFO_2A, *LPJOB_INFO_2A;
-
-typedef struct _JOB_INFO_2W {
- DWORD JobId;
- LPWSTR pPrinterName;
- LPWSTR pMachineName;
- LPWSTR pUserName;
- LPWSTR pDocument;
- LPWSTR pNotifyName;
- LPWSTR pDatatype;
- LPWSTR pPrintProcessor;
- LPWSTR pParameters;
- LPWSTR pDriverName;
- LPDEVMODEW pDevMode;
- LPWSTR pStatus;
- PSECURITY_DESCRIPTOR pSecurityDescriptor;
- DWORD Status;
- DWORD Priority;
- DWORD Position;
- DWORD StartTime;
- DWORD UntilTime;
- DWORD TotalPages;
- DWORD Size;
- SYSTEMTIME Submitted;
- DWORD Time;
- DWORD PagesPrinted;
-} JOB_INFO_2W, *PJOB_INFO_2W, *LPJOB_INFO_2W;
-
-typedef struct _JOB_INFO_3 {
- DWORD JobId;
- DWORD NextJobId;
- DWORD Reserved;
-} JOB_INFO_3, *PJOB_INFO_3, *LPJOB_INFO_3;
-
-typedef struct _JOB_INFO_4A {
- DWORD JobId;
- LPSTR pPrinterName;
- LPSTR pMachineName;
- LPSTR pUserName;
- LPSTR pDocument;
- LPSTR pNotifyName;
- LPSTR pDatatype;
- LPSTR pPrintProcessor;
- LPSTR pParameters;
- LPSTR pDriverName;
- LPDEVMODEA pDevMode;
- LPSTR pStatus;
- PSECURITY_DESCRIPTOR pSecurityDescriptor;
- DWORD Status;
- DWORD Priority;
- DWORD Position;
- DWORD StartTime;
- DWORD UntilTime;
- DWORD TotalPages;
- DWORD Size;
- SYSTEMTIME Submitted;
- DWORD Time;
- DWORD PagesPrinted;
- LONG SizeHigh;
-} JOB_INFO_4A, *PJOB_INFO_4A, *LPJOB_INFO_4A;
-
-typedef struct _JOB_INFO_4W {
- DWORD JobId;
- LPWSTR pPrinterName;
- LPWSTR pMachineName;
- LPWSTR pUserName;
- LPWSTR pDocument;
- LPWSTR pNotifyName;
- LPWSTR pDatatype;
- LPWSTR pPrintProcessor;
- LPWSTR pParameters;
- LPWSTR pDriverName;
- LPDEVMODEW pDevMode;
- LPWSTR pStatus;
- PSECURITY_DESCRIPTOR pSecurityDescriptor;
- DWORD Status;
- DWORD Priority;
- DWORD Position;
- DWORD StartTime;
- DWORD UntilTime;
- DWORD TotalPages;
- DWORD Size;
- SYSTEMTIME Submitted;
- DWORD Time;
- DWORD PagesPrinted;
- LONG SizeHigh;
-} JOB_INFO_4W, *PJOB_INFO_4W, *LPJOB_INFO_4W;
-
-typedef struct _DOC_INFO_1A {
- LPSTR pDocName;
- LPSTR pOutputFile;
- LPSTR pDatatype;
-} DOC_INFO_1A, *PDOC_INFO_1A, *LPDOC_INFO_1A;
-
-typedef struct _DOC_INFO_1W {
- LPWSTR pDocName;
- LPWSTR pOutputFile;
- LPWSTR pDatatype;
-} DOC_INFO_1W, *PDOC_INFO_1W, *LPDOC_INFO_1W;
-
-typedef struct _DOC_INFO_2A {
- LPSTR pDocName;
- LPSTR pOutputFile;
- LPSTR pDatatype;
- DWORD dwMode;
- DWORD JobId;
-} DOC_INFO_2A, *PDOC_INFO_2A, *LPDOC_INFO_2A;
-
-typedef struct _DOC_INFO_2W {
- LPWSTR pDocName;
- LPWSTR pOutputFile;
- LPWSTR pDatatype;
- DWORD dwMode;
- DWORD JobId;
-} DOC_INFO_2W, *PDOC_INFO_2W, *LPDOC_INFO_2W;
-
-typedef struct _DRIVER_INFO_1A {
- LPSTR pName;
-} DRIVER_INFO_1A, *PDRIVER_INFO_1A, *LPDRIVER_INFO_1A;
-
-typedef struct _DRIVER_INFO_1W {
- LPWSTR pName;
-} DRIVER_INFO_1W, *PDRIVER_INFO_1W, *LPDRIVER_INFO_1W;
-
-typedef struct _DRIVER_INFO_2A {
- DWORD cVersion;
- LPSTR pName;
- LPSTR pEnvironment;
- LPSTR pDriverPath;
- LPSTR pDataFile;
- LPSTR pConfigFile;
-} DRIVER_INFO_2A, *PDRIVER_INFO_2A, *LPDRIVER_INFO_2A;
-
-typedef struct _DRIVER_INFO_2W {
- DWORD cVersion;
- LPWSTR pName;
- LPWSTR pEnvironment;
- LPWSTR pDriverPath;
- LPWSTR pDataFile;
- LPWSTR pConfigFile;
-} DRIVER_INFO_2W, *PDRIVER_INFO_2W, *LPDRIVER_INFO_2W;
-
-typedef struct _DRIVER_INFO_3A {
- DWORD cVersion;
- LPSTR pName;
- LPSTR pEnvironment;
- LPSTR pDriverPath;
- LPSTR pDataFile;
- LPSTR pConfigFile;
- LPSTR pHelpFile;
- LPSTR pDependentFiles;
- LPSTR pMonitorName;
- LPSTR pDefaultDataType;
-} DRIVER_INFO_3A, *PDRIVER_INFO_3A, *LPDRIVER_INFO_3A;
-
-typedef struct _DRIVER_INFO_3W {
- DWORD cVersion;
- LPWSTR pName;
- LPWSTR pEnvironment;
- LPWSTR pDriverPath;
- LPWSTR pDataFile;
- LPWSTR pConfigFile;
- LPWSTR pHelpFile;
- LPWSTR pDependentFiles;
- LPWSTR pMonitorName;
- LPWSTR pDefaultDataType;
-} DRIVER_INFO_3W, *PDRIVER_INFO_3W, *LPDRIVER_INFO_3W;
-
-typedef struct _DRIVER_INFO_4A {
- DWORD cVersion; // SDK examples:
- LPSTR pName; // QMS 810
- LPSTR pEnvironment; // Win32 x86
- LPSTR pDriverPath; // c:\drivers\pscript.dll
- LPSTR pDataFile; // c:\drivers\QMS810.PPD
- LPSTR pConfigFile; // c:\drivers\PSCRPTUI.DLL
- LPSTR pHelpFile; // c:\drivers\PSCRPTUI.HLP
- LPSTR pDependentFiles; // PSCRIPT.DLL\0QMS810.PPD\0PSCRIPTUI.DLL\0PSCRIPTUI.HLP\0PSTEST.TXT\0\0
- LPSTR pMonitorName; // "PJL monitor"
- LPSTR pDefaultDataType; // "EMF"
- LPSTR pszzPreviousNames; // "OldName1\0OldName2\0\0
-} DRIVER_INFO_4A, *PDRIVER_INFO_4A, *LPDRIVER_INFO_4A;
-
-typedef struct _DRIVER_INFO_4W {
- DWORD cVersion;
- LPWSTR pName;
- LPWSTR pEnvironment;
- LPWSTR pDriverPath;
- LPWSTR pDataFile;
- LPWSTR pConfigFile;
- LPWSTR pHelpFile;
- LPWSTR pDependentFiles;
- LPWSTR pMonitorName;
- LPWSTR pDefaultDataType;
- LPWSTR pszzPreviousNames;
-} DRIVER_INFO_4W, *PDRIVER_INFO_4W, *LPDRIVER_INFO_4W;
-
-typedef struct _DRIVER_INFO_5A {
- DWORD cVersion; // SDK examples:
- LPSTR pName; // QMS 810
- LPSTR pEnvironment; // Win32 x86
- LPSTR pDriverPath; // c:\drivers\pscript.dll
- LPSTR pDataFile; // c:\drivers\QMS810.PPD
- LPSTR pConfigFile; // c:\drivers\PSCRPTUI.DLL
- DWORD dwDriverAttributes; // driver attributes (like UMPD/KMPD)
- DWORD dwConfigVersion; // version number of the config file since reboot
- DWORD dwDriverVersion; // version number of the driver file since reboot
-} DRIVER_INFO_5A, *PDRIVER_INFO_5A, *LPDRIVER_INFO_5A;
-
-typedef struct _DRIVER_INFO_5W {
- DWORD cVersion;
- LPWSTR pName;
- LPWSTR pEnvironment;
- LPWSTR pDriverPath;
- LPWSTR pDataFile;
- LPWSTR pConfigFile;
- DWORD dwDriverAttributes;
- DWORD dwConfigVersion;
- DWORD dwDriverVersion;
-} DRIVER_INFO_5W, *PDRIVER_INFO_5W, *LPDRIVER_INFO_5W;
-
-typedef struct _DRIVER_INFO_6A {
- DWORD cVersion;
- LPSTR pName;
- LPSTR pEnvironment;
- LPSTR pDriverPath;
- LPSTR pDataFile;
- LPSTR pConfigFile;
- LPSTR pHelpFile;
- LPSTR pDependentFiles;
- LPSTR pMonitorName;
- LPSTR pDefaultDataType;
- LPSTR pszzPreviousNames;
- FILETIME ftDriverDate;
- DWORDLONG dwlDriverVersion;
- LPSTR pszMfgName;
- LPSTR pszOEMUrl;
- LPSTR pszHardwareID;
- LPSTR pszProvider;
-} DRIVER_INFO_6A, *PDRIVER_INFO_6A, *LPDRIVER_INFO_6A;
-
-typedef struct _DRIVER_INFO_6W {
- DWORD cVersion;
- LPWSTR pName;
- LPWSTR pEnvironment;
- LPWSTR pDriverPath;
- LPWSTR pDataFile;
- LPWSTR pConfigFile;
- LPWSTR pHelpFile;
- LPWSTR pDependentFiles;
- LPWSTR pMonitorName;
- LPWSTR pDefaultDataType;
- LPWSTR pszzPreviousNames;
- FILETIME ftDriverDate;
- DWORDLONG dwlDriverVersion;
- LPWSTR pszMfgName;
- LPWSTR pszOEMUrl;
- LPWSTR pszHardwareID;
- LPWSTR pszProvider;
-} DRIVER_INFO_6W, *PDRIVER_INFO_6W, *LPDRIVER_INFO_6W;
+ typedef struct _JOB_INFO_1A {
+ DWORD JobId;
+ LPSTR pPrinterName;
+ LPSTR pMachineName;
+ LPSTR pUserName;
+ LPSTR pDocument;
+ LPSTR pDatatype;
+ LPSTR pStatus;
+ DWORD Status;
+ DWORD Priority;
+ DWORD Position;
+ DWORD TotalPages;
+ DWORD PagesPrinted;
+ SYSTEMTIME Submitted;
+ } JOB_INFO_1A,*PJOB_INFO_1A,*LPJOB_INFO_1A;
+
+ typedef struct _JOB_INFO_1W {
+ DWORD JobId;
+ LPWSTR pPrinterName;
+ LPWSTR pMachineName;
+ LPWSTR pUserName;
+ LPWSTR pDocument;
+ LPWSTR pDatatype;
+ LPWSTR pStatus;
+ DWORD Status;
+ DWORD Priority;
+ DWORD Position;
+ DWORD TotalPages;
+ DWORD PagesPrinted;
+ SYSTEMTIME Submitted;
+ } JOB_INFO_1W,*PJOB_INFO_1W,*LPJOB_INFO_1W;
+
+ __MINGW_TYPEDEF_AW(JOB_INFO_1)
+ __MINGW_TYPEDEF_AW(PJOB_INFO_1)
+ __MINGW_TYPEDEF_AW(LPJOB_INFO_1)
+
+ typedef struct _JOB_INFO_2A {
+ DWORD JobId;
+ LPSTR pPrinterName;
+ LPSTR pMachineName;
+ LPSTR pUserName;
+ LPSTR pDocument;
+ LPSTR pNotifyName;
+ LPSTR pDatatype;
+ LPSTR pPrintProcessor;
+ LPSTR pParameters;
+ LPSTR pDriverName;
+ LPDEVMODEA pDevMode;
+ LPSTR pStatus;
+ PSECURITY_DESCRIPTOR pSecurityDescriptor;
+ DWORD Status;
+ DWORD Priority;
+ DWORD Position;
+ DWORD StartTime;
+ DWORD UntilTime;
+ DWORD TotalPages;
+ DWORD Size;
+ SYSTEMTIME Submitted;
+ DWORD Time;
+ DWORD PagesPrinted;
+ } JOB_INFO_2A,*PJOB_INFO_2A,*LPJOB_INFO_2A;
+
+ typedef struct _JOB_INFO_2W {
+ DWORD JobId;
+ LPWSTR pPrinterName;
+ LPWSTR pMachineName;
+ LPWSTR pUserName;
+ LPWSTR pDocument;
+ LPWSTR pNotifyName;
+ LPWSTR pDatatype;
+ LPWSTR pPrintProcessor;
+ LPWSTR pParameters;
+ LPWSTR pDriverName;
+ LPDEVMODEW pDevMode;
+ LPWSTR pStatus;
+ PSECURITY_DESCRIPTOR pSecurityDescriptor;
+ DWORD Status;
+ DWORD Priority;
+ DWORD Position;
+ DWORD StartTime;
+ DWORD UntilTime;
+ DWORD TotalPages;
+ DWORD Size;
+ SYSTEMTIME Submitted;
+ DWORD Time;
+ DWORD PagesPrinted;
+ } JOB_INFO_2W,*PJOB_INFO_2W,*LPJOB_INFO_2W;
+
+ __MINGW_TYPEDEF_AW(JOB_INFO_2)
+ __MINGW_TYPEDEF_AW(PJOB_INFO_2)
+ __MINGW_TYPEDEF_AW(LPJOB_INFO_2)
+
+ typedef struct _JOB_INFO_3 {
+ DWORD JobId;
+ DWORD NextJobId;
+ DWORD Reserved;
+ } JOB_INFO_3,*PJOB_INFO_3,*LPJOB_INFO_3;
+
+#define JOB_CONTROL_PAUSE 1
+#define JOB_CONTROL_RESUME 2
+#define JOB_CONTROL_CANCEL 3
+#define JOB_CONTROL_RESTART 4
+#define JOB_CONTROL_DELETE 5
+#define JOB_CONTROL_SENT_TO_PRINTER 6
+#define JOB_CONTROL_LAST_PAGE_EJECTED 7
+
+#define JOB_STATUS_PAUSED 0x00000001
+#define JOB_STATUS_ERROR 0x00000002
+#define JOB_STATUS_DELETING 0x00000004
+#define JOB_STATUS_SPOOLING 0x00000008
+#define JOB_STATUS_PRINTING 0x00000010
+#define JOB_STATUS_OFFLINE 0x00000020
+#define JOB_STATUS_PAPEROUT 0x00000040
+#define JOB_STATUS_PRINTED 0x00000080
+#define JOB_STATUS_DELETED 0x00000100
+#define JOB_STATUS_BLOCKED_DEVQ 0x00000200
+#define JOB_STATUS_USER_INTERVENTION 0x00000400
+#define JOB_STATUS_RESTART 0x00000800
+#define JOB_STATUS_COMPLETE 0x00001000
+
+#define JOB_POSITION_UNSPECIFIED 0
+
+ typedef struct _ADDJOB_INFO_1A {
+ LPSTR Path;
+ DWORD JobId;
+ } ADDJOB_INFO_1A,*PADDJOB_INFO_1A,*LPADDJOB_INFO_1A;
+
+ typedef struct _ADDJOB_INFO_1W {
+ LPWSTR Path;
+ DWORD JobId;
+ } ADDJOB_INFO_1W,*PADDJOB_INFO_1W,*LPADDJOB_INFO_1W;
+
+ __MINGW_TYPEDEF_AW(ADDJOB_INFO_1)
+ __MINGW_TYPEDEF_AW(PADDJOB_INFO_1)
+ __MINGW_TYPEDEF_AW(LPADDJOB_INFO_1)
+
+ typedef struct _DRIVER_INFO_1A {
+ LPSTR pName;
+ } DRIVER_INFO_1A,*PDRIVER_INFO_1A,*LPDRIVER_INFO_1A;
+
+ typedef struct _DRIVER_INFO_1W {
+ LPWSTR pName;
+ } DRIVER_INFO_1W,*PDRIVER_INFO_1W,*LPDRIVER_INFO_1W;
+
+ __MINGW_TYPEDEF_AW(DRIVER_INFO_1)
+ __MINGW_TYPEDEF_AW(PDRIVER_INFO_1)
+ __MINGW_TYPEDEF_AW(LPDRIVER_INFO_1)
+
+ typedef struct _DRIVER_INFO_2A {
+ DWORD cVersion;
+ LPSTR pName;
+ LPSTR pEnvironment;
+ LPSTR pDriverPath;
+ LPSTR pDataFile;
+ LPSTR pConfigFile;
+ } DRIVER_INFO_2A,*PDRIVER_INFO_2A,*LPDRIVER_INFO_2A;
+
+ typedef struct _DRIVER_INFO_2W {
+ DWORD cVersion;
+ LPWSTR pName;
+ LPWSTR pEnvironment;
+ LPWSTR pDriverPath;
+ LPWSTR pDataFile;
+ LPWSTR pConfigFile;
+ } DRIVER_INFO_2W,*PDRIVER_INFO_2W,*LPDRIVER_INFO_2W;
+
+ __MINGW_TYPEDEF_AW(DRIVER_INFO_2)
+ __MINGW_TYPEDEF_AW(PDRIVER_INFO_2)
+ __MINGW_TYPEDEF_AW(LPDRIVER_INFO_2)
+
+ typedef struct _DRIVER_INFO_3A {
+ DWORD cVersion;
+ LPSTR pName;
+ LPSTR pEnvironment;
+ LPSTR pDriverPath;
+ LPSTR pDataFile;
+ LPSTR pConfigFile;
+ LPSTR pHelpFile;
+ LPSTR pDependentFiles;
+ LPSTR pMonitorName;
+ LPSTR pDefaultDataType;
+ } DRIVER_INFO_3A,*PDRIVER_INFO_3A,*LPDRIVER_INFO_3A;
+
+ typedef struct _DRIVER_INFO_3W {
+ DWORD cVersion;
+ LPWSTR pName;
+ LPWSTR pEnvironment;
+ LPWSTR pDriverPath;
+ LPWSTR pDataFile;
+ LPWSTR pConfigFile;
+ LPWSTR pHelpFile;
+ LPWSTR pDependentFiles;
+ LPWSTR pMonitorName;
+ LPWSTR pDefaultDataType;
+ } DRIVER_INFO_3W,*PDRIVER_INFO_3W,*LPDRIVER_INFO_3W;
+
+ __MINGW_TYPEDEF_AW(DRIVER_INFO_3)
+ __MINGW_TYPEDEF_AW(PDRIVER_INFO_3)
+ __MINGW_TYPEDEF_AW(LPDRIVER_INFO_3)
+
+ typedef struct _DRIVER_INFO_4A {
+ DWORD cVersion;
+ LPSTR pName;
+ LPSTR pEnvironment;
+ LPSTR pDriverPath;
+ LPSTR pDataFile;
+ LPSTR pConfigFile;
+ LPSTR pHelpFile;
+ LPSTR pDependentFiles;
+ LPSTR pMonitorName;
+ LPSTR pDefaultDataType;
+ LPSTR pszzPreviousNames;
+ } DRIVER_INFO_4A,*PDRIVER_INFO_4A,*LPDRIVER_INFO_4A;
+
+ typedef struct _DRIVER_INFO_4W {
+ DWORD cVersion;
+ LPWSTR pName;
+ LPWSTR pEnvironment;
+ LPWSTR pDriverPath;
+ LPWSTR pDataFile;
+ LPWSTR pConfigFile;
+ LPWSTR pHelpFile;
+ LPWSTR pDependentFiles;
+ LPWSTR pMonitorName;
+ LPWSTR pDefaultDataType;
+ LPWSTR pszzPreviousNames;
+ } DRIVER_INFO_4W,*PDRIVER_INFO_4W,*LPDRIVER_INFO_4W;
+
+ __MINGW_TYPEDEF_AW(DRIVER_INFO_4)
+ __MINGW_TYPEDEF_AW(PDRIVER_INFO_4)
+ __MINGW_TYPEDEF_AW(LPDRIVER_INFO_4)
+
+ typedef struct _DRIVER_INFO_5A {
+ DWORD cVersion;
+ LPSTR pName;
+ LPSTR pEnvironment;
+ LPSTR pDriverPath;
+ LPSTR pDataFile;
+ LPSTR pConfigFile;
+ DWORD dwDriverAttributes;
+ DWORD dwConfigVersion;
+ DWORD dwDriverVersion;
+ } DRIVER_INFO_5A,*PDRIVER_INFO_5A,*LPDRIVER_INFO_5A;
+
+ typedef struct _DRIVER_INFO_5W {
+ DWORD cVersion;
+ LPWSTR pName;
+ LPWSTR pEnvironment;
+ LPWSTR pDriverPath;
+ LPWSTR pDataFile;
+ LPWSTR pConfigFile;
+ DWORD dwDriverAttributes;
+ DWORD dwConfigVersion;
+ DWORD dwDriverVersion;
+ } DRIVER_INFO_5W,*PDRIVER_INFO_5W,*LPDRIVER_INFO_5W;
+
+ __MINGW_TYPEDEF_AW(DRIVER_INFO_5)
+ __MINGW_TYPEDEF_AW(PDRIVER_INFO_5)
+ __MINGW_TYPEDEF_AW(LPDRIVER_INFO_5)
+
+ typedef struct _DRIVER_INFO_6A {
+ DWORD cVersion;
+ LPSTR pName;
+ LPSTR pEnvironment;
+ LPSTR pDriverPath;
+ LPSTR pDataFile;
+ LPSTR pConfigFile;
+ LPSTR pHelpFile;
+ LPSTR pDependentFiles;
+ LPSTR pMonitorName;
+ LPSTR pDefaultDataType;
+ LPSTR pszzPreviousNames;
+ FILETIME ftDriverDate;
+ DWORDLONG dwlDriverVersion;
+ LPSTR pszMfgName;
+ LPSTR pszOEMUrl;
+ LPSTR pszHardwareID;
+ LPSTR pszProvider;
+ } DRIVER_INFO_6A,*PDRIVER_INFO_6A,*LPDRIVER_INFO_6A;
+
+ typedef struct _DRIVER_INFO_6W {
+ DWORD cVersion;
+ LPWSTR pName;
+ LPWSTR pEnvironment;
+ LPWSTR pDriverPath;
+ LPWSTR pDataFile;
+ LPWSTR pConfigFile;
+ LPWSTR pHelpFile;
+ LPWSTR pDependentFiles;
+ LPWSTR pMonitorName;
+ LPWSTR pDefaultDataType;
+ LPWSTR pszzPreviousNames;
+ FILETIME ftDriverDate;
+ DWORDLONG dwlDriverVersion;
+ LPWSTR pszMfgName;
+ LPWSTR pszOEMUrl;
+ LPWSTR pszHardwareID;
+ LPWSTR pszProvider;
+ } DRIVER_INFO_6W,*PDRIVER_INFO_6W,*LPDRIVER_INFO_6W;
+
+ __MINGW_TYPEDEF_AW(DRIVER_INFO_6)
+ __MINGW_TYPEDEF_AW(PDRIVER_INFO_6)
+ __MINGW_TYPEDEF_AW(LPDRIVER_INFO_6)
-#define PRINTER_DRIVER_PACKAGE_AWARE 0x00000001
+#define DRIVER_KERNELMODE 0x00000001
+#define DRIVER_USERMODE 0x00000002
-typedef struct _DRIVER_INFO_8A {
- DWORD cVersion;
- LPSTR pName;
- LPSTR pEnvironment;
- LPSTR pDriverPath;
- LPSTR pDataFile;
- LPSTR pConfigFile;
- LPSTR pHelpFile;
- LPSTR pDependentFiles;
- LPSTR pMonitorName;
- LPSTR pDefaultDataType;
- LPSTR pszzPreviousNames;
- FILETIME ftDriverDate;
- DWORDLONG dwlDriverVersion;
- LPSTR pszMfgName;
- LPSTR pszOEMUrl;
- LPSTR pszHardwareID;
- LPSTR pszProvider;
- LPSTR pszPrintProcessor;
- LPSTR pszVendorSetup;
- LPSTR pszzColorProfiles;
- LPSTR pszInfPath;
- DWORD dwPrinterDriverAttributes;
- LPSTR pszzCoreDriverDependencies;
- FILETIME ftMinInboxDriverVerDate;
- DWORDLONG dwlMinInboxDriverVerVersion;
-} DRIVER_INFO_8A, *PDRIVER_INFO_8A, *LPDRIVER_INFO_8A;
+#define DPD_DELETE_UNUSED_FILES 0x00000001
+#define DPD_DELETE_SPECIFIC_VERSION 0x00000002
+#define DPD_DELETE_ALL_FILES 0x00000004
+
+#define APD_STRICT_UPGRADE 0x00000001
+#define APD_STRICT_DOWNGRADE 0x00000002
+#define APD_COPY_ALL_FILES 0x00000004
+#define APD_COPY_NEW_FILES 0x00000008
+#define APD_COPY_FROM_DIRECTORY 0x00000010
+
+ typedef struct _DOC_INFO_1A {
+ LPSTR pDocName;
+ LPSTR pOutputFile;
+ LPSTR pDatatype;
+ } DOC_INFO_1A,*PDOC_INFO_1A,*LPDOC_INFO_1A;
+
+ typedef struct _DOC_INFO_1W {
+ LPWSTR pDocName;
+ LPWSTR pOutputFile;
+ LPWSTR pDatatype;
+ } DOC_INFO_1W,*PDOC_INFO_1W,*LPDOC_INFO_1W;
+
+ __MINGW_TYPEDEF_AW(DOC_INFO_1)
+ __MINGW_TYPEDEF_AW(PDOC_INFO_1)
+ __MINGW_TYPEDEF_AW(LPDOC_INFO_1)
+
+ typedef struct _FORM_INFO_1A {
+ DWORD Flags;
+ LPSTR pName;
+ SIZEL Size;
+ RECTL ImageableArea;
+ } FORM_INFO_1A,*PFORM_INFO_1A,*LPFORM_INFO_1A;
+
+ typedef struct _FORM_INFO_1W {
+ DWORD Flags;
+ LPWSTR pName;
+ SIZEL Size;
+ RECTL ImageableArea;
+ } FORM_INFO_1W,*PFORM_INFO_1W,*LPFORM_INFO_1W;
+
+ __MINGW_TYPEDEF_AW(FORM_INFO_1)
+ __MINGW_TYPEDEF_AW(PFORM_INFO_1)
+ __MINGW_TYPEDEF_AW(LPFORM_INFO_1)
+
+ typedef struct _DOC_INFO_2A {
+ LPSTR pDocName;
+ LPSTR pOutputFile;
+ LPSTR pDatatype;
+ DWORD dwMode;
+ DWORD JobId;
+ } DOC_INFO_2A,*PDOC_INFO_2A,*LPDOC_INFO_2A;
+
+ typedef struct _DOC_INFO_2W {
+ LPWSTR pDocName;
+ LPWSTR pOutputFile;
+ LPWSTR pDatatype;
+ DWORD dwMode;
+ DWORD JobId;
+ } DOC_INFO_2W,*PDOC_INFO_2W,*LPDOC_INFO_2W;
+
+ __MINGW_TYPEDEF_AW(DOC_INFO_2)
+ __MINGW_TYPEDEF_AW(PDOC_INFO_2)
+ __MINGW_TYPEDEF_AW(LPDOC_INFO_2)
+
+#define DI_CHANNEL 1
+#define DI_READ_SPOOL_JOB 3
+
+ typedef struct _DOC_INFO_3A {
+ LPSTR pDocName;
+ LPSTR pOutputFile;
+ LPSTR pDatatype;
+ DWORD dwFlags;
+ } DOC_INFO_3A,*PDOC_INFO_3A,*LPDOC_INFO_3A;
+
+ typedef struct _DOC_INFO_3W {
+ LPWSTR pDocName;
+ LPWSTR pOutputFile;
+ LPWSTR pDatatype;
+ DWORD dwFlags;
+ } DOC_INFO_3W,*PDOC_INFO_3W,*LPDOC_INFO_3W;
+
+ __MINGW_TYPEDEF_AW(DOC_INFO_3)
+ __MINGW_TYPEDEF_AW(PDOC_INFO_3)
+ __MINGW_TYPEDEF_AW(LPDOC_INFO_3)
+
+#define DI_MEMORYMAP_WRITE 0x00000001
+
+#define FORM_USER 0x00000000
+#define FORM_BUILTIN 0x00000001
+#define FORM_PRINTER 0x00000002
+
+ typedef struct _PRINTPROCESSOR_INFO_1A {
+ LPSTR pName;
+ } PRINTPROCESSOR_INFO_1A,*PPRINTPROCESSOR_INFO_1A,*LPPRINTPROCESSOR_INFO_1A;
+
+ typedef struct _PRINTPROCESSOR_INFO_1W {
+ LPWSTR pName;
+ } PRINTPROCESSOR_INFO_1W,*PPRINTPROCESSOR_INFO_1W,*LPPRINTPROCESSOR_INFO_1W;
+
+ __MINGW_TYPEDEF_AW(PRINTPROCESSOR_INFO_1)
+ __MINGW_TYPEDEF_AW(PPRINTPROCESSOR_INFO_1)
+ __MINGW_TYPEDEF_AW(LPPRINTPROCESSOR_INFO_1)
+
+ typedef struct _PRINTPROCESSOR_CAPS_1 {
+ DWORD dwLevel;
+ DWORD dwNupOptions;
+ DWORD dwPageOrderFlags;
+ DWORD dwNumberOfCopies;
+ } PRINTPROCESSOR_CAPS_1,*PPRINTPROCESSOR_CAPS_1;
+
+#define NORMAL_PRINT 0x00000000
+#define REVERSE_PRINT 0x00000001
+
+ typedef struct _PORT_INFO_1A {
+ LPSTR pName;
+ } PORT_INFO_1A,*PPORT_INFO_1A,*LPPORT_INFO_1A;
+ typedef struct _PORT_INFO_1W {
+ LPWSTR pName;
+ } PORT_INFO_1W,*PPORT_INFO_1W,*LPPORT_INFO_1W;
+
+ __MINGW_TYPEDEF_AW(PORT_INFO_1)
+ __MINGW_TYPEDEF_AW(PPORT_INFO_1)
+ __MINGW_TYPEDEF_AW(LPPORT_INFO_1)
+
+ typedef struct _PORT_INFO_2A {
+ LPSTR pPortName;
+ LPSTR pMonitorName;
+ LPSTR pDescription;
+ DWORD fPortType;
+ DWORD Reserved;
+ } PORT_INFO_2A,*PPORT_INFO_2A,*LPPORT_INFO_2A;
+
+ typedef struct _PORT_INFO_2W {
+ LPWSTR pPortName;
+ LPWSTR pMonitorName;
+ LPWSTR pDescription;
+ DWORD fPortType;
+ DWORD Reserved;
+ } PORT_INFO_2W,*PPORT_INFO_2W,*LPPORT_INFO_2W;
+
+ __MINGW_TYPEDEF_AW(PORT_INFO_2)
+ __MINGW_TYPEDEF_AW(PPORT_INFO_2)
+ __MINGW_TYPEDEF_AW(LPPORT_INFO_2)
+
+#define PORT_TYPE_WRITE 0x0001
+#define PORT_TYPE_READ 0x0002
+#define PORT_TYPE_REDIRECTED 0x0004
+#define PORT_TYPE_NET_ATTACHED 0x0008
+
+ typedef struct _PORT_INFO_3A {
+ DWORD dwStatus;
+ LPSTR pszStatus;
+ DWORD dwSeverity;
+ } PORT_INFO_3A,*PPORT_INFO_3A,*LPPORT_INFO_3A;
+
+ typedef struct _PORT_INFO_3W {
+ DWORD dwStatus;
+ LPWSTR pszStatus;
+ DWORD dwSeverity;
+ } PORT_INFO_3W,*PPORT_INFO_3W,*LPPORT_INFO_3W;
+
+ __MINGW_TYPEDEF_AW(PORT_INFO_3)
+ __MINGW_TYPEDEF_AW(PPORT_INFO_3)
+ __MINGW_TYPEDEF_AW(LPPORT_INFO_3)
+
+#define PORT_STATUS_TYPE_ERROR 1
+#define PORT_STATUS_TYPE_WARNING 2
+#define PORT_STATUS_TYPE_INFO 3
+
+#define PORT_STATUS_OFFLINE 1
+#define PORT_STATUS_PAPER_JAM 2
+#define PORT_STATUS_PAPER_OUT 3
+#define PORT_STATUS_OUTPUT_BIN_FULL 4
+#define PORT_STATUS_PAPER_PROBLEM 5
+#define PORT_STATUS_NO_TONER 6
+#define PORT_STATUS_DOOR_OPEN 7
+#define PORT_STATUS_USER_INTERVENTION 8
+#define PORT_STATUS_OUT_OF_MEMORY 9
+#define PORT_STATUS_TONER_LOW 10
+#define PORT_STATUS_WARMING_UP 11
+#define PORT_STATUS_POWER_SAVE 12
+
+ typedef struct _MONITOR_INFO_1A{
+ LPSTR pName;
+ } MONITOR_INFO_1A,*PMONITOR_INFO_1A,*LPMONITOR_INFO_1A;
+
+ typedef struct _MONITOR_INFO_1W{
+ LPWSTR pName;
+ } MONITOR_INFO_1W,*PMONITOR_INFO_1W,*LPMONITOR_INFO_1W;
+
+ __MINGW_TYPEDEF_AW(MONITOR_INFO_1)
+ __MINGW_TYPEDEF_AW(PMONITOR_INFO_1)
+ __MINGW_TYPEDEF_AW(LPMONITOR_INFO_1)
+
+ typedef struct _MONITOR_INFO_2A {
+ LPSTR pName;
+ LPSTR pEnvironment;
+ LPSTR pDLLName;
+ } MONITOR_INFO_2A,*PMONITOR_INFO_2A,*LPMONITOR_INFO_2A;
+
+ typedef struct _MONITOR_INFO_2W {
+ LPWSTR pName;
+ LPWSTR pEnvironment;
+ LPWSTR pDLLName;
+ } MONITOR_INFO_2W,*PMONITOR_INFO_2W,*LPMONITOR_INFO_2W;
+
+ __MINGW_TYPEDEF_AW(MONITOR_INFO_2)
+ __MINGW_TYPEDEF_AW(PMONITOR_INFO_2)
+ __MINGW_TYPEDEF_AW(LPMONITOR_INFO_2)
+
+ typedef struct _DATATYPES_INFO_1A {
+ LPSTR pName;
+ } DATATYPES_INFO_1A,*PDATATYPES_INFO_1A,*LPDATATYPES_INFO_1A;
+
+ typedef struct _DATATYPES_INFO_1W {
+ LPWSTR pName;
+ } DATATYPES_INFO_1W,*PDATATYPES_INFO_1W,*LPDATATYPES_INFO_1W;
+
+ __MINGW_TYPEDEF_AW(DATATYPES_INFO_1)
+ __MINGW_TYPEDEF_AW(PDATATYPES_INFO_1)
+ __MINGW_TYPEDEF_AW(LPDATATYPES_INFO_1)
+
+ typedef struct _PRINTER_DEFAULTSA {
+ LPSTR pDatatype;
+ LPDEVMODEA pDevMode;
+ ACCESS_MASK DesiredAccess;
+ } PRINTER_DEFAULTSA,*PPRINTER_DEFAULTSA,*LPPRINTER_DEFAULTSA;
+
+ typedef struct _PRINTER_DEFAULTSW {
+ LPWSTR pDatatype;
+ LPDEVMODEW pDevMode;
+ ACCESS_MASK DesiredAccess;
+ } PRINTER_DEFAULTSW,*PPRINTER_DEFAULTSW,*LPPRINTER_DEFAULTSW;
+
+ __MINGW_TYPEDEF_AW(PRINTER_DEFAULTS)
+ __MINGW_TYPEDEF_AW(PPRINTER_DEFAULTS)
+ __MINGW_TYPEDEF_AW(LPPRINTER_DEFAULTS)
+
+ typedef struct _PRINTER_ENUM_VALUESA {
+ LPSTR pValueName;
+ DWORD cbValueName;
+ DWORD dwType;
+ LPBYTE pData;
+ DWORD cbData;
+ } PRINTER_ENUM_VALUESA,*PPRINTER_ENUM_VALUESA,*LPPRINTER_ENUM_VALUESA;
+
+ typedef struct _PRINTER_ENUM_VALUESW {
+ LPWSTR pValueName;
+ DWORD cbValueName;
+ DWORD dwType;
+ LPBYTE pData;
+ DWORD cbData;
+ } PRINTER_ENUM_VALUESW,*PPRINTER_ENUM_VALUESW,*LPPRINTER_ENUM_VALUESW;
+
+ __MINGW_TYPEDEF_AW(PRINTER_ENUM_VALUES)
+ __MINGW_TYPEDEF_AW(PPRINTER_ENUM_VALUES)
+ __MINGW_TYPEDEF_AW(LPPRINTER_ENUM_VALUES)
+
+#define EnumPrinters __MINGW_NAME_AW(EnumPrinters)
+
+ WINBOOL WINAPI EnumPrintersA(DWORD Flags,LPSTR Name,DWORD Level,LPBYTE pPrinterEnum,DWORD cbBuf,LPDWORD pcbNeeded,LPDWORD pcReturned);
+ WINBOOL WINAPI EnumPrintersW(DWORD Flags,LPWSTR Name,DWORD Level,LPBYTE pPrinterEnum,DWORD cbBuf,LPDWORD pcbNeeded,LPDWORD pcReturned);
+
+#define PRINTER_ENUM_DEFAULT 0x00000001
+#define PRINTER_ENUM_LOCAL 0x00000002
+#define PRINTER_ENUM_CONNECTIONS 0x00000004
+#define PRINTER_ENUM_FAVORITE 0x00000004
+#define PRINTER_ENUM_NAME 0x00000008
+#define PRINTER_ENUM_REMOTE 0x00000010
+#define PRINTER_ENUM_SHARED 0x00000020
+#define PRINTER_ENUM_NETWORK 0x00000040
+
+#define PRINTER_ENUM_EXPAND 0x00004000
+#define PRINTER_ENUM_CONTAINER 0x00008000
+
+#define PRINTER_ENUM_ICONMASK 0x00ff0000
+#define PRINTER_ENUM_ICON1 0x00010000
+#define PRINTER_ENUM_ICON2 0x00020000
+#define PRINTER_ENUM_ICON3 0x00040000
+#define PRINTER_ENUM_ICON4 0x00080000
+#define PRINTER_ENUM_ICON5 0x00100000
+#define PRINTER_ENUM_ICON6 0x00200000
+#define PRINTER_ENUM_ICON7 0x00400000
+#define PRINTER_ENUM_ICON8 0x00800000
+#define PRINTER_ENUM_HIDE 0x01000000
+
+#define SPOOL_FILE_PERSISTENT 0x00000001
+#define SPOOL_FILE_TEMPORARY 0x00000002
+
+#define OpenPrinter __MINGW_NAME_AW(OpenPrinter)
+#define ResetPrinter __MINGW_NAME_AW(ResetPrinter)
+#define SetJob __MINGW_NAME_AW(SetJob)
+#define GetJob __MINGW_NAME_AW(GetJob)
+#define EnumJobs __MINGW_NAME_AW(EnumJobs)
+#define AddPrinter __MINGW_NAME_AW(AddPrinter)
+#define SetPrinter __MINGW_NAME_AW(SetPrinter)
+#define GetPrinter __MINGW_NAME_AW(GetPrinter)
+#define AddPrinterDriver __MINGW_NAME_AW(AddPrinterDriver)
+#define AddPrinterDriverEx __MINGW_NAME_AW(AddPrinterDriverEx)
+#define EnumPrinterDrivers __MINGW_NAME_AW(EnumPrinterDrivers)
+#define GetPrinterDriver __MINGW_NAME_AW(GetPrinterDriver)
+#define GetPrinterDriverDirectory __MINGW_NAME_AW(GetPrinterDriverDirectory)
+#define DeletePrinterDriver __MINGW_NAME_AW(DeletePrinterDriver)
+#define DeletePrinterDriverEx __MINGW_NAME_AW(DeletePrinterDriverEx)
+#define AddPrintProcessor __MINGW_NAME_AW(AddPrintProcessor)
+#define EnumPrintProcessors __MINGW_NAME_AW(EnumPrintProcessors)
+#define GetPrintProcessorDirectory __MINGW_NAME_AW(GetPrintProcessorDirectory)
+#define EnumPrintProcessorDatatypes __MINGW_NAME_AW(EnumPrintProcessorDatatypes)
+#define DeletePrintProcessor __MINGW_NAME_AW(DeletePrintProcessor)
+#define StartDocPrinter __MINGW_NAME_AW(StartDocPrinter)
+#define AddJob __MINGW_NAME_AW(AddJob)
+#define DocumentProperties __MINGW_NAME_AW(DocumentProperties)
+#define AdvancedDocumentProperties __MINGW_NAME_AW(AdvancedDocumentProperties)
+#define GetPrinterData __MINGW_NAME_AW(GetPrinterData)
+#define GetPrinterDataEx __MINGW_NAME_AW(GetPrinterDataEx)
+#define EnumPrinterData __MINGW_NAME_AW(EnumPrinterData)
+#define EnumPrinterDataEx __MINGW_NAME_AW(EnumPrinterDataEx)
+#define EnumPrinterKey __MINGW_NAME_AW(EnumPrinterKey)
+#define SetPrinterData __MINGW_NAME_AW(SetPrinterData)
+#define SetPrinterDataEx __MINGW_NAME_AW(SetPrinterDataEx)
+#define DeletePrinterData __MINGW_NAME_AW(DeletePrinterData)
+#define DeletePrinterDataEx __MINGW_NAME_AW(DeletePrinterDataEx)
+#define DeletePrinterKey __MINGW_NAME_AW(DeletePrinterKey)
+
+ WINBOOL WINAPI OpenPrinterA(LPSTR pPrinterName,LPHANDLE phPrinter,LPPRINTER_DEFAULTSA pDefault);
+ WINBOOL WINAPI OpenPrinterW(LPWSTR pPrinterName,LPHANDLE phPrinter,LPPRINTER_DEFAULTSW pDefault);
+ WINBOOL WINAPI ResetPrinterA(HANDLE hPrinter,LPPRINTER_DEFAULTSA pDefault);
+ WINBOOL WINAPI ResetPrinterW(HANDLE hPrinter,LPPRINTER_DEFAULTSW pDefault);
+ WINBOOL WINAPI SetJobA(HANDLE hPrinter,DWORD JobId,DWORD Level,LPBYTE pJob,DWORD Command);
+ WINBOOL WINAPI SetJobW(HANDLE hPrinter,DWORD JobId,DWORD Level,LPBYTE pJob,DWORD Command);
+ WINBOOL WINAPI GetJobA(HANDLE hPrinter,DWORD JobId,DWORD Level,LPBYTE pJob,DWORD cbBuf,LPDWORD pcbNeeded);
+ WINBOOL WINAPI GetJobW(HANDLE hPrinter,DWORD JobId,DWORD Level,LPBYTE pJob,DWORD cbBuf,LPDWORD pcbNeeded);
+ WINBOOL WINAPI EnumJobsA(HANDLE hPrinter,DWORD FirstJob,DWORD NoJobs,DWORD Level,LPBYTE pJob,DWORD cbBuf,LPDWORD pcbNeeded,LPDWORD pcReturned);
+ WINBOOL WINAPI EnumJobsW(HANDLE hPrinter,DWORD FirstJob,DWORD NoJobs,DWORD Level,LPBYTE pJob,DWORD cbBuf,LPDWORD pcbNeeded,LPDWORD pcReturned);
+ HANDLE WINAPI AddPrinterA(LPSTR pName,DWORD Level,LPBYTE pPrinter);
+ HANDLE WINAPI AddPrinterW(LPWSTR pName,DWORD Level,LPBYTE pPrinter);
+ WINBOOL WINAPI DeletePrinter(HANDLE hPrinter);
+ WINBOOL WINAPI SetPrinterA(HANDLE hPrinter,DWORD Level,LPBYTE pPrinter,DWORD Command);
+ WINBOOL WINAPI SetPrinterW(HANDLE hPrinter,DWORD Level,LPBYTE pPrinter,DWORD Command);
+ WINBOOL WINAPI GetPrinterA(HANDLE hPrinter,DWORD Level,LPBYTE pPrinter,DWORD cbBuf,LPDWORD pcbNeeded);
+ WINBOOL WINAPI GetPrinterW(HANDLE hPrinter,DWORD Level,LPBYTE pPrinter,DWORD cbBuf,LPDWORD pcbNeeded);
+ WINBOOL WINAPI AddPrinterDriverA(LPSTR pName,DWORD Level,LPBYTE pDriverInfo);
+ WINBOOL WINAPI AddPrinterDriverW(LPWSTR pName,DWORD Level,LPBYTE pDriverInfo);
+ WINBOOL WINAPI AddPrinterDriverExA(LPSTR pName,DWORD Level,LPBYTE pDriverInfo,DWORD dwFileCopyFlags);
+ WINBOOL WINAPI AddPrinterDriverExW(LPWSTR pName,DWORD Level,LPBYTE pDriverInfo,DWORD dwFileCopyFlags);
+ WINBOOL WINAPI EnumPrinterDriversA(LPSTR pName,LPSTR pEnvironment,DWORD Level,LPBYTE pDriverInfo,DWORD cbBuf,LPDWORD pcbNeeded,LPDWORD pcReturned);
+ WINBOOL WINAPI EnumPrinterDriversW(LPWSTR pName,LPWSTR pEnvironment,DWORD Level,LPBYTE pDriverInfo,DWORD cbBuf,LPDWORD pcbNeeded,LPDWORD pcReturned);
+ WINBOOL WINAPI GetPrinterDriverA(HANDLE hPrinter,LPSTR pEnvironment,DWORD Level,LPBYTE pDriverInfo,DWORD cbBuf,LPDWORD pcbNeeded);
+ WINBOOL WINAPI GetPrinterDriverW(HANDLE hPrinter,LPWSTR pEnvironment,DWORD Level,LPBYTE pDriverInfo,DWORD cbBuf,LPDWORD pcbNeeded);
+ WINBOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName,LPSTR pEnvironment,DWORD Level,LPBYTE pDriverDirectory,DWORD cbBuf,LPDWORD pcbNeeded);
+ WINBOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName,LPWSTR pEnvironment,DWORD Level,LPBYTE pDriverDirectory,DWORD cbBuf,LPDWORD pcbNeeded);
+ WINBOOL WINAPI DeletePrinterDriverA(LPSTR pName,LPSTR pEnvironment,LPSTR pDriverName);
+ WINBOOL WINAPI DeletePrinterDriverW(LPWSTR pName,LPWSTR pEnvironment,LPWSTR pDriverName);
+ WINBOOL WINAPI DeletePrinterDriverExA(LPSTR pName,LPSTR pEnvironment,LPSTR pDriverName,DWORD dwDeleteFlag,DWORD dwVersionFlag);
+ WINBOOL WINAPI DeletePrinterDriverExW(LPWSTR pName,LPWSTR pEnvironment,LPWSTR pDriverName,DWORD dwDeleteFlag,DWORD dwVersionFlag);
+ WINBOOL WINAPI AddPrintProcessorA(LPSTR pName,LPSTR pEnvironment,LPSTR pPathName,LPSTR pPrintProcessorName);
+ WINBOOL WINAPI AddPrintProcessorW(LPWSTR pName,LPWSTR pEnvironment,LPWSTR pPathName,LPWSTR pPrintProcessorName);
+ WINBOOL WINAPI EnumPrintProcessorsA(LPSTR pName,LPSTR pEnvironment,DWORD Level,LPBYTE pPrintProcessorInfo,DWORD cbBuf,LPDWORD pcbNeeded,LPDWORD pcReturned);
+ WINBOOL WINAPI EnumPrintProcessorsW(LPWSTR pName,LPWSTR pEnvironment,DWORD Level,LPBYTE pPrintProcessorInfo,DWORD cbBuf,LPDWORD pcbNeeded,LPDWORD pcReturned);
+ WINBOOL WINAPI GetPrintProcessorDirectoryA(LPSTR pName,LPSTR pEnvironment,DWORD Level,LPBYTE pPrintProcessorInfo,DWORD cbBuf,LPDWORD pcbNeeded);
+ WINBOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR pName,LPWSTR pEnvironment,DWORD Level,LPBYTE pPrintProcessorInfo,DWORD cbBuf,LPDWORD pcbNeeded);
+ WINBOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName,LPSTR pPrintProcessorName,DWORD Level,LPBYTE pDatatypes,DWORD cbBuf,LPDWORD pcbNeeded,LPDWORD pcReturned);
+ WINBOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName,LPWSTR pPrintProcessorName,DWORD Level,LPBYTE pDatatypes,DWORD cbBuf,LPDWORD pcbNeeded,LPDWORD pcReturned);
+ WINBOOL WINAPI DeletePrintProcessorA(LPSTR pName,LPSTR pEnvironment,LPSTR pPrintProcessorName);
+ WINBOOL WINAPI DeletePrintProcessorW(LPWSTR pName,LPWSTR pEnvironment,LPWSTR pPrintProcessorName);
+ DWORD WINAPI StartDocPrinterA(HANDLE hPrinter,DWORD Level,LPBYTE pDocInfo);
+ DWORD WINAPI StartDocPrinterW(HANDLE hPrinter,DWORD Level,LPBYTE pDocInfo);
+ WINBOOL WINAPI StartPagePrinter(HANDLE hPrinter);
+ WINBOOL WINAPI WritePrinter(HANDLE hPrinter,LPVOID pBuf,DWORD cbBuf,LPDWORD pcWritten);
+ WINBOOL WINAPI FlushPrinter(HANDLE hPrinter,LPVOID pBuf,DWORD cbBuf,LPDWORD pcWritten,DWORD cSleep);
+ WINBOOL WINAPI EndPagePrinter(HANDLE hPrinter);
+ WINBOOL WINAPI AbortPrinter(HANDLE hPrinter);
+ WINBOOL WINAPI ReadPrinter(HANDLE hPrinter,LPVOID pBuf,DWORD cbBuf,LPDWORD pNoBytesRead);
+ WINBOOL WINAPI EndDocPrinter(HANDLE hPrinter);
+ WINBOOL WINAPI AddJobA(HANDLE hPrinter,DWORD Level,LPBYTE pData,DWORD cbBuf,LPDWORD pcbNeeded);
+ WINBOOL WINAPI AddJobW(HANDLE hPrinter,DWORD Level,LPBYTE pData,DWORD cbBuf,LPDWORD pcbNeeded);
+ WINBOOL WINAPI ScheduleJob(HANDLE hPrinter,DWORD JobId);
+ WINBOOL WINAPI PrinterProperties(HWND hWnd,HANDLE hPrinter);
+ LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,LPSTR pDeviceName,PDEVMODEA pDevModeOutput,PDEVMODEA pDevModeInput,DWORD fMode);
+ LONG WINAPI DocumentPropertiesW(HWND hWnd,HANDLE hPrinter,LPWSTR pDeviceName,PDEVMODEW pDevModeOutput,PDEVMODEW pDevModeInput,DWORD fMode);
+ LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd,HANDLE hPrinter,LPSTR pDeviceName,PDEVMODEA pDevModeOutput,PDEVMODEA pDevModeInput);
+ LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd,HANDLE hPrinter,LPWSTR pDeviceName,PDEVMODEW pDevModeOutput,PDEVMODEW pDevModeInput);
+ LONG ExtDeviceMode(HWND hWnd,HANDLE hInst,LPDEVMODEA pDevModeOutput,LPSTR pDeviceName,LPSTR pPort,LPDEVMODEA pDevModeInput,LPSTR pProfile,DWORD fMode);
+ DWORD WINAPI GetPrinterDataA(HANDLE hPrinter,LPSTR pValueName,LPDWORD pType,LPBYTE pData,DWORD nSize,LPDWORD pcbNeeded);
+ DWORD WINAPI GetPrinterDataW(HANDLE hPrinter,LPWSTR pValueName,LPDWORD pType,LPBYTE pData,DWORD nSize,LPDWORD pcbNeeded);
+ DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter,LPCSTR pKeyName,LPCSTR pValueName,LPDWORD pType,LPBYTE pData,DWORD nSize,LPDWORD pcbNeeded);
+ DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter,LPCWSTR pKeyName,LPCWSTR pValueName,LPDWORD pType,LPBYTE pData,DWORD nSize,LPDWORD pcbNeeded);
+ DWORD WINAPI EnumPrinterDataA(HANDLE hPrinter,DWORD dwIndex,LPSTR pValueName,DWORD cbValueName,LPDWORD pcbValueName,LPDWORD pType,LPBYTE pData,DWORD cbData,LPDWORD pcbData);
+ DWORD WINAPI EnumPrinterDataW(HANDLE hPrinter,DWORD dwIndex,LPWSTR pValueName,DWORD cbValueName,LPDWORD pcbValueName,LPDWORD pType,LPBYTE pData,DWORD cbData,LPDWORD pcbData);
+ DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter,LPCSTR pKeyName,LPBYTE pEnumValues,DWORD cbEnumValues,LPDWORD pcbEnumValues,LPDWORD pnEnumValues);
+ DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter,LPCWSTR pKeyName,LPBYTE pEnumValues,DWORD cbEnumValues,LPDWORD pcbEnumValues,LPDWORD pnEnumValues);
+ DWORD WINAPI EnumPrinterKeyA(HANDLE hPrinter,LPCSTR pKeyName,LPSTR pSubkey,DWORD cbSubkey,LPDWORD pcbSubkey);
+ DWORD WINAPI EnumPrinterKeyW(HANDLE hPrinter,LPCWSTR pKeyName,LPWSTR pSubkey,DWORD cbSubkey,LPDWORD pcbSubkey);
+ DWORD WINAPI SetPrinterDataA(HANDLE hPrinter,LPSTR pValueName,DWORD Type,LPBYTE pData,DWORD cbData);
+ DWORD WINAPI SetPrinterDataW(HANDLE hPrinter,LPWSTR pValueName,DWORD Type,LPBYTE pData,DWORD cbData);
+ DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter,LPCSTR pKeyName,LPCSTR pValueName,DWORD Type,LPBYTE pData,DWORD cbData);
+ DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter,LPCWSTR pKeyName,LPCWSTR pValueName,DWORD Type,LPBYTE pData,DWORD cbData);
+ DWORD WINAPI DeletePrinterDataA(HANDLE hPrinter,LPSTR pValueName);
+ DWORD WINAPI DeletePrinterDataW(HANDLE hPrinter,LPWSTR pValueName);
+ DWORD WINAPI DeletePrinterDataExA(HANDLE hPrinter,LPCSTR pKeyName,LPCSTR pValueName);
+ DWORD WINAPI DeletePrinterDataExW(HANDLE hPrinter,LPCWSTR pKeyName,LPCWSTR pValueName);
+ DWORD WINAPI DeletePrinterKeyA(HANDLE hPrinter,LPCSTR pKeyName);
+ DWORD WINAPI DeletePrinterKeyW(HANDLE hPrinter,LPCWSTR pKeyName);
+
+#define PRINTER_NOTIFY_TYPE 0x00
+#define JOB_NOTIFY_TYPE 0x01
+
+#define PRINTER_NOTIFY_FIELD_SERVER_NAME 0x00
+#define PRINTER_NOTIFY_FIELD_PRINTER_NAME 0x01
+#define PRINTER_NOTIFY_FIELD_SHARE_NAME 0x02
+#define PRINTER_NOTIFY_FIELD_PORT_NAME 0x03
+#define PRINTER_NOTIFY_FIELD_DRIVER_NAME 0x04
+#define PRINTER_NOTIFY_FIELD_COMMENT 0x05
+#define PRINTER_NOTIFY_FIELD_LOCATION 0x06
+#define PRINTER_NOTIFY_FIELD_DEVMODE 0x07
+#define PRINTER_NOTIFY_FIELD_SEPFILE 0x08
+#define PRINTER_NOTIFY_FIELD_PRINT_PROCESSOR 0x09
+#define PRINTER_NOTIFY_FIELD_PARAMETERS 0x0A
+#define PRINTER_NOTIFY_FIELD_DATATYPE 0x0B
+#define PRINTER_NOTIFY_FIELD_SECURITY_DESCRIPTOR 0x0C
+#define PRINTER_NOTIFY_FIELD_ATTRIBUTES 0x0D
+#define PRINTER_NOTIFY_FIELD_PRIORITY 0x0E
+#define PRINTER_NOTIFY_FIELD_DEFAULT_PRIORITY 0x0F
+#define PRINTER_NOTIFY_FIELD_START_TIME 0x10
+#define PRINTER_NOTIFY_FIELD_UNTIL_TIME 0x11
+#define PRINTER_NOTIFY_FIELD_STATUS 0x12
+#define PRINTER_NOTIFY_FIELD_STATUS_STRING 0x13
+#define PRINTER_NOTIFY_FIELD_CJOBS 0x14
+#define PRINTER_NOTIFY_FIELD_AVERAGE_PPM 0x15
+#define PRINTER_NOTIFY_FIELD_TOTAL_PAGES 0x16
+#define PRINTER_NOTIFY_FIELD_PAGES_PRINTED 0x17
+#define PRINTER_NOTIFY_FIELD_TOTAL_BYTES 0x18
+#define PRINTER_NOTIFY_FIELD_BYTES_PRINTED 0x19
+#define PRINTER_NOTIFY_FIELD_OBJECT_GUID 0x1A
+
+#define JOB_NOTIFY_FIELD_PRINTER_NAME 0x00
+#define JOB_NOTIFY_FIELD_MACHINE_NAME 0x01
+#define JOB_NOTIFY_FIELD_PORT_NAME 0x02
+#define JOB_NOTIFY_FIELD_USER_NAME 0x03
+#define JOB_NOTIFY_FIELD_NOTIFY_NAME 0x04
+#define JOB_NOTIFY_FIELD_DATATYPE 0x05
+#define JOB_NOTIFY_FIELD_PRINT_PROCESSOR 0x06
+#define JOB_NOTIFY_FIELD_PARAMETERS 0x07
+#define JOB_NOTIFY_FIELD_DRIVER_NAME 0x08
+#define JOB_NOTIFY_FIELD_DEVMODE 0x09
+#define JOB_NOTIFY_FIELD_STATUS 0x0A
+#define JOB_NOTIFY_FIELD_STATUS_STRING 0x0B
+#define JOB_NOTIFY_FIELD_SECURITY_DESCRIPTOR 0x0C
+#define JOB_NOTIFY_FIELD_DOCUMENT 0x0D
+#define JOB_NOTIFY_FIELD_PRIORITY 0x0E
+#define JOB_NOTIFY_FIELD_POSITION 0x0F
+#define JOB_NOTIFY_FIELD_SUBMITTED 0x10
+#define JOB_NOTIFY_FIELD_START_TIME 0x11
+#define JOB_NOTIFY_FIELD_UNTIL_TIME 0x12
+#define JOB_NOTIFY_FIELD_TIME 0x13
+#define JOB_NOTIFY_FIELD_TOTAL_PAGES 0x14
+#define JOB_NOTIFY_FIELD_PAGES_PRINTED 0x15
+#define JOB_NOTIFY_FIELD_TOTAL_BYTES 0x16
+#define JOB_NOTIFY_FIELD_BYTES_PRINTED 0x17
+
+ typedef struct _PRINTER_NOTIFY_OPTIONS_TYPE {
+ WORD Type;
+ WORD Reserved0;
+ DWORD Reserved1;
+ DWORD Reserved2;
+ DWORD Count;
+ PWORD pFields;
+ } PRINTER_NOTIFY_OPTIONS_TYPE,*PPRINTER_NOTIFY_OPTIONS_TYPE,*LPPRINTER_NOTIFY_OPTIONS_TYPE;
+
+#define PRINTER_NOTIFY_OPTIONS_REFRESH 0x01
+
+ typedef struct _PRINTER_NOTIFY_OPTIONS {
+ DWORD Version;
+ DWORD Flags;
+ DWORD Count;
+ PPRINTER_NOTIFY_OPTIONS_TYPE pTypes;
+ } PRINTER_NOTIFY_OPTIONS,*PPRINTER_NOTIFY_OPTIONS,*LPPRINTER_NOTIFY_OPTIONS;
+
+#define PRINTER_NOTIFY_INFO_DISCARDED 0x01
+
+ typedef struct _PRINTER_NOTIFY_INFO_DATA {
+ WORD Type;
+ WORD Field;
+ DWORD Reserved;
+ DWORD Id;
+ union {
+ DWORD adwData[2];
+ struct {
+ DWORD cbBuf;
+ LPVOID pBuf;
+ } Data;
+ } NotifyData;
+ } PRINTER_NOTIFY_INFO_DATA,*PPRINTER_NOTIFY_INFO_DATA,*LPPRINTER_NOTIFY_INFO_DATA;
+
+ typedef struct _PRINTER_NOTIFY_INFO {
+ DWORD Version;
+ DWORD Flags;
+ DWORD Count;
+ PRINTER_NOTIFY_INFO_DATA aData[1];
+ } PRINTER_NOTIFY_INFO,*PPRINTER_NOTIFY_INFO,*LPPRINTER_NOTIFY_INFO;
+
+ typedef struct _BINARY_CONTAINER{
+ DWORD cbBuf;
+ LPBYTE pData;
+ } BINARY_CONTAINER,*PBINARY_CONTAINER;
+
+ typedef struct _BIDI_DATA{
+ DWORD dwBidiType;
+ union {
+ WINBOOL bData;
+ LONG iData;
+ LPWSTR sData;
+ FLOAT fData;
+ BINARY_CONTAINER biData;
+ } u;
+ } BIDI_DATA,*PBIDI_DATA,*LPBIDI_DATA;
+
+ typedef struct _BIDI_REQUEST_DATA{
+ DWORD dwReqNumber;
+ LPWSTR pSchema;
+ BIDI_DATA data;
+ } BIDI_REQUEST_DATA ,*PBIDI_REQUEST_DATA ,*LPBIDI_REQUEST_DATA;
+
+ typedef struct _BIDI_REQUEST_CONTAINER{
+ DWORD Version;
+ DWORD Flags;
+ DWORD Count;
+ BIDI_REQUEST_DATA aData[1 ];
+ }BIDI_REQUEST_CONTAINER,*PBIDI_REQUEST_CONTAINER,*LPBIDI_REQUEST_CONTAINER;
+
+ typedef struct _BIDI_RESPONSE_DATA{
+ DWORD dwResult;
+ DWORD dwReqNumber;
+ LPWSTR pSchema;
+ BIDI_DATA data;
+ } BIDI_RESPONSE_DATA,*PBIDI_RESPONSE_DATA,*LPBIDI_RESPONSE_DATA;
+
+ typedef struct _BIDI_RESPONSE_CONTAINER{
+ DWORD Version;
+ DWORD Flags;
+ DWORD Count;
+ BIDI_RESPONSE_DATA aData[1 ];
+ } BIDI_RESPONSE_CONTAINER,*PBIDI_RESPONSE_CONTAINER,*LPBIDI_RESPONSE_CONTAINER;
+
+#define BIDI_ACTION_ENUM_SCHEMA L"EnumSchema"
+#define BIDI_ACTION_GET L"Get"
+#define BIDI_ACTION_SET L"Set"
+#define BIDI_ACTION_GET_ALL L"GetAll"
+
+ typedef enum {
+ BIDI_NULL = 0,BIDI_INT = 1,BIDI_FLOAT = 2,BIDI_BOOL = 3,BIDI_STRING = 4,BIDI_TEXT = 5,BIDI_ENUM = 6,BIDI_BLOB = 7
+ } BIDI_TYPE;
+
+#define BIDI_ACCESS_ADMINISTRATOR 0x1
+#define BIDI_ACCESS_USER 0x2
+
+#define ERROR_BIDI_STATUS_OK 0
+#define ERROR_BIDI_NOT_SUPPORTED ERROR_NOT_SUPPORTED
+
+#define ERROR_BIDI_ERROR_BASE 13000
+#define ERROR_BIDI_STATUS_WARNING (ERROR_BIDI_ERROR_BASE + 1)
+#define ERROR_BIDI_SCHEMA_READ_ONLY (ERROR_BIDI_ERROR_BASE + 2)
+#define ERROR_BIDI_SERVER_OFFLINE (ERROR_BIDI_ERROR_BASE + 3)
+#define ERROR_BIDI_DEVICE_OFFLINE (ERROR_BIDI_ERROR_BASE + 4)
+#define ERROR_BIDI_SCHEMA_NOT_SUPPORTED (ERROR_BIDI_ERROR_BASE + 5)
+
+ DWORD WINAPI WaitForPrinterChange(HANDLE hPrinter,DWORD Flags);
+ HANDLE WINAPI FindFirstPrinterChangeNotification(HANDLE hPrinter,DWORD fdwFlags,DWORD fdwOptions,LPVOID pPrinterNotifyOptions);
+ WINBOOL WINAPI FindNextPrinterChangeNotification(HANDLE hChange,PDWORD pdwChange,LPVOID pPrinterNotifyOptions,LPVOID *ppPrinterNotifyInfo);
+ WINBOOL WINAPI FreePrinterNotifyInfo (PPRINTER_NOTIFY_INFO pPrinterNotifyInfo);
+ WINBOOL WINAPI FindClosePrinterChangeNotification(HANDLE hChange);
+
+#define PRINTER_CHANGE_ADD_PRINTER 0x00000001
+#define PRINTER_CHANGE_SET_PRINTER 0x00000002
+#define PRINTER_CHANGE_DELETE_PRINTER 0x00000004
+#define PRINTER_CHANGE_FAILED_CONNECTION_PRINTER 0x00000008
+#define PRINTER_CHANGE_PRINTER 0x000000FF
+#define PRINTER_CHANGE_ADD_JOB 0x00000100
+#define PRINTER_CHANGE_SET_JOB 0x00000200
+#define PRINTER_CHANGE_DELETE_JOB 0x00000400
+#define PRINTER_CHANGE_WRITE_JOB 0x00000800
+#define PRINTER_CHANGE_JOB 0x0000FF00
+#define PRINTER_CHANGE_ADD_FORM 0x00010000
+#define PRINTER_CHANGE_SET_FORM 0x00020000
+#define PRINTER_CHANGE_DELETE_FORM 0x00040000
+#define PRINTER_CHANGE_FORM 0x00070000
+#define PRINTER_CHANGE_ADD_PORT 0x00100000
+#define PRINTER_CHANGE_CONFIGURE_PORT 0x00200000
+#define PRINTER_CHANGE_DELETE_PORT 0x00400000
+#define PRINTER_CHANGE_PORT 0x00700000
+#define PRINTER_CHANGE_ADD_PRINT_PROCESSOR 0x01000000
+#define PRINTER_CHANGE_DELETE_PRINT_PROCESSOR 0x04000000
+#define PRINTER_CHANGE_PRINT_PROCESSOR 0x07000000
+#define PRINTER_CHANGE_ADD_PRINTER_DRIVER 0x10000000
+#define PRINTER_CHANGE_SET_PRINTER_DRIVER 0x20000000
+#define PRINTER_CHANGE_DELETE_PRINTER_DRIVER 0x40000000
+#define PRINTER_CHANGE_PRINTER_DRIVER 0x70000000
+#define PRINTER_CHANGE_TIMEOUT 0x80000000
+#define PRINTER_CHANGE_ALL 0x7777FFFF
+
+#define PrinterMessageBox __MINGW_NAME_AW(PrinterMessageBox)
+#define AddForm __MINGW_NAME_AW(AddForm)
+#define DeleteForm __MINGW_NAME_AW(DeleteForm)
+#define GetForm __MINGW_NAME_AW(GetForm)
+#define SetForm __MINGW_NAME_AW(SetForm)
+#define EnumForms __MINGW_NAME_AW(EnumForms)
+#define EnumMonitors __MINGW_NAME_AW(EnumMonitors)
+#define AddMonitor __MINGW_NAME_AW(AddMonitor)
+#define DeleteMonitor __MINGW_NAME_AW(DeleteMonitor)
+#define EnumPorts __MINGW_NAME_AW(EnumPorts)
+#define AddPort __MINGW_NAME_AW(AddPort)
+#define ConfigurePort __MINGW_NAME_AW(ConfigurePort)
+#define DeletePort __MINGW_NAME_AW(DeletePort)
+#define GetDefaultPrinter __MINGW_NAME_AW(GetDefaultPrinter)
+#define SetDefaultPrinter __MINGW_NAME_AW(SetDefaultPrinter)
+#define SetPort __MINGW_NAME_AW(SetPort)
+#define AddPrinterConnection __MINGW_NAME_AW(AddPrinterConnection)
+#define DeletePrinterConnection __MINGW_NAME_AW(DeletePrinterConnection)
+
+ DWORD WINAPI PrinterMessageBoxA(HANDLE hPrinter,DWORD Error,HWND hWnd,LPSTR pText,LPSTR pCaption,DWORD dwType);
+ DWORD WINAPI PrinterMessageBoxW(HANDLE hPrinter,DWORD Error,HWND hWnd,LPWSTR pText,LPWSTR pCaption,DWORD dwType);
+
+#define PRINTER_ERROR_INFORMATION 0x80000000
+#define PRINTER_ERROR_WARNING 0x40000000
+#define PRINTER_ERROR_SEVERE 0x20000000
+
+#define PRINTER_ERROR_OUTOFPAPER 0x00000001
+#define PRINTER_ERROR_JAM 0x00000002
+#define PRINTER_ERROR_OUTOFTONER 0x00000004
+
+ WINBOOL WINAPI ClosePrinter(HANDLE hPrinter);
+ WINBOOL WINAPI AddFormA(HANDLE hPrinter,DWORD Level,LPBYTE pForm);
+ WINBOOL WINAPI AddFormW(HANDLE hPrinter,DWORD Level,LPBYTE pForm);
+ WINBOOL WINAPI DeleteFormA(HANDLE hPrinter,LPSTR pFormName);
+ WINBOOL WINAPI DeleteFormW(HANDLE hPrinter,LPWSTR pFormName);
+ WINBOOL WINAPI GetFormA(HANDLE hPrinter,LPSTR pFormName,DWORD Level,LPBYTE pForm,DWORD cbBuf,LPDWORD pcbNeeded);
+ WINBOOL WINAPI GetFormW(HANDLE hPrinter,LPWSTR pFormName,DWORD Level,LPBYTE pForm,DWORD cbBuf,LPDWORD pcbNeeded);
+ WINBOOL WINAPI SetFormA(HANDLE hPrinter,LPSTR pFormName,DWORD Level,LPBYTE pForm);
+ WINBOOL WINAPI SetFormW(HANDLE hPrinter,LPWSTR pFormName,DWORD Level,LPBYTE pForm);
+ WINBOOL WINAPI EnumFormsA(HANDLE hPrinter,DWORD Level,LPBYTE pForm,DWORD cbBuf,LPDWORD pcbNeeded,LPDWORD pcReturned);
+ WINBOOL WINAPI EnumFormsW(HANDLE hPrinter,DWORD Level,LPBYTE pForm,DWORD cbBuf,LPDWORD pcbNeeded,LPDWORD pcReturned);
+ WINBOOL WINAPI EnumMonitorsA(LPSTR pName,DWORD Level,LPBYTE pMonitor,DWORD cbBuf,LPDWORD pcbNeeded,LPDWORD pcReturned);
+ WINBOOL WINAPI EnumMonitorsW(LPWSTR pName,DWORD Level,LPBYTE pMonitor,DWORD cbBuf,LPDWORD pcbNeeded,LPDWORD pcReturned);
+ WINBOOL WINAPI AddMonitorA(LPSTR pName,DWORD Level,LPBYTE pMonitorInfo);
+ WINBOOL WINAPI AddMonitorW(LPWSTR pName,DWORD Level,LPBYTE pMonitorInfo);
+ WINBOOL WINAPI DeleteMonitorA(LPSTR pName,LPSTR pEnvironment,LPSTR pMonitorName);
+ WINBOOL WINAPI DeleteMonitorW(LPWSTR pName,LPWSTR pEnvironment,LPWSTR pMonitorName);
+ WINBOOL WINAPI EnumPortsA(LPSTR pName,DWORD Level,LPBYTE pPorts,DWORD cbBuf,LPDWORD pcbNeeded,LPDWORD pcReturned);
+ WINBOOL WINAPI EnumPortsW(LPWSTR pName,DWORD Level,LPBYTE pPorts,DWORD cbBuf,LPDWORD pcbNeeded,LPDWORD pcReturned);
+ WINBOOL WINAPI AddPortA(LPSTR pName,HWND hWnd,LPSTR pMonitorName);
+ WINBOOL WINAPI AddPortW(LPWSTR pName,HWND hWnd,LPWSTR pMonitorName);
+ WINBOOL WINAPI ConfigurePortA(LPSTR pName,HWND hWnd,LPSTR pPortName);
+ WINBOOL WINAPI ConfigurePortW(LPWSTR pName,HWND hWnd,LPWSTR pPortName);
+ WINBOOL WINAPI DeletePortA(LPSTR pName,HWND hWnd,LPSTR pPortName);
+ WINBOOL WINAPI DeletePortW(LPWSTR pName,HWND hWnd,LPWSTR pPortName);
+ WINBOOL WINAPI XcvDataW(HANDLE hXcv,PCWSTR pszDataName,PBYTE pInputData,DWORD cbInputData,PBYTE pOutputData,DWORD cbOutputData,PDWORD pcbOutputNeeded,PDWORD pdwStatus);
+
+#define XcvData XcvDataW
+
+ WINBOOL WINAPI GetDefaultPrinterA(LPSTR pszBuffer,LPDWORD pcchBuffer);
+ WINBOOL WINAPI GetDefaultPrinterW(LPWSTR pszBuffer,LPDWORD pcchBuffer);
+ WINBOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter);
+ WINBOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter);
+ WINBOOL WINAPI SetPortA(LPSTR pName,LPSTR pPortName,DWORD dwLevel,LPBYTE pPortInfo);
+ WINBOOL WINAPI SetPortW(LPWSTR pName,LPWSTR pPortName,DWORD dwLevel,LPBYTE pPortInfo);
+ WINBOOL WINAPI AddPrinterConnectionA(LPSTR pName);
+ WINBOOL WINAPI AddPrinterConnectionW(LPWSTR pName);
+ WINBOOL WINAPI DeletePrinterConnectionA(LPSTR pName);
+ WINBOOL WINAPI DeletePrinterConnectionW(LPWSTR pName);
+ HANDLE WINAPI ConnectToPrinterDlg(HWND hwnd,DWORD Flags);
+
+ typedef struct _PROVIDOR_INFO_1A{
+ LPSTR pName;
+ LPSTR pEnvironment;
+ LPSTR pDLLName;
+ } PROVIDOR_INFO_1A,*PPROVIDOR_INFO_1A,*LPPROVIDOR_INFO_1A;
+
+ typedef struct _PROVIDOR_INFO_1W{
+ LPWSTR pName;
+ LPWSTR pEnvironment;
+ LPWSTR pDLLName;
+ } PROVIDOR_INFO_1W,*PPROVIDOR_INFO_1W,*LPPROVIDOR_INFO_1W;
+
+ __MINGW_TYPEDEF_AW(PROVIDOR_INFO_1)
+ __MINGW_TYPEDEF_AW(PPROVIDOR_INFO_1)
+ __MINGW_TYPEDEF_AW(LPPROVIDOR_INFO_1)
+
+ typedef struct _PROVIDOR_INFO_2A{
+ LPSTR pOrder;
+ } PROVIDOR_INFO_2A,*PPROVIDOR_INFO_2A,*LPPROVIDOR_INFO_2A;
+
+ typedef struct _PROVIDOR_INFO_2W{
+ LPWSTR pOrder;
+ } PROVIDOR_INFO_2W,*PPROVIDOR_INFO_2W,*LPPROVIDOR_INFO_2W;
+
+ __MINGW_TYPEDEF_AW(PROVIDOR_INFO_2)
+ __MINGW_TYPEDEF_AW(PPROVIDOR_INFO_2)
+ __MINGW_TYPEDEF_AW(LPPROVIDOR_INFO_2)
+
+#define AddPrintProvidor __MINGW_NAME_AW(AddPrintProvidor)
+#define DeletePrintProvidor __MINGW_NAME_AW(DeletePrintProvidor)
+#define IsValidDevmode __MINGW_NAME_AW(IsValidDevmode)
+
+ WINBOOL WINAPI AddPrintProvidorA(LPSTR pName,DWORD level,LPBYTE pProvidorInfo);
+ WINBOOL WINAPI AddPrintProvidorW(LPWSTR pName,DWORD level,LPBYTE pProvidorInfo);
+ WINBOOL WINAPI DeletePrintProvidorA(LPSTR pName,LPSTR pEnvironment,LPSTR pPrintProvidorName);
+ WINBOOL WINAPI DeletePrintProvidorW(LPWSTR pName,LPWSTR pEnvironment,LPWSTR pPrintProvidorName);
+ WINBOOL WINAPI IsValidDevmodeA (PDEVMODEA pDevmode,size_t DevmodeSize);
+ WINBOOL WINAPI IsValidDevmodeW (PDEVMODEW pDevmode,size_t DevmodeSize);
+
+#define SPLREG_DEFAULT_SPOOL_DIRECTORY TEXT("DefaultSpoolDirectory")
+#define SPLREG_PORT_THREAD_PRIORITY_DEFAULT TEXT("PortThreadPriorityDefault")
+#define SPLREG_PORT_THREAD_PRIORITY TEXT("PortThreadPriority")
+#define SPLREG_SCHEDULER_THREAD_PRIORITY_DEFAULT TEXT("SchedulerThreadPriorityDefault")
+#define SPLREG_SCHEDULER_THREAD_PRIORITY TEXT("SchedulerThreadPriority")
+#define SPLREG_BEEP_ENABLED TEXT("BeepEnabled")
+#define SPLREG_NET_POPUP TEXT("NetPopup")
+#define SPLREG_RETRY_POPUP TEXT("RetryPopup")
+#define SPLREG_NET_POPUP_TO_COMPUTER TEXT("NetPopupToComputer")
+#define SPLREG_EVENT_LOG TEXT("EventLog")
+#define SPLREG_MAJOR_VERSION TEXT("MajorVersion")
+#define SPLREG_MINOR_VERSION TEXT("MinorVersion")
+#define SPLREG_ARCHITECTURE TEXT("Architecture")
+#define SPLREG_OS_VERSION TEXT("OSVersion")
+#define SPLREG_OS_VERSIONEX TEXT("OSVersionEx")
+#define SPLREG_DS_PRESENT TEXT("DsPresent")
+#define SPLREG_DS_PRESENT_FOR_USER TEXT("DsPresentForUser")
+#define SPLREG_REMOTE_FAX TEXT("RemoteFax")
+#define SPLREG_RESTART_JOB_ON_POOL_ERROR TEXT("RestartJobOnPoolError")
+#define SPLREG_RESTART_JOB_ON_POOL_ENABLED TEXT("RestartJobOnPoolEnabled")
+#define SPLREG_DNS_MACHINE_NAME TEXT("DNSMachineName")
+#define SPLREG_ALLOW_USER_MANAGEFORMS TEXT("AllowUserManageForms")
+#define SPLREG_WEBSHAREMGMT TEXT("WebShareMgmt")
+
+#define SERVER_ACCESS_ADMINISTER 0x00000001
+#define SERVER_ACCESS_ENUMERATE 0x00000002
+
+#define PRINTER_ACCESS_ADMINISTER 0x00000004
+#define PRINTER_ACCESS_USE 0x00000008
+
+#define JOB_ACCESS_ADMINISTER 0x00000010
+#define JOB_ACCESS_READ 0x00000020
+
+#define SERVER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SERVER_ACCESS_ADMINISTER | SERVER_ACCESS_ENUMERATE)
+#define SERVER_READ (STANDARD_RIGHTS_READ | SERVER_ACCESS_ENUMERATE)
+#define SERVER_WRITE (STANDARD_RIGHTS_WRITE | SERVER_ACCESS_ADMINISTER | SERVER_ACCESS_ENUMERATE)
+#define SERVER_EXECUTE (STANDARD_RIGHTS_EXECUTE | SERVER_ACCESS_ENUMERATE)
+#define PRINTER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE)
+#define PRINTER_READ (STANDARD_RIGHTS_READ | PRINTER_ACCESS_USE)
+#define PRINTER_WRITE (STANDARD_RIGHTS_WRITE | PRINTER_ACCESS_USE)
+#define PRINTER_EXECUTE (STANDARD_RIGHTS_EXECUTE | PRINTER_ACCESS_USE)
+#define JOB_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | JOB_ACCESS_ADMINISTER | JOB_ACCESS_READ)
+#define JOB_READ (STANDARD_RIGHTS_READ | JOB_ACCESS_READ)
+#define JOB_WRITE (STANDARD_RIGHTS_WRITE | JOB_ACCESS_ADMINISTER)
+#define JOB_EXECUTE (STANDARD_RIGHTS_EXECUTE | JOB_ACCESS_ADMINISTER)
+
+#define SPLDS_SPOOLER_KEY TEXT("DsSpooler")
+#define SPLDS_DRIVER_KEY TEXT("DsDriver")
+#define SPLDS_USER_KEY TEXT("DsUser")
+
+#define SPLDS_ASSET_NUMBER TEXT("assetNumber")
+#define SPLDS_BYTES_PER_MINUTE TEXT("bytesPerMinute")
+#define SPLDS_DESCRIPTION TEXT("description")
+#define SPLDS_DRIVER_NAME TEXT("driverName")
+#define SPLDS_DRIVER_VERSION TEXT("driverVersion")
+#define SPLDS_LOCATION TEXT("location")
+#define SPLDS_PORT_NAME TEXT("portName")
+#define SPLDS_PRINT_ATTRIBUTES TEXT("printAttributes")
+#define SPLDS_PRINT_BIN_NAMES TEXT("printBinNames")
+#define SPLDS_PRINT_COLLATE TEXT("printCollate")
+#define SPLDS_PRINT_COLOR TEXT("printColor")
+#define SPLDS_PRINT_DUPLEX_SUPPORTED TEXT("printDuplexSupported")
+#define SPLDS_PRINT_END_TIME TEXT("printEndTime")
+#define SPLDS_PRINTER_CLASS TEXT("printQueue")
+#define SPLDS_PRINTER_NAME TEXT("printerName")
+#define SPLDS_PRINT_KEEP_PRINTED_JOBS TEXT("printKeepPrintedJobs")
+#define SPLDS_PRINT_LANGUAGE TEXT("printLanguage")
+#define SPLDS_PRINT_MAC_ADDRESS TEXT("printMACAddress")
+#define SPLDS_PRINT_MAX_X_EXTENT TEXT("printMaxXExtent")
+#define SPLDS_PRINT_MAX_Y_EXTENT TEXT("printMaxYExtent")
+#define SPLDS_PRINT_MAX_RESOLUTION_SUPPORTED TEXT("printMaxResolutionSupported")
+#define SPLDS_PRINT_MEDIA_READY TEXT("printMediaReady")
+#define SPLDS_PRINT_MEDIA_SUPPORTED TEXT("printMediaSupported")
+#define SPLDS_PRINT_MEMORY TEXT("printMemory")
+#define SPLDS_PRINT_MIN_X_EXTENT TEXT("printMinXExtent")
+#define SPLDS_PRINT_MIN_Y_EXTENT TEXT("printMinYExtent")
+#define SPLDS_PRINT_NETWORK_ADDRESS TEXT("printNetworkAddress")
+#define SPLDS_PRINT_NOTIFY TEXT("printNotify")
+#define SPLDS_PRINT_NUMBER_UP TEXT("printNumberUp")
+#define SPLDS_PRINT_ORIENTATIONS_SUPPORTED TEXT("printOrientationsSupported")
+#define SPLDS_PRINT_OWNER TEXT("printOwner")
+#define SPLDS_PRINT_PAGES_PER_MINUTE TEXT("printPagesPerMinute")
+#define SPLDS_PRINT_RATE TEXT("printRate")
+#define SPLDS_PRINT_RATE_UNIT TEXT("printRateUnit")
+#define SPLDS_PRINT_SEPARATOR_FILE TEXT("printSeparatorFile")
+#define SPLDS_PRINT_SHARE_NAME TEXT("printShareName")
+#define SPLDS_PRINT_SPOOLING TEXT("printSpooling")
+#define SPLDS_PRINT_STAPLING_SUPPORTED TEXT("printStaplingSupported")
+#define SPLDS_PRINT_START_TIME TEXT("printStartTime")
+#define SPLDS_PRINT_STATUS TEXT("printStatus")
+#define SPLDS_PRIORITY TEXT("priority")
+#define SPLDS_SERVER_NAME TEXT("serverName")
+#define SPLDS_SHORT_SERVER_NAME TEXT("shortServerName")
+#define SPLDS_UNC_NAME TEXT("uNCName")
+#define SPLDS_URL TEXT("url")
+#define SPLDS_FLAGS TEXT("flags")
+#define SPLDS_VERSION_NUMBER TEXT("versionNumber")
+
+#define SPLDS_PRINTER_NAME_ALIASES TEXT("printerNameAliases")
+#define SPLDS_PRINTER_LOCATIONS TEXT("printerLocations")
+#define SPLDS_PRINTER_MODEL TEXT("printerModel")
+
+#if (_WIN32_WINNT >= 0x0600)
+#define AddPrinterConnection2 __MINGW_NAME_AW(AddPrinterConnection2)
+#define DeletePrinterDriverPackage __MINGW_NAME_AW(DeletePrinterDriverPackage)
+#define DocumentEvent __MINGW_NAME_AW(DocumentEvent)
+
+#define PRINTER_CONNECTION_MISMATCH 0x00000020
+#define PRINTER_CONNECTION_NO_UI 0x00000040
+
+typedef enum tagPRINTER_OPTION_FLAGS {
+ PRINTER_OPTION_NO_CACHE,
+ PRINTER_OPTION_CACHE,
+ PRINTER_OPTION_CLIENT_CHANGE
+} PRINTER_OPTION_FLAGS;
+
+typedef enum tagEPrintXPSJobOperation {
+ kJobProduction,
+ kJobConsumption
+} EPrintXPSJobOperation;
+
+typedef enum tagEPrintXPSJobProgress {
+ kAddingDocumentSequence,
+ kDocumentSequenceAdded,
+ kAddingFixedDocument,
+ kFixedDocumentAdded,
+ kAddingFixedPage,
+ kFixedPageAdded,
+ kResourceAdded,
+ kFontAdded,
+ kImageAdded,
+ kXpsDocumentCommitted
+} EPrintXPSJobProgress;
+
+typedef struct _PRINTER_CONNECTION_INFO_1 {
+ DWORD dwFlags;
+ LPTSTR pszDriverName;
+} PRINTER_CONNECTION_INFO_1, *PPRINTER_CONNECTION_INFO_1;
+
+ WINBOOL AddPrinterConnection2W(HWND hWnd,LPCWSTR pszName,DWORD dwLevel,PVOID pConnectionInfo);
+ WINBOOL AddPrinterConnection2A(HWND hWnd,LPCSTR pszName,DWORD dwLevel,PVOID pConnectionInfo); /*Not supported and returns ERROR_NOT_SUPPORTED.*/
+
+HRESULT WINAPI DeletePrinterDriverPackageA(
+ LPCSTR pszServer,
+ LPCSTR pszInfPath,
+ LPCSTR pszEnvironment
+);
+
+HRESULT WINAPI DeletePrinterDriverPackageW(
+ LPCWSTR pszServer,
+ LPCWSTR pszInfPath,
+ LPCWSTR pszEnvironment
+);
+
+HRESULT DocumentEventA(
+ HANDLE hPrinter,
+ HDC hdc,
+ INT iEsc,
+ ULONG cbIn,
+ PVOID pvIn,
+ ULONG cbOut,
+ PVOID pvOut
+);
+
+HRESULT DocumentEventW(
+ HANDLE hPrinter,
+ HDC hdc,
+ INT iEsc,
+ ULONG cbIn,
+ PVOID pvIn,
+ ULONG cbOut,
+ PVOID pvOut
+);
typedef struct _DRIVER_INFO_8W {
- DWORD cVersion;
- LPWSTR pName;
- LPWSTR pEnvironment;
- LPWSTR pDriverPath;
- LPWSTR pDataFile;
- LPWSTR pConfigFile;
- LPWSTR pHelpFile;
- LPWSTR pDependentFiles;
- LPWSTR pMonitorName;
- LPWSTR pDefaultDataType;
- LPWSTR pszzPreviousNames;
- FILETIME ftDriverDate;
+ DWORD cVersion;
+ LPWSTR pName;
+ LPWSTR pEnvironment;
+ LPWSTR pDriverPath;
+ LPWSTR pDataFile;
+ LPWSTR pConfigFile;
+ LPWSTR pHelpFile;
+ LPWSTR pDependentFiles;
+ LPWSTR pMonitorName;
+ LPWSTR pDefaultDataType;
+ LPWSTR pszzPreviousNames;
+ FILETIME ftDriverDate;
DWORDLONG dwlDriverVersion;
- LPWSTR pszMfgName;
- LPWSTR pszOEMUrl;
- LPWSTR pszHardwareID;
- LPWSTR pszProvider;
- LPWSTR pszPrintProcessor;
- LPWSTR pszVendorSetup;
- LPWSTR pszzColorProfiles;
- LPWSTR pszInfPath;
- DWORD dwPrinterDriverAttributes;
- LPWSTR pszzCoreDriverDependencies;
- FILETIME ftMinInboxDriverVerDate;
+ LPWSTR pszMfgName;
+ LPWSTR pszOEMUrl;
+ LPWSTR pszHardwareID;
+ LPWSTR pszProvider;
+ LPWSTR pszPrintProcessor;
+ LPWSTR pszVendorSetup;
+ LPWSTR pszzColorProfiles;
+ LPWSTR pszInfPath;
+ DWORD dwPrinterDriverAttributes;
+ LPWSTR pszzCoreDriverDependencies;
+ FILETIME ftMinInboxDriverVerDate;
DWORDLONG dwlMinInboxDriverVerVersion;
} DRIVER_INFO_8W, *PDRIVER_INFO_8W, *LPDRIVER_INFO_8W;
-// FLAGS for dwDriverAttributes
-#define DRIVER_KERNELMODE 0x00000001
-#define DRIVER_USERMODE 0x00000002
-
-// FLAGS for DeletePrinterDriverEx.
-#define DPD_DELETE_UNUSED_FILES 0x00000001
-#define DPD_DELETE_SPECIFIC_VERSION 0x00000002
-#define DPD_DELETE_ALL_FILES 0x00000004
-
-// FLAGS for AddPrinterDriverEx.
-#define APD_STRICT_UPGRADE 0x00000001
-#define APD_STRICT_DOWNGRADE 0x00000002
-#define APD_COPY_ALL_FILES 0x00000004
-#define APD_COPY_NEW_FILES 0x00000008
-#if(_WIN32_WINNT >= 0x0501)
-#define APD_COPY_FROM_DIRECTORY 0x00000010
-#endif
-
-typedef struct _MONITOR_INFO_1A {
- LPSTR pName;
-} MONITOR_INFO_1A, *PMONITOR_INFO_1A, *LPMONITOR_INFO_1A;
-
-typedef struct _MONITOR_INFO_1W {
- LPWSTR pName;
-} MONITOR_INFO_1W, *PMONITOR_INFO_1W, *LPMONITOR_INFO_1W;
-
-typedef struct _PORT_INFO_1A {
- LPSTR pName;
-} PORT_INFO_1A, *PPORT_INFO_1A, *LPPORT_INFO_1A;
-
-typedef struct _PORT_INFO_1W {
- LPWSTR pName;
-} PORT_INFO_1W, *PPORT_INFO_1W, *LPPORT_INFO_1W;
-
-typedef struct _MONITOR_INFO_2A {
- LPSTR pName;
- LPSTR pEnvironment;
- LPSTR pDLLName;
-} MONITOR_INFO_2A, *PMONITOR_INFO_2A, *LPMONITOR_INFO_2A;
-
-typedef struct _MONITOR_INFO_2W {
- LPWSTR pName;
- LPWSTR pEnvironment;
- LPWSTR pDLLName;
-} MONITOR_INFO_2W, *PMONITOR_INFO_2W, *LPMONITOR_INFO_2W;
-
-typedef struct _PORT_INFO_2A {
- LPSTR pPortName;
- LPSTR pMonitorName;
- LPSTR pDescription;
- DWORD fPortType;
- DWORD Reserved;
-} PORT_INFO_2A, *PPORT_INFO_2A, *LPPORT_INFO_2A;
-
-typedef struct _PORT_INFO_2W {
- LPWSTR pPortName;
- LPWSTR pMonitorName;
- LPWSTR pDescription;
- DWORD fPortType;
- DWORD Reserved;
-} PORT_INFO_2W, *PPORT_INFO_2W, *LPPORT_INFO_2W;
-
-typedef struct _PORT_INFO_3A {
- DWORD dwStatus;
- LPSTR pszStatus;
- DWORD dwSeverity;
-} PORT_INFO_3A, *PPORT_INFO_3A, *LPPORT_INFO_3A;
-
-typedef struct _PORT_INFO_3W {
- DWORD dwStatus;
- LPWSTR pszStatus;
- DWORD dwSeverity;
-} PORT_INFO_3W, *PPORT_INFO_3W, *LPPORT_INFO_3W;
-
-typedef struct _PRINTER_INFO_1A {
- DWORD Flags;
- LPSTR pDescription;
- LPSTR pName;
- LPSTR pComment;
-} PRINTER_INFO_1A, *PPRINTER_INFO_1A, *LPPRINTER_INFO_1A;
-
-typedef struct _PRINTER_INFO_1W {
- DWORD Flags;
- LPWSTR pDescription;
- LPWSTR pName;
- LPWSTR pComment;
-} PRINTER_INFO_1W, *PPRINTER_INFO_1W, *LPPRINTER_INFO_1W;
-
-typedef struct _PRINTER_INFO_2A {
- LPSTR pServerName;
- LPSTR pPrinterName;
- LPSTR pShareName;
- LPSTR pPortName;
- LPSTR pDriverName;
- LPSTR pComment;
- LPSTR pLocation;
- LPDEVMODEA pDevMode;
- LPSTR pSepFile;
- LPSTR pPrintProcessor;
- LPSTR pDatatype;
- LPSTR pParameters;
- PSECURITY_DESCRIPTOR pSecurityDescriptor;
- DWORD Attributes;
- DWORD Priority;
- DWORD DefaultPriority;
- DWORD StartTime;
- DWORD UntilTime;
- DWORD Status;
- DWORD cJobs;
- DWORD AveragePPM;
-} PRINTER_INFO_2A, *PPRINTER_INFO_2A, *LPPRINTER_INFO_2A;
-
-typedef struct _PRINTER_INFO_2W {
- LPWSTR pServerName;
- LPWSTR pPrinterName;
- LPWSTR pShareName;
- LPWSTR pPortName;
- LPWSTR pDriverName;
- LPWSTR pComment;
- LPWSTR pLocation;
- LPDEVMODEW pDevMode;
- LPWSTR pSepFile;
- LPWSTR pPrintProcessor;
- LPWSTR pDatatype;
- LPWSTR pParameters;
- PSECURITY_DESCRIPTOR pSecurityDescriptor;
- DWORD Attributes;
- DWORD Priority;
- DWORD DefaultPriority;
- DWORD StartTime;
- DWORD UntilTime;
- DWORD Status;
- DWORD cJobs;
- DWORD AveragePPM;
-} PRINTER_INFO_2W, *PPRINTER_INFO_2W, *LPPRINTER_INFO_2W;
-
-typedef struct _PRINTER_INFO_3 {
- PSECURITY_DESCRIPTOR pSecurityDescriptor;
-} PRINTER_INFO_3, *PPRINTER_INFO_3, *LPPRINTER_INFO_3;
-
-typedef struct _PRINTER_INFO_4A {
- LPSTR pPrinterName;
- LPSTR pServerName;
- DWORD Attributes;
-} PRINTER_INFO_4A, *PPRINTER_INFO_4A, *LPPRINTER_INFO_4A;
-
-typedef struct _PRINTER_INFO_4W {
- LPWSTR pPrinterName;
- LPWSTR pServerName;
- DWORD Attributes;
-} PRINTER_INFO_4W, *PPRINTER_INFO_4W, *LPPRINTER_INFO_4W;
-
-typedef struct _PRINTER_INFO_5A {
- LPSTR pPrinterName;
- LPSTR pPortName;
- DWORD Attributes;
- DWORD DeviceNotSelectedTimeout;
- DWORD TransmissionRetryTimeout;
-} PRINTER_INFO_5A, *PPRINTER_INFO_5A, *LPPRINTER_INFO_5A;
-
-typedef struct _PRINTER_INFO_5W {
- LPWSTR pPrinterName;
- LPWSTR pPortName;
- DWORD Attributes;
- DWORD DeviceNotSelectedTimeout;
- DWORD TransmissionRetryTimeout;
-} PRINTER_INFO_5W, *PPRINTER_INFO_5W, *LPPRINTER_INFO_5W;
-
-typedef struct _PRINTER_INFO_6 {
- DWORD dwStatus;
-} PRINTER_INFO_6, *PPRINTER_INFO_6, *LPPRINTER_INFO_6;
-
-typedef struct _PRINTER_INFO_7A {
- LPSTR pszObjectGUID;
- DWORD dwAction;
-} PRINTER_INFO_7A, *PPRINTER_INFO_7A, *LPPRINTER_INFO_7A;
-
-typedef struct _PRINTER_INFO_7W {
- LPWSTR pszObjectGUID;
- DWORD dwAction;
-} PRINTER_INFO_7W, *PPRINTER_INFO_7W, *LPPRINTER_INFO_7W;
-
-typedef struct _PRINTER_INFO_8A {
- LPDEVMODEA pDevMode;
-} PRINTER_INFO_8A, *PPRINTER_INFO_8A, *LPPRINTER_INFO_8A;
-
-typedef struct _PRINTER_INFO_8W {
- LPDEVMODEW pDevMode;
-} PRINTER_INFO_8W, *PPRINTER_INFO_8W, *LPPRINTER_INFO_8W;
-
-typedef struct _PRINTER_INFO_9A {
- LPDEVMODEA pDevMode;
-} PRINTER_INFO_9A, *PPRINTER_INFO_9A, *LPPRINTER_INFO_9A;
-
-typedef struct _PRINTER_INFO_9W {
- LPDEVMODEW pDevMode;
-} PRINTER_INFO_9W, *PPRINTER_INFO_9W, *LPPRINTER_INFO_9W;
-
-typedef struct _PRINTPROCESSOR_INFO_1A {
- LPSTR pName;
-} PRINTPROCESSOR_INFO_1A, *PPRINTPROCESSOR_INFO_1A, *LPPRINTPROCESSOR_INFO_1A;
-
-typedef struct _PRINTPROCESSOR_INFO_1W {
- LPWSTR pName;
-} PRINTPROCESSOR_INFO_1W, *PPRINTPROCESSOR_INFO_1W, *LPPRINTPROCESSOR_INFO_1W;
-
-typedef struct _PRINTER_NOTIFY_INFO_DATA {
- WORD Type;
- WORD Field;
- DWORD Reserved;
- DWORD Id;
- union {
- DWORD adwData[2];
- struct {
- DWORD cbBuf;
- PVOID pBuf;
- } Data;
- } NotifyData;
-} PRINTER_NOTIFY_INFO_DATA, *PPRINTER_NOTIFY_INFO_DATA, *LPPRINTER_NOTIFY_INFO_DATA;
-
-typedef struct _PRINTER_NOTIFY_INFO {
- DWORD Version;
- DWORD Flags;
- DWORD Count;
- PRINTER_NOTIFY_INFO_DATA aData[1];
-} PRINTER_NOTIFY_INFO, *PPRINTER_NOTIFY_INFO, *LPPRINTER_NOTIFY_INFO;
-
-typedef struct _FORM_INFO_1A {
- DWORD Flags;
- LPSTR pName;
- SIZEL Size;
- RECTL ImageableArea;
-} FORM_INFO_1A, *PFORM_INFO_1A, *LPFORM_INFO_1A;
-
-typedef struct _FORM_INFO_1W {
- DWORD Flags;
- LPWSTR pName;
- SIZEL Size;
- RECTL ImageableArea;
-} FORM_INFO_1W, *PFORM_INFO_1W, *LPFORM_INFO_1W;
-
-#if (NTDDI_VERSION >= NTDDI_VISTA)
+typedef struct _DRIVER_INFO_8A {
+ DWORD cVersion;
+ LPSTR pName;
+ LPSTR pEnvironment;
+ LPSTR pDriverPath;
+ LPSTR pDataFile;
+ LPSTR pConfigFile;
+ LPSTR pHelpFile;
+ LPSTR pDependentFiles;
+ LPSTR pMonitorName;
+ LPSTR pDefaultDataType;
+ LPSTR pszzPreviousNames;
+ FILETIME ftDriverDate;
+ DWORDLONG dwlDriverVersion;
+ LPSTR pszMfgName;
+ LPSTR pszOEMUrl;
+ LPSTR pszHardwareID;
+ LPSTR pszProvider;
+ LPSTR pszPrintProcessor;
+ LPSTR pszVendorSetup;
+ LPSTR pszzColorProfiles;
+ LPSTR pszInfPath;
+ DWORD dwPrinterDriverAttributes;
+ LPSTR pszzCoreDriverDependencies;
+ FILETIME ftMinInboxDriverVerDate;
+ DWORDLONG dwlMinInboxDriverVerVersion;
+} DRIVER_INFO_8A, *PDRIVER_INFO_8A, *LPDRIVER_INFO_8A;
typedef struct _FORM_INFO_2A {
- DWORD Flags;
- LPCSTR pName;
- SIZEL Size;
- RECTL ImageableArea;
- LPCSTR pKeyword;
- DWORD StringType;
- LPCSTR pMuiDll;
- DWORD dwResourceId;
- LPCSTR pDisplayName;
- LANGID wLangId;
-} FORM_INFO_2A, *PFORM_INFO_2A, *LPFORM_INFO_2A;
+ DWORD Flags;
+ LPSTR pName;
+ SIZEL Size;
+ RECTL ImageableArea;
+ LPCSTR pKeyword;
+ DWORD StringType;
+ LPCSTR pMuiDll;
+ DWORD dwResourceId;
+ LPCSTR pDisplayName;
+ LANGID wLangId;
+} FORM_INFO_2A, *PFORM_INFO_2A;
typedef struct _FORM_INFO_2W {
- DWORD Flags;
- LPCWSTR pName;
- SIZEL Size;
- RECTL ImageableArea;
- LPCSTR pKeyword;
- DWORD StringType;
+ DWORD Flags;
+ LPWSTR pName;
+ SIZEL Size;
+ RECTL ImageableArea;
+ LPCSTR pKeyword;
+ DWORD StringType;
LPCWSTR pMuiDll;
- DWORD dwResourceId;
+ DWORD dwResourceId;
LPCWSTR pDisplayName;
- LANGID wLangId;
-} FORM_INFO_2W, *PFORM_INFO_2W, *LPFORM_INFO_2W;
-
-#endif /* (NTDDI_VERSION >= NTDDI_VISTA) */
-
-typedef struct _PRINTER_DEFAULTSA {
- LPSTR pDatatype;
- LPDEVMODE pDevMode;
- ACCESS_MASK DesiredAccess;
-} PRINTER_DEFAULTSA, *PPRINTER_DEFAULTSA, *LPPRINTER_DEFAULTSA;
-
-typedef struct _PRINTER_DEFAULTSW {
- LPWSTR pDatatype;
- LPDEVMODE pDevMode;
- ACCESS_MASK DesiredAccess;
-} PRINTER_DEFAULTSW, *PPRINTER_DEFAULTSW, *LPPRINTER_DEFAULTSW;
-
-typedef struct _PROVIDOR_INFO_1A {
- LPSTR pName;
- LPSTR pEnvironment;
- LPSTR pDLLName;
-} PROVIDOR_INFO_1A, *PPROVIDOR_INFO_1A, *LPPROVIDOR_INFO_1A;
-
-typedef struct _PROVIDOR_INFO_1W {
- LPWSTR pName;
- LPWSTR pEnvironment;
- LPWSTR pDLLName;
-} PROVIDOR_INFO_1W, *LPPROVIDOR_INFO_1W;
-
-typedef struct _PROVIDOR_INFO_2A {
- LPSTR pOrder;
-} PROVIDOR_INFO_2A, *PPROVIDOR_INFO_2A, *LPPROVIDOR_INFO_2A;
-
-typedef struct _PROVIDOR_INFO_2W {
- LPWSTR pOrder;
-} PROVIDOR_INFO_2W, *LPPROVIDOR_INFO_2W;
-
-typedef struct _BINARY_CONTAINER {
- DWORD cbBuf;
- LPBYTE pData;
-} BINARY_CONTAINER, *PBINARY_CONTAINER;
-
-typedef struct _BIDI_DATA {
- DWORD dwBidiType;
- union {
- BOOL bData;
- INT iData;
- LPWSTR sData;
- FLOAT fData;
- BINARY_CONTAINER biData;
- } u;
-} BIDI_DATA, *LPBIDI_DATA, *PBIDI_DATA;
-
-typedef struct _BIDI_REQUEST_DATA {
- DWORD dwReqNumber;
- LPWSTR pSchema;
- BIDI_DATA data;
-} BIDI_REQUEST_DATA, *LPBIDI_REQUEST_DATA, *PBIDI_REQUEST_DATA;
-
-typedef struct _BIDI_REQUEST_CONTAINER {
- DWORD Version;
- DWORD Flags;
- DWORD Count;
- BIDI_REQUEST_DATA aData[1];
-} BIDI_REQUEST_CONTAINER, *LPBIDI_REQUEST_CONTAINER, *PBIDI_REQUEST_CONTAINER;
-
-typedef struct _BIDI_RESPONSE_DATA {
- DWORD dwResult;
- DWORD dwReqNumber;
- LPWSTR pSchema;
- BIDI_DATA data;
-} BIDI_RESPONSE_DATA, *LPBIDI_RESPONSE_DATA, *PBIDI_RESPONSE_DATA;
-
-typedef struct _BIDI_RESPONSE_CONTAINER {
- DWORD Version;
- DWORD Flags;
- DWORD Count;
- BIDI_RESPONSE_DATA aData[1];
-} BIDI_RESPONSE_CONTAINER, *LPBIDI_RESPONSE_CONTAINER, *PBIDI_RESPONSE_CONTAINER;
-
-#ifdef UNICODE
-
-typedef JOB_INFO_1W JOB_INFO_1, *PJOB_INFO_1, *LPJOB_INFO_1;
-typedef JOB_INFO_2W JOB_INFO_2, *PJOB_INFO_2, *LPJOB_INFO_2;
-typedef JOB_INFO_4W JOB_INFO_4, *PJOB_INFO_4, *LPJOB_INFO_4;
-typedef ADDJOB_INFO_1W ADDJOB_INFO_1, *PADDJOB_INFO_1, *LPADDJOB_INFO_1;
-typedef DATATYPES_INFO_1W DATATYPES_INFO_1, *PDATATYPES_INFO_1, *LPDATATYPES_INFO_1;
-typedef MONITOR_INFO_1W MONITOR_INFO_1, *PMONITOR_INFO_1, *LPMONITOR_INFO_1;
-typedef MONITOR_INFO_2W MONITOR_INFO_2, *PMONITOR_INFO_2, *LPMONITOR_INFO_2;
-typedef DOC_INFO_1W DOC_INFO_1, *PDOC_INFO_1, *LPDOC_INFO_1;
-typedef DOC_INFO_2W DOC_INFO_2, *PDOC_INFO_2, *LPDOC_INFO_2;
-typedef PORT_INFO_1W PORT_INFO_1, *PPORT_INFO_1, *LPPORT_INFO_1;
-typedef PORT_INFO_2W PORT_INFO_2, *PPORT_INFO_2, *LPPORT_INFO_2;
-typedef PORT_INFO_3W PORT_INFO_3, *PPORT_INFO_3, *LPPORT_INFO_3;
-typedef DRIVER_INFO_2W DRIVER_INFO_2, *PDRIVER_INFO_2, *LPDRIVER_INFO_2;
-typedef DRIVER_INFO_4W DRIVER_INFO_4, *PDRIVER_INFO_4, *LPDRIVER_INFO_4;
-typedef DRIVER_INFO_5W DRIVER_INFO_5, *PDRIVER_INFO_5, *LPDRIVER_INFO_5;
-typedef DRIVER_INFO_6W DRIVER_INFO_6, *PDRIVER_INFO_6, *LPDRIVER_INFO_6;
-typedef DRIVER_INFO_8W DRIVER_INFO_8, *PDRIVER_INFO_8, *LPDRIVER_INFO_8;
-typedef PRINTER_INFO_1W PRINTER_INFO_1, *PPRINTER_INFO_1, *LPPRINTER_INFO_1;
-typedef PRINTER_INFO_2W PRINTER_INFO_2, *PPRINTER_INFO_2, *LPPRINTER_INFO_2;
-typedef PRINTER_INFO_4W PRINTER_INFO_4, *PPRINTER_INFO_4, *LPPRINTER_INFO_4;
-typedef PRINTER_INFO_5W PRINTER_INFO_5, *PPRINTER_INFO_5, *LPPRINTER_INFO_5;
-typedef PRINTER_INFO_7W PRINTER_INFO_7, *PPRINTER_INFO_7, *LPPRINTER_INFO_7;
-typedef PRINTER_INFO_8W PRINTER_INFO_8, *PPRINTER_INFO_8, *LPPRINTER_INFO_8;
-typedef PRINTER_INFO_9W PRINTER_INFO_9, *PPRINTER_INFO_9, *LPPRINTER_INFO_9;
-typedef PRINTPROCESSOR_INFO_1W PRINTPROCESSOR_INFO_1, *PPRINTPROCESSOR_INFO_1, *LPPRINTPROCESSOR_INFO_1;
-typedef FORM_INFO_1W FORM_INFO_1, *PFORM_INFO_1, *LPFORM_INFO_1;
-#if (NTDDI_VERSION >= NTDDI_VISTA)
-typedef FORM_INFO_2W FORM_INFO_2, *PFORM_INFO_2, *LPFORM_INFO_2;
-#endif
-typedef PRINTER_DEFAULTSW PRINTER_DEFAULTS, *PPRINTER_DEFAULTS, *LPPRINTER_DEFAULTS;
-typedef PROVIDOR_INFO_1W PROVIDOR_INFO_1, *PPROVIDOR_INFO_1, *LPPROVIDOR_INFO_1;
-typedef PROVIDOR_INFO_2W PROVIDOR_INFO_2, *PPROVIDOR_INFO_2, *LPPROVIDOR_INFO_2;
-
-#else /* UNICODE */
-
-typedef JOB_INFO_1A JOB_INFO_1, *PJOB_INFO_1, *LPJOB_INFO_1;
-typedef JOB_INFO_2A JOB_INFO_2, *PJOB_INFO_2, *LPJOB_INFO_2;
-typedef JOB_INFO_4A JOB_INFO_4, *PJOB_INFO_4, *LPJOB_INFO_4;
-typedef ADDJOB_INFO_1A ADDJOB_INFO_1, *PADDJOB_INFO_1, *LPADDJOB_INFO_1;
-typedef DATATYPES_INFO_1A DATATYPES_INFO_1, *PDATATYPES_INFO_1, *LPDATATYPES_INFO_1;
-typedef MONITOR_INFO_1A MONITOR_INFO_1, *PMONITOR_INFO_1, *LPMONITOR_INFO_1;
-typedef MONITOR_INFO_2A MONITOR_INFO_2, *PMONITOR_INFO_2, *LPMONITOR_INFO_2;
-typedef DOC_INFO_1A DOC_INFO_1, *PDOC_INFO_1, *LPDOC_INFO_1;
-typedef DOC_INFO_2A DOC_INFO_2, *PDOC_INFO_2, *LPDOC_INFO_2;
-typedef PORT_INFO_1A PORT_INFO_1, *PPORT_INFO_1, *LPPORT_INFO_1;
-typedef PORT_INFO_2A PORT_INFO_2, *PPORT_INFO_2, *LPPORT_INFO_2;
-typedef PORT_INFO_3A PORT_INFO_3, *PPORT_INFO_3, *LPPORT_INFO_3;
-typedef DRIVER_INFO_2A DRIVER_INFO_2, *PDRIVER_INFO_2, *LPDRIVER_INFO_2;
-typedef DRIVER_INFO_4A DRIVER_INFO_4, *PDRIVER_INFO_4, *LPDRIVER_INFO_4;
-typedef DRIVER_INFO_5A DRIVER_INFO_5, *PDRIVER_INFO_5, *LPDRIVER_INFO_5;
-typedef DRIVER_INFO_6A DRIVER_INFO_6, *PDRIVER_INFO_6, *LPDRIVER_INFO_6;
-typedef DRIVER_INFO_8A DRIVER_INFO_8, *PDRIVER_INFO_8, *LPDRIVER_INFO_8;
-typedef PRINTER_INFO_1A PRINTER_INFO_1, *PPRINTER_INFO_1, *LPPRINTER_INFO_1;
-typedef PRINTER_INFO_2A PRINTER_INFO_2, *PPRINTER_INFO_2, *LPPRINTER_INFO_2;
-typedef PRINTER_INFO_4A PRINTER_INFO_4, *PPRINTER_INFO_4, *LPPRINTER_INFO_4;
-typedef PRINTER_INFO_5A PRINTER_INFO_5, *PPRINTER_INFO_5, *LPPRINTER_INFO_5;
-typedef PRINTER_INFO_7A PRINTER_INFO_7, *PPRINTER_INFO_7, *LPPRINTER_INFO_7;
-typedef PRINTER_INFO_8A PRINTER_INFO_8, *PPRINTER_INFO_8, *LPPRINTER_INFO_8;
-typedef PRINTER_INFO_9A PRINTER_INFO_9, *PPRINTER_INFO_9, *LPPRINTER_INFO_9;
-typedef PRINTPROCESSOR_INFO_1A PRINTPROCESSOR_INFO_1, *PPRINTPROCESSOR_INFO_1, *LPPRINTPROCESSOR_INFO_1;
-typedef FORM_INFO_1A FORM_INFO_1, *PFORM_INFO_1, *LPFORM_INFO_1;
-#if (NTDDI_VERSION >= NTDDI_VISTA)
-typedef FORM_INFO_2A FORM_INFO_2, *PFORM_INFO_2, *LPFORM_INFO_2;
-#endif
-typedef PRINTER_DEFAULTSA PRINTER_DEFAULTS, *PPRINTER_DEFAULTS, *LPPRINTER_DEFAULTS;
-typedef PROVIDOR_INFO_1A PROVIDOR_INFO_1, *PPROVIDOR_INFO_1, *LPPROVIDOR_INFO_1;
-typedef PROVIDOR_INFO_2A PROVIDOR_INFO_2, *PPROVIDOR_INFO_2, *LPPROVIDOR_INFO_2;
-
-#endif /* UNICODE */
-
-BOOL WINAPI AbortPrinter(_In_ HANDLE);
-
-BOOL
-WINAPI
-AddFormA(
- _In_ HANDLE hPrinter,
- _In_range_(1, 2) DWORD Level,
- _When_(Level == 1, _In_reads_bytes_(sizeof(FORM_INFO_1A)))
-#if (NTDDI_VERSION >= NTDDI_VISTA)
- _When_(Level == 2, _In_reads_bytes_(sizeof(FORM_INFO_2A)))
-#endif
- LPBYTE pForm);
-
-BOOL
-WINAPI
-AddFormW(
- _In_ HANDLE hPrinter,
- _In_range_(1, 2) DWORD Level,
- _When_(Level == 1, _In_reads_bytes_(sizeof(FORM_INFO_1W)))
-#if (NTDDI_VERSION >= NTDDI_VISTA)
- _When_(Level == 2, _In_reads_bytes_(sizeof(FORM_INFO_2W)))
-#endif
- LPBYTE pForm);
-
-BOOL
-WINAPI
-AddJobA(
- _In_ HANDLE hPrinter,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pData,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded);
-
-BOOL
-WINAPI
-AddJobW(
- _In_ HANDLE hPrinter,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pData,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded);
-
-BOOL
-WINAPI
-AddMonitorA(
- _In_opt_ LPSTR pName,
- _In_ DWORD Level,
- _In_reads_bytes_opt_(sizeof(MONITOR_INFO_2)) LPBYTE pMonitors);
-
-BOOL
-WINAPI
-AddMonitorW(
- _In_opt_ LPWSTR pName,
- _In_ DWORD Level,
- _In_reads_bytes_opt_(sizeof(MONITOR_INFO_2)) LPBYTE pMonitors);
-
-BOOL WINAPI AddPortA(_In_opt_ LPSTR, _In_ HWND, _In_ LPSTR);
-BOOL WINAPI AddPortW(_In_opt_ LPWSTR, _In_ HWND, _In_ LPWSTR);
-
-HANDLE
-WINAPI
-AddPrinterA(
- _In_opt_ LPSTR pName,
- _In_range_(1, 2) DWORD Level,
- _When_(Level == 1, _In_reads_bytes_(sizeof(PRINTER_INFO_1)))
- _When_(Level == 2, _In_reads_bytes_(sizeof(PRINTER_INFO_2)))
- LPBYTE pPrinter);
-
-HANDLE
-WINAPI
-AddPrinterW(
- _In_opt_ LPWSTR pName,
- _In_range_(1, 2) DWORD Level,
- _When_(Level == 1, _In_reads_bytes_(sizeof(PRINTER_INFO_1)))
- _When_(Level == 2, _In_reads_bytes_(sizeof(PRINTER_INFO_2)))
- LPBYTE pPrinter);
-
-BOOL WINAPI AddPrinterConnectionA(_In_ LPSTR);
-BOOL WINAPI AddPrinterConnectionW(_In_ LPWSTR);
-BOOL WINAPI AddPrinterDriverA(_In_opt_ LPSTR, _In_ DWORD, _In_ PBYTE);
-BOOL WINAPI AddPrinterDriverW(_In_opt_ LPWSTR, _In_ DWORD, _In_ PBYTE);
-
-BOOL
-WINAPI
-AddPrintProcessorA(
- _In_opt_ LPSTR pName,
- _In_opt_ LPSTR pEnvironment,
- _In_ LPSTR pPathName,
- _In_ LPSTR pPrintProcessorName);
-
-BOOL
-WINAPI
-AddPrintProcessorW(
- _In_opt_ LPWSTR pName,
- _In_opt_ LPWSTR pEnvironment,
- _In_ LPWSTR pPathName,
- _In_ LPWSTR pPrintProcessorName);
-
-BOOL
-WINAPI
-AddPrintProvidorA(
- _In_opt_ LPSTR pName,
- _In_range_(1, 2) DWORD Level,
- _When_(Level == 1, _In_reads_bytes_(sizeof(PROVIDOR_INFO_1)))
- _When_(Level == 2, _In_reads_bytes_(sizeof(PROVIDOR_INFO_2)))
- LPBYTE pProvidorInfo);
-
-BOOL
-WINAPI
-AddPrintProvidorW(
- _In_opt_ LPWSTR pName,
- _In_range_(1, 2) DWORD Level,
- _When_(Level == 1, _In_reads_bytes_(sizeof(PROVIDOR_INFO_1)))
- _When_(Level == 2, _In_reads_bytes_(sizeof(PROVIDOR_INFO_2)))
- LPBYTE pProvidorInfo);
-
-LONG
-WINAPI
-AdvancedDocumentPropertiesA(
- _In_ HWND hWnd,
- _In_ HANDLE hPrinter,
- _In_ LPSTR pDeviceName,
- _Inout_opt_ PDEVMODEA pDevModeOutput,
- _In_opt_ PDEVMODEA pDevModeInput);
-
-LONG
-WINAPI
-AdvancedDocumentPropertiesW(
- _In_ HWND hWnd,
- _In_ HANDLE hPrinter,
- _In_ LPWSTR pDeviceName,
- _Inout_opt_ PDEVMODEW pDevModeOutput,
- _In_opt_ PDEVMODEW pDevModeInput);
-
-BOOL WINAPI ClosePrinter(_In_ HANDLE);
-BOOL WINAPI ConfigurePortA(_In_opt_ LPSTR, _In_ HWND, _In_ LPSTR);
-BOOL WINAPI ConfigurePortW(_In_opt_ LPWSTR, _In_ HWND, _In_ LPWSTR);
-HANDLE WINAPI ConnectToPrinterDlg(_In_ HWND, _In_ DWORD);
-BOOL WINAPI DeleteFormA(_In_ HANDLE, _In_ LPSTR);
-BOOL WINAPI DeleteFormW(_In_ HANDLE, _In_ LPWSTR);
-BOOL WINAPI DeleteMonitorA(_In_opt_ LPSTR, _In_opt_ LPSTR, _In_ LPSTR);
-BOOL WINAPI DeleteMonitorW(_In_opt_ LPWSTR, _In_opt_ LPWSTR, _In_ LPWSTR);
-BOOL WINAPI DeletePortA(_In_opt_ LPSTR, _In_ HWND, _In_ LPSTR);
-BOOL WINAPI DeletePortW(_In_opt_ LPWSTR, _In_ HWND, _In_ LPWSTR);
-BOOL WINAPI DeletePrinter(_Inout_ HANDLE);
-BOOL WINAPI DeletePrinterConnectionA(_In_ LPSTR);
-BOOL WINAPI DeletePrinterConnectionW(_In_ LPWSTR);
-DWORD WINAPI DeletePrinterDataA(_In_ HANDLE, _In_ LPSTR);
-DWORD WINAPI DeletePrinterDataW(_In_ HANDLE, _In_ LPWSTR);
-
-BOOL
-WINAPI
-DeletePrinterDriverA(
- _In_opt_ LPSTR pName,
- _In_opt_ LPSTR pEnvironment,
- _In_ LPSTR pDriverName);
-
-BOOL
-WINAPI
-DeletePrinterDriverW(
- _In_opt_ LPWSTR pName,
- _In_opt_ LPWSTR pEnvironment,
- _In_ LPWSTR pDriverName);
-
-BOOL
-WINAPI
-DeletePrintProcessorA(
- _In_opt_ LPSTR pName,
- _In_opt_ LPSTR pEnvironment,
- _In_ LPSTR pPrintProcessorName);
-
-BOOL
-WINAPI
-DeletePrintProcessorW(
- _In_opt_ LPWSTR pName,
- _In_opt_ LPWSTR pEnvironment,
- _In_ LPWSTR pPrintProcessorName);
-
-BOOL
-WINAPI
-DeletePrintProvidorA(
- _In_opt_ LPSTR pName,
- _In_opt_ LPSTR pEnvironment,
- _In_ LPSTR pPrintProvidorName);
-
-BOOL
-WINAPI
-DeletePrintProvidorW(
- _In_opt_ LPWSTR pName,
- _In_opt_ LPWSTR pEnvironment,
- _In_ LPWSTR pPrintProvidorName);
-
-LONG
-WINAPI
-DocumentPropertiesA(
- _In_opt_ HWND hWnd,
- _In_ HANDLE hPrinter,
- _In_ LPSTR pDeviceName,
- _Out_opt_ PDEVMODEA pDevModeOutput,
- _In_opt_ PDEVMODEA pDevModeInput,
- _In_ DWORD fMode);
-
-LONG
-WINAPI
-DocumentPropertiesW(
- _In_opt_ HWND hWnd,
- _In_ HANDLE hPrinter,
- _In_ LPWSTR pDeviceName,
- _Out_opt_ PDEVMODEW pDevModeOutput,
- _In_opt_ PDEVMODEW pDevModeInput,
- _In_ DWORD fMode);
-
-BOOL WINAPI EndDocPrinter(_In_ HANDLE);
-BOOL WINAPI EndPagePrinter(_In_ HANDLE);
-
-BOOL
-WINAPI
-EnumFormsA(
- _In_ HANDLE hPrinter,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pForm,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded,
- _Out_ LPDWORD pcReturned);
-
-BOOL
-WINAPI
-EnumFormsW(
- _In_ HANDLE hPrinter,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pForm,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded,
- _Out_ LPDWORD pcReturned);
-
-BOOL
-WINAPI
-EnumJobsA(
- _In_ HANDLE hPrinter,
- _In_ DWORD FirstJob,
- _In_ DWORD NoJobs,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pJob,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded,
- _Out_ LPDWORD pcReturned);
-
-BOOL
-WINAPI
-EnumJobsW(
- _In_ HANDLE hPrinter,
- _In_ DWORD FirstJob,
- _In_ DWORD NoJobs,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pJob,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded,
- _Out_ LPDWORD pcReturned);
-
-BOOL
-WINAPI
-EnumMonitorsA(
- _In_opt_ LPSTR pName,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pMonitor,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded,
- _Out_ LPDWORD pcReturned);
-
-BOOL
-WINAPI
-EnumMonitorsW(
- _In_opt_ LPWSTR pName,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pMonitor,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded,
- _Out_ LPDWORD pcReturned);
-
-BOOL
-WINAPI
-EnumPortsA(
- _In_opt_ LPSTR pName,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pPort,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded,
- _Out_ LPDWORD pcReturned);
-
-BOOL
-WINAPI
-EnumPortsW(
- _In_opt_ LPWSTR pName,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pPort,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded,
- _Out_ LPDWORD pcReturned);
-
-DWORD
-WINAPI
-EnumPrinterDataA(
- _In_ HANDLE hPrinter,
- _In_ DWORD dwIndex,
- _Out_writes_bytes_(cbValueName) LPSTR pValueName,
- _In_ DWORD cbValueName,
- _Out_ LPDWORD pcbValueName,
- _Out_opt_ LPDWORD pType,
- _Out_writes_to_opt_(cbData, *pcbData) LPBYTE pData,
- _In_ DWORD cbData,
- _When_(pData != NULL, _Pre_notnull_) _Out_opt_ LPDWORD pcbData);
-
-DWORD
-WINAPI
-EnumPrinterDataW(
- _In_ HANDLE hPrinter,
- _In_ DWORD dwIndex,
- _Out_writes_bytes_(cbValueName) LPWSTR pValueName,
- _In_ DWORD cbValueName,
- _Out_ LPDWORD pcbValueName,
- _Out_opt_ LPDWORD pType,
- _Out_writes_to_opt_(cbData, *pcbData) LPBYTE pData,
- _In_ DWORD cbData,
- _When_(pData != NULL, _Pre_notnull_) _Out_opt_ LPDWORD pcbData);
-
-BOOL
-WINAPI
-EnumPrinterDriversA(
- _In_opt_ LPSTR pName,
- _In_opt_ LPSTR pEnvironment,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pDriverInfo,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded,
- _Out_ LPDWORD pcReturned);
-
-BOOL
-WINAPI
-EnumPrinterDriversW(
- _In_opt_ LPWSTR pName,
- _In_opt_ LPWSTR pEnvironment,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pDriverInfo,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded,
- _Out_ LPDWORD pcReturned);
-
-_Success_(return != 0)
-BOOL
-WINAPI
-EnumPrintersA(
- _In_ DWORD Flags,
- _In_opt_ LPSTR Name,
- _In_ DWORD Level,
- _Out_writes_bytes_to_opt_(cbBuf, *pcbNeeded) LPBYTE pPrinterEnum,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded,
- _Out_ LPDWORD pcReturned);
-
-_Success_(return != 0)
-BOOL
-WINAPI
-EnumPrintersW(
- _In_ DWORD Flags,
- _In_opt_ LPWSTR Name,
- _In_ DWORD Level,
- _Out_writes_bytes_to_opt_(cbBuf, *pcbNeeded) LPBYTE pPrinterEnum,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded,
- _Out_ LPDWORD pcReturned);
-
-_Success_(return != 0)
-BOOL
-WINAPI
-EnumPrintProcessorDatatypesA(
- _In_opt_ LPSTR pName,
- _In_ LPSTR pPrintProcessorName,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pDatatypes,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded,
- _Out_ LPDWORD pcReturned);
-
-_Success_(return != 0)
-BOOL
-WINAPI
-EnumPrintProcessorDatatypesW(
- _In_opt_ LPWSTR pName,
- _In_ LPWSTR pPrintProcessorName,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pDatatypes,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded,
- _Out_ LPDWORD pcReturned);
-
-BOOL
-WINAPI
-EnumPrintProcessorsA(
- _In_opt_ LPSTR pName,
- _In_opt_ LPSTR pEnvironment,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pPrintProcessorInfo,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded,
- _Out_ LPDWORD pcReturned);
-
-BOOL
-WINAPI
-EnumPrintProcessorsW(
- _In_opt_ LPWSTR pName,
- _In_opt_ LPWSTR pEnvironment,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pPrintProcessorInfo,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded,
- _Out_ LPDWORD pcReturned);
-
-LONG
-WINAPI
-ExtDeviceMode(
- _In_opt_ HWND hWnd,
- _In_opt_ HANDLE hInst,
- _Inout_opt_ LPDEVMODEA pDevModeOutput,
- _In_opt_ LPSTR pDeviceName,
- _In_opt_ LPSTR pPort,
- _In_opt_ LPDEVMODEA pDevModeInput,
- _In_opt_ LPSTR pProfile,
- _In_ DWORD fMode);
-
-BOOL WINAPI FindClosePrinterChangeNotification(_In_ HANDLE);
-
-HANDLE
-WINAPI
-FindFirstPrinterChangeNotification(
- _In_ HANDLE hPrinter,
- DWORD fdwFilter,
- DWORD fdwOptions,
- _In_opt_ PVOID pPrinterNotifyOptions);
-
-BOOL
-WINAPI
-FindNextPrinterChangeNotification(
- _In_ HANDLE hChange,
- _Out_opt_ PDWORD pdwChange,
- _In_opt_ LPVOID pvReserved,
- _Out_opt_ LPVOID *ppPrinterNotifyInfo);
-
-BOOL WINAPI FreePrinterNotifyInfo(_In_ PPRINTER_NOTIFY_INFO);
-
-#if _WIN32_WINNT >= 0x0500
-
-BOOL
-WINAPI
-GetDefaultPrinterA(
- _Out_writes_opt_(*pcchBuffer) LPSTR pszBuffer,
- _Inout_ LPDWORD pcchBuffer);
-
-BOOL
-WINAPI
-GetDefaultPrinterW(
- _Out_writes_opt_(*pcchBuffer) LPWSTR pszBuffer,
- _Inout_ LPDWORD pcchBuffer);
-
-#endif
-
-BOOL
-WINAPI
-GetFormA(
- _In_ HANDLE hPrinter,
- _In_ LPSTR pFormName,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pForm,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded);
-
-BOOL
-WINAPI
-GetFormW(
- _In_ HANDLE hPrinter,
- _In_ LPWSTR pFormName,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pForm,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded);
-
-BOOL
-WINAPI
-GetJobA(
- _In_ HANDLE hPrinter,
- _In_ DWORD JobId,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pJob,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded);
-
-BOOL
-WINAPI
-GetJobW(
- _In_ HANDLE hPrinter,
- _In_ DWORD JobId,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pJob,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded);
-
-BOOL
-WINAPI
-GetPrinterA(
- _In_ HANDLE hPrinter,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pPrinter,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded);
-
-BOOL
-WINAPI
-GetPrinterW(
- _In_ HANDLE hPrinter,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pPrinter,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded);
-
-DWORD
-WINAPI
-GetPrinterDataA(
- _In_ HANDLE hPrinter,
- _In_ LPSTR pValueName,
- _Out_opt_ LPDWORD pType,
- _Out_writes_bytes_opt_(nSize) LPBYTE pData,
- _In_ DWORD nSize,
- _Out_ LPDWORD pcbNeeded);
-
-DWORD
-WINAPI
-GetPrinterDataW(
- _In_ HANDLE hPrinter,
- _In_ LPWSTR pValueName,
- _Out_opt_ LPDWORD pType,
- _Out_writes_bytes_opt_(nSize) LPBYTE pData,
- _In_ DWORD nSize,
- _Out_ LPDWORD pcbNeeded);
-
-BOOL
-WINAPI
-GetPrinterDriverA(
- _In_ HANDLE hPrinter,
- _In_opt_ LPSTR pEnvironment,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pDriverInfo,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded);
-
-BOOL
-WINAPI
-GetPrinterDriverW(
- _In_ HANDLE hPrinter,
- _In_opt_ LPWSTR pEnvironment,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pDriverInfo,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded);
-
-BOOL
-WINAPI
-GetPrinterDriverDirectoryA(
- _In_opt_ LPSTR pName,
- _In_opt_ LPSTR pEnvironment,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pDriverDirectory,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded);
-
-BOOL
-WINAPI
-GetPrinterDriverDirectoryW(
- _In_opt_ LPWSTR pName,
- _In_opt_ LPWSTR pEnvironment,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pDriverDirectory,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded);
-
-BOOL
-WINAPI
-GetPrintProcessorDirectoryA(
- _In_opt_ LPSTR pName,
- _In_opt_ LPSTR pEnvironment,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pPrintProcessorInfo,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded);
-
-BOOL
-WINAPI
-GetPrintProcessorDirectoryW(
- _In_opt_ LPWSTR pName,
- _In_opt_ LPWSTR pEnvironment,
- _In_ DWORD Level,
- _Out_writes_bytes_opt_(cbBuf) LPBYTE pPrintProcessorInfo,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcbNeeded);
-
-#if NTDDI_VERSION >= NTDDI_WINXPSP2
-BOOL WINAPI IsValidDevmodeA(_In_opt_ PDEVMODEA, size_t);
-BOOL WINAPI IsValidDevmodeW(_In_opt_ PDEVMODEW, size_t);
-#endif
-
-BOOL
-WINAPI
-OpenPrinterA(
- _In_opt_ LPSTR pPrinterName,
- _Out_ LPHANDLE phPrinter,
- _In_opt_ LPPRINTER_DEFAULTSA pDefault);
-
-BOOL
-WINAPI
-OpenPrinterW(
- _In_opt_ LPWSTR pPrinterName,
- _Out_ LPHANDLE phPrinter,
- _In_opt_ LPPRINTER_DEFAULTSW pDefault);
-
-DWORD
-WINAPI
-PrinterMessageBoxA(
- _In_ HANDLE hPrinter,
- DWORD Error,
- _In_ HWND hWnd,
- _In_ LPSTR pText,
- _In_ LPSTR pCaption,
- DWORD dwType);
-
-DWORD
-WINAPI
-PrinterMessageBoxW(
- _In_ HANDLE hPrinter,
- DWORD Error,
- _In_ HWND hWnd,
- _In_ LPWSTR pText,
- _In_ LPWSTR pCaption,
- DWORD dwType);
-
-BOOL WINAPI PrinterProperties(_In_ HWND, _In_ HANDLE);
-
-BOOL
-WINAPI
-ReadPrinter(
- _In_ HANDLE hPrinter,
- _Out_writes_bytes_(cbBuf) LPVOID pBuf,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pNoBytesRead);
-
-BOOL WINAPI ResetPrinterA(_In_ HANDLE, _In_opt_ LPPRINTER_DEFAULTSA);
-BOOL WINAPI ResetPrinterW(_In_ HANDLE, _In_opt_ LPPRINTER_DEFAULTSW);
-BOOL WINAPI ScheduleJob(_In_ HANDLE, _In_ DWORD);
-
-BOOL
-WINAPI
-SetFormA(
- _In_ HANDLE hPrinter,
- _In_ LPSTR pFormName,
- _In_range_(1, 2) DWORD Level,
- _When_(Level == 1, _In_reads_bytes_(sizeof(FORM_INFO_1A))) LPBYTE pForm);
-
-BOOL
-WINAPI
-SetFormW(
- _In_ HANDLE hPrinter,
- _In_ LPWSTR pFormName,
- _In_range_(1, 2) DWORD Level,
- _When_(Level == 1, _In_reads_bytes_(sizeof(FORM_INFO_1W))) LPBYTE pForm);
-
-BOOL
-WINAPI
-SetJobA(
- _In_ HANDLE hPrinter,
- _In_ DWORD JobId,
- _In_range_(0, 4) DWORD Level,
- _When_(Level == 0, _Reserved_)
- _When_(Level == 1, _In_reads_bytes_opt_(sizeof(JOB_INFO_1)))
- _When_(Level == 2, _In_reads_bytes_opt_(sizeof(JOB_INFO_2)))
- _When_(Level == 3, _In_reads_bytes_opt_(sizeof(JOB_INFO_3)))
- _When_(Level == 4, _In_reads_bytes_opt_(sizeof(JOB_INFO_4)))
- LPBYTE pJob,
- _In_ DWORD Command);
-
-BOOL
-WINAPI
-SetJobW(
- _In_ HANDLE hPrinter,
- _In_ DWORD JobId,
- _In_range_(0, 4) DWORD Level,
- _When_(Level == 0, _Reserved_)
- _When_(Level == 1, _In_reads_bytes_opt_(sizeof(JOB_INFO_1)))
- _When_(Level == 2, _In_reads_bytes_opt_(sizeof(JOB_INFO_2)))
- _When_(Level == 3, _In_reads_bytes_opt_(sizeof(JOB_INFO_3)))
- _When_(Level == 4, _In_reads_bytes_opt_(sizeof(JOB_INFO_4)))
- LPBYTE pJob,
- _In_ DWORD Command);
-
-BOOL
-WINAPI
-SetPrinterA(
- _In_ HANDLE hPrinter,
- _In_range_(0, 9) DWORD Level,
- _When_(Level == 0 && Command == PRINTER_CONTROL_SET_STATUS, _In_reads_bytes_(sizeof(DWORD)))
- _When_(Level == 0 && Command != PRINTER_CONTROL_SET_STATUS, _In_opt_)
- _When_(Level == 1, _In_reads_bytes_(sizeof(PRINTER_INFO_1)))
- _When_(Level == 2, _In_reads_bytes_(sizeof(PRINTER_INFO_2)))
- _When_(Level == 3, _In_reads_bytes_(sizeof(PRINTER_INFO_3)))
- _When_(Level == 4, _In_reads_bytes_(sizeof(PRINTER_INFO_4)))
- _When_(Level == 5, _In_reads_bytes_(sizeof(PRINTER_INFO_5)))
- _When_(Level == 6, _In_reads_bytes_(sizeof(PRINTER_INFO_6)))
- _When_(Level == 7, _In_reads_bytes_(sizeof(PRINTER_INFO_7)))
- _When_(Level == 8, _In_reads_bytes_(sizeof(PRINTER_INFO_8)))
- _When_(Level == 9, _In_reads_bytes_(sizeof(PRINTER_INFO_9)))
- LPBYTE pPrinter,
- _In_ DWORD Command);
-
-BOOL
-WINAPI
-SetPrinterW(
- _In_ HANDLE hPrinter,
- _In_range_(0, 9) DWORD Level,
- _When_(Level == 0 && Command == PRINTER_CONTROL_SET_STATUS, _In_reads_bytes_(sizeof(DWORD)))
- _When_(Level == 0 && Command != PRINTER_CONTROL_SET_STATUS, _In_opt_)
- _When_(Level == 1, _In_reads_bytes_(sizeof(PRINTER_INFO_1)))
- _When_(Level == 2, _In_reads_bytes_(sizeof(PRINTER_INFO_2)))
- _When_(Level == 3, _In_reads_bytes_(sizeof(PRINTER_INFO_3)))
- _When_(Level == 4, _In_reads_bytes_(sizeof(PRINTER_INFO_4)))
- _When_(Level == 5, _In_reads_bytes_(sizeof(PRINTER_INFO_5)))
- _When_(Level == 6, _In_reads_bytes_(sizeof(PRINTER_INFO_6)))
- _When_(Level == 7, _In_reads_bytes_(sizeof(PRINTER_INFO_7)))
- _When_(Level == 8, _In_reads_bytes_(sizeof(PRINTER_INFO_8)))
- _When_(Level == 9, _In_reads_bytes_(sizeof(PRINTER_INFO_9)))
- LPBYTE pPrinter,
- _In_ DWORD Command);
-
-BOOL
-WINAPI
-SetPrinterDataA(
- _In_ HANDLE hPrinter,
- _In_ LPSTR pValueName,
- _In_ DWORD Type,
- _In_reads_bytes_(cbData) LPBYTE pData,
- _In_ DWORD cbData);
-
-BOOL
-WINAPI
-SetPrinterDataW(
- _In_ HANDLE hPrinter,
- _In_ LPWSTR pValueName,
- _In_ DWORD Type,
- _In_reads_bytes_(cbData) LPBYTE pData,
- _In_ DWORD cbData);
-
-#ifdef _WINE
-LPSTR WINAPI StartDocDlgA(HANDLE hPrinter, DOCINFOA *doc);
-LPWSTR WINAPI StartDocDlgW(HANDLE hPrinter, DOCINFOW *doc);
-#define StartDocDlg WINELIB_NAME_AW(StartDocDlg)
-#endif
+ LANGID wLangId;
+} FORM_INFO_2W, *PFORM_INFO_2W;
+
+__MINGW_TYPEDEF_AW(DRIVER_INFO_8)
+__MINGW_TYPEDEF_AW(PDRIVER_INFO_8)
+__MINGW_TYPEDEF_AW(LPDRIVER_INFO_8)
+__MINGW_TYPEDEF_AW(FORM_INFO_2)
+__MINGW_TYPEDEF_AW(PFORM_INFO_2)
+
+typedef struct _PRINTPROCESSOR_CAPS_2 {
+ DWORD dwLevel;
+ DWORD dwNupOptions;
+ DWORD dwPageOrderFlags;
+ DWORD dwNumberOfCopies;
+ DWORD dwNupDirectionCaps;
+ DWORD dwNupBorderCaps;
+ DWORD dwBookletHandlingCaps;
+ DWORD dwDuplexHandlingCaps;
+ DWORD dwScalingCaps;
+} PRINTPROCESSOR_CAPS_2, *PPRINTPROCESSOR_CAPS_2;
+
+HRESULT ReportJobProcessingProgress(
+ HANDLE printerHandle,
+ ULONG jobId,
+ EPrintXPSJobOperation jobOperation,
+ EPrintXPSJobProgress jobProgress
+);
+
+typedef struct _CORE_PRINTER_DRIVERA {
+ GUID CoreDriverGUID;
+ FILETIME ftDriverDate;
+ DWORDLONG dwlDriverVersion;
+ CHAR szPackageID[MAX_PATH];
+} CORE_PRINTER_DRIVERA, *PCORE_PRINTER_DRIVERA;
-DWORD
-WINAPI
-StartDocPrinterA(
- _In_ HANDLE hPrinter,
- _In_range_(1, 3) DWORD Level,
- _When_(Level == 1, _In_reads_bytes_(sizeof(DOC_INFO_1))) LPBYTE pDocInfo);
-
-DWORD
-WINAPI
-StartDocPrinterW(
- _In_ HANDLE hPrinter,
- _In_range_(1, 3) DWORD Level,
- _When_(Level == 1, _In_reads_bytes_(sizeof(DOC_INFO_1))) LPBYTE pDocInfo);
-
-BOOL WINAPI StartPagePrinter(_In_ HANDLE);
-DWORD WINAPI WaitForPrinterChange(_In_ HANDLE, _In_ DWORD);
-
-BOOL
-WINAPI
-WritePrinter(
- _In_ HANDLE hPrinter,
- _In_reads_bytes_(cbBuf) LPVOID pBuf,
- _In_ DWORD cbBuf,
- _Out_ LPDWORD pcWritten);
-
-BOOL
-WINAPI
-XcvDataW(
- _In_ HANDLE hXcv,
- _In_ PCWSTR pszDataName,
- _In_reads_bytes_opt_(cbInputData) PBYTE pInputData,
- DWORD cbInputData,
- _Out_writes_bytes_opt_(cbOutputData) PBYTE pOutputData,
- DWORD cbOutputData,
- _Out_ PDWORD pcbOutputNeeded,
- _Out_opt_ PDWORD pdwStatus);
-
-#ifdef UNICODE
-
-#define AddForm AddFormW
-#define AddJob AddJobW
-#define AddMonitor AddMonitorW
-#define AddPort AddPortW
-#define AddPrinter AddPrinterW
-#define AddPrinterConnection AddPrinterConnectionW
-#define AddPrinterDriver AddPrinterDriverW
-#define AddPrintProcessor AddPrintProcessorW
-#define AddPrintProvidor AddPrintProvidorW
-#define AdvancedDocumentProperties AdvancedDocumentPropertiesW
-#define ConfigurePort ConfigurePortW
-#define DeleteForm DeleteFormW
-#define DeleteMonitor DeleteMonitorW
-#define DeletePort DeletePortW
-#define DeletePrinterConnection DeletePrinterConnectionW
-#define DeletePrinterData DeletePrinterDataW
-#define DeletePrinterDriver DeletePrinterDriverW
-#define DeletePrintProcessor DeletePrinterProcessorW
-#define DeletePrintProvidor DeletePrinterProvidorW
-#define DocumentProperties DocumentPropertiesW
-#define EnumForms EnumFormsW
-#define EnumJobs EnumJobsW
-#define EnumMonitors EnumMonitorsW
-#define EnumPorts EnumPortsW
-#define EnumPrinterData EnumPrinterDataW
-#define EnumPrinterDrivers EnumPrinterDriversW
-#define EnumPrinters EnumPrintersW
-#define EnumPrintProcessorDatatypes EnumPrintProcessorDatatypesW
-#define EnumPrintProcessors EnumPrintProcessorsW
-#define GetDefaultPrinter GetDefaultPrinterW
-#define GetForm GetFormW
-#define GetJob GetJobW
-#define GetPrinter GetPrinterW
-#define GetPrinterData GetPrinterDataW
-#define GetPrinterDriver GetPrinterDriverW
-#define GetPrinterDriverDirectory GetPrinterDriverDirectoryW
-#define GetPrintProcessorDirectory GetPrintProcessorDirectoryW
-#define IsValidDevmode IsValidDevmodeW
-#define OpenPrinter OpenPrinterW
-#define PrinterMessageBox PrinterMessageBoxW
-#define ResetPrinter ResetPrinterW
-#define SetForm SetFormW
-#define SetJob SetJobW
-#define SetPrinter SetPrinterW
-#define SetPrinterData SetPrinterDataW
-#define StartDocPrinter StartDocPrinterW
-
-#else /* UNICODE */
-
-#define AddForm AddFormA
-#define AddJob AddJobA
-#define AddMonitor AddMonitorA
-#define AddPort AddPortA
-#define AddPrinter AddPrinterA
-#define AddPrinterConnection AddPrinterConnectionA
-#define AddPrinterDriver AddPrinterDriverA
-#define AddPrintProcessor AddPrintProcessorA
-#define AddPrintProvidor AddPrintProvidorA
-#define AdvancedDocumentProperties AdvancedDocumentPropertiesA
-#define ConfigurePort ConfigurePortA
-#define DeleteForm DeleteFormA
-#define DeleteMonitor DeleteMonitorA
-#define DeletePort DeletePortA
-#define DeletePrinterConnection DeletePrinterConnectionA
-#define DeletePrinterData DeletePrinterDataA
-#define DeletePrinterDriver DeletePrinterDriverA
-#define DeletePrintProcessor DeletePrinterProcessorA
-#define DeletePrintProvidor DeletePrinterProvidorA
-#define DocumentProperties DocumentPropertiesA
-#define EnumForms EnumFormsA
-#define EnumJobs EnumJobsA
-#define EnumMonitors EnumMonitorsA
-#define EnumPorts EnumPortsA
-#define EnumPrinterData EnumPrinterDataA
-#define EnumPrinterDrivers EnumPrinterDriversA
-#define EnumPrinters EnumPrintersA
-#define EnumPrintProcessorDatatypes EnumPrintProcessorDatatypesA
-#define EnumPrintProcessors EnumPrintProcessorsA
-#define GetDefaultPrinter GetDefaultPrinterA
-#define GetForm GetFormA
-#define GetJob GetJobA
-#define GetPrinter GetPrinterA
-#define GetPrinterData GetPrinterDataA
-#define GetPrinterDriver GetPrinterDriverA
-#define GetPrinterDriverDirectory GetPrinterDriverDirectoryA
-#define GetPrintProcessorDirectory GetPrintProcessorDirectoryA
-#define IsValidDevmode IsValidDevmodeA
-#define OpenPrinter OpenPrinterA
-#define PrinterMessageBox PrinterMessageBoxA
-#define ResetPrinter ResetPrinterA
-#define SetForm SetFormA
-#define SetJob SetJobA
-#define SetPrinter SetPrinterA
-#define SetPrinterData SetPrinterDataA
-#define StartDocPrinter StartDocPrinterA
-
-#endif /* UNICODE */
-
-#endif /* !RC_INVOKED */
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
+typedef struct _CORE_PRINTER_DRIVERW {
+ GUID CoreDriverGUID;
+ FILETIME ftDriverDate;
+ DWORDLONG dwlDriverVersion;
+ WCHAR szPackageID[MAX_PATH];
+} CORE_PRINTER_DRIVERW, *PCORE_PRINTER_DRIVERW;
+
+typedef struct _PRINTER_OPTIONS {
+ UINT cbSize;
+ DWORD dwFlags;
+} PRINTER_OPTIONS, *PPRINTER_OPTIONS;
+
+__MINGW_TYPEDEF_AW(CORE_PRINTER_DRIVER)
+__MINGW_TYPEDEF_AW(PCORE_PRINTER_DRIVER)
+#define GetCorePrinterDrivers __MINGW_NAME_AW(GetCorePrinterDrivers)
+#define GetPrinterDriver2 __MINGW_NAME_AW(GetPrinterDriver2)
+#define GetPrinterDriverPackagePath __MINGW_NAME_AW(GetPrinterDriverPackagePath)
+#define GetSpoolFileHandle __MINGW_NAME_AW(GetSpoolFileHandle)
+
+HRESULT WINAPI GetCorePrinterDriversA(
+ LPCSTR pszServer,
+ LPCSTR pszEnvironment,
+ LPCSTR pszzCoreDriverDependencies,
+ DWORD cCorePrinterDrivers,
+ PCORE_PRINTER_DRIVERA pCorePrinterDrivers
+);
+
+HRESULT WINAPI GetCorePrinterDriversW(
+ LPCWSTR pszServer,
+ LPCWSTR pszEnvironment,
+ LPCWSTR pszzCoreDriverDependencies,
+ DWORD cCorePrinterDrivers,
+ PCORE_PRINTER_DRIVERW pCorePrinterDrivers
+);
+
+/*Unsupported*/
+WINBOOL WINAPI GetPrinterDriver2A(
+ HWND hWnd,
+ HANDLE hPrinter,
+ LPSTR pEnvironment,
+ DWORD Level,
+ LPBYTE pDriverInfo,
+ DWORD cbBuf,
+ LPDWORD pcbNeeded
+);
+
+WINBOOL WINAPI GetPrinterDriver2W(
+ HWND hWnd,
+ HANDLE hPrinter,
+ LPWSTR pEnvironment,
+ DWORD Level,
+ LPBYTE pDriverInfo,
+ DWORD cbBuf,
+ LPDWORD pcbNeeded
+);
+
+HRESULT WINAPI GetPrinterDriverPackagePathA(
+ LPCSTR pszServer,
+ LPCSTR pszEnvironment,
+ LPCSTR pszLanguage,
+ LPCSTR pszPackageID,
+ LPSTR pszDriverPackageCab,
+ DWORD cchDriverPackageCab,
+ LPDWORD pcchRequiredSize
+);
+
+HRESULT WINAPI GetPrinterDriverPackagePathW(
+ LPCWSTR pszServer,
+ LPCWSTR pszEnvironment,
+ LPCWSTR pszLanguage,
+ LPCWSTR pszPackageID,
+ LPWSTR pszDriverPackageCab,
+ DWORD cchDriverPackageCab,
+ LPDWORD pcchRequiredSize
+);
+
+HANDLE WINAPI GetSpoolFileHandleA(
+ HANDLE hPrinter
+);
+
+HANDLE WINAPI GetSpoolFileHandleW(
+ HANDLE hPrinter
+);
+
+HANDLE WINAPI CommitSpoolData(
+ HANDLE hPrinter,
+ HANDLE hSpoolFile,
+ DWORD cbCommit
+);
+
+WINBOOL WINAPI CloseSpoolFileHandle(
+ HANDLE hPrinter,
+ HANDLE hSpoolFile
+);
+
+WINBOOL WINAPI OpenPrinter2A(
+ LPCSTR pPrinterName,
+ LPHANDLE phPrinter,
+ LPPRINTER_DEFAULTS pDefault,
+ PPRINTER_OPTIONS pOptions
+);
+
+WINBOOL WINAPI OpenPrinter2W(
+ LPCWSTR pPrinterName,
+ LPHANDLE phPrinter,
+ LPPRINTER_DEFAULTS pDefault,
+ PPRINTER_OPTIONS pOptions
+);
+
+#define OpenPrinter2 __MINGW_NAME_AW(OpenPrinter2)
+
+HRESULT WINAPI UploadPrinterDriverPackageA(
+ LPCSTR pszServer,
+ LPCSTR pszInfPath,
+ LPCSTR pszEnvironment,
+ DWORD dwFlags,
+ HWND hwnd,
+ LPSTR pszDestInfPath,
+ PULONG pcchDestInfPath
+);
+
+HRESULT WINAPI UploadPrinterDriverPackageW(
+ LPCWSTR pszServer,
+ LPCWSTR pszInfPath,
+ LPCWSTR pszEnvironment,
+ DWORD dwFlags,
+ HWND hwnd,
+ LPWSTR pszDestInfPath,
+ PULONG pcchDestInfPath
+);
+
+#define UploadPrinterDriverPackage __MINGW_NAME_AW(UploadPrinterDriverPackage)
+
+#endif /*(_WIN32_WINNT >= 0x0600)*/
#ifdef __cplusplus
}
#endif
-
-#endif /* _WINSPOOL_ */
+#endif
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler API
+ * LICENSE: This file is in the public domain
+ * PURPOSE: WIDL-compatible interface definition for the Spooler API
+ * AUTHORS: Colin Finck <colin@reactos.org>
+ */
+
+#include <ms-dtyp.idl>
+
+/*
+ * Handle definitions
+ */
+typedef [context_handle] void* WINSPOOL_GDI_HANDLE;
+typedef [context_handle] void* WINSPOOL_PRINTER_HANDLE;
+typedef [handle, string] WCHAR* WINSPOOL_HANDLE;
+
+
+/*
+ * Type definitions and enumerations
+ */
+typedef WORD WINSPOOL_LANGID;
+
+typedef enum
+{
+ WINSPOOL_BIDI_NULL = 0,
+ WINSPOOL_BIDI_INT = 1,
+ WINSPOOL_BIDI_FLOAT = 2,
+ WINSPOOL_BIDI_BOOL = 3,
+ WINSPOOL_BIDI_STRING = 4,
+ WINSPOOL_BIDI_TEXT = 5,
+ WINSPOOL_BIDI_ENUM = 6,
+ WINSPOOL_BIDI_BLOB = 7
+}
+WINSPOOL_BIDI_TYPE;
+
+typedef enum
+{
+ WINSPOOL_TABLE_DWORD = 1,
+ WINSPOOL_TABLE_STRING = 2,
+ WINSPOOL_TABLE_DEVMODE = 3,
+ WINSPOOL_TABLE_TIME = 4,
+ WINSPOOL_TABLE_SECURITYDESCRIPTOR = 5
+}
+WINSPOOL_TABLE_TYPE;
+
+
+/*
+ * Various definitions
+ */
+typedef struct _WINSPOOL_RECTL
+{
+ LONG left;
+ LONG top;
+ LONG right;
+ LONG bottom;
+}
+WINSPOOL_RECTL;
+
+typedef struct _WINSPOOL_SIZEL
+{
+ LONG cx;
+ LONG cy;
+}
+WINSPOOL_SIZEL;
+
+
+/*
+ * INFO structures
+ */
+typedef struct _WINSPOOL_DOC_INFO_1 {
+ [string] WCHAR* pDocName;
+ [string] WCHAR* pOutputFile;
+ [string] WCHAR* pDatatype;
+}
+WINSPOOL_DOC_INFO_1;
+
+typedef struct _WINSPOOL_DRIVER_INFO_1
+{
+ [string] WCHAR* pName;
+}
+WINSPOOL_DRIVER_INFO_1;
+
+typedef struct _WINSPOOL_DRIVER_INFO_2
+{
+ DWORD cVersion;
+ [string] WCHAR* pName;
+ [string] WCHAR* pEnvironment;
+ [string] WCHAR* pDriverPath;
+ [string] WCHAR* pDataFile;
+ [string] WCHAR* pConfigFile;
+}
+WINSPOOL_DRIVER_INFO_2;
+
+typedef struct _WINSPOOL_DRIVER_INFO_3
+{
+ DWORD cVersion;
+ [string] WCHAR* pName;
+ [string] WCHAR* pEnvironment;
+ [string] WCHAR* pDriverPath;
+ [string] WCHAR* pDataFile;
+ [string] WCHAR* pConfigFile;
+ [string] WCHAR* pHelpFile;
+ [string] WCHAR* pMonitorName;
+ [string] WCHAR* pDefaultDataType;
+ DWORD cchDependentFiles;
+ [size_is(cchDependentFiles), unique] WCHAR* pDependentFiles;
+}
+WINSPOOL_DRIVER_INFO_3;
+
+typedef struct _WINSPOOL_DRIVER_INFO_4
+{
+ DWORD cVersion;
+ [string] WCHAR* pName;
+ [string] WCHAR* pEnvironment;
+ [string] WCHAR* pDriverPath;
+ [string] WCHAR* pDataFile;
+ [string] WCHAR* pConfigFile;
+ [string] WCHAR* pHelpFile;
+ [string] WCHAR* pMonitorName;
+ [string] WCHAR* pDefaultDataType;
+ DWORD cchDependentFiles;
+ [size_is(cchDependentFiles), unique] WCHAR* pDependentFiles;
+ DWORD cchPreviousNames;
+ [size_is(cchPreviousNames), unique] WCHAR* pszzPreviousNames;
+}
+WINSPOOL_DRIVER_INFO_4;
+
+typedef struct _WINSPOOL_DRIVER_INFO_6
+{
+ DWORD cVersion;
+ [string] WCHAR* pName;
+ [string] WCHAR* pEnvironment;
+ [string] WCHAR* pDriverPath;
+ [string] WCHAR* pDataFile;
+ [string] WCHAR* pConfigFile;
+ [string] WCHAR* pHelpFile;
+ [string] WCHAR* pMonitorName;
+ [string] WCHAR* pDefaultDataType;
+ DWORD cchDependentFiles;
+ [size_is(cchDependentFiles), unique] WCHAR* pDependentFiles;
+ DWORD cchPreviousNames;
+ [size_is(cchPreviousNames), unique] WCHAR* pszzPreviousNames;
+ FILETIME ftDriverDate;
+ DWORDLONG dwlDriverVersion;
+ [string] WCHAR* pMfgName;
+ [string] WCHAR* pOEMUrl;
+ [string] WCHAR* pHardwareID;
+ [string] WCHAR* pProvider;
+}
+WINSPOOL_DRIVER_INFO_6;
+
+typedef struct _WINSPOOL_DRIVER_INFO_8
+{
+ DWORD cVersion;
+ [string] WCHAR* pName;
+ [string] WCHAR* pEnvironment;
+ [string] WCHAR* pDriverPath;
+ [string] WCHAR* pDataFile;
+ [string] WCHAR* pConfigFile;
+ [string] WCHAR* pHelpFile;
+ [string] WCHAR* pMonitorName;
+ [string] WCHAR* pDefaultDataType;
+ DWORD cchDependentFiles;
+ [size_is(cchDependentFiles), unique] WCHAR* pDependentFiles;
+ DWORD cchPreviousNames;
+ [size_is(cchPreviousNames), unique] WCHAR* pszzPreviousNames;
+ FILETIME ftDriverDate;
+ DWORDLONG dwlDriverVersion;
+ [string] WCHAR* pMfgName;
+ [string] WCHAR* pOEMUrl;
+ [string] WCHAR* pHardwareID;
+ [string] WCHAR* pProvider;
+ [string] WCHAR* pPrintProcessor;
+ [string] WCHAR* pVendorSetup;
+ DWORD cchColorProfiles;
+ [size_is(cchColorProfiles), unique] WCHAR* pszzColorProfiles;
+ [string] WCHAR* pInfPath;
+ DWORD dwPrinterDriverAttributes;
+ DWORD cchCoreDependencies;
+ [size_is(cchCoreDependencies), unique] WCHAR* pszzCoreDriverDependencies;
+ FILETIME ftMinInboxDriverVerDate;
+ DWORDLONG dwlMinInboxDriverVerVersion;
+}
+WINSPOOL_DRIVER_INFO_8;
+
+typedef struct _WINSPOOL_FORM_INFO_1
+{
+ DWORD Flags;
+ [string] WCHAR* pName;
+ WINSPOOL_SIZEL Size;
+ WINSPOOL_RECTL ImageableArea;
+}
+WINSPOOL_FORM_INFO_1;
+
+typedef struct _WINSPOOL_FORM_INFO_2
+{
+ DWORD Flags;
+ [string, unique] const WCHAR* pName;
+ WINSPOOL_SIZEL Size;
+ WINSPOOL_RECTL ImageableArea;
+ [string, unique] const WCHAR* pKeyword;
+ DWORD StringType;
+ [string, unique] const WCHAR* pMuiDll;
+ DWORD dwResourceId;
+ [string, unique] const WCHAR* pDisplayName;
+ WINSPOOL_LANGID wLangID;
+}
+WINSPOOL_FORM_INFO_2;
+
+typedef struct _WINSPOOL_JOB_INFO_1
+{
+ DWORD JobId;
+ [string] WCHAR* pPrinterName;
+ [string] WCHAR* pMachineName;
+ [string] WCHAR* pUserName;
+ [string] WCHAR* pDocument;
+ [string] WCHAR* pDatatype;
+ [string] WCHAR* pStatus;
+ DWORD Status;
+ DWORD Priority;
+ DWORD Position;
+ DWORD TotalPages;
+ DWORD PagesPrinted;
+ SYSTEMTIME Submitted;
+}
+WINSPOOL_JOB_INFO_1;
+
+typedef struct _WINSPOOL_JOB_INFO_2
+{
+ DWORD JobId;
+ [string] WCHAR* pPrinterName;
+ [string] WCHAR* pMachineName;
+ [string] WCHAR* pUserName;
+ [string] WCHAR* pDocument;
+ [string] WCHAR* pNotifyName;
+ [string] WCHAR* pDatatype;
+ [string] WCHAR* pPrintProcessor;
+ [string] WCHAR* pParameters;
+ [string] WCHAR* pDriverName;
+ ULONG_PTR pDevMode;
+ [string] WCHAR* pStatus;
+ ULONG_PTR pSecurityDescriptor;
+ DWORD Status;
+ DWORD Priority;
+ DWORD Position;
+ DWORD StartTime;
+ DWORD UntilTime;
+ DWORD TotalPages;
+ DWORD Size;
+ SYSTEMTIME Submitted;
+ DWORD Time;
+ DWORD PagesPrinted;
+}
+WINSPOOL_JOB_INFO_2;
+
+typedef struct _WINSPOOL_JOB_INFO_3
+{
+ DWORD JobId;
+ DWORD NextJobId;
+ DWORD Reserved;
+}
+WINSPOOL_JOB_INFO_3;
+
+typedef struct _WINSPOOL_JOB_INFO_4
+{
+ DWORD JobId;
+ [string] WCHAR* pPrinterName;
+ [string] WCHAR* pMachineName;
+ [string] WCHAR* pUserName;
+ [string] WCHAR* pDocument;
+ [string] WCHAR* pNotifyName;
+ [string] WCHAR* pDatatype;
+ [string] WCHAR* pPrintProcessor;
+ [string] WCHAR* pParameters;
+ [string] WCHAR* pDriverName;
+ ULONG_PTR pDevMode;
+ [string] WCHAR* pStatus;
+ ULONG_PTR pSecurityDescriptor;
+ DWORD Status;
+ DWORD Priority;
+ DWORD Position;
+ DWORD StartTime;
+ DWORD UntilTime;
+ DWORD TotalPages;
+ DWORD Size;
+ SYSTEMTIME Submitted;
+ DWORD Time;
+ DWORD PagesPrinted;
+ LONG SizeHigh;
+}
+WINSPOOL_JOB_INFO_4;
+
+typedef struct _WINSPOOL_MONITOR_INFO_1
+{
+ [string] WCHAR* pName;
+}
+WINSPOOL_MONITOR_INFO_1;
+
+typedef struct _WINSPOOL_MONITOR_INFO_2
+{
+ [string] WCHAR* pName;
+ [string] WCHAR* pEnvironment;
+ [string] WCHAR* pDLLName;
+}
+WINSPOOL_MONITOR_INFO_2;
+
+typedef struct _WINSPOOL_PORT_INFO_1
+{
+ [string] WCHAR* pPortName;
+}
+WINSPOOL_PORT_INFO_1;
+
+typedef struct _WINSPOOL_PORT_INFO_2
+{
+ [string] WCHAR* pPortName;
+ [string] WCHAR* pMonitorName;
+ [string] WCHAR* pDescription;
+ DWORD fPortType;
+ DWORD Reserved;
+}
+WINSPOOL_PORT_INFO_2;
+
+typedef struct _WINSPOOL_PORT_INFO_3
+{
+ DWORD dwStatus;
+ [string] WCHAR* pszStatus;
+ DWORD dwSeverity;
+}
+WINSPOOL_PORT_INFO_3;
+
+typedef struct _WINSPOOL_PORT_INFO_FF
+{
+ [string] WCHAR* pPortName;
+ DWORD cbMonitorData;
+ BYTE* pMonitorData;
+}
+WINSPOOL_PORT_INFO_FF;
+
+typedef struct _WINSPOOL_PRINTER_INFO_STRESS {
+ [string] WCHAR* pPrinterName;
+ [string] WCHAR* pServerName;
+ DWORD cJobs;
+ DWORD cTotalJobs;
+ DWORD cTotalBytes;
+ SYSTEMTIME stUpTime;
+ DWORD MaxcRef;
+ DWORD cTotalPagesPrinted;
+ DWORD dwGetVersion;
+ DWORD fFreeBuild;
+ DWORD cSpooling;
+ DWORD cMaxSpooling;
+ DWORD cRef;
+ DWORD cErrorOutOfPaper;
+ DWORD cErrorNotReady;
+ DWORD cJobError;
+ DWORD dwNumberOfProcessors;
+ DWORD dwProcessorType;
+ DWORD dwHighPartTotalBytes;
+ DWORD cChangeID;
+ DWORD dwLastError;
+ DWORD Status;
+ DWORD cEnumerateNetworkPrinters;
+ DWORD cAddNetPrinters;
+ USHORT wProcessorArchitecture;
+ USHORT wProcessorLevel;
+ DWORD cRefIC;
+ DWORD dwReserved2;
+ DWORD dwReserved3;
+}
+WINSPOOL_PRINTER_INFO_STRESS;
+
+typedef struct _WINSPOOL_PRINTER_INFO_1
+{
+ DWORD Flags;
+ [string] WCHAR* pDescription;
+ [string] WCHAR* pName;
+ [string] WCHAR* pComment;
+}
+WINSPOOL_PRINTER_INFO_1;
+
+typedef struct _WINSPOOL_PRINTER_INFO_2
+{
+ [string] WCHAR* pServerName;
+ [string] WCHAR* pPrinterName;
+ [string] WCHAR* pShareName;
+ [string] WCHAR* pPortName;
+ [string] WCHAR* pDriverName;
+ [string] WCHAR* pComment;
+ [string] WCHAR* pLocation;
+ ULONG_PTR pDevMode;
+ [string] WCHAR* pSepFile;
+ [string] WCHAR* pPrintProcessor;
+ [string] WCHAR* pDatatype;
+ [string] WCHAR* pParameters;
+ ULONG_PTR pSecurityDescriptor;
+ DWORD Attributes;
+ DWORD Priority;
+ DWORD DefaultPriority;
+ DWORD StartTime;
+ DWORD UntilTime;
+ DWORD Status;
+ DWORD cJobs;
+ DWORD AveragePPM;
+}
+WINSPOOL_PRINTER_INFO_2;
+
+typedef struct _WINSPOOL_PRINTER_INFO_3
+{
+ ULONG_PTR pSecurityDescriptor;
+}
+WINSPOOL_PRINTER_INFO_3;
+
+typedef struct _WINSPOOL_PRINTER_INFO_4
+{
+ [string] WCHAR* pPrinterName;
+ [string] WCHAR* pServerName;
+ DWORD Attributes;
+}
+WINSPOOL_PRINTER_INFO_4;
+
+typedef struct _WINSPOOL_PRINTER_INFO_5
+{
+ [string] WCHAR* pPrinterName;
+ [string] WCHAR* pPortName;
+ DWORD Attributes;
+ DWORD DeviceNotSelectedTimeout;
+ DWORD TransmissionRetryTimeout;
+}
+WINSPOOL_PRINTER_INFO_5;
+
+typedef struct _WINSPOOL_PRINTER_INFO_6
+{
+ DWORD dwStatus;
+}
+WINSPOOL_PRINTER_INFO_6;
+
+typedef struct _WINSPOOL_PRINTER_INFO_7
+{
+ [string] WCHAR* pszObjectGUID;
+ DWORD dwAction;
+}
+WINSPOOL_PRINTER_INFO_7;
+
+typedef struct _WINSPOOL_PRINTER_INFO_8
+{
+ ULONG_PTR pDevMode;
+}
+WINSPOOL_PRINTER_INFO_8;
+
+typedef struct _WINSPOOL_PRINTER_INFO_9
+{
+ ULONG_PTR pDevMode;
+}
+WINSPOOL_PRINTER_INFO_9;
+
+typedef struct _WINSPOOL_PROVIDOR_INFO_1
+{
+ WCHAR* pName;
+ WCHAR* pEnvironment;
+ WCHAR* pDLLName;
+}
+WINSPOOL_PROVIDOR_INFO_1;
+
+typedef struct _WINSPOOL_PROVIDOR_INFO_2
+{
+ WCHAR* pOrder;
+}
+WINSPOOL_PROVIDOR_INFO_2;
+
+typedef struct _WINSPOOL_SPLCLIENT_INFO_1
+{
+ DWORD dwSize;
+ [string] WCHAR* pMachineName;
+ [string] WCHAR* pUserName;
+ DWORD dwBuildNum;
+ DWORD dwMajorVersion;
+ DWORD dwMinorVersion;
+ USHORT wProcessorArchitecture;
+}
+WINSPOOL_SPLCLIENT_INFO_1;
+
+typedef struct _WINSPOOL_SPLCLIENT_INFO_2
+{
+ LONG_PTR notUsed;
+}
+WINSPOOL_SPLCLIENT_INFO_2;
+
+typedef struct _WINSPOOL_SPLCLIENT_INFO_3
+{
+ UINT cbSize;
+ DWORD dwFlags;
+ DWORD dwSize;
+ [string] WCHAR* pMachineName;
+ [string] WCHAR* pUserName;
+ DWORD dwBuildNum;
+ DWORD dwMajorVersion;
+ DWORD dwMinorVersion;
+ USHORT wProcessorArchitecture;
+ UINT64 hSplPrinter;
+}
+WINSPOOL_SPLCLIENT_INFO_3;
+
+
+/*
+ * CONTAINER structures
+ */
+typedef struct _WINSPOOL_BINARY_CONTAINER
+{
+ DWORD cbBuf;
+ [size_is(cbBuf), unique] BYTE* pszString;
+}
+WINSPOOL_BINARY_CONTAINER;
+
+typedef struct _WINSPOOL_BIDI_DATA
+{
+ DWORD dwBidiType;
+
+ [switch_is(dwBidiType)] union
+ {
+ [case(WINSPOOL_BIDI_NULL, WINSPOOL_BIDI_BOOL)]
+ INT bData;
+ [case(WINSPOOL_BIDI_INT)]
+ LONG iData;
+ [case(WINSPOOL_BIDI_STRING, WINSPOOL_BIDI_TEXT, WINSPOOL_BIDI_ENUM)]
+ [string, unique] WCHAR* sData;
+ [case(WINSPOOL_BIDI_FLOAT)]
+ FLOAT fData;
+ [case(WINSPOOL_BIDI_BLOB)]
+ WINSPOOL_BINARY_CONTAINER biData;
+ }
+ u;
+}
+WINSPOOL_BIDI_DATA;
+
+typedef struct _WINSPOOL_BIDI_REQUEST_DATA
+{
+ DWORD dwReqNumber;
+ [string, unique] WCHAR* pSchema;
+ WINSPOOL_BIDI_DATA data;
+}
+WINSPOOL_BIDI_REQUEST_DATA;
+
+typedef struct _WINSPOOL_BIDI_RESPONSE_DATA
+{
+ DWORD dwResult;
+ DWORD dwReqNumber;
+ [string, unique] WCHAR* pSchema;
+ WINSPOOL_BIDI_DATA data;
+}
+WINSPOOL_BIDI_RESPONSE_DATA;
+
+typedef struct _WINSPOOL_BIDI_REQUEST_CONTAINER
+{
+ DWORD Version;
+ DWORD Flags;
+ DWORD Count;
+ [size_is(Count), unique] WINSPOOL_BIDI_REQUEST_DATA aData[];
+}
+WINSPOOL_BIDI_REQUEST_CONTAINER;
+
+typedef struct _WINSPOOL_BIDI_RESPONSE_CONTAINER
+{
+ DWORD Version;
+ DWORD Flags;
+ DWORD Count;
+ [size_is(Count), unique] WINSPOOL_BIDI_RESPONSE_DATA aData[];
+}
+WINSPOOL_BIDI_RESPONSE_CONTAINER;
+
+typedef struct _WINSPOOL_DOC_INFO_CONTAINER
+{
+ DWORD Level;
+
+ [switch_is(Level)] union
+ {
+ [case(1)]
+ WINSPOOL_DOC_INFO_1* pDocInfo1;
+ }
+ DocInfo;
+}
+WINSPOOL_DOC_INFO_CONTAINER;
+
+typedef struct _WINSPOOL_DEVMODE_CONTAINER
+{
+ DWORD cbBuf;
+ [size_is(cbBuf), unique] BYTE* pDevMode;
+}
+WINSPOOL_DEVMODE_CONTAINER;
+
+typedef struct _WINSPOOL_DRIVER_CONTAINER
+{
+ DWORD Level;
+
+ [switch_is(Level)] union
+ {
+ [case(1)]
+ WINSPOOL_DRIVER_INFO_1* pNotUsed;
+ [case(2)]
+ WINSPOOL_DRIVER_INFO_2* Level2;
+ [case(3)]
+ WINSPOOL_DRIVER_INFO_3* Level3;
+ [case(4)]
+ WINSPOOL_DRIVER_INFO_4* Level4;
+ [case(6)]
+ WINSPOOL_DRIVER_INFO_6* Level6;
+ [case(8)]
+ WINSPOOL_DRIVER_INFO_8* Level8;
+ }
+ DriverInfo;
+}
+WINSPOOL_DRIVER_CONTAINER;
+
+typedef struct _WINSPOOL_FORM_CONTAINER
+{
+ DWORD Level;
+
+ [switch_is(Level)] union
+ {
+ [case(1)]
+ WINSPOOL_FORM_INFO_1* pFormInfo1;
+ [case(2)]
+ WINSPOOL_FORM_INFO_2* pFormInfo2;
+ }
+ FormInfo;
+}
+WINSPOOL_FORM_CONTAINER;
+
+typedef struct _WINSPOOL_JOB_CONTAINER
+{
+ DWORD Level;
+
+ [switch_is(Level)] union
+ {
+ [case(1)]
+ WINSPOOL_JOB_INFO_1* Level1;
+ [case(2)]
+ WINSPOOL_JOB_INFO_2* Level2;
+ [case(3)]
+ WINSPOOL_JOB_INFO_3* Level3;
+ [case(4)]
+ WINSPOOL_JOB_INFO_4* Level4;
+ }
+ JobInfo;
+}
+WINSPOOL_JOB_CONTAINER;
+
+typedef struct _WINSPOOL_MONITOR_CONTAINER
+{
+ DWORD Level;
+
+ [switch_is(Level)] union
+ {
+ [case(1)]
+ WINSPOOL_MONITOR_INFO_1* pMonitorInfo1;
+ [case(2)]
+ WINSPOOL_MONITOR_INFO_2* pMonitorInfo2;
+ }
+ MonitorInfo;
+}
+WINSPOOL_MONITOR_CONTAINER;
+
+typedef struct _WINSPOOL_PORT_CONTAINER
+{
+ DWORD Level;
+
+ [switch_is(0x00FFFFFF & Level)]
+ union
+ {
+ [case(1)]
+ WINSPOOL_PORT_INFO_1* pPortInfo1;
+ [case(2)]
+ WINSPOOL_PORT_INFO_2* pPortInfo2;
+ [case(3)]
+ WINSPOOL_PORT_INFO_3* pPortInfo3;
+ [case(0x00FFFFFF)]
+ WINSPOOL_PORT_INFO_FF* pPortInfoFF;
+ }
+ PortInfo;
+}
+WINSPOOL_PORT_CONTAINER;
+
+typedef struct _WINSPOOL_PORT_VAR_CONTAINER
+{
+ DWORD cbMonitorData;
+ [size_is(cbMonitorData), unique] BYTE* pMonitorData;
+}
+WINSPOOL_PORT_VAR_CONTAINER;
+
+typedef struct _WINSPOOL_PRINTER_CONTAINER
+{
+ DWORD Level;
+
+ [switch_is(Level)] union
+ {
+ [case(0)]
+ WINSPOOL_PRINTER_INFO_STRESS* pPrinterInfoStress;
+ [case(1)]
+ WINSPOOL_PRINTER_INFO_1* pPrinterInfo1;
+ [case(2)]
+ WINSPOOL_PRINTER_INFO_2* pPrinterInfo2;
+ [case(3)]
+ WINSPOOL_PRINTER_INFO_3* pPrinterInfo3;
+ [case(4)]
+ WINSPOOL_PRINTER_INFO_4* pPrinterInfo4;
+ [case(5)]
+ WINSPOOL_PRINTER_INFO_5* pPrinterInfo5;
+ [case(6)]
+ WINSPOOL_PRINTER_INFO_6* pPrinterInfo6;
+ [case(7)]
+ WINSPOOL_PRINTER_INFO_7* pPrinterInfo7;
+ [case(8)]
+ WINSPOOL_PRINTER_INFO_8* pPrinterInfo8;
+ [case(9)]
+ WINSPOOL_PRINTER_INFO_9* pPrinterInfo9;
+ }
+ PrinterInfo;
+}
+WINSPOOL_PRINTER_CONTAINER;
+
+typedef struct _WINSPOOL_PROVIDOR_CONTAINER
+{
+ DWORD Level;
+
+ [switch_is(Level)] union
+ {
+ [case(1)]
+ WINSPOOL_PROVIDOR_INFO_1* pProvidorInfo1;
+ [case(2)]
+ WINSPOOL_PROVIDOR_INFO_2* pProvidorInfo2;
+ }
+ ProvidorInfo;
+}
+WINSPOOL_PROVIDOR_CONTAINER;
+
+typedef struct _WINSPOOL_SECURITY_CONTAINER
+{
+ DWORD cbBuf;
+ [size_is(cbBuf), unique] BYTE* pSecurity;
+}
+WINSPOOL_SECURITY_CONTAINER;
+
+typedef struct _WINSPOOL_SPLCLIENT_CONTAINER
+{
+ DWORD Level;
+
+ [switch_is(Level)] union
+ {
+ [case(1)]
+ WINSPOOL_SPLCLIENT_INFO_1* pClientInfo1;
+ [case(2)]
+ WINSPOOL_SPLCLIENT_INFO_2* pNotUsed1;
+ [case(3)]
+ WINSPOOL_SPLCLIENT_INFO_3* pNotUsed2;
+ }
+ ClientInfo;
+}
+WINSPOOL_SPLCLIENT_CONTAINER;
+
+typedef struct _WINSPOOL_STRING_CONTAINER
+{
+ DWORD cbBuf;
+ [size_is(cbBuf / 2), unique] WCHAR* pszString;
+}
+WINSPOOL_STRING_CONTAINER;
+
+typedef struct _WINSPOOL_SYSTEMTIME_CONTAINER {
+ DWORD cbBuf;
+ SYSTEMTIME* pSystemTime;
+}
+WINSPOOL_SYSTEMTIME_CONTAINER;
+
+
+/*
+ * Various definitions
+ */
+typedef struct _WINSPOOL_V2_NOTIFY_OPTIONS_TYPE
+{
+ USHORT Type;
+ USHORT Reserved0;
+ DWORD Reserved1;
+ DWORD Reserved2;
+ DWORD Count;
+ [size_is(Count), unique] USHORT* pFields;
+}
+WINSPOOL_V2_NOTIFY_OPTIONS_TYPE;
+
+typedef struct _WINSPOOL_V2_NOTIFY_OPTIONS
+{
+ DWORD Version;
+ DWORD Reserved;
+ DWORD Count;
+ [size_is(Count), unique] WINSPOOL_V2_NOTIFY_OPTIONS_TYPE* pTypes;
+}
+WINSPOOL_V2_NOTIFY_OPTIONS;
+
+typedef [switch_type(DWORD)] union _WINSPOOL_V2_NOTIFY_INFO_DATA_DATA
+{
+ [case(WINSPOOL_TABLE_STRING)]
+ WINSPOOL_STRING_CONTAINER String;
+ [case(WINSPOOL_TABLE_DWORD)]
+ DWORD dwData[2];
+ [case(WINSPOOL_TABLE_TIME)]
+ WINSPOOL_SYSTEMTIME_CONTAINER SystemTime;
+ [case(WINSPOOL_TABLE_DEVMODE)]
+ WINSPOOL_DEVMODE_CONTAINER DevMode;
+ [case(WINSPOOL_TABLE_SECURITYDESCRIPTOR)]
+ WINSPOOL_SECURITY_CONTAINER SecurityDescriptor;
+}
+WINSPOOL_V2_NOTIFY_INFO_DATA_DATA;
+
+typedef struct _WINSPOOL_V2_NOTIFY_INFO_DATA
+{
+ USHORT Type;
+ USHORT Field;
+ DWORD Reserved;
+ DWORD Id;
+ [switch_is(Reserved & 0xffff)] WINSPOOL_V2_NOTIFY_INFO_DATA_DATA Data;
+}
+WINSPOOL_V2_NOTIFY_INFO_DATA;
+
+typedef struct _WINSPOOL_V2_NOTIFY_INFO
+{
+ DWORD Version;
+ DWORD Flags;
+ DWORD Count;
+ [size_is(Count), unique] WINSPOOL_V2_NOTIFY_INFO_DATA aData[];
+}
+WINSPOOL_V2_NOTIFY_INFO;
+
+typedef [switch_type(DWORD)] union _WINSPOOL_V2_UREPLY_PRINTER
+{
+ [case(0)]
+ WINSPOOL_V2_NOTIFY_INFO* pInfo;
+}
+WINSPOOL_V2_UREPLY_PRINTER;
+
+
+/*
+ * The actual interface
+ */
+[
+ uuid(12345678-1234-ABCD-EF00-0123456789AB),
+ version(1.0),
+ endpoint("ncalrpc:[spoolss]", "ncacn_np:[\\pipe\\spoolss]"),
+ pointer_default(unique)
+]
+
+interface winspool {
+ /* Function 0x00 */
+ DWORD _RpcEnumPrinters(
+ [in] DWORD Flags,
+ [in, unique] WINSPOOL_HANDLE Name,
+ [in] DWORD Level,
+ [in, out, unique, size_is(cbBuf), disable_consistency_check] BYTE* pPrinterEnum,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcbNeeded,
+ [out] DWORD* pcReturned
+ );
+
+ /* Function 0x01 */
+ DWORD _RpcOpenPrinter(
+ [in, unique] WINSPOOL_HANDLE pPrinterName,
+ [out] WINSPOOL_PRINTER_HANDLE* phPrinter,
+ [in, string, unique] WCHAR* pDatatype,
+ [in] WINSPOOL_DEVMODE_CONTAINER* pDevModeContainer,
+ [in] DWORD AccessRequired
+ );
+
+ /* Function 0x02 */
+ DWORD _RpcSetJob(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in] DWORD JobId,
+ [in, unique] WINSPOOL_JOB_CONTAINER* pJobContainer,
+ [in] DWORD Command
+ );
+
+ /* Function 0x03 */
+ DWORD _RpcGetJob(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in] DWORD JobId,
+ [in] DWORD Level,
+ [in, out, unique, size_is(cbBuf), disable_consistency_check] BYTE* pJob,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcbNeeded
+ );
+
+ /* Function 0x04 */
+ DWORD _RpcEnumJobs(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in] DWORD FirstJob,
+ [in] DWORD NoJobs,
+ [in] DWORD Level,
+ [in, out, unique, size_is(cbBuf), disable_consistency_check] BYTE* pJob,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcbNeeded,
+ [out] DWORD* pcReturned
+ );
+
+ /* Function 0x05 */
+ DWORD _RpcAddPrinter(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in] WINSPOOL_PRINTER_CONTAINER* pPrinterContainer,
+ [in] WINSPOOL_DEVMODE_CONTAINER* pDevModeContainer,
+ [in] WINSPOOL_SECURITY_CONTAINER* pSecurityContainer,
+ [out] WINSPOOL_PRINTER_HANDLE* pHandle
+ );
+
+ /* Function 0x06 */
+ DWORD _RpcDeletePrinter(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter
+ );
+
+ /* Function 0x07 */
+ DWORD _RpcSetPrinter(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in] WINSPOOL_PRINTER_CONTAINER* pPrinterContainer,
+ [in] WINSPOOL_DEVMODE_CONTAINER* pDevModeContainer,
+ [in] WINSPOOL_SECURITY_CONTAINER* pSecurityContainer,
+ [in] DWORD Command
+ );
+
+ /* Function 0x08 */
+ DWORD _RpcGetPrinter(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in] DWORD Level,
+ [in, out, unique, size_is(cbBuf), disable_consistency_check] BYTE* pPrinter,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcbNeeded
+ );
+
+ /* Function 0x09 */
+ DWORD _RpcAddPrinterDriver(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in] WINSPOOL_DRIVER_CONTAINER* pDriverContainer
+ );
+
+ /* Function 0x0A */
+ DWORD _RpcEnumPrinterDrivers(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in, string, unique] WCHAR* pEnvironment,
+ [in] DWORD Level,
+ [in, out, unique, size_is(cbBuf), disable_consistency_check] BYTE* pDrivers,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcbNeeded,
+ [out] DWORD* pcReturned
+ );
+
+ /* Function 0x0B */
+ DWORD _RpcGetPrinterDriver(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in, string, unique] WCHAR* pEnvironment,
+ [in] DWORD Level,
+ [in, out, unique, size_is(cbBuf), disable_consistency_check] BYTE* pDriver,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcbNeeded
+ );
+
+ /* Function 0x0C */
+ DWORD _RpcGetPrinterDriverDirectory(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in, string, unique] WCHAR* pEnvironment,
+ [in] DWORD Level,
+ [in, out, unique, size_is(cbBuf), disable_consistency_check] BYTE* pDriverDirectory,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcbNeeded
+ );
+
+ /* Function 0x0D */
+ DWORD _RpcDeletePrinterDriver(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in, string] WCHAR* pEnvironment,
+ [in, string] WCHAR* pDriverName
+ );
+
+ /* Function 0x0E */
+ DWORD _RpcAddPrintProcessor(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in, string] WCHAR* pEnvironment,
+ [in, string] WCHAR* pPathName,
+ [in, string] WCHAR* pPrintProcessorName
+ );
+
+ /* Function 0x0F */
+ DWORD _RpcEnumPrintProcessors(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in, string, unique] WCHAR* pEnvironment,
+ [in] DWORD Level,
+ [in, out, unique, size_is(cbBuf), disable_consistency_check] BYTE* pPrintProcessorInfo,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcbNeeded,
+ [out] DWORD* pcReturned
+ );
+
+ /* Function 0x10 */
+ DWORD _RpcGetPrintProcessorDirectory(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in, string, unique] WCHAR* pEnvironment,
+ [in] DWORD Level,
+ [in, out, unique, size_is(cbBuf), disable_consistency_check] BYTE* pPrintProcessorDirectory,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcbNeeded
+ );
+
+ /* Function 0x11 */
+ DWORD _RpcStartDocPrinter(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in] WINSPOOL_DOC_INFO_CONTAINER* pDocInfoContainer,
+ [out] DWORD* pJobId
+ );
+
+ /* Function 0x12 */
+ DWORD _RpcStartPagePrinter(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter
+ );
+
+ /* Function 0x13 */
+ DWORD _RpcWritePrinter(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in, size_is(cbBuf)] BYTE* pBuf,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcWritten
+ );
+
+ /* Function 0x14 */
+ DWORD _RpcEndPagePrinter(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter
+ );
+
+ /* Function 0x15 */
+ DWORD _RpcAbortPrinter(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter
+ );
+
+ /* Function 0x16 */
+ DWORD _RpcReadPrinter(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [out, size_is(cbBuf)] BYTE* pBuf,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcNoBytesRead
+ );
+
+ /* Function 0x17 */
+ DWORD _RpcEndDocPrinter(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter
+ );
+
+ /* Function 0x18 */
+ DWORD _RpcAddJob(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in] DWORD Level,
+ [in, out, unique, size_is(cbBuf), disable_consistency_check] BYTE* pAddJob,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcbNeeded
+ );
+
+ /* Function 0x19 */
+ DWORD _RpcScheduleJob(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in] DWORD JobId
+ );
+
+ /* Function 0x1A */
+ DWORD _RpcGetPrinterData(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in, string] WCHAR* pValueName,
+ [out] DWORD* pType,
+ [out, size_is(nSize)] BYTE* pData,
+ [in] DWORD nSize,
+ [out] DWORD* pcbNeeded
+ );
+
+ /* Function 0x1B */
+ DWORD _RpcSetPrinterData(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in, string] WCHAR* pValueName,
+ [in] DWORD Type,
+ [in, size_is(cbData)] BYTE* pData,
+ [in] DWORD cbData
+ );
+
+ /* Function 0x1C */
+ DWORD _RpcWaitForPrinterChange(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in] DWORD Flags,
+ [out] DWORD* pFlags
+ );
+
+ /* Function 0x1D */
+ DWORD _RpcClosePrinter(
+ [in, out] WINSPOOL_PRINTER_HANDLE* phPrinter
+ );
+
+ /* Function 0x1E */
+ DWORD _RpcAddForm(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in] WINSPOOL_FORM_CONTAINER* pFormInfoContainer
+ );
+
+ /* Function 0x1F */
+ DWORD _RpcDeleteForm(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in, string] WCHAR* pFormName
+ );
+
+ /* Function 0x20 */
+ DWORD _RpcGetForm(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in, string] WCHAR* pFormName,
+ [in] DWORD Level,
+ [in, out, unique, size_is(cbBuf), disable_consistency_check] BYTE* pForm,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcbNeeded
+ );
+
+ /* Function 0x21 */
+ DWORD _RpcSetForm(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in, string] WCHAR* pFormName,
+ [in] WINSPOOL_FORM_CONTAINER* pFormInfoContainer
+ );
+
+ /* Function 0x22 */
+ DWORD _RpcEnumForms(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in] DWORD Level,
+ [in, out, unique, size_is(cbBuf), disable_consistency_check] BYTE* pForm,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcbNeeded,
+ [out] DWORD* pcReturned
+ );
+
+ /* Function 0x23 */
+ DWORD _RpcEnumPorts(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in] DWORD Level,
+ [in, out, unique, size_is(cbBuf), disable_consistency_check] BYTE* pPort,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcbNeeded,
+ [out] DWORD* pcReturned
+ );
+
+ /* Function 0x24 */
+ DWORD _RpcEnumMonitors(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in] DWORD Level,
+ [in, out, unique, size_is(cbBuf), disable_consistency_check] BYTE* pMonitor,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcbNeeded,
+ [out] DWORD* pcReturned
+ );
+
+ /* Function 0x25 */
+ DWORD _RpcAddPort(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in] ULONG_PTR hWnd,
+ [in] WCHAR* pMonitorName
+ );
+
+ /* Function 0x26 */
+ DWORD _RpcConfigurePort(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in] ULONG_PTR hWnd,
+ [in] WCHAR* pPortName
+ );
+
+ /* Function 0x27 */
+ DWORD _RpcDeletePort(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in] ULONG_PTR hWnd,
+ [in, string] WCHAR* pPortName
+ );
+
+ /* Function 0x28 */
+ DWORD _RpcCreatePrinterIC(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [out] WINSPOOL_GDI_HANDLE* pHandle,
+ [in] WINSPOOL_DEVMODE_CONTAINER* pDevModeContainer
+ );
+
+ /* Function 0x29 */
+ DWORD _RpcPlayGdiScriptOnPrinterIC(
+ [in] WINSPOOL_GDI_HANDLE hPrinterIC,
+ [in, size_is(cIn)] BYTE* pIn,
+ [in] DWORD cIn,
+ [out, size_is(cOut)] BYTE* pOut,
+ [in] DWORD cOut,
+ [in] DWORD ul
+ );
+
+ /* Function 0x2A */
+ DWORD _RpcDeletePrinterIC(
+ [in, out] WINSPOOL_GDI_HANDLE* phPrinterIC
+ );
+
+ /* Function 0x2B */
+ DWORD _RpcAddPrinterConnection(
+ [in, unique] WINSPOOL_HANDLE pName
+ );
+
+ /* Function 0x2C */
+ DWORD _RpcDeletePrinterConnection(
+ [in, unique] WINSPOOL_HANDLE pName
+ );
+
+ /* Function 0x2D */
+ DWORD _RpcPrinterMessageBox(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in] DWORD Error,
+ [in] ULONG_PTR hWnd,
+ [in, string] WCHAR* pText,
+ [in, string] WCHAR* pCaption,
+ [in] DWORD dwType
+ );
+
+ /* Function 0x2E */
+ DWORD _RpcAddMonitor(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in] WINSPOOL_MONITOR_CONTAINER* pMonitorContainer
+ );
+
+ /* Function 0x2F */
+ DWORD _RpcDeleteMonitor(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in, string, unique] WCHAR* pEnvironment,
+ [in, string] WCHAR* pMonitorName
+ );
+
+ /* Function 0x30 */
+ DWORD _RpcDeletePrintProcessor(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in, string, unique] WCHAR* pEnvironment,
+ [in, string] WCHAR* pPrintProcessorName
+ );
+
+ /* Function 0x31 */
+ DWORD _RpcAddPrintProvidor(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in] WINSPOOL_PROVIDOR_CONTAINER* pProvidorContainer
+ );
+
+ /* Function 0x32 */
+ DWORD _RpcDeletePrintProvidor(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in, string, unique] WCHAR* pEnvironment,
+ [in, string] WCHAR* pPrintProviderName
+ );
+
+ /* Function 0x33 */
+ DWORD _RpcEnumPrintProcessorDatatypes(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in, string, unique] WCHAR* pPrintProcessorName,
+ [in] DWORD Level,
+ [in, out, unique, size_is(cbBuf), disable_consistency_check] BYTE* pDatatypes,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcbNeeded,
+ [out] DWORD* pcReturned
+ );
+
+ /* Function 0x34 */
+ DWORD _RpcResetPrinter(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in, string, unique] WCHAR* pDatatype,
+ [in] WINSPOOL_DEVMODE_CONTAINER* pDevModeContainer
+ );
+
+ /* Function 0x35 */
+ DWORD _RpcGetPrinterDriver2(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in, string, unique] WCHAR* pEnvironment,
+ [in] DWORD Level,
+ [in, out, unique, size_is(cbBuf), disable_consistency_check] BYTE* pDriver,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcbNeeded,
+ [in] DWORD dwClientMajorVersion,
+ [in] DWORD dwClientMinorVersion,
+ [out] DWORD* pdwServerMaxVersion,
+ [out] DWORD* pdwServerMinVersion
+ );
+
+ /* Function 0x36 (TODO) */
+ DWORD _RpcClientFindFirstPrinterChangeNotification(
+ /* TODO */
+ );
+
+ /* Function 0x37 (TODO) */
+ DWORD _RpcFindNextPrinterChangeNotification(
+ /* TODO */
+ );
+
+ /* Function 0x38 (TODO) */
+ DWORD _RpcFindClosePrinterChangeNotification(
+ /* TODO */
+ );
+
+ /* Function 0x39 (TODO) */
+ DWORD _RpcRouterFindFirstPrinterChangeNotificationOld(
+ /* TODO */
+ );
+
+ /* Function 0x3A */
+ DWORD _RpcReplyOpenPrinter(
+ [in] WINSPOOL_HANDLE pMachine,
+ [out] WINSPOOL_PRINTER_HANDLE* phPrinterNotify,
+ [in] DWORD dwPrinterRemote,
+ [in] DWORD dwType,
+ [in, range(0, 512)] DWORD cbBuffer,
+ [in, unique, size_is(cbBuffer), disable_consistency_check] BYTE* pBuffer
+ );
+
+ /* Function 0x3B */
+ DWORD _RpcRouterReplyPrinter(
+ [in] WINSPOOL_PRINTER_HANDLE hNotify,
+ [in] DWORD fdwFlags,
+ [in, range(0, 512)] DWORD cbBuffer,
+ [in, unique, size_is(cbBuffer), disable_consistency_check] BYTE* pBuffer
+ );
+
+ /* Function 0x3C */
+ DWORD _RpcReplyClosePrinter(
+ [in, out] WINSPOOL_PRINTER_HANDLE* phNotify
+ );
+
+ /* Function 0x3D */
+ DWORD _RpcAddPortEx(
+ [in] WINSPOOL_HANDLE pName,
+ [in] WINSPOOL_PORT_CONTAINER* pPortContainer,
+ [in] WINSPOOL_PORT_VAR_CONTAINER* pPortVarContainer,
+ [in, string] WCHAR* pMonitorName
+ );
+
+ /* Function 0x3E */
+ DWORD _RpcRemoteFindFirstPrinterChangeNotification(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in] DWORD fdwFlags,
+ [in] DWORD fdwOptions,
+ [in, string, unique] WCHAR* pszLocalMachine,
+ [in] DWORD dwPrinterLocal,
+ [in, range(0, 512)] DWORD cbBuffer,
+ [in, out, unique, size_is(cbBuffer), disable_consistency_check] BYTE* pBuffer
+ );
+
+ /* Function 0x3F */
+ DWORD _RpcSpoolerInit();
+
+ /* Function 0x40 (TODO) */
+ DWORD _RpcResetPrinterEx(
+ /* TODO */
+ );
+
+ /* Function 0x41 */
+ DWORD _RpcRemoteFindFirstPrinterChangeNotificationEx(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in] DWORD fdwFlags,
+ [in] DWORD fdwOptions,
+ [in, string, unique] WCHAR* pszLocalMachine,
+ [in] DWORD dwPrinterLocal,
+ [in, unique] WINSPOOL_V2_NOTIFY_OPTIONS* pOptions
+ );
+
+ /* Function 0x42 */
+ DWORD _RpcRouterReplyPrinterEx(
+ [in] WINSPOOL_PRINTER_HANDLE hNotify,
+ [in] DWORD dwColor,
+ [in] DWORD fdwFlags,
+ [out] DWORD* pdwResult,
+ [in] DWORD dwReplyType,
+ [in, switch_is(dwReplyType)] WINSPOOL_V2_UREPLY_PRINTER Reply
+ );
+
+ /* Function 0x43 */
+ DWORD _RpcRouterRefreshPrinterChangeNotification(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in] DWORD dwColor,
+ [in, unique] WINSPOOL_V2_NOTIFY_OPTIONS* pOptions,
+ [out] WINSPOOL_V2_NOTIFY_INFO** ppInfo
+ );
+
+ /* Function 0x44 (TODO) */
+ DWORD _RpcSetAllocFailCount(
+ /* TODO */
+ );
+
+ /* Function 0x45 */
+ DWORD _RpcOpenPrinterEx(
+ [in, unique] WINSPOOL_HANDLE pPrinterName,
+ [out] WINSPOOL_PRINTER_HANDLE* pHandle,
+ [in, string, unique] WCHAR* pDatatype,
+ [in] WINSPOOL_DEVMODE_CONTAINER* pDevModeContainer,
+ [in] DWORD AccessRequired,
+ [in] WINSPOOL_SPLCLIENT_CONTAINER* pClientInfo
+ );
+
+ /* Function 0x46 */
+ DWORD _RpcAddPrinterEx(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in] WINSPOOL_PRINTER_CONTAINER* pPrinterContainer,
+ [in] WINSPOOL_DEVMODE_CONTAINER* pDevModeContainer,
+ [in] WINSPOOL_SECURITY_CONTAINER* pSecurityContainer,
+ [in] WINSPOOL_SPLCLIENT_CONTAINER* pClientInfo,
+ [out] WINSPOOL_PRINTER_HANDLE* pHandle
+ );
+
+ /* Function 0x47 */
+ DWORD _RpcSetPort(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in, string, unique] WCHAR* pPortName,
+ [in] WINSPOOL_PORT_CONTAINER* pPortContainer
+ );
+
+ /* Function 0x48 */
+ DWORD _RpcEnumPrinterData(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in] DWORD dwIndex,
+ [out, size_is(cbValueName / sizeof(WCHAR))] WCHAR* pValueName,
+ [in] DWORD cbValueName,
+ [out] DWORD* pcbValueName,
+ [out] DWORD* pType,
+ [out, size_is(cbData)] BYTE* pData,
+ [in] DWORD cbData,
+ [out] DWORD* pcbData
+ );
+
+ /* Function 0x49 */
+ DWORD _RpcDeletePrinterData(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in, string] WCHAR* pValueName
+ );
+
+ /* Function 0x4A (TODO) */
+ DWORD _RpcClusterSplOpen(
+ /* TODO */
+ );
+
+ /* Function 0x4B (TODO) */
+ DWORD _RpcClusterSplClose(
+ /* TODO */
+ );
+
+ /* Function 0x4C (TODO) */
+ DWORD _RpcClusterSplIsAlive(
+ /* TODO */
+ );
+
+ /* Function 0x4D */
+ DWORD _RpcSetPrinterDataEx(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in, string] const WCHAR* pKeyName,
+ [in, string] const WCHAR* pValueName,
+ [in] DWORD Type,
+ [in, size_is(cbData)] BYTE* pData,
+ [in] DWORD cbData
+ );
+
+ /* Function 0x4E */
+ DWORD _RpcGetPrinterDataEx(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in, string] const WCHAR* pKeyName,
+ [in, string] const WCHAR* pValueName,
+ [out] DWORD* pType,
+ [out, size_is(nSize)] BYTE* pData,
+ [in] DWORD nSize,
+ [out] DWORD* pcbNeeded
+ );
+
+ /* Function 0x4F */
+ DWORD _RpcEnumPrinterDataEx(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in, string] const WCHAR* pKeyName,
+ [out, size_is(cbEnumValues)] BYTE* pEnumValues,
+ [in] DWORD cbEnumValues,
+ [out] DWORD* pcbEnumValues,
+ [out] DWORD* pnEnumValues
+ );
+
+ /* Function 0x50 */
+ DWORD _RpcEnumPrinterKey(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in, string] const WCHAR* pKeyName,
+ [out, size_is(cbSubkey / sizeof(WCHAR))] WCHAR* pSubkey,
+ [in] DWORD cbSubkey,
+ [out] DWORD* pcbSubkey
+ );
+
+ /* Function 0x51 */
+ DWORD _RpcDeletePrinterDataEx(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in, string] const WCHAR* pKeyName,
+ [in, string] const WCHAR* pValueName
+ );
+
+ /* Function 0x52 */
+ DWORD _RpcDeletePrinterKey(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in, string] const WCHAR* pKeyName
+ );
+
+ /* Function 0x53 (TODO) */
+ DWORD _RpcSeekPrinter(
+ /* TODO */
+ );
+
+ /* Function 0x54 */
+ DWORD _RpcDeletePrinterDriverEx(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in, string] WCHAR* pEnvironment,
+ [in, string] WCHAR* pDriverName,
+ [in] DWORD dwDeleteFlag,
+ [in] DWORD dwVersionNum
+ );
+
+ /* Function 0x55 */
+ DWORD _RpcAddPerMachineConnection(
+ [in, unique] WINSPOOL_HANDLE pServer,
+ [in, string] const WCHAR* pPrinterName,
+ [in, string] const WCHAR* pPrintServer,
+ [in, string] const WCHAR* pProvider
+ );
+
+ /* Function 0x56 */
+ DWORD _RpcDeletePerMachineConnection(
+ [in, unique] WINSPOOL_HANDLE pServer,
+ [in, string] const WCHAR* pPrinterName
+ );
+
+ /* Function 0x57 */
+ DWORD _RpcEnumPerMachineConnections(
+ [in, unique] WINSPOOL_HANDLE pServer,
+ [in, out, unique, size_is(cbBuf), disable_consistency_check] BYTE* pPrinterEnum,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcbNeeded,
+ [out] DWORD* pcReturned
+ );
+
+ /* Function 0x58 */
+ DWORD _RpcXcvData(
+ [in] WINSPOOL_PRINTER_HANDLE hXcv,
+ [in, string] const WCHAR* pszDataName,
+ [in, size_is(cbInputData)] BYTE* pInputData,
+ [in] DWORD cbInputData,
+ [out, size_is(cbOutputData)] BYTE* pOutputData,
+ [in] DWORD cbOutputData,
+ [out] DWORD* pcbOutputNeeded,
+ [in, out] DWORD* pdwStatus
+ );
+
+ /* Function 0x59 */
+ DWORD _RpcAddPrinterDriverEx(
+ [in, unique] WINSPOOL_HANDLE pName,
+ [in] WINSPOOL_DRIVER_CONTAINER* pDriverContainer,
+ [in] DWORD dwFileCopyFlags
+ );
+
+ /* Function 0x5A (TODO) */
+ DWORD _RpcSplOpenPrinter(
+ /* TODO */
+ );
+
+ /* Function 0x5B (TODO) */
+ DWORD _RpcGetSpoolFileInfo(
+ /* TODO */
+ );
+
+ /* Function 0x5C (TODO) */
+ DWORD _RpcCommitSpoolData(
+ /* TODO */
+ );
+
+ /* Function 0x5D (TODO) */
+ DWORD _RpcCloseSpoolFileHandle(
+ /* TODO */
+ );
+
+ /* Function 0x5E */
+ DWORD _RpcFlushPrinter(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in, size_is(cbBuf)] BYTE* pBuf,
+ [in] DWORD cbBuf,
+ [out] DWORD* pcWritten,
+ [in] DWORD cSleep
+ );
+
+ /* Function 0x5F */
+ DWORD _RpcSendRecvBidiData(
+ [in] WINSPOOL_PRINTER_HANDLE hPrinter,
+ [in, string, unique] const WCHAR* pAction,
+ [in] WINSPOOL_BIDI_REQUEST_CONTAINER* pReqData,
+ [out] WINSPOOL_BIDI_RESPONSE_CONTAINER** ppRespData
+ );
+
+ /* Function 0x60 (TODO) */
+ DWORD _RpcAddDriverCatalog(
+ /* TODO */
+ );
+}
add_subdirectory(rtl)
add_subdirectory(scrnsave)
+add_subdirectory(skiplist)
add_subdirectory(strmiids)
add_subdirectory(smlib)
add_subdirectory(tdilib)
--- /dev/null
+
+# The library
+add_definitions(-DSKIPLIST_LEVELS=16)
+add_library(skiplist16 skiplist.c)
+add_dependencies(skiplist16 psdk)
+
+# The Test program
+add_executable(skiplist_test skiplist_test.c)
+target_link_libraries(skiplist_test skiplist16)
+set_module_type(skiplist_test win32cui)
+add_importlibs(skiplist_test msvcrt kernel32 ntdll)
--- /dev/null
+/*
+ * PROJECT: Skiplist implementation for the ReactOS Project
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: All implemented functions operating on the Skiplist
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include <intrin.h>
+#include <windef.h>
+#include <winbase.h>
+#include "skiplist.h"
+
+/**
+ * @name _GetRandomLevel
+ *
+ * Returns a random level for the next element to be inserted.
+ * This level is geometrically distributed for p = 0.5, so perfectly suitable for an efficient Skiplist implementation.
+ *
+ * @return
+ * A value between 0 and SKIPLIST_LEVELS - 1.
+ */
+static __inline CHAR
+_GetRandomLevel()
+{
+ // Using a simple fixed seed and the Park-Miller Lehmer Minimal Standard Random Number Generator gives an acceptable distribution for our "random" levels.
+ static DWORD dwRandom = 1;
+
+ DWORD dwLevel = 0;
+ DWORD dwShifted;
+
+ // Generate 31 uniformly distributed pseudo-random bits using the Park-Miller Lehmer Minimal Standard Random Number Generator.
+ dwRandom = (DWORD)(((ULONGLONG)dwRandom * 48271UL) % 2147483647UL);
+
+ // Shift out (31 - SKIPLIST_LEVELS) bits to the right to have no more than SKIPLIST_LEVELS bits set.
+ dwShifted = dwRandom >> (31 - SKIPLIST_LEVELS);
+
+ // BitScanForward doesn't operate on a zero input value.
+ if (dwShifted)
+ {
+ // BitScanForward sets dwLevel to the zero-based position of the first set bit (from LSB to MSB).
+ // This makes dwLevel a geometrically distributed value between 0 and SKIPLIST_LEVELS - 1 for p = 0.5.
+ BitScanForward(&dwLevel, dwShifted);
+ }
+
+ // dwLevel can't have a value higher than 30 this way, so a CHAR is more than enough.
+ return (CHAR)dwLevel;
+}
+
+/**
+ * @name _InsertElementSkiplistWithInformation
+ *
+ * Determines a level for the new element and inserts it at the given position in the Skiplist.
+ * This function is internally used by the Skiplist insertion functions.
+ *
+ * @param Skiplist
+ * Pointer to the SKIPLIST structure to operate on.
+ *
+ * @param Element
+ * The element to insert.
+ *
+ * @param pUpdate
+ * Array containing the last nodes before our new node on each level.
+ *
+ * @param dwDistance
+ * Array containing the distance to the last node before our new node on each level.
+ *
+ * @return
+ * TRUE if the node was successfully inserted, FALSE if no memory could be allocated for it.
+ */
+static BOOL
+_InsertElementSkiplistWithInformation(PSKIPLIST Skiplist, PVOID Element, PSKIPLIST_NODE* pUpdate, DWORD* dwDistance)
+{
+ CHAR chNewLevel;
+ CHAR i;
+ PSKIPLIST_NODE pNode;
+
+ // Get the highest level, on which the node shall be inserted.
+ chNewLevel = _GetRandomLevel();
+
+ // Check if the new level is higher than the maximum level we currently have in the Skiplist.
+ if (chNewLevel > Skiplist->MaximumLevel)
+ {
+ // It is, so we also need to insert the new node right after the Head node on some levels.
+ // These are the levels higher than the current maximum level up to the new level.
+ // We also need to set the distance of these elements to the new node count to account for the calculations below.
+ for (i = Skiplist->MaximumLevel + 1; i <= chNewLevel; i++)
+ {
+ pUpdate[i] = &Skiplist->Head;
+ pUpdate[i]->Distance[i] = Skiplist->NodeCount + 1;
+ }
+
+ // The new level is the new maximum level of the entire Skiplist.
+ Skiplist->MaximumLevel = chNewLevel;
+ }
+
+ // Finally create our new Skiplist node.
+ pNode = Skiplist->AllocateRoutine(sizeof(SKIPLIST_NODE));
+ if (!pNode)
+ return FALSE;
+
+ pNode->Element = Element;
+
+ // For each used level, insert us between the saved node for this level and its current next node.
+ for (i = 0; i <= chNewLevel; i++)
+ {
+ pNode->Next[i] = pUpdate[i]->Next[i];
+ pUpdate[i]->Next[i] = pNode;
+
+ // We know the walked distance in this level: dwDistance[i]
+ // We also know the element index of the new node: dwDistance[0]
+ // The new node's distance is now the walked distance in this level plus the difference between the saved node's distance and the element index.
+ pNode->Distance[i] = dwDistance[i] + (pUpdate[i]->Distance[i] - dwDistance[0]);
+
+ // The saved node's distance is now the element index plus one (to account for the added node) minus the walked distance in this level.
+ pUpdate[i]->Distance[i] = dwDistance[0] + 1 - dwDistance[i];
+ }
+
+ // For all levels above the new node's level, we need to increment the distance, because we've just added our new node.
+ for (i = chNewLevel + 1; i <= Skiplist->MaximumLevel; i++)
+ ++pUpdate[i]->Distance[i];
+
+ // We've successfully added a node :)
+ ++Skiplist->NodeCount;
+ return TRUE;
+}
+
+/**
+ * @name DeleteElementSkiplist
+ *
+ * Deletes an element from the Skiplist. The efficiency of this operation is O(log N) on average.
+ *
+ * Instead of the result of a LookupElementSkiplist call, it's sufficient to provide a dummy element with just enough information for your CompareRoutine.
+ * A lookup for the element to be deleted needs to be performed in any case.
+ *
+ * @param Skiplist
+ * Pointer to the SKIPLIST structure to operate on.
+ *
+ * @param Element
+ * Information about the element to be deleted.
+ *
+ * @return
+ * Returns the deleted element or NULL if no such element was found.
+ * You can then free memory for the deleted element if necessary.
+ */
+PVOID
+DeleteElementSkiplist(PSKIPLIST Skiplist, PVOID Element)
+{
+ CHAR i;
+ PSKIPLIST_NODE pLastComparedNode = NULL;
+ PSKIPLIST_NODE pNode = &Skiplist->Head;
+ PSKIPLIST_NODE pUpdate[SKIPLIST_LEVELS];
+ PVOID pReturnValue;
+
+ // Find the node on every currently used level, after which the node to be deleted must follow.
+ // This can be done efficiently by starting from the maximum level and going down a level each time a position has been found.
+ for (i = Skiplist->MaximumLevel + 1; --i >= 0;)
+ {
+ while (pNode->Next[i] && pNode->Next[i] != pLastComparedNode && Skiplist->CompareRoutine(pNode->Next[i]->Element, Element) < 0)
+ pNode = pNode->Next[i];
+
+ // Reduce the number of comparisons by not comparing the same node on different levels twice.
+ pLastComparedNode = pNode->Next[i];
+ pUpdate[i] = pNode;
+ }
+
+ // Check if the node we're looking for has been found.
+ pNode = pNode->Next[0];
+ if (!pNode || Skiplist->CompareRoutine(pNode->Element, Element) != 0)
+ {
+ // It hasn't been found, so there's nothing to delete.
+ return NULL;
+ }
+
+ // Beginning at the lowest level, remove the node from each level of the list and merge distances.
+ // We can stop as soon as we found the first level that doesn't contain the node.
+ for (i = 0; i <= Skiplist->MaximumLevel && pUpdate[i]->Next[i] == pNode; i++)
+ {
+ pUpdate[i]->Distance[i] += pNode->Distance[i] - 1;
+ pUpdate[i]->Next[i] = pNode->Next[i];
+ }
+
+ // Now decrement the distance of the corresponding node in levels higher than the deleted node's level to account for the deleted node.
+ while (i <= Skiplist->MaximumLevel)
+ {
+ --pUpdate[i]->Distance[i];
+ i++;
+ }
+
+ // Return the deleted element (so the caller can free it if necessary) and free the memory for the node itself (allocated by us).
+ pReturnValue = pNode->Element;
+ Skiplist->FreeRoutine(pNode);
+
+ // Find all levels which now contain no more nodes and reduce the maximum level of the entire Skiplist accordingly.
+ while (Skiplist->MaximumLevel > 0 && !Skiplist->Head.Next[Skiplist->MaximumLevel])
+ --Skiplist->MaximumLevel;
+
+ // We've successfully deleted the node :)
+ --Skiplist->NodeCount;
+ return pReturnValue;
+}
+
+/**
+ * @name InitializeSkiplist
+ *
+ * Initializes a new Skiplist structure.
+ *
+ * @param Skiplist
+ * Pointer to the SKIPLIST structure to operate on.
+ *
+ * @param AllocateRoutine
+ * Pointer to a SKIPLIST_ALLOCATE_ROUTINE for allocating memory for new Skiplist nodes.
+ *
+ * @param CompareRoutine
+ * Pointer to a SKIPLIST_COMPARE_ROUTINE for comparing two elements of the Skiplist.
+ *
+ * @param FreeRoutine
+ * Pointer to a SKIPLIST_FREE_ROUTINE for freeing memory allocated with AllocateRoutine.
+ */
+void
+InitializeSkiplist(PSKIPLIST Skiplist, PSKIPLIST_ALLOCATE_ROUTINE AllocateRoutine, PSKIPLIST_COMPARE_ROUTINE CompareRoutine, PSKIPLIST_FREE_ROUTINE FreeRoutine)
+{
+ // Store the routines.
+ Skiplist->AllocateRoutine = AllocateRoutine;
+ Skiplist->CompareRoutine = CompareRoutine;
+ Skiplist->FreeRoutine = FreeRoutine;
+
+ // Initialize the members and pointers.
+ // The Distance array is only used when a node is non-NULL, so it doesn't need initialization.
+ Skiplist->MaximumLevel = 0;
+ Skiplist->NodeCount = 0;
+ ZeroMemory(Skiplist->Head.Next, sizeof(Skiplist->Head.Next));
+}
+
+/**
+ * @name InsertElementSkiplist
+ *
+ * Inserts a new element into the Skiplist. The efficiency of this operation is O(log N) on average.
+ * Uses CompareRoutine to find the right position for the insertion.
+ *
+ * @param Skiplist
+ * Pointer to the SKIPLIST structure to operate on.
+ *
+ * @param Element
+ * The element to insert.
+ *
+ * @return
+ * TRUE if the node was successfully inserted, FALSE if it already exists or no memory could be allocated for it.
+ */
+BOOL
+InsertElementSkiplist(PSKIPLIST Skiplist, PVOID Element)
+{
+ CHAR i;
+ DWORD dwDistance[SKIPLIST_LEVELS + 1] = { 0 };
+ PSKIPLIST_NODE pLastComparedNode = NULL;
+ PSKIPLIST_NODE pNode = &Skiplist->Head;
+ PSKIPLIST_NODE pUpdate[SKIPLIST_LEVELS];
+
+ // Find the node on every currently used level, after which the new node needs to be inserted.
+ // This can be done efficiently by starting from the maximum level and going down a level each time a position has been found.
+ for (i = Skiplist->MaximumLevel + 1; --i >= 0;)
+ {
+ // When entering this level, we begin at the distance of the last level we walked through.
+ dwDistance[i] = dwDistance[i + 1];
+
+ while (pNode->Next[i] && pNode->Next[i] != pLastComparedNode && Skiplist->CompareRoutine(pNode->Next[i]->Element, Element) < 0)
+ {
+ // Save our position in every level when walking through the nodes.
+ dwDistance[i] += pNode->Distance[i];
+
+ // Advance to the next node.
+ pNode = pNode->Next[i];
+ }
+
+ // Reduce the number of comparisons by not comparing the same node on different levels twice.
+ pLastComparedNode = pNode->Next[i];
+ pUpdate[i] = pNode;
+ }
+
+ // Check if the node already exists in the Skiplist.
+ pNode = pNode->Next[0];
+ if (pNode && Skiplist->CompareRoutine(pNode->Element, Element) == 0)
+ {
+ // All elements to be inserted mustn't exist in the list, so we see this as a failure.
+ return FALSE;
+ }
+
+ // The rest of the procedure is the same for both insertion functions.
+ return _InsertElementSkiplistWithInformation(Skiplist, Element, pUpdate, dwDistance);
+}
+
+/**
+ * @name InsertTailElementSkiplist
+ *
+ * Inserts a new element at the end of the Skiplist. The efficiency of this operation is O(log N) on average.
+ * In contrast to InsertElementSkiplist, this function is more efficient by not calling CompareRoutine at all and always inserting the element at the end.
+ * You're responsible for calling this function only when you can guarantee that InsertElementSkiplist would also insert the element at the end.
+ *
+ * @param Skiplist
+ * Pointer to the SKIPLIST structure to operate on.
+ *
+ * @param Element
+ * The element to insert.
+ *
+ * @return
+ * TRUE if the node was successfully inserted, FALSE if it already exists or no memory could be allocated for it.
+ */
+BOOL
+InsertTailElementSkiplist(PSKIPLIST Skiplist, PVOID Element)
+{
+ CHAR i;
+ DWORD dwDistance[SKIPLIST_LEVELS + 1] = { 0 };
+ PSKIPLIST_NODE pNode = &Skiplist->Head;
+ PSKIPLIST_NODE pUpdate[SKIPLIST_LEVELS];
+
+ // Find the last node on every currently used level, after which the new node needs to be inserted.
+ // This can be done efficiently by starting from the maximum level and going down a level each time a position has been found.
+ for (i = Skiplist->MaximumLevel + 1; --i >= 0;)
+ {
+ // When entering this level, we begin at the distance of the last level we walked through.
+ dwDistance[i] = dwDistance[i + 1];
+
+ while (pNode->Next[i])
+ {
+ // Save our position in every level when walking through the nodes.
+ dwDistance[i] += pNode->Distance[i];
+
+ // Advance to the next node.
+ pNode = pNode->Next[i];
+ }
+
+ pUpdate[i] = pNode;
+ }
+
+ // The rest of the procedure is the same for both insertion functions.
+ return _InsertElementSkiplistWithInformation(Skiplist, Element, pUpdate, dwDistance);
+}
+
+/**
+ * @name LookupElementSkiplist
+ *
+ * Looks up an element in the Skiplist. The efficiency of this operation is O(log N) on average.
+ *
+ * @param Skiplist
+ * Pointer to the SKIPLIST structure to operate on.
+ *
+ * @param Element
+ * Information about the element to look for.
+ *
+ * @param ElementIndex
+ * Pointer to a DWORD that will contain the zero-based index of the element in the Skiplist.
+ * If you're not interested in the index, you can set this parameter to NULL.
+ *
+ * @return
+ * Returns the found element or NULL if no such element was found.
+ */
+PVOID
+LookupElementSkiplist(PSKIPLIST Skiplist, PVOID Element, PDWORD ElementIndex)
+{
+ CHAR i;
+ DWORD dwIndex = 0;
+ PSKIPLIST_NODE pLastComparedNode = NULL;
+ PSKIPLIST_NODE pNode = &Skiplist->Head;
+
+ // Do the efficient lookup in Skiplists:
+ // * Start from the maximum level.
+ // * Walk through all nodes on this level that come before the node we're looking for.
+ // * When we have reached such a node, go down a level and continue there.
+ // * Repeat these steps till we're in level 0, right in front of the node we're looking for.
+ for (i = Skiplist->MaximumLevel + 1; --i >= 0;)
+ {
+ while (pNode->Next[i] && pNode->Next[i] != pLastComparedNode && Skiplist->CompareRoutine(pNode->Next[i]->Element, Element) < 0)
+ {
+ dwIndex += pNode->Distance[i];
+ pNode = pNode->Next[i];
+ }
+
+ // Reduce the number of comparisons by not comparing the same node on different levels twice.
+ pLastComparedNode = pNode->Next[i];
+ }
+
+ // We must be right in front of the node we're looking for now, otherwise it doesn't exist in the Skiplist at all.
+ pNode = pNode->Next[0];
+ if (!pNode || Skiplist->CompareRoutine(pNode->Element, Element) != 0)
+ {
+ // It hasn't been found, so there's nothing to return.
+ return NULL;
+ }
+
+ // Return the index of the element if the caller is interested.
+ if (ElementIndex)
+ *ElementIndex = dwIndex;
+
+ // Return the stored element of the found node.
+ return pNode->Element;
+}
+
+/**
+ * @name LookupNodeByIndexSkiplist
+ *
+ * Looks up a node in the Skiplist at the given position. The efficiency of this operation is O(log N) on average.
+ *
+ * @param Skiplist
+ * Pointer to the SKIPLIST structure to operate on.
+ *
+ * @param ElementIndex
+ * Zero-based position of the node in the Skiplist.
+ *
+ * @return
+ * Returns the found node or NULL if the position is invalid.
+ */
+PSKIPLIST_NODE
+LookupNodeByIndexSkiplist(PSKIPLIST Skiplist, DWORD ElementIndex)
+{
+ CHAR i;
+ DWORD dwIndex = 0;
+ PSKIPLIST_NODE pNode = &Skiplist->Head;
+
+ // The only way the node can't be found is when the index is out of range.
+ if (ElementIndex >= Skiplist->NodeCount)
+ return NULL;
+
+ // Do the efficient lookup in Skiplists:
+ // * Start from the maximum level.
+ // * Walk through all nodes on this level that come before the node we're looking for.
+ // * When we have reached such a node, go down a level and continue there.
+ // * Repeat these steps till we're in level 0, right in front of the node we're looking for.
+ for (i = Skiplist->MaximumLevel + 1; --i >= 0;)
+ {
+ // We compare with <= instead of < here, because the added distances make up a 1-based index while ElementIndex is zero-based,
+ // so we have to jump one node further.
+ while (pNode->Next[i] && dwIndex + pNode->Distance[i] <= ElementIndex)
+ {
+ dwIndex += pNode->Distance[i];
+ pNode = pNode->Next[i];
+ }
+ }
+
+ // We are right in front of the node we're looking for now.
+ return pNode->Next[0];
+}
--- /dev/null
+/*
+ * PROJECT: Skiplist implementation for the ReactOS Project
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Interfaces for the Skiplist
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#ifndef _REACTOS_SKIPLIST_H
+#define _REACTOS_SKIPLIST_H
+
+// Define SKIPLIST_LEVELS to a value between 1 and 31 before including this header.
+// This specifies the maximum number of levels you want your Skiplist to have.
+// A value of X is recommended for handling up to 2^X elements.
+#ifndef SKIPLIST_LEVELS
+#error Please define SKIPLIST_LEVELS to a value between 1 and 31.
+#endif
+
+C_ASSERT(SKIPLIST_LEVELS >= 1);
+C_ASSERT(SKIPLIST_LEVELS <= 31);
+
+// Function pointer definitions
+typedef PVOID (WINAPI *PSKIPLIST_ALLOCATE_ROUTINE)(DWORD);
+typedef int (WINAPI *PSKIPLIST_COMPARE_ROUTINE)(PVOID, PVOID);
+typedef void (WINAPI *PSKIPLIST_FREE_ROUTINE)(PVOID);
+
+// Structure definitions
+typedef struct _SKIPLIST_NODE
+{
+ DWORD Distance[SKIPLIST_LEVELS];
+ struct _SKIPLIST_NODE* Next[SKIPLIST_LEVELS];
+ PVOID Element;
+}
+SKIPLIST_NODE, *PSKIPLIST_NODE;
+
+typedef struct _SKIPLIST
+{
+ SKIPLIST_NODE Head;
+ CHAR MaximumLevel;
+ DWORD NodeCount;
+ PSKIPLIST_ALLOCATE_ROUTINE AllocateRoutine;
+ PSKIPLIST_COMPARE_ROUTINE CompareRoutine;
+ PSKIPLIST_FREE_ROUTINE FreeRoutine;
+}
+SKIPLIST, *PSKIPLIST;
+
+// Function prototypes
+void InitializeSkiplist(PSKIPLIST Skiplist, PSKIPLIST_ALLOCATE_ROUTINE AllocateRoutine, PSKIPLIST_COMPARE_ROUTINE CompareRoutine, PSKIPLIST_FREE_ROUTINE FreeRoutine);
+BOOL InsertElementSkiplist(PSKIPLIST Skiplist, PVOID Element);
+BOOL InsertTailElementSkiplist(PSKIPLIST Skiplist, PVOID Element);
+PVOID DeleteElementSkiplist(PSKIPLIST Skiplist, PVOID Element);
+PVOID LookupElementSkiplist(PSKIPLIST Skiplist, PVOID Element, PDWORD ElementIndex);
+PSKIPLIST_NODE LookupNodeByIndexSkiplist(PSKIPLIST Skiplist, DWORD ElementIndex);
+
+#endif
--- /dev/null
+/*
+ * PROJECT: Skiplist implementation for the ReactOS Project
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: A simple program for testing the Skiplist implementation
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include <windows.h>
+#include <stdio.h>
+#include "skiplist.h"
+
+void
+DumpSkiplist(PSKIPLIST Skiplist)
+{
+ CHAR i;
+ DWORD j;
+ PSKIPLIST_NODE pNode;
+
+ printf("======= DUMPING SKIPLIST =======\n");
+
+ for (i = Skiplist->MaximumLevel + 1; --i >= 0;)
+ {
+ pNode = &Skiplist->Head;
+ printf("H");
+
+ while (pNode->Next[i])
+ {
+ printf("-");
+
+ // By using the Distance array for painting the lines, we verify both the links and the distances for correctness.
+ for (j = 1; j < pNode->Distance[i]; j++)
+ printf("---");
+
+ printf("%02lu", (DWORD)pNode->Next[i]->Element);
+
+ pNode = pNode->Next[i];
+ }
+
+ printf("\n");
+ }
+
+ printf("================================\n\n");
+}
+
+PVOID WINAPI
+MyAlloc(DWORD Size)
+{
+ return HeapAlloc(GetProcessHeap(), 0, Size);
+}
+
+int WINAPI
+MyCompare(PVOID A, PVOID B)
+{
+ return (DWORD)A - (DWORD)B;
+}
+
+void WINAPI
+MyFree(PVOID Ptr)
+{
+ HeapFree(GetProcessHeap(), 0, Ptr);
+}
+
+int
+main()
+{
+ DWORD Element;
+ DWORD ElementIndex;
+ DWORD i;
+ SKIPLIST Skiplist;
+ PSKIPLIST_NODE pNode;
+
+ system("mode con cols=300");
+ InitializeSkiplist(&Skiplist, MyAlloc, MyCompare, MyFree);
+
+ // Insert some random elements with random numbers.
+ for (i = 0; i < 40; i++)
+ InsertElementSkiplist(&Skiplist, (PVOID)(rand() % 100));
+
+ // Delete all with index 0 to 29.
+ for (i = 0; i < 30; i++)
+ DeleteElementSkiplist(&Skiplist, (PVOID)i);
+
+ // Insert some more random elements.
+ for (i = 0; i < 40; i++)
+ InsertElementSkiplist(&Skiplist, (PVOID)(rand() % 100));
+
+ // Output the third element (with zero-based index 2).
+ pNode = LookupNodeByIndexSkiplist(&Skiplist, 2);
+ printf("Element = %lu for index 2\n", (DWORD)pNode->Element);
+
+ // Check if an element with number 44 is in the list and output its index.
+ Element = (DWORD)LookupElementSkiplist(&Skiplist, (PVOID)44, &ElementIndex);
+ printf("Element = %lu, ElementIndex = %lu\n\n", Element, ElementIndex);
+
+ DumpSkiplist(&Skiplist);
+
+ return 0;
+}
endif()
add_subdirectory(gdi/gdi32)
+add_subdirectory(printing)
add_subdirectory(reactx)
add_subdirectory(user/user32)
add_subdirectory(user/winsrv)
--- /dev/null
+include_directories(include)
+
+add_subdirectory(base)
+#add_subdirectory(drivers)
+add_subdirectory(monitors)
+add_subdirectory(processors)
+add_subdirectory(providers)
--- /dev/null
+#add_subdirectory(printui)
+add_subdirectory(spoolss)
+add_subdirectory(spoolsv)
+add_subdirectory(winspool)
--- /dev/null
+
+spec2def(spoolss.dll spoolss.spec ADD_IMPORTLIB)
+
+list(APPEND SOURCE
+ context.c
+ jobs.c
+ main.c
+ memory.c
+ monitors.c
+ ports.c
+ precomp.h
+ printers.c
+ printprocessors.c
+ tools.c)
+
+add_library(spoolss SHARED
+ ${SOURCE}
+ spoolss.rc
+ ${CMAKE_CURRENT_BINARY_DIR}/spoolss_stubs.c
+ ${CMAKE_CURRENT_BINARY_DIR}/spoolss.def)
+
+set_module_type(spoolss win32dll UNICODE)
+target_link_libraries(spoolss wine)
+add_importlibs(spoolss advapi32 msvcrt kernel32 ntdll)
+add_pch(spoolss precomp.h SOURCE)
+add_cd_file(TARGET spoolss DESTINATION reactos/system32 FOR all)
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler Router
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to switching between security contexts
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+/**
+ * @see RevertToPrinterSelf
+ */
+BOOL WINAPI
+ImpersonatePrinterClient(HANDLE hToken)
+{
+ DWORD cbReturned;
+ DWORD dwErrorCode;
+ TOKEN_TYPE Type;
+
+ // Sanity check
+ if (!hToken)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Get the type of the supplied token.
+ if (!GetTokenInformation(hToken, TokenType, &Type, sizeof(TOKEN_TYPE), &cbReturned))
+ {
+ dwErrorCode = GetLastError();
+ ERR("GetTokenInformation failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Check if this is an impersonation token and only set it as the thread token in this case.
+ // This is not always an impersonation token, see RevertToPrinterSelf.
+ if (Type == TokenImpersonation)
+ {
+ if (!SetThreadToken(NULL, hToken))
+ {
+ dwErrorCode = GetLastError();
+ ERR("SetThreadToken failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+ }
+
+Cleanup:
+ if (hToken)
+ CloseHandle(hToken);
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+/**
+ * RevertToPrinterSelf reverts the security context from the current user's context back to the process context.
+ * As spoolss.dll is used by spoolsv.exe, this is usually the SYSTEM security context.
+ *
+ * Unlike the traditional ImpersonateClient and then RevertToSelf approach, we do it the other way round here,
+ * because spoolss.dll is delay-loaded by spoolsv.exe in the current user's context. Use RevertToPrinterSelf then to
+ * return to the SYSTEM context for specific tasks.
+ */
+HANDLE WINAPI
+RevertToPrinterSelf()
+{
+ DWORD dwErrorCode;
+ HANDLE hReturnValue = NULL;
+ HANDLE hToken = NULL;
+
+ // All spoolss code is usually called after impersonating the client. In this case, we can retrieve our current thread impersonation token using OpenThreadToken.
+ // But in rare occasions, spoolss code is also called from a higher-privileged thread that doesn't impersonate the client. Then we don't get an impersonation token.
+ // Anyway, we can't just return nothing in this case, because this is being treated as failure by the caller. So we return the token of the current process.
+ // This behaviour is verified with Windows!
+ if (OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE, TRUE, &hToken))
+ {
+ // Tell the thread to stop impersonating.
+ if (!SetThreadToken(NULL, NULL))
+ {
+ dwErrorCode = GetLastError();
+ ERR("SetThreadToken failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+ }
+ else if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
+ {
+ dwErrorCode = GetLastError();
+ ERR("OpenProcessToken failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // We were successful, return a token!
+ dwErrorCode = ERROR_SUCCESS;
+ hReturnValue = hToken;
+
+ // Don't let the cleanup routine close this.
+ hToken = NULL;
+
+Cleanup:
+ if (hToken)
+ CloseHandle(hToken);
+
+ SetLastError(dwErrorCode);
+ return hReturnValue;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler Router
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions for managing print jobs
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+BOOL WINAPI
+AddJobW(HANDLE hPrinter, DWORD Level, PBYTE pData, DWORD cbBuf, PDWORD pcbNeeded)
+{
+ PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ return pHandle->pPrintProvider->PrintProvider.fpAddJob(pHandle->hPrinter, Level, pData, cbBuf, pcbNeeded);
+}
+
+BOOL WINAPI
+EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ return pHandle->pPrintProvider->PrintProvider.fpEnumJobs(pHandle->hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned);
+}
+
+BOOL WINAPI
+GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded)
+{
+ PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ return pHandle->pPrintProvider->PrintProvider.fpGetJob(pHandle->hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
+}
+
+BOOL WINAPI
+ScheduleJob(HANDLE hPrinter, DWORD dwJobID)
+{
+ PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ return pHandle->pPrintProvider->PrintProvider.fpScheduleJob(pHandle->hPrinter, dwJobID);
+}
+
+BOOL WINAPI
+SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command)
+{
+ PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ return pHandle->pPrintProvider->PrintProvider.fpSetJob(pHandle->hPrinter, JobId, Level, pJobInfo, Command);
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler Router
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Main functions
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+// Global Variables
+HANDLE hProcessHeap;
+LIST_ENTRY PrintProviderList;
+
+
+static DWORD
+_AddPrintProviderToList(PCWSTR pwszFileName)
+{
+ DWORD dwErrorCode;
+ HINSTANCE hinstPrintProvider;
+ PInitializePrintProvidor pfnInitializePrintProvidor;
+ PSPOOLSS_PRINT_PROVIDER pPrintProvider = NULL;
+
+ // Try to load it.
+ hinstPrintProvider = LoadLibraryW(pwszFileName);
+ if (!hinstPrintProvider)
+ {
+ dwErrorCode = GetLastError();
+ ERR("LoadLibraryW failed for \"%S\" with error %lu!\n", pwszFileName, dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Get the initialization routine.
+ pfnInitializePrintProvidor = (PInitializePrintProvidor)GetProcAddress(hinstPrintProvider, "InitializePrintProvidor");
+ if (!pfnInitializePrintProvidor)
+ {
+ dwErrorCode = GetLastError();
+ ERR("GetProcAddress failed for \"%S\" with error %lu!\n", pwszFileName, dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Create a new SPOOLSS_PRINT_PROVIDER structure for it.
+ pPrintProvider = DllAllocSplMem(sizeof(SPOOLSS_PRINT_PROVIDER));
+ if (!pPrintProvider)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Call the Print Provider initialization function.
+ if (!pfnInitializePrintProvidor(&pPrintProvider->PrintProvider, sizeof(PRINTPROVIDOR), NULL))
+ {
+ dwErrorCode = GetLastError();
+ ERR("InitializePrintProvidor failed for \"%S\" with error %lu!\n", pwszFileName, dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Add this Print Provider to the list.
+ InsertTailList(&PrintProviderList, &pPrintProvider->Entry);
+
+ // Don't let the cleanup routine free this.
+ pPrintProvider = NULL;
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ if (pPrintProvider)
+ DllFreeSplMem(pPrintProvider);
+
+ return dwErrorCode;
+}
+
+static BOOL
+_InitializePrintProviderList()
+{
+ DWORD cbFileName;
+ DWORD cchMaxSubKey;
+ DWORD cchPrintProviderName;
+ DWORD dwErrorCode;
+ DWORD dwSubKeys;
+ DWORD i;
+ HKEY hKey = NULL;
+ HKEY hSubKey = NULL;
+ PWSTR pwszPrintProviderName = NULL;
+ WCHAR wszFileName[MAX_PATH];
+
+ // Initialize an empty list for our Print Providers.
+ InitializeListHead(&PrintProviderList);
+
+ // First add the Local Spooler.
+ // This one must exist and must be the first one in the list.
+ dwErrorCode = _AddPrintProviderToList(L"localspl");
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("The Local Spooler could not be loaded!\n");
+ goto Cleanup;
+ }
+
+ // Now add additional Print Providers from the registry.
+ // First of all, open the key containing print providers.
+ dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Print\\Providers", 0, KEY_READ, &hKey);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Get the number of Print Providers and maximum sub key length.
+ dwErrorCode = (DWORD)RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &dwSubKeys, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Allocate a temporary buffer for the Print Provider names.
+ pwszPrintProviderName = DllAllocSplMem((cchMaxSubKey + 1) * sizeof(WCHAR));
+ if (!pwszPrintProviderName)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Loop through all available Print Providers.
+ for (i = 0; i < dwSubKeys; i++)
+ {
+ // Cleanup tasks from the previous run
+ if (hSubKey)
+ {
+ RegCloseKey(hSubKey);
+ hSubKey = NULL;
+ }
+
+ // Get the name of this Print Provider.
+ cchPrintProviderName = cchMaxSubKey + 1;
+ dwErrorCode = (DWORD)RegEnumKeyExW(hKey, i, pwszPrintProviderName, &cchPrintProviderName, NULL, NULL, NULL, NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegEnumKeyExW failed for iteration %lu with status %lu!\n", i, dwErrorCode);
+ continue;
+ }
+
+ // Open this Print Provider's registry key.
+ dwErrorCode = (DWORD)RegOpenKeyExW(hKey, pwszPrintProviderName, 0, KEY_READ, &hSubKey);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegOpenKeyExW failed for Print Provider \"%S\" with status %lu!\n", pwszPrintProviderName, dwErrorCode);
+ continue;
+ }
+
+ // Get the file name of the Print Provider.
+ cbFileName = MAX_PATH * sizeof(WCHAR);
+ dwErrorCode = (DWORD)RegQueryValueExW(hKey, L"Driver", NULL, NULL, (PBYTE)wszFileName, &cbFileName);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
+ continue;
+ }
+
+ // Load and add it to the list.
+ dwErrorCode = _AddPrintProviderToList(wszFileName);
+ if (dwErrorCode != ERROR_SUCCESS)
+ continue;
+ }
+
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ // Inside the loop
+ if (hSubKey)
+ RegCloseKey(hSubKey);
+
+ // Outside the loop
+ if (pwszPrintProviderName)
+ DllFreeSplMem(pwszPrintProviderName);
+
+ if (hKey)
+ RegCloseKey(hKey);
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ DisableThreadLibraryCalls(hinstDLL);
+ hProcessHeap = GetProcessHeap();
+ break;
+ }
+
+ return TRUE;
+}
+
+BOOL WINAPI
+InitializeRouter(HANDLE SpoolerStatusHandle)
+{
+ return _InitializePrintProviderList();
+}
+
+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;
+}
+
+BOOL WINAPI
+SpoolerInit()
+{
+ // Nothing to do here yet
+ SetLastError(ERROR_SUCCESS);
+ return TRUE;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler Router
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Print Monitors
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+BOOL WINAPI
+EnumMonitorsW(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ BOOL bReturnValue;
+ DWORD cbCallBuffer;
+ DWORD cbNeeded;
+ DWORD dwReturned;
+ PBYTE pCallBuffer;
+ PSPOOLSS_PRINT_PROVIDER pPrintProvider;
+ PLIST_ENTRY pEntry;
+
+ // Sanity checks.
+ if ((cbBuf && !pMonitors) || !pcbNeeded || !pcReturned)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ // Begin counting.
+ *pcbNeeded = 0;
+ *pcReturned = 0;
+
+ // At the beginning, we have the full buffer available.
+ cbCallBuffer = cbBuf;
+ pCallBuffer = pMonitors;
+
+ // Loop through all Print Provider.
+ for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
+ {
+ pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
+
+ // Check if this Print Provider provides an EnumMonitors function.
+ if (!pPrintProvider->PrintProvider.fpEnumMonitors)
+ continue;
+
+ // Call the EnumMonitors function of this Print Provider.
+ bReturnValue = pPrintProvider->PrintProvider.fpEnumMonitors(pName, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
+
+ // Add the returned counts to the total values.
+ *pcbNeeded += cbNeeded;
+ *pcReturned += dwReturned;
+
+ // Reduce the available buffer size for the next call without risking an underflow.
+ if (cbNeeded < cbCallBuffer)
+ cbCallBuffer -= cbNeeded;
+ else
+ cbCallBuffer = 0;
+
+ // Advance the buffer if the caller provided it.
+ if (pCallBuffer)
+ pCallBuffer += cbNeeded;
+
+ // Check if we shall not ask other Print Providers.
+ if (bReturnValue == ROUTER_STOP_ROUTING)
+ break;
+ }
+
+ return bReturnValue;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler Router
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Ports of the Print Monitors
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+BOOL WINAPI
+EnumPortsW(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ BOOL bReturnValue;
+ DWORD cbCallBuffer;
+ DWORD cbNeeded;
+ DWORD dwReturned;
+ PBYTE pCallBuffer;
+ PSPOOLSS_PRINT_PROVIDER pPrintProvider;
+ PLIST_ENTRY pEntry;
+
+ // Sanity checks.
+ if ((cbBuf && !pPorts) || !pcbNeeded || !pcReturned)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ // Begin counting.
+ *pcbNeeded = 0;
+ *pcReturned = 0;
+
+ // At the beginning, we have the full buffer available.
+ cbCallBuffer = cbBuf;
+ pCallBuffer = pPorts;
+
+ // Loop through all Print Provider.
+ for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
+ {
+ pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
+
+ // Call the EnumPorts function of this Print Provider.
+ bReturnValue = pPrintProvider->PrintProvider.fpEnumPorts(pName, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
+
+ // Add the returned counts to the total values.
+ *pcbNeeded += cbNeeded;
+ *pcReturned += dwReturned;
+
+ // Reduce the available buffer size for the next call without risking an underflow.
+ if (cbNeeded < cbCallBuffer)
+ cbCallBuffer -= cbNeeded;
+ else
+ cbCallBuffer = 0;
+
+ // Advance the buffer if the caller provided it.
+ if (pCallBuffer)
+ pCallBuffer += cbNeeded;
+
+ // Check if we shall not ask other Print Providers.
+ if (bReturnValue == ROUTER_STOP_ROUTING)
+ break;
+ }
+
+ return bReturnValue;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler Router
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Precompiled Header for all source files
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#ifndef _PRECOMP_H
+#define _PRECOMP_H
+
+#define WIN32_NO_STATUS
+#include <windef.h>
+#include <winbase.h>
+#include <wingdi.h>
+#include <winreg.h>
+#include <winspool.h>
+#include <winsplp.h>
+#include <ndk/rtlfuncs.h>
+
+#include <spoolss.h>
+
+#include <wine/debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(spoolss);
+
+// Function pointers
+typedef BOOL (WINAPI *PInitializePrintProvidor)(LPPRINTPROVIDOR, DWORD, LPWSTR);
+
+// Structures
+/**
+ * Describes a Print Provider.
+ */
+typedef struct _SPOOLSS_PRINT_PROVIDER
+{
+ LIST_ENTRY Entry;
+ PRINTPROVIDOR PrintProvider;
+}
+SPOOLSS_PRINT_PROVIDER, *PSPOOLSS_PRINT_PROVIDER;
+
+/*
+ * Describes a handle returned by OpenPrinterW.
+ * We can't just pass the handle returned by the Print Provider, because spoolss has to remember which Print Provider opened this handle.
+ */
+typedef struct _SPOOLSS_PRINTER_HANDLE
+{
+ PSPOOLSS_PRINT_PROVIDER pPrintProvider; /** Pointer to the Print Provider that opened this printer. */
+ HANDLE hPrinter; /** The handle returned by fpOpenPrinter of the Print Provider and passed to subsequent Print Provider functions. */
+}
+SPOOLSS_PRINTER_HANDLE, *PSPOOLSS_PRINTER_HANDLE;
+
+// main.c
+extern HANDLE hProcessHeap;
+extern LIST_ENTRY PrintProviderList;
+
+#endif
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler Router
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Printers and printing
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+
+BOOL WINAPI
+ClosePrinter(HANDLE hPrinter)
+{
+ BOOL bReturnValue;
+ PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ // FIXME: Call FindClosePrinterChangeNotification for all created change notifications (according to MSDN).
+
+ // Call CloseHandle of the Print Provider.
+ bReturnValue = pHandle->pPrintProvider->PrintProvider.fpClosePrinter(pHandle->hPrinter);
+
+ // Free our handle information.
+ DllFreeSplMem(pHandle);
+
+ return bReturnValue;
+}
+
+BOOL WINAPI
+EndDocPrinter(HANDLE hPrinter)
+{
+ PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ return pHandle->pPrintProvider->PrintProvider.fpEndDocPrinter(pHandle->hPrinter);
+}
+
+BOOL WINAPI
+EndPagePrinter(HANDLE hPrinter)
+{
+ PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ return pHandle->pPrintProvider->PrintProvider.fpEndPagePrinter(pHandle->hPrinter);
+}
+
+BOOL WINAPI
+EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ BOOL bReturnValue;
+ DWORD cbCallBuffer;
+ DWORD cbNeeded;
+ DWORD dwReturned;
+ PBYTE pCallBuffer;
+ PSPOOLSS_PRINT_PROVIDER pPrintProvider;
+ PLIST_ENTRY pEntry;
+
+ // Sanity checks.
+ if ((cbBuf && !pPrinterEnum) || !pcbNeeded || !pcReturned)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ // Begin counting.
+ *pcbNeeded = 0;
+ *pcReturned = 0;
+
+ // At the beginning, we have the full buffer available.
+ cbCallBuffer = cbBuf;
+ pCallBuffer = pPrinterEnum;
+
+ // Loop through all Print Provider.
+ for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
+ {
+ pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
+
+ // Call the EnumPrinters function of this Print Provider.
+ bReturnValue = pPrintProvider->PrintProvider.fpEnumPrinters(Flags, Name, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
+
+ // Add the returned counts to the total values.
+ *pcbNeeded += cbNeeded;
+ *pcReturned += dwReturned;
+
+ // Reduce the available buffer size for the next call without risking an underflow.
+ if (cbNeeded < cbCallBuffer)
+ cbCallBuffer -= cbNeeded;
+ else
+ cbCallBuffer = 0;
+
+ // Advance the buffer if the caller provided it.
+ if (pCallBuffer)
+ pCallBuffer += cbNeeded;
+ }
+
+ return bReturnValue;
+}
+
+BOOL WINAPI
+GetPrinterDriverW(HANDLE hPrinter, PWSTR pEnvironment, DWORD Level, PBYTE pDriverInfo, DWORD cbBuf, PDWORD pcbNeeded)
+{
+ PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ return pHandle->pPrintProvider->PrintProvider.fpGetPrinterDriver(pHandle->hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
+}
+
+BOOL WINAPI
+GetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD cbBuf, PDWORD pcbNeeded)
+{
+ PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ return pHandle->pPrintProvider->PrintProvider.fpGetPrinter(pHandle->hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
+}
+
+BOOL WINAPI
+OpenPrinterW(PWSTR pPrinterName, PHANDLE phPrinter, PPRINTER_DEFAULTSW pDefault)
+{
+ BOOL bReturnValue;
+ HANDLE hPrinter;
+ PLIST_ENTRY pEntry;
+ PSPOOLSS_PRINTER_HANDLE pHandle;
+ PSPOOLSS_PRINT_PROVIDER pPrintProvider;
+
+ // Sanity checks.
+ if (!pPrinterName || !phPrinter)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ // Loop through all Print Providers to find one able to open this Printer.
+ for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
+ {
+ pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
+
+ bReturnValue = pPrintProvider->PrintProvider.fpOpenPrinter(pPrinterName, &hPrinter, pDefault);
+ if (bReturnValue == ROUTER_SUCCESS)
+ {
+ // This Print Provider has opened this Printer.
+ // Store this information and return a handle.
+ pHandle = DllAllocSplMem(sizeof(SPOOLSS_PRINTER_HANDLE));
+ if (!pHandle)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ return FALSE;
+ }
+
+ pHandle->pPrintProvider = pPrintProvider;
+ pHandle->hPrinter = hPrinter;
+ *phPrinter = (HANDLE)pHandle;
+
+ SetLastError(ERROR_SUCCESS);
+ return TRUE;
+ }
+ else if (bReturnValue == ROUTER_STOP_ROUTING)
+ {
+ ERR("A Print Provider returned ROUTER_STOP_ROUTING for Printer \"%S\"!\n", pPrinterName);
+ return FALSE;
+ }
+ }
+
+ // We found no Print Provider able to open this Printer.
+ return FALSE;
+}
+
+BOOL WINAPI
+ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
+{
+ PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ return pHandle->pPrintProvider->PrintProvider.fpReadPrinter(pHandle->hPrinter, pBuf, cbBuf, pNoBytesRead);
+}
+
+DWORD WINAPI
+StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
+{
+ PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ return pHandle->pPrintProvider->PrintProvider.fpStartDocPrinter(pHandle->hPrinter, Level, pDocInfo);
+}
+
+BOOL WINAPI
+StartPagePrinter(HANDLE hPrinter)
+{
+ PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ return pHandle->pPrintProvider->PrintProvider.fpStartPagePrinter(pHandle->hPrinter);
+}
+
+BOOL WINAPI
+WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
+{
+ PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ return pHandle->pPrintProvider->PrintProvider.fpWritePrinter(pHandle->hPrinter, pBuf, cbBuf, pcWritten);
+}
+
+BOOL WINAPI
+XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus)
+{
+ PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hXcv;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ return pHandle->pPrintProvider->PrintProvider.fpXcvData(pHandle->hPrinter, pszDataName, pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler Router
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Print Processors
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+BOOL WINAPI
+EnumPrintProcessorDatatypesW(PWSTR pName, PWSTR pPrintProcessorName, DWORD Level, PBYTE pDatatypes, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ // Always call this function on the Local Spooler.
+ PSPOOLSS_PRINT_PROVIDER pPrintProvider = CONTAINING_RECORD(&PrintProviderList.Flink, SPOOLSS_PRINT_PROVIDER, Entry);
+ return pPrintProvider->PrintProvider.fpEnumPrintProcessorDatatypes(pName, pPrintProcessorName, Level, pDatatypes, cbBuf, pcbNeeded, pcReturned);
+}
+
+BOOL WINAPI
+EnumPrintProcessorsW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ // Always call this function on the Local Spooler.
+ PSPOOLSS_PRINT_PROVIDER pPrintProvider = CONTAINING_RECORD(&PrintProviderList.Flink, SPOOLSS_PRINT_PROVIDER, Entry);
+ return pPrintProvider->PrintProvider.fpEnumPrintProcessors(pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded, pcReturned);
+}
+
+BOOL WINAPI
+GetPrintProcessorDirectoryW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded)
+{
+ // Always call this function on the Local Spooler.
+ PSPOOLSS_PRINT_PROVIDER pPrintProvider = CONTAINING_RECORD(&PrintProviderList.Flink, SPOOLSS_PRINT_PROVIDER, Entry);
+ return pPrintProvider->PrintProvider.fpGetPrintProcessorDirectory(pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded);
+}
--- /dev/null
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Spooler Router"
+#define REACTOS_STR_INTERNAL_NAME "spoolss"
+#define REACTOS_STR_ORIGINAL_FILENAME "spoolss.dll"
+#include <reactos/version.rc>
@ stub AbortPrinter
+@ stub AddDriverCatalog
@ stub AddFormW
-@ stub AddJobW
-@ stdcall AddMonitorW(wstr long ptr)
+@ stdcall AddJobW(long long ptr long ptr)
+@ stub AddMonitorW
@ stub AddPerMachineConnectionW
@ stub AddPortExW
@ stub AddPortW
-@ stub AddPrintProcessorW
-@ stub AddPrintProvidorW
@ stub AddPrinterConnectionW
-@ stdcall AddPrinterDriverExW(wstr long ptr long)
+@ stub AddPrinterDriverExW
@ stub AddPrinterDriverW
@ stub AddPrinterExW
@ stub AddPrinterW
-@ stdcall AllocSplStr(wstr)
+@ stub AddPrintProcessorW
+@ stub AddPrintProvidorW
+@ stub AdjustPointers
+@ stub AdjustPointersInStructuresArray
+@ stub AlignKMPtr
+@ stub AlignRpcPtr
+@ stdcall AllocSplStr(ptr)
+@ stub AllowRemoteCalls
@ stub AppendPrinterNotifyInfoData
-@ stdcall BuildOtherNamesFromMachineName(ptr ptr)
+@ stub bGetDevModePerUser
+@ stub bSetDevModePerUser
+@ stub BuildOtherNamesFromMachineName
+@ stub CacheAddName
+@ stub CacheCreateAndAddNode
+@ stub CacheCreateAndAddNodeWithIPAddresses
+@ stub CacheDeleteNode
+@ stub CacheIsNameCluster
+@ stub CacheIsNameInNodeList
@ stub CallDrvDevModeConversion
@ stub CallRouterFindFirstPrinterChangeNotification
-@ stub ClosePrinter
+@ stub CheckLocalCall
+@ stdcall ClosePrinter(long)
@ stub ClusterSplClose
@ stub ClusterSplIsAlive
@ stub ClusterSplOpen
@ stub CreatePrinterIC
@ stub DbgGetPointers
@ stub DeleteFormW
-@ stdcall DeleteMonitorW(wstr wstr wstr)
+@ stub DeleteMonitorW
@ stub DeletePerMachineConnectionW
@ stub DeletePortW
-@ stub DeletePrintProcessorW
-@ stub DeletePrintProvidorW
@ stub DeletePrinter
@ stub DeletePrinterConnectionW
@ stub DeletePrinterDataExW
@ stub DeletePrinterDriverW
@ stub DeletePrinterIC
@ stub DeletePrinterKeyW
+@ stub DeletePrintProcessorW
+@ stub DeletePrintProvidorW
@ stdcall DllAllocSplMem(long)
@ stdcall DllFreeSplMem(ptr)
-@ stdcall DllFreeSplStr(wstr)
-@ stub EndDocPrinter
-@ stub EndPagePrinter
+@ stdcall DllFreeSplStr(ptr)
+@ stdcall EndDocPrinter(long)
+@ stdcall EndPagePrinter(long)
@ stub EnumFormsW
-@ stub EnumJobsW
+@ stdcall EnumJobsW(long long long long ptr long ptr ptr)
@ stdcall EnumMonitorsW(wstr long ptr long ptr ptr)
@ stub EnumPerMachineConnectionsW
@ stdcall EnumPortsW(wstr long ptr long ptr ptr)
-@ stub EnumPrintProcessorDatatypesW
-@ stub EnumPrintProcessorsW
@ stub EnumPrinterDataExW
@ stub EnumPrinterDataW
@ stub EnumPrinterDriversW
@ stub EnumPrinterKeyW
-@ stub EnumPrintersW
+@ stdcall EnumPrintersW(long wstr long ptr long ptr ptr)
+@ stdcall EnumPrintProcessorDatatypesW(wstr wstr long ptr long ptr ptr)
+@ stdcall EnumPrintProcessorsW(wstr wstr long ptr long ptr ptr)
@ stub FindClosePrinterChangeNotification
@ stub FlushPrinter
@ stub FormatPrinterForRegistryKey
@ stub GetClientUserHandle
@ stub GetFormW
@ stub GetJobAttributes
-@ stub GetJobW
+@ stdcall GetJobW(long long long ptr long ptr)
@ stub GetNetworkId
-@ stub GetPrintProcessorDirectoryW
@ stub GetPrinterDataExW
@ stub GetPrinterDataW
-@ stdcall GetPrinterDriverDirectoryW(wstr wstr long ptr long ptr)
+@ stub GetPrinterDriverDirectoryW
@ stub GetPrinterDriverExW
-@ stub GetPrinterDriverW
-@ stub GetPrinterW
+@ stdcall GetPrinterDriverW(long wstr long ptr long ptr)
+@ stdcall GetPrinterW(long long ptr long ptr)
+@ stdcall GetPrintProcessorDirectoryW(wstr wstr long ptr long ptr)
+@ stub GetServerPolicy
+@ stub GetShrinkedSize
@ stdcall ImpersonatePrinterClient(long)
-@ stdcall InitializeRouter()
-@ stdcall IsLocalCall()
+@ stdcall InitializeRouter(long)
@ stub IsNamedPipeRpcCall
@ stub LoadDriver
@ stub LoadDriverFiletoConvertDevmode
+@ stub LoadDriverWithVersion
+@ stub LogWmiTraceEvent
+@ stdcall MarshallDownStructure(ptr ptr long long)
+@ stub MarshallDownStructuresArray
+@ stub MarshallUpStructure
+@ stub MarshallUpStructuresArray
@ stub MIDL_user_allocate1
@ stub MIDL_user_free1
-@ stub MarshallDownStructure
-@ stub MarshallUpStructure
@ stub OldGetPrinterDriverW
@ stub OpenPrinterExW
@ stub OpenPrinterPortW
-@ stub OpenPrinterW
-@ stub PackStrings
+@ stdcall OpenPrinterW(wstr ptr ptr)
+@ stdcall PackStrings(ptr ptr ptr ptr)
@ stub PartialReplyPrinterChangeNotification
@ stub PlayGdiScriptOnPrinterIC
@ stub PrinterHandleRundown
@ stub PrinterMessageBoxW
@ stub ProvidorFindClosePrinterChangeNotification
@ stub ProvidorFindFirstPrinterChangeNotification
-@ stub ReadPrinter
-@ stub ReallocSplMem
-@ stub ReallocSplStr
+@ stub pszDbgAllocMsgA
+@ stdcall ReadPrinter(long ptr long ptr)
+@ stdcall ReallocSplMem(ptr long long)
+@ stdcall ReallocSplStr(ptr ptr)
@ stub RemoteFindFirstPrinterChangeNotification
@ stub ReplyClosePrinter
@ stub ReplyOpenPrinter
@ stub ReplyPrinterChangeNotification
@ stub ResetPrinterW
@ stdcall RevertToPrinterSelf()
+@ stub RouterAllocBidiMem
+@ stub RouterAllocBidiResponseContainer
@ stub RouterAllocPrinterNotifyInfo
@ stub RouterFindFirstPrinterChangeNotification
@ stub RouterFindNextPrinterChangeNotification
+@ stub RouterFreeBidiMem
@ stub RouterFreePrinterNotifyInfo
@ stub RouterRefreshPrinterChangeNotification
@ stub RouterReplyPrinter
-@ stub ScheduleJob
+@ stdcall ScheduleJob(long long)
@ stub SeekPrinter
+@ stub SendRecvBidiData
@ stub SetAllocFailCount
@ stub SetFormW
-@ stub SetJobW
+@ stdcall SetJobW(long long long ptr long)
@ stub SetPortW
@ stub SetPrinterDataExW
@ stub SetPrinterDataW
@ stub SplDriverUnloadComplete
@ stub SplGetSpoolFileInfo
@ stdcall SplInitializeWinSpoolDrv(ptr)
+@ stub SplIsSessionZero
@ stdcall SplIsUpgrade()
+@ stub SplPowerEvent
@ stub SplProcessPnPEvent
+@ stub SplPromptUIInUsersSession
@ stub SplReadPrinter
@ stub SplRegisterForDeviceEvents
-@ stub SplStartPhase2Init
+@ stub SplShutDownRouter
@ stub SplUnregisterForDeviceEvents
@ stub SpoolerFindClosePrinterChangeNotification
@ stub SpoolerFindFirstPrinterChangeNotification
@ stub SpoolerFindNextPrinterChangeNotification
@ stub SpoolerFreePrinterNotifyInfo
-@ stdcall SpoolerHasInitialized()
+@ stub SpoolerHasInitialized
@ stdcall SpoolerInit()
-@ stub StartDocPrinterW
-@ stub StartPagePrinter
+@ stdcall StartDocPrinterW(long long ptr)
+@ stdcall StartPagePrinter(long)
+@ stub UndoAlignKMPtr
+@ stub UndoAlignRpcPtr
@ stub UnloadDriver
@ stub UnloadDriverFile
@ stub UpdateBufferSize
@ stub UpdatePrinterRegAll
@ stub UpdatePrinterRegUser
-@ stub WaitForPrinterChange
-@ stdcall WaitForSpoolerInitialization()
-@ stub WritePrinter
-@ stub XcvDataW
-@ stub bGetDevModePerUser
-@ stub bSetDevModePerUser
-@ stub pszDbgAllocMsgA
@ stub vDbgLogError
+@ stub WaitForPrinterChange
+@ stub WaitForSpoolerInitialization
+@ stdcall WritePrinter(long ptr long ptr)
+@ stdcall XcvDataW(long wstr ptr long ptr long ptr ptr)
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler Router
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Miscellaneous tool functions
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+
+/**
+ * @name MarshallDownStructure
+ *
+ * Prepare a structure for marshalling/serialization by replacing absolute pointer addresses in its fields by relative offsets.
+ *
+ * @param pStructure
+ * Pointer to the structure to operate on.
+ *
+ * @param pParameters
+ * Array of MARSHALL_DOWN_INFO elements containing information about the fields of the structure as well as how to modify them.
+ * See the documentation on MARSHALL_DOWN_INFO for more information.
+ * You have to indicate the end of the array by setting the dwOffset field to MAXDWORD.
+ *
+ * @param cbStructureSize
+ * Apparently, this is the size in bytes of the structure given through pStructure under Windows.
+ * This parameter is unused in my implementation.
+ *
+ * @param bSomeBoolean
+ * Unknown boolean value
+ *
+ * @return
+ * TRUE if the structure was successfully adjusted, FALSE otherwise.
+ */
+BOOL WINAPI
+MarshallDownStructure(PVOID pStructure, PMARSHALL_DOWN_INFO pParameters, DWORD cbStructureSize, BOOL bSomeBoolean)
+{
+ // Sanity checks
+ if (!pStructure || !pParameters)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ // Loop until we reach an element with offset set to MAXDWORD.
+ while (pParameters->dwOffset != MAXDWORD)
+ {
+ if (pParameters->bAdjustAddress)
+ {
+ // Apply the byte offset on pStructure. There must be a pointer at this position, whose address we're adjusting
+ // by subtracting the address of pStructure from it.
+ *((PULONG_PTR)((PBYTE)pStructure + pParameters->dwOffset)) -= (ULONG_PTR)pStructure;
+ }
+
+ // Advance to the next element description.
+ pParameters++;
+ }
+
+ return TRUE;
+}
+
+/**
+ * @name PackStrings
+ *
+ * Takes an array of Unicode strings and fills an output buffer with these strings at the end and pointers to each string at specific offsets.
+ * Useful helper for functions that copy an information structure including strings into a given buffer (like PRINTER_INFO_1).
+ *
+ * @param pSource
+ * The array of Unicode strings to copy. Needs to have at least as many elements as the DestOffsets array.
+ *
+ * @param pDest
+ * Pointer to the beginning of the output buffer.
+ * The caller is responsible for verifying that this buffer is large enough to hold all strings and pointers.
+ *
+ * @param DestOffsets
+ * Array of byte offsets in the output buffer. For each element of DestOffsets, the function will copy the address of the corresponding copied
+ * string of pSource to this location in the output buffer. If a string in pSource is NULL, the function will set the pointer address to NULL
+ * in the output buffer.
+ * Use macros like FIELD_OFFSET to calculate the offsets for this array.
+ * The last element of the array must have the value MAXDWORD to let the function detect the end of the array.
+ *
+ * @param pEnd
+ * Pointer to the end of the output buffer. That means the first element outside of the buffer given in pDest.
+ *
+ * @return
+ * Returns a pointer to the beginning of the strings in pDest.
+ * The strings are copied in reverse order, so this pointer will point to the last copied string of pSource.
+ */
+PBYTE WINAPI
+PackStrings(PCWSTR* pSource, PBYTE pDest, PDWORD DestOffsets, PBYTE pEnd)
+{
+ DWORD cbString;
+ ULONG_PTR StringAddress;
+
+ // Loop until we reach an element with offset set to MAXDWORD.
+ while (*DestOffsets != MAXDWORD)
+ {
+ StringAddress = 0;
+
+ if (*pSource)
+ {
+ // Determine the length of the source string.
+ cbString = (wcslen(*pSource) + 1) * sizeof(WCHAR);
+
+ // Copy it before the last string.
+ pEnd -= cbString;
+ StringAddress = (ULONG_PTR)pEnd;
+ CopyMemory(pEnd, *pSource, cbString);
+ }
+
+ // Copy the address of the copied string to the location given by the offset.
+ CopyMemory(&pDest[*DestOffsets], &StringAddress, sizeof(ULONG_PTR));
+
+ // Advance to the next source string and destination offset.
+ pSource++;
+ DestOffsets++;
+ }
+
+ // pEnd is now at the last string we copied. Return this value as a pointer to the beginning of all strings in the output buffer.
+ return pEnd;
+}
--- /dev/null
+
+include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/idl)
+add_rpc_files(server ${REACTOS_SOURCE_DIR}/sdk/include/reactos/idl/winspool.idl)
+
+list(APPEND SOURCE
+ forms.c
+ init.c
+ jobs.c
+ main.c
+ monitors.c
+ notifications.c
+ ports.c
+ precomp.h
+ printerdata.c
+ printerdrivers.c
+ printers.c
+ printprocessors.c
+ printproviders.c
+ rpcserver.c
+ rpcstubs.c
+ xcv.c
+ ${CMAKE_CURRENT_BINARY_DIR}/winspool_s.c)
+
+add_executable(spoolsv ${SOURCE} spoolsv.rc)
+set_module_type(spoolsv win32cui UNICODE)
+target_link_libraries(spoolsv wine)
+add_delay_importlibs(spoolsv spoolss)
+add_importlibs(spoolsv advapi32 rpcrt4 msvcrt kernel32 ntdll)
+add_pch(spoolsv precomp.h SOURCE)
+add_cd_file(TARGET spoolsv DESTINATION reactos/system32 FOR all)
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler Service
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Forms
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+DWORD
+_RpcAddForm(WINSPOOL_PRINTER_HANDLE hPrinter, WINSPOOL_FORM_CONTAINER* pFormInfoContainer)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcDeleteForm(WINSPOOL_PRINTER_HANDLE hPrinter, WCHAR* pFormName)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcEnumForms(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD Level, BYTE* pForm, DWORD cbBuf, DWORD* pcbNeeded, DWORD* pcReturned)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcGetForm(WINSPOOL_PRINTER_HANDLE hPrinter, WCHAR* pFormName, DWORD Level, BYTE* pForm, DWORD cbBuf, DWORD* pcbNeeded)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcSetForm(WINSPOOL_PRINTER_HANDLE hPrinter, WCHAR* pFormName, WINSPOOL_FORM_CONTAINER* pFormInfoContainer)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler Service
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Various initialization functions
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+DWORD
+_RpcSpoolerInit()
+{
+ DWORD dwErrorCode;
+
+ // Call SpoolerInit in the security context of the client.
+ // This delay-loads spoolss.dll in the user context and all further calls to functions in spoolss.dll will be done in the user context as well.
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ SpoolerInit();
+ dwErrorCode = GetLastError();
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler Service
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions for managing print jobs
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+static void
+_MarshallDownAddJobInfo(PADDJOB_INFO_1W pAddJobInfo1)
+{
+ // Replace absolute pointer addresses in the output by relative offsets.
+ pAddJobInfo1->Path = (PWSTR)((ULONG_PTR)pAddJobInfo1->Path - (ULONG_PTR)pAddJobInfo1);
+}
+
+static void
+_MarshallDownJobInfo(PBYTE pJobInfo, DWORD Level)
+{
+ PJOB_INFO_1W pJobInfo1;
+ PJOB_INFO_2W pJobInfo2;
+
+ // Replace absolute pointer addresses in the output by relative offsets.
+ if (Level == 1)
+ {
+ pJobInfo1 = (PJOB_INFO_1W)pJobInfo;
+ pJobInfo1->pDatatype = (PWSTR)((ULONG_PTR)pJobInfo1->pDatatype - (ULONG_PTR)pJobInfo1);
+ pJobInfo1->pDocument = (PWSTR)((ULONG_PTR)pJobInfo1->pDocument - (ULONG_PTR)pJobInfo1);
+ pJobInfo1->pMachineName = (PWSTR)((ULONG_PTR)pJobInfo1->pMachineName - (ULONG_PTR)pJobInfo1);
+ pJobInfo1->pPrinterName = (PWSTR)((ULONG_PTR)pJobInfo1->pPrinterName - (ULONG_PTR)pJobInfo1);
+
+ if (pJobInfo1->pStatus)
+ pJobInfo1->pStatus = (PWSTR)((ULONG_PTR)pJobInfo1->pStatus - (ULONG_PTR)pJobInfo1);
+
+ pJobInfo1->pUserName = (PWSTR)((ULONG_PTR)pJobInfo1->pUserName - (ULONG_PTR)pJobInfo1);
+ }
+ else if (Level == 2)
+ {
+ pJobInfo2 = (PJOB_INFO_2W)pJobInfo;
+ pJobInfo2->pDatatype = (PWSTR)((ULONG_PTR)pJobInfo2->pDatatype - (ULONG_PTR)pJobInfo2);
+ pJobInfo2->pDevMode = (PDEVMODEW)((ULONG_PTR)pJobInfo2->pDevMode - (ULONG_PTR)pJobInfo2);
+ pJobInfo2->pDocument = (PWSTR)((ULONG_PTR)pJobInfo2->pDocument - (ULONG_PTR)pJobInfo2);
+ pJobInfo2->pDriverName = (PWSTR)((ULONG_PTR)pJobInfo2->pDriverName - (ULONG_PTR)pJobInfo2);
+ pJobInfo2->pMachineName = (PWSTR)((ULONG_PTR)pJobInfo2->pMachineName - (ULONG_PTR)pJobInfo2);
+ pJobInfo2->pNotifyName = (PWSTR)((ULONG_PTR)pJobInfo2->pNotifyName - (ULONG_PTR)pJobInfo2);
+ pJobInfo2->pPrinterName = (PWSTR)((ULONG_PTR)pJobInfo2->pPrinterName - (ULONG_PTR)pJobInfo2);
+ pJobInfo2->pPrintProcessor = (PWSTR)((ULONG_PTR)pJobInfo2->pPrintProcessor - (ULONG_PTR)pJobInfo2);
+
+ if (pJobInfo2->pParameters)
+ pJobInfo2->pParameters = (PWSTR)((ULONG_PTR)pJobInfo2->pParameters - (ULONG_PTR)pJobInfo2);
+
+ if (pJobInfo2->pStatus)
+ pJobInfo2->pStatus = (PWSTR)((ULONG_PTR)pJobInfo2->pStatus - (ULONG_PTR)pJobInfo2);
+
+ pJobInfo2->pUserName = (PWSTR)((ULONG_PTR)pJobInfo2->pUserName - (ULONG_PTR)pJobInfo2);
+ }
+}
+
+DWORD
+_RpcAddJob(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD Level, BYTE* pAddJob, DWORD cbBuf, DWORD* pcbNeeded)
+{
+ DWORD dwErrorCode;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ AddJobW(hPrinter, Level, pAddJob, cbBuf, pcbNeeded);
+ dwErrorCode = GetLastError();
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ _MarshallDownAddJobInfo((PADDJOB_INFO_1W)pAddJob);
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
+
+DWORD
+_RpcEnumJobs(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, BYTE* pJob, DWORD cbBuf, DWORD* pcbNeeded, DWORD* pcReturned)
+{
+ DWORD dwErrorCode;
+ DWORD i;
+ PBYTE p = pJob;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ EnumJobsW(hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned);
+ dwErrorCode = GetLastError();
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ // Replace absolute pointer addresses in the output by relative offsets.
+ for (i = 0; i < *pcReturned; i++)
+ {
+ _MarshallDownJobInfo(p, Level);
+
+ if (Level == 1)
+ p += sizeof(JOB_INFO_1W);
+ else if (Level == 2)
+ p += sizeof(JOB_INFO_2W);
+ }
+ }
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
+
+DWORD
+_RpcGetJob(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD JobId, DWORD Level, BYTE* pJob, DWORD cbBuf, DWORD* pcbNeeded)
+{
+ DWORD dwErrorCode;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ GetJobW(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
+ dwErrorCode = GetLastError();
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ // Replace absolute pointer addresses in the output by relative offsets.
+ _MarshallDownJobInfo(pJob, Level);
+ }
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
+
+DWORD
+_RpcScheduleJob(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD JobId)
+{
+ DWORD dwErrorCode;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ ScheduleJob(hPrinter, JobId);
+ dwErrorCode = GetLastError();
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
+
+DWORD
+_RpcSetJob(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD JobId, WINSPOOL_JOB_CONTAINER* pJobContainer, DWORD Command)
+{
+ DWORD dwErrorCode;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ // pJobContainer->JobInfo is a union of pointers, so we can just convert any element to our BYTE pointer.
+ SetJobW(hPrinter, JobId, pJobContainer->Level, (PBYTE)pJobContainer->JobInfo.Level1, Command);
+ dwErrorCode = GetLastError();
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler Service
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Main functions
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+SERVICE_STATUS_HANDLE hServiceStatus;
+SERVICE_STATUS ServiceStatus;
+WCHAR wszServiceName[] = L"Spooler";
+
+static void
+_UpdateServiceStatus(DWORD dwNewStatus, DWORD dwCheckPoint)
+{
+ ServiceStatus.dwCheckPoint = dwCheckPoint;
+ ServiceStatus.dwCurrentState = dwNewStatus;
+ SetServiceStatus(hServiceStatus, &ServiceStatus);
+}
+
+static DWORD WINAPI
+_ServiceControlHandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
+{
+ switch (dwControl)
+ {
+ case SERVICE_CONTROL_SHUTDOWN:
+ case SERVICE_CONTROL_STOP:
+ _UpdateServiceStatus(SERVICE_STOP_PENDING, 1);
+ RpcMgmtStopServerListening(NULL);
+ _UpdateServiceStatus(SERVICE_STOPPED, 0);
+ return NO_ERROR;
+
+ case SERVICE_CONTROL_INTERROGATE:
+ return NO_ERROR;
+
+ default:
+ return ERROR_CALL_NOT_IMPLEMENTED;
+ }
+}
+
+static VOID WINAPI
+_ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv)
+{
+ HANDLE hThread;
+
+ UNREFERENCED_PARAMETER(dwArgc);
+ UNREFERENCED_PARAMETER(lpszArgv);
+
+ // Register our service for control
+ hServiceStatus = RegisterServiceCtrlHandlerExW(wszServiceName, _ServiceControlHandlerEx, NULL);
+
+ // Report initial SERVICE_START_PENDING status
+ ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+ ServiceStatus.dwServiceSpecificExitCode = 0;
+ ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ ServiceStatus.dwWaitHint = 4000;
+ ServiceStatus.dwWin32ExitCode = NO_ERROR;
+ _UpdateServiceStatus(SERVICE_START_PENDING, 0);
+
+ // Create a thread for serving RPC requests
+ hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)LrpcThreadProc, NULL, 0, NULL);
+ if (!hThread)
+ {
+ ERR("CreateThread failed with error %u!\n", GetLastError());
+ _UpdateServiceStatus(SERVICE_STOPPED, 0);
+ return;
+ }
+
+ // We don't need the thread handle. Keeping it open blocks the thread from terminating.
+ CloseHandle(hThread);
+
+ // Initialize the routing layer in spoolss.dll
+ if (!InitializeRouter(hServiceStatus))
+ {
+ ERR("InitializeRouter failed with error %lu!\n", GetLastError());
+ _UpdateServiceStatus(SERVICE_STOPPED, 0);
+ return;
+ }
+
+ // We're alive!
+ _UpdateServiceStatus(SERVICE_RUNNING, 0);
+}
+
+int
+wmain(int argc, WCHAR* argv[])
+{
+ SERVICE_TABLE_ENTRYW ServiceTable[] =
+ {
+ {wszServiceName, _ServiceMain},
+ {NULL, NULL}
+ };
+
+ UNREFERENCED_PARAMETER(argc);
+ UNREFERENCED_PARAMETER(argv);
+
+ StartServiceCtrlDispatcherW(ServiceTable);
+
+ return 0;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler Service
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Print Monitors
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+static void
+_MarshallDownMonitorInfo(PBYTE pMonitorInfo, DWORD Level)
+{
+ PMONITOR_INFO_2W pMonitorInfo2 = (PMONITOR_INFO_2W)pMonitorInfo; // MONITOR_INFO_1W is a subset of MONITOR_INFO_2W
+
+ // Replace absolute pointer addresses in the output by relative offsets.
+ pMonitorInfo2->pName = (PWSTR)((ULONG_PTR)pMonitorInfo2->pName - (ULONG_PTR)pMonitorInfo2);
+
+ if (Level == 2)
+ {
+ pMonitorInfo2->pDLLName = (PWSTR)((ULONG_PTR)pMonitorInfo2->pDLLName - (ULONG_PTR)pMonitorInfo2);
+ pMonitorInfo2->pEnvironment = (PWSTR)((ULONG_PTR)pMonitorInfo2->pEnvironment - (ULONG_PTR)pMonitorInfo2);
+ }
+}
+
+DWORD
+_RpcAddMonitor(WINSPOOL_HANDLE pName, WINSPOOL_MONITOR_CONTAINER* pMonitorContainer)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcDeleteMonitor(WINSPOOL_HANDLE pName, WCHAR* pEnvironment, WCHAR* pMonitorName)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcEnumMonitors(WINSPOOL_HANDLE pName, DWORD Level, BYTE* pMonitor, DWORD cbBuf, DWORD* pcbNeeded, DWORD* pcReturned)
+{
+ DWORD dwErrorCode;
+ DWORD i;
+ PBYTE p = pMonitor;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ EnumMonitorsW(pName, Level, pMonitor, cbBuf, pcbNeeded, pcReturned);
+ dwErrorCode = GetLastError();
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ // Replace absolute pointer addresses in the output by relative offsets.
+ for (i = 0; i < *pcReturned; i++)
+ {
+ _MarshallDownMonitorInfo(p, Level);
+
+ if (Level == 1)
+ p += sizeof(MONITOR_INFO_1W);
+ else if (Level == 2)
+ p += sizeof(MONITOR_INFO_2W);
+ }
+ }
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler Service
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Printer Configuration Data
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+DWORD
+_RpcClientFindFirstPrinterChangeNotification()
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcFindClosePrinterChangeNotification()
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcFindNextPrinterChangeNotification()
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcRemoteFindFirstPrinterChangeNotification(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD fdwFlags, DWORD fdwOptions, WCHAR* pszLocalMachine, DWORD dwPrinterLocal, DWORD cbBuffer, BYTE* pBuffer)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcRemoteFindFirstPrinterChangeNotificationEx(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD fdwFlags, DWORD fdwOptions, WCHAR* pszLocalMachine, DWORD dwPrinterLocal, WINSPOOL_V2_NOTIFY_OPTIONS* pOptions)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcReplyClosePrinter(WINSPOOL_PRINTER_HANDLE* phNotify)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcReplyOpenPrinter(WINSPOOL_HANDLE pMachine, WINSPOOL_PRINTER_HANDLE* phPrinterNotify, DWORD dwPrinterRemote, DWORD dwType, DWORD cbBuffer, BYTE* pBuffer)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcRouterFindFirstPrinterChangeNotificationOld()
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcRouterRefreshPrinterChangeNotification(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD dwColor, WINSPOOL_V2_NOTIFY_OPTIONS* pOptions, WINSPOOL_V2_NOTIFY_INFO** ppInfo)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcRouterReplyPrinter(WINSPOOL_PRINTER_HANDLE hNotify, DWORD fdwFlags, DWORD cbBuffer, BYTE* pBuffer)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcRouterReplyPrinterEx(WINSPOOL_PRINTER_HANDLE hNotify, DWORD dwColor, DWORD fdwFlags, DWORD* pdwResult, DWORD dwReplyType, WINSPOOL_V2_UREPLY_PRINTER Reply)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcWaitForPrinterChange(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD Flags, DWORD* pFlags)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler Service
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Ports
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+static void
+_MarshallDownPortInfo(PBYTE pPortInfo, DWORD Level)
+{
+ PPORT_INFO_2W pPortInfo2 = (PPORT_INFO_2W)pPortInfo; // PORT_INFO_1W is a subset of PORT_INFO_2W
+
+ // Replace absolute pointer addresses in the output by relative offsets.
+ pPortInfo2->pPortName = (PWSTR)((ULONG_PTR)pPortInfo2->pPortName - (ULONG_PTR)pPortInfo2);
+
+ if (Level == 2)
+ {
+ pPortInfo2->pDescription = (PWSTR)((ULONG_PTR)pPortInfo2->pDescription - (ULONG_PTR)pPortInfo2);
+ pPortInfo2->pMonitorName = (PWSTR)((ULONG_PTR)pPortInfo2->pMonitorName - (ULONG_PTR)pPortInfo2);
+ }
+}
+
+DWORD
+_RpcAddPort(WINSPOOL_HANDLE pName, ULONG_PTR hWnd, WCHAR* pMonitorName)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcAddPortEx(WINSPOOL_HANDLE pName, WINSPOOL_PORT_CONTAINER* pPortContainer, WINSPOOL_PORT_VAR_CONTAINER* pPortVarContainer, WCHAR* pMonitorName)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcConfigurePort(WINSPOOL_HANDLE pName, ULONG_PTR hWnd, WCHAR* pPortName)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcDeletePort(WINSPOOL_HANDLE pName, ULONG_PTR hWnd, WCHAR* pPortName)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcEnumPorts(WINSPOOL_HANDLE pName, DWORD Level, BYTE* pPort, DWORD cbBuf, DWORD* pcbNeeded, DWORD* pcReturned)
+{
+ DWORD dwErrorCode;
+ DWORD i;
+ PBYTE p = pPort;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ EnumPortsW(pName, Level, pPort, cbBuf, pcbNeeded, pcReturned);
+ dwErrorCode = GetLastError();
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ // Replace absolute pointer addresses in the output by relative offsets.
+ for (i = 0; i < *pcReturned; i++)
+ {
+ _MarshallDownPortInfo(p, Level);
+
+ if (Level == 1)
+ p += sizeof(PORT_INFO_1W);
+ else if (Level == 2)
+ p += sizeof(PORT_INFO_2W);
+ }
+ }
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
+
+DWORD
+_RpcSetPort(WINSPOOL_HANDLE pName, WCHAR* pPortName, WINSPOOL_PORT_CONTAINER* pPortContainer)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler Service
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Precompiled Header for all source files
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#ifndef _PRECOMP_H
+#define _PRECOMP_H
+
+#define WIN32_NO_STATUS
+#include <windef.h>
+#include <winbase.h>
+#include <winreg.h>
+#include <winsvc.h>
+#include <wingdi.h>
+#include <winspool.h>
+#include <winsplp.h>
+#include <winspool_s.h>
+
+#include <wine/debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(spoolsv);
+
+// rpcserver.c
+DWORD WINAPI LrpcThreadProc(LPVOID lpParameter);
+
+// Undocumented spoolss
+BOOL WINAPI InitializeRouter(HANDLE SpoolerStatusHandle);
+DWORD WINAPI SpoolerInit();
+
+#endif
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler Service
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Printer Configuration Data
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+DWORD
+_RpcDeletePrinterData(WINSPOOL_PRINTER_HANDLE hPrinter, WCHAR* pValueName)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcDeletePrinterDataEx(WINSPOOL_PRINTER_HANDLE hPrinter, const WCHAR* pKeyName, const WCHAR* pValueName)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcDeletePrinterKey(WINSPOOL_PRINTER_HANDLE hPrinter, const WCHAR* pKeyName)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcEnumPrinterData(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD dwIndex, WCHAR* pValueName, DWORD cbValueName, DWORD* pcbValueName, DWORD* pType, BYTE* pData, DWORD cbData, DWORD* pcbData)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcEnumPrinterKey(WINSPOOL_PRINTER_HANDLE hPrinter, const WCHAR* pKeyName, WCHAR* pSubkey, DWORD cbSubkey, DWORD* pcbSubkey)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcEnumPrinterDataEx(WINSPOOL_PRINTER_HANDLE hPrinter, const WCHAR* pKeyName, BYTE* pEnumValues, DWORD cbEnumValues, DWORD* pcbEnumValues, DWORD* pnEnumValues)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcGetPrinterData(WINSPOOL_PRINTER_HANDLE hPrinter, WCHAR* pValueName, DWORD* pType, BYTE* pData, DWORD nSize, DWORD* pcbNeeded)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcGetPrinterDataEx(WINSPOOL_PRINTER_HANDLE hPrinter, const WCHAR* pKeyName, const WCHAR* pValueName, DWORD* pType, BYTE* pData, DWORD nSize, DWORD* pcbNeeded)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcSetPrinterData(WINSPOOL_PRINTER_HANDLE hPrinter, WCHAR* pValueName, DWORD Type, BYTE* pData, DWORD cbData)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcSetPrinterDataEx(WINSPOOL_PRINTER_HANDLE hPrinter, const WCHAR* pKeyName, const WCHAR* pValueName, DWORD Type, BYTE* pData, DWORD cbData)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler Service
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Printer Drivers
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+DWORD
+_RpcAddPrinterDriver(WINSPOOL_HANDLE pName, WINSPOOL_DRIVER_CONTAINER* pDriverContainer)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcAddPrinterDriverEx(WINSPOOL_HANDLE pName, WINSPOOL_DRIVER_CONTAINER* pDriverContainer, DWORD dwFileCopyFlags)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcDeletePrinterDriver(WINSPOOL_HANDLE pName, WCHAR* pEnvironment, WCHAR* pDriverName)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcDeletePrinterDriverEx(WINSPOOL_HANDLE pName, WCHAR* pEnvironment, WCHAR* pDriverName, DWORD dwDeleteFlag, DWORD dwVersionNum)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcEnumPrinterDrivers(WINSPOOL_HANDLE pName, WCHAR* pEnvironment, DWORD Level, BYTE* pDrivers, DWORD cbBuf, DWORD* pcbNeeded, DWORD* pcReturned)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcGetPrinterDriver(WINSPOOL_PRINTER_HANDLE hPrinter, WCHAR* pEnvironment, DWORD Level, BYTE* pDriver, DWORD cbBuf, DWORD* pcbNeeded)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcGetPrinterDriver2(WINSPOOL_PRINTER_HANDLE hPrinter, WCHAR* pEnvironment, DWORD Level, BYTE* pDriver, DWORD cbBuf, DWORD* pcbNeeded, DWORD dwClientMajorVersion, DWORD dwClientMinorVersion, DWORD* pdwServerMaxVersion, DWORD* pdwServerMinVersion)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcGetPrinterDriverDirectory(WINSPOOL_HANDLE pName, WCHAR* pEnvironment, DWORD Level, BYTE* pDriverDirectory, DWORD cbBuf, DWORD* pcbNeeded)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler Service
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Printers and printing
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+static void
+_MarshallDownPrinterInfo(PBYTE pPrinterInfo, DWORD Level)
+{
+ PPRINTER_INFO_1W pPrinterInfo1;
+ PPRINTER_INFO_2W pPrinterInfo2;
+
+ // Replace absolute pointer addresses in the output by relative offsets.
+ if (Level == 1)
+ {
+ pPrinterInfo1 = (PPRINTER_INFO_1W)pPrinterInfo;
+
+ pPrinterInfo1->pName = (PWSTR)((ULONG_PTR)pPrinterInfo1->pName - (ULONG_PTR)pPrinterInfo1);
+ pPrinterInfo1->pDescription = (PWSTR)((ULONG_PTR)pPrinterInfo1->pDescription - (ULONG_PTR)pPrinterInfo1);
+ pPrinterInfo1->pComment = (PWSTR)((ULONG_PTR)pPrinterInfo1->pComment - (ULONG_PTR)pPrinterInfo1);
+ }
+ else if (Level == 2)
+ {
+ pPrinterInfo2 = (PPRINTER_INFO_2W)pPrinterInfo;
+
+ pPrinterInfo2->pPrinterName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pPrinterName - (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pShareName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pShareName - (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pPortName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pPortName - (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pDriverName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pDriverName - (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pComment = (PWSTR)((ULONG_PTR)pPrinterInfo2->pComment - (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pLocation = (PWSTR)((ULONG_PTR)pPrinterInfo2->pLocation - (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pDevMode = (PDEVMODEW)((ULONG_PTR)pPrinterInfo2->pDevMode - (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pSepFile = (PWSTR)((ULONG_PTR)pPrinterInfo2->pSepFile - (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pPrintProcessor = (PWSTR)((ULONG_PTR)pPrinterInfo2->pPrintProcessor - (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pDatatype = (PWSTR)((ULONG_PTR)pPrinterInfo2->pDatatype - (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pParameters = (PWSTR)((ULONG_PTR)pPrinterInfo2->pParameters - (ULONG_PTR)pPrinterInfo2);
+
+ if (pPrinterInfo2->pServerName)
+ pPrinterInfo2->pServerName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pServerName - (ULONG_PTR)pPrinterInfo2);
+
+ if (pPrinterInfo2->pSecurityDescriptor)
+ pPrinterInfo2->pSecurityDescriptor = (PWSTR)((ULONG_PTR)pPrinterInfo2->pSecurityDescriptor - (ULONG_PTR)pPrinterInfo2);
+ }
+}
+
+DWORD
+_RpcAbortPrinter(WINSPOOL_PRINTER_HANDLE hPrinter)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcAddPrinter(WINSPOOL_HANDLE pName, WINSPOOL_PRINTER_CONTAINER* pPrinterContainer, WINSPOOL_DEVMODE_CONTAINER* pDevModeContainer, WINSPOOL_SECURITY_CONTAINER* pSecurityContainer, WINSPOOL_PRINTER_HANDLE* pHandle)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcAddPrinterEx(WINSPOOL_HANDLE pName, WINSPOOL_PRINTER_CONTAINER* pPrinterContainer, WINSPOOL_DEVMODE_CONTAINER* pDevModeContainer, WINSPOOL_SECURITY_CONTAINER* pSecurityContainer, WINSPOOL_SPLCLIENT_CONTAINER* pClientInfo, WINSPOOL_PRINTER_HANDLE* pHandle)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcClosePrinter(WINSPOOL_PRINTER_HANDLE* phPrinter)
+{
+ DWORD dwErrorCode;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ if (ClosePrinter(*phPrinter))
+ *phPrinter = NULL;
+
+ dwErrorCode = GetLastError();
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
+
+DWORD
+_RpcDeletePrinter(WINSPOOL_PRINTER_HANDLE hPrinter)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcEndDocPrinter(WINSPOOL_PRINTER_HANDLE hPrinter)
+{
+ DWORD dwErrorCode;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ EndDocPrinter(hPrinter);
+ dwErrorCode = GetLastError();
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
+
+DWORD
+_RpcEndPagePrinter(WINSPOOL_PRINTER_HANDLE hPrinter)
+{
+ DWORD dwErrorCode;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ EndPagePrinter(hPrinter);
+ dwErrorCode = GetLastError();
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
+
+DWORD
+_RpcEnumPrinters(DWORD Flags, WINSPOOL_HANDLE Name, DWORD Level, BYTE* pPrinterEnum, DWORD cbBuf, DWORD* pcbNeeded, DWORD* pcReturned)
+{
+ DWORD dwErrorCode;
+ DWORD i;
+ PBYTE p = pPrinterEnum;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ EnumPrintersW(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
+ dwErrorCode = GetLastError();
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ // Replace absolute pointer addresses in the output by relative offsets.
+ for (i = 0; i < *pcReturned; i++)
+ {
+ _MarshallDownPrinterInfo(p, Level);
+
+ if (Level == 1)
+ p += sizeof(PRINTER_INFO_1W);
+ else if (Level == 2)
+ p += sizeof(PRINTER_INFO_2W);
+ }
+ }
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
+
+DWORD
+_RpcFlushPrinter(WINSPOOL_PRINTER_HANDLE hPrinter, BYTE* pBuf, DWORD cbBuf, DWORD* pcWritten, DWORD cSleep)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcGetPrinter(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD Level, BYTE* pPrinter, DWORD cbBuf, DWORD* pcbNeeded)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcOpenPrinter(WINSPOOL_HANDLE pPrinterName, WINSPOOL_PRINTER_HANDLE* phPrinter, WCHAR* pDatatype, WINSPOOL_DEVMODE_CONTAINER* pDevModeContainer, DWORD AccessRequired)
+{
+ DWORD dwErrorCode;
+ PRINTER_DEFAULTSW Default;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ Default.DesiredAccess = AccessRequired;
+ Default.pDatatype = pDatatype;
+ Default.pDevMode = (PDEVMODEW)pDevModeContainer->pDevMode;
+
+ OpenPrinterW(pPrinterName, phPrinter, &Default);
+ dwErrorCode = GetLastError();
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
+
+DWORD
+_RpcOpenPrinterEx(WINSPOOL_HANDLE pPrinterName, WINSPOOL_PRINTER_HANDLE* pHandle, WCHAR* pDatatype, WINSPOOL_DEVMODE_CONTAINER* pDevModeContainer, DWORD AccessRequired, WINSPOOL_SPLCLIENT_CONTAINER* pClientInfo)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcReadPrinter(WINSPOOL_PRINTER_HANDLE hPrinter, BYTE* pBuf, DWORD cbBuf, DWORD* pcNoBytesRead)
+{
+ DWORD dwErrorCode;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ ReadPrinter(hPrinter, pBuf, cbBuf, pcNoBytesRead);
+ dwErrorCode = GetLastError();
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
+
+DWORD
+_RpcResetPrinter(WINSPOOL_PRINTER_HANDLE hPrinter, WCHAR* pDatatype, WINSPOOL_DEVMODE_CONTAINER* pDevModeContainer)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcResetPrinterEx()
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcSeekPrinter()
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcSetPrinter(WINSPOOL_PRINTER_HANDLE hPrinter, WINSPOOL_PRINTER_CONTAINER* pPrinterContainer, WINSPOOL_DEVMODE_CONTAINER* pDevModeContainer, WINSPOOL_SECURITY_CONTAINER* pSecurityContainer, DWORD Command)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcStartDocPrinter(WINSPOOL_PRINTER_HANDLE hPrinter, WINSPOOL_DOC_INFO_CONTAINER* pDocInfoContainer, DWORD* pJobId)
+{
+ DWORD dwErrorCode;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ *pJobId = StartDocPrinterW(hPrinter, pDocInfoContainer->Level, (PBYTE)pDocInfoContainer->DocInfo.pDocInfo1);
+ dwErrorCode = GetLastError();
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
+
+DWORD
+_RpcStartPagePrinter(WINSPOOL_PRINTER_HANDLE hPrinter)
+{
+ DWORD dwErrorCode;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ StartPagePrinter(hPrinter);
+ dwErrorCode = GetLastError();
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
+
+DWORD
+_RpcWritePrinter(WINSPOOL_PRINTER_HANDLE hPrinter, BYTE* pBuf, DWORD cbBuf, DWORD* pcWritten)
+{
+ DWORD dwErrorCode;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ WritePrinter(hPrinter, pBuf, cbBuf, pcWritten);
+ dwErrorCode = GetLastError();
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler Service
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Print Processors
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+static void
+_MarshallDownDatatypesInfo(PDATATYPES_INFO_1W pDatatypesInfo1)
+{
+ // Replace absolute pointer addresses in the output by relative offsets.
+ pDatatypesInfo1->pName = (PWSTR)((ULONG_PTR)pDatatypesInfo1->pName - (ULONG_PTR)pDatatypesInfo1);
+}
+
+static void
+_MarshallDownPrintProcessorInfo(PPRINTPROCESSOR_INFO_1W pPrintProcessorInfo1)
+{
+ // Replace absolute pointer addresses in the output by relative offsets.
+ pPrintProcessorInfo1->pName = (PWSTR)((ULONG_PTR)pPrintProcessorInfo1->pName - (ULONG_PTR)pPrintProcessorInfo1);
+}
+
+DWORD
+_RpcAddPrintProcessor(WINSPOOL_HANDLE pName, WCHAR* pEnvironment, WCHAR* pPathName, WCHAR* pPrintProcessorName)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcDeletePrintProcessor(WINSPOOL_HANDLE pName, WCHAR* pEnvironment, WCHAR* pPrintProcessorName)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcEnumPrintProcessorDatatypes(WINSPOOL_HANDLE pName, WCHAR* pPrintProcessorName, DWORD Level, BYTE* pDatatypes, DWORD cbBuf, DWORD* pcbNeeded, DWORD* pcReturned)
+{
+ DWORD dwErrorCode;
+ DWORD i;
+ PBYTE p = pDatatypes;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ EnumPrintProcessorDatatypesW(pName, pPrintProcessorName, Level, pDatatypes, cbBuf, pcbNeeded, pcReturned);
+ dwErrorCode = GetLastError();
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ // Replace absolute pointer addresses in the output by relative offsets.
+ for (i = 0; i < *pcReturned; i++)
+ {
+ _MarshallDownDatatypesInfo((PDATATYPES_INFO_1W)p);
+ p += sizeof(DATATYPES_INFO_1W);
+ }
+ }
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
+
+DWORD
+_RpcEnumPrintProcessors(WINSPOOL_HANDLE pName, WCHAR* pEnvironment, DWORD Level, BYTE* pPrintProcessorInfo, DWORD cbBuf, DWORD* pcbNeeded, DWORD* pcReturned)
+{
+ DWORD dwErrorCode;
+ DWORD i;
+ PBYTE p = pPrintProcessorInfo;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ EnumPrintProcessorsW(pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded, pcReturned);
+ dwErrorCode = GetLastError();
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ // Replace absolute pointer addresses in the output by relative offsets.
+ for (i = 0; i < *pcReturned; i++)
+ {
+ _MarshallDownPrintProcessorInfo((PPRINTPROCESSOR_INFO_1W)p);
+ p += sizeof(PRINTPROCESSOR_INFO_1W);
+ }
+ }
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
+
+DWORD
+_RpcGetPrintProcessorDirectory(WINSPOOL_HANDLE pName, WCHAR* pEnvironment, DWORD Level, BYTE* pPrintProcessorDirectory, DWORD cbBuf, DWORD* pcbNeeded)
+{
+ DWORD dwErrorCode;
+
+ dwErrorCode = RpcImpersonateClient(NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
+ return dwErrorCode;
+ }
+
+ GetPrintProcessorDirectoryW(pName, pEnvironment, Level, pPrintProcessorDirectory, cbBuf, pcbNeeded);
+ dwErrorCode = GetLastError();
+
+ RpcRevertToSelf();
+ return dwErrorCode;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler Service
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Print Providers
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+DWORD
+_RpcAddPrintProvidor(WINSPOOL_HANDLE pName, WINSPOOL_PROVIDOR_CONTAINER* pProvidorContainer)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcDeletePrintProvidor(WINSPOOL_HANDLE pName, WCHAR* pEnvironment, WCHAR* pPrintProviderName)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler Service
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: RPC Server Thread
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+DWORD WINAPI
+LrpcThreadProc(LPVOID lpParameter)
+{
+ RPC_STATUS Status;
+
+ Status = RpcServerUseProtseqEpW(L"ncalrpc", 20, L"spoolss", NULL);
+ if (Status != RPC_S_OK)
+ {
+ ERR("RpcServerUseProtseqEpW failed with status %ld!\n", Status);
+ return 0;
+ }
+
+ Status = RpcServerRegisterIf(winspool_v1_0_s_ifspec, NULL, NULL);
+ if (Status != RPC_S_OK)
+ {
+ ERR("RpcServerRegisterIf failed with status %ld!\n", Status);
+ return 0;
+ }
+
+ Status = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, 0);
+ if (Status != RPC_S_OK)
+ {
+ ERR("RpcServerListen() failed with status %ld!\n", Status);
+ }
+
+ return 0;
+}
+
+void __RPC_FAR* __RPC_USER
+midl_user_allocate(SIZE_T len)
+{
+ return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
+}
+
+void __RPC_USER
+midl_user_free(void __RPC_FAR* ptr)
+{
+ HeapFree(GetProcessHeap(), 0, ptr);
+}
+
+void __RPC_USER
+WINSPOOL_GDI_HANDLE_rundown(WINSPOOL_GDI_HANDLE hGdiHandle)
+{
+}
+
+void __RPC_USER
+WINSPOOL_PRINTER_HANDLE_rundown(WINSPOOL_PRINTER_HANDLE hPrinter)
+{
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler Service
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Unimplemented RPC calls
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+DWORD
+_RpcCreatePrinterIC(WINSPOOL_PRINTER_HANDLE hPrinter, WINSPOOL_GDI_HANDLE* pHandle, WINSPOOL_DEVMODE_CONTAINER* pDevModeContainer)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcPlayGdiScriptOnPrinterIC(WINSPOOL_GDI_HANDLE hPrinterIC, BYTE* pIn, DWORD cIn, BYTE* pOut, DWORD cOut, DWORD ul)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcDeletePrinterIC(WINSPOOL_GDI_HANDLE* phPrinterIC)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcAddPrinterConnection(WINSPOOL_HANDLE pName)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcDeletePrinterConnection(WINSPOOL_HANDLE pName)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcPrinterMessageBox(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD Error, ULONG_PTR hWnd, WCHAR* pText, WCHAR* pCaption, DWORD dwType)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcSetAllocFailCount()
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcClusterSplOpen()
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcClusterSplClose()
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcClusterSplIsAlive()
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcAddPerMachineConnection(WINSPOOL_HANDLE pServer, const WCHAR* pPrinterName, const WCHAR* pPrintServer, const WCHAR* pProvider)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcDeletePerMachineConnection(WINSPOOL_HANDLE pServer, const WCHAR* pPrinterName)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcEnumPerMachineConnections(WINSPOOL_HANDLE pServer, BYTE* pPrinterEnum, DWORD cbBuf, DWORD* pcbNeeded, DWORD* pcReturned)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcSplOpenPrinter()
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcGetSpoolFileInfo()
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcCommitSpoolData()
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcCloseSpoolFileHandle()
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcSendRecvBidiData(WINSPOOL_PRINTER_HANDLE hPrinter, const WCHAR* pAction, WINSPOOL_BIDI_REQUEST_CONTAINER* pReqData, WINSPOOL_BIDI_RESPONSE_CONTAINER** ppRespData)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
+
+DWORD
+_RpcAddDriverCatalog()
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
--- /dev/null
+#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Print Spooler Service"
+#define REACTOS_STR_INTERNAL_NAME "spoolsv"
+#define REACTOS_STR_ORIGINAL_FILENAME "spoolsv.exe"
+#include <reactos/version.rc>
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler Service
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Xcv* functions
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+DWORD
+_RpcXcvData(WINSPOOL_PRINTER_HANDLE hXcv, const WCHAR* pszDataName, BYTE* pInputData, DWORD cbInputData, BYTE* pOutputData, DWORD cbOutputData, DWORD* pcbOutputNeeded, DWORD* pdwStatus)
+{
+ UNIMPLEMENTED;
+ return ERROR_INVALID_FUNCTION;
+}
--- /dev/null
+
+include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/idl)
+add_rpc_files(client ${REACTOS_SOURCE_DIR}/sdk/include/reactos/idl/winspool.idl)
+spec2def(winspool.drv winspool.spec ADD_IMPORTLIB)
+
+list(APPEND SOURCE
+ devmode.c
+ jobs.c
+ main.c
+ monitors.c
+ ports.c
+ precomp.h
+ printerdata.c
+ printerdrivers.c
+ printers.c
+ printprocessors.c
+ printproviders.c
+ ${CMAKE_CURRENT_BINARY_DIR}/winspool_c.c)
+
+add_library(winspool SHARED
+ ${SOURCE}
+ winspool.rc
+ ${CMAKE_CURRENT_BINARY_DIR}/winspool_stubs.c
+ ${CMAKE_CURRENT_BINARY_DIR}/winspool.def)
+
+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_pch(winspool precomp.h SOURCE)
+add_cd_file(TARGET winspool DESTINATION reactos/system32 FOR all)
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler API
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions giving information about DEVMODE structures
+ * COPYRIGHT: Copyright 2016 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+typedef struct _MINIMUM_SIZE_TABLE
+{
+ DWORD dwField;
+ WORD wSize;
+}
+MINIMUM_SIZE_TABLE, *PMINIMUM_SIZE_TABLE;
+
+/**
+ * Minimum required DEVMODEA structure size based on the used fields. Must be in descending order!
+ */
+static MINIMUM_SIZE_TABLE MinimumSizeA[] = {
+ { DM_PANNINGHEIGHT, FIELD_OFFSET(DEVMODEA, dmPanningHeight) + RTL_FIELD_SIZE(DEVMODEA, dmPanningHeight) },
+ { DM_PANNINGWIDTH, FIELD_OFFSET(DEVMODEA, dmPanningWidth) + RTL_FIELD_SIZE(DEVMODEA, dmPanningWidth) },
+ { DM_DITHERTYPE, FIELD_OFFSET(DEVMODEA, dmDitherType) + RTL_FIELD_SIZE(DEVMODEA, dmDitherType) },
+ { DM_MEDIATYPE, FIELD_OFFSET(DEVMODEA, dmMediaType) + RTL_FIELD_SIZE(DEVMODEA, dmMediaType) },
+ { DM_ICMINTENT, FIELD_OFFSET(DEVMODEA, dmICMIntent) + RTL_FIELD_SIZE(DEVMODEA, dmICMIntent) },
+ { DM_ICMMETHOD, FIELD_OFFSET(DEVMODEA, dmICMMethod) + RTL_FIELD_SIZE(DEVMODEA, dmICMMethod) },
+ { DM_DISPLAYFREQUENCY, FIELD_OFFSET(DEVMODEA, dmDisplayFrequency) + RTL_FIELD_SIZE(DEVMODEA, dmDisplayFrequency) },
+ { DM_NUP, FIELD_OFFSET(DEVMODEA, dmNup) + RTL_FIELD_SIZE(DEVMODEA, dmNup) },
+ { DM_DISPLAYFLAGS, FIELD_OFFSET(DEVMODEA, dmDisplayFlags) + RTL_FIELD_SIZE(DEVMODEA, dmDisplayFlags) },
+ { DM_PELSHEIGHT, FIELD_OFFSET(DEVMODEA, dmPelsHeight) + RTL_FIELD_SIZE(DEVMODEA, dmPelsHeight) },
+ { DM_PELSWIDTH, FIELD_OFFSET(DEVMODEA, dmPelsWidth) + RTL_FIELD_SIZE(DEVMODEA, dmPelsWidth) },
+ { DM_BITSPERPEL, FIELD_OFFSET(DEVMODEA, dmBitsPerPel) + RTL_FIELD_SIZE(DEVMODEA, dmBitsPerPel) },
+ { DM_LOGPIXELS, FIELD_OFFSET(DEVMODEA, dmLogPixels) + RTL_FIELD_SIZE(DEVMODEA, dmLogPixels) },
+ { DM_FORMNAME, FIELD_OFFSET(DEVMODEA, dmFormName) + RTL_FIELD_SIZE(DEVMODEA, dmFormName) },
+ { DM_COLLATE, FIELD_OFFSET(DEVMODEA, dmCollate) + RTL_FIELD_SIZE(DEVMODEA, dmCollate) },
+ { DM_TTOPTION, FIELD_OFFSET(DEVMODEA, dmTTOption) + RTL_FIELD_SIZE(DEVMODEA, dmTTOption) },
+ { DM_YRESOLUTION, FIELD_OFFSET(DEVMODEA, dmYResolution) + RTL_FIELD_SIZE(DEVMODEA, dmYResolution) },
+ { DM_DUPLEX, FIELD_OFFSET(DEVMODEA, dmDuplex) + RTL_FIELD_SIZE(DEVMODEA, dmDuplex) },
+ { DM_COLOR, FIELD_OFFSET(DEVMODEA, dmColor) + RTL_FIELD_SIZE(DEVMODEA, dmColor) },
+ { DM_DISPLAYFIXEDOUTPUT, FIELD_OFFSET(DEVMODEA, dmDisplayFixedOutput) + RTL_FIELD_SIZE(DEVMODEA, dmDisplayFixedOutput) },
+ { DM_DISPLAYORIENTATION, FIELD_OFFSET(DEVMODEA, dmDisplayOrientation) + RTL_FIELD_SIZE(DEVMODEA, dmDisplayOrientation) },
+ { DM_POSITION, FIELD_OFFSET(DEVMODEA, dmPosition) + RTL_FIELD_SIZE(DEVMODEA, dmPosition) },
+ { DM_PRINTQUALITY, FIELD_OFFSET(DEVMODEA, dmPrintQuality) + RTL_FIELD_SIZE(DEVMODEA, dmPrintQuality) },
+ { DM_DEFAULTSOURCE, FIELD_OFFSET(DEVMODEA, dmDefaultSource) + RTL_FIELD_SIZE(DEVMODEA, dmDefaultSource) },
+ { DM_COPIES, FIELD_OFFSET(DEVMODEA, dmCopies) + RTL_FIELD_SIZE(DEVMODEA, dmCopies) },
+ { DM_SCALE, FIELD_OFFSET(DEVMODEA, dmScale) + RTL_FIELD_SIZE(DEVMODEA, dmScale) },
+ { DM_PAPERWIDTH, FIELD_OFFSET(DEVMODEA, dmPaperWidth) + RTL_FIELD_SIZE(DEVMODEA, dmPaperWidth) },
+ { DM_PAPERLENGTH, FIELD_OFFSET(DEVMODEA, dmPaperLength) + RTL_FIELD_SIZE(DEVMODEA, dmPaperLength) },
+ { DM_PAPERSIZE, FIELD_OFFSET(DEVMODEA, dmPaperSize) + RTL_FIELD_SIZE(DEVMODEA, dmPaperSize) },
+ { DM_ORIENTATION, FIELD_OFFSET(DEVMODEA, dmOrientation) + RTL_FIELD_SIZE(DEVMODEA, dmOrientation) },
+ { 0, 0 }
+};
+
+/**
+ * Minimum required DEVMODEW structure size based on the used fields. Must be in descending order!
+ */
+static MINIMUM_SIZE_TABLE MinimumSizeW[] = {
+ { DM_PANNINGHEIGHT, FIELD_OFFSET(DEVMODEW, dmPanningHeight) + RTL_FIELD_SIZE(DEVMODEW, dmPanningHeight) },
+ { DM_PANNINGWIDTH, FIELD_OFFSET(DEVMODEW, dmPanningWidth) + RTL_FIELD_SIZE(DEVMODEW, dmPanningWidth) },
+ { DM_DITHERTYPE, FIELD_OFFSET(DEVMODEW, dmDitherType) + RTL_FIELD_SIZE(DEVMODEW, dmDitherType) },
+ { DM_MEDIATYPE, FIELD_OFFSET(DEVMODEW, dmMediaType) + RTL_FIELD_SIZE(DEVMODEW, dmMediaType) },
+ { DM_ICMINTENT, FIELD_OFFSET(DEVMODEW, dmICMIntent) + RTL_FIELD_SIZE(DEVMODEW, dmICMIntent) },
+ { DM_ICMMETHOD, FIELD_OFFSET(DEVMODEW, dmICMMethod) + RTL_FIELD_SIZE(DEVMODEW, dmICMMethod) },
+ { DM_DISPLAYFREQUENCY, FIELD_OFFSET(DEVMODEW, dmDisplayFrequency) + RTL_FIELD_SIZE(DEVMODEW, dmDisplayFrequency) },
+ { DM_NUP, FIELD_OFFSET(DEVMODEW, dmNup) + RTL_FIELD_SIZE(DEVMODEW, dmNup) },
+ { DM_DISPLAYFLAGS, FIELD_OFFSET(DEVMODEW, dmDisplayFlags) + RTL_FIELD_SIZE(DEVMODEW, dmDisplayFlags) },
+ { DM_PELSHEIGHT, FIELD_OFFSET(DEVMODEW, dmPelsHeight) + RTL_FIELD_SIZE(DEVMODEW, dmPelsHeight) },
+ { DM_PELSWIDTH, FIELD_OFFSET(DEVMODEW, dmPelsWidth) + RTL_FIELD_SIZE(DEVMODEW, dmPelsWidth) },
+ { DM_BITSPERPEL, FIELD_OFFSET(DEVMODEW, dmBitsPerPel) + RTL_FIELD_SIZE(DEVMODEW, dmBitsPerPel) },
+ { DM_LOGPIXELS, FIELD_OFFSET(DEVMODEW, dmLogPixels) + RTL_FIELD_SIZE(DEVMODEW, dmLogPixels) },
+ { DM_FORMNAME, FIELD_OFFSET(DEVMODEW, dmFormName) + RTL_FIELD_SIZE(DEVMODEW, dmFormName) },
+ { DM_COLLATE, FIELD_OFFSET(DEVMODEW, dmCollate) + RTL_FIELD_SIZE(DEVMODEW, dmCollate) },
+ { DM_TTOPTION, FIELD_OFFSET(DEVMODEW, dmTTOption) + RTL_FIELD_SIZE(DEVMODEW, dmTTOption) },
+ { DM_YRESOLUTION, FIELD_OFFSET(DEVMODEW, dmYResolution) + RTL_FIELD_SIZE(DEVMODEW, dmYResolution) },
+ { DM_DUPLEX, FIELD_OFFSET(DEVMODEW, dmDuplex) + RTL_FIELD_SIZE(DEVMODEW, dmDuplex) },
+ { DM_COLOR, FIELD_OFFSET(DEVMODEW, dmColor) + RTL_FIELD_SIZE(DEVMODEW, dmColor) },
+ { DM_DISPLAYFIXEDOUTPUT, FIELD_OFFSET(DEVMODEW, dmDisplayFixedOutput) + RTL_FIELD_SIZE(DEVMODEW, dmDisplayFixedOutput) },
+ { DM_DISPLAYORIENTATION, FIELD_OFFSET(DEVMODEW, dmDisplayOrientation) + RTL_FIELD_SIZE(DEVMODEW, dmDisplayOrientation) },
+ { DM_POSITION, FIELD_OFFSET(DEVMODEW, dmPosition) + RTL_FIELD_SIZE(DEVMODEW, dmPosition) },
+ { DM_PRINTQUALITY, FIELD_OFFSET(DEVMODEW, dmPrintQuality) + RTL_FIELD_SIZE(DEVMODEW, dmPrintQuality) },
+ { DM_DEFAULTSOURCE, FIELD_OFFSET(DEVMODEW, dmDefaultSource) + RTL_FIELD_SIZE(DEVMODEW, dmDefaultSource) },
+ { DM_COPIES, FIELD_OFFSET(DEVMODEW, dmCopies) + RTL_FIELD_SIZE(DEVMODEW, dmCopies) },
+ { DM_SCALE, FIELD_OFFSET(DEVMODEW, dmScale) + RTL_FIELD_SIZE(DEVMODEW, dmScale) },
+ { DM_PAPERWIDTH, FIELD_OFFSET(DEVMODEW, dmPaperWidth) + RTL_FIELD_SIZE(DEVMODEW, dmPaperWidth) },
+ { DM_PAPERLENGTH, FIELD_OFFSET(DEVMODEW, dmPaperLength) + RTL_FIELD_SIZE(DEVMODEW, dmPaperLength) },
+ { DM_PAPERSIZE, FIELD_OFFSET(DEVMODEW, dmPaperSize) + RTL_FIELD_SIZE(DEVMODEW, dmPaperSize) },
+ { DM_ORIENTATION, FIELD_OFFSET(DEVMODEW, dmOrientation) + RTL_FIELD_SIZE(DEVMODEW, dmOrientation) },
+ { 0, 0 }
+};
+
+/**
+ * Replace the last character by a null terminator if the given ANSI string is not null-terminated.
+ */
+static __inline void
+_FixStringA(PBYTE String, DWORD cbString)
+{
+ const PBYTE pLastCharacter = &String[cbString / sizeof(BYTE) - 1];
+ PBYTE p = String;
+
+ while (*p)
+ {
+ if (p == pLastCharacter)
+ {
+ *p = 0;
+ break;
+ }
+
+ p++;
+ }
+}
+
+/**
+ * Replace the last character by a null terminator if the given Unicode string is not null-terminated.
+ */
+static __inline void
+_FixStringW(PWSTR String, DWORD cbString)
+{
+ const PWSTR pLastCharacter = &String[cbString / sizeof(WCHAR) - 1];
+ PWSTR p = String;
+
+ while (*p)
+ {
+ if (p == pLastCharacter)
+ {
+ *p = 0;
+ break;
+ }
+
+ p++;
+ }
+}
+
+BOOL WINAPI
+IsValidDevmodeA(PDEVMODEA pDevmode, size_t DevmodeSize)
+{
+ PMINIMUM_SIZE_TABLE pTable = MinimumSizeA;
+ WORD wRequiredSize;
+
+ // Check if a Devmode was given at all.
+ if (!pDevmode)
+ goto Failure;
+
+ // Verify that DevmodeSize is large enough to hold the public and private members of the structure.
+ if (DevmodeSize < pDevmode->dmSize + pDevmode->dmDriverExtra)
+ goto Failure;
+
+ // If the structure has private members, the public structure must be 32-bit packed.
+ if (pDevmode->dmDriverExtra && pDevmode->dmSize % 4)
+ goto Failure;
+
+ // Now determine the minimum possible dmSize based on the given fields in dmFields.
+ wRequiredSize = FIELD_OFFSET(DEVMODEA, dmFields) + RTL_FIELD_SIZE(DEVMODEA, dmFields);
+
+ while (pTable->dwField)
+ {
+ if (pDevmode->dmFields & pTable->dwField)
+ {
+ wRequiredSize = pTable->wSize;
+ break;
+ }
+
+ pTable++;
+ }
+
+ // Verify that the value in dmSize is big enough for the used fields.
+ if (pDevmode->dmSize < wRequiredSize)
+ goto Failure;
+
+ // Check if dmDeviceName and (if used) dmFormName are null-terminated.
+ // Fix this if they aren't.
+ _FixStringA(pDevmode->dmDeviceName, sizeof(pDevmode->dmDeviceName));
+ if (pDevmode->dmFields & DM_FORMNAME)
+ _FixStringA(pDevmode->dmFormName, sizeof(pDevmode->dmFormName));
+
+ // Return success without setting the error code.
+ return TRUE;
+
+Failure:
+ SetLastError(ERROR_INVALID_DATA);
+ return FALSE;
+}
+
+BOOL WINAPI
+IsValidDevmodeW(PDEVMODEW pDevmode, size_t DevmodeSize)
+{
+ PMINIMUM_SIZE_TABLE pTable = MinimumSizeW;
+ WORD wRequiredSize;
+
+ // Check if a Devmode was given at all.
+ if (!pDevmode)
+ goto Failure;
+
+ // Verify that DevmodeSize is large enough to hold the public and private members of the structure.
+ if (DevmodeSize < pDevmode->dmSize + pDevmode->dmDriverExtra)
+ goto Failure;
+
+ // If the structure has private members, the public structure must be 32-bit packed.
+ if (pDevmode->dmDriverExtra && pDevmode->dmSize % 4)
+ goto Failure;
+
+ // Now determine the minimum possible dmSize based on the given fields in dmFields.
+ wRequiredSize = FIELD_OFFSET(DEVMODEW, dmFields) + RTL_FIELD_SIZE(DEVMODEW, dmFields);
+
+ while (pTable->dwField)
+ {
+ if (pDevmode->dmFields & pTable->dwField)
+ {
+ wRequiredSize = pTable->wSize;
+ break;
+ }
+
+ pTable++;
+ }
+
+ // Verify that the value in dmSize is big enough for the used fields.
+ if (pDevmode->dmSize < wRequiredSize)
+ goto Failure;
+
+ // Check if dmDeviceName and (if used) dmFormName are null-terminated.
+ // Fix this if they aren't.
+ _FixStringW(pDevmode->dmDeviceName, sizeof(pDevmode->dmDeviceName));
+ if (pDevmode->dmFields & DM_FORMNAME)
+ _FixStringW(pDevmode->dmFormName, sizeof(pDevmode->dmFormName));
+
+ // Return success without setting the error code.
+ return TRUE;
+
+Failure:
+ SetLastError(ERROR_INVALID_DATA);
+ return FALSE;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler API
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions for managing print jobs
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+static void
+_MarshallUpAddJobInfo(PADDJOB_INFO_1W pAddJobInfo1)
+{
+ // Replace relative offset addresses in the output by absolute pointers.
+ pAddJobInfo1->Path = (PWSTR)((ULONG_PTR)pAddJobInfo1->Path + (ULONG_PTR)pAddJobInfo1);
+}
+
+static void
+_MarshallUpJobInfo(PBYTE pJobInfo, DWORD Level)
+{
+ PJOB_INFO_1W pJobInfo1;
+ PJOB_INFO_2W pJobInfo2;
+
+ // Replace relative offset addresses in the output by absolute pointers.
+ if (Level == 1)
+ {
+ pJobInfo1 = (PJOB_INFO_1W)pJobInfo;
+ pJobInfo1->pDatatype = (PWSTR)((ULONG_PTR)pJobInfo1->pDatatype + (ULONG_PTR)pJobInfo1);
+ pJobInfo1->pDocument = (PWSTR)((ULONG_PTR)pJobInfo1->pDocument + (ULONG_PTR)pJobInfo1);
+ pJobInfo1->pMachineName = (PWSTR)((ULONG_PTR)pJobInfo1->pMachineName + (ULONG_PTR)pJobInfo1);
+ pJobInfo1->pPrinterName = (PWSTR)((ULONG_PTR)pJobInfo1->pPrinterName + (ULONG_PTR)pJobInfo1);
+
+ if (pJobInfo1->pStatus)
+ pJobInfo1->pStatus = (PWSTR)((ULONG_PTR)pJobInfo1->pStatus + (ULONG_PTR)pJobInfo1);
+
+ pJobInfo1->pUserName = (PWSTR)((ULONG_PTR)pJobInfo1->pUserName + (ULONG_PTR)pJobInfo1);
+ }
+ else if (Level == 2)
+ {
+ pJobInfo2 = (PJOB_INFO_2W)pJobInfo;
+ pJobInfo2->pDatatype = (PWSTR)((ULONG_PTR)pJobInfo2->pDatatype + (ULONG_PTR)pJobInfo2);
+ pJobInfo2->pDevMode = (PDEVMODEW)((ULONG_PTR)pJobInfo2->pDevMode + (ULONG_PTR)pJobInfo2);
+ pJobInfo2->pDocument = (PWSTR)((ULONG_PTR)pJobInfo2->pDocument + (ULONG_PTR)pJobInfo2);
+ pJobInfo2->pDriverName = (PWSTR)((ULONG_PTR)pJobInfo2->pDriverName + (ULONG_PTR)pJobInfo2);
+ pJobInfo2->pMachineName = (PWSTR)((ULONG_PTR)pJobInfo2->pMachineName + (ULONG_PTR)pJobInfo2);
+ pJobInfo2->pNotifyName = (PWSTR)((ULONG_PTR)pJobInfo2->pNotifyName + (ULONG_PTR)pJobInfo2);
+ pJobInfo2->pPrinterName = (PWSTR)((ULONG_PTR)pJobInfo2->pPrinterName + (ULONG_PTR)pJobInfo2);
+ pJobInfo2->pPrintProcessor = (PWSTR)((ULONG_PTR)pJobInfo2->pPrintProcessor + (ULONG_PTR)pJobInfo2);
+
+ if (pJobInfo2->pParameters)
+ pJobInfo2->pParameters = (PWSTR)((ULONG_PTR)pJobInfo2->pParameters + (ULONG_PTR)pJobInfo2);
+
+ if (pJobInfo2->pStatus)
+ pJobInfo2->pStatus = (PWSTR)((ULONG_PTR)pJobInfo2->pStatus + (ULONG_PTR)pJobInfo2);
+
+ pJobInfo2->pUserName = (PWSTR)((ULONG_PTR)pJobInfo2->pUserName + (ULONG_PTR)pJobInfo2);
+ }
+}
+
+BOOL WINAPI
+AddJobA(HANDLE hPrinter, DWORD Level, PBYTE pData, DWORD cbBuf, PDWORD pcbNeeded)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL WINAPI
+AddJobW(HANDLE hPrinter, DWORD Level, PBYTE pData, DWORD cbBuf, PDWORD pcbNeeded)
+{
+ DWORD dwErrorCode;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcAddJob(pHandle->hPrinter, Level, pData, cbBuf, pcbNeeded);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcAddJob failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ _MarshallUpAddJobInfo((PADDJOB_INFO_1W)pData);
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL WINAPI
+EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ DWORD dwErrorCode;
+ DWORD i;
+ PBYTE p = pJob;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcEnumJobs(pHandle->hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcEnumJobs failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ // Replace relative offset addresses in the output by absolute pointers.
+ for (i = 0; i < *pcReturned; i++)
+ {
+ _MarshallUpJobInfo(p, Level);
+
+ if (Level == 1)
+ p += sizeof(JOB_INFO_1W);
+ else if (Level == 2)
+ p += sizeof(JOB_INFO_2W);
+ }
+ }
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL WINAPI
+GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded)
+{
+ DWORD dwErrorCode;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcGetJob(pHandle->hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcGetJob failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ // Replace relative offset addresses in the output by absolute pointers.
+ _MarshallUpJobInfo(pJob, Level);
+ }
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+ScheduleJob(HANDLE hPrinter, DWORD dwJobID)
+{
+ DWORD dwErrorCode;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcScheduleJob(pHandle->hPrinter, dwJobID);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL WINAPI
+SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command)
+{
+ DWORD dwErrorCode;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+ WINSPOOL_JOB_CONTAINER JobContainer;
+
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // pJobContainer->JobInfo is a union of pointers, so we can just set any element to our BYTE pointer.
+ JobContainer.Level = Level;
+ JobContainer.JobInfo.Level1 = (WINSPOOL_JOB_INFO_1*)pJobInfo;
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcSetJob(pHandle->hPrinter, JobId, &JobContainer, Command);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcSetJob failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler API
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Main functions
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+// Global Variables
+HANDLE hProcessHeap;
+
+
+handle_t __RPC_USER
+WINSPOOL_HANDLE_bind(WINSPOOL_HANDLE wszName)
+{
+ handle_t hBinding;
+ PWSTR wszStringBinding;
+ RPC_STATUS Status;
+
+ // Get us a string binding handle from the supplied connection information
+ Status = RpcStringBindingComposeW(NULL, L"ncalrpc", NULL, L"spoolss", NULL, &wszStringBinding);
+ if (Status != RPC_S_OK)
+ {
+ ERR("RpcStringBindingComposeW failed with status %ld!\n", Status);
+ return NULL;
+ }
+
+ // Get a handle_t binding handle from the string binding handle
+ Status = RpcBindingFromStringBindingW(wszStringBinding, &hBinding);
+ if (Status != RPC_S_OK)
+ {
+ ERR("RpcBindingFromStringBindingW failed with status %ld!\n", Status);
+ return NULL;
+ }
+
+ // Free the string binding handle
+ Status = RpcStringFreeW(&wszStringBinding);
+ if (Status != RPC_S_OK)
+ {
+ ERR("RpcStringFreeW failed with status %ld!\n", Status);
+ return NULL;
+ }
+
+ return hBinding;
+}
+
+void __RPC_USER
+WINSPOOL_HANDLE_unbind(WINSPOOL_HANDLE wszName, handle_t hBinding)
+{
+ RPC_STATUS Status;
+
+ Status = RpcBindingFree(&hBinding);
+ if (Status != RPC_S_OK)
+ {
+ ERR("RpcBindingFree failed with status %ld!\n", Status);
+ }
+}
+
+void __RPC_FAR* __RPC_USER
+midl_user_allocate(SIZE_T len)
+{
+ return HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, len);
+}
+
+void __RPC_USER
+midl_user_free(void __RPC_FAR* ptr)
+{
+ HeapFree(hProcessHeap, 0, ptr);
+}
+
+BOOL WINAPI
+DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ DisableThreadLibraryCalls(hinstDLL);
+ hProcessHeap = GetProcessHeap();
+ break;
+ }
+
+ return TRUE;
+}
+
+BOOL WINAPI
+SpoolerInit()
+{
+ BOOL bReturnValue = FALSE;
+ DWORD dwErrorCode;
+
+ // Nothing to initialize here yet, but pass this call to the Spool Service as well.
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcSpoolerInit();
+ SetLastError(dwErrorCode);
+ bReturnValue = (dwErrorCode == ERROR_SUCCESS);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ERR("_RpcSpoolerInit failed with exception code %lu!\n", RpcExceptionCode());
+ }
+ RpcEndExcept;
+
+ return bReturnValue;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler API
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Print Monitors
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+static void
+_MarshallUpMonitorInfo(PBYTE pMonitorInfo, DWORD Level)
+{
+ PMONITOR_INFO_2W pMonitorInfo2 = (PMONITOR_INFO_2W)pMonitorInfo; // MONITOR_INFO_1W is a subset of MONITOR_INFO_2W
+
+ // Replace relative offset addresses in the output by absolute pointers.
+ pMonitorInfo2->pName = (PWSTR)((ULONG_PTR)pMonitorInfo2->pName + (ULONG_PTR)pMonitorInfo2);
+
+ if (Level == 2)
+ {
+ pMonitorInfo2->pDLLName = (PWSTR)((ULONG_PTR)pMonitorInfo2->pDLLName + (ULONG_PTR)pMonitorInfo2);
+ pMonitorInfo2->pEnvironment = (PWSTR)((ULONG_PTR)pMonitorInfo2->pEnvironment + (ULONG_PTR)pMonitorInfo2);
+ }
+}
+
+BOOL WINAPI
+AddMonitorW(PWSTR pName, DWORD Level, PBYTE pMonitors)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL WINAPI
+DeleteMonitorW(PWSTR pName, PWSTR pEnvironment, PWSTR pMonitorName)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL WINAPI
+EnumMonitorsW(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ DWORD dwErrorCode;
+ DWORD i;
+ PBYTE p = pMonitors;
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcEnumPorts failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ // Replace relative offset addresses in the output by absolute pointers.
+ for (i = 0; i < *pcReturned; i++)
+ {
+ _MarshallUpMonitorInfo(p, Level);
+
+ if (Level == 1)
+ p += sizeof(MONITOR_INFO_1W);
+ else if (Level == 2)
+ p += sizeof(MONITOR_INFO_2W);
+ }
+ }
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler API
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Ports
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+static void
+_MarshallUpPortInfo(PBYTE pPortInfo, DWORD Level)
+{
+ PPORT_INFO_2W pPortInfo2 = (PPORT_INFO_2W)pPortInfo; // PORT_INFO_1W is a subset of PORT_INFO_2W
+
+ // Replace relative offset addresses in the output by absolute pointers.
+ pPortInfo2->pPortName = (PWSTR)((ULONG_PTR)pPortInfo2->pPortName + (ULONG_PTR)pPortInfo2);
+
+ if (Level == 2)
+ {
+ pPortInfo2->pDescription = (PWSTR)((ULONG_PTR)pPortInfo2->pDescription + (ULONG_PTR)pPortInfo2);
+ pPortInfo2->pMonitorName = (PWSTR)((ULONG_PTR)pPortInfo2->pMonitorName + (ULONG_PTR)pPortInfo2);
+ }
+}
+
+BOOL WINAPI
+AddPortW(PWSTR pName, HWND hWnd, PWSTR pMonitorName)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL WINAPI
+ConfigurePortW(PWSTR pName, HWND hWnd, PWSTR pPortName)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL WINAPI
+DeletePortW(PWSTR pName, HWND hWnd, PWSTR pPortName)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL WINAPI
+EnumPortsW(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ DWORD dwErrorCode;
+ DWORD i;
+ PBYTE p = pPorts;
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcEnumPorts failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ // Replace relative offset addresses in the output by absolute pointers.
+ for (i = 0; i < *pcReturned; i++)
+ {
+ _MarshallUpPortInfo(p, Level);
+
+ if (Level == 1)
+ p += sizeof(PORT_INFO_1W);
+ else if (Level == 2)
+ p += sizeof(PORT_INFO_2W);
+ }
+ }
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler API
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Precompiled Header for all source files
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#ifndef _PRECOMP_H
+#define _PRECOMP_H
+
+#define WIN32_NO_STATUS
+#include <windef.h>
+#include <winbase.h>
+#include <wingdi.h>
+#include <winreg.h>
+#include <winspool.h>
+#include <winspool_c.h>
+
+#include <wine/debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(winspool);
+
+// Structures
+/*
+ * Describes a handle returned by OpenPrinterW.
+ */
+typedef struct _SPOOLER_HANDLE
+{
+ BOOL bStartedDoc : 1;
+ DWORD dwJobID;
+ HANDLE hPrinter;
+ HANDLE hSPLFile;
+}
+SPOOLER_HANDLE, *PSPOOLER_HANDLE;
+
+// main.c
+extern HANDLE hProcessHeap;
+
+#endif
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler API
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Printer Configuration Data
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+LONG WINAPI
+AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, PWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+DWORD WINAPI
+GetPrinterDataW(HANDLE hPrinter, PWSTR pValueName, PDWORD pType, PBYTE pData, DWORD nSize, PDWORD pcbNeeded)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+DWORD WINAPI
+SetPrinterDataW(HANDLE hPrinter, PWSTR pValueName, DWORD Type, PBYTE pData, DWORD cbData)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler API
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Printer Drivers
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+BOOL WINAPI
+AddPrinterDriverW(PWSTR pName, DWORD Level, PBYTE pDriverInfo)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL WINAPI
+DeletePrinterDriverW(PWSTR pName, PWSTR pEnvironment, PWSTR pDriverName)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL WINAPI
+EnumPrinterDriversW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pDriverInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL WINAPI
+GetPrinterDriverDirectoryW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pDriverDirectory, DWORD cbBuf, PDWORD pcbNeeded)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler API
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Printers and printing
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+static void
+_MarshallUpPrinterInfo(PBYTE pPrinterInfo, DWORD Level)
+{
+ PPRINTER_INFO_1W pPrinterInfo1;
+ PPRINTER_INFO_2W pPrinterInfo2;
+
+ // Replace relative offset addresses in the output by absolute pointers.
+ if (Level == 1)
+ {
+ pPrinterInfo1 = (PPRINTER_INFO_1W)pPrinterInfo;
+
+ pPrinterInfo1->pName = (PWSTR)((ULONG_PTR)pPrinterInfo1->pName + (ULONG_PTR)pPrinterInfo1);
+ pPrinterInfo1->pDescription = (PWSTR)((ULONG_PTR)pPrinterInfo1->pDescription + (ULONG_PTR)pPrinterInfo1);
+ pPrinterInfo1->pComment = (PWSTR)((ULONG_PTR)pPrinterInfo1->pComment + (ULONG_PTR)pPrinterInfo1);
+ }
+ else if (Level == 2)
+ {
+ pPrinterInfo2 = (PPRINTER_INFO_2W)pPrinterInfo;
+
+ pPrinterInfo2->pPrinterName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pPrinterName + (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pShareName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pShareName + (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pPortName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pPortName + (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pDriverName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pDriverName + (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pComment = (PWSTR)((ULONG_PTR)pPrinterInfo2->pComment + (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pLocation = (PWSTR)((ULONG_PTR)pPrinterInfo2->pLocation + (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pDevMode = (PDEVMODEW)((ULONG_PTR)pPrinterInfo2->pDevMode + (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pSepFile = (PWSTR)((ULONG_PTR)pPrinterInfo2->pSepFile + (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pPrintProcessor = (PWSTR)((ULONG_PTR)pPrinterInfo2->pPrintProcessor + (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pDatatype = (PWSTR)((ULONG_PTR)pPrinterInfo2->pDatatype + (ULONG_PTR)pPrinterInfo2);
+ pPrinterInfo2->pParameters = (PWSTR)((ULONG_PTR)pPrinterInfo2->pParameters + (ULONG_PTR)pPrinterInfo2);
+
+ if (pPrinterInfo2->pServerName)
+ pPrinterInfo2->pServerName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pServerName + (ULONG_PTR)pPrinterInfo2);
+
+ if (pPrinterInfo2->pSecurityDescriptor)
+ pPrinterInfo2->pSecurityDescriptor = (PWSTR)((ULONG_PTR)pPrinterInfo2->pSecurityDescriptor + (ULONG_PTR)pPrinterInfo2);
+ }
+}
+
+static DWORD
+_StartDocPrinterSpooled(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1, PADDJOB_INFO_1W pAddJobInfo1)
+{
+ DWORD cbNeeded;
+ DWORD dwErrorCode;
+ PJOB_INFO_1W pJobInfo1 = NULL;
+
+ // Create the spool file.
+ pHandle->hSPLFile = CreateFileW(pAddJobInfo1->Path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
+ if (pHandle->hSPLFile == INVALID_HANDLE_VALUE)
+ {
+ dwErrorCode = GetLastError();
+ ERR("CreateFileW failed for \"%S\" with error %lu!\n", pAddJobInfo1->Path, dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Get the size of the job information.
+ GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, NULL, 0, &cbNeeded);
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+ dwErrorCode = GetLastError();
+ ERR("GetJobW failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Allocate enough memory for the returned job information.
+ pJobInfo1 = HeapAlloc(hProcessHeap, 0, cbNeeded);
+ if (!pJobInfo1)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("HeapAlloc failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Get the job information.
+ if (!GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, cbNeeded, &cbNeeded))
+ {
+ dwErrorCode = GetLastError();
+ ERR("GetJobW failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Add our document information.
+ if (pDocInfo1->pDatatype)
+ pJobInfo1->pDatatype = pDocInfo1->pDatatype;
+
+ pJobInfo1->pDocument = pDocInfo1->pDocName;
+
+ // Set the new job information.
+ if (!SetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, 0))
+ {
+ dwErrorCode = GetLastError();
+ ERR("SetJobW failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // We were successful!
+ pHandle->dwJobID = pAddJobInfo1->JobId;
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ if (pJobInfo1)
+ HeapFree(hProcessHeap, 0, pJobInfo1);
+
+ return dwErrorCode;
+}
+
+static DWORD
+_StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1)
+{
+ DWORD dwErrorCode;
+ WINSPOOL_DOC_INFO_CONTAINER DocInfoContainer;
+
+ DocInfoContainer.Level = 1;
+ DocInfoContainer.DocInfo.pDocInfo1 = (WINSPOOL_DOC_INFO_1*)pDocInfo1;
+
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcStartDocPrinter(pHandle->hPrinter, &DocInfoContainer, &pHandle->dwJobID);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcStartDocPrinter failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+
+ return dwErrorCode;
+}
+
+HANDLE WINAPI
+AddPrinterW(PWSTR pName, DWORD Level, PBYTE pPrinter)
+{
+ UNIMPLEMENTED;
+ return NULL;
+}
+
+BOOL WINAPI
+ClosePrinter(HANDLE hPrinter)
+{
+ DWORD dwErrorCode;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Do the RPC call.
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcClosePrinter(pHandle->hPrinter);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcClosePrinter failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+
+ // Close any open file handle.
+ if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
+ CloseHandle(pHandle->hSPLFile);
+
+ // Free the memory for the handle.
+ HeapFree(hProcessHeap, 0, pHandle);
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+
+}
+
+DWORD WINAPI
+DeviceCapabilitiesA(LPCSTR pDevice, LPCSTR pPort, WORD fwCapability, LPSTR pOutput, const DEVMODEA* pDevMode)
+{
+ return 0;
+}
+
+DWORD WINAPI
+DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort, WORD fwCapability, LPWSTR pOutput, const DEVMODEW* pDevMode)
+{
+ return 0;
+}
+
+LONG WINAPI
+DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput, DWORD fMode)
+{
+ return 0;
+}
+
+LONG WINAPI
+DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput, DWORD fMode)
+{
+ return 0;
+}
+
+BOOL WINAPI
+EndDocPrinter(HANDLE hPrinter)
+{
+ DWORD dwErrorCode;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
+ {
+ // For spooled jobs, the document is finished by calling _RpcScheduleJob.
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcScheduleJob(pHandle->hPrinter, pHandle->dwJobID);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+
+ // Close the spool file handle.
+ CloseHandle(pHandle->hSPLFile);
+ }
+ else
+ {
+ // In all other cases, just call _RpcEndDocPrinter.
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcEndDocPrinter(pHandle->hPrinter);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcEndDocPrinter failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+ }
+
+ // A new document can now be started again.
+ pHandle->bStartedDoc = FALSE;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+EndPagePrinter(HANDLE hPrinter)
+{
+ DWORD dwErrorCode;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
+ {
+ // For spooled jobs, we don't need to do anything.
+ dwErrorCode = ERROR_SUCCESS;
+ }
+ else
+ {
+ // In all other cases, just call _RpcEndPagePrinter.
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcEndPagePrinter(pHandle->hPrinter);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcEndPagePrinter failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+ }
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+EnumPrintersA(DWORD Flags, PSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ return FALSE;
+}
+
+BOOL WINAPI
+EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ DWORD dwErrorCode;
+ DWORD i;
+ PBYTE p = pPrinterEnum;
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ // Replace relative offset addresses in the output by absolute pointers.
+ for (i = 0; i < *pcReturned; i++)
+ {
+ _MarshallUpPrinterInfo(p, Level);
+
+ if (Level == 1)
+ p += sizeof(PRINTER_INFO_1W);
+ else if (Level == 2)
+ p += sizeof(PRINTER_INFO_2W);
+ }
+ }
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer)
+{
+ return FALSE;
+}
+
+BOOL WINAPI
+GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer)
+{
+ return FALSE;
+}
+
+BOOL WINAPI
+GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
+{
+ return FALSE;
+}
+
+BOOL WINAPI
+GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
+{
+ return FALSE;
+}
+
+BOOL WINAPI
+GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
+{
+ return FALSE;
+}
+
+BOOL WINAPI
+GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
+{
+ return FALSE;
+}
+
+BOOL WINAPI
+OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefault)
+{
+ BOOL bReturnValue = FALSE;
+ DWORD cch;
+ PWSTR pwszPrinterName = NULL;
+ PRINTER_DEFAULTSW wDefault = { 0 };
+
+ if (pPrinterName)
+ {
+ // Convert pPrinterName to a Unicode string pwszPrinterName
+ cch = strlen(pPrinterName);
+
+ pwszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
+ if (!pwszPrinterName)
+ {
+ ERR("HeapAlloc failed for pwszPrinterName with last error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ MultiByteToWideChar(CP_ACP, 0, pPrinterName, -1, pwszPrinterName, cch + 1);
+ }
+
+ if (pDefault)
+ {
+ wDefault.DesiredAccess = pDefault->DesiredAccess;
+
+ if (pDefault->pDatatype)
+ {
+ // Convert pDefault->pDatatype to a Unicode string wDefault.pDatatype
+ cch = strlen(pDefault->pDatatype);
+
+ wDefault.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
+ if (!wDefault.pDatatype)
+ {
+ ERR("HeapAlloc failed for wDefault.pDatatype with last error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ MultiByteToWideChar(CP_ACP, 0, pDefault->pDatatype, -1, wDefault.pDatatype, cch + 1);
+ }
+
+ if (pDefault->pDevMode)
+ wDefault.pDevMode = GdiConvertToDevmodeW(pDefault->pDevMode);
+ }
+
+ bReturnValue = OpenPrinterW(pwszPrinterName, phPrinter, &wDefault);
+
+Cleanup:
+ if (wDefault.pDatatype)
+ HeapFree(hProcessHeap, 0, wDefault.pDatatype);
+
+ if (wDefault.pDevMode)
+ HeapFree(hProcessHeap, 0, wDefault.pDevMode);
+
+ if (pwszPrinterName)
+ HeapFree(hProcessHeap, 0, pwszPrinterName);
+
+ return bReturnValue;
+}
+
+BOOL WINAPI
+OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault)
+{
+ DWORD dwErrorCode;
+ HANDLE hPrinter;
+ PSPOOLER_HANDLE pHandle;
+ PWSTR pDatatype = NULL;
+ WINSPOOL_DEVMODE_CONTAINER DevModeContainer = { 0 };
+ ACCESS_MASK AccessRequired = 0;
+
+ // Prepare the additional parameters in the format required by _RpcOpenPrinter
+ if (pDefault)
+ {
+ pDatatype = pDefault->pDatatype;
+ DevModeContainer.cbBuf = sizeof(DEVMODEW);
+ DevModeContainer.pDevMode = (BYTE*)pDefault->pDevMode;
+ AccessRequired = pDefault->DesiredAccess;
+ }
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcOpenPrinter(pPrinterName, &hPrinter, pDatatype, &DevModeContainer, AccessRequired);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ // Create a new SPOOLER_HANDLE structure.
+ pHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SPOOLER_HANDLE));
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("HeapAlloc failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ pHandle->hPrinter = hPrinter;
+ pHandle->hSPLFile = INVALID_HANDLE_VALUE;
+
+ // Return it as phPrinter.
+ *phPrinter = (HANDLE)pHandle;
+ }
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
+{
+ DWORD dwErrorCode;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcReadPrinter(pHandle->hPrinter, pBuf, cbBuf, pNoBytesRead);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+ResetPrinterW(HANDLE hPrinter, PPRINTER_DEFAULTSW pDefault)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL WINAPI
+SetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+DWORD WINAPI
+StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
+{
+ DOC_INFO_1W wDocInfo1 = { 0 };
+ DWORD cch;
+ DWORD dwErrorCode;
+ DWORD dwReturnValue = 0;
+ PDOC_INFO_1A pDocInfo1 = (PDOC_INFO_1A)pDocInfo;
+
+ // Only check the minimum required for accessing pDocInfo.
+ // Additional sanity checks are done in StartDocPrinterW.
+ if (!pDocInfo1)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ if (Level != 1)
+ {
+ dwErrorCode = ERROR_INVALID_LEVEL;
+ goto Cleanup;
+ }
+
+ if (pDocInfo1->pDatatype)
+ {
+ // Convert pDocInfo1->pDatatype to a Unicode string wDocInfo1.pDatatype
+ cch = strlen(pDocInfo1->pDatatype);
+
+ wDocInfo1.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
+ if (!wDocInfo1.pDatatype)
+ {
+ ERR("HeapAlloc failed for wDocInfo1.pDatatype with last error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDatatype, -1, wDocInfo1.pDatatype, cch + 1);
+ }
+
+ if (pDocInfo1->pDocName)
+ {
+ // Convert pDocInfo1->pDocName to a Unicode string wDocInfo1.pDocName
+ cch = strlen(pDocInfo1->pDocName);
+
+ wDocInfo1.pDocName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
+ if (!wDocInfo1.pDocName)
+ {
+ ERR("HeapAlloc failed for wDocInfo1.pDocName with last error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDocName, -1, wDocInfo1.pDocName, cch + 1);
+ }
+
+ if (pDocInfo1->pOutputFile)
+ {
+ // Convert pDocInfo1->pOutputFile to a Unicode string wDocInfo1.pOutputFile
+ cch = strlen(pDocInfo1->pOutputFile);
+
+ wDocInfo1.pOutputFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
+ if (!wDocInfo1.pOutputFile)
+ {
+ ERR("HeapAlloc failed for wDocInfo1.pOutputFile with last error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pOutputFile, -1, wDocInfo1.pOutputFile, cch + 1);
+ }
+
+ dwReturnValue = StartDocPrinterW(hPrinter, Level, (PBYTE)&wDocInfo1);
+ dwErrorCode = GetLastError();
+
+Cleanup:
+ if (wDocInfo1.pDatatype)
+ HeapFree(hProcessHeap, 0, wDocInfo1.pDatatype);
+
+ if (wDocInfo1.pDocName)
+ HeapFree(hProcessHeap, 0, wDocInfo1.pDocName);
+
+ if (wDocInfo1.pOutputFile)
+ HeapFree(hProcessHeap, 0, wDocInfo1.pOutputFile);
+
+ SetLastError(dwErrorCode);
+ return dwReturnValue;
+}
+
+DWORD WINAPI
+StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
+{
+ DWORD cbAddJobInfo1;
+ DWORD cbNeeded;
+ DWORD dwErrorCode;
+ DWORD dwReturnValue = 0;
+ PADDJOB_INFO_1W pAddJobInfo1 = NULL;
+ PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ if (!pDocInfo1)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ if (Level != 1)
+ {
+ dwErrorCode = ERROR_INVALID_LEVEL;
+ goto Cleanup;
+ }
+
+ if (pHandle->bStartedDoc)
+ {
+ dwErrorCode = ERROR_INVALID_PRINTER_STATE;
+ goto Cleanup;
+ }
+
+ // Check if we want to redirect output into a file.
+ if (pDocInfo1->pOutputFile)
+ {
+ // Do a StartDocPrinter RPC call in this case.
+ dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
+ }
+ else
+ {
+ // Allocate memory for the ADDJOB_INFO_1W structure and a path.
+ cbAddJobInfo1 = sizeof(ADDJOB_INFO_1W) + MAX_PATH * sizeof(WCHAR);
+ pAddJobInfo1 = HeapAlloc(hProcessHeap, 0, cbAddJobInfo1);
+ if (!pAddJobInfo1)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("HeapAlloc failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Try to add a new job.
+ // This only succeeds if the printer is set to do spooled printing.
+ if (AddJobW((HANDLE)pHandle, 1, (PBYTE)pAddJobInfo1, cbAddJobInfo1, &cbNeeded))
+ {
+ // Do spooled printing.
+ dwErrorCode = _StartDocPrinterSpooled(pHandle, pDocInfo1, pAddJobInfo1);
+ }
+ else if (GetLastError() == ERROR_INVALID_ACCESS)
+ {
+ // ERROR_INVALID_ACCESS is returned when the printer is set to do direct printing.
+ // In this case, we do a StartDocPrinter RPC call.
+ dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
+ }
+ else
+ {
+ dwErrorCode = GetLastError();
+ ERR("AddJobW failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+ }
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ pHandle->bStartedDoc = TRUE;
+ dwReturnValue = pHandle->dwJobID;
+ }
+
+Cleanup:
+ if (pAddJobInfo1)
+ HeapFree(hProcessHeap, 0, pAddJobInfo1);
+
+ SetLastError(dwErrorCode);
+ return dwReturnValue;
+}
+
+BOOL WINAPI
+StartPagePrinter(HANDLE hPrinter)
+{
+ DWORD dwErrorCode;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcStartPagePrinter(pHandle->hPrinter);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcStartPagePrinter failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
+{
+ DWORD dwErrorCode;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ if (!pHandle->bStartedDoc)
+ {
+ dwErrorCode = ERROR_SPL_NO_STARTDOC;
+ goto Cleanup;
+ }
+
+ if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
+ {
+ // Write to the spool file. This doesn't need an RPC request.
+ if (!WriteFile(pHandle->hSPLFile, pBuf, cbBuf, pcWritten, NULL))
+ {
+ dwErrorCode = GetLastError();
+ ERR("WriteFile failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ dwErrorCode = ERROR_SUCCESS;
+ }
+ else
+ {
+ // TODO: This case (for direct printing or remote printing) has bad performance if multiple small-sized WritePrinter calls are performed.
+ // We may increase performance by writing into a buffer and only doing a single RPC call when the buffer is full.
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcWritePrinter(pHandle->hPrinter, pBuf, cbBuf, pcWritten);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcWritePrinter failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+ }
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus)
+{
+ return FALSE;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler API
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Print Processors
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+static void
+_MarshallUpDatatypesInfo(PDATATYPES_INFO_1W pDatatypesInfo1)
+{
+ // Replace relative offset addresses in the output by absolute pointers.
+ pDatatypesInfo1->pName = (PWSTR)((ULONG_PTR)pDatatypesInfo1->pName + (ULONG_PTR)pDatatypesInfo1);
+}
+
+static void
+_MarshallUpPrintProcessorInfo(PPRINTPROCESSOR_INFO_1W pPrintProcessorInfo1)
+{
+ // Replace relative offset addresses in the output by absolute pointers.
+ pPrintProcessorInfo1->pName = (PWSTR)((ULONG_PTR)pPrintProcessorInfo1->pName + (ULONG_PTR)pPrintProcessorInfo1);
+}
+
+BOOL WINAPI
+AddPrintProcessorW(PWSTR pName, PWSTR pEnvironment, PWSTR pPathName, PWSTR pPrintProcessorName)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL WINAPI
+DeletePrintProcessorW(PWSTR pName, PWSTR pEnvironment, PWSTR pPrintProcessorName)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL WINAPI
+EnumPrintProcessorDatatypesA(PSTR pName, LPSTR pPrintProcessorName, DWORD Level, PBYTE pDatatypes, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL WINAPI
+EnumPrintProcessorDatatypesW(PWSTR pName, LPWSTR pPrintProcessorName, DWORD Level, PBYTE pDatatypes, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ DWORD dwErrorCode;
+ DWORD i;
+ PBYTE p = pDatatypes;
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcEnumPrintProcessorDatatypes(pName, pPrintProcessorName, Level, pDatatypes, cbBuf, pcbNeeded, pcReturned);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcEnumPrintProcessorDatatypes failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ // Replace relative offset addresses in the output by absolute pointers.
+ for (i = 0; i < *pcReturned; i++)
+ {
+ _MarshallUpDatatypesInfo((PDATATYPES_INFO_1W)p);
+ p += sizeof(DATATYPES_INFO_1W);
+ }
+ }
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+EnumPrintProcessorsW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ DWORD dwErrorCode;
+ DWORD i;
+ PBYTE p = pPrintProcessorInfo;
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcEnumPrintProcessors(pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded, pcReturned);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcEnumPrintProcessors failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ // Replace relative offset addresses in the output by absolute pointers.
+ for (i = 0; i < *pcReturned; i++)
+ {
+ _MarshallUpPrintProcessorInfo((PPRINTPROCESSOR_INFO_1W)p);
+ p += sizeof(PRINTPROCESSOR_INFO_1W);
+ }
+ }
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+GetPrintProcessorDirectoryW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded)
+{
+ BOOL bReturnValue = FALSE;
+ DWORD dwErrorCode;
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcGetPrintProcessorDirectory(pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded);
+ SetLastError(dwErrorCode);
+ bReturnValue = (dwErrorCode == ERROR_SUCCESS);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ERR("_RpcGetPrintProcessorDirectory failed with exception code %lu!\n", RpcExceptionCode());
+ }
+ RpcEndExcept;
+
+ return bReturnValue;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler API
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Print Providers
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+BOOL WINAPI
+AddPrintProvidorW(PWSTR pName, DWORD Level, PBYTE pProviderInfo)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL WINAPI
+DeletePrintProvidorW(PWSTR pName, PWSTR pEnvironment, PWSTR pPrintProviderName)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
#define REACTOS_VERSION_DLL
-#define REACTOS_STR_FILE_DESCRIPTION "Windows printer spooler"
+#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Spooler API"
#define REACTOS_STR_INTERNAL_NAME "winspool"
#define REACTOS_STR_ORIGINAL_FILENAME "winspool.drv"
#include <reactos/version.rc>
--- /dev/null
+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 stdcall AddJobA(long long ptr long ptr)
+112 stdcall AddJobW(long long ptr long ptr)
+113 stub AddMonitorA
+114 stdcall AddMonitorW(wstr long ptr)
+115 stub AddPortA
+116 stub AddPortExA
+117 stub AddPortExW
+118 stdcall AddPortW(wstr long wstr)
+119 stub AddPrintProcessorA
+120 stdcall AddPrintProcessorW(wstr wstr wstr wstr)
+121 stub AddPrintProvidorA
+122 stdcall AddPrintProvidorW(wstr long ptr)
+123 stub AddPrinterA
+124 stub AddPrinterConnectionA
+125 stub AddPrinterConnectionW
+126 stub AddPrinterDriverA
+127 stub AddPrinterDriverExA
+128 stub AddPrinterDriverExW
+129 stdcall AddPrinterDriverW(wstr long ptr)
+130 stdcall AddPrinterW(wstr long ptr)
+131 stub AdvancedDocumentPropertiesA
+132 stdcall AdvancedDocumentPropertiesW(long long wstr ptr ptr)
+133 stub AdvancedSetupDialog
+134 stdcall ClosePrinter(long)
+135 stub CloseSpoolFileHandle
+136 stub CommitSpoolData
+137 stub ConfigurePortA
+138 stdcall ConfigurePortW(wstr long wstr)
+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 stdcall DeleteMonitorW(wstr wstr wstr)
+149 stub DeletePortA
+150 stdcall DeletePortW(wstr long wstr)
+151 stub DeletePrintProcessorA
+152 stdcall DeletePrintProcessorW(wstr wstr wstr)
+153 stub DeletePrintProvidorA
+154 stdcall DeletePrintProvidorW(wstr wstr wstr)
+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 stdcall DeletePrinterDriverW(wstr wstr wstr)
+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 stdcall EnumJobsA(long long long long ptr long ptr ptr)
+186 stdcall EnumJobsW(long long long long ptr long ptr ptr)
+187 stub EnumMonitorsA
+188 stdcall EnumMonitorsW(wstr long ptr long ptr ptr)
+189 stub EnumPortsA
+190 stdcall EnumPortsW(wstr long ptr long ptr ptr)
+191 stdcall EnumPrintProcessorDatatypesA(ptr ptr long ptr long ptr ptr)
+192 stdcall EnumPrintProcessorDatatypesW(ptr ptr long ptr long ptr ptr)
+193 stub EnumPrintProcessorsA
+194 stdcall EnumPrintProcessorsW(ptr ptr long ptr long ptr ptr)
+195 stub EnumPrinterDataA
+196 stub EnumPrinterDataExA
+197 stub EnumPrinterDataExW
+198 stub EnumPrinterDataW
+199 stub EnumPrinterDriversA
+200 stdcall EnumPrinterDriversW(wstr wstr long ptr long ptr ptr)
+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 stdcall GetJobA(long long long ptr long ptr)
+245 stdcall GetJobW(long long long ptr long ptr)
+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 stdcall GetPrinterDataW(long wstr ptr ptr long ptr)
+253 stdcall GetPrinterDriverA(long str long ptr long ptr)
+254 stub GetPrinterDriverDirectoryA
+255 stdcall GetPrinterDriverDirectoryW(wstr wstr long ptr long ptr)
+256 stdcall GetPrinterDriverW(long wstr long ptr long ptr)
+257 stdcall GetPrinterW(long long ptr long ptr)
+258 stub GetSpoolFileHandle
+259 stdcall IsValidDevmodeA(ptr long)
+260 stdcall IsValidDevmodeW(ptr long)
+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 stdcall ReadPrinter(long ptr long ptr)
+271 stub ResetPrinterA
+272 stdcall ResetPrinterW(long ptr)
+273 stdcall ScheduleJob(long long)
+274 stub SeekPrinter
+275 stub SetAllocFailCount
+276 stub SetFormA
+277 stub SetFormW
+278 stdcall SetJobA(long long long ptr long)
+279 stdcall SetJobW(long long long ptr long)
+280 stub SetPortA
+281 stub SetPortW
+282 stub SetPrinterA
+283 stub SetPrinterDataA
+284 stub SetPrinterDataExA
+285 stub SetPrinterDataExW
+286 stdcall SetPrinterDataW(long wstr long ptr long)
+287 stdcall SetPrinterW(long long ptr long)
+288 stub SplDriverUnloadComplete
+289 stub SpoolerDevQueryPrintW
+290 stdcall SpoolerInit()
+291 stub SpoolerPrinterEvent
+292 stub StartDocDlgA
+293 stub StartDocDlgW
+294 stdcall StartDocPrinterA(long long ptr)
+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)
--- /dev/null
+#add_subdirectory(tty)
+#add_subdirectory(unidrv)
--- /dev/null
+/*
+ * 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"
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#ifndef _REACTOS_SPOOLSS_H
+#define _REACTOS_SPOOLSS_H
+
+typedef struct _MARSHALL_DOWN_INFO
+{
+ DWORD dwOffset; /** Byte offset of this element within the structure or MAXDWORD to indicate the end of the array */
+ DWORD cbSize; /** Total size of this element in bytes under Windows. Unused here, I don't know what we need this number for. */
+ DWORD cbPerElementSize; /** If this element is a structure itself, this field gives the size in bytes of each element of the structure.
+ Otherwise, this is the same as cbTotalSize. E.g. for SYSTEMTIME, cbSize would be 16 and cbPerElementSize would be 2.
+ Unused here, I don't know what we need this number for. */
+ BOOL bAdjustAddress; /** TRUE if MarshallDownStructure shall adjust the address of this element, FALSE if it shall leave this element untouched. */
+}
+MARSHALL_DOWN_INFO, *PMARSHALL_DOWN_INFO;
+
+PWSTR WINAPI AllocSplStr(PCWSTR pwszInput);
+PVOID WINAPI DllAllocSplMem(DWORD dwBytes);
+BOOL WINAPI DllFreeSplMem(PVOID pMem);
+BOOL WINAPI DllFreeSplStr(PWSTR pwszString);
+BOOL WINAPI MarshallDownStructure(PVOID pStructure, PMARSHALL_DOWN_INFO pParameters, DWORD cbStructureSize, BOOL bSomeBoolean);
+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
--- /dev/null
+add_subdirectory(localmon)
+#add_subdirectory(pjlmon)
+#add_subdirectory(tcpmon)
+#add_subdirectory(usbmon)
--- /dev/null
+
+add_subdirectory(ui)
+
+spec2def(localmon.dll localmon.spec ADD_IMPORTLIB)
+
+list(APPEND SOURCE
+ main.c
+ ports.c
+ precomp.h
+ tools.c
+ xcv.c)
+
+add_library(localmon SHARED
+ ${SOURCE}
+ localmon.rc
+ ${CMAKE_CURRENT_BINARY_DIR}/localmon.def)
+
+set_module_type(localmon win32dll UNICODE)
+target_link_libraries(localmon wine)
+add_importlibs(localmon advapi32 spoolss user32 msvcrt kernel32 ntdll)
+add_pch(localmon precomp.h SOURCE)
+add_cd_file(TARGET localmon DESTINATION reactos/system32 FOR all)
--- /dev/null
+LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
+
+STRINGTABLE
+BEGIN
+ IDS_LOCAL_PORT "Lokaler Anschluss"
+ IDS_LOCAL_MONITOR "Lokaler Monitor"
+END
--- /dev/null
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+STRINGTABLE
+BEGIN
+ IDS_LOCAL_PORT "Local Port"
+ IDS_LOCAL_MONITOR "Local Monitor"
+END
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Port Monitor
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Resource file
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include <windef.h>
+#include "resource.h"
+
+/* Version Information */
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Local Port Monitor"
+#define REACTOS_STR_INTERNAL_NAME "localmon"
+#define REACTOS_STR_ORIGINAL_FILENAME "localmon.dll"
+#include <reactos/version.rc>
+
+/* UTF-8 */
+#pragma code_page(65001)
+
+#ifdef LANGUAGE_DE_DE
+ #include "lang/de-DE.rc"
+#endif
+#ifdef LANGUAGE_EN_US
+ #include "lang/en-US.rc"
+#endif
--- /dev/null
+@ stdcall InitializePrintMonitor2(ptr ptr)
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Port Monitor
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Main functions
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+// Global Variables
+DWORD cbLocalMonitor;
+DWORD cbLocalPort;
+PCWSTR pwszLocalMonitor;
+PCWSTR pwszLocalPort;
+
+// Local Constants
+static MONITOR2 _MonitorFunctions = {
+ sizeof(MONITOR2), // cbSize
+ LocalmonEnumPorts, // pfnEnumPorts
+ LocalmonOpenPort, // pfnOpenPort
+ NULL, // pfnOpenPortEx
+ LocalmonStartDocPort, // pfnStartDocPort
+ LocalmonWritePort, // pfnWritePort
+ LocalmonReadPort, // pfnReadPort
+ LocalmonEndDocPort, // pfnEndDocPort
+ LocalmonClosePort, // pfnClosePort
+ NULL, // pfnAddPort
+ NULL, // pfnAddPortEx
+ NULL, // pfnConfigurePort
+ NULL, // pfnDeletePort
+ LocalmonGetPrinterDataFromPort, // pfnGetPrinterDataFromPort
+ LocalmonSetPortTimeOuts, // pfnSetPortTimeOuts
+ LocalmonXcvOpenPort, // pfnXcvOpenPort
+ LocalmonXcvDataPort, // pfnXcvDataPort
+ LocalmonXcvClosePort, // pfnXcvClosePort
+ LocalmonShutdown, // pfnShutdown
+ NULL, // pfnSendRecvBidiDataFromPort
+};
+
+
+/**
+ * @name _IsNEPort
+ *
+ * Checks if the given port name is a virtual Ne port.
+ * A virtual Ne port may appear in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Ports and can have the formats
+ * Ne00:, Ne01:, Ne-02:, Ne456:
+ * This check is extra picky to not cause false positives (like file name ports starting with "Ne").
+ *
+ * @param pwszPortName
+ * The port name to check.
+ *
+ * @return
+ * TRUE if this is definitely a virtual Ne port, FALSE if not.
+ */
+static __inline BOOL
+_IsNEPort(PCWSTR pwszPortName)
+{
+ PCWSTR p = pwszPortName;
+
+ // First character needs to be 'N' (uppercase or lowercase)
+ if (*p != L'N' && *p != L'n')
+ return FALSE;
+
+ // Next character needs to be 'E' (uppercase or lowercase)
+ p++;
+ if (*p != L'E' && *p != L'e')
+ return FALSE;
+
+ // An optional hyphen may follow now.
+ p++;
+ if (*p == L'-')
+ p++;
+
+ // Now an arbitrary number of digits may follow.
+ while (*p >= L'0' && *p <= L'9')
+ p++;
+
+ // Finally, the virtual Ne port must be terminated by a colon.
+ if (*p != ':')
+ return FALSE;
+
+ // If this is the end of the string, we have a virtual Ne port.
+ p++;
+ return (*p == L'\0');
+}
+
+static void
+_LoadResources(HINSTANCE hinstDLL)
+{
+ LoadStringW(hinstDLL, IDS_LOCAL_MONITOR, (PWSTR)&pwszLocalMonitor, 0);
+ cbLocalMonitor = (wcslen(pwszLocalMonitor) + 1) * sizeof(WCHAR);
+
+ LoadStringW(hinstDLL, IDS_LOCAL_PORT, (PWSTR)&pwszLocalPort, 0);
+ cbLocalPort = (wcslen(pwszLocalPort) + 1) * sizeof(WCHAR);
+}
+
+BOOL WINAPI
+DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ DisableThreadLibraryCalls(hinstDLL);
+ _LoadResources(hinstDLL);
+ break;
+ }
+
+ return TRUE;
+}
+
+void WINAPI
+LocalmonShutdown(HANDLE hMonitor)
+{
+ PLOCALMON_HANDLE pLocalmon;
+ PLOCALMON_PORT pPort;
+ PLOCALMON_XCV pXcv;
+
+ TRACE("LocalmonShutdown(%p)\n", hMonitor);
+
+ pLocalmon = (PLOCALMON_HANDLE)hMonitor;
+
+ // Close all virtual file ports.
+ while (!IsListEmpty(&pLocalmon->FilePorts))
+ {
+ pPort = CONTAINING_RECORD(&pLocalmon->FilePorts.Flink, LOCALMON_PORT, Entry);
+ LocalmonClosePort((HANDLE)pPort);
+ }
+
+ // Do the same for the open Xcv ports.
+ while (!IsListEmpty(&pLocalmon->XcvHandles))
+ {
+ pXcv = CONTAINING_RECORD(&pLocalmon->XcvHandles.Flink, LOCALMON_XCV, Entry);
+ LocalmonXcvClosePort((HANDLE)pXcv);
+ }
+
+ // Now close all registry ports, remove them from the list and free their memory.
+ while (!IsListEmpty(&pLocalmon->RegistryPorts))
+ {
+ pPort = CONTAINING_RECORD(&pLocalmon->RegistryPorts.Flink, LOCALMON_PORT, Entry);
+ LocalmonClosePort((HANDLE)pPort);
+ RemoveEntryList(&pPort->Entry);
+ DllFreeSplMem(pPort);
+ }
+
+ // Finally clean the LOCALMON_HANDLE structure itself.
+ DeleteCriticalSection(&pLocalmon->Section);
+ DllFreeSplMem(pLocalmon);
+}
+
+PMONITOR2 WINAPI
+InitializePrintMonitor2(PMONITORINIT pMonitorInit, PHANDLE phMonitor)
+{
+ DWORD cchMaxPortName;
+ DWORD cchPortName;
+ DWORD dwErrorCode;
+ DWORD dwPortCount;
+ DWORD i;
+ HKEY hKey;
+ PMONITOR2 pReturnValue = NULL;
+ PLOCALMON_HANDLE pLocalmon;
+ PLOCALMON_PORT pPort = NULL;
+
+ TRACE("InitializePrintMonitor2(%p, %p)\n", pMonitorInit, phMonitor);
+
+ // Create a new LOCALMON_HANDLE structure.
+ pLocalmon = DllAllocSplMem(sizeof(LOCALMON_HANDLE));
+ InitializeCriticalSection(&pLocalmon->Section);
+ InitializeListHead(&pLocalmon->FilePorts);
+ InitializeListHead(&pLocalmon->RegistryPorts);
+ InitializeListHead(&pLocalmon->XcvHandles);
+
+ // The Local Spooler Port Monitor doesn't need to care about the given registry key and functions.
+ // Instead it uses a well-known registry key for getting its information about local ports. Open this one.
+ dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports", 0, KEY_READ, &hKey);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Get the number of ports and the length of the largest port name.
+ dwErrorCode = (DWORD)RegQueryInfoKeyW(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwPortCount, &cchMaxPortName, NULL, NULL, NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Loop through all ports.
+ for (i = 0; i < dwPortCount; i++)
+ {
+ // Allocate memory for a new LOCALMON_PORT structure and its name.
+ pPort = DllAllocSplMem(sizeof(LOCALMON_PORT) + (cchMaxPortName + 1) * sizeof(WCHAR));
+ if (!pPort)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ pPort->pLocalmon = pLocalmon;
+ pPort->hFile = INVALID_HANDLE_VALUE;
+ pPort->pwszPortName = (PWSTR)((PBYTE)pPort + sizeof(LOCALMON_PORT));
+
+ // Get the port name.
+ cchPortName = cchMaxPortName + 1;
+ dwErrorCode = (DWORD)RegEnumValueW(hKey, i, pPort->pwszPortName, &cchPortName, NULL, NULL, NULL, NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegEnumValueW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // pwszPortName can be one of the following to be valid for this Port Monitor:
+ // COMx: - Physical COM port
+ // LPTx: - Physical LPT port (or redirected one using "net use LPT1 ...")
+ // FILE: - Opens a prompt that asks for an output filename
+ // C:\bla.txt - Redirection into the file "C:\bla.txt"
+ // \\COMPUTERNAME\PrinterName - Redirection to a shared network printer installed as a local port
+ //
+ // We can't detect valid and invalid ones by the name, so we can only exclude empty ports and the virtual "Ne00:", "Ne01:", ... ports.
+ // Skip the invalid ones here.
+ if (!cchPortName || _IsNEPort(pPort->pwszPortName))
+ {
+ DllFreeSplMem(pPort);
+ continue;
+ }
+
+ // Add it to the list.
+ InsertTailList(&pLocalmon->RegistryPorts, &pPort->Entry);
+
+ // Don't let the cleanup routine free this.
+ pPort = NULL;
+ }
+
+ // Return our handle and the Print Monitor functions.
+ *phMonitor = (HANDLE)pLocalmon;
+ pReturnValue = &_MonitorFunctions;
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ if (pPort)
+ DllFreeSplMem(pPort);
+
+ SetLastError(dwErrorCode);
+ return pReturnValue;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Port Monitor
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to ports
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+
+// Local Constants
+static const WCHAR wszNonspooledPrefix[] = L"NONSPOOLED_";
+static const DWORD cchNonspooledPrefix = _countof(wszNonspooledPrefix) - 1;
+
+
+/**
+ * @name _GetNonspooledPortName
+ *
+ * Prepends "NONSPOOLED_" to a port name without colon.
+ *
+ * @param pwszPortNameWithoutColon
+ * Result of a previous GetPortNameWithoutColon call.
+ *
+ * @param ppwszNonspooledPortName
+ * Pointer to a buffer that will contain the NONSPOOLED port name.
+ * You have to free this buffer using DllFreeSplMem.
+ *
+ * @return
+ * ERROR_SUCCESS if the NONSPOOLED port name was successfully copied into the buffer.
+ * ERROR_NOT_ENOUGH_MEMORY if memory allocation failed.
+ */
+static __inline DWORD
+_GetNonspooledPortName(PCWSTR pwszPortNameWithoutColon, PWSTR* ppwszNonspooledPortName)
+{
+ DWORD cchPortNameWithoutColon;
+
+ cchPortNameWithoutColon = wcslen(pwszPortNameWithoutColon);
+
+ *ppwszNonspooledPortName = DllAllocSplMem((cchNonspooledPrefix + cchPortNameWithoutColon + 1) * sizeof(WCHAR));
+ if (!*ppwszNonspooledPortName)
+ {
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ CopyMemory(*ppwszNonspooledPortName, wszNonspooledPrefix, cchNonspooledPrefix * sizeof(WCHAR));
+ CopyMemory(&(*ppwszNonspooledPortName)[cchNonspooledPrefix], pwszPortNameWithoutColon, (cchPortNameWithoutColon + 1) * sizeof(WCHAR));
+
+ return ERROR_SUCCESS;
+}
+
+/**
+ * @name _IsLegacyPort
+ *
+ * Checks if the given port name is a legacy port (COM or LPT).
+ * This check is extra picky to not cause false positives (like file name ports starting with "COM" or "LPT").
+ *
+ * @param pwszPortName
+ * The port name to check.
+ *
+ * @param pwszPortType
+ * L"COM" or L"LPT"
+ *
+ * @return
+ * TRUE if this is definitely the asked legacy port, FALSE if not.
+ */
+static __inline BOOL
+_IsLegacyPort(PCWSTR pwszPortName, PCWSTR pwszPortType)
+{
+ const DWORD cchPortType = 3;
+ PCWSTR p = pwszPortName;
+
+ // The port name must begin with pwszPortType.
+ if (_wcsnicmp(p, pwszPortType, cchPortType) != 0)
+ return FALSE;
+
+ p += cchPortType;
+
+ // Now an arbitrary number of digits may follow.
+ while (*p >= L'0' && *p <= L'9')
+ p++;
+
+ // Finally, the legacy port must be terminated by a colon.
+ if (*p != ':')
+ return FALSE;
+
+ // If this is the end of the string, we have a legacy port.
+ p++;
+ return (*p == L'\0');
+}
+
+/**
+ * @name _ClosePortHandles
+ *
+ * Closes a port of any type if it's open.
+ * Removes any saved mapping or existing definition of a NONSPOOLED device mapping.
+ *
+ * @param pPort
+ * The port you want to close.
+ */
+static void
+_ClosePortHandles(PLOCALMON_PORT pPort)
+{
+ PWSTR pwszNonspooledPortName;
+ PWSTR pwszPortNameWithoutColon;
+
+ // A port is already fully closed if the file handle is invalid.
+ if (pPort->hFile == INVALID_HANDLE_VALUE)
+ return;
+
+ // Close the file handle.
+ CloseHandle(pPort->hFile);
+ pPort->hFile = INVALID_HANDLE_VALUE;
+
+ // A NONSPOOLED port was only created if pwszMapping contains the current port mapping.
+ if (!pPort->pwszMapping)
+ return;
+
+ // Free the information about the current mapping.
+ DllFreeSplStr(pPort->pwszMapping);
+ pPort->pwszMapping = NULL;
+
+ // Finally get the required strings and remove the DOS device definition for the NONSPOOLED port.
+ if (GetPortNameWithoutColon(pPort->pwszPortName, &pwszPortNameWithoutColon) == ERROR_SUCCESS)
+ {
+ if (_GetNonspooledPortName(pwszPortNameWithoutColon, &pwszNonspooledPortName) == ERROR_SUCCESS)
+ {
+ DefineDosDeviceW(DDD_REMOVE_DEFINITION, pwszNonspooledPortName, NULL);
+ DllFreeSplMem(pwszNonspooledPortName);
+ }
+
+ DllFreeSplMem(pwszPortNameWithoutColon);
+ }
+}
+
+/**
+ * @name _CreateNonspooledPort
+ *
+ * Queries the system-wide device definition of the given port.
+ * If such a definition exists, it's a legacy port remapped to a named pipe by the spooler.
+ * In this case, the function creates and opens a NONSPOOLED device definition to the most recent mapping before the current one (usually the physical device).
+ *
+ * @param pPort
+ * Pointer to the LOCALMON_PORT structure of the desired port.
+ *
+ * @return
+ * TRUE if a NONSPOOLED port was successfully created, FALSE otherwise.
+ * A more specific error code can be obtained through GetLastError.
+ * In particular, if the return value is FALSE and GetLastError returns ERROR_SUCCESS, no NONSPOOLED port is needed for this port.
+ */
+static BOOL
+_CreateNonspooledPort(PLOCALMON_PORT pPort)
+{
+ const WCHAR wszLocalSlashes[] = L"\\\\.\\";
+ const DWORD cchLocalSlashes = _countof(wszLocalSlashes) - 1;
+
+ const WCHAR wszSpoolerNamedPipe[] = L"\\Device\\NamedPipe\\Spooler\\";
+ const DWORD cchSpoolerNamedPipe = _countof(wszSpoolerNamedPipe) - 1;
+
+ BOOL bReturnValue = FALSE;
+ DWORD cchPortNameWithoutColon;
+ DWORD dwErrorCode;
+ HANDLE hToken = NULL;
+ PWSTR p;
+ PWSTR pwszDeviceMappings = NULL;
+ PWSTR pwszNonspooledFileName = NULL;
+ PWSTR pwszNonspooledPortName = NULL;
+ PWSTR pwszPipeName = NULL;
+ PWSTR pwszPortNameWithoutColon = NULL;
+
+ // We need the port name without the trailing colon.
+ dwErrorCode = GetPortNameWithoutColon(pPort->pwszPortName, &pwszPortNameWithoutColon);
+ if (dwErrorCode == ERROR_INVALID_PARAMETER)
+ {
+ // This port has no trailing colon, so we also need no NONSPOOLED mapping for it.
+ dwErrorCode = ERROR_SUCCESS;
+ goto Cleanup;
+ }
+ else if (dwErrorCode != ERROR_SUCCESS)
+ {
+ // Another unexpected failure.
+ goto Cleanup;
+ }
+
+ cchPortNameWithoutColon = wcslen(pwszPortNameWithoutColon);
+
+ // The spooler has usually remapped the legacy port to a named pipe of the format in wszSpoolerNamedPipe.
+ // Construct the device name of this pipe.
+ pwszPipeName = DllAllocSplMem((cchSpoolerNamedPipe + cchPortNameWithoutColon + 1) * sizeof(WCHAR));
+ if (!pwszPipeName)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ CopyMemory(pwszPipeName, wszSpoolerNamedPipe, cchSpoolerNamedPipe * sizeof(WCHAR));
+ CopyMemory(&pwszPipeName[cchSpoolerNamedPipe], pwszPortNameWithoutColon, (cchPortNameWithoutColon + 1) * sizeof(WCHAR));
+
+ // QueryDosDeviceW is one of the shitty APIs that gives no information about the required buffer size and wants you to know it by pure magic.
+ // Examples show that a value of MAX_PATH * sizeof(WCHAR) is usually taken here, so we have no other option either.
+ pwszDeviceMappings = DllAllocSplMem(MAX_PATH * sizeof(WCHAR));
+ if (!pwszDeviceMappings)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Switch to the SYSTEM context, because we're only interested in creating NONSPOOLED ports for system-wide ports.
+ // User-local ports (like _some_ redirected networked ones) aren't remapped by the spooler and can be opened directly.
+ hToken = RevertToPrinterSelf();
+ if (!hToken)
+ {
+ dwErrorCode = GetLastError();
+ ERR("RevertToPrinterSelf failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // QueryDosDeviceW returns the current mapping and a list of prior mappings of this legacy port, which is managed as a DOS device in the system.
+ if (!QueryDosDeviceW(pwszPortNameWithoutColon, pwszDeviceMappings, MAX_PATH))
+ {
+ // No system-wide port exists, so we also need no NONSPOOLED mapping.
+ dwErrorCode = ERROR_SUCCESS;
+ goto Cleanup;
+ }
+
+ // Check if this port has already been opened by _CreateNonspooledPort previously.
+ if (pPort->pwszMapping)
+ {
+ // In this case, we just need to do something if the mapping has changed.
+ // Therefore, check if the stored mapping equals the current mapping.
+ if (wcscmp(pPort->pwszMapping, pwszDeviceMappings) == 0)
+ {
+ // We don't need to do anything in this case.
+ dwErrorCode = ERROR_SUCCESS;
+ goto Cleanup;
+ }
+ else
+ {
+ // Close the open file handle and free the memory for pwszMapping before remapping.
+ CloseHandle(pPort->hFile);
+ pPort->hFile = INVALID_HANDLE_VALUE;
+
+ DllFreeSplStr(pPort->pwszMapping);
+ pPort->pwszMapping = NULL;
+ }
+ }
+
+ // The port is usually mapped to the named pipe and this is how we received our data for printing.
+ // What we now need for accessing the actual port is the most recent mapping different from the named pipe.
+ p = pwszDeviceMappings;
+
+ for (;;)
+ {
+ if (!*p)
+ {
+ // We reached the end of the list without finding a mapping.
+ ERR("Can't find a suitable mapping for the port \"%S\"!", pPort->pwszPortName);
+ goto Cleanup;
+ }
+
+ if (_wcsicmp(p, pwszPipeName) != 0)
+ break;
+
+ // Advance to the next mapping in the list.
+ p += wcslen(p) + 1;
+ }
+
+ // We now want to create a DOS device "NONSPOOLED_<PortName>" to this mapping, so that we're able to open it through CreateFileW.
+ dwErrorCode = _GetNonspooledPortName(pwszPortNameWithoutColon, &pwszNonspooledPortName);
+ if (dwErrorCode != ERROR_SUCCESS)
+ goto Cleanup;
+
+ // Delete a possibly existing NONSPOOLED device before creating the new one, so we don't stack up device definitions.
+ DefineDosDeviceW(DDD_REMOVE_DEFINITION, pwszNonspooledPortName, NULL);
+
+ if (!DefineDosDeviceW(DDD_RAW_TARGET_PATH, pwszNonspooledPortName, p))
+ {
+ dwErrorCode = GetLastError();
+ ERR("DefineDosDeviceW failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // This is all we needed to do in SYSTEM context.
+ ImpersonatePrinterClient(hToken);
+ hToken = NULL;
+
+ // Construct the file name to our created device for CreateFileW.
+ pwszNonspooledFileName = DllAllocSplMem((cchLocalSlashes + cchNonspooledPrefix + cchPortNameWithoutColon + 1) * sizeof(WCHAR));
+ if (!pwszNonspooledFileName)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ CopyMemory(pwszNonspooledFileName, wszLocalSlashes, cchLocalSlashes * sizeof(WCHAR));
+ CopyMemory(&pwszNonspooledFileName[cchLocalSlashes], wszNonspooledPrefix, cchNonspooledPrefix * sizeof(WCHAR));
+ CopyMemory(&pwszNonspooledFileName[cchLocalSlashes + cchNonspooledPrefix], pwszPortNameWithoutColon, (cchPortNameWithoutColon + 1) * sizeof(WCHAR));
+
+ // Finally open it for reading and writing.
+ pPort->hFile = CreateFileW(pwszNonspooledFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
+ if (pPort->hFile == INVALID_HANDLE_VALUE)
+ {
+ dwErrorCode = GetLastError();
+ ERR("CreateFileW failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Store the current mapping of the port, so that we can check if it has changed.
+ pPort->pwszMapping = AllocSplStr(pwszDeviceMappings);
+ if (!pPort->pwszMapping)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ bReturnValue = TRUE;
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ if (hToken)
+ ImpersonatePrinterClient(hToken);
+
+ if (pwszDeviceMappings)
+ DllFreeSplMem(pwszDeviceMappings);
+
+ if (pwszNonspooledFileName)
+ DllFreeSplMem(pwszNonspooledFileName);
+
+ if (pwszNonspooledPortName)
+ DllFreeSplMem(pwszNonspooledPortName);
+
+ if (pwszPipeName)
+ DllFreeSplMem(pwszPipeName);
+
+ if (pwszPortNameWithoutColon)
+ DllFreeSplMem(pwszPortNameWithoutColon);
+
+ SetLastError(dwErrorCode);
+ return bReturnValue;
+}
+
+static PLOCALMON_PORT
+_FindPort(PLOCALMON_HANDLE pLocalmon, PCWSTR pwszPortName)
+{
+ PLIST_ENTRY pEntry;
+ PLOCALMON_PORT pPort;
+
+ for (pEntry = pLocalmon->RegistryPorts.Flink; pEntry != &pLocalmon->RegistryPorts; pEntry = pEntry->Flink)
+ {
+ pPort = CONTAINING_RECORD(pEntry, LOCALMON_PORT, Entry);
+
+ if (wcscmp(pPort->pwszPortName, pwszPortName) == 0)
+ return pPort;
+ }
+
+ return NULL;
+}
+
+static DWORD
+_LocalmonEnumPortsLevel1(PLOCALMON_HANDLE pLocalmon, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ DWORD cbPortName;
+ DWORD dwErrorCode;
+ DWORD dwPortCount = 0;
+ PBYTE pPortInfo;
+ PBYTE pPortString;
+ PLIST_ENTRY pEntry;
+ PLOCALMON_PORT pPort;
+ PORT_INFO_1W PortInfo1;
+
+ // Count the required buffer size and the number of datatypes.
+ for (pEntry = pLocalmon->RegistryPorts.Flink; pEntry != &pLocalmon->RegistryPorts; pEntry = pEntry->Flink)
+ {
+ pPort = CONTAINING_RECORD(pEntry, LOCALMON_PORT, Entry);
+
+ cbPortName = (wcslen(pPort->pwszPortName) + 1) * sizeof(WCHAR);
+ *pcbNeeded += sizeof(PORT_INFO_1W) + cbPortName;
+ dwPortCount++;
+ }
+
+ // Check if the supplied buffer is large enough.
+ if (cbBuf < *pcbNeeded)
+ {
+ dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
+ goto Cleanup;
+ }
+
+ // Put the strings right after the last PORT_INFO_1W structure.
+ pPortInfo = pPorts;
+ pPortString = pPorts + dwPortCount * sizeof(PORT_INFO_1W);
+
+ // Copy over all ports.
+ for (pEntry = pLocalmon->RegistryPorts.Flink; pEntry != &pLocalmon->RegistryPorts; pEntry = pEntry->Flink)
+ {
+ pPort = CONTAINING_RECORD(pEntry, LOCALMON_PORT, Entry);
+
+ // Copy the port name.
+ PortInfo1.pName = (PWSTR)pPortString;
+ cbPortName = (wcslen(pPort->pwszPortName) + 1) * sizeof(WCHAR);
+ CopyMemory(pPortString, pPort->pwszPortName, cbPortName);
+ pPortString += cbPortName;
+
+ // Copy the structure and advance to the next one in the output buffer.
+ CopyMemory(pPortInfo, &PortInfo1, sizeof(PORT_INFO_1W));
+ pPortInfo += sizeof(PORT_INFO_1W);
+ }
+
+ *pcReturned = dwPortCount;
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ return dwErrorCode;
+}
+
+static DWORD
+_LocalmonEnumPortsLevel2(PLOCALMON_HANDLE pLocalmon, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ DWORD cbPortName;
+ DWORD dwErrorCode;
+ DWORD dwPortCount = 0;
+ PBYTE pPortInfo;
+ PBYTE pPortString;
+ PLIST_ENTRY pEntry;
+ PLOCALMON_PORT pPort;
+ PORT_INFO_2W PortInfo2;
+
+ // Count the required buffer size and the number of datatypes.
+ for (pEntry = pLocalmon->RegistryPorts.Flink; pEntry != &pLocalmon->RegistryPorts; pEntry = pEntry->Flink)
+ {
+ pPort = CONTAINING_RECORD(pEntry, LOCALMON_PORT, Entry);
+
+ cbPortName = (wcslen(pPort->pwszPortName) + 1) * sizeof(WCHAR);
+ *pcbNeeded += sizeof(PORT_INFO_2W) + cbPortName + cbLocalMonitor + cbLocalPort;
+ dwPortCount++;
+ }
+
+ // Check if the supplied buffer is large enough.
+ if (cbBuf < *pcbNeeded)
+ {
+ dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
+ goto Cleanup;
+ }
+
+ // Put the strings right after the last PORT_INFO_2W structure.
+ pPortInfo = pPorts;
+ pPortString = pPorts + dwPortCount * sizeof(PORT_INFO_2W);
+
+ // Copy over all ports.
+ for (pEntry = pLocalmon->RegistryPorts.Flink; pEntry != &pLocalmon->RegistryPorts; pEntry = pEntry->Flink)
+ {
+ pPort = CONTAINING_RECORD(pEntry, LOCALMON_PORT, Entry);
+
+ // All local ports are writable and readable.
+ PortInfo2.fPortType = PORT_TYPE_WRITE | PORT_TYPE_READ;
+ PortInfo2.Reserved = 0;
+
+ // Copy the port name.
+ PortInfo2.pPortName = (PWSTR)pPortString;
+ cbPortName = (wcslen(pPort->pwszPortName) + 1) * sizeof(WCHAR);
+ CopyMemory(pPortString, pPort->pwszPortName, cbPortName);
+ pPortString += cbPortName;
+
+ // Copy the monitor name.
+ PortInfo2.pMonitorName = (PWSTR)pPortString;
+ CopyMemory(pPortString, pwszLocalMonitor, cbLocalMonitor);
+ pPortString += cbLocalMonitor;
+
+ // Copy the description.
+ PortInfo2.pDescription = (PWSTR)pPortString;
+ CopyMemory(pPortString, pwszLocalPort, cbLocalPort);
+ pPortString += cbLocalPort;
+
+ // Copy the structure and advance to the next one in the output buffer.
+ CopyMemory(pPortInfo, &PortInfo2, sizeof(PORT_INFO_2W));
+ pPortInfo += sizeof(PORT_INFO_2W);
+ }
+
+ *pcReturned = dwPortCount;
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ return dwErrorCode;
+}
+
+/**
+ * @name _SetTransmissionRetryTimeout
+ *
+ * Checks if the given port is a physical one and sets the transmission retry timeout in this case using the value from registry.
+ *
+ * @param pPort
+ * The port to operate on.
+ *
+ * @return
+ * TRUE if the given port is a physical one, FALSE otherwise.
+ */
+static BOOL
+_SetTransmissionRetryTimeout(PLOCALMON_PORT pPort)
+{
+ COMMTIMEOUTS CommTimeouts;
+
+ // Get the timeout from the port.
+ if (!GetCommTimeouts(pPort->hFile, &CommTimeouts))
+ return FALSE;
+
+ // Set the timeout using the value from registry.
+ CommTimeouts.WriteTotalTimeoutConstant = GetLPTTransmissionRetryTimeout() * 1000;
+ SetCommTimeouts(pPort->hFile, &CommTimeouts);
+
+ return TRUE;
+}
+
+BOOL WINAPI
+LocalmonClosePort(HANDLE hPort)
+{
+ PLOCALMON_PORT pPort = (PLOCALMON_PORT)hPort;
+
+ TRACE("LocalmonClosePort(%p)\n", hPort);
+
+ // Sanity checks
+ if (!pPort)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ // Close the file handle, free memory for pwszMapping and delete any NONSPOOLED port.
+ _ClosePortHandles(pPort);
+
+ // Close any open printer handle.
+ if (pPort->hPrinter)
+ {
+ ClosePrinter(pPort->hPrinter);
+ pPort->hPrinter = NULL;
+ }
+
+ // Free virtual FILE: ports which were created in LocalmonOpenPort.
+ if (pPort->PortType == PortType_FILE)
+ {
+ EnterCriticalSection(&pPort->pLocalmon->Section);
+ RemoveEntryList(&pPort->Entry);
+ DllFreeSplMem(pPort);
+ LeaveCriticalSection(&pPort->pLocalmon->Section);
+ }
+
+ SetLastError(ERROR_SUCCESS);
+ return TRUE;
+}
+
+BOOL WINAPI
+LocalmonEndDocPort(HANDLE hPort)
+{
+ PLOCALMON_PORT pPort = (PLOCALMON_PORT)hPort;
+
+ TRACE("LocalmonEndDocPort(%p)\n", hPort);
+
+ // Sanity checks
+ if (!pPort)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ // Ending a document requires starting it first :-P
+ if (pPort->bStartedDoc)
+ {
+ // Close all ports opened in StartDocPort.
+ // That is, all but physical LPT ports (opened in OpenPort).
+ if (pPort->PortType != PortType_PhysicalLPT)
+ _ClosePortHandles(pPort);
+
+ // Report our progress.
+ SetJobW(pPort->hPrinter, pPort->dwJobID, 0, NULL, JOB_CONTROL_SENT_TO_PRINTER);
+
+ // We're done with the printer.
+ ClosePrinter(pPort->hPrinter);
+ pPort->hPrinter = NULL;
+
+ // A new document can now be started again.
+ pPort->bStartedDoc = FALSE;
+ }
+
+ SetLastError(ERROR_SUCCESS);
+ return TRUE;
+}
+
+BOOL WINAPI
+LocalmonEnumPorts(HANDLE hMonitor, PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ DWORD dwErrorCode;
+ PLOCALMON_HANDLE pLocalmon = (PLOCALMON_HANDLE)hMonitor;
+
+ TRACE("LocalmonEnumPorts(%p, %S, %lu, %p, %lu, %p, %p)\n", hMonitor, pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
+
+ // Sanity checks
+ if (!pLocalmon || (cbBuf && !pPorts) || !pcbNeeded || !pcReturned)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ if (Level > 2)
+ {
+ dwErrorCode = ERROR_INVALID_LEVEL;
+ goto Cleanup;
+ }
+
+ // Begin counting.
+ *pcbNeeded = 0;
+ *pcReturned = 0;
+
+ EnterCriticalSection(&pLocalmon->Section);
+
+ // The function behaves differently for each level.
+ if (Level == 1)
+ dwErrorCode = _LocalmonEnumPortsLevel1(pLocalmon, pPorts, cbBuf, pcbNeeded, pcReturned);
+ else if (Level == 2)
+ dwErrorCode = _LocalmonEnumPortsLevel2(pLocalmon, pPorts, cbBuf, pcbNeeded, pcReturned);
+
+ LeaveCriticalSection(&pLocalmon->Section);
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+/*
+ * @name LocalmonGetPrinterDataFromPort
+ *
+ * Performs a DeviceIoControl call for the given port.
+ *
+ * @param hPort
+ * The port to operate on.
+ *
+ * @param ControlID
+ * The dwIoControlCode passed to DeviceIoControl. Must not be zero!
+ *
+ * @param pValueName
+ * This parameter is ignored.
+ *
+ * @param lpInBuffer
+ * The lpInBuffer passed to DeviceIoControl.
+ *
+ * @param cbInBuffer
+ * The nInBufferSize passed to DeviceIoControl.
+ *
+ * @param lpOutBuffer
+ * The lpOutBuffer passed to DeviceIoControl.
+ *
+ * @param cbOutBuffer
+ * The nOutBufferSize passed to DeviceIoControl.
+ *
+ * @param lpcbReturned
+ * The lpBytesReturned passed to DeviceIoControl. Must not be zero!
+ *
+ * @return
+ * TRUE if the DeviceIoControl call was successful, FALSE otherwise.
+ * A more specific error code can be obtained through GetLastError.
+ */
+BOOL WINAPI
+LocalmonGetPrinterDataFromPort(HANDLE hPort, DWORD ControlID, PWSTR pValueName, PWSTR lpInBuffer, DWORD cbInBuffer, PWSTR lpOutBuffer, DWORD cbOutBuffer, PDWORD lpcbReturned)
+{
+ BOOL bOpenedPort = FALSE;
+ DWORD dwErrorCode;
+ PLOCALMON_PORT pPort = (PLOCALMON_PORT)hPort;
+
+ TRACE("LocalmonGetPrinterDataFromPort(%p, %lu, %p, %p, %lu, %p, %lu, %p)\n", hPort, ControlID, pValueName, lpInBuffer, cbInBuffer, lpOutBuffer, cbOutBuffer, lpcbReturned);
+
+ // Sanity checks
+ if (!pPort || !ControlID || !lpcbReturned)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // If this is a serial port, a temporary file handle may be opened.
+ if (pPort->PortType == PortType_PhysicalCOM)
+ {
+ if (_CreateNonspooledPort(pPort))
+ {
+ bOpenedPort = TRUE;
+ }
+ else if (GetLastError() != ERROR_SUCCESS)
+ {
+ dwErrorCode = GetLastError();
+ goto Cleanup;
+ }
+ }
+ else if (pPort->hFile == INVALID_HANDLE_VALUE)
+ {
+ // All other port types need to be opened already.
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // Pass the parameters to DeviceIoControl.
+ if (!DeviceIoControl(pPort->hFile, ControlID, lpInBuffer, cbInBuffer, lpOutBuffer, cbOutBuffer, lpcbReturned, NULL))
+ {
+ dwErrorCode = GetLastError();
+ ERR("DeviceIoControl failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ if (bOpenedPort)
+ _ClosePortHandles(pPort);
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+LocalmonOpenPort(HANDLE hMonitor, PWSTR pName, PHANDLE pHandle)
+{
+ DWORD dwErrorCode;
+ PLOCALMON_HANDLE pLocalmon = (PLOCALMON_HANDLE)hMonitor;
+ PLOCALMON_PORT pPort;
+
+ TRACE("LocalmonOpenPort(%p, %S, %p)\n", hMonitor, pName, pHandle);
+
+ // Sanity checks
+ if (!pLocalmon || !pName || !pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // Check if this is a FILE: port.
+ if (_wcsicmp(pName, L"FILE:") == 0)
+ {
+ // For FILE:, we create a virtual port for each request.
+ pPort = DllAllocSplMem(sizeof(LOCALMON_PORT));
+ pPort->pLocalmon = pLocalmon;
+ pPort->PortType = PortType_FILE;
+ pPort->hFile = INVALID_HANDLE_VALUE;
+
+ // Add it to the list of file ports.
+ EnterCriticalSection(&pLocalmon->Section);
+ InsertTailList(&pLocalmon->FilePorts, &pPort->Entry);
+ }
+ else
+ {
+ EnterCriticalSection(&pLocalmon->Section);
+
+ // Check if the port name is valid.
+ pPort = _FindPort(pLocalmon, pName);
+ if (!pPort)
+ {
+ LeaveCriticalSection(&pLocalmon->Section);
+ dwErrorCode = ERROR_UNKNOWN_PORT;
+ goto Cleanup;
+ }
+
+ // Even if this API is called OpenPort, port file handles aren't always opened here :-P
+ // Windows only does this for physical LPT ports here to enable bidirectional communication with the printer outside of jobs (using ReadPort and WritePort).
+ // The others are only opened per job in StartDocPort.
+ if (_IsLegacyPort(pName, L"LPT"))
+ {
+ // Try to create a NONSPOOLED port and open it.
+ if (_CreateNonspooledPort(pPort))
+ {
+ // Set the transmission retry timeout for the ReadPort and WritePort calls.
+ // This also checks if this port is a physical one.
+ if (_SetTransmissionRetryTimeout(pPort))
+ {
+ // This is definitely a physical LPT port!
+ pPort->PortType = PortType_PhysicalLPT;
+ }
+ else
+ {
+ // This is no physical port, so don't keep its handle open.
+ _ClosePortHandles(pPort);
+ }
+ }
+ else if (GetLastError() != ERROR_SUCCESS)
+ {
+ LeaveCriticalSection(&pLocalmon->Section);
+ dwErrorCode = GetLastError();
+ goto Cleanup;
+ }
+ }
+ else if (_IsLegacyPort(pName, L"COM"))
+ {
+ // COM ports can't be redirected over the network, so this is a physical one.
+ pPort->PortType = PortType_PhysicalCOM;
+ }
+ }
+
+ LeaveCriticalSection(&pLocalmon->Section);
+
+ // Return our fetched LOCALMON_PORT structure in the handle.
+ *pHandle = (PHANDLE)pPort;
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+/*
+ * @name LocalmonSetPortTimeOuts
+ *
+ * Performs a SetCommTimeouts call for the given port.
+ *
+ * @param hPort
+ * The port to operate on.
+ *
+ * @param lpCTO
+ * Pointer to a COMMTIMEOUTS structure that is passed to SetCommTimeouts.
+ *
+ * @param Reserved
+ * Reserved parameter, must be 0.
+ *
+ * @return
+ * TRUE if the SetCommTimeouts call was successful, FALSE otherwise.
+ * A more specific error code can be obtained through GetLastError.
+ */
+BOOL WINAPI
+LocalmonSetPortTimeOuts(HANDLE hPort, LPCOMMTIMEOUTS lpCTO, DWORD Reserved)
+{
+ BOOL bOpenedPort = FALSE;
+ DWORD dwErrorCode;
+ PLOCALMON_PORT pPort = (PLOCALMON_PORT)hPort;
+
+ TRACE("LocalmonSetPortTimeOuts(%p, %p, %lu)\n", hPort, lpCTO, Reserved);
+
+ // Sanity checks
+ if (!pPort || !lpCTO)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // If this is a serial port, a temporary file handle may be opened.
+ if (pPort->PortType == PortType_PhysicalCOM)
+ {
+ if (_CreateNonspooledPort(pPort))
+ {
+ bOpenedPort = TRUE;
+ }
+ else if (GetLastError() != ERROR_SUCCESS)
+ {
+ dwErrorCode = GetLastError();
+ goto Cleanup;
+ }
+ }
+ else if (pPort->hFile == INVALID_HANDLE_VALUE)
+ {
+ // All other port types need to be opened already.
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // Finally pass the parameters to SetCommTimeouts.
+ if (!SetCommTimeouts(pPort->hFile, lpCTO))
+ {
+ dwErrorCode = GetLastError();
+ ERR("SetCommTimeouts failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ if (bOpenedPort)
+ _ClosePortHandles(pPort);
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+LocalmonReadPort(HANDLE hPort, PBYTE pBuffer, DWORD cbBuffer, PDWORD pcbRead)
+{
+ BOOL bOpenedPort = FALSE;
+ DWORD dwErrorCode;
+ PLOCALMON_PORT pPort = (PLOCALMON_PORT)hPort;
+
+ TRACE("LocalmonReadPort(%p, %p, %lu, %p)\n", hPort, pBuffer, cbBuffer, pcbRead);
+
+ // Sanity checks
+ if (!pPort || (cbBuffer && !pBuffer) || !pcbRead)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // Reading is only supported for physical ports.
+ if (pPort->PortType != PortType_PhysicalCOM && pPort->PortType != PortType_PhysicalLPT)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // If this is a serial port, a temporary file handle may be opened.
+ if (pPort->PortType == PortType_PhysicalCOM)
+ {
+ if (_CreateNonspooledPort(pPort))
+ {
+ bOpenedPort = TRUE;
+ }
+ else if (GetLastError() != ERROR_SUCCESS)
+ {
+ dwErrorCode = GetLastError();
+ goto Cleanup;
+ }
+ }
+
+ // Pass the parameters to ReadFile.
+ if (!ReadFile(pPort->hFile, pBuffer, cbBuffer, pcbRead, NULL))
+ {
+ dwErrorCode = GetLastError();
+ ERR("ReadFile failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+Cleanup:
+ if (bOpenedPort)
+ _ClosePortHandles(pPort);
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+LocalmonStartDocPort(HANDLE hPort, PWSTR pPrinterName, DWORD JobId, DWORD Level, PBYTE pDocInfo)
+{
+ DWORD dwErrorCode;
+ PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo; // DOC_INFO_1W is the least common denominator for both DOC_INFO levels.
+ PLOCALMON_PORT pPort = (PLOCALMON_PORT)hPort;
+
+ TRACE("LocalmonStartDocPort(%p, %S, %lu, %lu, %p)\n", hPort, pPrinterName, JobId, Level, pDocInfo);
+
+ // Sanity checks
+ if (!pPort || !pPrinterName || (pPort->PortType == PortType_FILE && (!pDocInfo1 || !pDocInfo1->pOutputFile || !*pDocInfo1->pOutputFile)))
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ if (Level > 2)
+ {
+ dwErrorCode = ERROR_INVALID_LEVEL;
+ goto Cleanup;
+ }
+
+ // Calling StartDocPort multiple times isn't considered a failure, but we don't need to do anything then.
+ if (pPort->bStartedDoc)
+ {
+ dwErrorCode = ERROR_SUCCESS;
+ goto Cleanup;
+ }
+
+ // Open a handle to the given printer for later reporting our progress using SetJobW.
+ if (!OpenPrinterW(pPrinterName, &pPort->hPrinter, NULL))
+ {
+ dwErrorCode = GetLastError();
+ ERR("OpenPrinterW failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // We need our Job ID for SetJobW as well.
+ pPort->dwJobID = JobId;
+
+ // Check the port type.
+ if (pPort->PortType == PortType_PhysicalLPT)
+ {
+ // Update the NONSPOOLED mapping if the port mapping has changed since our OpenPort call.
+ if (!_CreateNonspooledPort(pPort) && GetLastError() != ERROR_SUCCESS)
+ {
+ dwErrorCode = GetLastError();
+ goto Cleanup;
+ }
+
+ // Update the transmission retry timeout as well.
+ _SetTransmissionRetryTimeout(pPort);
+ }
+ else if(pPort->PortType == PortType_FILE)
+ {
+ // This is a FILE: port. Open the output file given in the Document Info.
+ pPort->hFile = CreateFileW(pDocInfo1->pOutputFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
+ if (pPort->hFile == INVALID_HANDLE_VALUE)
+ {
+ dwErrorCode = GetLastError();
+ goto Cleanup;
+ }
+ }
+ else
+ {
+ // This can be:
+ // - a physical COM port
+ // - a non-physical LPT port (e.g. with "net use LPT1 ...")
+ // - any other port (e.g. a file or a shared printer installed as a local port)
+ //
+ // For all these cases, we try to create a NONSPOOLED port per job.
+ // If _CreateNonspooledPort reports that no NONSPOOLED port is necessary, we can just open the port name.
+ if (!_CreateNonspooledPort(pPort))
+ {
+ if (GetLastError() == ERROR_SUCCESS)
+ {
+ pPort->hFile = CreateFileW(pPort->pwszPortName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
+ if (pPort->hFile == INVALID_HANDLE_VALUE)
+ {
+ dwErrorCode = GetLastError();
+ goto Cleanup;
+ }
+ }
+ else
+ {
+ dwErrorCode = GetLastError();
+ goto Cleanup;
+ }
+ }
+ }
+
+ // We were successful!
+ dwErrorCode = ERROR_SUCCESS;
+ pPort->bStartedDoc = TRUE;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+LocalmonWritePort(HANDLE hPort, PBYTE pBuffer, DWORD cbBuf, PDWORD pcbWritten)
+{
+ BOOL bOpenedPort = FALSE;
+ DWORD dwErrorCode;
+ PLOCALMON_PORT pPort = (PLOCALMON_PORT)hPort;
+
+ TRACE("LocalmonWritePort(%p, %p, %lu, %p)\n", hPort, pBuffer, cbBuf, pcbWritten);
+
+ // Sanity checks
+ if (!pPort || (cbBuf && !pBuffer) || !pcbWritten)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // If this is a serial port, a temporary file handle may be opened.
+ if (pPort->PortType == PortType_PhysicalCOM)
+ {
+ if (_CreateNonspooledPort(pPort))
+ {
+ bOpenedPort = TRUE;
+ }
+ else if (GetLastError() != ERROR_SUCCESS)
+ {
+ dwErrorCode = GetLastError();
+ goto Cleanup;
+ }
+ }
+ else if (pPort->hFile == INVALID_HANDLE_VALUE)
+ {
+ // All other port types need to be opened already.
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // Pass the parameters to WriteFile.
+ if (!WriteFile(pPort->hFile, pBuffer, cbBuf, pcbWritten, NULL))
+ {
+ dwErrorCode = GetLastError();
+ ERR("WriteFile failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // If something was written down, we consider that a success, otherwise it's a timeout.
+ if (*pcbWritten)
+ dwErrorCode = ERROR_SUCCESS;
+ else
+ dwErrorCode = ERROR_TIMEOUT;
+
+Cleanup:
+ if (bOpenedPort)
+ _ClosePortHandles(pPort);
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Port Monitor
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Precompiled Header for all source files
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#ifndef _PRECOMP_H
+#define _PRECOMP_H
+
+#define WIN32_NO_STATUS
+#include <stdlib.h>
+
+#include <windef.h>
+#include <winbase.h>
+#include <wingdi.h>
+#include <winreg.h>
+#include <winspool.h>
+#include <winsplp.h>
+#include <winuser.h>
+#include <ndk/rtlfuncs.h>
+
+#include <spoolss.h>
+
+#include <wine/debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(localmon);
+
+#include "resource.h"
+
+// Structures
+/**
+ * Describes the monitor handle returned by InitializePrintMonitor2.
+ * Manages all available ports in this instance.
+ */
+typedef struct _LOCALMON_HANDLE
+{
+ CRITICAL_SECTION Section; /** Critical Section for modifying or reading the ports. */
+ LIST_ENTRY FilePorts; /** Ports created when a document is printed on FILE: and the user entered a file name. */
+ LIST_ENTRY RegistryPorts; /** Valid ports loaded from the local registry. */
+ LIST_ENTRY XcvHandles; /** Xcv handles created with LocalmonXcvOpenPort. */
+}
+LOCALMON_HANDLE, *PLOCALMON_HANDLE;
+
+/**
+ * Describes the port handle returned by LocalmonOpenPort.
+ * Manages a legacy port (COM/LPT) or virtual FILE: port for printing as well as its associated printer and job.
+ */
+typedef struct _LOCALMON_PORT
+{
+ LIST_ENTRY Entry;
+ enum {
+ PortType_Other = 0, /** Any port that doesn't belong into the other categories (default). */
+ PortType_FILE, /** A port created when a document is printed on FILE: and the user entered a file name. */
+ PortType_PhysicalCOM, /** A physical serial port (COM) */
+ PortType_PhysicalLPT /** A physical parallel port (LPT) */
+ }
+ PortType;
+ BOOL bStartedDoc; /** Whether a document has been started with StartDocPort. */
+ DWORD dwJobID; /** ID of the printing job we are processing (for later reporting progress using SetJobW). */
+ HANDLE hFile; /** Handle to the opened port or INVALID_HANDLE_VALUE if it isn't currently opened. */
+ HANDLE hPrinter; /** Handle to the printer for the job on this port (for using SetJobW). */
+ PLOCALMON_HANDLE pLocalmon; /** Pointer to the parent LOCALMON_HANDLE structure. */
+ PWSTR pwszMapping; /** The current mapping of the DOS Device corresponding to this port at the time _CreateNonspooledPort has been called. */
+ PWSTR pwszPortName; /** The name of this port including the trailing colon. Empty for virtual file ports. */
+}
+LOCALMON_PORT, *PLOCALMON_PORT;
+
+/**
+ * Describes the Xcv handle returned by LocalmonXcvOpenPort.
+ * Manages the required data for the Xcv* calls.
+ */
+typedef struct _LOCALMON_XCV
+{
+ LIST_ENTRY Entry;
+ ACCESS_MASK GrantedAccess;
+ PLOCALMON_HANDLE pLocalmon;
+ PWSTR pwszObject;
+}
+LOCALMON_XCV, *PLOCALMON_XCV;
+
+// main.c
+extern DWORD cbLocalMonitor;
+extern DWORD cbLocalPort;
+extern PCWSTR pwszLocalMonitor;
+extern PCWSTR pwszLocalPort;
+void WINAPI LocalmonShutdown(HANDLE hMonitor);
+
+// ports.c
+BOOL WINAPI LocalmonClosePort(HANDLE hPort);
+BOOL WINAPI LocalmonEndDocPort(HANDLE hPort);
+BOOL WINAPI LocalmonEnumPorts(HANDLE hMonitor, PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned);
+BOOL WINAPI LocalmonGetPrinterDataFromPort(HANDLE hPort, DWORD ControlID, PWSTR pValueName, PWSTR lpInBuffer, DWORD cbInBuffer, PWSTR lpOutBuffer, DWORD cbOutBuffer, PDWORD lpcbReturned);
+BOOL WINAPI LocalmonOpenPort(HANDLE hMonitor, PWSTR pName, PHANDLE pHandle);
+BOOL WINAPI LocalmonReadPort(HANDLE hPort, PBYTE pBuffer, DWORD cbBuffer, PDWORD pcbRead);
+BOOL WINAPI LocalmonSetPortTimeOuts(HANDLE hPort, LPCOMMTIMEOUTS lpCTO, DWORD Reserved);
+BOOL WINAPI LocalmonStartDocPort(HANDLE hPort, PWSTR pPrinterName, DWORD JobId, DWORD Level, PBYTE pDocInfo);
+BOOL WINAPI LocalmonWritePort(HANDLE hPort, PBYTE pBuffer, DWORD cbBuf, PDWORD pcbWritten);
+
+// tools.c
+BOOL DoesPortExist(PCWSTR pwszPortName);
+DWORD GetLPTTransmissionRetryTimeout();
+DWORD GetPortNameWithoutColon(PCWSTR pwszPortName, PWSTR* ppwszPortNameWithoutColon);
+
+// xcv.c
+BOOL WINAPI LocalmonXcvClosePort(HANDLE hXcv);
+DWORD WINAPI LocalmonXcvDataPort(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded);
+BOOL WINAPI LocalmonXcvOpenPort(HANDLE hMonitor, PCWSTR pszObject, ACCESS_MASK GrantedAccess, PHANDLE phXcv);
+
+#endif
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Port Monitor
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Resource IDs
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#pragma once
+
+#define IDS_LOCAL_PORT 500
+#define IDS_LOCAL_MONITOR 507
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Port Monitor
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Various support functions shared by multiple files
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+/**
+ * @name DoesPortExist
+ *
+ * Checks all Port Monitors installed on the local system to find out if a given port already exists.
+ *
+ * @param pwszPortName
+ * The port name to check.
+ *
+ * @return
+ * TRUE if a port with that name already exists on the local system.
+ * If the return value is FALSE, either the port doesn't exist or an error occurred.
+ * Use GetLastError in this case to check the error case.
+ */
+BOOL
+DoesPortExist(PCWSTR pwszPortName)
+{
+ BOOL bReturnValue = FALSE;
+ DWORD cbNeeded;
+ DWORD dwErrorCode;
+ DWORD dwReturned;
+ DWORD i;
+ PPORT_INFO_1W p;
+ PPORT_INFO_1W pPortInfo1 = NULL;
+
+ // Determine the required buffer size.
+ EnumPortsW(NULL, 1, NULL, 0, &cbNeeded, &dwReturned);
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+ dwErrorCode = GetLastError();
+ ERR("EnumPortsW failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Allocate a buffer large enough.
+ pPortInfo1 = DllAllocSplMem(cbNeeded);
+ if (!pPortInfo1)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Now get the actual port information.
+ if (!EnumPortsW(NULL, 1, (PBYTE)pPortInfo1, cbNeeded, &cbNeeded, &dwReturned))
+ {
+ dwErrorCode = GetLastError();
+ ERR("EnumPortsW failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // We were successful! Loop through all returned ports.
+ dwErrorCode = ERROR_SUCCESS;
+ p = pPortInfo1;
+
+ for (i = 0; i < dwReturned; i++)
+ {
+ // Check if this existing port matches our queried one.
+ if (wcsicmp(p->pName, pwszPortName) == 0)
+ {
+ bReturnValue = TRUE;
+ goto Cleanup;
+ }
+
+ p++;
+ }
+
+Cleanup:
+ if (pPortInfo1)
+ DllFreeSplMem(pPortInfo1);
+
+ SetLastError(dwErrorCode);
+ return bReturnValue;
+}
+
+DWORD
+GetLPTTransmissionRetryTimeout()
+{
+ DWORD cbBuffer;
+ DWORD dwReturnValue = 90; // Use 90 seconds as default if we fail to read from registry.
+ HKEY hKey;
+ LSTATUS lStatus;
+
+ // Six digits is the most you can enter in Windows' LocalUI.dll.
+ // Larger values make it crash, so introduce a limit here.
+ WCHAR wszBuffer[6 + 1];
+
+ // Open the key where our value is stored.
+ lStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows", 0, KEY_READ, &hKey);
+ if (lStatus != ERROR_SUCCESS)
+ {
+ ERR("RegOpenKeyExW failed with status %ld!\n", lStatus);
+ goto Cleanup;
+ }
+
+ // Query the value.
+ cbBuffer = sizeof(wszBuffer);
+ lStatus = RegQueryValueExW(hKey, L"TransmissionRetryTimeout", NULL, NULL, (PBYTE)wszBuffer, &cbBuffer);
+ if (lStatus != ERROR_SUCCESS)
+ {
+ ERR("RegQueryValueExW failed with status %ld!\n", lStatus);
+ goto Cleanup;
+ }
+
+ // Return it converted to a DWORD.
+ dwReturnValue = wcstoul(wszBuffer, NULL, 10);
+
+Cleanup:
+ if (hKey)
+ RegCloseKey(hKey);
+
+ return dwReturnValue;
+}
+
+/**
+ * @name GetPortNameWithoutColon
+ *
+ * Most of the time, we operate on port names with a trailing colon. But some functions require the name without the trailing colon.
+ * This function checks if the port has a trailing colon and if so, it returns the port name without the colon.
+ *
+ * @param pwszPortName
+ * The port name with colon
+ *
+ * @param ppwszPortNameWithoutColon
+ * Pointer to a PWSTR that will contain the port name without colon.
+ * You have to free this buffer using DllFreeSplMem.
+ *
+ * @return
+ * ERROR_SUCCESS if the port name without colon was successfully copied into the buffer.
+ * ERROR_INVALID_PARAMETER if this port name has no trailing colon.
+ * ERROR_NOT_ENOUGH_MEMORY if memory allocation failed.
+ */
+DWORD
+GetPortNameWithoutColon(PCWSTR pwszPortName, PWSTR* ppwszPortNameWithoutColon)
+{
+ DWORD cchPortNameWithoutColon;
+
+ // Compute the string length of pwszPortNameWithoutColon.
+ cchPortNameWithoutColon = wcslen(pwszPortName) - 1;
+
+ // Check if pwszPortName really has a colon as the last character.
+ if (pwszPortName[cchPortNameWithoutColon] != L':')
+ return ERROR_INVALID_PARAMETER;
+
+ // Allocate the output buffer.
+ *ppwszPortNameWithoutColon = DllAllocSplMem((cchPortNameWithoutColon + 1) * sizeof(WCHAR));
+ if (!*ppwszPortNameWithoutColon)
+ {
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Copy the port name without colon into the buffer.
+ // The buffer is already zero-initialized, so no additional null-termination is necessary.
+ CopyMemory(*ppwszPortNameWithoutColon, pwszPortName, cchPortNameWithoutColon * sizeof(WCHAR));
+
+ return ERROR_SUCCESS;
+}
--- /dev/null
+
+add_definitions(-D__WINESRC__)
+include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine)
+spec2def(localui.dll localui.spec)
+
+list(APPEND SOURCE
+ localui.c
+ ${CMAKE_CURRENT_BINARY_DIR}/localui.def)
+
+add_library(localui SHARED ${SOURCE} localui.rc)
+set_module_type(localui win32dll)
+target_link_libraries(localui wine)
+add_importlibs(localui winspool user32 msvcrt kernel32 ntdll)
+add_cd_file(TARGET localui DESTINATION reactos/system32 FOR all)
--- /dev/null
+/*
+ * Danish resources for localui
+ *
+ * Copyright 2008 Jens Albretsen <jens@albretsen.dk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+LANGUAGE LANG_DANISH, SUBLANG_DEFAULT
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Lokal port"
+ IDS_INVALIDNAME "'%s' er ikke et gyldigt port navn"
+ IDS_PORTEXISTS "Porten %s findes allerede"
+ IDS_NOTHINGTOCONFIG "Denne port har ingen indstillinger"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Opret en lokal port"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Skriv navnet på den nye port:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Annuller", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Opsæt LPT port"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Timeout (sekunder)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "&Transmission retry:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "OK", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Annuller", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * German resources for localui
+ *
+ * Copyright 2007 Detlef Riekenberg
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+#pragma code_page(65001)
+
+LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Lokaler Anschluss"
+ IDS_INVALIDNAME "'%s' ist kein gültiger Anschlussname"
+ IDS_PORTEXISTS "Der Anschluss %s existiert bereits"
+ IDS_NOTHINGTOCONFIG "Dieser Anschluss besitzt keine zu konfigurierenden Optionen"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Lokalen Anschluss hinzufügen"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Lokaler Anschluss, der hinzugefügt werden soll:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Abbrechen", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "LPT-Anschluss konfigurieren"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Zeitüberschreitung (Sekunden)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "Ü&bertragung wiederholen:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "OK", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Abbrechen", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * English resources for localui
+ *
+ * Copyright 2007 Detlef Riekenberg
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Local Port"
+ IDS_INVALIDNAME "'%s' is not a valid port name"
+ IDS_PORTEXISTS "Port %s already exists"
+ IDS_NOTHINGTOCONFIG "This port has no options to configure"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Add a Local Port"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Enter the port name to add:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Cancel", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Configure LPT Port"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Timeout (seconds)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "&Transmission Retry:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "OK", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Cancel", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * Spanish resources for localui
+ *
+ * Copyright 2010 José Rostagno
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+#pragma code_page(65001)
+
+LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Puerto local"
+ IDS_INVALIDNAME "'%s' no es un nombre de puerto válido"
+ IDS_PORTEXISTS "El puerto %s ya existe"
+ IDS_NOTHINGTOCONFIG "Este puerto no tiene opciones para configurar"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Agregar un puerto local"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Ingrese el nombre del puerto a agregar:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "Aceptar", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Cancelar", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Configurar puerto LPT"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Tiempo de espera (segundos)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "&Reintentar transmisión:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "Aceptar", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Cancelar", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * French resources for localui
+ *
+ * Copyright 2007 Jonathan Ernst
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+#pragma code_page(65001)
+
+LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Port local"
+ IDS_INVALIDNAME "« %s » n'est pas un nom de port valide"
+ IDS_PORTEXISTS "Le port %s existe déjà"
+ IDS_NOTHINGTOCONFIG "Ce port n'a pas d'options de configuration"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Ajouter un port local"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Saisisser le nom du port à ajouter :", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Annuler", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Configurer un port LPT"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Délai (en secondes)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "&Essais de retransmission :", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "OK", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Annuler", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * Hebrew resources for localui
+ *
+ * Copyright 2007 Detlef Riekenberg
+ *
+ * Translated by Baruch Rutman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+LANGUAGE LANG_HEBREW, SUBLANG_DEFAULT
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "יציאה מקומית"
+ IDS_INVALIDNAME "'%s' אינו שם יציאה חוקי"
+ IDS_PORTEXISTS "יציאה %s כבר קיימת"
+ IDS_NOTHINGTOCONFIG "ליציאה הזו אין אפשרויות להגדיר"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "הוסף יציאה מקומית"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "הזן את שם היציאה כדי להוסיפה:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "אישור", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "ביטול", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "הגדרת יציאת LPT"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "פסק זמן (שניות)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "ניסיון שידור חוזר:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "אישור", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "ביטול", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * Hungarian resources for localui
+ *
+ * Copyright 2010 Andras Kovacs
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+/* UTF-8 */
+#pragma code_page(65001)
+
+LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Helyi port"
+ IDS_INVALIDNAME "A(z) '%s' nem egy érvényes portnév"
+ IDS_PORTEXISTS "A port: %s már létezik"
+ IDS_NOTHINGTOCONFIG "Ennek a portnak nincsenek beállítható tulajdonságai"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Helyi port hozzáadása"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Adja meg a &hozzáadni kívánt port nevét:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Mégse", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "LPT port beállítása"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Időtúllépés (másodperc)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "Á&tviteli újrapróbálkozás:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "OK", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Mégse", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * Italian resources for localui
+ *
+ * Copyright 2007 Detlef Riekenberg
+ * Copyright 2010 Luca Bennati
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+/* UTF-8 */
+#pragma code_page(65001)
+
+LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Porta locale"
+ IDS_INVALIDNAME "'%s' non è un nome di porta valido"
+ IDS_PORTEXISTS "La porta %s già esiste"
+ IDS_NOTHINGTOCONFIG "Questa porta non ha opzioni da configurare"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Aggiungi una porta locale"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Inserisci il nome della porta da aggiungere:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Annulla", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Configura la porta LPT"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Timeout (secondi)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "&Tentativi di trasmissione:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "OK", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Annulla", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * Japanese resources for localui
+ *
+ * Copyright 2007 Detlef Riekenberg
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+/* UTF-8 */
+#pragma code_page(65001)
+
+LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "ローカル ポート"
+ IDS_INVALIDNAME "'%s' はポート名として正しくありません"
+ IDS_PORTEXISTS "ポート %s はすでに存在します"
+ IDS_NOTHINGTOCONFIG "このポートには設定項目がありません"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "ローカル ポートの追加"
+FONT 9, "MS UI Gothic"
+BEGIN
+ LTEXT "追加するポートの名前(&E):", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "キャンセル", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "プリンタ ポートの設定"
+FONT 9, "MS UI Gothic"
+BEGIN
+ GROUPBOX "タイムアウト (秒)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "再送回数(&T):", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "OK", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "キャンセル", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * Korean resources for localui
+ *
+ * Copyright 2007 Detlef Riekenberg
+ * Copyright 2007 YunSong Hwang(황윤성)(hys545@dreamwiz.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "지역 포트"
+ IDS_INVALIDNAME "'%s'는 올바른 포트 이름이 아닙니다"
+ IDS_PORTEXISTS "포트 %s는 이미 존재합니다"
+ IDS_NOTHINGTOCONFIG "이 포트는 설정할 옵션이 없습니다"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "지역 포트 더하기"
+FONT 9, "MS Shell Dlg"
+BEGIN
+ LTEXT "더할 포트 이름 입력(&E):", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "확인", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "취소", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "LPT 포트 설정"
+FONT 9, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "시간초과(초)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "재 전송 횟수(&T):", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "확인", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "취소", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * Lithuanian resources for localui
+ *
+ * Copyright 2009 Aurimas Fišeras <aurimas@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+/* UTF-8 */
+#pragma code_page(65001)
+
+LANGUAGE LANG_LITHUANIAN, SUBLANG_NEUTRAL
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Vietinis prievadas"
+ IDS_INVALIDNAME "„%s“ yra netinkamas prievado vardas"
+ IDS_PORTEXISTS "Prievadas %s jau egzistuoja"
+ IDS_NOTHINGTOCONFIG "Šis prievadas neturi parinkčių konfigūravimui"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Pridėti vietinį prievadą"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Įveskite pridedamo prievado vardą:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "Gerai", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Atsisakyti", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Konfigūruoti LPT prievadą"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Laukimo laikas (sekundėmis)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "&Perdavimo pakartojimas:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "Gerai", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Atsisakyti", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * Dutch resources for localui
+ *
+ * Copyright 2008 Frans Kool
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+LANGUAGE LANG_DUTCH, SUBLANG_NEUTRAL
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Lokale Poort"
+ IDS_INVALIDNAME "'%s' is geen valide poort naam"
+ IDS_PORTEXISTS "Poort %s bestaat reeds"
+ IDS_NOTHINGTOCONFIG "Deze poort heeft geen opties om in te stellen"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Voeg een Lokale Poort toe"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Voer de toe te voegen poort naam in:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Annuleren", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Configureer LPT Poort"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Timeout (seconden)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "&Transmissie Herstart:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "OK", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Annuleren", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * Norwegian Bokmål resources for localui
+ *
+ * Copyright 2007 Alexander N. Sørnes <alex@thehandofagony.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Lokal port"
+ IDS_INVALIDNAME "«%s» er ikke et gyldig portnavn"
+ IDS_PORTEXISTS "Porten %s finnes allerede"
+ IDS_NOTHINGTOCONFIG "Denne porten har ingen innstillinger"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Legg til en lokal port"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Skriv inn navn&et på den nye porten:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Avbryt", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Oppsett av LPT-port"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Tidsavbrudd (sekunder)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "Prøv å sende på nyt&t:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "OK", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Avbryt", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * Polish resources for localui
+ *
+ * Copyright 2007 Detlef Riekenberg
+ * Copyright 2007 Mikolaj Zalewski
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+LANGUAGE LANG_POLISH, SUBLANG_DEFAULT
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Port lokalny"
+ IDS_INVALIDNAME "'%s' nie jest poprawną nazwą portu"
+ IDS_PORTEXISTS "Port %s już istnieje"
+ IDS_NOTHINGTOCONFIG "Ten port nie ma opcji do skonfigurowania"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Dodaj port lokalny"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Nazwa nowego portu:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "&OK", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "&Anuluj", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Konfiguracja portu LPT"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Czasy oczekiwania (sekundy)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "&Ponowienie transmisji:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "&OK", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "&Anuluj", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * Portuguese resources for localui
+ *
+ * Copyright 2008 Ricardo Filipe
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+LANGUAGE LANG_PORTUGUESE, SUBLANG_NEUTRAL
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Porta Local"
+ IDS_INVALIDNAME "'%s' não é um nome de porta válido"
+ IDS_PORTEXISTS "Porta %s já existe"
+ IDS_NOTHINGTOCONFIG "Esta porta não possui opções de configuração"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Adicionar uma porta local"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Introduza o nome da porta a adicionar:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Cancelar", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Configurar porta LPT"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Tempo expirado (segundos)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "&Recomeço da transmissão:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "OK", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Cancelar", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * Copyright 2007 Detlef Riekenberg
+ * Copyright 2008 Michael Stefaniuc
+ * 2011 Fulea Ștefan
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+#pragma code_page(65001)
+
+LANGUAGE LANG_ROMANIAN, SUBLANG_NEUTRAL
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Port local"
+ IDS_INVALIDNAME "„%s” nu este un nume valid de port"
+ IDS_PORTEXISTS "Portul %s existsă deja"
+ IDS_NOTHINGTOCONFIG "Acest port nu are opțiuni de configurat"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Adaugare port local"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "N&umele portului adăugat:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "Con&firmă", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "A&nulează", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Configurare port LPT"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Temporizare (secunde)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "&Reîncearcă transmisia:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "Con&firmă", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "A&nulează", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * Russian resources for localui
+ *
+ * Copyright 2008 Vitaliy Margolen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+/* UTF-8 */
+#pragma code_page(65001)
+
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Локальный порт"
+ IDS_INVALIDNAME "Неправильное название порта '%s'"
+ IDS_PORTEXISTS "Порт '%s' уже существует"
+ IDS_NOTHINGTOCONFIG "Этот порт не имеет настроек"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Добавить локальный порт"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Введите &название локального порта:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Отменить", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Установки параллельного порта"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Тайм-аут (секунд)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "&Попыток пересылки:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "OK", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Отмена", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * Slovenian resources for localui
+ *
+ * Copyright 2008 Rok Mandeljc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+#pragma code_page(65001)
+
+LANGUAGE LANG_SLOVENIAN, SUBLANG_DEFAULT
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Lokalna vrata"
+ IDS_INVALIDNAME "'%s' ni veljavno ime vrat"
+ IDS_PORTEXISTS "Vrata z imenom %s že obstajajo"
+ IDS_NOTHINGTOCONFIG "Ta vrata nimajo možnosti nastavitve"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Dodaj lokalna vrata"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Ime vrat:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "V redu", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Prekliči", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Nastavitev LPT vrat"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Časovna omejitev (seconds)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "&Ponoven poskus prenosa:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "V redu", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Prekliči", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * English resources for localui
+ *
+ * Copyright 2007 Detlef Riekenberg
+ * Translation: Ardit Dani (Albanian Translation Resource File)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+LANGUAGE LANG_ALBANIAN, SUBLANG_NEUTRAL
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Porti Vendor"
+ IDS_INVALIDNAME "'%s' nuk është emer e vlefshem porti"
+ IDS_PORTEXISTS "Porti %s ekziston"
+ IDS_NOTHINGTOCONFIG "Ky port ska opsione për të konfiguruar"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Shto një Port Vendor"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Fut emrin e Portit për të shtuar:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Anulo", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Konfiguro Portin LPT"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Timeout (sekonda)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "&Transmission Riprove:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "OK", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Anulo", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * Swedish resources for localui
+ *
+ * Copyright 2007 Daniel Nylander
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+LANGUAGE LANG_SWEDISH, SUBLANG_NEUTRAL
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Lokal port"
+ IDS_INVALIDNAME "'%s' är inte ett giltigt portnamn"
+ IDS_PORTEXISTS "Porten %s finns redan"
+ IDS_NOTHINGTOCONFIG "Denna port har inga alternativ att konfigurera"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Lägg till en lokal port"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Ange portnamnet att lägga till:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Avbryt", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Konfigurera LPT-port"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Tidsgräns (sekunder)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "Öve&rföringsförsök:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "OK", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Avbryt", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * Turkish resources for localui
+ *
+ * Copyright: 2014 Erdem Ersoy (eersoy93) (erdemersoy@live.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Yerli Giriş"
+ IDS_INVALIDNAME """%s"", geçerli bir giriş adı değil."
+ IDS_PORTEXISTS "%s girişi önceden var."
+ IDS_NOTHINGTOCONFIG "Bu girişin yapılandırmak için seçeneği yok."
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Bir Yerli Giriş Ekle"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Eklemek için giriş adını giriniz:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "Tamam", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "İptal", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "LPT Girişini Yapılandır"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Süre Aşımı (Sâniye)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "&İletimi Yeniden Dene:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "Tamam", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "İptal", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * Ukrainian resources for localui
+ *
+ * Copyright 2010 Igor Paliychuk
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+/* UTF-8 */
+#pragma code_page(65001)
+
+LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "Локальний порт"
+ IDS_INVALIDNAME "'%s' не дійсна назва порту"
+ IDS_PORTEXISTS "Порт '%s' вже існує"
+ IDS_NOTHINGTOCONFIG "Цей порт не має налаштувань"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Додати локальний порт"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Введіть &назву локального порта:", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Скасувати", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Налаштування LPT порта"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Тайм-аут (секунд)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "&Спроб пересилання:", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "OK", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "Скасувати", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * localui (Simplified and Traditional Chinese Resources)
+ *
+ * Copyright 2008 Hongbo Ni <hongbo.at.njstar.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+/* Chinese text is encoded in UTF-8 */
+#pragma code_page(65001)
+
+LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "本地端口"
+ IDS_INVALIDNAME "'%s' 不是有效的端口名称"
+ IDS_PORTEXISTS "端口 %s 已经存在"
+ IDS_NOTHINGTOCONFIG "这个端口没有可设置选项"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "添加本地端口"
+FONT 9, "MS Shell Dlg"
+BEGIN
+ LTEXT "添加本地端口名称(&E):", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "确定", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "取消", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "设置打印端口"
+FONT 9, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "超时(秒)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "重试通讯(&T):", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "确定", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "取消", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
+
+LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL
+
+STRINGTABLE
+{
+ IDS_LOCALPORT "本地端口"
+ IDS_INVALIDNAME "'%s' 不是有效的端口名稱"
+ IDS_PORTEXISTS "端口 %s 已經存在"
+ IDS_NOTHINGTOCONFIG "這個端口沒有可設定選項"
+}
+
+ADDPORT_DIALOG DIALOGEX 6, 18, 245, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "添加本地端口"
+FONT 9, "MS Shell Dlg"
+BEGIN
+ LTEXT "添加本地端口名稱(&E):", -1, 7, 13, 194, 13, WS_VISIBLE
+ EDITTEXT ADDPORT_EDIT, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "確定", IDOK, 188, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "取消", IDCANCEL, 188, 27, 50, 14, WS_VISIBLE
+END
+
+
+LPTCONFIG_DIALOG DIALOGEX 6, 18, 220, 47
+STYLE DS_SHELLFONT | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "設定列印端口"
+FONT 9, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "超時(秒)", LPTCONFIG_GROUP, 6, 6, 150, 35, BS_GROUPBOX
+ LTEXT "重試通訊(&T):", -1, 14, 22, 90, 13, WS_VISIBLE
+ EDITTEXT LPTCONFIG_EDIT, 112, 20, 32, 13, WS_VISIBLE | ES_NUMBER
+ DEFPUSHBUTTON "確定", IDOK, 164, 10, 50, 14, WS_VISIBLE
+ PUSHBUTTON "取消", IDCANCEL, 164, 27, 50, 14, WS_VISIBLE
+END
--- /dev/null
+/*
+ * Implementation of the Local Printmonitor User Interface
+ *
+ * Copyright 2007 Detlef Riekenberg
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define WIN32_NO_STATUS
+
+#include <stdarg.h>
+
+#define NONAMELESSUNION
+
+#include <windef.h>
+#include <winbase.h>
+#include <wingdi.h>
+#include <winreg.h>
+#include <winuser.h>
+
+#include <winspool.h>
+#include <ddk/winsplp.h>
+
+#include <wine/debug.h>
+#include <wine/unicode.h>
+#include "localui.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(localui);
+
+/*****************************************************/
+
+static HINSTANCE LOCALUI_hInstance;
+
+static const WCHAR cmd_AddPortW[] = {'A','d','d','P','o','r','t',0};
+static const WCHAR cmd_ConfigureLPTPortCommandOKW[] = {'C','o','n','f','i','g','u','r','e',
+ 'L','P','T','P','o','r','t',
+ 'C','o','m','m','a','n','d','O','K',0};
+static const WCHAR cmd_DeletePortW[] = {'D','e','l','e','t','e','P','o','r','t',0};
+static const WCHAR cmd_GetDefaultCommConfigW[] = {'G','e','t',
+ 'D','e','f','a','u','l','t',
+ 'C','o','m','m','C','o','n','f','i','g',0};
+static const WCHAR cmd_GetTransmissionRetryTimeoutW[] = {'G','e','t',
+ 'T','r','a','n','s','m','i','s','s','i','o','n',
+ 'R','e','t','r','y','T','i','m','e','o','u','t',0};
+static const WCHAR cmd_PortIsValidW[] = {'P','o','r','t','I','s','V','a','l','i','d',0};
+static const WCHAR cmd_SetDefaultCommConfigW[] = {'S','e','t',
+ 'D','e','f','a','u','l','t',
+ 'C','o','m','m','C','o','n','f','i','g',0};
+
+static const WCHAR fmt_uW[] = {'%','u',0};
+static const WCHAR portname_LPT[] = {'L','P','T',0};
+static const WCHAR portname_COM[] = {'C','O','M',0};
+static const WCHAR portname_FILE[] = {'F','I','L','E',':',0};
+static const WCHAR portname_CUPS[] = {'C','U','P','S',':',0};
+static const WCHAR portname_LPR[] = {'L','P','R',':',0};
+
+static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
+static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
+
+/*****************************************************/
+
+typedef struct tag_addportui_t {
+ LPWSTR portname;
+ HANDLE hXcv;
+} addportui_t;
+
+typedef struct tag_lptconfig_t {
+ HANDLE hXcv;
+ DWORD value;
+} lptconfig_t;
+
+
+static INT_PTR CALLBACK dlgproc_lptconfig(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+
+/*****************************************************
+ * strdupWW [internal]
+ */
+
+static LPWSTR strdupWW(LPCWSTR pPrefix, LPCWSTR pSuffix)
+{
+ LPWSTR ptr;
+ DWORD len;
+
+ len = lstrlenW(pPrefix) + (pSuffix ? lstrlenW(pSuffix) : 0) + 1;
+ ptr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (ptr) {
+ lstrcpyW(ptr, pPrefix);
+ if (pSuffix) lstrcatW(ptr, pSuffix);
+ }
+ return ptr;
+}
+
+/*****************************************************
+ * dlg_configure_com [internal]
+ *
+ */
+
+static BOOL dlg_configure_com(HANDLE hXcv, HWND hWnd, PCWSTR pPortName)
+{
+ COMMCONFIG cfg;
+ LPWSTR shortname;
+ DWORD status;
+ DWORD dummy;
+ DWORD len;
+ BOOL res;
+
+ /* strip the colon (pPortName is never empty here) */
+ len = lstrlenW(pPortName);
+ shortname = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (shortname) {
+ memcpy(shortname, pPortName, (len -1) * sizeof(WCHAR));
+ shortname[len-1] = '\0';
+
+ /* get current settings */
+ len = FIELD_OFFSET(COMMCONFIG, wcProviderData[1]);
+ status = ERROR_SUCCESS;
+ res = XcvDataW( hXcv, cmd_GetDefaultCommConfigW,
+ (PBYTE) shortname,
+ (lstrlenW(shortname) +1) * sizeof(WCHAR),
+ (PBYTE) &cfg, len, &len, &status);
+
+ if (res && (status == ERROR_SUCCESS)) {
+ /* display the Dialog */
+ res = CommConfigDialogW(pPortName, hWnd, &cfg);
+ if (res) {
+ status = ERROR_SUCCESS;
+ /* set new settings */
+ res = XcvDataW(hXcv, cmd_SetDefaultCommConfigW,
+ (PBYTE) &cfg, len,
+ (PBYTE) &dummy, 0, &len, &status);
+ }
+ }
+ HeapFree(GetProcessHeap(), 0, shortname);
+ return res;
+ }
+ return FALSE;
+}
+
+
+/*****************************************************
+ * dlg_configure_lpt [internal]
+ *
+ */
+
+static BOOL dlg_configure_lpt(HANDLE hXcv, HWND hWnd)
+{
+ lptconfig_t data;
+ BOOL res;
+
+
+ data.hXcv = hXcv;
+
+ res = DialogBoxParamW(LOCALUI_hInstance, MAKEINTRESOURCEW(LPTCONFIG_DIALOG), hWnd,
+ dlgproc_lptconfig, (LPARAM) &data);
+
+ TRACE("got %u with %u\n", res, GetLastError());
+
+ if (!res) SetLastError(ERROR_CANCELLED);
+ return res;
+}
+
+/******************************************************************
+ * dlg_port_already_exists [internal]
+ */
+
+static void dlg_port_already_exists(HWND hWnd, LPCWSTR portname)
+{
+ WCHAR res_PortW[IDS_LOCALPORT_MAXLEN];
+ WCHAR res_PortExistsW[IDS_PORTEXISTS_MAXLEN];
+ LPWSTR message;
+ DWORD len;
+
+ res_PortW[0] = '\0';
+ res_PortExistsW[0] = '\0';
+ LoadStringW(LOCALUI_hInstance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN);
+ LoadStringW(LOCALUI_hInstance, IDS_PORTEXISTS, res_PortExistsW, IDS_PORTEXISTS_MAXLEN);
+
+ len = lstrlenW(portname) + IDS_PORTEXISTS_MAXLEN + 1;
+ message = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (message) {
+ message[0] = '\0';
+ snprintfW(message, len, res_PortExistsW, portname);
+ MessageBoxW(hWnd, message, res_PortW, MB_OK | MB_ICONERROR);
+ HeapFree(GetProcessHeap(), 0, message);
+ }
+}
+
+/******************************************************************
+ * dlg_invalid_portname [internal]
+ */
+
+static void dlg_invalid_portname(HWND hWnd, LPCWSTR portname)
+{
+ WCHAR res_PortW[IDS_LOCALPORT_MAXLEN];
+ WCHAR res_InvalidNameW[IDS_INVALIDNAME_MAXLEN];
+ LPWSTR message;
+ DWORD len;
+
+ res_PortW[0] = '\0';
+ res_InvalidNameW[0] = '\0';
+ LoadStringW(LOCALUI_hInstance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN);
+ LoadStringW(LOCALUI_hInstance, IDS_INVALIDNAME, res_InvalidNameW, IDS_INVALIDNAME_MAXLEN);
+
+ len = lstrlenW(portname) + IDS_INVALIDNAME_MAXLEN;
+ message = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (message) {
+ message[0] = '\0';
+ snprintfW(message, len, res_InvalidNameW, portname);
+ MessageBoxW(hWnd, message, res_PortW, MB_OK | MB_ICONERROR);
+ HeapFree(GetProcessHeap(), 0, message);
+ }
+}
+
+/******************************************************************
+ * display the Dialog "Nothing to configure"
+ *
+ */
+
+static void dlg_nothingtoconfig(HWND hWnd)
+{
+ WCHAR res_PortW[IDS_LOCALPORT_MAXLEN];
+ WCHAR res_nothingW[IDS_NOTHINGTOCONFIG_MAXLEN];
+
+ res_PortW[0] = '\0';
+ res_nothingW[0] = '\0';
+ LoadStringW(LOCALUI_hInstance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN);
+ LoadStringW(LOCALUI_hInstance, IDS_NOTHINGTOCONFIG, res_nothingW, IDS_NOTHINGTOCONFIG_MAXLEN);
+
+ MessageBoxW(hWnd, res_nothingW, res_PortW, MB_OK | MB_ICONINFORMATION);
+}
+
+/******************************************************************
+ * dlg_win32error [internal]
+ */
+
+static void dlg_win32error(HWND hWnd, DWORD lasterror)
+{
+ WCHAR res_PortW[IDS_LOCALPORT_MAXLEN];
+ LPWSTR message = NULL;
+ DWORD res;
+
+ res_PortW[0] = '\0';
+ LoadStringW(LOCALUI_hInstance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN);
+
+
+ res = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, lasterror, 0, (LPWSTR) &message, 0, NULL);
+
+ if (res > 0) {
+ MessageBoxW(hWnd, message, res_PortW, MB_OK | MB_ICONERROR);
+ LocalFree(message);
+ }
+}
+
+/*****************************************************************************
+ *
+ */
+
+static INT_PTR CALLBACK dlgproc_addport(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ addportui_t * data;
+ DWORD status;
+ DWORD dummy;
+ DWORD len;
+ DWORD res;
+
+ switch(msg)
+ {
+ case WM_INITDIALOG:
+ SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
+ return TRUE;
+
+ case WM_COMMAND:
+ if (wparam == MAKEWPARAM(IDOK, BN_CLICKED))
+ {
+ data = (addportui_t *) GetWindowLongPtrW(hwnd, DWLP_USER);
+ /* length in WCHAR, without the '\0' */
+ len = SendDlgItemMessageW(hwnd, ADDPORT_EDIT, WM_GETTEXTLENGTH, 0, 0);
+ data->portname = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
+
+ if (!data->portname) {
+ EndDialog(hwnd, FALSE);
+ return TRUE;
+ }
+ /* length is in WCHAR, including the '\0' */
+ GetDlgItemTextW(hwnd, ADDPORT_EDIT, data->portname, len + 1);
+ status = ERROR_SUCCESS;
+ res = XcvDataW( data->hXcv, cmd_PortIsValidW, (PBYTE) data->portname,
+ (lstrlenW(data->portname) + 1) * sizeof(WCHAR),
+ (PBYTE) &dummy, 0, &len, &status);
+
+ TRACE("got %u with status %u\n", res, status);
+ if (res && (status == ERROR_SUCCESS)) {
+ /* The caller must free data->portname */
+ EndDialog(hwnd, TRUE);
+ return TRUE;
+ }
+
+ if (res && (status == ERROR_INVALID_NAME)) {
+ dlg_invalid_portname(hwnd, data->portname);
+ HeapFree(GetProcessHeap(), 0, data->portname);
+ data->portname = NULL;
+ return TRUE;
+ }
+
+ dlg_win32error(hwnd, status);
+ HeapFree(GetProcessHeap(), 0, data->portname);
+ data->portname = NULL;
+ return TRUE;
+ }
+
+ if (wparam == MAKEWPARAM(IDCANCEL, BN_CLICKED))
+ {
+ EndDialog(hwnd, FALSE);
+ return TRUE;
+ }
+ return FALSE;
+ }
+ return FALSE;
+}
+
+/*****************************************************************************
+ * dlgproc_lptconfig [internal]
+ *
+ * Our message-proc is simple, as the range-check is done only during the
+ * command "OK" and the dialog is set to the start-value at "out of range".
+ *
+ * Native localui.dll does the check during keyboard-input and set the dialog
+ * to the previous value.
+ *
+ */
+
+static INT_PTR CALLBACK dlgproc_lptconfig(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ lptconfig_t * data;
+ WCHAR bufferW[16];
+ DWORD status;
+ DWORD dummy;
+ DWORD len;
+ DWORD res;
+
+
+ switch(msg)
+ {
+ case WM_INITDIALOG:
+ SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
+ data = (lptconfig_t *) lparam;
+
+ /* Get current setting */
+ data->value = 45;
+ status = ERROR_SUCCESS;
+ res = XcvDataW( data->hXcv, cmd_GetTransmissionRetryTimeoutW,
+ (PBYTE) &dummy, 0,
+ (PBYTE) &data->value, sizeof(data->value), &len, &status);
+
+ TRACE("got %u with status %u\n", res, status);
+
+ /* Set current setting as the initial value in the Dialog */
+ SetDlgItemInt(hwnd, LPTCONFIG_EDIT, data->value, FALSE);
+ return TRUE;
+
+ case WM_COMMAND:
+ if (wparam == MAKEWPARAM(IDOK, BN_CLICKED))
+ {
+ data = (lptconfig_t *) GetWindowLongPtrW(hwnd, DWLP_USER);
+
+ status = FALSE;
+ res = GetDlgItemInt(hwnd, LPTCONFIG_EDIT, (BOOL *) &status, FALSE);
+ /* length is in WCHAR, including the '\0' */
+ GetDlgItemTextW(hwnd, LPTCONFIG_EDIT, bufferW, sizeof(bufferW) / sizeof(bufferW[0]));
+ TRACE("got %s and %u (translated: %u)\n", debugstr_w(bufferW), res, status);
+
+ /* native localui.dll use the same limits */
+ if ((res > 0) && (res < 1000000) && status) {
+ sprintfW(bufferW, fmt_uW, res);
+ res = XcvDataW( data->hXcv, cmd_ConfigureLPTPortCommandOKW,
+ (PBYTE) bufferW,
+ (lstrlenW(bufferW) +1) * sizeof(WCHAR),
+ (PBYTE) &dummy, 0, &len, &status);
+
+ TRACE("got %u with status %u\n", res, status);
+ EndDialog(hwnd, TRUE);
+ return TRUE;
+ }
+
+ /* Set initial value and rerun the Dialog */
+ SetDlgItemInt(hwnd, LPTCONFIG_EDIT, data->value, FALSE);
+ return TRUE;
+ }
+
+ if (wparam == MAKEWPARAM(IDCANCEL, BN_CLICKED))
+ {
+ EndDialog(hwnd, FALSE);
+ return TRUE;
+ }
+ return FALSE;
+ }
+ return FALSE;
+}
+
+
+/*****************************************************
+ * get_type_from_name (internal)
+ *
+ */
+
+static DWORD get_type_from_name(LPCWSTR name)
+{
+ HANDLE hfile;
+
+ if (!strncmpiW(name, portname_LPT, sizeof(portname_LPT) / sizeof(WCHAR) -1))
+ return PORT_IS_LPT;
+
+ if (!strncmpiW(name, portname_COM, sizeof(portname_COM) / sizeof(WCHAR) -1))
+ return PORT_IS_COM;
+
+ if (!strcmpiW(name, portname_FILE))
+ return PORT_IS_FILE;
+
+ if (name[0] == '/')
+ return PORT_IS_UNIXNAME;
+
+ if (name[0] == '|')
+ return PORT_IS_PIPE;
+
+ if (!strncmpW(name, portname_CUPS, sizeof(portname_CUPS) / sizeof(WCHAR) -1))
+ return PORT_IS_CUPS;
+
+ if (!strncmpW(name, portname_LPR, sizeof(portname_LPR) / sizeof(WCHAR) -1))
+ return PORT_IS_LPR;
+
+ /* Must be a file or a directory. Does the file exist ? */
+ hfile = CreateFileW(name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ TRACE("%p for OPEN_EXISTING on %s\n", hfile, debugstr_w(name));
+ if (hfile == INVALID_HANDLE_VALUE) {
+ /* Can we create the file? */
+ hfile = CreateFileW(name, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
+ TRACE("%p for OPEN_ALWAYS\n", hfile);
+ }
+ if (hfile != INVALID_HANDLE_VALUE) {
+ CloseHandle(hfile);
+ return PORT_IS_FILENAME;
+ }
+ /* We can't use the name. use GetLastError() for the reason */
+ return PORT_IS_UNKNOWN;
+}
+
+/*****************************************************
+ * open_monitor_by_name [internal]
+ *
+ */
+static BOOL open_monitor_by_name(LPCWSTR pPrefix, LPCWSTR pPort, HANDLE * phandle)
+{
+ PRINTER_DEFAULTSW pd;
+ LPWSTR fullname;
+ BOOL res;
+
+ * phandle = 0;
+ TRACE("(%s,%s)\n", debugstr_w(pPrefix),debugstr_w(pPort) );
+
+ fullname = strdupWW(pPrefix, pPort);
+ pd.pDatatype = NULL;
+ pd.pDevMode = NULL;
+ pd.DesiredAccess = SERVER_ACCESS_ADMINISTER;
+
+ res = OpenPrinterW(fullname, phandle, &pd);
+ HeapFree(GetProcessHeap(), 0, fullname);
+ return res;
+}
+
+/*****************************************************
+ * localui_AddPortUI [exported through MONITORUI]
+ *
+ * Display a Dialog to add a local Port
+ *
+ * PARAMS
+ * pName [I] Servername or NULL (local Computer)
+ * hWnd [I] Handle to parent Window for the Dialog-Box or NULL
+ * pMonitorName[I] Name of the Monitor, that should be used to add a Port or NULL
+ * ppPortName [O] PTR to PTR of a buffer, that receive the Name of the new Port or NULL
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ *
+ * NOTES
+ * The caller must free the buffer (returned in ppPortName) with GlobalFree().
+ * Native localui.dll failed with ERROR_INVALID_PARAMETER, when the user tried
+ * to add a Port, that start with "COM" or "LPT".
+ *
+ */
+static BOOL WINAPI localui_AddPortUI(PCWSTR pName, HWND hWnd, PCWSTR pMonitorName, PWSTR *ppPortName)
+{
+ addportui_t data;
+ HANDLE hXcv;
+ DWORD needed;
+ DWORD dummy;
+ DWORD status;
+ DWORD res = FALSE;
+
+ TRACE( "(%s, %p, %s, %p) (*ppPortName: %p)\n", debugstr_w(pName), hWnd,
+ debugstr_w(pMonitorName), ppPortName, ppPortName ? *ppPortName : NULL);
+
+ if (open_monitor_by_name(XcvMonitorW, pMonitorName, &hXcv)) {
+
+ ZeroMemory(&data, sizeof(addportui_t));
+ data.hXcv = hXcv;
+ res = DialogBoxParamW(LOCALUI_hInstance, MAKEINTRESOURCEW(ADDPORT_DIALOG), hWnd,
+ dlgproc_addport, (LPARAM) &data);
+
+ TRACE("got %u with %u for %s\n", res, GetLastError(), debugstr_w(data.portname));
+
+ if (ppPortName) *ppPortName = NULL;
+
+ if (res) {
+ res = XcvDataW(hXcv, cmd_AddPortW, (PBYTE) data.portname,
+ (lstrlenW(data.portname)+1) * sizeof(WCHAR),
+ (PBYTE) &dummy, 0, &needed, &status);
+
+ TRACE("got %u with status %u\n", res, status);
+ if (res && (status == ERROR_SUCCESS) && ppPortName) {
+ /* Native localui uses GlobalAlloc also.
+ The caller must GlobalFree the buffer */
+ *ppPortName = GlobalAlloc(GPTR, (lstrlenW(data.portname)+1) * sizeof(WCHAR));
+ if (*ppPortName) lstrcpyW(*ppPortName, data.portname);
+ }
+
+ if (res && (status == ERROR_ALREADY_EXISTS)) {
+ dlg_port_already_exists(hWnd, data.portname);
+ /* Native localui also return "TRUE" from AddPortUI in this case */
+ }
+
+ HeapFree(GetProcessHeap(), 0, data.portname);
+ }
+ else
+ {
+ SetLastError(ERROR_CANCELLED);
+ }
+ ClosePrinter(hXcv);
+ }
+
+ TRACE("=> %u with %u\n", res, GetLastError());
+ return res;
+}
+
+
+/*****************************************************
+ * localui_ConfigurePortUI [exported through MONITORUI]
+ *
+ * Display the Configuration-Dialog for a specific Port
+ *
+ * PARAMS
+ * pName [I] Servername or NULL (local Computer)
+ * hWnd [I] Handle to parent Window for the Dialog-Box or NULL
+ * pPortName [I] Name of the Port, that should be configured
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ *
+ */
+static BOOL WINAPI localui_ConfigurePortUI(PCWSTR pName, HWND hWnd, PCWSTR pPortName)
+{
+ HANDLE hXcv;
+ DWORD res;
+
+ TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
+ if (open_monitor_by_name(XcvPortW, pPortName, &hXcv)) {
+
+ res = get_type_from_name(pPortName);
+ switch(res)
+ {
+
+ case PORT_IS_COM:
+ res = dlg_configure_com(hXcv, hWnd, pPortName);
+ break;
+
+ case PORT_IS_LPT:
+ res = dlg_configure_lpt(hXcv, hWnd);
+ break;
+
+ default:
+ dlg_nothingtoconfig(hWnd);
+ SetLastError(ERROR_CANCELLED);
+ res = FALSE;
+ }
+
+ ClosePrinter(hXcv);
+ return res;
+ }
+ return FALSE;
+
+}
+
+/*****************************************************
+ * localui_DeletePortUI [exported through MONITORUI]
+ *
+ * Delete a specific Port
+ *
+ * PARAMS
+ * pName [I] Servername or NULL (local Computer)
+ * hWnd [I] Handle to parent Window
+ * pPortName [I] Name of the Port, that should be deleted
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ *
+ * NOTES
+ * Native localui does not allow to delete a COM / LPT - Port (ERROR_NOT_SUPPORTED)
+ *
+ */
+static BOOL WINAPI localui_DeletePortUI(PCWSTR pName, HWND hWnd, PCWSTR pPortName)
+{
+ HANDLE hXcv;
+ DWORD dummy;
+ DWORD needed;
+ DWORD status;
+
+ TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
+
+ if ((!pPortName) || (!pPortName[0])) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ if (open_monitor_by_name(XcvPortW, pPortName, &hXcv)) {
+ /* native localui tests here for LPT / COM - Ports and failed with
+ ERROR_NOT_SUPPORTED. */
+ if (XcvDataW(hXcv, cmd_DeletePortW, (LPBYTE) pPortName,
+ (lstrlenW(pPortName)+1) * sizeof(WCHAR), (LPBYTE) &dummy, 0, &needed, &status)) {
+
+ ClosePrinter(hXcv);
+ if (status != ERROR_SUCCESS) SetLastError(status);
+ return (status == ERROR_SUCCESS);
+ }
+ ClosePrinter(hXcv);
+ return FALSE;
+ }
+ SetLastError(ERROR_UNKNOWN_PORT);
+ return FALSE;
+}
+
+/*****************************************************
+ * InitializePrintMonitorUI (LOCALUI.@)
+ *
+ * Initialize the User-Interface for the Local Ports
+ *
+ * RETURNS
+ * Success: Pointer to a MONITORUI Structure
+ * Failure: NULL
+ *
+ */
+
+PMONITORUI WINAPI InitializePrintMonitorUI(void)
+{
+ static MONITORUI mymonitorui =
+ {
+ sizeof(MONITORUI),
+ localui_AddPortUI,
+ localui_ConfigurePortUI,
+ localui_DeletePortUI
+ };
+
+ TRACE("=> %p\n", &mymonitorui);
+ return &mymonitorui;
+}
+
+/*****************************************************
+ * DllMain
+ */
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ TRACE("(%p, %d, %p)\n",hinstDLL, fdwReason, lpvReserved);
+
+ switch(fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ DisableThreadLibraryCalls( hinstDLL );
+ LOCALUI_hInstance = hinstDLL;
+ break;
+ }
+ return TRUE;
+}
--- /dev/null
+/*
+ * internal include file of the Local Printmonitor User Interface
+ *
+ * Copyright 2007 Detlef Riekenberg
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_LOCALUI__
+#define __WINE_LOCALUI__
+
+//#include <windef.h>
+//#include <winuser.h>
+
+/* ## Resource-ID ## */
+#define ADDPORT_DIALOG 100
+#define ADDPORT_EDIT 101
+
+#define LPTCONFIG_DIALOG 200
+#define LPTCONFIG_GROUP 201
+#define LPTCONFIG_EDIT 202
+
+#define IDS_LOCALPORT 300
+#define IDS_INVALIDNAME 301
+#define IDS_PORTEXISTS 302
+#define IDS_NOTHINGTOCONFIG 303
+
+/* ## Reserved memorysize for the strings (in WCHAR) ## */
+#define IDS_LOCALPORT_MAXLEN 32
+#define IDS_INVALIDNAME_MAXLEN 48
+#define IDS_PORTEXISTS_MAXLEN 48
+#define IDS_NOTHINGTOCONFIG_MAXLEN 80
+
+/* ## Type of Ports ## */
+/* windows types */
+#define PORT_IS_UNKNOWN 0
+#define PORT_IS_LPT 1
+#define PORT_IS_COM 2
+#define PORT_IS_FILE 3
+#define PORT_IS_FILENAME 4
+
+/* wine extensions */
+#define PORT_IS_WINE 5
+#define PORT_IS_UNIXNAME 5
+#define PORT_IS_PIPE 6
+#define PORT_IS_CUPS 7
+#define PORT_IS_LPR 8
+
+
+#endif /* __WINE_LOCALUI__ */
/*
- * Top level resource file for localspl
+ * Top level resource file for localui
*
- * Copyright 2006 Detlef Riekenberg
+ * Copyright 2007 Detlef Riekenberg
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
*
*/
-#include "resource.h"
+#include <windef.h>
+#include <winuser.h>
-#define WINE_FILENAME_STR "localspl.dll"
-#define WINE_FILEDESCRIPTION_STR "Wine Printer spooler component"
+#include "localui.h"
+
+#define WINE_FILENAME_STR "localui.dll"
+#define WINE_FILEDESCRIPTION_STR "User Interface for the Local Monitor"
/* Same Version as WinXP_sp2 */
#define WINE_FILEVERSION 5,1,2600,2180
#define WINE_PRODUCTVERSION 5,1,2600,2180
#define WINE_PRODUCTVERSION_STR "5.1.2600.2180"
-#include <wine/wine_common_ver.rc>
+#include "wine/wine_common_ver.rc"
+
+#include <reactos/manifest_dll.rc>
/* UTF-8 */
#pragma code_page(65001)
#ifdef LANGUAGE_DA_DK
- #include "lang/spl_Da.rc"
+ #include "lang/ui_Da.rc"
#endif
#ifdef LANGUAGE_DE_DE
- #include "lang/spl_De.rc"
+ #include "lang/ui_De.rc"
#endif
#ifdef LANGUAGE_EN_US
- #include "lang/spl_En.rc"
+ #include "lang/ui_En.rc"
#endif
#ifdef LANGUAGE_ES_ES
- #include "lang/spl_Es.rc"
+ #include "lang/ui_Es.rc"
#endif
#ifdef LANGUAGE_FR_FR
- #include "lang/spl_Fr.rc"
+ #include "lang/ui_Fr.rc"
#endif
#ifdef LANGUAGE_HE_IL
- #include "lang/spl_He.rc"
+ #include "lang/ui_He.rc"
#endif
#ifdef LANGUAGE_HU_HU
- #include "lang/spl_Hu.rc"
+ #include "lang/ui_Hu.rc"
#endif
#ifdef LANGUAGE_IT_IT
- #include "lang/spl_It.rc"
+ #include "lang/ui_It.rc"
#endif
#ifdef LANGUAGE_JA_JP
- #include "lang/spl_Ja.rc"
+ #include "lang/ui_Ja.rc"
#endif
#ifdef LANGUAGE_KO_KR
- #include "lang/spl_Ko.rc"
+ #include "lang/ui_Ko.rc"
#endif
#ifdef LANGUAGE_LT_LT
- #include "lang/spl_Lt.rc"
+ #include "lang/ui_Lt.rc"
#endif
#ifdef LANGUAGE_NL_NL
- #include "lang/spl_Nl.rc"
+ #include "lang/ui_Nl.rc"
#endif
#ifdef LANGUAGE_NO_NO
- #include "lang/spl_No.rc"
+ #include "lang/ui_No.rc"
#endif
#ifdef LANGUAGE_PL_PL
- #include "lang/spl_Pl.rc"
+ #include "lang/ui_Pl.rc"
#endif
#ifdef LANGUAGE_PT_PT
- #include "lang/spl_Pt.rc"
+ #include "lang/ui_Pt.rc"
#endif
#ifdef LANGUAGE_RO_RO
- #include "lang/spl_Ro.rc"
+ #include "lang/ui_Ro.rc"
#endif
#ifdef LANGUAGE_RU_RU
- #include "lang/spl_Ru.rc"
+ #include "lang/ui_Ru.rc"
#endif
#ifdef LANGUAGE_SL_SI
- #include "lang/spl_Si.rc"
+ #include "lang/ui_Si.rc"
#endif
#ifdef LANGUAGE_SQ_AL
- #include "lang/spl_Sq.rc"
+ #include "lang/ui_Sq.rc"
#endif
#ifdef LANGUAGE_SV_SE
- #include "lang/spl_Sv.rc"
+ #include "lang/ui_Sv.rc"
#endif
#ifdef LANGUAGE_TR_TR
- #include "lang/spl_Tr.rc"
+ #include "lang/ui_Tr.rc"
#endif
#ifdef LANGUAGE_UK_UA
- #include "lang/spl_Uk.rc"
+ #include "lang/ui_Uk.rc"
#endif
#ifdef LANGUAGE_ZH_CN
- #include "lang/spl_Zh.rc"
+ #include "lang/ui_Zh.rc"
#endif
--- /dev/null
+@ stdcall InitializePrintMonitorUI()
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Port Monitor
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Implementation of Xcv* and support functions
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+static DWORD
+_HandleAddPort(PLOCALMON_XCV pXcv, PBYTE pInputData, PDWORD pcbOutputNeeded)
+{
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+/**
+ * @name _HandleConfigureLPTPortCommandOK
+ *
+ * Writes the value for "TransmissionRetryTimeout" to the registry. Checks for granted SERVER_ACCESS_ADMINISTER access.
+ * Actually the opposite of _HandleGetTransmissionRetryTimeout, but name kept for compatibility.
+ *
+ * @param pXcv
+ * Pointer to the LOCALMON_XCV structure of the currently opened Xcv port.
+ *
+ * @param pInputData
+ * Pointer to a Unicode string containing the value to be written to the registry.
+ *
+ * @param pcbOutputNeeded
+ * Pointer to a DWORD that will be zeroed on return.
+ *
+ * @return
+ * An error code indicating success or failure.
+ */
+static DWORD
+_HandleConfigureLPTPortCommandOK(PLOCALMON_XCV pXcv, PBYTE pInputData, PDWORD pcbOutputNeeded)
+{
+ DWORD cbBuffer;
+ DWORD dwErrorCode;
+ HKEY hKey = NULL;
+ HKEY hToken = NULL;
+
+ // Sanity checks
+ if (!pXcv || !pInputData || !pcbOutputNeeded)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ *pcbOutputNeeded = 0;
+
+ // This action can only happen at SERVER_ACCESS_ADMINISTER access level.
+ if (!(pXcv->GrantedAccess & SERVER_ACCESS_ADMINISTER))
+ {
+ dwErrorCode = ERROR_ACCESS_DENIED;
+ goto Cleanup;
+ }
+
+ // Switch to the SYSTEM context for modifying the registry.
+ hToken = RevertToPrinterSelf();
+ if (!hToken)
+ {
+ dwErrorCode = GetLastError();
+ ERR("RevertToPrinterSelf failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Open the key where our value is stored.
+ dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows", 0, KEY_SET_VALUE, &hKey);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // We don't use cbInputData here, because the buffer pInputData could be bigger than the data it contains.
+ cbBuffer = (wcslen((PWSTR)pInputData) + 1) * sizeof(WCHAR);
+
+ // Write the value to the registry.
+ dwErrorCode = (DWORD)RegSetValueExW(hKey, L"TransmissionRetryTimeout", 0, REG_SZ, pInputData, cbBuffer);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegSetValueExW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+Cleanup:
+ if (hKey)
+ RegCloseKey(hKey);
+
+ if (hToken)
+ ImpersonatePrinterClient(hToken);
+
+ return dwErrorCode;
+}
+
+static DWORD
+_HandleDeletePort(PLOCALMON_XCV pXcv, PBYTE pInputData, PDWORD pcbOutputNeeded)
+{
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+/**
+ * @name _HandleGetDefaultCommConfig
+ *
+ * Gets the default configuration of a legacy port.
+ * The opposite function is _HandleSetDefaultCommConfig.
+ *
+ * @param pInputData
+ * The port name (without colon!) whose default configuration you want to get.
+ *
+ * @param pOutputData
+ * Pointer to a COMMCONFIG structure that will receive the configuration information.
+ *
+ * @param cbOutputData
+ * Size of the variable pointed to by pOutputData.
+ *
+ * @param pcbOutputNeeded
+ * Pointer to a DWORD that contains the required size for pOutputData on return.
+ *
+ * @return
+ * An error code indicating success or failure.
+ */
+static DWORD
+_HandleGetDefaultCommConfig(PBYTE pInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded)
+{
+ // Sanity checks
+ if (!pInputData || !pcbOutputNeeded)
+ return ERROR_INVALID_PARAMETER;
+
+ *pcbOutputNeeded = sizeof(COMMCONFIG);
+
+ // Check if the supplied buffer is large enough.
+ if (cbOutputData < *pcbOutputNeeded)
+ return ERROR_INSUFFICIENT_BUFFER;
+
+ // Finally get the port configuration.
+ if (!GetDefaultCommConfigW((PCWSTR)pInputData, (LPCOMMCONFIG)pOutputData, pcbOutputNeeded))
+ return GetLastError();
+
+ return ERROR_SUCCESS;
+}
+
+/**
+ * @name _HandleGetTransmissionRetryTimeout
+ *
+ * Reads the value for "TransmissionRetryTimeout" from the registry and converts it to a DWORD.
+ * The opposite function is _HandleConfigureLPTPortCommandOK.
+ *
+ * @param pOutputData
+ * Pointer to a DWORD that will receive the timeout value.
+ *
+ * @param cbOutputData
+ * Size of the variable pointed to by pOutputData.
+ *
+ * @param pcbOutputNeeded
+ * Pointer to a DWORD that contains the required size for pOutputData on return.
+ *
+ * @return
+ * An error code indicating success or failure.
+ */
+static DWORD
+_HandleGetTransmissionRetryTimeout(PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded)
+{
+ DWORD dwTimeout;
+
+ // Sanity checks
+ if (!pOutputData || !pcbOutputNeeded)
+ return ERROR_INVALID_PARAMETER;
+
+ *pcbOutputNeeded = sizeof(DWORD);
+
+ // Check if the supplied buffer is large enough.
+ if (cbOutputData < *pcbOutputNeeded)
+ return ERROR_INSUFFICIENT_BUFFER;
+
+ // Retrieve and copy the number.
+ dwTimeout = GetLPTTransmissionRetryTimeout();
+ CopyMemory(pOutputData, &dwTimeout, sizeof(DWORD));
+ return ERROR_SUCCESS;
+}
+
+/**
+ * @name _HandleMonitorUI
+ *
+ * Returns the filename of the associated UI DLL for this Port Monitor.
+ *
+ * @param pOutputData
+ * Pointer to a Unicode string that will receive the DLL filename.
+ *
+ * @param cbOutputData
+ * Size of the variable pointed to by pOutputData.
+ *
+ * @param pcbOutputNeeded
+ * Pointer to a DWORD that contains the required size for pOutputData on return.
+ *
+ * @return
+ * An error code indicating success or failure.
+ */
+static DWORD
+_HandleMonitorUI(PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded)
+{
+ const WCHAR wszMonitorUI[] = L"LocalUI.dll";
+
+ // Sanity checks
+ if (!pOutputData || !pcbOutputNeeded)
+ return ERROR_INVALID_PARAMETER;
+
+ *pcbOutputNeeded = sizeof(wszMonitorUI);
+
+ // Check if the supplied buffer is large enough.
+ if (cbOutputData < *pcbOutputNeeded)
+ return ERROR_INSUFFICIENT_BUFFER;
+
+ // Copy the string.
+ CopyMemory(pOutputData, wszMonitorUI, sizeof(wszMonitorUI));
+ return ERROR_SUCCESS;
+}
+
+/**
+ * @name _HandlePortExists
+ *
+ * Checks all Port Monitors installed on the local system to find out if a given port already exists.
+ *
+ * @param pInputData
+ * Pointer to a Unicode string specifying the port name to check.
+ *
+ * @param pOutputData
+ * Pointer to a BOOL that receives the result of the check.
+ *
+ * @param cbOutputData
+ * Size of the variable pointed to by pOutputData.
+ *
+ * @param pcbOutputNeeded
+ * Pointer to a DWORD that contains the required size for pOutputData on return.
+ *
+ * @return
+ * An error code indicating success or failure.
+ */
+static DWORD
+_HandlePortExists(PBYTE pInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded)
+{
+ // Sanity checks
+ if (!pInputData || !pOutputData || !pcbOutputNeeded)
+ return ERROR_INVALID_PARAMETER;
+
+ *pcbOutputNeeded = sizeof(BOOL);
+
+ // Check if the supplied buffer is large enough.
+ if (cbOutputData < *pcbOutputNeeded)
+ return ERROR_INSUFFICIENT_BUFFER;
+
+ // Return the check result and error code.
+ *(PBOOL)pOutputData = DoesPortExist((PCWSTR)pInputData);
+ return GetLastError();
+}
+
+static DWORD
+_HandlePortIsValid(PBYTE pInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded)
+{
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+/**
+ * @name _HandleSetDefaultCommConfig
+ *
+ * Sets the default configuration of a legacy port. Checks for granted SERVER_ACCESS_ADMINISTER access.
+ * You have to supply the port name (with colon!) in XcvOpenPort.
+ * The opposite function is _HandleGetDefaultCommConfig.
+ *
+ * @param pXcv
+ * Pointer to the LOCALMON_XCV structure of the currently opened Xcv port.
+ *
+ * @param pInputData
+ * Pointer to the COMMCONFIG structure that shall be passed to SetDefaultCommConfigW.
+ *
+ * @param pcbOutputNeeded
+ * Pointer to a DWORD that will be zeroed on return.
+ *
+ * @return
+ * An error code indicating success or failure.
+ */
+static DWORD
+_HandleSetDefaultCommConfig(PLOCALMON_XCV pXcv, PBYTE pInputData, PDWORD pcbOutputNeeded)
+{
+ DWORD dwErrorCode;
+ HANDLE hToken = NULL;
+ LPCOMMCONFIG pCommConfig;
+ PWSTR pwszPortNameWithoutColon = NULL;
+
+ // Sanity checks
+ // pwszObject needs to be at least 2 characters long to be a port name with a trailing colon.
+ if (!pXcv || !pXcv->pwszObject || !pXcv->pwszObject[0] || !pXcv->pwszObject[1] || !pInputData || !pcbOutputNeeded)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ *pcbOutputNeeded = 0;
+
+ // This action can only happen at SERVER_ACCESS_ADMINISTER access level.
+ if (!(pXcv->GrantedAccess & SERVER_ACCESS_ADMINISTER))
+ {
+ dwErrorCode = ERROR_ACCESS_DENIED;
+ goto Cleanup;
+ }
+
+ // SetDefaultCommConfigW needs the port name without colon.
+ dwErrorCode = GetPortNameWithoutColon(pXcv->pwszObject, &pwszPortNameWithoutColon);
+ if (dwErrorCode != ERROR_SUCCESS)
+ goto Cleanup;
+
+ // Switch to the SYSTEM context for setting the port configuration.
+ hToken = RevertToPrinterSelf();
+ if (!hToken)
+ {
+ dwErrorCode = GetLastError();
+ ERR("RevertToPrinterSelf failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Finally pass the parameters to SetDefaultCommConfigW.
+ pCommConfig = (LPCOMMCONFIG)pInputData;
+ if (!SetDefaultCommConfigW(pwszPortNameWithoutColon, pCommConfig, pCommConfig->dwSize))
+ {
+ dwErrorCode = GetLastError();
+ ERR("SetDefaultCommConfigW failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ if (hToken)
+ ImpersonatePrinterClient(hToken);
+
+ if (pwszPortNameWithoutColon)
+ DllFreeSplMem(pwszPortNameWithoutColon);
+
+ return dwErrorCode;
+}
+
+BOOL WINAPI
+LocalmonXcvClosePort(HANDLE hXcv)
+{
+ PLOCALMON_XCV pXcv = (PLOCALMON_XCV)hXcv;
+
+ TRACE("LocalmonXcvClosePort(%p)\n", hXcv);
+
+ // Sanity checks
+ if (!pXcv)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ // Remove it from the list and free the memory.
+ RemoveEntryList(&pXcv->Entry);
+ DllFreeSplMem(pXcv);
+
+ SetLastError(ERROR_SUCCESS);
+ return TRUE;
+}
+
+DWORD WINAPI
+LocalmonXcvDataPort(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded)
+{
+ TRACE("LocalmonXcvDataPort(%p, %S, %p, %lu, %p, %lu, %p)\n", hXcv, pszDataName, pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
+
+ // Sanity checks
+ if (!pszDataName)
+ return ERROR_INVALID_PARAMETER;
+
+ // Call the appropriate handler for the requested data name.
+ if (wcscmp(pszDataName, L"AddPort") == 0)
+ return _HandleAddPort((PLOCALMON_XCV)hXcv, pInputData, pcbOutputNeeded);
+
+ if (wcscmp(pszDataName, L"ConfigureLPTPortCommandOK") == 0)
+ return _HandleConfigureLPTPortCommandOK((PLOCALMON_XCV)hXcv, pInputData, pcbOutputNeeded);
+
+ if (wcscmp(pszDataName, L"DeletePort") == 0)
+ return _HandleDeletePort((PLOCALMON_XCV)hXcv, pInputData, pcbOutputNeeded);
+
+ if (wcscmp(pszDataName, L"GetDefaultCommConfig") == 0)
+ return _HandleGetDefaultCommConfig(pInputData, pOutputData, cbOutputData, pcbOutputNeeded);
+
+ if (wcscmp(pszDataName, L"GetTransmissionRetryTimeout") == 0)
+ return _HandleGetTransmissionRetryTimeout(pOutputData, cbOutputData, pcbOutputNeeded);
+
+ if (wcscmp(pszDataName, L"MonitorUI") == 0)
+ return _HandleMonitorUI(pOutputData, cbOutputData, pcbOutputNeeded);
+
+ if (wcscmp(pszDataName, L"PortExists") == 0)
+ return _HandlePortExists(pInputData, pOutputData, cbOutputData, pcbOutputNeeded);
+
+ if (wcscmp(pszDataName, L"PortIsValid") == 0)
+ return _HandlePortIsValid(pInputData, pOutputData, cbOutputData, pcbOutputNeeded);
+
+ if (wcscmp(pszDataName, L"SetDefaultCommConfig") == 0)
+ return _HandleSetDefaultCommConfig((PLOCALMON_XCV)hXcv, pInputData, pcbOutputNeeded);
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+BOOL WINAPI
+LocalmonXcvOpenPort(HANDLE hMonitor, PCWSTR pwszObject, ACCESS_MASK GrantedAccess, PHANDLE phXcv)
+{
+ DWORD cbObject = 0;
+ DWORD dwErrorCode;
+ PLOCALMON_HANDLE pLocalmon = (PLOCALMON_HANDLE)hMonitor;
+ PLOCALMON_XCV pXcv;
+
+ TRACE("LocalmonXcvOpenPort(%p, %S, %lu, %p)\n", hMonitor, pwszObject, GrantedAccess, phXcv);
+
+ // Sanity checks
+ if (!pLocalmon || !phXcv)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ if (pwszObject)
+ cbObject = (wcslen(pwszObject) + 1) * sizeof(WCHAR);
+
+ // Create a new LOCALMON_XCV structure and fill the relevant fields.
+ pXcv = DllAllocSplMem(sizeof(LOCALMON_XCV) + cbObject);
+ if (!pXcv)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ pXcv->pLocalmon = pLocalmon;
+ pXcv->GrantedAccess = GrantedAccess;
+
+ if (cbObject)
+ {
+ pXcv->pwszObject = (PWSTR)((PBYTE)pXcv + sizeof(LOCALMON_XCV));
+ CopyMemory(pXcv->pwszObject, pwszObject, cbObject);
+ }
+
+ InsertTailList(&pLocalmon->XcvHandles, &pXcv->Entry);
+
+ // Return it as the Xcv handle.
+ *phXcv = (HANDLE)pXcv;
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
--- /dev/null
+#add_subdirectory(ui)
--- /dev/null
+add_subdirectory(winprint)
--- /dev/null
+
+spec2def(winprint.dll winprint.spec ADD_IMPORTLIB)
+
+list(APPEND SOURCE
+ main.c
+ raw.c
+ precomp.h)
+
+add_library(winprint SHARED
+ ${SOURCE}
+ winprint.rc
+ ${CMAKE_CURRENT_BINARY_DIR}/winprint.def)
+
+set_module_type(winprint win32dll UNICODE)
+target_link_libraries(winprint wine)
+add_importlibs(winprint spoolss msvcrt kernel32 ntdll)
+add_pch(winprint precomp.h SOURCE)
+add_cd_file(TARGET winprint DESTINATION reactos/system32/spool/prtprocs/w32x86 FOR all)
--- /dev/null
+/*
+ * PROJECT: ReactOS Standard Print Processor
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Main functions
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+// Local Constants
+static PCWSTR _pwszDatatypes[] = {
+ L"RAW",
+ 0
+};
+
+
+/**
+ * @name ClosePrintProcessor
+ *
+ * Closes a Print Processor Handle that has previously been opened through OpenPrintProcessor.
+ *
+ * @param hPrintProcessor
+ * The return value of a previous successful OpenPrintProcessor call.
+ *
+ * @return
+ * TRUE if the Print Processor Handle was successfully closed, FALSE otherwise.
+ * A more specific error code can be obtained through GetLastError.
+ */
+BOOL WINAPI
+ClosePrintProcessor(HANDLE hPrintProcessor)
+{
+ DWORD dwErrorCode;
+ PWINPRINT_HANDLE pHandle;
+
+ TRACE("ClosePrintProcessor(%p)\n", hPrintProcessor);
+
+ // Sanity checks
+ if (!hPrintProcessor)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ pHandle = (PWINPRINT_HANDLE)hPrintProcessor;
+
+ // Free all structure fields for which memory has been allocated.
+ if (pHandle->pwszDatatype)
+ DllFreeSplStr(pHandle->pwszDatatype);
+
+ if (pHandle->pwszDocumentName)
+ DllFreeSplStr(pHandle->pwszDocumentName);
+
+ if (pHandle->pwszOutputFile)
+ DllFreeSplStr(pHandle->pwszOutputFile);
+
+ if (pHandle->pwszPrinterPort)
+ DllFreeSplStr(pHandle->pwszPrinterPort);
+
+ // Finally free the WINSPOOL_HANDLE structure itself.
+ DllFreeSplMem(pHandle);
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+ControlPrintProcessor(HANDLE hPrintProcessor, DWORD Command)
+{
+ TRACE("ControlPrintProcessor(%p, %lu)\n", hPrintProcessor, Command);
+
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+/**
+ * @name EnumPrintProcessorDatatypesW
+ *
+ * Obtains an array of all datatypes supported by this Print Processor.
+ *
+ * @param pName
+ * Server Name. Ignored here, because every caller of EnumPrintProcessorDatatypesW is interested in this Print Processor's information.
+ *
+ * @param pPrintProcessorName
+ * Print Processor Name. Ignored here, because every caller of EnumPrintProcessorDatatypesW is interested in this Print Processor's information.
+ *
+ * @param Level
+ * The level of the structure supplied through pDatatypes. This must be 1.
+ *
+ * @param pDatatypes
+ * Pointer to the buffer that receives an array of DATATYPES_INFO_1W structures.
+ * Can be NULL if you just want to know the required size of the buffer.
+ *
+ * @param cbBuf
+ * Size of the buffer you supplied for pDatatypes, in bytes.
+ *
+ * @param pcbNeeded
+ * Pointer to a variable that receives the required size of the buffer for pDatatypes, in bytes.
+ * This parameter mustn't be NULL!
+ *
+ * @param pcReturned
+ * Pointer to a variable that receives the number of elements of the DATATYPES_INFO_1W array.
+ * This parameter mustn't be NULL!
+ *
+ * @return
+ * TRUE if we successfully copied the array into pDatatypes, FALSE otherwise.
+ * A more specific error code can be obtained through GetLastError.
+ */
+BOOL WINAPI
+EnumPrintProcessorDatatypesW(PWSTR pName, PWSTR pPrintProcessorName, DWORD Level, PBYTE pDatatypes, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ DWORD cbDatatype;
+ DWORD dwDatatypeCount = 0;
+ DWORD dwErrorCode;
+ DWORD dwOffsets[_countof(_pwszDatatypes)];
+ PCWSTR* pCurrentDatatype;
+ PDWORD pCurrentOffset = dwOffsets;
+
+ TRACE("EnumPrintProcessorDatatypesW(%S, %S, %lu, %p, %lu, %p, %p)\n", pName, pPrintProcessorName, Level, pDatatypes, cbBuf, pcbNeeded, pcReturned);
+
+ // Sanity checks
+ if (Level != 1 || !pcbNeeded || !pcReturned)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // Count the required buffer size and the number of datatypes.
+ *pcbNeeded = 0;
+ *pcReturned = 0;
+
+ for (pCurrentDatatype = _pwszDatatypes; *pCurrentDatatype; pCurrentDatatype++)
+ {
+ cbDatatype = (wcslen(*pCurrentDatatype) + 1) * sizeof(WCHAR);
+ *pcbNeeded += sizeof(DATATYPES_INFO_1W) + cbDatatype;
+
+ // Also calculate the offset in the output buffer of the pointer to this datatype string.
+ *pCurrentOffset = dwDatatypeCount * sizeof(DATATYPES_INFO_1W) + FIELD_OFFSET(DATATYPES_INFO_1W, pName);
+
+ dwDatatypeCount++;
+ pCurrentOffset++;
+ }
+
+ // Check if the supplied buffer is large enough.
+ if (cbBuf < *pcbNeeded)
+ {
+ dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
+ goto Cleanup;
+ }
+
+ // Check if a buffer was supplied at all.
+ if (!pDatatypes)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // Copy over all datatypes.
+ *pCurrentOffset = MAXDWORD;
+ PackStrings(_pwszDatatypes, pDatatypes, dwOffsets, &pDatatypes[*pcbNeeded]);
+
+ *pcReturned = dwDatatypeCount;
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+
+DWORD WINAPI
+GetPrintProcessorCapabilities(PWSTR pValueName, DWORD dwAttributes, PBYTE pData, DWORD nSize, PDWORD pcbNeeded)
+{
+ TRACE("GetPrintProcessorCapabilities(%S, %lu, %p, %lu, %p)\n", pValueName, dwAttributes, pData, nSize, pcbNeeded);
+
+ UNIMPLEMENTED;
+ return 0;
+}
+
+/**
+ * @name OpenPrintProcessor
+ *
+ * Prepares this Print Processor for processing a document.
+ *
+ * @param pPrinterName
+ * String in the format "\\COMPUTERNAME\Port:, Port" that is passed to OpenPrinterW for writing to the Print Monitor on the specified port.
+ *
+ * @param pPrintProcessorOpenData
+ * Pointer to a PRINTPROCESSOROPENDATA structure containing details about the print job to be processed.
+ *
+ * @return
+ * A Print Processor handle on success or NULL in case of a failure. This handle has to be passed to PrintDocumentOnPrintProcessor to do the actual processing.
+ * A more specific error code can be obtained through GetLastError.
+ */
+HANDLE WINAPI
+OpenPrintProcessor(PWSTR pPrinterName, PPRINTPROCESSOROPENDATA pPrintProcessorOpenData)
+{
+ DWORD dwErrorCode;
+ HANDLE hReturnValue = NULL;
+ PWINPRINT_HANDLE pHandle = NULL;
+
+ TRACE("OpenPrintProcessor(%S, %p)\n", pPrinterName, pPrintProcessorOpenData);
+
+ // Sanity checks
+ // This time a datatype needs to be given. We can't fall back to a default here.
+ if (!pPrintProcessorOpenData || !pPrintProcessorOpenData->pDatatype || !*pPrintProcessorOpenData->pDatatype)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // Create a new WINPRINT_HANDLE structure and fill the relevant fields.
+ pHandle = DllAllocSplMem(sizeof(WINPRINT_HANDLE));
+
+ // Check what datatype was given.
+ if (wcsicmp(pPrintProcessorOpenData->pDatatype, L"RAW") == 0)
+ {
+ pHandle->Datatype = RAW;
+ }
+ else
+ {
+ dwErrorCode = ERROR_INVALID_DATATYPE;
+ goto Cleanup;
+ }
+
+ // Fill the relevant fields.
+ pHandle->dwJobID = pPrintProcessorOpenData->JobId;
+ pHandle->pwszDatatype = AllocSplStr(pPrintProcessorOpenData->pDatatype);
+ pHandle->pwszDocumentName = AllocSplStr(pPrintProcessorOpenData->pDocumentName);
+ pHandle->pwszOutputFile = AllocSplStr(pPrintProcessorOpenData->pOutputFile);
+ pHandle->pwszPrinterPort = AllocSplStr(pPrinterName);
+
+ // We were successful! Return the handle and don't let the cleanup routine free it.
+ dwErrorCode = ERROR_SUCCESS;
+ hReturnValue = pHandle;
+ pHandle = NULL;
+
+Cleanup:
+ if (pHandle)
+ DllFreeSplMem(pHandle);
+
+ SetLastError(dwErrorCode);
+ return hReturnValue;
+}
+
+/**
+ * @name PrintDocumentOnPrintProcessor
+ *
+ * Prints a document on this Print Processor after a handle for the document has been opened through OpenPrintProcessor.
+ *
+ * @param hPrintProcessor
+ * The return value of a previous successful OpenPrintProcessor call.
+ *
+ * @param pDocumentName
+ * String in the format "Printer, Job N" describing the spooled job that is to be processed.
+ *
+ * @return
+ * TRUE if the document was successfully processed by this Print Processor, FALSE otherwise.
+ * A more specific error code can be obtained through GetLastError.
+ */
+BOOL WINAPI
+PrintDocumentOnPrintProcessor(HANDLE hPrintProcessor, PWSTR pDocumentName)
+{
+ DWORD dwErrorCode;
+ PWINPRINT_HANDLE pHandle;
+
+ TRACE("PrintDocumentOnPrintProcessor(%p, %S)\n", hPrintProcessor, pDocumentName);
+
+ // Sanity checks
+ if (!hPrintProcessor)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ pHandle = (PWINPRINT_HANDLE)hPrintProcessor;
+
+ // Call the corresponding Print function for the datatype.
+ if (pHandle->Datatype == RAW)
+ dwErrorCode = PrintRawJob(pHandle, pDocumentName);
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Standard Print Processor
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Precompiled Header for all source files
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#ifndef _PRECOMP_H
+#define _PRECOMP_H
+
+#define WIN32_NO_STATUS
+#include <stdlib.h>
+#include <windef.h>
+#include <winbase.h>
+#include <wingdi.h>
+#include <winreg.h>
+#include <winspool.h>
+#include <winsplp.h>
+
+#include <spoolss.h>
+
+#include <wine/debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(winprint);
+
+// Structures
+typedef struct _WINPRINT_HANDLE
+{
+ enum { RAW } Datatype;
+ DWORD dwJobID;
+ PWSTR pwszDatatype;
+ PWSTR pwszDocumentName;
+ PWSTR pwszOutputFile;
+ PWSTR pwszPrinterPort;
+}
+WINPRINT_HANDLE, *PWINPRINT_HANDLE;
+
+// raw.c
+DWORD PrintRawJob(PWINPRINT_HANDLE pHandle, PWSTR pwszPrinterAndJob);
+
+#endif
--- /dev/null
+/*
+ * PROJECT: ReactOS Standard Print Processor
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Printing a job with RAW datatype
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+/**
+ * @name PrintRawJob
+ *
+ * @param pHandle
+ * Pointer to a WINPRINT_HANDLE structure containing information about this job.
+ *
+ * @param pwszPrinterAndJob
+ * String in the format "Printer, Job N" that is passed to OpenPrinterW to read from the spooled print job.
+ *
+ * @return
+ * An error code indicating success or failure.
+ */
+DWORD
+PrintRawJob(PWINPRINT_HANDLE pHandle, PWSTR pwszPrinterAndJob)
+{
+ // Use a read buffer of 256 KB size like Windows does.
+ const DWORD cbReadBuffer = 262144;
+
+ BOOL bStartedDoc = FALSE;
+ DOC_INFO_1W DocInfo1;
+ DWORD cbRead;
+ DWORD cbWritten;
+ DWORD dwErrorCode;
+ HANDLE hPrintJob;
+ HANDLE hPrintMonitor;
+ PBYTE pBuffer = NULL;
+
+ // Open the spooled job to read from it.
+ if (!OpenPrinterW(pwszPrinterAndJob, &hPrintJob, NULL))
+ {
+ dwErrorCode = GetLastError();
+ ERR("OpenPrinterW failed for \"%S\" with error %lu!\n", pwszPrinterAndJob, GetLastError());
+ goto Cleanup;
+ }
+
+ // Open a Print Monitor handle to write to it.
+ if (!OpenPrinterW(pHandle->pwszPrinterPort, &hPrintMonitor, NULL))
+ {
+ dwErrorCode = GetLastError();
+ ERR("OpenPrinterW failed for \"%S\" with error %lu!\n", pHandle->pwszPrinterPort, GetLastError());
+ goto Cleanup;
+ }
+
+ // Fill the Document Information.
+ DocInfo1.pDatatype = pHandle->pwszDatatype;
+ DocInfo1.pDocName = pHandle->pwszDocumentName;
+ DocInfo1.pOutputFile = pHandle->pwszOutputFile;
+
+ // Tell the Print Monitor that we're starting a new document.
+ if (!StartDocPrinterW(hPrintMonitor, 1, (PBYTE)&DocInfo1))
+ {
+ dwErrorCode = GetLastError();
+ ERR("StartDocPrinterW failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ bStartedDoc = TRUE;
+
+ // Allocate a read buffer on the heap. This would easily exceed the stack size.
+ pBuffer = DllAllocSplMem(cbReadBuffer);
+ if (!pBuffer)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Loop as long as data is available.
+ while (ReadPrinter(hPrintJob, pBuffer, cbReadBuffer, &cbRead) && cbRead)
+ {
+ // Write it to the Print Monitor.
+ WritePrinter(hPrintMonitor, pBuffer, cbRead, &cbWritten);
+ }
+
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ if (pBuffer)
+ DllFreeSplMem(pBuffer);
+
+ if (bStartedDoc)
+ EndDocPrinter(hPrintMonitor);
+
+ if (hPrintMonitor)
+ ClosePrinter(hPrintMonitor);
+
+ if (hPrintJob)
+ ClosePrinter(hPrintJob);
+
+ return dwErrorCode;
+}
--- /dev/null
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Standard Print Processor"
+#define REACTOS_STR_INTERNAL_NAME "winprint"
+#define REACTOS_STR_ORIGINAL_FILENAME "winprint.dll"
+#include <reactos/version.rc>
--- /dev/null
+@ stdcall ClosePrintProcessor(long)
+@ stdcall ControlPrintProcessor(long long)
+@ stdcall EnumPrintProcessorDatatypesW(ptr ptr long ptr long ptr ptr)
+@ stdcall GetPrintProcessorCapabilities(wstr long ptr long ptr)
+@ stdcall OpenPrintProcessor(wstr ptr)
+@ stdcall PrintDocumentOnPrintProcessor(long wstr)
--- /dev/null
+#add_subdirectory(inetpp)
+add_subdirectory(localspl)
+#add_subdirectory(win32spl)
--- /dev/null
+
+spec2def(localspl.dll localspl.spec ADD_IMPORTLIB)
+
+include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/skiplist)
+
+list(APPEND SOURCE
+ jobs.c
+ main.c
+ monitors.c
+ ports.c
+ precomp.h
+ printers.c
+ printingthread.c
+ printprocessors.c
+ tools.c)
+
+add_library(localspl SHARED
+ ${SOURCE}
+ localspl.rc
+ ${CMAKE_CURRENT_BINARY_DIR}/localspl_stubs.c
+ ${CMAKE_CURRENT_BINARY_DIR}/localspl.def)
+
+set_module_type(localspl win32dll UNICODE)
+target_link_libraries(localspl skiplist16 wine)
+add_importlibs(localspl advapi32 rpcrt4 spoolss msvcrt kernel32 ntdll)
+add_pch(localspl precomp.h SOURCE)
+add_cd_file(TARGET localspl DESTINATION reactos/system32 FOR all)
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Spooler
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions for managing print jobs
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+// Global Variables
+SKIPLIST GlobalJobList;
+
+// Local Variables
+static DWORD _dwLastJobID;
+
+
+/**
+ * @name _EqualStrings
+ *
+ * Returns whether two strings are equal.
+ * Unlike wcscmp, this function also works with NULL strings.
+ *
+ * @param pwszA
+ * First string to compare.
+ *
+ * @param pwszB
+ * Second string to compare.
+ *
+ * @return
+ * TRUE if the strings are equal, FALSE if they differ.
+ */
+static __inline BOOL
+_EqualStrings(PCWSTR pwszA, PCWSTR pwszB)
+{
+ if (!pwszA && !pwszB)
+ return TRUE;
+
+ if (pwszA && !pwszB)
+ return FALSE;
+
+ if (!pwszA && pwszB)
+ return FALSE;
+
+ return (wcscmp(pwszA, pwszB) == 0);
+}
+
+static BOOL
+_GetNextJobID(PDWORD dwJobID)
+{
+ ++_dwLastJobID;
+
+ while (LookupElementSkiplist(&GlobalJobList, &_dwLastJobID, NULL))
+ {
+ // This ID is already taken. Try the next one.
+ ++_dwLastJobID;
+ }
+
+ if (!IS_VALID_JOB_ID(_dwLastJobID))
+ {
+ ERR("Job ID %lu isn't valid!\n", _dwLastJobID);
+ return FALSE;
+ }
+
+ *dwJobID = _dwLastJobID;
+ return TRUE;
+}
+
+/**
+ * @name _GlobalJobListCompareRoutine
+ *
+ * SKIPLIST_COMPARE_ROUTINE for the Global Job List.
+ * We need the Global Job List to check whether a Job ID is already in use. Consequently, this list is sorted by ID.
+ */
+static int WINAPI
+_GlobalJobListCompareRoutine(PVOID FirstStruct, PVOID SecondStruct)
+{
+ PLOCAL_JOB A = (PLOCAL_JOB)FirstStruct;
+ PLOCAL_JOB B = (PLOCAL_JOB)SecondStruct;
+
+ return A->dwJobID - B->dwJobID;
+}
+
+/**
+ * @name _PrinterJobListCompareRoutine
+ *
+ * SKIPLIST_COMPARE_ROUTINE for the each Printer's Job List.
+ * Jobs in this list are sorted in the desired order of processing.
+ */
+static int WINAPI
+_PrinterJobListCompareRoutine(PVOID FirstStruct, PVOID SecondStruct)
+{
+ PLOCAL_JOB A = (PLOCAL_JOB)FirstStruct;
+ PLOCAL_JOB B = (PLOCAL_JOB)SecondStruct;
+ int iComparison;
+ FILETIME ftSubmittedA;
+ FILETIME ftSubmittedB;
+ ULARGE_INTEGER uliSubmittedA;
+ ULARGE_INTEGER uliSubmittedB;
+ ULONGLONG ullResult;
+
+ // First compare the priorities to determine the order.
+ // The job with a higher priority shall come first.
+ iComparison = A->dwPriority - B->dwPriority;
+ if (iComparison != 0)
+ return iComparison;
+
+ // Both have the same priority, so go by creation time.
+ // Comparison is done using the MSDN-recommended way for comparing SYSTEMTIMEs.
+ if (!SystemTimeToFileTime(&A->stSubmitted, &ftSubmittedA))
+ {
+ ERR("SystemTimeToFileTime failed for A with error %lu!\n", GetLastError());
+ return 0;
+ }
+
+ if (!SystemTimeToFileTime(&B->stSubmitted, &ftSubmittedB))
+ {
+ ERR("SystemTimeToFileTime failed for B with error %lu!\n", GetLastError());
+ return 0;
+ }
+
+ uliSubmittedA.LowPart = ftSubmittedA.dwLowDateTime;
+ uliSubmittedA.HighPart = ftSubmittedA.dwHighDateTime;
+ uliSubmittedB.LowPart = ftSubmittedB.dwLowDateTime;
+ uliSubmittedB.HighPart = ftSubmittedB.dwHighDateTime;
+ ullResult = uliSubmittedA.QuadPart - uliSubmittedB.QuadPart;
+
+ if (ullResult < 0)
+ return -1;
+ else if (ullResult > 0)
+ return 1;
+
+ return 0;
+}
+
+DWORD
+GetJobFilePath(PCWSTR pwszExtension, DWORD dwJobID, PWSTR pwszOutput)
+{
+ const WCHAR wszPrintersPath[] = L"\\PRINTERS\\";
+ const DWORD cchPrintersPath = _countof(wszPrintersPath) - 1;
+ const DWORD cchSpoolerFile = sizeof("?????.") - 1;
+ const DWORD cchExtension = sizeof("SPL") - 1; // pwszExtension may be L"SPL" or L"SHD", same length for both!
+
+ if (pwszOutput)
+ {
+ CopyMemory(pwszOutput, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR));
+ CopyMemory(&pwszOutput[cchSpoolDirectory], wszPrintersPath, cchPrintersPath * sizeof(WCHAR));
+ swprintf(&pwszOutput[cchSpoolDirectory + cchPrintersPath], L"%05lu.", dwJobID);
+ CopyMemory(&pwszOutput[cchSpoolDirectory + cchPrintersPath + cchSpoolerFile], pwszExtension, (cchExtension + 1) * sizeof(WCHAR));
+ }
+
+ return (cchSpoolDirectory + cchPrintersPath + cchSpoolerFile + cchExtension + 1) * sizeof(WCHAR);
+}
+
+BOOL
+InitializeGlobalJobList()
+{
+ const WCHAR wszPath[] = L"\\PRINTERS\\?????.SHD";
+ const DWORD cchPath = _countof(wszPath) - 1;
+
+ DWORD dwErrorCode;
+ DWORD dwJobID;
+ HANDLE hFind;
+ PLOCAL_JOB pJob = NULL;
+ PWSTR p;
+ WCHAR wszFullPath[MAX_PATH];
+ WIN32_FIND_DATAW FindData;
+
+ // This one is incremented in _GetNextJobID.
+ _dwLastJobID = 0;
+
+ // Initialize an empty list for all jobs of all local printers.
+ // We will search it by Job ID (supply a pointer to a DWORD in LookupElementSkiplist).
+ InitializeSkiplist(&GlobalJobList, DllAllocSplMem, _GlobalJobListCompareRoutine, (PSKIPLIST_FREE_ROUTINE)DllFreeSplMem);
+
+ // Construct the full path search pattern.
+ CopyMemory(wszFullPath, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR));
+ CopyMemory(&wszFullPath[cchSpoolDirectory], wszPath, (cchPath + 1) * sizeof(WCHAR));
+
+ // Use the search pattern to look for unfinished jobs serialized in shadow files (.SHD)
+ hFind = FindFirstFileW(wszFullPath, &FindData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ // No unfinished jobs found.
+ dwErrorCode = ERROR_SUCCESS;
+ goto Cleanup;
+ }
+
+ do
+ {
+ // Skip possible subdirectories.
+ if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ continue;
+
+ // Extract the Job ID and verify the file name format at the same time.
+ // This includes all valid names (like "00005.SHD") and excludes invalid ones (like "10ABC.SHD").
+ dwJobID = wcstoul(FindData.cFileName, &p, 10);
+ if (!IS_VALID_JOB_ID(dwJobID))
+ continue;
+
+ if (wcsicmp(p, L".SHD") != 0)
+ continue;
+
+ // This shadow file has a valid name. Construct the full path and try to load it.
+ GetJobFilePath(L"SHD", dwJobID, wszFullPath);
+ pJob = ReadJobShadowFile(wszFullPath);
+ if (!pJob)
+ continue;
+
+ // Add it to the Global Job List.
+ if (!InsertElementSkiplist(&GlobalJobList, pJob))
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("InsertElementSkiplist failed for job %lu for the GlobalJobList!\n", pJob->dwJobID);
+ goto Cleanup;
+ }
+
+ // Add it to the Printer's Job List.
+ if (!InsertElementSkiplist(&pJob->pPrinter->JobList, pJob))
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("InsertElementSkiplist failed for job %lu for the Printer's Job List!\n", pJob->dwJobID);
+ goto Cleanup;
+ }
+ }
+ while (FindNextFileW(hFind, &FindData));
+
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ // Outside the loop
+ if (hFind)
+ FindClose(hFind);
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+void
+InitializePrinterJobList(PLOCAL_PRINTER pPrinter)
+{
+ // Initialize an empty list for this printer's jobs.
+ // This one is only for sorting the jobs. If you need to lookup a job, search the GlobalJobList by Job ID.
+ InitializeSkiplist(&pPrinter->JobList, DllAllocSplMem, _PrinterJobListCompareRoutine, (PSKIPLIST_FREE_ROUTINE)DllFreeSplMem);
+}
+
+DWORD WINAPI
+CreateJob(PLOCAL_PRINTER_HANDLE pPrinterHandle)
+{
+ const WCHAR wszDoubleBackslash[] = L"\\";
+ const DWORD cchDoubleBackslash = _countof(wszDoubleBackslash) - 1;
+
+ DWORD cchMachineName;
+ DWORD cchUserName;
+ DWORD dwErrorCode;
+ PLOCAL_JOB pJob;
+ RPC_BINDING_HANDLE hServerBinding = NULL;
+ RPC_WSTR pwszBinding = NULL;
+ RPC_WSTR pwszMachineName = NULL;
+
+ // Create a new job.
+ pJob = DllAllocSplMem(sizeof(LOCAL_JOB));
+ if (!pJob)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Reserve an ID for this job.
+ if (!_GetNextJobID(&pJob->dwJobID))
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ // Copy over defaults to the LOCAL_JOB structure.
+ pJob->pPrinter = pPrinterHandle->pPrinter;
+ pJob->pPrintProcessor = pPrinterHandle->pPrinter->pPrintProcessor;
+ pJob->dwPriority = DEF_PRIORITY;
+ pJob->dwStatus = JOB_STATUS_SPOOLING;
+ pJob->pwszDatatype = AllocSplStr(pPrinterHandle->pwszDatatype);
+ pJob->pwszDocumentName = AllocSplStr(wszDefaultDocumentName);
+ pJob->pDevMode = DuplicateDevMode(pPrinterHandle->pDevMode);
+ GetSystemTime(&pJob->stSubmitted);
+
+ // Get the user name for the Job.
+ cchUserName = UNLEN + 1;
+ pJob->pwszUserName = DllAllocSplMem(cchUserName * sizeof(WCHAR));
+ if (!GetUserNameW(pJob->pwszUserName, &cchUserName))
+ {
+ dwErrorCode = GetLastError();
+ ERR("GetUserNameW failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // FIXME: For now, pwszNotifyName equals pwszUserName.
+ pJob->pwszNotifyName = AllocSplStr(pJob->pwszUserName);
+
+ // Get the name of the machine that submitted the Job over RPC.
+ dwErrorCode = RpcBindingServerFromClient(NULL, &hServerBinding);
+ if (dwErrorCode != RPC_S_OK)
+ {
+ ERR("RpcBindingServerFromClient failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ dwErrorCode = RpcBindingToStringBindingW(hServerBinding, &pwszBinding);
+ if (dwErrorCode != RPC_S_OK)
+ {
+ ERR("RpcBindingToStringBindingW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ dwErrorCode = RpcStringBindingParseW(pwszBinding, NULL, NULL, &pwszMachineName, NULL, NULL);
+ if (dwErrorCode != RPC_S_OK)
+ {
+ ERR("RpcStringBindingParseW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ cchMachineName = wcslen(pwszMachineName);
+ pJob->pwszMachineName = DllAllocSplMem((cchMachineName + cchDoubleBackslash + 1) * sizeof(WCHAR));
+ CopyMemory(pJob->pwszMachineName, wszDoubleBackslash, cchDoubleBackslash * sizeof(WCHAR));
+ CopyMemory(&pJob->pwszMachineName[cchDoubleBackslash], pwszMachineName, (cchMachineName + 1) * sizeof(WCHAR));
+
+ // Add the job to the Global Job List.
+ if (!InsertElementSkiplist(&GlobalJobList, pJob))
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("InsertElementSkiplist failed for job %lu for the GlobalJobList!\n", pJob->dwJobID);
+ goto Cleanup;
+ }
+
+ // Add the job at the end of the Printer's Job List.
+ // As all new jobs are created with default priority, we can be sure that it would always be inserted at the end.
+ if (!InsertTailElementSkiplist(&pJob->pPrinter->JobList, pJob))
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("InsertTailElementSkiplist failed for job %lu for the Printer's Job List!\n", pJob->dwJobID);
+ goto Cleanup;
+ }
+
+ // We were successful!
+ pPrinterHandle->bStartedDoc = TRUE;
+ pPrinterHandle->pJob = pJob;
+ dwErrorCode = ERROR_SUCCESS;
+
+ // Don't let the cleanup routine free this.
+ pJob = NULL;
+
+Cleanup:
+ if (pJob)
+ DllFreeSplMem(pJob);
+
+ if (pwszMachineName)
+ RpcStringFreeW(&pwszMachineName);
+
+ if (pwszBinding)
+ RpcStringFreeW(&pwszBinding);
+
+ if (hServerBinding)
+ RpcBindingFree(&hServerBinding);
+
+ return dwErrorCode;
+}
+
+BOOL WINAPI
+LocalAddJob(HANDLE hPrinter, DWORD Level, PBYTE pData, DWORD cbBuf, PDWORD pcbNeeded)
+{
+ ADDJOB_INFO_1W AddJobInfo1;
+ DWORD dwErrorCode;
+ PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
+ PLOCAL_PRINTER_HANDLE pPrinterHandle;
+
+ // Check if this is a printer handle.
+ if (pHandle->HandleType != HandleType_Printer)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
+
+ // This handle must not have started a job yet!
+ if (pPrinterHandle->pJob)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Check if this is the right structure level.
+ if (Level != 1)
+ {
+ dwErrorCode = ERROR_INVALID_LEVEL;
+ goto Cleanup;
+ }
+
+ // Check if the printer is set to do direct printing.
+ // The Job List isn't used in this case.
+ if (pPrinterHandle->pPrinter->dwAttributes & PRINTER_ATTRIBUTE_DIRECT)
+ {
+ dwErrorCode = ERROR_INVALID_ACCESS;
+ goto Cleanup;
+ }
+
+ // Check if the supplied buffer is large enough.
+ *pcbNeeded = sizeof(ADDJOB_INFO_1W) + GetJobFilePath(L"SPL", 0, NULL);
+ if (cbBuf < *pcbNeeded)
+ {
+ dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
+ goto Cleanup;
+ }
+
+ // All requirements are met - create a new job.
+ dwErrorCode = CreateJob(pPrinterHandle);
+ if (dwErrorCode != ERROR_SUCCESS)
+ goto Cleanup;
+
+ // Mark that this job was started with AddJob (so that it can be scheduled for printing with ScheduleJob).
+ pPrinterHandle->pJob->bAddedJob = TRUE;
+
+ // Return a proper ADDJOB_INFO_1W structure.
+ AddJobInfo1.JobId = pPrinterHandle->pJob->dwJobID;
+ AddJobInfo1.Path = (PWSTR)(pData + sizeof(ADDJOB_INFO_1W));
+
+ CopyMemory(pData, &AddJobInfo1, sizeof(ADDJOB_INFO_1W));
+ GetJobFilePath(L"SPL", AddJobInfo1.JobId, AddJobInfo1.Path);
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+
+static DWORD
+_LocalGetJobLevel1(PLOCAL_PRINTER_HANDLE pPrinterHandle, PLOCAL_JOB pJob, PBYTE* ppStart, PBYTE* ppEnd, DWORD cbBuf, PDWORD pcbNeeded)
+{
+ DWORD cbDatatype = (wcslen(pJob->pwszDatatype) + 1) * sizeof(WCHAR);
+ DWORD cbDocumentName = 0;
+ DWORD cbMachineName = (wcslen(pJob->pwszMachineName) + 1) * sizeof(WCHAR);
+ DWORD cbPrinterName = (wcslen(pJob->pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
+ DWORD cbStatus = 0;
+ DWORD cbUserName = 0;
+ DWORD dwErrorCode;
+ JOB_INFO_1W JobInfo1 = { 0 };
+
+ // Calculate the lengths of the optional values.
+ if (pJob->pwszDocumentName)
+ cbDocumentName = (wcslen(pJob->pwszDocumentName) + 1) * sizeof(WCHAR);
+
+ if (pJob->pwszStatus)
+ cbStatus = (wcslen(pJob->pwszStatus) + 1) * sizeof(WCHAR);
+
+ if (pJob->pwszUserName)
+ cbUserName = (wcslen(pJob->pwszUserName) + 1) * sizeof(WCHAR);
+
+ // Check if the supplied buffer is large enough.
+ *pcbNeeded += sizeof(JOB_INFO_1W) + cbDatatype + cbDocumentName + cbMachineName + cbPrinterName + cbStatus + cbUserName;
+ if (cbBuf < *pcbNeeded)
+ {
+ dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
+ goto Cleanup;
+ }
+
+ // Put the strings at the end of the buffer.
+ *ppEnd -= cbDatatype;
+ JobInfo1.pDatatype = (PWSTR)*ppEnd;
+ CopyMemory(*ppEnd, pJob->pwszDatatype, cbDatatype);
+
+ *ppEnd -= cbMachineName;
+ JobInfo1.pMachineName = (PWSTR)*ppEnd;
+ CopyMemory(*ppEnd, pJob->pwszMachineName, cbMachineName);
+
+ *ppEnd -= cbPrinterName;
+ JobInfo1.pPrinterName = (PWSTR)*ppEnd;
+ CopyMemory(*ppEnd, pJob->pPrinter->pwszPrinterName, cbPrinterName);
+
+ // Copy the optional values.
+ if (cbDocumentName)
+ {
+ *ppEnd -= cbDocumentName;
+ JobInfo1.pDocument = (PWSTR)*ppEnd;
+ CopyMemory(*ppEnd, pJob->pwszDocumentName, cbDocumentName);
+ }
+
+ if (cbStatus)
+ {
+ *ppEnd -= cbStatus;
+ JobInfo1.pStatus = (PWSTR)*ppEnd;
+ CopyMemory(*ppEnd, pJob->pwszStatus, cbStatus);
+ }
+
+ if (cbUserName)
+ {
+ *ppEnd -= cbUserName;
+ JobInfo1.pUserName = (PWSTR)*ppEnd;
+ CopyMemory(*ppEnd, pJob->pwszUserName, cbUserName);
+ }
+
+ // Fill the rest of the structure.
+ JobInfo1.JobId = pJob->dwJobID;
+ JobInfo1.Priority = pJob->dwPriority;
+ JobInfo1.Status = pJob->dwStatus;
+ JobInfo1.TotalPages = pJob->dwTotalPages;
+ CopyMemory(&JobInfo1.Submitted, &pJob->stSubmitted, sizeof(SYSTEMTIME));
+
+ // Finally copy the structure to the output pointer.
+ CopyMemory(*ppStart, &JobInfo1, sizeof(JOB_INFO_1W));
+ *ppStart += sizeof(JOB_INFO_1W);
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ return dwErrorCode;
+}
+
+static DWORD
+_LocalGetJobLevel2(PLOCAL_PRINTER_HANDLE pPrinterHandle, PLOCAL_JOB pJob, PBYTE* ppStart, PBYTE* ppEnd, DWORD cbBuf, PDWORD pcbNeeded)
+{
+ DWORD cbDatatype = (wcslen(pJob->pwszDatatype) + 1) * sizeof(WCHAR);
+ DWORD cbDevMode = pJob->pDevMode->dmSize + pJob->pDevMode->dmDriverExtra;
+ DWORD cbDocumentName = 0;
+ DWORD cbDriverName = (wcslen(pJob->pPrinter->pwszPrinterDriver) + 1) * sizeof(WCHAR);
+ DWORD cbMachineName = (wcslen(pJob->pwszMachineName) + 1) * sizeof(WCHAR);
+ DWORD cbNotifyName = 0;
+ DWORD cbPrinterName = (wcslen(pJob->pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
+ DWORD cbPrintProcessor = (wcslen(pJob->pPrintProcessor->pwszName) + 1) * sizeof(WCHAR);
+ DWORD cbPrintProcessorParameters = 0;
+ DWORD cbStatus = 0;
+ DWORD cbUserName = 0;
+ DWORD dwErrorCode;
+ FILETIME ftNow;
+ FILETIME ftSubmitted;
+ JOB_INFO_2W JobInfo2 = { 0 };
+ ULARGE_INTEGER uliNow;
+ ULARGE_INTEGER uliSubmitted;
+
+ // Calculate the lengths of the optional values.
+ if (pJob->pwszDocumentName)
+ cbDocumentName = (wcslen(pJob->pwszDocumentName) + 1) * sizeof(WCHAR);
+
+ if (pJob->pwszNotifyName)
+ cbNotifyName = (wcslen(pJob->pwszNotifyName) + 1) * sizeof(WCHAR);
+
+ if (pJob->pwszPrintProcessorParameters)
+ cbPrintProcessorParameters = (wcslen(pJob->pwszPrintProcessorParameters) + 1) * sizeof(WCHAR);
+
+ if (pJob->pwszStatus)
+ cbStatus = (wcslen(pJob->pwszStatus) + 1) * sizeof(WCHAR);
+
+ if (pJob->pwszUserName)
+ cbUserName = (wcslen(pJob->pwszUserName) + 1) * sizeof(WCHAR);
+
+ // Check if the supplied buffer is large enough.
+ *pcbNeeded += sizeof(JOB_INFO_2W) + cbDatatype + cbDevMode + cbDocumentName + cbDriverName + cbMachineName + cbNotifyName + cbPrinterName + cbPrintProcessor + cbPrintProcessorParameters + cbStatus + cbUserName;
+ if (cbBuf < *pcbNeeded)
+ {
+ dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
+ goto Cleanup;
+ }
+
+ // Put the strings at the end of the buffer.
+ *ppEnd -= cbDatatype;
+ JobInfo2.pDatatype = (PWSTR)*ppEnd;
+ CopyMemory(*ppEnd, pJob->pwszDatatype, cbDatatype);
+
+ *ppEnd -= cbDevMode;
+ JobInfo2.pDevMode = (PDEVMODEW)*ppEnd;
+ CopyMemory(*ppEnd, pJob->pDevMode, cbDevMode);
+
+ *ppEnd -= cbDriverName;
+ JobInfo2.pDriverName = (PWSTR)*ppEnd;
+ CopyMemory(*ppEnd, pJob->pPrinter->pwszPrinterDriver, cbDriverName);
+
+ *ppEnd -= cbMachineName;
+ JobInfo2.pMachineName = (PWSTR)*ppEnd;
+ CopyMemory(*ppEnd, pJob->pwszMachineName, cbMachineName);
+
+ *ppEnd -= cbPrinterName;
+ JobInfo2.pPrinterName = (PWSTR)*ppEnd;
+ CopyMemory(*ppEnd, pJob->pPrinter->pwszPrinterName, cbPrinterName);
+
+ *ppEnd -= cbPrintProcessor;
+ JobInfo2.pPrintProcessor = (PWSTR)*ppEnd;
+ CopyMemory(*ppEnd, pJob->pPrintProcessor->pwszName, cbPrintProcessor);
+
+ // Copy the optional values.
+ if (cbDocumentName)
+ {
+ *ppEnd -= cbDocumentName;
+ JobInfo2.pDocument = (PWSTR)*ppEnd;
+ CopyMemory(*ppEnd, pJob->pwszDocumentName, cbDocumentName);
+ }
+
+ if (cbNotifyName)
+ {
+ *ppEnd -= cbNotifyName;
+ JobInfo2.pNotifyName = (PWSTR)*ppEnd;
+ CopyMemory(*ppEnd, pJob->pwszNotifyName, cbNotifyName);
+ }
+
+ if (cbPrintProcessorParameters)
+ {
+ *ppEnd -= cbPrintProcessorParameters;
+ JobInfo2.pParameters = (PWSTR)*ppEnd;
+ CopyMemory(*ppEnd, pJob->pwszPrintProcessorParameters, cbPrintProcessorParameters);
+ }
+
+ if (cbStatus)
+ {
+ *ppEnd -= cbStatus;
+ JobInfo2.pStatus = (PWSTR)*ppEnd;
+ CopyMemory(*ppEnd, pJob->pwszStatus, cbStatus);
+ }
+
+ if (cbUserName)
+ {
+ *ppEnd -= cbUserName;
+ JobInfo2.pUserName = (PWSTR)*ppEnd;
+ CopyMemory(*ppEnd, pJob->pwszUserName, cbUserName);
+ }
+
+ // Time in JOB_INFO_2W is the number of milliseconds elapsed since the job was submitted. Calculate this time.
+ if (!SystemTimeToFileTime(&pJob->stSubmitted, &ftSubmitted))
+ {
+ ERR("SystemTimeToFileTime failed with error %lu!\n", GetLastError());
+ return FALSE;
+ }
+
+ GetSystemTimeAsFileTime(&ftNow);
+ uliSubmitted.LowPart = ftSubmitted.dwLowDateTime;
+ uliSubmitted.HighPart = ftSubmitted.dwHighDateTime;
+ uliNow.LowPart = ftNow.dwLowDateTime;
+ uliNow.HighPart = ftNow.dwHighDateTime;
+ JobInfo2.Time = (DWORD)((uliNow.QuadPart - uliSubmitted.QuadPart) / 10000);
+
+ // Position in JOB_INFO_2W is the 1-based index of the job in the processing queue.
+ // Retrieve this through the element index of the job in the Printer's Job List.
+ if (!LookupElementSkiplist(&pJob->pPrinter->JobList, pJob, &JobInfo2.Position))
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("pJob could not be located in the Printer's Job List!\n");
+ goto Cleanup;
+ }
+
+ // Make the index 1-based.
+ ++JobInfo2.Position;
+
+ // Fill the rest of the structure.
+ JobInfo2.JobId = pJob->dwJobID;
+ JobInfo2.PagesPrinted = pJob->dwPagesPrinted;
+ JobInfo2.Priority = pJob->dwPriority;
+ JobInfo2.StartTime = pJob->dwStartTime;
+ JobInfo2.Status = pJob->dwStatus;
+ JobInfo2.TotalPages = pJob->dwTotalPages;
+ JobInfo2.UntilTime = pJob->dwUntilTime;
+ CopyMemory(&JobInfo2.Submitted, &pJob->stSubmitted, sizeof(SYSTEMTIME));
+
+ // Finally copy the structure to the output pointer.
+ CopyMemory(*ppStart, &JobInfo2, sizeof(JOB_INFO_2W));
+ *ppStart += sizeof(JOB_INFO_2W);
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ return dwErrorCode;
+}
+
+BOOL WINAPI
+LocalGetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pStart, DWORD cbBuf, LPDWORD pcbNeeded)
+{
+ DWORD dwErrorCode;
+ PBYTE pEnd = &pStart[cbBuf];
+ PLOCAL_HANDLE pHandle;
+ PLOCAL_JOB pJob;
+ PLOCAL_PRINTER_HANDLE pPrinterHandle;
+
+ // Check if this is a printer handle.
+ pHandle = (PLOCAL_HANDLE)hPrinter;
+ if (pHandle->HandleType != HandleType_Printer)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
+
+ // Get the desired job.
+ pJob = LookupElementSkiplist(&GlobalJobList, &JobId, NULL);
+ if (!pJob || pJob->pPrinter != pPrinterHandle->pPrinter)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // Begin counting.
+ *pcbNeeded = 0;
+
+ // The function behaves differently for each level.
+ if (Level == 1)
+ dwErrorCode = _LocalGetJobLevel1(pPrinterHandle, pJob, &pStart, &pEnd, cbBuf, pcbNeeded);
+ else if (Level == 2)
+ dwErrorCode = _LocalGetJobLevel2(pPrinterHandle, pJob, &pStart, &pEnd, cbBuf, pcbNeeded);
+ else
+ dwErrorCode = ERROR_INVALID_LEVEL;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+static DWORD
+_LocalSetJobLevel1(PLOCAL_PRINTER_HANDLE pPrinterHandle, PLOCAL_JOB pJob, PJOB_INFO_1W pJobInfo)
+{
+ DWORD dwErrorCode;
+
+ // First check the validity of the input before changing anything.
+ if (!FindDatatype(pJob->pPrintProcessor, pJobInfo->pDatatype))
+ {
+ dwErrorCode = ERROR_INVALID_DATATYPE;
+ goto Cleanup;
+ }
+
+ // Check if the datatype has changed.
+ if (!_EqualStrings(pJob->pwszDatatype, pJobInfo->pDatatype))
+ {
+ // Use the new value.
+ if (!ReallocSplStr(&pJob->pwszDatatype, pJobInfo->pDatatype))
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+ }
+
+ // Check if the document name has changed. An empty string is permitted here!
+ if (!_EqualStrings(pJob->pwszDocumentName, pJobInfo->pDocument))
+ {
+ // Use the new value.
+ if (!ReallocSplStr(&pJob->pwszDocumentName, pJobInfo->pDocument))
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+ }
+
+ // Check if the status message has changed. An empty string is permitted here!
+ if (!_EqualStrings(pJob->pwszStatus, pJobInfo->pStatus))
+ {
+ // Use the new value.
+ if (!ReallocSplStr(&pJob->pwszStatus, pJobInfo->pStatus))
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+ }
+
+ // Check if the user name has changed. An empty string is permitted here!
+ if (!_EqualStrings(pJob->pwszUserName, pJobInfo->pUserName) != 0)
+ {
+ // The new user name doesn't need to exist, so no additional verification is required.
+
+ // Use the new value.
+ if (!ReallocSplStr(&pJob->pwszUserName, pJobInfo->pUserName))
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+ }
+
+ // Check if the priority has changed.
+ if (pJob->dwPriority != pJobInfo->Priority && IS_VALID_PRIORITY(pJobInfo->Priority))
+ {
+ // Set the new priority.
+ pJob->dwPriority = pJobInfo->Priority;
+
+ // Remove and reinsert the job in the Printer's Job List.
+ // The Compare function will be used to find the right position now considering the new priority.
+ DeleteElementSkiplist(&pJob->pPrinter->JobList, pJob);
+ InsertElementSkiplist(&pJob->pPrinter->JobList, pJob);
+ }
+
+ // Check if the status flags have changed.
+ if (pJob->dwStatus != pJobInfo->Status)
+ {
+ // Only add status flags that make sense.
+ if (pJobInfo->Status & JOB_STATUS_PAUSED)
+ pJob->dwStatus |= JOB_STATUS_PAUSED;
+
+ if (pJobInfo->Status & JOB_STATUS_ERROR)
+ pJob->dwStatus |= JOB_STATUS_ERROR;
+
+ if (pJobInfo->Status & JOB_STATUS_OFFLINE)
+ pJob->dwStatus |= JOB_STATUS_OFFLINE;
+
+ if (pJobInfo->Status & JOB_STATUS_PAPEROUT)
+ pJob->dwStatus |= JOB_STATUS_PAPEROUT;
+ }
+
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ return dwErrorCode;
+}
+
+static DWORD
+_LocalSetJobLevel2(PLOCAL_PRINTER_HANDLE pPrinterHandle, PLOCAL_JOB pJob, PJOB_INFO_2W pJobInfo)
+{
+ DWORD dwErrorCode;
+ PLOCAL_PRINT_PROCESSOR pPrintProcessor;
+
+ // First check the validity of the input before changing anything.
+ pPrintProcessor = FindPrintProcessor(pJobInfo->pPrintProcessor);
+ if (!pPrintProcessor)
+ {
+ dwErrorCode = ERROR_UNKNOWN_PRINTPROCESSOR;
+ goto Cleanup;
+ }
+
+ if (!FindDatatype(pPrintProcessor, pJobInfo->pDatatype))
+ {
+ dwErrorCode = ERROR_INVALID_DATATYPE;
+ goto Cleanup;
+ }
+
+ // Check if the datatype has changed.
+ if (!_EqualStrings(pJob->pwszDatatype, pJobInfo->pDatatype))
+ {
+ // Use the new value.
+ if (!ReallocSplStr(&pJob->pwszDatatype, pJobInfo->pDatatype))
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+ }
+
+ // Check if the document name has changed. An empty string is permitted here!
+ if (!_EqualStrings(pJob->pwszDocumentName, pJobInfo->pDocument))
+ {
+ // Use the new value.
+ if (!ReallocSplStr(&pJob->pwszDocumentName, pJobInfo->pDocument))
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+ }
+
+ // Check if the notify name has changed. An empty string is permitted here!
+ if (!_EqualStrings(pJob->pwszNotifyName, pJobInfo->pNotifyName))
+ {
+ // The new notify name doesn't need to exist, so no additional verification is required.
+
+ // Use the new value.
+ if (!ReallocSplStr(&pJob->pwszNotifyName, pJobInfo->pNotifyName))
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+ }
+
+ // Check if the Print Processor Parameters have changed. An empty string is permitted here!
+ if (!_EqualStrings(pJob->pwszPrintProcessorParameters, pJobInfo->pParameters))
+ {
+ // Use the new value.
+ if (!ReallocSplStr(&pJob->pwszPrintProcessorParameters, pJobInfo->pParameters))
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+ }
+
+ // Check if the Status Message has changed. An empty string is permitted here!
+ if (!_EqualStrings(pJob->pwszStatus, pJobInfo->pStatus))
+ {
+ // Use the new value.
+ if (!ReallocSplStr(&pJob->pwszStatus, pJobInfo->pStatus))
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+ }
+
+ // Check if the user name has changed. An empty string is permitted here!
+ if (!_EqualStrings(pJob->pwszUserName, pJobInfo->pUserName))
+ {
+ // The new user name doesn't need to exist, so no additional verification is required.
+
+ // Use the new value.
+ if (!ReallocSplStr(&pJob->pwszUserName, pJobInfo->pUserName))
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+ }
+
+ // Check if the priority has changed.
+ if (pJob->dwPriority != pJobInfo->Priority && IS_VALID_PRIORITY(pJobInfo->Priority))
+ {
+ // Set the new priority.
+ pJob->dwPriority = pJobInfo->Priority;
+
+ // Remove and reinsert the job in the Printer's Job List.
+ // The Compare function will be used to find the right position now considering the new priority.
+ DeleteElementSkiplist(&pJob->pPrinter->JobList, pJob);
+ InsertElementSkiplist(&pJob->pPrinter->JobList, pJob);
+ }
+
+ // Check if the status flags have changed.
+ if (pJob->dwStatus != pJobInfo->Status)
+ {
+ // Only add status flags that make sense.
+ if (pJobInfo->Status & JOB_STATUS_PAUSED)
+ pJob->dwStatus |= JOB_STATUS_PAUSED;
+
+ if (pJobInfo->Status & JOB_STATUS_ERROR)
+ pJob->dwStatus |= JOB_STATUS_ERROR;
+
+ if (pJobInfo->Status & JOB_STATUS_OFFLINE)
+ pJob->dwStatus |= JOB_STATUS_OFFLINE;
+
+ if (pJobInfo->Status & JOB_STATUS_PAPEROUT)
+ pJob->dwStatus |= JOB_STATUS_PAPEROUT;
+ }
+
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ return dwErrorCode;
+}
+
+BOOL WINAPI
+LocalSetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command)
+{
+ DWORD dwErrorCode;
+ PLOCAL_HANDLE pHandle;
+ PLOCAL_JOB pJob;
+ PLOCAL_PRINTER_HANDLE pPrinterHandle;
+ WCHAR wszFullPath[MAX_PATH];
+
+ // Check if this is a printer handle.
+ pHandle = (PLOCAL_HANDLE)hPrinter;
+ if (pHandle->HandleType != HandleType_Printer)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
+
+ // Get the desired job.
+ pJob = LookupElementSkiplist(&GlobalJobList, &JobId, NULL);
+ if (!pJob || pJob->pPrinter != pPrinterHandle->pPrinter)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // Setting job information is handled differently for each level.
+ if (Level)
+ {
+ if (Level == 1)
+ dwErrorCode = _LocalSetJobLevel1(pPrinterHandle, pJob, (PJOB_INFO_1W)pJobInfo);
+ else if (Level == 2)
+ dwErrorCode = _LocalSetJobLevel2(pPrinterHandle, pJob, (PJOB_INFO_2W)pJobInfo);
+ else
+ dwErrorCode = ERROR_INVALID_LEVEL;
+ }
+
+ if (dwErrorCode != ERROR_SUCCESS)
+ goto Cleanup;
+
+ // If we do spooled printing, the job information is written down into a shadow file.
+ if (!(pPrinterHandle->pPrinter->dwAttributes & PRINTER_ATTRIBUTE_DIRECT))
+ {
+ // Write the job data into the shadow file.
+ GetJobFilePath(L"SHD", JobId, wszFullPath);
+ WriteJobShadowFile(wszFullPath, pJob);
+ }
+
+ // Perform an additional command if desired.
+ if (Command)
+ {
+ if (Command == JOB_CONTROL_SENT_TO_PRINTER)
+ {
+ // This indicates the end of the Print Job.
+
+ // Cancel the Job at the Print Processor.
+ if (pJob->hPrintProcessor)
+ pJob->pPrintProcessor->pfnControlPrintProcessor(pJob->hPrintProcessor, JOB_CONTROL_CANCEL);
+
+ FreeJob(pJob);
+
+ // TODO: All open handles associated with the job need to be invalidated.
+ // This certainly needs handle tracking...
+ }
+ else
+ {
+ ERR("Unimplemented SetJob Command: %lu!\n", Command);
+ }
+ }
+
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+LocalEnumJobs(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pStart, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
+{
+ DWORD dwErrorCode;
+ DWORD i;
+ PBYTE pEnd = &pStart[cbBuf];
+ PLOCAL_HANDLE pHandle;
+ PLOCAL_JOB pJob;
+ PSKIPLIST_NODE pFirstJobNode;
+ PSKIPLIST_NODE pNode;
+ PLOCAL_PRINTER_HANDLE pPrinterHandle;
+
+ // Check if this is a printer handle.
+ pHandle = (PLOCAL_HANDLE)hPrinter;
+ if (pHandle->HandleType != HandleType_Printer)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
+
+ // Check the level.
+ if (Level > 2)
+ {
+ dwErrorCode = ERROR_INVALID_LEVEL;
+ goto Cleanup;
+ }
+
+ // Begin counting.
+ *pcbNeeded = 0;
+ *pcReturned = 0;
+
+ // Lookup the node of the first job requested by the caller in the Printer's Job List.
+ pFirstJobNode = LookupNodeByIndexSkiplist(&pPrinterHandle->pPrinter->JobList, FirstJob);
+
+ // Count the required buffer size and the number of jobs.
+ i = 0;
+ pNode = pFirstJobNode;
+
+ while (i < NoJobs && pNode)
+ {
+ pJob = (PLOCAL_JOB)pNode->Element;
+
+ // The function behaves differently for each level.
+ if (Level == 1)
+ _LocalGetJobLevel1(pPrinterHandle, pJob, NULL, NULL, 0, pcbNeeded);
+ else if (Level == 2)
+ _LocalGetJobLevel2(pPrinterHandle, pJob, NULL, NULL, 0, pcbNeeded);
+
+ // We stop either when there are no more jobs in the list or when the caller didn't request more, whatever comes first.
+ i++;
+ pNode = pNode->Next[0];
+ }
+
+ // Check if the supplied buffer is large enough.
+ if (cbBuf < *pcbNeeded)
+ {
+ dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
+ goto Cleanup;
+ }
+
+ // Begin counting again and also empty the given buffer.
+ *pcbNeeded = 0;
+ ZeroMemory(pStart, cbBuf);
+
+ // Now call the same functions again to copy the actual data for each job into the buffer.
+ i = 0;
+ pNode = pFirstJobNode;
+
+ while (i < NoJobs && pNode)
+ {
+ pJob = (PLOCAL_JOB)pNode->Element;
+
+ // The function behaves differently for each level.
+ if (Level == 1)
+ dwErrorCode = _LocalGetJobLevel1(pPrinterHandle, pJob, &pStart, &pEnd, cbBuf, pcbNeeded);
+ else if (Level == 2)
+ dwErrorCode = _LocalGetJobLevel2(pPrinterHandle, pJob, &pStart, &pEnd, cbBuf, pcbNeeded);
+
+ if (dwErrorCode != ERROR_SUCCESS)
+ goto Cleanup;
+
+ // We stop either when there are no more jobs in the list or when the caller didn't request more, whatever comes first.
+ i++;
+ pNode = pNode->Next[0];
+ }
+
+ *pcReturned = i;
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+LocalScheduleJob(HANDLE hPrinter, DWORD dwJobID)
+{
+ DWORD dwAttributes;
+ DWORD dwErrorCode;
+ HANDLE hThread;
+ PLOCAL_JOB pJob;
+ PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
+ PLOCAL_PRINTER_HANDLE pPrinterHandle;
+ WCHAR wszFullPath[MAX_PATH];
+
+ // Check if this is a printer handle.
+ if (pHandle->HandleType != HandleType_Printer)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
+
+ // Check if the Job ID is valid.
+ pJob = LookupElementSkiplist(&GlobalJobList, &dwJobID, NULL);
+ if (!pJob || pJob->pPrinter != pPrinterHandle->pPrinter)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // Check if this Job was started with AddJob.
+ if (!pJob->bAddedJob)
+ {
+ dwErrorCode = ERROR_SPL_NO_ADDJOB;
+ goto Cleanup;
+ }
+
+ // Construct the full path to the spool file.
+ GetJobFilePath(L"SPL", dwJobID, wszFullPath);
+
+ // Check if it exists.
+ dwAttributes = GetFileAttributesW(wszFullPath);
+ if (dwAttributes == INVALID_FILE_ATTRIBUTES || dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ dwErrorCode = ERROR_SPOOL_FILE_NOT_FOUND;
+ goto Cleanup;
+ }
+
+ // Spooling is finished at this point.
+ pJob->dwStatus &= ~JOB_STATUS_SPOOLING;
+
+ // Write the job data into the shadow file.
+ wcscpy(wcsrchr(wszFullPath, L'.'), L".SHD");
+ WriteJobShadowFile(wszFullPath, pJob);
+
+ // Create the thread for performing the printing process.
+ hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PrintingThreadProc, pJob, 0, NULL);
+ if (!hThread)
+ {
+ dwErrorCode = GetLastError();
+ ERR("CreateThread failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // We don't need the thread handle. Keeping it open blocks the thread from terminating.
+ CloseHandle(hThread);
+
+ // ScheduleJob has done its job. The rest happens inside the thread.
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+PLOCAL_JOB
+ReadJobShadowFile(PCWSTR pwszFilePath)
+{
+ DWORD cbFileSize;
+ DWORD cbRead;
+ HANDLE hFile = INVALID_HANDLE_VALUE;
+ PLOCAL_JOB pJob;
+ PLOCAL_JOB pReturnValue = NULL;
+ PLOCAL_PRINTER pPrinter;
+ PLOCAL_PRINT_PROCESSOR pPrintProcessor;
+ PSHD_HEADER pShadowFile = NULL;
+ PWSTR pwszPrinterName;
+ PWSTR pwszPrintProcessor;
+
+ // Try to open the file.
+ hFile = CreateFileW(pwszFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ ERR("CreateFileW failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath);
+ goto Cleanup;
+ }
+
+ // Get its file size (small enough for a single DWORD) and allocate memory for all of it.
+ cbFileSize = GetFileSize(hFile, NULL);
+ pShadowFile = DllAllocSplMem(cbFileSize);
+ if (!pShadowFile)
+ {
+ ERR("DllAllocSplMem failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath);
+ goto Cleanup;
+ }
+
+ // Read the entire file.
+ if (!ReadFile(hFile, pShadowFile, cbFileSize, &cbRead, NULL))
+ {
+ ERR("ReadFile failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath);
+ goto Cleanup;
+ }
+
+ // Check signature and header size.
+ if (pShadowFile->dwSignature != SHD_WIN2003_SIGNATURE || pShadowFile->cbHeader != sizeof(SHD_HEADER))
+ {
+ ERR("Signature or Header Size mismatch for file \"%S\"!\n", pwszFilePath);
+ goto Cleanup;
+ }
+
+ // Retrieve the associated printer from the list.
+ pwszPrinterName = (PWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offPrinterName);
+ pPrinter = LookupElementSkiplist(&PrinterList, &pwszPrinterName, NULL);
+ if (!pPrinter)
+ {
+ ERR("Shadow file \"%S\" references a non-existing printer \"%S\"!\n", pwszFilePath, pwszPrinterName);
+ goto Cleanup;
+ }
+
+ // Retrieve the associated Print Processor from the list.
+ pwszPrintProcessor = (PWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offPrintProcessor);
+ pPrintProcessor = FindPrintProcessor(pwszPrintProcessor);
+ if (!pPrintProcessor)
+ {
+ ERR("Shadow file \"%S\" references a non-existing Print Processor \"%S\"!\n", pwszFilePath, pwszPrintProcessor);
+ goto Cleanup;
+ }
+
+ // Create a new job structure and copy over the relevant fields.
+ pJob = DllAllocSplMem(sizeof(LOCAL_JOB));
+ if (!pJob)
+ {
+ ERR("DllAllocSplMem failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath);
+ goto Cleanup;
+ }
+
+ pJob->dwJobID = pShadowFile->dwJobID;
+ pJob->dwPriority = pShadowFile->dwPriority;
+ pJob->dwStartTime = pShadowFile->dwStartTime;
+ pJob->dwTotalPages = pShadowFile->dwTotalPages;
+ pJob->dwUntilTime = pShadowFile->dwUntilTime;
+ pJob->pPrinter = pPrinter;
+ pJob->pPrintProcessor = pPrintProcessor;
+ pJob->pDevMode = DuplicateDevMode((PDEVMODEW)((ULONG_PTR)pShadowFile + pShadowFile->offDevMode));
+ pJob->pwszDatatype = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offDatatype));
+ pJob->pwszMachineName = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offMachineName));
+ CopyMemory(&pJob->stSubmitted, &pShadowFile->stSubmitted, sizeof(SYSTEMTIME));
+
+ // Copy the optional values.
+ if (pShadowFile->offDocumentName)
+ pJob->pwszDocumentName = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offDocumentName));
+
+ if (pShadowFile->offNotifyName)
+ pJob->pwszNotifyName = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offNotifyName));
+
+ if (pShadowFile->offPrintProcessorParameters)
+ pJob->pwszPrintProcessorParameters = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offPrintProcessorParameters));
+
+ if (pShadowFile->offUserName)
+ pJob->pwszUserName = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offUserName));
+
+ // Jobs read from shadow files were always added using AddJob.
+ pJob->bAddedJob = TRUE;
+
+ pReturnValue = pJob;
+
+Cleanup:
+ if (pShadowFile)
+ DllFreeSplMem(pShadowFile);
+
+ if (hFile != INVALID_HANDLE_VALUE)
+ CloseHandle(hFile);
+
+ return pReturnValue;
+}
+
+BOOL
+WriteJobShadowFile(PWSTR pwszFilePath, const PLOCAL_JOB pJob)
+{
+ BOOL bReturnValue = FALSE;
+ DWORD cbDatatype = (wcslen(pJob->pwszDatatype) + 1) * sizeof(WCHAR);
+ DWORD cbDevMode = pJob->pDevMode->dmSize + pJob->pDevMode->dmDriverExtra;
+ DWORD cbDocumentName = 0;
+ DWORD cbFileSize;
+ DWORD cbMachineName = (wcslen(pJob->pwszMachineName) + 1) * sizeof(WCHAR);
+ DWORD cbNotifyName = 0;
+ DWORD cbPrinterDriver = (wcslen(pJob->pPrinter->pwszPrinterDriver) + 1) * sizeof(WCHAR);
+ DWORD cbPrinterName = (wcslen(pJob->pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
+ DWORD cbPrintProcessor = (wcslen(pJob->pPrintProcessor->pwszName) + 1) * sizeof(WCHAR);
+ DWORD cbPrintProcessorParameters = 0;
+ DWORD cbUserName = 0;
+ DWORD cbWritten;
+ DWORD dwCurrentOffset;
+ HANDLE hSHDFile = INVALID_HANDLE_VALUE;
+ HANDLE hSPLFile = INVALID_HANDLE_VALUE;
+ PSHD_HEADER pShadowFile = NULL;
+
+ // Try to open the SHD file.
+ hSHDFile = CreateFileW(pwszFilePath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
+ if (hSHDFile == INVALID_HANDLE_VALUE)
+ {
+ ERR("CreateFileW failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath);
+ goto Cleanup;
+ }
+
+ // Calculate the lengths of the optional values and the total size of the shadow file.
+ if (pJob->pwszDocumentName)
+ cbDocumentName = (wcslen(pJob->pwszDocumentName) + 1) * sizeof(WCHAR);
+
+ if (pJob->pwszNotifyName)
+ cbNotifyName = (wcslen(pJob->pwszNotifyName) + 1) * sizeof(WCHAR);
+
+ if (pJob->pwszPrintProcessorParameters)
+ cbPrintProcessorParameters = (wcslen(pJob->pwszPrintProcessorParameters) + 1) * sizeof(WCHAR);
+
+ if (pJob->pwszUserName)
+ cbUserName = (wcslen(pJob->pwszUserName) + 1) * sizeof(WCHAR);
+
+ cbFileSize = sizeof(SHD_HEADER) + cbDatatype + cbDocumentName + cbDevMode + cbMachineName + cbNotifyName + cbPrinterDriver + cbPrinterName + cbPrintProcessor + cbPrintProcessorParameters + cbUserName;
+
+ // Allocate memory for it.
+ pShadowFile = DllAllocSplMem(cbFileSize);
+ if (!pShadowFile)
+ {
+ ERR("DllAllocSplMem failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath);
+ goto Cleanup;
+ }
+
+ // Fill out the shadow file header information.
+ pShadowFile->dwSignature = SHD_WIN2003_SIGNATURE;
+ pShadowFile->cbHeader = sizeof(SHD_HEADER);
+
+ // Copy the values.
+ pShadowFile->dwJobID = pJob->dwJobID;
+ pShadowFile->dwPriority = pJob->dwPriority;
+ pShadowFile->dwStartTime = pJob->dwStartTime;
+ pShadowFile->dwTotalPages = pJob->dwTotalPages;
+ pShadowFile->dwUntilTime = pJob->dwUntilTime;
+ CopyMemory(&pShadowFile->stSubmitted, &pJob->stSubmitted, sizeof(SYSTEMTIME));
+
+ // Determine the file size of the .SPL file
+ wcscpy(wcsrchr(pwszFilePath, L'.'), L".SPL");
+ hSPLFile = CreateFileW(pwszFilePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+ if (hSPLFile != INVALID_HANDLE_VALUE)
+ pShadowFile->dwSPLSize = GetFileSize(hSPLFile, NULL);
+
+ // Add the extra values that are stored as offsets in the shadow file.
+ // The first value begins right after the shadow file header.
+ dwCurrentOffset = sizeof(SHD_HEADER);
+
+ CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszDatatype, cbDatatype);
+ pShadowFile->offDatatype = dwCurrentOffset;
+ dwCurrentOffset += cbDatatype;
+
+ CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pDevMode, cbDevMode);
+ pShadowFile->offDevMode = dwCurrentOffset;
+ dwCurrentOffset += cbDevMode;
+
+ // offDriverName is only written, but automatically determined through offPrinterName when reading.
+ CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pPrinter->pwszPrinterDriver, cbPrinterDriver);
+ pShadowFile->offDriverName = dwCurrentOffset;
+ dwCurrentOffset += cbPrinterDriver;
+
+ CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszMachineName, cbMachineName);
+ pShadowFile->offMachineName = dwCurrentOffset;
+ dwCurrentOffset += cbMachineName;
+
+ CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pPrinter->pwszPrinterName, cbPrinterName);
+ pShadowFile->offPrinterName = dwCurrentOffset;
+ dwCurrentOffset += cbPrinterName;
+
+ CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pPrintProcessor->pwszName, cbPrintProcessor);
+ pShadowFile->offPrintProcessor = dwCurrentOffset;
+ dwCurrentOffset += cbPrintProcessor;
+
+ // Copy the optional values.
+ if (cbDocumentName)
+ {
+ CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszDocumentName, cbDocumentName);
+ pShadowFile->offDocumentName = dwCurrentOffset;
+ dwCurrentOffset += cbDocumentName;
+ }
+
+ if (cbNotifyName)
+ {
+ CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszNotifyName, cbNotifyName);
+ pShadowFile->offNotifyName = dwCurrentOffset;
+ dwCurrentOffset += cbNotifyName;
+ }
+
+ if (cbPrintProcessorParameters)
+ {
+ CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszPrintProcessorParameters, cbPrintProcessorParameters);
+ pShadowFile->offPrintProcessorParameters = dwCurrentOffset;
+ dwCurrentOffset += cbPrintProcessorParameters;
+ }
+
+ if (cbUserName)
+ {
+ CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszUserName, cbUserName);
+ pShadowFile->offUserName = dwCurrentOffset;
+ dwCurrentOffset += cbUserName;
+ }
+
+ // Write the file.
+ if (!WriteFile(hSHDFile, pShadowFile, cbFileSize, &cbWritten, NULL))
+ {
+ ERR("WriteFile failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath);
+ goto Cleanup;
+ }
+
+ bReturnValue = TRUE;
+
+Cleanup:
+ if (pShadowFile)
+ DllFreeSplMem(pShadowFile);
+
+ if (hSHDFile != INVALID_HANDLE_VALUE)
+ CloseHandle(hSHDFile);
+
+ if (hSPLFile != INVALID_HANDLE_VALUE)
+ CloseHandle(hSPLFile);
+
+ return bReturnValue;
+}
+
+void
+FreeJob(PLOCAL_JOB pJob)
+{
+ PWSTR pwszSHDFile;
+
+ // Remove the Job from both Job Lists.
+ DeleteElementSkiplist(&pJob->pPrinter->JobList, pJob);
+ DeleteElementSkiplist(&GlobalJobList, pJob);
+
+ // Try to delete the corresponding .SHD file.
+ pwszSHDFile = DllAllocSplMem(GetJobFilePath(L"SHD", 0, NULL));
+ if (pwszSHDFile && GetJobFilePath(L"SHD", pJob->dwJobID, pwszSHDFile))
+ DeleteFileW(pwszSHDFile);
+
+ // Free memory for the mandatory fields.
+ DllFreeSplMem(pJob->pDevMode);
+ DllFreeSplStr(pJob->pwszDatatype);
+ DllFreeSplStr(pJob->pwszDocumentName);
+ DllFreeSplStr(pJob->pwszMachineName);
+ DllFreeSplStr(pJob->pwszNotifyName);
+ DllFreeSplStr(pJob->pwszUserName);
+
+ // Free memory for the optional fields if they are present.
+ if (pJob->pwszOutputFile)
+ DllFreeSplStr(pJob->pwszOutputFile);
+
+ if (pJob->pwszPrintProcessorParameters)
+ DllFreeSplStr(pJob->pwszPrintProcessorParameters);
+
+ if (pJob->pwszStatus)
+ DllFreeSplStr(pJob->pwszStatus);
+
+ // Finally free the job structure itself.
+ DllFreeSplMem(pJob);
+}
--- /dev/null
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Local Spooler"
+#define REACTOS_STR_INTERNAL_NAME "localspl"
+#define REACTOS_STR_ORIGINAL_FILENAME "localspl.dll"
+#include <reactos/version.rc>
--- /dev/null
+@ stdcall InitializePrintProvidor(ptr long ptr)
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Spooler
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Main functions
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+// Global Variables
+WCHAR wszSpoolDirectory[MAX_PATH];
+DWORD cchSpoolDirectory;
+
+// Global Constants
+const WCHAR wszCurrentEnvironment[] =
+#if defined(_X86_)
+ L"Windows NT x86";
+#elif defined(_AMD64_)
+ L"Windows x64";
+#elif defined(_ARM_)
+ L"Windows ARM";
+#else
+ #error Unsupported architecture
+#endif
+
+const DWORD cbCurrentEnvironment = sizeof(wszCurrentEnvironment);
+
+const WCHAR wszDefaultDocumentName[] = L"Local Downlevel Document";
+
+const WCHAR* wszPrintProviderInfo[3] = {
+ L"Windows NT Local Print Providor", // Name
+ L"Windows NT Local Printers", // Description
+ L"Locally connected Printers" // Comment
+};
+
+// Local Constants
+static const PRINTPROVIDOR _PrintProviderFunctions = {
+ LocalOpenPrinter, // fpOpenPrinter
+ LocalSetJob, // fpSetJob
+ LocalGetJob, // fpGetJob
+ LocalEnumJobs, // fpEnumJobs
+ NULL, // fpAddPrinter
+ NULL, // fpDeletePrinter
+ NULL, // fpSetPrinter
+ NULL, // fpGetPrinter
+ LocalEnumPrinters, // fpEnumPrinters
+ NULL, // fpAddPrinterDriver
+ NULL, // fpEnumPrinterDrivers
+ NULL, // fpGetPrinterDriver
+ NULL, // fpGetPrinterDriverDirectory
+ NULL, // fpDeletePrinterDriver
+ NULL, // fpAddPrintProcessor
+ LocalEnumPrintProcessors, // fpEnumPrintProcessors
+ LocalGetPrintProcessorDirectory, // fpGetPrintProcessorDirectory
+ NULL, // fpDeletePrintProcessor
+ LocalEnumPrintProcessorDatatypes, // fpEnumPrintProcessorDatatypes
+ LocalStartDocPrinter, // fpStartDocPrinter
+ LocalStartPagePrinter, // fpStartPagePrinter
+ LocalWritePrinter, // fpWritePrinter
+ LocalEndPagePrinter, // fpEndPagePrinter
+ NULL, // fpAbortPrinter
+ LocalReadPrinter, // fpReadPrinter
+ LocalEndDocPrinter, // fpEndDocPrinter
+ LocalAddJob, // fpAddJob
+ LocalScheduleJob, // fpScheduleJob
+ NULL, // fpGetPrinterData
+ NULL, // fpSetPrinterData
+ NULL, // fpWaitForPrinterChange
+ LocalClosePrinter, // fpClosePrinter
+ NULL, // fpAddForm
+ NULL, // fpDeleteForm
+ NULL, // fpGetForm
+ NULL, // fpSetForm
+ NULL, // fpEnumForms
+ LocalEnumMonitors, // fpEnumMonitors
+ LocalEnumPorts, // fpEnumPorts
+ NULL, // fpAddPort
+ NULL, // fpConfigurePort
+ NULL, // fpDeletePort
+ NULL, // fpCreatePrinterIC
+ NULL, // fpPlayGdiScriptOnPrinterIC
+ NULL, // fpDeletePrinterIC
+ NULL, // fpAddPrinterConnection
+ NULL, // fpDeletePrinterConnection
+ NULL, // fpPrinterMessageBox
+ NULL, // fpAddMonitor
+ NULL, // fpDeleteMonitor
+ NULL, // fpResetPrinter
+ NULL, // fpGetPrinterDriverEx
+ NULL, // fpFindFirstPrinterChangeNotification
+ NULL, // fpFindClosePrinterChangeNotification
+ NULL, // fpAddPortEx
+ NULL, // fpShutDown
+ NULL, // fpRefreshPrinterChangeNotification
+ NULL, // fpOpenPrinterEx
+ NULL, // fpAddPrinterEx
+ NULL, // fpSetPort
+ NULL, // fpEnumPrinterData
+ NULL, // fpDeletePrinterData
+ NULL, // fpClusterSplOpen
+ NULL, // fpClusterSplClose
+ NULL, // fpClusterSplIsAlive
+ NULL, // fpSetPrinterDataEx
+ NULL, // fpGetPrinterDataEx
+ NULL, // fpEnumPrinterDataEx
+ NULL, // fpEnumPrinterKey
+ NULL, // fpDeletePrinterDataEx
+ NULL, // fpDeletePrinterKey
+ NULL, // fpSeekPrinter
+ NULL, // fpDeletePrinterDriverEx
+ NULL, // fpAddPerMachineConnection
+ NULL, // fpDeletePerMachineConnection
+ NULL, // fpEnumPerMachineConnections
+ NULL, // fpXcvData
+ NULL, // fpAddPrinterDriverEx
+ NULL, // fpSplReadPrinter
+ NULL, // fpDriverUnloadComplete
+ NULL, // fpGetSpoolFileInfo
+ NULL, // fpCommitSpoolData
+ NULL, // fpCloseSpoolFileHandle
+ NULL, // fpFlushPrinter
+ NULL, // fpSendRecvBidiData
+ NULL, // fpAddDriverCatalog
+};
+
+static void
+_GetSpoolDirectory()
+{
+ const WCHAR wszSpoolPath[] = L"\\spool";
+ 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...
+ cchSpoolDirectory = GetSystemDirectoryW(wszSpoolDirectory, MAX_PATH);
+ CopyMemory(&wszSpoolDirectory[cchSpoolDirectory], wszSpoolPath, (cchSpoolPath + 1) * sizeof(WCHAR));
+ cchSpoolDirectory += cchSpoolPath;
+}
+
+BOOL WINAPI
+DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ DisableThreadLibraryCalls(hinstDLL);
+ _GetSpoolDirectory();
+
+ return InitializePrintMonitorList() &&
+ InitializePortList() &&
+ InitializePrintProcessorList() &&
+ InitializePrinterList() &&
+ InitializeGlobalJobList();
+
+ default:
+ return TRUE;
+ }
+}
+
+BOOL WINAPI
+InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor, DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
+{
+ CopyMemory(pPrintProvidor, &_PrintProviderFunctions, min(cbPrintProvidor, sizeof(PRINTPROVIDOR)));
+
+ SetLastError(ERROR_SUCCESS);
+ return TRUE;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Spooler
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Print Monitors
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+// Global Variables
+LIST_ENTRY PrintMonitorList;
+
+
+PLOCAL_PRINT_MONITOR
+FindPrintMonitor(PCWSTR pwszName)
+{
+ PLIST_ENTRY pEntry;
+ PLOCAL_PRINT_MONITOR pPrintMonitor;
+
+ if (!pwszName)
+ return NULL;
+
+ for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
+ {
+ pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
+
+ if (_wcsicmp(pPrintMonitor->pwszName, pwszName) == 0)
+ return pPrintMonitor;
+ }
+
+ return NULL;
+}
+
+BOOL
+InitializePrintMonitorList()
+{
+ const WCHAR wszMonitorsPath[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors";
+ const DWORD cchMonitorsPath = _countof(wszMonitorsPath) - 1;
+
+ DWORD cchMaxSubKey;
+ DWORD cchPrintMonitorName;
+ DWORD dwErrorCode;
+ DWORD dwSubKeys;
+ DWORD i;
+ HINSTANCE hinstPrintMonitor = NULL;
+ HKEY hKey = NULL;
+ HKEY hSubKey = NULL;
+ MONITORINIT MonitorInit;
+ PInitializePrintMonitor pfnInitializePrintMonitor;
+ PInitializePrintMonitor2 pfnInitializePrintMonitor2;
+ PLOCAL_PRINT_MONITOR pPrintMonitor = NULL;
+ PWSTR pwszRegistryPath = NULL;
+
+ // Initialize an empty list for our Print Monitors.
+ InitializeListHead(&PrintMonitorList);
+
+ // Open the key containing Print Monitors.
+ dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszMonitorsPath, 0, KEY_READ, &hKey);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Get the number of Print Providers and maximum sub key length.
+ dwErrorCode = (DWORD)RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &dwSubKeys, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Loop through all available Print Providers.
+ for (i = 0; i < dwSubKeys; i++)
+ {
+ // Cleanup tasks from the previous run
+ if (hSubKey)
+ {
+ RegCloseKey(hSubKey);
+ hSubKey = NULL;
+ }
+
+ if (pwszRegistryPath)
+ {
+ DllFreeSplMem(pwszRegistryPath);
+ pwszRegistryPath = NULL;
+ }
+
+ if (pPrintMonitor)
+ {
+ if (pPrintMonitor->pwszFileName)
+ DllFreeSplMem(pPrintMonitor->pwszFileName);
+
+ if (pPrintMonitor->pwszName)
+ DllFreeSplMem(pPrintMonitor->pwszName);
+
+ DllFreeSplMem(pPrintMonitor);
+ pPrintMonitor = NULL;
+ }
+
+ // Create a new LOCAL_PRINT_MONITOR structure for it.
+ pPrintMonitor = DllAllocSplMem(sizeof(LOCAL_PRINT_MONITOR));
+ if (!pPrintMonitor)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Allocate memory for the Print Monitor Name.
+ pPrintMonitor->pwszName = DllAllocSplMem((cchMaxSubKey + 1) * sizeof(WCHAR));
+ if (!pPrintMonitor->pwszName)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Get the name of this Print Monitor.
+ cchPrintMonitorName = cchMaxSubKey + 1;
+ dwErrorCode = (DWORD)RegEnumKeyExW(hKey, i, pPrintMonitor->pwszName, &cchPrintMonitorName, NULL, NULL, NULL, NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegEnumKeyExW failed for iteration %lu with status %lu!\n", i, dwErrorCode);
+ continue;
+ }
+
+ // Open this Print Monitor's registry key.
+ dwErrorCode = (DWORD)RegOpenKeyExW(hKey, pPrintMonitor->pwszName, 0, KEY_READ, &hSubKey);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegOpenKeyExW failed for Print Provider \"%S\" with status %lu!\n", pPrintMonitor->pwszName, dwErrorCode);
+ continue;
+ }
+
+ // Get the file name of the Print Monitor.
+ pPrintMonitor->pwszFileName = AllocAndRegQueryWSZ(hSubKey, L"Driver");
+ if (!pPrintMonitor->pwszFileName)
+ continue;
+
+ // Try to load it.
+ hinstPrintMonitor = LoadLibraryW(pPrintMonitor->pwszFileName);
+ if (!hinstPrintMonitor)
+ {
+ ERR("LoadLibraryW failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
+ continue;
+ }
+
+ // Try to find a Level 2 initialization routine first.
+ pfnInitializePrintMonitor2 = (PInitializePrintMonitor2)GetProcAddress(hinstPrintMonitor, "InitializePrintMonitor2");
+ if (pfnInitializePrintMonitor2)
+ {
+ // Prepare a MONITORINIT structure.
+ MonitorInit.cbSize = sizeof(MONITORINIT);
+ MonitorInit.bLocal = TRUE;
+
+ // TODO: Fill the other fields.
+
+ // Call the Level 2 initialization routine.
+ pPrintMonitor->pMonitor = (PMONITOR2)pfnInitializePrintMonitor2(&MonitorInit, &pPrintMonitor->hMonitor);
+ if (!pPrintMonitor->pMonitor)
+ {
+ ERR("InitializePrintMonitor2 failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
+ continue;
+ }
+
+ pPrintMonitor->bIsLevel2 = TRUE;
+ }
+ else
+ {
+ // Try to find a Level 1 initialization routine then.
+ pfnInitializePrintMonitor = (PInitializePrintMonitor)GetProcAddress(hinstPrintMonitor, "InitializePrintMonitor");
+ if (pfnInitializePrintMonitor)
+ {
+ // Construct the registry path.
+ pwszRegistryPath = DllAllocSplMem((cchMonitorsPath + 1 + cchPrintMonitorName + 1) * sizeof(WCHAR));
+ if (!pwszRegistryPath)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ CopyMemory(pwszRegistryPath, wszMonitorsPath, cchMonitorsPath * sizeof(WCHAR));
+ pwszRegistryPath[cchMonitorsPath] = L'\\';
+ CopyMemory(&pwszRegistryPath[cchMonitorsPath + 1], pPrintMonitor->pwszName, (cchPrintMonitorName + 1) * sizeof(WCHAR));
+
+ // Call the Level 1 initialization routine.
+ pPrintMonitor->pMonitor = (LPMONITOREX)pfnInitializePrintMonitor(pwszRegistryPath);
+ if (!pPrintMonitor->pMonitor)
+ {
+ ERR("InitializePrintMonitor failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
+ continue;
+ }
+ }
+ else
+ {
+ ERR("No initialization routine found for \"%S\"!\n", pPrintMonitor->pwszFileName);
+ continue;
+ }
+ }
+
+ // Add this Print Monitor to the list.
+ InsertTailList(&PrintMonitorList, &pPrintMonitor->Entry);
+
+ // Don't let the cleanup routine free this.
+ pPrintMonitor = NULL;
+ }
+
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ // Inside the loop
+ if (hSubKey)
+ RegCloseKey(hSubKey);
+
+ if (pwszRegistryPath)
+ DllFreeSplMem(pwszRegistryPath);
+
+ if (pPrintMonitor)
+ {
+ if (pPrintMonitor->pwszFileName)
+ DllFreeSplMem(pPrintMonitor->pwszFileName);
+
+ if (pPrintMonitor->pwszName)
+ DllFreeSplMem(pPrintMonitor->pwszName);
+
+ DllFreeSplMem(pPrintMonitor);
+ }
+
+ // Outside the loop
+ if (hKey)
+ RegCloseKey(hKey);
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+LocalEnumMonitors(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ DWORD cbFileName;
+ DWORD cbMonitorName;
+ DWORD dwErrorCode;
+ PBYTE pStart;
+ PBYTE pEnd;
+ PLIST_ENTRY pEntry;
+ PLOCAL_PRINT_MONITOR pPrintMonitor;
+ MONITOR_INFO_2W MonitorInfo2; // MONITOR_INFO_1W is a subset of MONITOR_INFO_2W, so we can handle both in one function here.
+
+ // Sanity checks.
+ if (Level > 2)
+ {
+ dwErrorCode = ERROR_INVALID_LEVEL;
+ goto Cleanup;
+ }
+
+ if ((cbBuf && !pMonitors) || !pcbNeeded || !pcReturned)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // Begin counting.
+ *pcbNeeded = 0;
+ *pcReturned = 0;
+
+ // Count the required buffer size and the number of monitors.
+ for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
+ {
+ pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
+
+ cbMonitorName = (wcslen(pPrintMonitor->pwszName) + 1) * sizeof(WCHAR);
+ cbFileName = (wcslen(pPrintMonitor->pwszFileName) + 1) * sizeof(WCHAR);
+
+ if (Level == 1)
+ *pcbNeeded += sizeof(MONITOR_INFO_1W) + cbMonitorName;
+ else
+ *pcbNeeded += sizeof(MONITOR_INFO_2W) + cbMonitorName + cbCurrentEnvironment + cbFileName;
+ }
+
+ // Check if the supplied buffer is large enough.
+ if (cbBuf < *pcbNeeded)
+ {
+ dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
+ goto Cleanup;
+ }
+
+ // Put the strings at the end of the buffer.
+ pStart = pMonitors;
+ pEnd = &pMonitors[cbBuf];
+
+ for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
+ {
+ pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
+
+ // Copy the monitor name.
+ cbMonitorName = (wcslen(pPrintMonitor->pwszName) + 1) * sizeof(WCHAR);
+ pEnd -= cbMonitorName;
+ MonitorInfo2.pName = (PWSTR)pEnd;
+ CopyMemory(pEnd, pPrintMonitor->pwszName, cbMonitorName);
+
+ if (Level == 1)
+ {
+ // Finally copy the structure.
+ CopyMemory(pStart, &MonitorInfo2, sizeof(MONITOR_INFO_1W));
+ pStart += sizeof(MONITOR_INFO_1W);
+ }
+ else
+ {
+ // Copy the environment.
+ pEnd -= cbCurrentEnvironment;
+ MonitorInfo2.pEnvironment = (PWSTR)pEnd;
+ CopyMemory(pEnd, wszCurrentEnvironment, cbCurrentEnvironment);
+
+ // Copy the file name.
+ cbFileName = (wcslen(pPrintMonitor->pwszFileName) + 1) * sizeof(WCHAR);
+ pEnd -= cbFileName;
+ MonitorInfo2.pDLLName = (PWSTR)pEnd;
+ CopyMemory(pEnd, pPrintMonitor->pwszFileName, cbFileName);
+
+ // Finally copy the structure.
+ CopyMemory(pStart, &MonitorInfo2, sizeof(MONITOR_INFO_2W));
+ pStart += sizeof(MONITOR_INFO_2W);
+ }
+
+ (*pcReturned)++;
+ }
+
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Spooler
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Ports of the Print Monitors
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+// Local Variables
+static LIST_ENTRY _PortList;
+
+
+PLOCAL_PORT
+FindPort(PCWSTR pwszName)
+{
+ PLIST_ENTRY pEntry;
+ PLOCAL_PORT pPort;
+
+ if (!pwszName)
+ return NULL;
+
+ for (pEntry = _PortList.Flink; pEntry != &_PortList; pEntry = pEntry->Flink)
+ {
+ pPort = CONTAINING_RECORD(pEntry, LOCAL_PORT, Entry);
+
+ if (_wcsicmp(pPort->pwszName, pwszName) == 0)
+ return pPort;
+ }
+
+ return NULL;
+}
+
+BOOL
+InitializePortList()
+{
+ BOOL bReturnValue;
+ DWORD cbNeeded;
+ DWORD cbPortName;
+ DWORD dwErrorCode;
+ DWORD dwReturned;
+ DWORD i;
+ PLOCAL_PORT pPort;
+ PLOCAL_PRINT_MONITOR pPrintMonitor;
+ PLIST_ENTRY pEntry;
+ PPORT_INFO_1W p;
+ PPORT_INFO_1W pPortInfo1 = NULL;
+
+ // Initialize an empty list for our Ports.
+ InitializeListHead(&_PortList);
+
+ // Loop through all Print Monitors.
+ for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
+ {
+ // Cleanup from the previous run.
+ if (pPortInfo1)
+ {
+ DllFreeSplMem(pPortInfo1);
+ pPortInfo1 = NULL;
+ }
+
+ pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
+
+ // Determine the required buffer size for EnumPorts.
+ if (pPrintMonitor->bIsLevel2)
+ bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnEnumPorts(pPrintMonitor->hMonitor, NULL, 1, NULL, 0, &cbNeeded, &dwReturned);
+ else
+ bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnEnumPorts(NULL, 1, NULL, 0, &cbNeeded, &dwReturned);
+
+ // Check the returned error code.
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+ ERR("Print Monitor \"%S\" failed with error %lu on EnumPorts!\n", pPrintMonitor->pwszName, GetLastError());
+ continue;
+ }
+
+ // Allocate a buffer large enough.
+ pPortInfo1 = DllAllocSplMem(cbNeeded);
+ if (!pPortInfo1)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Get the ports handled by this monitor.
+ if (pPrintMonitor->bIsLevel2)
+ bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnEnumPorts(pPrintMonitor->hMonitor, NULL, 1, (PBYTE)pPortInfo1, cbNeeded, &cbNeeded, &dwReturned);
+ else
+ bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnEnumPorts(NULL, 1, (PBYTE)pPortInfo1, cbNeeded, &cbNeeded, &dwReturned);
+
+ // Check the return value.
+ if (!bReturnValue)
+ {
+ ERR("Print Monitor \"%S\" failed with error %lu on EnumPorts!\n", pPrintMonitor->pwszName, GetLastError());
+ continue;
+ }
+
+ // Loop through all returned ports.
+ p = pPortInfo1;
+
+ for (i = 0; i < dwReturned; i++)
+ {
+ cbPortName = (wcslen(p->pName) + 1) * sizeof(WCHAR);
+
+ // Create a new LOCAL_PORT structure for it.
+ pPort = DllAllocSplMem(sizeof(LOCAL_PORT) + cbPortName);
+ if (!pPort)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ pPort->pPrintMonitor = pPrintMonitor;
+ pPort->pwszName = (PWSTR)((PBYTE)pPort + sizeof(LOCAL_PORT));
+ CopyMemory(pPort->pwszName, p->pName, cbPortName);
+
+ // Insert it into the list and advance to the next port.
+ InsertTailList(&_PortList, &pPort->Entry);
+ p++;
+ }
+ }
+
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ // Inside the loop
+ if (pPortInfo1)
+ DllFreeSplMem(pPortInfo1);
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+LocalEnumPorts(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+ BOOL bReturnValue;
+ DWORD cbCallBuffer;
+ DWORD cbNeeded;
+ DWORD dwReturned;
+ PBYTE pCallBuffer;
+ PLOCAL_PRINT_MONITOR pPrintMonitor;
+ PLIST_ENTRY pEntry;
+
+ // Sanity checks.
+ if ((cbBuf && !pPorts) || !pcbNeeded || !pcReturned)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ // Begin counting.
+ *pcbNeeded = 0;
+ *pcReturned = 0;
+
+ // At the beginning, we have the full buffer available.
+ cbCallBuffer = cbBuf;
+ pCallBuffer = pPorts;
+
+ // Loop through all Print Monitors.
+ for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
+ {
+ pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
+
+ // Call the EnumPorts function of this Print Monitor.
+ if (pPrintMonitor->bIsLevel2)
+ bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnEnumPorts(pPrintMonitor->hMonitor, pName, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
+ else
+ bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnEnumPorts(pName, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
+
+ // Add the returned counts to the total values.
+ *pcbNeeded += cbNeeded;
+ *pcReturned += dwReturned;
+
+ // Reduce the available buffer size for the next call without risking an underflow.
+ if (cbNeeded < cbCallBuffer)
+ cbCallBuffer -= cbNeeded;
+ else
+ cbCallBuffer = 0;
+
+ // Advance the buffer if the caller provided it.
+ if (pCallBuffer)
+ pCallBuffer += cbNeeded;
+ }
+
+ return bReturnValue;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Spooler
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Precompiled Header for all source files
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#ifndef _PRECOMP_H
+#define _PRECOMP_H
+
+#define WIN32_NO_STATUS
+#include <limits.h>
+#include <stdlib.h>
+#include <wchar.h>
+
+#include <lmcons.h>
+#include <rpc.h>
+#include <windef.h>
+#include <winbase.h>
+#include <wingdi.h>
+#include <winreg.h>
+#include <winspool.h>
+#include <winsplp.h>
+#include <ndk/rtlfuncs.h>
+
+#define SKIPLIST_LEVELS 16
+#include <skiplist.h>
+#include <spoolss.h>
+
+#include <wine/debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(localspl);
+
+// Macros
+#define IS_VALID_JOB_ID(ID) (ID >= 1 && ID <= 99999)
+#define IS_VALID_PRIORITY(P) (P >= MIN_PRIORITY && P <= MAX_PRIORITY)
+
+// Constants
+#define MAX_PRINTER_NAME 220
+#define SHD_WIN2003_SIGNATURE 0x4968
+
+// Function pointers
+typedef BOOL (WINAPI *PClosePrintProcessor)(HANDLE);
+typedef BOOL (WINAPI *PControlPrintProcessor)(HANDLE, DWORD);
+typedef BOOL (WINAPI *PEnumPrintProcessorDatatypesW)(LPWSTR, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
+typedef DWORD (WINAPI *PGetPrintProcessorCapabilities)(LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD);
+typedef HANDLE (WINAPI *POpenPrintProcessor)(LPWSTR, PPRINTPROCESSOROPENDATA);
+typedef BOOL (WINAPI *PPrintDocumentOnPrintProcessor)(HANDLE, LPWSTR);
+typedef LPMONITOREX(WINAPI *PInitializePrintMonitor)(PWSTR);
+typedef LPMONITOR2(WINAPI *PInitializePrintMonitor2)(PMONITORINIT, PHANDLE);
+
+// Forward declarations
+typedef struct _LOCAL_HANDLE LOCAL_HANDLE, *PLOCAL_HANDLE;
+typedef struct _LOCAL_JOB LOCAL_JOB, *PLOCAL_JOB;
+typedef struct _LOCAL_PORT LOCAL_PORT, *PLOCAL_PORT;
+typedef struct _LOCAL_PORT_HANDLE LOCAL_PORT_HANDLE, *PLOCAL_PORT_HANDLE;
+typedef struct _LOCAL_PRINT_MONITOR LOCAL_PRINT_MONITOR, *PLOCAL_PRINT_MONITOR;
+typedef struct _LOCAL_PRINT_PROCESSOR LOCAL_PRINT_PROCESSOR, *PLOCAL_PRINT_PROCESSOR;
+typedef struct _LOCAL_PRINTER LOCAL_PRINTER, *PLOCAL_PRINTER;
+typedef struct _LOCAL_PRINTER_HANDLE LOCAL_PRINTER_HANDLE, *PLOCAL_PRINTER_HANDLE;
+typedef struct _LOCAL_XCV_HANDLE LOCAL_XCV_HANDLE, *PLOCAL_XCV_HANDLE;
+typedef struct _SHD_HEADER SHD_HEADER, *PSHD_HEADER;
+
+// Structures
+/**
+ * Describes a Print Monitor.
+ */
+struct _LOCAL_PRINT_MONITOR
+{
+ LIST_ENTRY Entry;
+ PWSTR pwszName; /** Name of the Print Monitor as read from the registry. */
+ PWSTR pwszFileName; /** DLL File Name of the Print Monitor. */
+ BOOL bIsLevel2; /** Whether this Print Monitor supplies an InitializePrintMonitor2 API (preferred) instead of InitializePrintMonitor. */
+ PVOID pMonitor; /** For bIsLevel2 == TRUE: LPMONITOR2 pointer returned by InitializePrintMonitor2.
+ For bIsLevel2 == FALSE: LPMONITOREX pointer returned by InitializePrintMonitor. */
+ HANDLE hMonitor; /** Only used when bIsLevel2 == TRUE: Handle returned by InitializePrintMonitor2. */
+};
+
+/**
+ * Describes a Port handled by a Print Monitor.
+ */
+struct _LOCAL_PORT
+{
+ LIST_ENTRY Entry;
+ PWSTR pwszName; /** The name of the port (including the trailing colon). */
+ PLOCAL_PRINT_MONITOR pPrintMonitor; /** The Print Monitor handling this port. */
+ PLOCAL_JOB pNextJobToProcess; /** The Print Job that will be processed by the next created Port handle. */
+};
+
+/**
+ * Describes a Print Processor.
+ */
+struct _LOCAL_PRINT_PROCESSOR
+{
+ LIST_ENTRY Entry;
+ PWSTR pwszName;
+ PDATATYPES_INFO_1W pDatatypesInfo1;
+ DWORD dwDatatypeCount;
+ PClosePrintProcessor pfnClosePrintProcessor;
+ PControlPrintProcessor pfnControlPrintProcessor;
+ PEnumPrintProcessorDatatypesW pfnEnumPrintProcessorDatatypesW;
+ PGetPrintProcessorCapabilities pfnGetPrintProcessorCapabilities;
+ POpenPrintProcessor pfnOpenPrintProcessor;
+ PPrintDocumentOnPrintProcessor pfnPrintDocumentOnPrintProcessor;
+};
+
+/**
+ * Describes a printer and manages its print jobs.
+ * Created once for every printer at startup.
+ */
+struct _LOCAL_PRINTER
+{
+ // This sort key must be the first element for LookupElementSkiplist to work!
+ PWSTR pwszPrinterName;
+
+ DWORD dwAttributes;
+ DWORD dwStatus;
+ PWSTR pwszPrinterDriver;
+ PWSTR pwszDescription;
+ PWSTR pwszDefaultDatatype;
+ PDEVMODEW pDefaultDevMode;
+ PLOCAL_PRINT_PROCESSOR pPrintProcessor;
+ PLOCAL_PORT pPort;
+ SKIPLIST JobList;
+};
+
+/**
+ * Describes an entire print job associated to a specific printer through the Printer member.
+ * Created with every valid call to LocalStartDocPrinter.
+ */
+struct _LOCAL_JOB
+{
+ // This sort key must be the first element for LookupElementSkiplist to work!
+ DWORD dwJobID; /** Internal and external ID of this Job */
+
+ BOOL bAddedJob : 1; /** Whether AddJob has already been called on this Job. */
+ HANDLE hPrintProcessor; /** Handle returned by OpenPrintProcessor while the Job is printing. */
+ PLOCAL_PRINTER pPrinter; /** Associated Printer to this Job */
+ PLOCAL_PRINT_PROCESSOR pPrintProcessor; /** Associated Print Processor to this Job */
+ DWORD dwPriority; /** Priority of this Job from MIN_PRIORITY to MAX_PRIORITY, default being DEF_PRIORITY */
+ SYSTEMTIME stSubmitted; /** Time of the submission of this Job */
+ PWSTR pwszUserName; /** Optional; User that submitted the Job */
+ PWSTR pwszNotifyName; /** Optional; User that shall be notified about the status of the Job */
+ PWSTR pwszDocumentName; /** Optional; Name of the Document that is printed */
+ PWSTR pwszDatatype; /** Datatype of the Document */
+ PWSTR pwszOutputFile; /** Output File to spool the Job to */
+ PWSTR pwszPrintProcessorParameters; /** Optional; Parameters for the chosen Print Processor */
+ PWSTR pwszStatus; /** Optional; a Status Message for the Job */
+ DWORD dwTotalPages; /** Total pages of the Document */
+ DWORD dwPagesPrinted; /** Number of pages that have already been printed */
+ DWORD dwStartTime; /** Earliest time in minutes since 12:00 AM UTC when this document can be printed */
+ DWORD dwUntilTime; /** Latest time in minutes since 12:00 AM UTC when this document can be printed */
+ DWORD dwStatus; /** JOB_STATUS_* flags of the Job */
+ PWSTR pwszMachineName; /** Name of the machine that submitted the Job (prepended with two backslashes) */
+ PDEVMODEW pDevMode; /** Associated Device Mode to this Job */
+};
+
+/**
+ * Specific handle returned by LocalOpenPrinter for every valid call that opens a Printer or Print Job.
+ */
+struct _LOCAL_PRINTER_HANDLE
+{
+ BOOL bStartedDoc : 1; /** Whether StartDocPrinter has already been called. */
+ HANDLE hSPLFile; /** Handle to an opened SPL file for Printer Job handles. */
+ PLOCAL_PRINTER pPrinter; /** Printer associated with this handle. */
+ PLOCAL_JOB pJob; /** Print Job associated with this handle. This can be the specified Job if this is a Print Job handle or the started job through LocalStartDocPrinter. */
+ PWSTR pwszDatatype; /** Datatype used for newly started jobs. */
+ PDEVMODEW pDevMode; /** DevMode used for newly started jobs. */
+};
+
+/**
+ * Specific handle returned by LocalOpenPrinter for every valid call that opens a Port.
+ */
+struct _LOCAL_PORT_HANDLE
+{
+ HANDLE hPort; /** Handle returned by pfnOpenPort. */
+ PLOCAL_PORT pPort; /** Port associated with this handle. */
+};
+
+/**
+ * Specific handle returned by LocalOpenPrinter for every valid call that opens an XcvMonitor or XcvPort.
+ */
+struct _LOCAL_XCV_HANDLE
+{
+ HANDLE hXcv; /** Handle returned by pfnXcvOpenPort. */
+ PLOCAL_PRINT_MONITOR pPrintMonitor; /** Print Monitor associated with this handle. */
+};
+
+/**
+ * Describes a handle returned by LocalOpenPrinter.
+ * Suitable for all things that can be opened through LocalOpenPrinter.
+ */
+struct _LOCAL_HANDLE
+{
+ enum {
+ HandleType_Port, /** pSpecificHandle is a PLOCAL_PORT_HANDLE. */
+ HandleType_Printer, /** pSpecificHandle is a PLOCAL_PRINTER_HANDLE. */
+ HandleType_Xcv /** pSpecificHandle is a PLOCAL_XCV_HANDLE. */
+ }
+ HandleType;
+ PVOID pSpecificHandle;
+};
+
+/**
+ * Describes the header of a print job serialized into a shadow file (.SHD)
+ * Documented in http://www.undocprint.org/formats/winspool/shd
+ * Compatible with Windows Server 2003
+ */
+struct _SHD_HEADER
+{
+ DWORD dwSignature;
+ DWORD cbHeader;
+ WORD wStatus;
+ WORD wUnknown1;
+ DWORD dwJobID;
+ DWORD dwPriority;
+ DWORD offUserName;
+ DWORD offNotifyName;
+ DWORD offDocumentName;
+ DWORD offPort;
+ DWORD offPrinterName;
+ DWORD offDriverName;
+ DWORD offDevMode;
+ DWORD offPrintProcessor;
+ DWORD offDatatype;
+ DWORD offPrintProcessorParameters;
+ SYSTEMTIME stSubmitted;
+ DWORD dwStartTime;
+ DWORD dwUntilTime;
+ DWORD dwUnknown6;
+ DWORD dwTotalPages;
+ DWORD cbSecurityDescriptor;
+ DWORD offSecurityDescriptor;
+ DWORD dwUnknown3;
+ DWORD dwUnknown4;
+ DWORD dwUnknown5;
+ DWORD offMachineName;
+ DWORD dwSPLSize;
+};
+
+// jobs.c
+extern SKIPLIST GlobalJobList;
+DWORD WINAPI CreateJob(PLOCAL_PRINTER_HANDLE pPrinterHandle);
+void FreeJob(PLOCAL_JOB pJob);
+DWORD GetJobFilePath(PCWSTR pwszExtension, DWORD dwJobID, PWSTR pwszOutput);
+BOOL InitializeGlobalJobList();
+void InitializePrinterJobList(PLOCAL_PRINTER pPrinter);
+BOOL WINAPI LocalAddJob(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded);
+BOOL WINAPI LocalEnumJobs(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pStart, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
+BOOL WINAPI LocalGetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pStart, DWORD cbBuf, LPDWORD pcbNeeded);
+BOOL WINAPI LocalScheduleJob(HANDLE hPrinter, DWORD dwJobID);
+BOOL WINAPI LocalSetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command);
+PLOCAL_JOB ReadJobShadowFile(PCWSTR pwszFilePath);
+BOOL WriteJobShadowFile(PWSTR pwszFilePath, const PLOCAL_JOB pJob);
+
+// main.c
+extern const WCHAR wszCurrentEnvironment[];
+extern const DWORD cbCurrentEnvironment;
+extern const WCHAR wszDefaultDocumentName[];
+extern const WCHAR* wszPrintProviderInfo[3];
+extern WCHAR wszSpoolDirectory[MAX_PATH];
+extern DWORD cchSpoolDirectory;
+
+// monitors.c
+extern LIST_ENTRY PrintMonitorList;
+PLOCAL_PRINT_MONITOR FindPrintMonitor(PCWSTR pwszName);
+BOOL InitializePrintMonitorList();
+BOOL WINAPI LocalEnumMonitors(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned);
+
+// ports.c
+PLOCAL_PORT FindPort(PCWSTR pwszName);
+BOOL InitializePortList();
+BOOL WINAPI LocalEnumPorts(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned);
+
+// printers.c
+extern SKIPLIST PrinterList;
+BOOL InitializePrinterList();
+BOOL WINAPI LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
+BOOL WINAPI LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDefault);
+BOOL WINAPI LocalReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead);
+DWORD WINAPI LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo);
+BOOL WINAPI LocalStartPagePrinter(HANDLE hPrinter);
+BOOL WINAPI LocalWritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten);
+BOOL WINAPI LocalEndPagePrinter(HANDLE hPrinter);
+BOOL WINAPI LocalEndDocPrinter(HANDLE hPrinter);
+BOOL WINAPI LocalClosePrinter(HANDLE hPrinter);
+
+// printingthread.c
+DWORD WINAPI PrintingThreadProc(PLOCAL_JOB pJob);
+
+// printprocessors.c
+BOOL FindDatatype(const PLOCAL_PRINT_PROCESSOR pPrintProcessor, PCWSTR pwszDatatype);
+PLOCAL_PRINT_PROCESSOR FindPrintProcessor(PCWSTR pwszName);
+BOOL InitializePrintProcessorList();
+BOOL WINAPI LocalEnumPrintProcessorDatatypes(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD Level, LPBYTE pDatatypes, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
+BOOL WINAPI LocalEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
+BOOL WINAPI LocalGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded);
+
+// tools.c
+PWSTR AllocAndRegQueryWSZ(HKEY hKey, PCWSTR pwszValueName);
+PDEVMODEW DuplicateDevMode(PDEVMODEW pInput);
+
+#endif
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Spooler
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Printers and printing
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+// Global Variables
+SKIPLIST PrinterList;
+
+
+/**
+ * @name _PrinterListCompareRoutine
+ *
+ * SKIPLIST_COMPARE_ROUTINE for the Printer List.
+ * Does a case-insensitive comparison, because e.g. LocalOpenPrinter doesn't match the case when looking for Printers.
+ */
+static int WINAPI
+_PrinterListCompareRoutine(PVOID FirstStruct, PVOID SecondStruct)
+{
+ PLOCAL_PRINTER A = (PLOCAL_PRINTER)FirstStruct;
+ PLOCAL_PRINTER B = (PLOCAL_PRINTER)SecondStruct;
+
+ return wcsicmp(A->pwszPrinterName, B->pwszPrinterName);
+}
+
+/**
+ * @name InitializePrinterList
+ *
+ * Initializes a list of locally available Printers.
+ * The list is searchable by name and returns information about the printers, including their job queues.
+ * During this process, the job queues are also initialized.
+ */
+BOOL
+InitializePrinterList()
+{
+ const WCHAR wszPrintersKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Printers";
+
+ DWORD cbData;
+ DWORD cchPrinterName;
+ DWORD dwErrorCode;
+ DWORD dwSubKeys;
+ DWORD i;
+ HKEY hKey = NULL;
+ HKEY hSubKey = NULL;
+ PLOCAL_PORT pPort;
+ PLOCAL_PRINTER pPrinter = NULL;
+ PLOCAL_PRINT_PROCESSOR pPrintProcessor;
+ PWSTR pwszPort = NULL;
+ PWSTR pwszPrintProcessor = NULL;
+ WCHAR wszPrinterName[MAX_PRINTER_NAME + 1];
+
+ // Initialize an empty list for our printers.
+ InitializeSkiplist(&PrinterList, DllAllocSplMem, _PrinterListCompareRoutine, (PSKIPLIST_FREE_ROUTINE)DllFreeSplMem);
+
+ // Open our printers registry key. Each subkey is a local printer there.
+ dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszPrintersKey, 0, KEY_READ, &hKey);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Get the number of subkeys.
+ dwErrorCode = (DWORD)RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &dwSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Loop through all available local printers.
+ for (i = 0; i < dwSubKeys; i++)
+ {
+ // Cleanup tasks from the previous run
+ if (hSubKey)
+ {
+ RegCloseKey(hSubKey);
+ hSubKey = NULL;
+ }
+
+ if (pPrinter)
+ {
+ if (pPrinter->pDefaultDevMode)
+ DllFreeSplMem(pPrinter->pDefaultDevMode);
+
+ if (pPrinter->pwszDefaultDatatype)
+ DllFreeSplStr(pPrinter->pwszDefaultDatatype);
+
+ if (pPrinter->pwszDescription)
+ DllFreeSplStr(pPrinter->pwszDescription);
+
+ if (pPrinter->pwszPrinterDriver)
+ DllFreeSplStr(pPrinter->pwszPrinterDriver);
+
+ if (pPrinter->pwszPrinterName)
+ DllFreeSplStr(pPrinter->pwszPrinterName);
+
+ DllFreeSplMem(pPrinter);
+ pPrinter = NULL;
+ }
+
+ if (pwszPrintProcessor)
+ {
+ DllFreeSplStr(pwszPrintProcessor);
+ pwszPrintProcessor = NULL;
+ }
+
+ // Get the name of this printer.
+ cchPrinterName = _countof(wszPrinterName);
+ dwErrorCode = (DWORD)RegEnumKeyExW(hKey, i, wszPrinterName, &cchPrinterName, NULL, NULL, NULL, NULL);
+ if (dwErrorCode == ERROR_MORE_DATA)
+ {
+ // This printer name exceeds the maximum length and is invalid.
+ continue;
+ }
+ else if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegEnumKeyExW failed for iteration %lu with status %lu!\n", i, dwErrorCode);
+ continue;
+ }
+
+ // Open this Printer's registry key.
+ dwErrorCode = (DWORD)RegOpenKeyExW(hKey, wszPrinterName, 0, KEY_READ, &hSubKey);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegOpenKeyExW failed for Printer \"%S\" with status %lu!\n", wszPrinterName, dwErrorCode);
+ continue;
+ }
+
+ // Get the Print Processor.
+ pwszPrintProcessor = AllocAndRegQueryWSZ(hSubKey, L"Print Processor");
+ if (!pwszPrintProcessor)
+ continue;
+
+ // Try to find it in the Print Processor List.
+ pPrintProcessor = FindPrintProcessor(pwszPrintProcessor);
+ if (!pPrintProcessor)
+ {
+ ERR("Invalid Print Processor \"%S\" for Printer \"%S\"!\n", pwszPrintProcessor, wszPrinterName);
+ continue;
+ }
+
+ // Get the Port.
+ pwszPort = AllocAndRegQueryWSZ(hSubKey, L"Port");
+ if (!pwszPort)
+ continue;
+
+ // Try to find it in the Port List.
+ pPort = FindPort(pwszPort);
+ if (!pPort)
+ {
+ ERR("Invalid Port \"%S\" for Printer \"%S\"!\n", pwszPort, wszPrinterName);
+ continue;
+ }
+
+ // Create a new LOCAL_PRINTER structure for it.
+ pPrinter = DllAllocSplMem(sizeof(LOCAL_PRINTER));
+ if (!pPrinter)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ pPrinter->pwszPrinterName = AllocSplStr(wszPrinterName);
+ pPrinter->pPrintProcessor = pPrintProcessor;
+ pPrinter->pPort = pPort;
+ InitializePrinterJobList(pPrinter);
+
+ // 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)
+ continue;
+
+ // Verify that it's valid.
+ if (!FindDatatype(pPrintProcessor, pPrinter->pwszDefaultDatatype))
+ {
+ ERR("Invalid default datatype \"%S\" for Printer \"%S\"!\n", pPrinter->pwszDefaultDatatype, wszPrinterName);
+ continue;
+ }
+
+ // Determine the size of the DevMode.
+ dwErrorCode = (DWORD)RegQueryValueExW(hSubKey, L"Default DevMode", NULL, NULL, NULL, &cbData);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("Couldn't query the size of the DevMode for Printer \"%S\", status is %lu, cbData is %lu!\n", wszPrinterName, dwErrorCode, cbData);
+ continue;
+ }
+
+ // Allocate enough memory for the DevMode.
+ pPrinter->pDefaultDevMode = DllAllocSplMem(cbData);
+ if (!pPrinter->pDefaultDevMode)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Get the default DevMode.
+ dwErrorCode = (DWORD)RegQueryValueExW(hSubKey, L"Default DevMode", NULL, NULL, (PBYTE)pPrinter->pDefaultDevMode, &cbData);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("Couldn't query a DevMode for Printer \"%S\", status is %lu, cbData is %lu!\n", wszPrinterName, dwErrorCode, cbData);
+ continue;
+ }
+
+ // Get the Attributes.
+ cbData = sizeof(DWORD);
+ dwErrorCode = (DWORD)RegQueryValueExW(hSubKey, L"Attributes", NULL, NULL, (PBYTE)&pPrinter->dwAttributes, &cbData);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("Couldn't query Attributes for Printer \"%S\", status is %lu!\n", wszPrinterName, dwErrorCode);
+ continue;
+ }
+
+ // Get the Status.
+ cbData = sizeof(DWORD);
+ dwErrorCode = (DWORD)RegQueryValueExW(hSubKey, L"Status", NULL, NULL, (PBYTE)&pPrinter->dwStatus, &cbData);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("Couldn't query Status for Printer \"%S\", status is %lu!\n", wszPrinterName, dwErrorCode);
+ continue;
+ }
+
+ // Add this printer to the printer list.
+ if (!InsertElementSkiplist(&PrinterList, pPrinter))
+ {
+ ERR("InsertElementSkiplist failed for Printer \"%S\"!\n", pPrinter->pwszPrinterName);
+ goto Cleanup;
+ }
+
+ // Don't let the cleanup routines free this.
+ pPrinter = NULL;
+ }
+
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ // Inside the loop
+ if (hSubKey)
+ RegCloseKey(hSubKey);
+
+ if (pPrinter)
+ {
+ if (pPrinter->pDefaultDevMode)
+ DllFreeSplMem(pPrinter->pDefaultDevMode);
+
+ if (pPrinter->pwszDefaultDatatype)
+ DllFreeSplStr(pPrinter->pwszDefaultDatatype);
+
+ if (pPrinter->pwszDescription)
+ DllFreeSplStr(pPrinter->pwszDescription);
+
+ if (pPrinter->pwszPrinterDriver)
+ DllFreeSplStr(pPrinter->pwszPrinterDriver);
+
+ if (pPrinter->pwszPrinterName)
+ DllFreeSplStr(pPrinter->pwszPrinterName);
+
+ DllFreeSplMem(pPrinter);
+ }
+
+ if (pwszPrintProcessor)
+ DllFreeSplStr(pwszPrintProcessor);
+
+ // Outside the loop
+ if (hKey)
+ RegCloseKey(hKey);
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+
+DWORD
+_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 dwErrorCode;
+ DWORD i;
+ PBYTE pPrinterInfo;
+ PBYTE pPrinterString;
+ PSKIPLIST_NODE pNode;
+ PLOCAL_PRINTER pPrinter;
+ PRINTER_INFO_1W PrinterInfo1;
+ 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))
+ {
+ dwErrorCode = GetLastError();
+ ERR("GetComputerNameW failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // 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)
+ {
+ dwErrorCode = ERROR_INVALID_NAME;
+ goto Cleanup;
+ }
+
+ // 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.
+ dwErrorCode = ERROR_INVALID_NAME;
+ goto Cleanup;
+ }
+ }
+ 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);
+
+ // Check if the supplied buffer is large enough.
+ if (cbBuf < *pcbNeeded)
+ {
+ dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
+ goto Cleanup;
+ }
+
+ // Copy over the print processor information.
+ ((PPRINTER_INFO_1W)pPrinterEnum)->Flags = 0;
+ PackStrings(wszPrintProviderInfo, pPrinterEnum, dwOffsets, &pPrinterEnum[*pcbNeeded]);
+ *pcReturned = 1;
+ dwErrorCode = ERROR_SUCCESS;
+ goto Cleanup;
+ }
+ }
+
+ // Count the required buffer size and the number of printers.
+ i = 0;
+
+ for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0])
+ {
+ pPrinter = (PLOCAL_PRINTER)pNode->Element;
+
+ // 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;
+ i++;
+ }
+
+ // Check if the supplied buffer is large enough.
+ if (cbBuf < *pcbNeeded)
+ {
+ dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
+ goto Cleanup;
+ }
+
+ // 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 + i * sizeof(PRINTER_INFO_1W);
+
+ // Copy over the printer information.
+ for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0])
+ {
+ pPrinter = (PLOCAL_PRINTER)pNode->Element;
+
+ // 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);
+ }
+
+ *pcReturned = i;
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ return dwErrorCode;
+}
+
+BOOL WINAPI
+LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
+{
+ DWORD dwErrorCode;
+
+ // Do no sanity checks here. This is verified by localspl_apitest!
+
+ // Begin counting.
+ *pcbNeeded = 0;
+ *pcReturned = 0;
+
+ // Think positive :)
+ // Treat it as success if the caller queried no information and we don't need to return any.
+ dwErrorCode = ERROR_SUCCESS;
+
+ if (Flags & PRINTER_ENUM_LOCAL)
+ {
+ // The function behaves quite differently for each level.
+ if (Level == 1)
+ {
+ dwErrorCode = _LocalEnumPrintersLevel1(Flags, Name, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
+ }
+ else
+ {
+ // TODO: Handle other levels.
+ // The caller supplied an invalid level.
+ dwErrorCode = ERROR_INVALID_LEVEL;
+ goto Cleanup;
+ }
+ }
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDefault)
+{
+ BOOL bReturnValue;
+ DWORD cchComputerName;
+ DWORD cchFirstParameter;
+ DWORD dwErrorCode;
+ DWORD dwJobID;
+ HANDLE hExternalHandle;
+ PWSTR p = lpPrinterName;
+ PWSTR pwszFirstParameter = NULL;
+ PWSTR pwszSecondParameter = NULL;
+ PLOCAL_JOB pJob;
+ PLOCAL_HANDLE pHandle = NULL;
+ PLOCAL_PORT pPort;
+ PLOCAL_PORT_HANDLE pPortHandle = NULL;
+ PLOCAL_PRINT_MONITOR pPrintMonitor;
+ PLOCAL_PRINTER pPrinter;
+ PLOCAL_PRINTER_HANDLE pPrinterHandle = NULL;
+ PLOCAL_XCV_HANDLE pXcvHandle = NULL;
+ WCHAR wszComputerName[MAX_COMPUTERNAME_LENGTH + 1];
+ WCHAR wszFullPath[MAX_PATH];
+
+ // TODO: lpPrinterName == NULL is supported and means access to the local printer server.
+ // Not sure yet if that is passed down to localspl.dll or processed in advance.
+
+ // Sanity checks
+ if (!lpPrinterName || !phPrinter)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ *phPrinter = NULL;
+
+ // Skip any server name in the first parameter.
+ // Does lpPrinterName begin with two backslashes to indicate a server name?
+ if (lpPrinterName[0] == L'\\' && lpPrinterName[1] == L'\\')
+ {
+ // Skip these two backslashes.
+ lpPrinterName += 2;
+
+ // Look for the closing backslash.
+ p = wcschr(lpPrinterName, L'\\');
+ if (!p)
+ {
+ // We didn't get a proper server name.
+ dwErrorCode = ERROR_INVALID_PRINTER_NAME;
+ goto Cleanup;
+ }
+
+ // Get the local computer name for comparison.
+ cchComputerName = _countof(wszComputerName);
+ if (!GetComputerNameW(wszComputerName, &cchComputerName))
+ {
+ dwErrorCode = GetLastError();
+ ERR("GetComputerNameW failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Now compare this string excerpt with the local computer name.
+ // The input parameter may not be writable, so we can't null-terminate the input string at this point.
+ // This print provider only supports local printers, so both strings have to match.
+ if (p - lpPrinterName != cchComputerName || _wcsnicmp(lpPrinterName, wszComputerName, cchComputerName) != 0)
+ {
+ dwErrorCode = ERROR_INVALID_PRINTER_NAME;
+ goto Cleanup;
+ }
+
+ // We have checked the server name and don't need it anymore.
+ lpPrinterName = p + 1;
+ }
+
+ // Look for a comma. If it exists, it indicates the end of the first parameter.
+ pwszSecondParameter = wcschr(lpPrinterName, L',');
+ if (pwszSecondParameter)
+ cchFirstParameter = pwszSecondParameter - p;
+ else
+ cchFirstParameter = wcslen(lpPrinterName);
+
+ // We must have at least one parameter.
+ if (!cchFirstParameter && !pwszSecondParameter)
+ {
+ dwErrorCode = ERROR_INVALID_PRINTER_NAME;
+ goto Cleanup;
+ }
+
+ // Do we have a first parameter?
+ if (cchFirstParameter)
+ {
+ // Yes, extract it.
+ // No null-termination is necessary here, because DllAllocSplMem returns a zero-initialized buffer.
+ pwszFirstParameter = DllAllocSplMem((cchFirstParameter + 1) * sizeof(WCHAR));
+ CopyMemory(pwszFirstParameter, lpPrinterName, cchFirstParameter * sizeof(WCHAR));
+ }
+
+ // Do we have a second parameter?
+ if (pwszSecondParameter)
+ {
+ // Yes, skip the comma at the beginning.
+ ++pwszSecondParameter;
+
+ // Skip whitespace as well.
+ while (*pwszSecondParameter == L' ')
+ ++pwszSecondParameter;
+ }
+
+ // Create a new handle.
+ pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE));
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Now we can finally check the type of handle actually requested.
+ if (pwszFirstParameter && pwszSecondParameter && wcsncmp(pwszSecondParameter, L"Port", 4) == 0)
+ {
+ // The caller wants a port handle and provided a string like:
+ // "LPT1:, Port"
+ // "\\COMPUTERNAME\LPT1:, Port"
+
+ // Look for this port in our Print Monitor Port list.
+ pPort = FindPort(pwszFirstParameter);
+ if (!pPort)
+ {
+ // The supplied port is unknown to all our Print Monitors.
+ dwErrorCode = ERROR_INVALID_PRINTER_NAME;
+ goto Cleanup;
+ }
+
+ pPrintMonitor = pPort->pPrintMonitor;
+
+ // Call the monitor's OpenPort function.
+ if (pPrintMonitor->bIsLevel2)
+ bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnOpenPort(pPrintMonitor->hMonitor, pwszFirstParameter, &hExternalHandle);
+ else
+ bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnOpenPort(pwszFirstParameter, &hExternalHandle);
+
+ if (!bReturnValue)
+ {
+ // The OpenPort function failed. Return its last error.
+ dwErrorCode = GetLastError();
+ goto Cleanup;
+ }
+
+ // Create a new LOCAL_PORT_HANDLE.
+ pPortHandle = DllAllocSplMem(sizeof(LOCAL_PORT_HANDLE));
+ if (!pPortHandle)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ pPortHandle->hPort = hExternalHandle;
+ pPortHandle->pPort = pPort;
+
+ // Return the Port handle through our general handle.
+ pHandle->HandleType = HandleType_Port;
+ pHandle->pSpecificHandle = pPortHandle;
+ }
+ else if (!pwszFirstParameter && pwszSecondParameter && wcsncmp(pwszSecondParameter, L"Xcv", 3) == 0)
+ {
+ // The caller wants an Xcv handle and provided a string like:
+ // ", XcvMonitor Local Port"
+ // "\\COMPUTERNAME\, XcvMonitor Local Port"
+ // ", XcvPort LPT1:"
+ // "\\COMPUTERNAME\, XcvPort LPT1:"
+
+ // Skip the "Xcv" string.
+ pwszSecondParameter += 3;
+
+ // Is XcvMonitor or XcvPort requested?
+ if (wcsncmp(pwszSecondParameter, L"Monitor ", 8) == 0)
+ {
+ // Skip the "Monitor " string.
+ pwszSecondParameter += 8;
+
+ // Look for this monitor in our Print Monitor list.
+ pPrintMonitor = FindPrintMonitor(pwszSecondParameter);
+ if (!pPrintMonitor)
+ {
+ // The caller supplied a non-existing Monitor name.
+ dwErrorCode = ERROR_INVALID_PRINTER_NAME;
+ goto Cleanup;
+ }
+ }
+ else if (wcsncmp(pwszSecondParameter, L"Port ", 5) == 0)
+ {
+ // Skip the "Port " string.
+ pwszSecondParameter += 5;
+
+ // Look for this port in our Print Monitor Port list.
+ pPort = FindPort(pwszFirstParameter);
+ if (!pPort)
+ {
+ // The supplied port is unknown to all our Print Monitors.
+ dwErrorCode = ERROR_INVALID_PRINTER_NAME;
+ goto Cleanup;
+ }
+
+ pPrintMonitor = pPort->pPrintMonitor;
+ }
+ else
+ {
+ dwErrorCode = ERROR_INVALID_PRINTER_NAME;
+ goto Cleanup;
+ }
+
+ // Call the monitor's XcvOpenPort function.
+ if (pPrintMonitor->bIsLevel2)
+ bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnXcvOpenPort(pPrintMonitor->hMonitor, pwszSecondParameter, SERVER_EXECUTE, &hExternalHandle);
+ else
+ bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnXcvOpenPort(pwszSecondParameter, SERVER_EXECUTE, &hExternalHandle);
+
+ if (!bReturnValue)
+ {
+ // The XcvOpenPort function failed. Return its last error.
+ dwErrorCode = GetLastError();
+ goto Cleanup;
+ }
+
+ // Create a new LOCAL_XCV_HANDLE.
+ pXcvHandle = DllAllocSplMem(sizeof(LOCAL_XCV_HANDLE));
+ if (!pXcvHandle)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ pXcvHandle->hXcv = hExternalHandle;
+ pXcvHandle->pPrintMonitor = pPrintMonitor;
+
+ // Return the Xcv handle through our general handle.
+ pHandle->HandleType = HandleType_Xcv;
+ pHandle->pSpecificHandle = pXcvHandle;
+ }
+ else
+ {
+ // The caller wants a Printer or Printer Job handle and provided a string like:
+ // "HP DeskJet"
+ // "\\COMPUTERNAME\HP DeskJet"
+ // "HP DeskJet, Job 5"
+ // "\\COMPUTERNAME\HP DeskJet, Job 5"
+
+ // Retrieve the printer from the list.
+ pPrinter = LookupElementSkiplist(&PrinterList, &pwszFirstParameter, NULL);
+ if (!pPrinter)
+ {
+ // The printer does not exist.
+ dwErrorCode = ERROR_INVALID_PRINTER_NAME;
+ goto Cleanup;
+ }
+
+ // Create a new LOCAL_PRINTER_HANDLE.
+ pPrinterHandle = DllAllocSplMem(sizeof(LOCAL_PRINTER_HANDLE));
+ if (!pPrinterHandle)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ pPrinterHandle->hSPLFile = INVALID_HANDLE_VALUE;
+ pPrinterHandle->pPrinter = pPrinter;
+
+ // Check if a datatype was given.
+ if (pDefault && pDefault->pDatatype)
+ {
+ // Use the datatype if it's valid.
+ if (!FindDatatype(pPrinter->pPrintProcessor, pDefault->pDatatype))
+ {
+ dwErrorCode = ERROR_INVALID_DATATYPE;
+ goto Cleanup;
+ }
+
+ pPrinterHandle->pwszDatatype = AllocSplStr(pDefault->pDatatype);
+ }
+ else
+ {
+ // Use the default datatype.
+ pPrinterHandle->pwszDatatype = AllocSplStr(pPrinter->pwszDefaultDatatype);
+ }
+
+ // Check if a DevMode was given, otherwise use the default.
+ if (pDefault && pDefault->pDevMode)
+ pPrinterHandle->pDevMode = DuplicateDevMode(pDefault->pDevMode);
+ else
+ pPrinterHandle->pDevMode = DuplicateDevMode(pPrinter->pDefaultDevMode);
+
+ // Check if the caller wants a handle to an existing Print Job.
+ if (pwszSecondParameter)
+ {
+ // The "Job " string has to follow now.
+ if (wcsncmp(pwszSecondParameter, L"Job ", 4) != 0)
+ {
+ dwErrorCode = ERROR_INVALID_PRINTER_NAME;
+ goto Cleanup;
+ }
+
+ // Skip the "Job " string.
+ pwszSecondParameter += 4;
+
+ // Skip even more whitespace.
+ while (*pwszSecondParameter == ' ')
+ ++pwszSecondParameter;
+
+ // Finally extract the desired Job ID.
+ dwJobID = wcstoul(pwszSecondParameter, NULL, 10);
+ if (!IS_VALID_JOB_ID(dwJobID))
+ {
+ // The user supplied an invalid Job ID.
+ dwErrorCode = ERROR_INVALID_PRINTER_NAME;
+ goto Cleanup;
+ }
+
+ // Look for this job in the Global Job List.
+ pJob = LookupElementSkiplist(&GlobalJobList, &dwJobID, NULL);
+ if (!pJob || pJob->pPrinter != pPrinter)
+ {
+ // The user supplied a non-existing Job ID or the Job ID does not belong to the supplied printer name.
+ dwErrorCode = ERROR_INVALID_PRINTER_NAME;
+ goto Cleanup;
+ }
+
+ // Try to open its SPL file.
+ GetJobFilePath(L"SPL", dwJobID, wszFullPath);
+ pPrinterHandle->hSPLFile = CreateFileW(wszFullPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+ if (pPrinterHandle->hSPLFile == INVALID_HANDLE_VALUE)
+ {
+ dwErrorCode = GetLastError();
+ ERR("CreateFileW failed with error %lu for \"%S\"!", dwErrorCode, wszFullPath);
+ goto Cleanup;
+ }
+
+ // Associate the job to our Printer Handle, but don't set bStartedDoc.
+ // This prevents the caller from doing further StartDocPrinter, WritePrinter, etc. calls on it.
+ pPrinterHandle->pJob = pJob;
+ }
+
+ // Return the Printer handle through our general handle.
+ pHandle->HandleType = HandleType_Printer;
+ pHandle->pSpecificHandle = pPrinterHandle;
+ }
+
+ // We were successful! Return the handle.
+ *phPrinter = (HANDLE)pHandle;
+ dwErrorCode = ERROR_SUCCESS;
+
+ // Don't let the cleanup routines free this.
+ pHandle = NULL;
+ pPrinterHandle = NULL;
+
+Cleanup:
+ if (pHandle)
+ DllFreeSplMem(pHandle);
+
+ if (pPrinterHandle)
+ {
+ if (pPrinterHandle->pwszDatatype)
+ DllFreeSplStr(pPrinterHandle->pwszDatatype);
+
+ if (pPrinterHandle->pDevMode)
+ DllFreeSplMem(pPrinterHandle->pDevMode);
+
+ DllFreeSplMem(pPrinterHandle);
+ }
+
+ if (pwszFirstParameter)
+ DllFreeSplMem(pwszFirstParameter);
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+LocalReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
+{
+ BOOL bReturnValue;
+ DWORD dwErrorCode;
+ PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
+ PLOCAL_PORT_HANDLE pPortHandle;
+ PLOCAL_PRINTER_HANDLE pPrinterHandle;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Port handles are an entirely different thing.
+ if (pHandle->HandleType == HandleType_Port)
+ {
+ pPortHandle = (PLOCAL_PORT_HANDLE)pHandle->pSpecificHandle;
+
+ // Call the monitor's ReadPort function.
+ if (pPortHandle->pPort->pPrintMonitor->bIsLevel2)
+ bReturnValue = ((PMONITOR2)pPortHandle->pPort->pPrintMonitor->pMonitor)->pfnReadPort(pPortHandle->hPort, pBuf, cbBuf, pNoBytesRead);
+ else
+ bReturnValue = ((LPMONITOREX)pPortHandle->pPort->pPrintMonitor->pMonitor)->Monitor.pfnReadPort(pPortHandle->hPort, pBuf, cbBuf, pNoBytesRead);
+
+ if (!bReturnValue)
+ {
+ // The ReadPort function failed. Return its last error.
+ dwErrorCode = GetLastError();
+ goto Cleanup;
+ }
+
+ // We were successful!
+ dwErrorCode = ERROR_SUCCESS;
+ goto Cleanup;
+ }
+
+ // The remaining function deals with Printer handles only.
+ if (pHandle->HandleType != HandleType_Printer)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
+
+ // ReadPrinter needs an opened SPL file to work.
+ // This only works if a Printer Job Handle was requested in OpenPrinter.
+ if (pPrinterHandle->hSPLFile == INVALID_HANDLE_VALUE)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Pass the parameters to ReadFile.
+ if (!ReadFile(pPrinterHandle->hSPLFile, pBuf, cbBuf, pNoBytesRead, NULL))
+ {
+ dwErrorCode = GetLastError();
+ ERR("ReadFile failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+DWORD WINAPI
+LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
+{
+ BOOL bReturnValue;
+ DWORD dwErrorCode;
+ DWORD dwReturnValue = 0;
+ PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo;
+ PLOCAL_JOB pJob;
+ PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
+ PLOCAL_PORT_HANDLE pPortHandle;
+ PLOCAL_PRINTER_HANDLE pPrinterHandle;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Port handles are an entirely different thing.
+ if (pHandle->HandleType == HandleType_Port)
+ {
+ pPortHandle = (PLOCAL_PORT_HANDLE)pHandle->pSpecificHandle;
+
+ // This call should come from a Print Processor and the job this port is going to print was assigned to us before opening the Print Processor.
+ // Claim it exclusively for this port handle.
+ pJob = pPortHandle->pPort->pNextJobToProcess;
+ pPortHandle->pPort->pNextJobToProcess = NULL;
+ ASSERT(pJob);
+
+ // Call the monitor's StartDocPort function.
+ if (pPortHandle->pPort->pPrintMonitor->bIsLevel2)
+ bReturnValue = ((PMONITOR2)pPortHandle->pPort->pPrintMonitor->pMonitor)->pfnStartDocPort(pPortHandle->hPort, pJob->pPrinter->pwszPrinterName, pJob->dwJobID, Level, pDocInfo);
+ else
+ bReturnValue = ((LPMONITOREX)pPortHandle->pPort->pPrintMonitor->pMonitor)->Monitor.pfnStartDocPort(pPortHandle->hPort, pJob->pPrinter->pwszPrinterName, pJob->dwJobID, Level, pDocInfo);
+
+ if (!bReturnValue)
+ {
+ // The StartDocPort function failed. Return its last error.
+ dwErrorCode = GetLastError();
+ goto Cleanup;
+ }
+
+ // We were successful!
+ dwErrorCode = ERROR_SUCCESS;
+ dwReturnValue = pJob->dwJobID;
+ goto Cleanup;
+ }
+
+ // The remaining function deals with Printer handles only.
+ if (pHandle->HandleType != HandleType_Printer)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ if (!pDocInfo1)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
+
+ // pJob may already be occupied if this is a Print Job handle. In this case, StartDocPrinter has to fail.
+ if (pPrinterHandle->pJob)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // Check the validity of the datatype if we got one.
+ if (pDocInfo1->pDatatype && !FindDatatype(pPrinterHandle->pJob->pPrintProcessor, pDocInfo1->pDatatype))
+ {
+ dwErrorCode = ERROR_INVALID_DATATYPE;
+ goto Cleanup;
+ }
+
+ // Check if this is the right document information level.
+ if (Level != 1)
+ {
+ dwErrorCode = ERROR_INVALID_LEVEL;
+ goto Cleanup;
+ }
+
+ // All requirements are met - create a new job.
+ dwErrorCode = CreateJob(pPrinterHandle);
+ if (dwErrorCode != ERROR_SUCCESS)
+ goto Cleanup;
+
+ // Use any given datatype.
+ if (pDocInfo1->pDatatype && !ReallocSplStr(&pPrinterHandle->pJob->pwszDatatype, pDocInfo1->pDatatype))
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Use any given document name.
+ if (pDocInfo1->pDocName && !ReallocSplStr(&pPrinterHandle->pJob->pwszDocumentName, pDocInfo1->pDocName))
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // We were successful!
+ dwErrorCode = ERROR_SUCCESS;
+ dwReturnValue = pPrinterHandle->pJob->dwJobID;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return dwReturnValue;
+}
+
+BOOL WINAPI
+LocalStartPagePrinter(HANDLE hPrinter)
+{
+ DWORD dwErrorCode;
+ PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
+ PLOCAL_PRINTER_HANDLE pPrinterHandle;
+
+ // Sanity checks.
+ if (!pHandle || pHandle->HandleType != HandleType_Printer)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
+
+ // We require StartDocPrinter or AddJob to be called first.
+ if (!pPrinterHandle->bStartedDoc)
+ {
+ dwErrorCode = ERROR_SPL_NO_STARTDOC;
+ goto Cleanup;
+ }
+
+ // Increase the page count.
+ ++pPrinterHandle->pJob->dwTotalPages;
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+LocalWritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
+{
+ BOOL bReturnValue;
+ DWORD dwErrorCode;
+ PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
+ PLOCAL_PORT_HANDLE pPortHandle;
+ PLOCAL_PRINTER_HANDLE pPrinterHandle;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Port handles are an entirely different thing.
+ if (pHandle->HandleType == HandleType_Port)
+ {
+ pPortHandle = (PLOCAL_PORT_HANDLE)pHandle->pSpecificHandle;
+
+ // Call the monitor's WritePort function.
+ if (pPortHandle->pPort->pPrintMonitor->bIsLevel2)
+ bReturnValue = ((PMONITOR2)pPortHandle->pPort->pPrintMonitor->pMonitor)->pfnWritePort(pPortHandle->hPort, pBuf, cbBuf, pcWritten);
+ else
+ bReturnValue = ((LPMONITOREX)pPortHandle->pPort->pPrintMonitor->pMonitor)->Monitor.pfnWritePort(pPortHandle->hPort, pBuf, cbBuf, pcWritten);
+
+ if (!bReturnValue)
+ {
+ // The WritePort function failed. Return its last error.
+ dwErrorCode = GetLastError();
+ goto Cleanup;
+ }
+
+ // We were successful!
+ dwErrorCode = ERROR_SUCCESS;
+ goto Cleanup;
+ }
+
+ // The remaining function deals with Printer handles only.
+ if (pHandle->HandleType != HandleType_Printer)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
+
+ // We require StartDocPrinter or AddJob to be called first.
+ if (!pPrinterHandle->bStartedDoc)
+ {
+ dwErrorCode = ERROR_SPL_NO_STARTDOC;
+ goto Cleanup;
+ }
+
+ // TODO: This function is only called when doing non-spooled printing.
+ // This needs to be investigated further. We can't just use pPrinterHandle->hSPLFile here, because that's currently reserved for Printer Job handles (see LocalReadPrinter).
+#if 0
+ // Pass the parameters to WriteFile.
+ if (!WriteFile(SOME_SPOOL_FILE_HANDLE, pBuf, cbBuf, pcWritten, NULL))
+ {
+ dwErrorCode = GetLastError();
+ ERR("WriteFile failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+#endif
+
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+LocalEndPagePrinter(HANDLE hPrinter)
+{
+ DWORD dwErrorCode;
+ PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle || pHandle->HandleType != HandleType_Printer)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // This function doesn't do anything else for now.
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+LocalEndDocPrinter(HANDLE hPrinter)
+{
+ BOOL bReturnValue;
+ DWORD dwErrorCode;
+ PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
+ PLOCAL_PORT_HANDLE pPortHandle;
+ PLOCAL_PRINTER_HANDLE pPrinterHandle;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Port handles are an entirely different thing.
+ if (pHandle->HandleType == HandleType_Port)
+ {
+ pPortHandle = (PLOCAL_PORT_HANDLE)pHandle->pSpecificHandle;
+
+ // Call the monitor's EndDocPort function.
+ if (pPortHandle->pPort->pPrintMonitor->bIsLevel2)
+ bReturnValue = ((PMONITOR2)pPortHandle->pPort->pPrintMonitor->pMonitor)->pfnEndDocPort(pPortHandle->hPort);
+ else
+ bReturnValue = ((LPMONITOREX)pPortHandle->pPort->pPrintMonitor->pMonitor)->Monitor.pfnEndDocPort(pPortHandle->hPort);
+
+ if (!bReturnValue)
+ {
+ // The EndDocPort function failed. Return its last error.
+ dwErrorCode = GetLastError();
+ goto Cleanup;
+ }
+
+ // We were successful!
+ dwErrorCode = ERROR_SUCCESS;
+ goto Cleanup;
+ }
+
+ // The remaining function deals with Printer handles only.
+ if (pHandle->HandleType != HandleType_Printer)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
+
+ // We require StartDocPrinter or AddJob to be called first.
+ if (!pPrinterHandle->bStartedDoc)
+ {
+ dwErrorCode = ERROR_SPL_NO_STARTDOC;
+ goto Cleanup;
+ }
+
+ // TODO: Something like ScheduleJob
+
+ // Finish the job.
+ pPrinterHandle->bStartedDoc = FALSE;
+ pPrinterHandle->pJob = NULL;
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+LocalClosePrinter(HANDLE hPrinter)
+{
+ PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
+ PLOCAL_PORT_HANDLE pPortHandle;
+ PLOCAL_PRINTER_HANDLE pPrinterHandle;
+ PLOCAL_XCV_HANDLE pXcvHandle;
+
+ if (!pHandle)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ if (pHandle->HandleType == HandleType_Port)
+ {
+ pPortHandle = (PLOCAL_PORT_HANDLE)pHandle->pSpecificHandle;
+
+ // Call the monitor's ClosePort function.
+ if (pPortHandle->pPort->pPrintMonitor->bIsLevel2)
+ ((PMONITOR2)pPortHandle->pPort->pPrintMonitor->pMonitor)->pfnClosePort(pPortHandle->hPort);
+ else
+ ((LPMONITOREX)pPortHandle->pPort->pPrintMonitor->pMonitor)->Monitor.pfnClosePort(pPortHandle->hPort);
+ }
+ else if (pHandle->HandleType == HandleType_Printer)
+ {
+ pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
+
+ // Terminate any started job.
+ if (pPrinterHandle->pJob)
+ FreeJob(pPrinterHandle->pJob);
+
+ // Free memory for the fields.
+ DllFreeSplMem(pPrinterHandle->pDevMode);
+ DllFreeSplStr(pPrinterHandle->pwszDatatype);
+ }
+ else if (pHandle->HandleType == HandleType_Xcv)
+ {
+ pXcvHandle = (PLOCAL_XCV_HANDLE)pHandle->pSpecificHandle;
+
+ // Call the monitor's XcvClosePort function.
+ if (pXcvHandle->pPrintMonitor->bIsLevel2)
+ ((PMONITOR2)pXcvHandle->pPrintMonitor->pMonitor)->pfnXcvClosePort(pXcvHandle->hXcv);
+ else
+ ((LPMONITOREX)pXcvHandle->pPrintMonitor->pMonitor)->Monitor.pfnXcvClosePort(pXcvHandle->hXcv);
+ }
+
+ // Free memory for the handle and the specific handle.
+ DllFreeSplMem(pHandle->pSpecificHandle);
+ DllFreeSplMem(pHandle);
+
+ return TRUE;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Spooler
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Implementation of the Thread that actually performs the printing process
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+DWORD WINAPI
+PrintingThreadProc(PLOCAL_JOB pJob)
+{
+ const DWORD cchMaxJobIdDigits = 5; // Job ID is limited to 5 decimal digits, see IS_VALID_JOB_ID
+ const WCHAR wszJobAppendix[] = L", Job ";
+ const DWORD cchJobAppendix = _countof(wszJobAppendix) - 1;
+ const WCHAR wszPortAppendix[] = L", Port";
+
+ DWORD cchPortName;
+ DWORD cchPrinterName;
+ DWORD dwErrorCode;
+ HANDLE hPrintProcessor = NULL;
+ PLOCAL_PRINT_PROCESSOR pPrintProcessor = pJob->pPrintProcessor;
+ PRINTPROCESSOROPENDATA OpenData;
+ PWSTR pwszPrinterAndJob = NULL;
+ PWSTR pwszPrinterPort = NULL;
+ PWSTR pwszSPLFile = NULL;
+
+ // Prepare the pPrinterName parameter.
+ // This is the string for LocalOpenPrinter to open a port (e.g. "LPT1:, Port").
+ cchPortName = wcslen(pJob->pPrinter->pPort->pwszName);
+ pwszPrinterPort = DllAllocSplMem(cchPortName * sizeof(WCHAR) + sizeof(wszPortAppendix));
+ if (!pwszPrinterPort)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ CopyMemory(pwszPrinterPort, pJob->pPrinter->pPort->pwszName, cchPortName * sizeof(WCHAR));
+ CopyMemory(&pwszPrinterPort[cchPortName], wszPortAppendix, sizeof(wszPortAppendix));
+
+ // Prepare the pPrintProcessorOpenData parameter.
+ OpenData.JobId = pJob->dwJobID;
+ OpenData.pDatatype = pJob->pwszDatatype;
+ OpenData.pDevMode = pJob->pDevMode;
+ OpenData.pDocumentName = pJob->pwszDocumentName;
+ OpenData.pOutputFile = NULL;
+ OpenData.pParameters = pJob->pwszPrintProcessorParameters;
+ OpenData.pPrinterName = pJob->pPrinter->pwszPrinterName;
+
+ // Associate our job to the port. The next port handle created through LocalOpenPrinter will pick this up.
+ // LocalStartDocPrinter needs this information to call StartDocPort of the Print Monitor, but as the parameters
+ // for LocalOpenPrinter and LocalStartDocPrinter are fixed, we can only pass over the information this way.
+ pJob->pPrinter->pPort->pNextJobToProcess = pJob;
+
+ // Open a handle to the Print Processor.
+ hPrintProcessor = pPrintProcessor->pfnOpenPrintProcessor(pwszPrinterPort, &OpenData);
+ if (!hPrintProcessor)
+ {
+ dwErrorCode = GetLastError();
+ ERR("OpenPrintProcessor failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Let other functions use the Print Processor as well while it's opened.
+ pJob->hPrintProcessor = hPrintProcessor;
+
+ // Prepare the pDocumentName parameter.
+ cchPrinterName = wcslen(OpenData.pPrinterName);
+ pwszPrinterAndJob = DllAllocSplMem((cchPrinterName + cchJobAppendix + cchMaxJobIdDigits + 1) * sizeof(WCHAR));
+ if (!pwszPrinterAndJob)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ CopyMemory(pwszPrinterAndJob, OpenData.pPrinterName, cchPrinterName * sizeof(WCHAR));
+ CopyMemory(&pwszPrinterAndJob[cchPrinterName], wszJobAppendix, cchJobAppendix * sizeof(WCHAR));
+ _ultow(OpenData.JobId, &pwszPrinterAndJob[cchPrinterName + cchJobAppendix], 10);
+
+ // Printing starts here.
+ pJob->dwStatus |= JOB_STATUS_PRINTING;
+
+ // Print the document.
+ // Note that pJob is freed after this function, so we may not access it anymore.
+ if (!pPrintProcessor->pfnPrintDocumentOnPrintProcessor(hPrintProcessor, pwszPrinterAndJob))
+ {
+ dwErrorCode = GetLastError();
+ ERR("PrintDocumentOnPrintProcessor failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Close the Print Processor.
+ pPrintProcessor->pfnClosePrintProcessor(hPrintProcessor);
+ hPrintProcessor = NULL;
+
+ // Delete the spool file.
+ pwszSPLFile = DllAllocSplMem(GetJobFilePath(L"SPL", 0, NULL));
+ if (!pwszSPLFile)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ GetJobFilePath(L"SPL", OpenData.JobId, pwszSPLFile);
+ DeleteFileW(pwszSPLFile);
+
+ // We were successful!
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ if (hPrintProcessor)
+ pPrintProcessor->pfnClosePrintProcessor(hPrintProcessor);
+
+ if (pwszPrinterPort)
+ DllFreeSplMem(pwszPrinterPort);
+
+ if (pwszPrinterAndJob)
+ DllFreeSplMem(pwszPrinterAndJob);
+
+ if (pwszSPLFile)
+ DllFreeSplMem(pwszSPLFile);
+
+ return dwErrorCode;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Spooler
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions related to Print Processors
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+
+// Local Variables
+static LIST_ENTRY _PrintProcessorList;
+
+/**
+ * @name _OpenEnvironment
+ *
+ * Checks a supplied pEnvironment variable for validity and opens its registry key.
+ *
+ * @param pEnvironment
+ * The pEnvironment variable to check. Can be NULL to use the current environment.
+ *
+ * @param hKey
+ * On success, this variable will contain a HKEY to the opened registry key of the environment.
+ * You can use it for further tasks and have to close it with RegCloseKey.
+ *
+ * @return
+ * A Windows Error Code indicating success or failure.
+ */
+static DWORD
+_OpenEnvironment(PCWSTR pEnvironment, PHKEY hKey)
+{
+ const WCHAR wszEnvironmentsKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Environments\\";
+ const DWORD cchEnvironmentsKey = _countof(wszEnvironmentsKey) - 1;
+
+ DWORD cchEnvironment;
+ DWORD dwErrorCode;
+ PWSTR pwszEnvironmentKey = NULL;
+
+ // Use the current environment if none was supplied.
+ if (!pEnvironment)
+ pEnvironment = wszCurrentEnvironment;
+
+ // Construct the registry key of the demanded environment.
+ cchEnvironment = wcslen(pEnvironment);
+ pwszEnvironmentKey = DllAllocSplMem((cchEnvironmentsKey + cchEnvironment + 1) * sizeof(WCHAR));
+ if (!pwszEnvironmentKey)
+ {
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ CopyMemory(pwszEnvironmentKey, wszEnvironmentsKey, cchEnvironmentsKey * sizeof(WCHAR));
+ CopyMemory(&pwszEnvironmentKey[cchEnvironmentsKey], pEnvironment, (cchEnvironment + 1) * sizeof(WCHAR));
+
+ // Open the registry key.
+ dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, pwszEnvironmentKey, 0, KEY_READ, hKey);
+ if (dwErrorCode == ERROR_FILE_NOT_FOUND)
+ {
+ dwErrorCode = ERROR_INVALID_ENVIRONMENT;
+ goto Cleanup;
+ }
+ else if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+Cleanup:
+ if (pwszEnvironmentKey)
+ DllFreeSplMem(pwszEnvironmentKey);
+
+ return dwErrorCode;
+}
+
+BOOL
+FindDatatype(const PLOCAL_PRINT_PROCESSOR pPrintProcessor, PCWSTR pwszDatatype)
+{
+ DWORD i;
+ PDATATYPES_INFO_1W pCurrentDatatype = pPrintProcessor->pDatatypesInfo1;
+
+ if (!pwszDatatype)
+ return FALSE;
+
+ for (i = 0; i < pPrintProcessor->dwDatatypeCount; i++)
+ {
+ if (wcsicmp(pCurrentDatatype->pName, pwszDatatype) == 0)
+ return TRUE;
+
+ ++pCurrentDatatype;
+ }
+
+ return FALSE;
+}
+
+PLOCAL_PRINT_PROCESSOR
+FindPrintProcessor(PCWSTR pwszName)
+{
+ PLIST_ENTRY pEntry;
+ PLOCAL_PRINT_PROCESSOR pPrintProcessor;
+
+ if (!pwszName)
+ return NULL;
+
+ for (pEntry = _PrintProcessorList.Flink; pEntry != &_PrintProcessorList; pEntry = pEntry->Flink)
+ {
+ pPrintProcessor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_PROCESSOR, Entry);
+
+ if (wcsicmp(pPrintProcessor->pwszName, pwszName) == 0)
+ return pPrintProcessor;
+ }
+
+ return NULL;
+}
+
+/**
+ * @name InitializePrintProcessorList
+ *
+ * Initializes a singly linked list of locally available Print Processors.
+ */
+BOOL
+InitializePrintProcessorList()
+{
+ DWORD cbDatatypes;
+ DWORD cbFileName;
+ DWORD cchPrintProcessorPath;
+ DWORD cchMaxSubKey;
+ DWORD cchPrintProcessorName;
+ DWORD dwErrorCode;
+ DWORD dwSubKeys;
+ DWORD i;
+ HINSTANCE hinstPrintProcessor;
+ HKEY hKey = NULL;
+ HKEY hSubKey = NULL;
+ HKEY hSubSubKey = NULL;
+ PLOCAL_PRINT_PROCESSOR pPrintProcessor = NULL;
+ WCHAR wszFileName[MAX_PATH];
+ WCHAR wszPrintProcessorPath[MAX_PATH];
+
+ // Initialize an empty list for our Print Processors.
+ InitializeListHead(&_PrintProcessorList);
+
+ // Prepare the path to the Print Processor directory.
+ if (!LocalGetPrintProcessorDirectory(NULL, NULL, 1, (PBYTE)wszPrintProcessorPath, sizeof(wszPrintProcessorPath), &cchPrintProcessorPath))
+ {
+ dwErrorCode = GetLastError();
+ goto Cleanup;
+ }
+
+ // LocalGetPrintProcessorDirectory returns the number of copied bytes. Convert this into a number of characters without the terminating null-character.
+ cchPrintProcessorPath /= sizeof(WCHAR);
+ --cchPrintProcessorPath;
+
+ // Append a trailing backslash.
+ wszPrintProcessorPath[cchPrintProcessorPath] = L'\\';
+ ++cchPrintProcessorPath;
+
+ // Open the environment registry key.
+ dwErrorCode = _OpenEnvironment(NULL, &hKey);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("_OpenEnvironment failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Open the "Print Processors" subkey.
+ dwErrorCode = (DWORD)RegOpenKeyExW(hKey, L"Print Processors", 0, KEY_READ, &hSubKey);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Get the number of Print Processors and maximum sub key length.
+ dwErrorCode = (DWORD)RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwSubKeys, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Loop through all available local Print Processors.
+ for (i = 0; i < dwSubKeys; i++)
+ {
+ // Cleanup tasks from the previous run
+ if (hSubSubKey)
+ {
+ RegCloseKey(hSubSubKey);
+ hSubSubKey = NULL;
+ }
+
+ if (pPrintProcessor)
+ {
+ if (pPrintProcessor->pwszName)
+ DllFreeSplStr(pPrintProcessor->pwszName);
+
+ if (pPrintProcessor->pDatatypesInfo1)
+ DllFreeSplMem(pPrintProcessor->pDatatypesInfo1);
+
+ DllFreeSplMem(pPrintProcessor);
+ pPrintProcessor = NULL;
+ }
+
+ // Create a new LOCAL_PRINT_PROCESSOR structure for it.
+ pPrintProcessor = DllAllocSplMem(sizeof(LOCAL_PRINT_PROCESSOR));
+ if (!pPrintProcessor)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Allocate memory for the Print Monitor Name.
+ pPrintProcessor->pwszName = DllAllocSplMem((cchMaxSubKey + 1) * sizeof(WCHAR));
+ if (!pPrintProcessor->pwszName)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Get the name of this Print Processor.
+ cchPrintProcessorName = cchMaxSubKey + 1;
+ dwErrorCode = (DWORD)RegEnumKeyExW(hSubKey, i, pPrintProcessor->pwszName, &cchPrintProcessorName, NULL, NULL, NULL, NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegEnumKeyExW failed with status %ld!\n", dwErrorCode);
+ continue;
+ }
+
+ // Open this Print Processor's registry key.
+ dwErrorCode = (DWORD)RegOpenKeyExW(hSubKey, pPrintProcessor->pwszName, 0, KEY_READ, &hSubSubKey);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegOpenKeyExW failed for Print Processor \"%S\" with status %lu!\n", pPrintProcessor->pwszName, dwErrorCode);
+ continue;
+ }
+
+ // Get the file name of the Print Processor.
+ cbFileName = sizeof(wszFileName);
+ dwErrorCode = (DWORD)RegQueryValueExW(hSubSubKey, L"Driver", NULL, NULL, (PBYTE)wszFileName, &cbFileName);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegQueryValueExW failed for Print Processor \"%S\" with status %lu!\n", pPrintProcessor->pwszName, dwErrorCode);
+ continue;
+ }
+
+ // Verify that our buffer is large enough.
+ if (cchPrintProcessorPath + cbFileName / sizeof(WCHAR) > MAX_PATH)
+ {
+ ERR("Print Processor directory \"%S\" for Print Processor \"%S\" is too long!\n", wszFileName, pPrintProcessor->pwszName);
+ continue;
+ }
+
+ // Construct the full path to the Print Processor.
+ CopyMemory(&wszPrintProcessorPath[cchPrintProcessorPath], wszFileName, cbFileName);
+
+ // Try to load it.
+ hinstPrintProcessor = LoadLibraryW(wszPrintProcessorPath);
+ if (!hinstPrintProcessor)
+ {
+ ERR("LoadLibraryW failed for \"%S\" with error %lu!\n", wszPrintProcessorPath, GetLastError());
+ continue;
+ }
+
+ // Get and verify all its function pointers.
+ pPrintProcessor->pfnClosePrintProcessor = (PClosePrintProcessor)GetProcAddress(hinstPrintProcessor, "ClosePrintProcessor");
+ if (!pPrintProcessor->pfnClosePrintProcessor)
+ {
+ ERR("Print Processor \"%S\" exports no ClosePrintProcessor!\n", wszPrintProcessorPath);
+ continue;
+ }
+
+ pPrintProcessor->pfnControlPrintProcessor = (PControlPrintProcessor)GetProcAddress(hinstPrintProcessor, "ControlPrintProcessor");
+ if (!pPrintProcessor->pfnControlPrintProcessor)
+ {
+ ERR("Print Processor \"%S\" exports no ControlPrintProcessor!\n", wszPrintProcessorPath);
+ continue;
+ }
+
+ pPrintProcessor->pfnEnumPrintProcessorDatatypesW = (PEnumPrintProcessorDatatypesW)GetProcAddress(hinstPrintProcessor, "EnumPrintProcessorDatatypesW");
+ if (!pPrintProcessor->pfnEnumPrintProcessorDatatypesW)
+ {
+ ERR("Print Processor \"%S\" exports no EnumPrintProcessorDatatypesW!\n", wszPrintProcessorPath);
+ continue;
+ }
+
+ pPrintProcessor->pfnGetPrintProcessorCapabilities = (PGetPrintProcessorCapabilities)GetProcAddress(hinstPrintProcessor, "GetPrintProcessorCapabilities");
+ if (!pPrintProcessor->pfnGetPrintProcessorCapabilities)
+ {
+ ERR("Print Processor \"%S\" exports no GetPrintProcessorCapabilities!\n", wszPrintProcessorPath);
+ continue;
+ }
+
+ pPrintProcessor->pfnOpenPrintProcessor = (POpenPrintProcessor)GetProcAddress(hinstPrintProcessor, "OpenPrintProcessor");
+ if (!pPrintProcessor->pfnOpenPrintProcessor)
+ {
+ ERR("Print Processor \"%S\" exports no OpenPrintProcessor!\n", wszPrintProcessorPath);
+ continue;
+ }
+
+ pPrintProcessor->pfnPrintDocumentOnPrintProcessor = (PPrintDocumentOnPrintProcessor)GetProcAddress(hinstPrintProcessor, "PrintDocumentOnPrintProcessor");
+ if (!pPrintProcessor->pfnPrintDocumentOnPrintProcessor)
+ {
+ ERR("Print Processor \"%S\" exports no PrintDocumentOnPrintProcessor!\n", wszPrintProcessorPath);
+ continue;
+ }
+
+ // Get all supported datatypes.
+ pPrintProcessor->pfnEnumPrintProcessorDatatypesW(NULL, NULL, 1, NULL, 0, &cbDatatypes, &pPrintProcessor->dwDatatypeCount);
+ pPrintProcessor->pDatatypesInfo1 = DllAllocSplMem(cbDatatypes);
+ if (!pPrintProcessor->pDatatypesInfo1)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ if (!pPrintProcessor->pfnEnumPrintProcessorDatatypesW(NULL, NULL, 1, (PBYTE)pPrintProcessor->pDatatypesInfo1, cbDatatypes, &cbDatatypes, &pPrintProcessor->dwDatatypeCount))
+ {
+ ERR("EnumPrintProcessorDatatypesW failed for Print Processor \"%S\" with error %lu!\n", wszPrintProcessorPath, GetLastError());
+ continue;
+ }
+
+ // Add the Print Processor to the list.
+ InsertTailList(&_PrintProcessorList, &pPrintProcessor->Entry);
+
+ // Don't let the cleanup routines free this.
+ pPrintProcessor = NULL;
+ }
+
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ // Inside the loop
+ if (hSubSubKey)
+ RegCloseKey(hSubSubKey);
+
+ if (pPrintProcessor)
+ {
+ if (pPrintProcessor->pwszName)
+ DllFreeSplStr(pPrintProcessor->pwszName);
+
+ if (pPrintProcessor->pDatatypesInfo1)
+ DllFreeSplMem(pPrintProcessor->pDatatypesInfo1);
+
+ DllFreeSplMem(pPrintProcessor);
+ }
+
+ // Outside the loop
+ if (hSubKey)
+ RegCloseKey(hSubKey);
+
+ if (hKey)
+ RegCloseKey(hKey);
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+/**
+ * @name LocalEnumPrintProcessorDatatypes
+ *
+ * Obtains an array of all datatypes supported by a particular Print Processor.
+ * Print Provider function for EnumPrintProcessorDatatypesA/EnumPrintProcessorDatatypesW.
+ *
+ * @param pName
+ * Server Name. Ignored here, because every caller of LocalEnumPrintProcessorDatatypes is interested in the local directory.
+ *
+ * @param pPrintProcessorName
+ * The (case-insensitive) name of the Print Processor to query.
+ *
+ * @param Level
+ * The level of the structure supplied through pDatatypes. This must be 1.
+ *
+ * @param pDatatypes
+ * Pointer to the buffer that receives an array of DATATYPES_INFO_1W structures.
+ * Can be NULL if you just want to know the required size of the buffer.
+ *
+ * @param cbBuf
+ * Size of the buffer you supplied for pDatatypes, in bytes.
+ *
+ * @param pcbNeeded
+ * Pointer to a variable that receives the required size of the buffer for pDatatypes, in bytes.
+ * This parameter mustn't be NULL!
+ *
+ * @param pcReturned
+ * Pointer to a variable that receives the number of elements of the DATATYPES_INFO_1W array.
+ * This parameter mustn't be NULL!
+ *
+ * @return
+ * TRUE if we successfully copied the array into pDatatypes, FALSE otherwise.
+ * A more specific error code can be obtained through GetLastError.
+ */
+BOOL WINAPI
+LocalEnumPrintProcessorDatatypes(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD Level, LPBYTE pDatatypes, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
+{
+ DWORD dwErrorCode;
+ PLOCAL_PRINT_PROCESSOR pPrintProcessor;
+
+ // Sanity checks
+ if (Level != 1)
+ {
+ dwErrorCode = ERROR_INVALID_LEVEL;
+ goto Cleanup;
+ }
+
+ // Try to find the Print Processor.
+ pPrintProcessor = FindPrintProcessor(pPrintProcessorName);
+ if (!pPrintProcessor)
+ {
+ dwErrorCode = ERROR_UNKNOWN_PRINTPROCESSOR;
+ goto Cleanup;
+ }
+
+ // Call its EnumPrintProcessorDatatypesW function.
+ if (pPrintProcessor->pfnEnumPrintProcessorDatatypesW(pName, pPrintProcessorName, Level, pDatatypes, cbBuf, pcbNeeded, pcReturned))
+ dwErrorCode = ERROR_SUCCESS;
+ else
+ dwErrorCode = GetLastError();
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+/**
+ * @name LocalEnumPrintProcessors
+ *
+ * Obtains an array of all available Print Processors on this computer.
+ * Print Provider function for EnumPrintProcessorsA/EnumPrintProcessorsW.
+ *
+ * @param pName
+ * Server Name. Ignored here, because every caller of LocalEnumPrintProcessors is interested in the local directory.
+ *
+ * @param pEnvironment
+ * One of the predefined operating system and architecture "environment" strings (like "Windows NT x86").
+ * Alternatively, NULL to output the Print Processor directory of the current environment.
+ *
+ * @param Level
+ * The level of the structure supplied through pPrintProcessorInfo. This must be 1.
+ *
+ * @param pPrintProcessorInfo
+ * Pointer to the buffer that receives an array of PRINTPROCESSOR_INFO_1W structures.
+ * Can be NULL if you just want to know the required size of the buffer.
+ *
+ * @param cbBuf
+ * Size of the buffer you supplied for pPrintProcessorInfo, in bytes.
+ *
+ * @param pcbNeeded
+ * Pointer to a variable that receives the required size of the buffer for pPrintProcessorInfo, in bytes.
+ * This parameter mustn't be NULL!
+ *
+ * @param pcReturned
+ * Pointer to a variable that receives the number of elements of the PRINTPROCESSOR_INFO_1W array.
+ * This parameter mustn't be NULL!
+ *
+ * @return
+ * TRUE if we successfully copied the array into pPrintProcessorInfo, FALSE otherwise.
+ * A more specific error code can be obtained through GetLastError.
+ */
+BOOL WINAPI
+LocalEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
+{
+ DWORD cchMaxSubKey;
+ DWORD cchPrintProcessor;
+ DWORD dwErrorCode;
+ DWORD dwPrintProcessorCount;
+ DWORD i;
+ HKEY hKey = NULL;
+ HKEY hSubKey = NULL;
+ PBYTE pCurrentOutputPrintProcessor;
+ PBYTE pCurrentOutputPrintProcessorInfo;
+ PRINTPROCESSOR_INFO_1W PrintProcessorInfo1;
+ PWSTR pwszTemp = NULL;
+
+ // Sanity checks
+ if (Level != 1)
+ {
+ dwErrorCode = ERROR_INVALID_LEVEL;
+ goto Cleanup;
+ }
+
+ if (!pcbNeeded || !pcReturned)
+ {
+ // This error is also caught by RPC and returned as RPC_X_NULL_REF_POINTER.
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // Verify pEnvironment and open its registry key.
+ // We use the registry and not the PrintProcessorList here, because the caller may request information about a different environment.
+ dwErrorCode = _OpenEnvironment(pEnvironment, &hKey);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("_OpenEnvironment failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Open the "Print Processors" subkey.
+ dwErrorCode = (DWORD)RegOpenKeyExW(hKey, L"Print Processors", 0, KEY_READ, &hSubKey);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Get the number of Print Processors and maximum sub key length.
+ dwErrorCode = (DWORD)RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwPrintProcessorCount, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Allocate a temporary buffer to let RegEnumKeyExW succeed.
+ pwszTemp = DllAllocSplMem((cchMaxSubKey + 1) * sizeof(WCHAR));
+ if (!pwszTemp)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Determine the required size of the output buffer.
+ *pcbNeeded = 0;
+
+ for (i = 0; i < dwPrintProcessorCount; i++)
+ {
+ // RegEnumKeyExW sucks! Unlike similar API functions, it only returns the actual numbers of characters copied when you supply a buffer large enough.
+ // So use pwszTemp with its size cchMaxSubKey for this.
+ cchPrintProcessor = cchMaxSubKey + 1;
+ dwErrorCode = (DWORD)RegEnumKeyExW(hSubKey, i, pwszTemp, &cchPrintProcessor, NULL, NULL, NULL, NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegEnumKeyExW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ *pcbNeeded += sizeof(PRINTPROCESSOR_INFO_1W) + (cchPrintProcessor + 1) * sizeof(WCHAR);
+ }
+
+ // Check if the supplied buffer is large enough.
+ if (cbBuf < *pcbNeeded)
+ {
+ dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
+ goto Cleanup;
+ }
+
+ // Put the Print Processor strings right after the last PRINTPROCESSOR_INFO_1W structure.
+ pCurrentOutputPrintProcessorInfo = pPrintProcessorInfo;
+ pCurrentOutputPrintProcessor = pPrintProcessorInfo + dwPrintProcessorCount * sizeof(PRINTPROCESSOR_INFO_1W);
+
+ // Copy over all Print Processors.
+ for (i = 0; i < dwPrintProcessorCount; i++)
+ {
+ // This isn't really correct, but doesn't cause any harm, because we've extensively checked the size of the supplied buffer above.
+ cchPrintProcessor = cchMaxSubKey + 1;
+
+ // Copy the Print Processor name.
+ dwErrorCode = (DWORD)RegEnumKeyExW(hSubKey, i, (PWSTR)pCurrentOutputPrintProcessor, &cchPrintProcessor, NULL, NULL, NULL, NULL);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegEnumKeyExW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Fill and copy the PRINTPROCESSOR_INFO_1W structure belonging to this Print Processor.
+ PrintProcessorInfo1.pName = (PWSTR)pCurrentOutputPrintProcessor;
+ CopyMemory(pCurrentOutputPrintProcessorInfo, &PrintProcessorInfo1, sizeof(PRINTPROCESSOR_INFO_1W));
+
+ // Advance to the next PRINTPROCESSOR_INFO_1W location and string location in the output buffer.
+ pCurrentOutputPrintProcessor += (cchPrintProcessor + 1) * sizeof(WCHAR);
+ pCurrentOutputPrintProcessorInfo += sizeof(PRINTPROCESSOR_INFO_1W);
+ }
+
+ // We've finished successfully!
+ *pcReturned = dwPrintProcessorCount;
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ if (pwszTemp)
+ DllFreeSplMem(pwszTemp);
+
+ if (hSubKey)
+ RegCloseKey(hSubKey);
+
+ if (hKey)
+ RegCloseKey(hKey);
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+/**
+ * @name LocalGetPrintProcessorDirectory
+ *
+ * Obtains the path to the local Print Processor directory.
+ * Print Provider function for GetPrintProcessorDirectoryA/GetPrintProcessorDirectoryW.
+ *
+ * @param pName
+ * Server Name. Ignored here, because every caller of LocalGetPrintProcessorDirectory is interested in the local directory.
+ *
+ * @param pEnvironment
+ * One of the predefined operating system and architecture "environment" strings (like "Windows NT x86").
+ * Alternatively, NULL to output the Print Processor directory of the current environment.
+ *
+ * @param Level
+ * The level of the (non-existing) structure supplied through pPrintProcessorInfo. This must be 1.
+ *
+ * @param pPrintProcessorInfo
+ * Pointer to the buffer that receives the full path to the Print Processor directory.
+ * Can be NULL if you just want to know the required size of the buffer.
+ *
+ * @param cbBuf
+ * Size of the buffer you supplied for pPrintProcessorInfo, in bytes.
+ *
+ * @param pcbNeeded
+ * Pointer to a variable that receives the required size of the buffer for pPrintProcessorInfo, in bytes.
+ * This parameter mustn't be NULL!
+ *
+ * @return
+ * TRUE if we successfully copied the directory into pPrintProcessorInfo, FALSE otherwise.
+ * A more specific error code can be obtained through GetLastError.
+ */
+BOOL WINAPI
+LocalGetPrintProcessorDirectory(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded)
+{
+ const WCHAR wszPath[] = L"\\PRTPROCS\\";
+ const DWORD cchPath = _countof(wszPath) - 1;
+
+ DWORD cbDirectoryName;
+ DWORD dwErrorCode;
+ HKEY hKey = NULL;
+ PWSTR pwszDirectory = (PWSTR)pPrintProcessorInfo;
+
+ // Sanity checks
+ if (Level != 1)
+ {
+ dwErrorCode = ERROR_INVALID_LEVEL;
+ goto Cleanup;
+ }
+
+ if (!pcbNeeded)
+ {
+ // This error is also caught by RPC and returned as RPC_X_NULL_REF_POINTER.
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // Verify pEnvironment and open its registry key.
+ dwErrorCode = _OpenEnvironment(pEnvironment, &hKey);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("_OpenEnvironment failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Determine the size of the required buffer.
+ dwErrorCode = (DWORD)RegQueryValueExW(hKey, L"Directory", NULL, NULL, NULL, &cbDirectoryName);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ *pcbNeeded = (cchSpoolDirectory + cchPath) * sizeof(WCHAR) + cbDirectoryName;
+
+ // Is the supplied buffer large enough?
+ if (cbBuf < *pcbNeeded)
+ {
+ dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
+ goto Cleanup;
+ }
+
+ // Copy the path to the "prtprocs" directory into pPrintProcessorInfo
+ CopyMemory(pwszDirectory, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR));
+ CopyMemory(&pwszDirectory[cchSpoolDirectory], wszPath, cchPath * sizeof(WCHAR));
+
+ // Get the directory name from the registry.
+ dwErrorCode = (DWORD)RegQueryValueExW(hKey, L"Directory", NULL, NULL, (PBYTE)&pwszDirectory[cchSpoolDirectory + cchPath], &cbDirectoryName);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // We've finished successfully!
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ if (hKey)
+ RegCloseKey(hKey);
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Spooler
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE: Various tools
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+/**
+ * @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 DllFreeSplMem.
+ *
+ * @param hKey
+ * HKEY variable of the key opened with RegOpenKeyExW.
+ *
+ * @param pwszValueName
+ * Name of the REG_SZ value to query.
+ *
+ * @return
+ * Pointer to the buffer containing the value or NULL in case of failure.
+ */
+PWSTR
+AllocAndRegQueryWSZ(HKEY hKey, PCWSTR pwszValueName)
+{
+ DWORD cbNeeded;
+ LONG lStatus;
+ PWSTR pwszValue;
+
+ // Determine the size of the required buffer.
+ lStatus = RegQueryValueExW(hKey, pwszValueName, NULL, NULL, NULL, &cbNeeded);
+ if (lStatus != ERROR_SUCCESS)
+ {
+ ERR("RegQueryValueExW failed with status %ld!\n", lStatus);
+ return NULL;
+ }
+
+ // Allocate it.
+ pwszValue = DllAllocSplMem(cbNeeded);
+ if (!pwszValue)
+ {
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ return NULL;
+ }
+
+ // Now get the actual value.
+ lStatus = RegQueryValueExW(hKey, pwszValueName, NULL, NULL, (PBYTE)pwszValue, &cbNeeded);
+ if (lStatus != ERROR_SUCCESS)
+ {
+ ERR("RegQueryValueExW failed with status %ld!\n", lStatus);
+ DllFreeSplMem(pwszValue);
+ return NULL;
+ }
+
+ return pwszValue;
+}
+
+PDEVMODEW
+DuplicateDevMode(PDEVMODEW pInput)
+{
+ PDEVMODEW pOutput;
+
+ // Allocate a buffer for this DevMode.
+ pOutput = DllAllocSplMem(pInput->dmSize + pInput->dmDriverExtra);
+ if (!pOutput)
+ {
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ return NULL;
+ }
+
+ // Copy it.
+ CopyMemory(pOutput, pInput, pInput->dmSize + pInput->dmDriverExtra);
+
+ return pOutput;
+}
add_subdirectory(tee)
add_subdirectory(touch)
add_subdirectory(uptime)
+add_subdirectory(winspool_print)
add_subdirectory(y)
--- /dev/null
+add_executable(winspool_print main.c)
+set_module_type(winspool_print win32cui)
+add_importlibs(winspool_print winspool msvcrt kernel32)
+add_cd_file(TARGET winspool_print DESTINATION reactos/system32 FOR all)
--- /dev/null
+#include <stdio.h>
+#include <windows.h>
+
+int main()
+{
+ int ReturnValue = 1;
+ DWORD dwRead;
+ DWORD dwWritten;
+ HANDLE hFile = INVALID_HANDLE_VALUE;
+ HANDLE hPrinter = NULL;
+ DOC_INFO_1W docInfo;
+ BYTE Buffer[20000];
+
+ hFile = CreateFileW(L"testfile", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ printf("CreateFileW failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ if (!ReadFile(hFile, Buffer, sizeof(Buffer), &dwRead, NULL))
+ {
+ printf("ReadFile failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ if (!OpenPrinterW(L"Dummy Printer On LPT1", &hPrinter, NULL))
+ {
+ printf("OpenPrinterW failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ ZeroMemory(&docInfo, sizeof(docInfo));
+ docInfo.pDocName = L"winspool_print";
+
+ if (!StartDocPrinterW(hPrinter, 1, (LPBYTE)&docInfo))
+ {
+ printf("StartDocPrinterW failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ if (!StartPagePrinter(hPrinter))
+ {
+ printf("StartPagePrinter failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ if (!WritePrinter(hPrinter, Buffer, dwRead, &dwWritten))
+ {
+ printf("WritePrinter failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ if (!EndPagePrinter(hPrinter))
+ {
+ printf("EndPagePrinter failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ if (!EndDocPrinter(hPrinter))
+ {
+ printf("EndDocPrinter failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ ReturnValue = 0;
+
+Cleanup:
+ if (hFile != INVALID_HANDLE_VALUE)
+ CloseHandle(hFile);
+
+ if (hPrinter)
+ ClosePrinter(hPrinter);
+
+ return ReturnValue;
+}
if(NOT ARCH STREQUAL "amd64")
add_subdirectory(kernel32)
endif()
+add_subdirectory(localspl)
add_subdirectory(msgina)
add_subdirectory(msvcrt)
add_subdirectory(ntdll)
add_subdirectory(sdk)
add_subdirectory(setupapi)
add_subdirectory(shell32)
+add_subdirectory(spoolss)
add_subdirectory(psapi)
add_subdirectory(user32)
add_subdirectory(user32_dynamic)
endif()
add_subdirectory(winhttp)
add_subdirectory(wininet)
+add_subdirectory(winprint)
+add_subdirectory(winspool)
add_subdirectory(ws2_32)
--- /dev/null
+
+add_subdirectory(dll)
+
+list(APPEND SOURCE
+ service.c
+ tests.c
+ testlist.c)
+
+add_executable(localspl_apitest ${SOURCE})
+target_link_libraries(localspl_apitest wine ${PSEH_LIB})
+set_module_type(localspl_apitest win32cui)
+add_importlibs(localspl_apitest advapi32 winspool msvcrt kernel32 ntdll)
+add_cd_file(TARGET localspl_apitest DESTINATION reactos/bin FOR all)
--- /dev/null
+
+include_directories(${REACTOS_SOURCE_DIR}/win32ss/printing/include)
+
+list(APPEND SOURCE
+ fpEnumPrinters.c
+ main.c)
+
+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 spoolss msvcrt kernel32 ntdll)
+set_target_properties(localspl_apitest.dll PROPERTIES SUFFIX "")
+add_cd_file(TARGET localspl_apitest.dll DESTINATION reactos/bin FOR all)
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Spooler API Tests Injected DLL
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Tests for fpEnumPrinters
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include <apitest.h>
+
+#define WIN32_NO_STATUS
+#include <windef.h>
+#include <winbase.h>
+#include <wingdi.h>
+#include <winreg.h>
+#include <winspool.h>
+#include <winsplp.h>
+
+#include "../localspl_apitest.h"
+#include <spoolss.h>
+
+extern BOOL GetLocalsplFuncs(LPPRINTPROVIDOR pp);
+
+START_TEST(fpEnumPrinters)
+{
+ DWORD cbNeeded;
+ DWORD cbTemp;
+ DWORD dwReturned;
+ DWORD i;
+ PRINTPROVIDOR pp;
+ PPRINTER_INFO_1W pPrinterInfo1;
+ PVOID pMem;
+
+ if (!GetLocalsplFuncs(&pp))
+ return;
+
+ // Verify that localspl only returns information about a single print provider (namely itself).
+ cbNeeded = 0xDEADBEEF;
+ dwReturned = 0xDEADBEEF;
+ SetLastError(0xDEADBEEF);
+ ok(!pp.fpEnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME, NULL, 1, NULL, 0, &cbNeeded, &dwReturned), "fpEnumPrinters returns TRUE\n");
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "fpEnumPrinters returns error %lu!\n", GetLastError());
+ ok(cbNeeded > 0, "cbNeeded is 0!\n");
+ ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
+ SetLastError(0xDEADBEEF);
+ pPrinterInfo1 = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
+ ok(pp.fpEnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME, NULL, 1, (PBYTE)pPrinterInfo1, cbNeeded, &cbNeeded, &dwReturned), "fpEnumPrinters returns FALSE\n");
+ ok(GetLastError() == ERROR_SUCCESS, "fpEnumPrinters returns error %lu!\n", GetLastError());
+ ok(cbNeeded > 0, "cbNeeded is 0!\n");
+ ok(dwReturned == 1, "dwReturned is %lu!\n", dwReturned);
+
+ // Verify the actual strings returned.
+ 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++)
+ {
+ // 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);
+
+ // 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);
+
+ // This test corrupts something inside spoolsv so that it's only runnable once without restarting spoolsv. Therefore it's disabled.
+#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);
+ }
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Spooler API Tests Injected DLL
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Main functions
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#define __ROS_LONG64__
+
+#define STANDALONE
+#include <apitest.h>
+
+#define WIN32_NO_STATUS
+#include <io.h>
+#include <windef.h>
+#include <winbase.h>
+#include <wingdi.h>
+#include <winreg.h>
+#include <winspool.h>
+#include <winsplp.h>
+
+#include "../localspl_apitest.h"
+
+//#define NDEBUG
+#include <debug.h>
+
+// Test list
+extern void func_fpEnumPrinters(void);
+
+const struct test winetest_testlist[] =
+{
+ { "fpEnumPrinters", func_fpEnumPrinters },
+
+ { 0, 0 }
+};
+
+BOOL
+GetLocalsplFuncs(LPPRINTPROVIDOR pp)
+{
+ HMODULE hLocalspl;
+ PInitializePrintProvidor pfnInitializePrintProvidor;
+
+ // Get us a handle to the loaded localspl.dll.
+ hLocalspl = GetModuleHandleW(L"localspl");
+ if (!hLocalspl)
+ {
+ skip("GetModuleHandleW failed with error %u!\n", GetLastError());
+ return FALSE;
+ }
+
+ // Get a pointer to its InitializePrintProvidor function.
+ pfnInitializePrintProvidor = (PInitializePrintProvidor)GetProcAddress(hLocalspl, "InitializePrintProvidor");
+ if (!pfnInitializePrintProvidor)
+ {
+ skip("GetProcAddress failed with error %u!\n", GetLastError());
+ return FALSE;
+ }
+
+ // Get localspl's function pointers.
+ if (!pfnInitializePrintProvidor(pp, sizeof(PRINTPROVIDOR), NULL))
+ {
+ skip("pfnInitializePrintProvidor failed with error %u!\n", GetLastError());
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// Running the tests from the injected DLL and redirecting their output to the pipe.
+BOOL WINAPI
+DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ char szTestName[150];
+ DWORD cbRead;
+ FILE* fpStdout;
+ HANDLE hCommandPipe;
+ int iOldStdout;
+
+ // We only want to run our test once when the DLL is injected to the process.
+ if (fdwReason != DLL_PROCESS_ATTACH)
+ return TRUE;
+
+ // Read the test to run from the command pipe.
+ hCommandPipe = CreateFileW(COMMAND_PIPE_NAME, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+ if (hCommandPipe == INVALID_HANDLE_VALUE)
+ {
+ DPRINT("DLL: CreateFileW failed for the command pipe with error %lu!\n", GetLastError());
+ return FALSE;
+ }
+
+ if (!ReadFile(hCommandPipe, szTestName, sizeof(szTestName), &cbRead, NULL))
+ {
+ DPRINT("DLL: ReadFile failed for the command pipe with error %lu!\n", GetLastError());
+ return FALSE;
+ }
+
+ CloseHandle(hCommandPipe);
+
+ // Check if the test name is valid.
+ if (!find_test(szTestName))
+ {
+ DPRINT("DLL: Got invalid test name \"%s\"!\n", szTestName);
+ return FALSE;
+ }
+
+ // Backup our current stdout and set it to the output pipe.
+ iOldStdout = _dup(_fileno(stdout));
+ fpStdout = _wfreopen(OUTPUT_PIPE_NAME, L"w", stdout);
+ setbuf(stdout, NULL);
+
+ // Run the test.
+ run_test(szTestName);
+
+ // Restore stdout to the previous value.
+ fclose(fpStdout);
+ _dup2(iOldStdout, _fileno(stdout));
+
+ // Return FALSE so that our DLL is immediately unloaded.
+ return FALSE;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Spooler API Tests
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Shared definitions for the test program and the test DLL
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#ifndef _LOCALSPL_APITEST_H
+#define _LOCALSPL_APITEST_H
+
+#define COMMAND_PIPE_NAME L"\\\\.\\pipe\\localspl_apitest_command_pipe"
+#define OUTPUT_PIPE_NAME L"\\\\.\\pipe\\localspl_apitest_output_pipe"
+#define SERVICE_NAME L"localspl_apitest_service"
+
+typedef BOOL (WINAPI *PInitializePrintProvidor)(LPPRINTPROVIDOR, DWORD, LPWSTR);
+
+#endif
\ No newline at end of file
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Spooler API Tests
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Functions needed to run our code as a service. This is needed to run in SYSTEM security context.
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include <apitest.h>
+
+#define WIN32_NO_STATUS
+#include <windef.h>
+#include <winbase.h>
+#include <wingdi.h>
+#include <winreg.h>
+#include <winsvc.h>
+#include <winspool.h>
+#include <winsplp.h>
+#include <tlhelp32.h>
+
+#include "localspl_apitest.h"
+
+//#define NDEBUG
+#include <debug.h>
+
+
+static void
+_DoDLLInjection()
+{
+ DWORD cbDLLPath;
+ HANDLE hProcess;
+ HANDLE hSnapshot;
+ HANDLE hThread;
+ PROCESSENTRY32W pe;
+ PVOID pLoadLibraryAddress;
+ PVOID pLoadLibraryArgument;
+ PWSTR p;
+ WCHAR wszFilePath[MAX_PATH];
+
+ // Get the full path to our EXE file.
+ if (!GetModuleFileNameW(NULL, wszFilePath, _countof(wszFilePath)))
+ {
+ DPRINT("GetModuleFileNameW failed with error %lu!\n", GetLastError());
+ return;
+ }
+
+ // Replace the extension.
+ p = wcsrchr(wszFilePath, L'.');
+ if (!p)
+ {
+ DPRINT("File path has no file extension: %S\n", wszFilePath);
+ return;
+ }
+
+ wcscpy(p, L".dll");
+ cbDLLPath = (wcslen(wszFilePath) + 1) * sizeof(WCHAR);
+
+ // Create a snapshot of the currently running processes.
+ hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (hSnapshot == INVALID_HANDLE_VALUE)
+ {
+ DPRINT("CreateToolhelp32Snapshot failed with error %lu!\n", GetLastError());
+ return;
+ }
+
+ // Enumerate through all running processes.
+ pe.dwSize = sizeof(pe);
+ if (!Process32FirstW(hSnapshot, &pe))
+ {
+ DPRINT("Process32FirstW failed with error %lu!\n", GetLastError());
+ return;
+ }
+
+ do
+ {
+ // Check if this is the spooler server process.
+ if (wcsicmp(pe.szExeFile, L"spoolsv.exe") != 0)
+ continue;
+
+ // Open a handle to the process.
+ hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);
+ if (!hProcess)
+ {
+ DPRINT("OpenProcess failed with error %lu!\n", GetLastError());
+ return;
+ }
+
+ // Get the address of LoadLibraryW.
+ pLoadLibraryAddress = (PVOID)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "LoadLibraryW");
+ if (!pLoadLibraryAddress)
+ {
+ DPRINT("GetProcAddress failed with error %lu!\n", GetLastError());
+ return;
+ }
+
+ // Allocate memory for the DLL path in the spooler process.
+ pLoadLibraryArgument = VirtualAllocEx(hProcess, NULL, cbDLLPath, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ if (!pLoadLibraryArgument)
+ {
+ DPRINT("VirtualAllocEx failed with error %lu!\n", GetLastError());
+ return;
+ }
+
+ // Write the DLL path to the process memory.
+ if (!WriteProcessMemory(hProcess, pLoadLibraryArgument, wszFilePath, cbDLLPath, NULL))
+ {
+ DPRINT("WriteProcessMemory failed with error %lu!\n", GetLastError());
+ return;
+ }
+
+ // Create a new thread in the spooler process that calls LoadLibraryW as the start routine with our DLL as the argument.
+ // This effectively injects our DLL into the spooler process and we can inspect localspl.dll there just like the spooler.
+ hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLibraryAddress, pLoadLibraryArgument, 0, NULL);
+ if (!hThread)
+ {
+ DPRINT("CreateRemoteThread failed with error %lu!\n", GetLastError());
+ return;
+ }
+
+ CloseHandle(hThread);
+ break;
+ }
+ while (Process32NextW(hSnapshot, &pe));
+}
+
+static DWORD WINAPI
+_ServiceControlHandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
+{
+ return NO_ERROR;
+}
+
+static void WINAPI
+_ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv)
+{
+ SERVICE_STATUS_HANDLE hServiceStatus;
+ SERVICE_STATUS ServiceStatus;
+
+ UNREFERENCED_PARAMETER(dwArgc);
+ UNREFERENCED_PARAMETER(lpszArgv);
+
+ // Register our service for control.
+ hServiceStatus = RegisterServiceCtrlHandlerExW(SERVICE_NAME, _ServiceControlHandlerEx, NULL);
+
+ // Report SERVICE_RUNNING status.
+ ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+ ServiceStatus.dwServiceSpecificExitCode = 0;
+ ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ ServiceStatus.dwWaitHint = 4000;
+ ServiceStatus.dwWin32ExitCode = NO_ERROR;
+ ServiceStatus.dwCurrentState = SERVICE_RUNNING;
+ SetServiceStatus(hServiceStatus, &ServiceStatus);
+
+ // Do our funky crazy stuff.
+ _DoDLLInjection();
+
+ // Our work is done.
+ ServiceStatus.dwCurrentState = SERVICE_STOPPED;
+ SetServiceStatus(hServiceStatus, &ServiceStatus);
+}
+
+START_TEST(service)
+{
+ int argc;
+ char** argv;
+
+ SERVICE_TABLE_ENTRYW ServiceTable[] =
+ {
+ { SERVICE_NAME, _ServiceMain },
+ { NULL, NULL }
+ };
+
+ // This is no real test, but an easy way to integrate the service handler routines into the API-Test executable.
+ // Therefore, bail out if someone tries to run "service" as a usual test.
+ argc = winetest_get_mainargs(&argv);
+ if (argc != 3)
+ return;
+
+ // If we have exactly 3 arguments, we're run as a service, so initialize the corresponding service handler functions.
+ StartServiceCtrlDispatcherW(ServiceTable);
+
+ // Prevent the testing framework from outputting a "0 tests executed" line here.
+ ExitProcess(0);
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Spooler API Tests
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Test list
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#define __ROS_LONG64__
+
+#define STANDALONE
+#include <apitest.h>
+
+extern void func_fpEnumPrinters(void);
+extern void func_service(void);
+
+const struct test winetest_testlist[] =
+{
+ { "fpEnumPrinters", func_fpEnumPrinters },
+ { "service", func_service },
+
+ { 0, 0 }
+};
--- /dev/null
+/*
+ * PROJECT: ReactOS Local Spooler API Tests
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Test list
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+/*
+ * The original localspl.dll from Windows Server 2003 is not easily testable.
+ * It relies on a proper initialization inside spoolsv.exe, so we can't just load it in an API-Test as usual.
+ * See https://www.reactos.org/pipermail/ros-dev/2015-June/017395.html for more information.
+ *
+ * To make testing possible anyway, this program basically does four things:
+ * - Injecting our testing code into spoolsv.exe.
+ * - Registering and running us as a service in the SYSTEM security context like spoolsv.exe, so that injection is possible at all.
+ * - Sending the test name and receiving the console output over named pipes.
+ * - Redirecting the received console output to stdout again, so it looks and feels like a standard API-Test.
+ *
+ * To simplify debugging of the injected code, it is entirely separated into a DLL file localspl_apitest.dll.
+ * What we actually inject is a LoadLibraryW call, so that the DLL is loaded gracefully without any hacks.
+ * Therefore, you can just attach your debugger to the spoolsv.exe process and set breakpoints on the localspl_apitest.dll code.
+ */
+
+#include <apitest.h>
+
+#define WIN32_NO_STATUS
+#include <stdio.h>
+#include <stdlib.h>
+#include <windef.h>
+#include <winbase.h>
+#include <wingdi.h>
+#include <winreg.h>
+#include <winsvc.h>
+#include <winspool.h>
+#include <winsplp.h>
+
+#include "localspl_apitest.h"
+
+
+static void
+_RunRemoteTest(const char* szTestName)
+{
+ BOOL bSuccessful = FALSE;
+ char szBuffer[1024];
+ DWORD cbRead;
+ DWORD cbWritten;
+ HANDLE hCommandPipe = INVALID_HANDLE_VALUE;
+ HANDLE hFind = NULL;
+ HANDLE hOutputPipe = INVALID_HANDLE_VALUE;
+ PWSTR p;
+ SC_HANDLE hSC = NULL;
+ SC_HANDLE hService = NULL;
+ SERVICE_STATUS ServiceStatus;
+ WCHAR wszFilePath[MAX_PATH + 20];
+ WIN32_FIND_DATAW fd;
+
+ // Do a dummy EnumPrintersW call.
+ // This guarantees that the Spooler Service has actually loaded localspl.dll, which is a requirement for our injected DLL to work properly.
+ EnumPrintersW(PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME, NULL, 1, NULL, 0, &cbRead, &cbWritten);
+
+ // Get the full path to our EXE file.
+ if (!GetModuleFileNameW(NULL, wszFilePath, MAX_PATH))
+ {
+ skip("GetModuleFileNameW failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Replace the extension.
+ p = wcsrchr(wszFilePath, L'.');
+ if (!p)
+ {
+ skip("File path has no file extension: %S\n", wszFilePath);
+ goto Cleanup;
+ }
+
+ wcscpy(p, L".dll");
+
+ // Check if the corresponding DLL file exists.
+ hFind = FindFirstFileW(wszFilePath, &fd);
+ if (!hFind)
+ {
+ skip("My DLL file \"%S\" does not exist!\n", wszFilePath);
+ goto Cleanup;
+ }
+
+ // Change the extension back to .exe and add the parameters.
+ wcscpy(p, L".exe service dummy");
+
+ // Open a handle to the service manager.
+ hSC = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ if (!hSC)
+ {
+ skip("OpenSCManagerW failed with error %lu!\n", GetLastError());
+ 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)
+ {
+ if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
+ {
+ // Create the service.
+ hService = CreateServiceW(hSC, SERVICE_NAME, NULL, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, wszFilePath, NULL, NULL, NULL, NULL, NULL);
+ if (!hService)
+ {
+ skip("CreateServiceW failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+ }
+ else
+ {
+ skip("OpenServiceW failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+ }
+
+ // Create pipes for the communication with the injected DLL.
+ hCommandPipe = CreateNamedPipeW(COMMAND_PIPE_NAME, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 1024, 1024, 10000, NULL);
+ if (hCommandPipe == INVALID_HANDLE_VALUE)
+ {
+ skip("CreateNamedPipeW failed for the command pipe with error %lu!\n", GetLastError());
+ 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());
+ 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());
+ goto Cleanup;
+ }
+
+ // 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());
+ goto Cleanup;
+ }
+
+ // Send the test name.
+ if (!WriteFile(hCommandPipe, szTestName, strlen(szTestName) + sizeof(char), &cbWritten, NULL))
+ {
+ skip("WriteFile failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // 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());
+ 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);
+
+ bSuccessful = TRUE;
+
+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)
+{
+ _RunRemoteTest("fpEnumPrinters");
+}
--- /dev/null
+
+include_directories(${REACTOS_SOURCE_DIR}/win32ss/printing/include)
+
+list(APPEND SOURCE
+ PackStrings.c
+ ReallocSplStr.c
+ SplInitializeWinSpoolDrv.c
+ testlist.c)
+
+add_executable(spoolss_apitest ${SOURCE})
+target_link_libraries(spoolss_apitest wine ${PSEH_LIB})
+set_module_type(spoolss_apitest win32cui)
+add_importlibs(spoolss_apitest spoolss msvcrt kernel32 ntdll)
+add_cd_file(TARGET spoolss_apitest DESTINATION reactos/bin FOR all)
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler Router API Tests
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Tests for PackStrings
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include <apitest.h>
+
+#define WIN32_NO_STATUS
+#include <windef.h>
+#include <winbase.h>
+#include <spoolss.h>
+
+typedef struct _EXAMPLE_STRUCT
+{
+ PWSTR String1;
+ PWSTR String2;
+}
+EXAMPLE_STRUCT, *PEXAMPLE_STRUCT;
+
+START_TEST(PackStrings)
+{
+ PCWSTR Source1[] = { L"Test", L"String" };
+ PCWSTR Source2[] = { L"Test", NULL };
+
+ BYTE Buffer[50];
+ PBYTE pEnd;
+ PEXAMPLE_STRUCT pStruct = (PEXAMPLE_STRUCT)Buffer;
+ DWORD Offsets[] = {
+ FIELD_OFFSET(EXAMPLE_STRUCT, String1),
+ FIELD_OFFSET(EXAMPLE_STRUCT, String2),
+ MAXDWORD
+ };
+
+ // Try a usual case with two strings. Verify that they are copied in reverse order.
+ pEnd = PackStrings(Source1, Buffer, Offsets, &Buffer[sizeof(Buffer)]);
+ ok(wcscmp(pStruct->String1, Source1[0]) == 0, "String1 and Source1[0] don't match!\n");
+ ok(wcscmp(pStruct->String2, Source1[1]) == 0, "String2 and Source1[1] don't match!\n");
+ ok(wcscmp((PWSTR)pEnd, Source1[1]) == 0, "pEnd and Source1[1] don't match!\n");
+
+ // Now verify that the corresponding pointer is set to NULL if a string is NULL.
+ pEnd = PackStrings(Source2, Buffer, Offsets, &Buffer[sizeof(Buffer)]);
+ ok(wcscmp(pStruct->String1, Source2[0]) == 0, "String1 and Source2[0] don't match!\n");
+ ok(!pStruct->String2, "String2 is %p!\n", pStruct->String2);
+ ok(wcscmp((PWSTR)pEnd, Source2[0]) == 0, "pEnd and Source2[0] don't match!\n");
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Spooler Router API Tests
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Tests for SplInitializeWinSpoolDrv
+ * 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(SplInitializeWinSpoolDrv)
+{
+ HINSTANCE hWinspool;
+ 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]);
+ ok(Table[1] == GetProcAddress(hWinspool, "ClosePrinter"), "Table[1] is %p\n", Table[1]);
+ ok(Table[2] == GetProcAddress(hWinspool, "SpoolerDevQueryPrintW"), "Table[2] is %p\n", Table[2]);
+ ok(Table[3] == GetProcAddress(hWinspool, "SpoolerPrinterEvent"), "Table[3] is %p\n", Table[3]);
+ ok(Table[4] == GetProcAddress(hWinspool, "DocumentPropertiesW"), "Table[4] is %p\n", Table[4]);
+ ok(Table[5] == GetProcAddress(hWinspool, (LPSTR)212), "Table[5] is %p\n", Table[5]);
+ ok(Table[6] == GetProcAddress(hWinspool, (LPSTR)213), "Table[6] is %p\n", Table[6]);
+ ok(Table[7] == GetProcAddress(hWinspool, (LPSTR)214), "Table[7] is %p\n", Table[7]);
+ ok(Table[8] == GetProcAddress(hWinspool, (LPSTR)215), "Table[8] is %p\n", Table[8]);
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler Router API Tests
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Test list
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#define __ROS_LONG64__
+
+#define STANDALONE
+#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 }
+};
--- /dev/null
+
+list(APPEND SOURCE
+ EnumPrintProcessorDatatypesW.c
+ testlist.c)
+
+add_executable(winprint_apitest ${SOURCE})
+target_link_libraries(winprint_apitest wine ${PSEH_LIB})
+set_module_type(winprint_apitest win32cui)
+add_importlibs(winprint_apitest winprint msvcrt kernel32 ntdll)
+add_cd_file(TARGET winprint_apitest DESTINATION reactos/bin FOR all)
--- /dev/null
+/*
+ * PROJECT: ReactOS Standard Print Processor API Tests
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Tests for EnumPrintProcessorDatatypesW
+ * COPYRIGHT: Copyright 2015 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(EnumPrintProcessorDatatypesW)
+{
+ DWORD cbNeeded;
+ DWORD cbTemp;
+ DWORD dwReturned;
+ PDATATYPES_INFO_1W pDatatypesInfo1;
+
+ // Try with an invalid level. The error needs to be set by winspool, but not by the Print Processor.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintProcessorDatatypesW(NULL, NULL, 0, NULL, 0, NULL, NULL), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+ ok(GetLastError() == 0xDEADBEEF, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+
+ // Now try with valid level, but no pcbNeeded and no pcReturned. The error needs to be set by RPC.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintProcessorDatatypesW(NULL, NULL, 1, NULL, 0, NULL, NULL), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+ ok(GetLastError() == 0xDEADBEEF, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+
+ // Now try with pcbNeeded and pcReturned, but give no Print Processor. Show that winprint actually ignores the given Print Processor.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintProcessorDatatypesW(NULL, NULL, 1, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+ ok(cbNeeded > 0, "cbNeeded is 0!\n");
+ ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
+ // Same error has to occur when looking for an invalid Print Processor.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintProcessorDatatypesW(NULL, L"invalid", 1, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+ ok(cbNeeded > 0, "cbNeeded is 0!\n");
+ ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
+ // Now get the required buffer size by supplying all information. This needs to fail with ERROR_INSUFFICIENT_BUFFER.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintProcessorDatatypesW(NULL, L"winprint", 1, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+ ok(cbNeeded > 0, "cbNeeded is 0!\n");
+ ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
+ // Same error has to occur with a size to small.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintProcessorDatatypesW(NULL, L"winprint", 1, NULL, 1, &cbNeeded, &dwReturned), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error %lu!\n", GetLastError());
+ ok(cbNeeded > 0, "cbNeeded is 0!\n");
+ ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
+ // Now provide the demanded size, but no buffer. Show that winprint returns a different error than the same function in winspool.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintProcessorDatatypesW(NULL, L"winprint", 1, NULL, cbNeeded, &cbTemp, &dwReturned), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+ ok(cbTemp == cbNeeded, "cbTemp is %lu!\n", cbTemp);
+ ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
+ // This also has to fail the same way when no Print Processor was given at all.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintProcessorDatatypesW(NULL, NULL, 1, NULL, cbNeeded, &cbTemp, &dwReturned), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+ ok(cbTemp == cbNeeded, "cbTemp is %lu!\n", cbTemp);
+ ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
+ // Finally use the function as intended and aim for success! Show that winprint doesn't modify the error code at all.
+ pDatatypesInfo1 = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
+ SetLastError(0xDEADBEEF);
+ ok(EnumPrintProcessorDatatypesW(NULL, L"winprint", 1, (PBYTE)pDatatypesInfo1, cbNeeded, &cbNeeded, &dwReturned), "EnumPrintProcessorDatatypesW returns FALSE!\n");
+ ok(GetLastError() == 0xDEADBEEF, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+ HeapFree(GetProcessHeap(), 0, pDatatypesInfo1);
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Standard Print Processor API Tests
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Test list
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+/*
+ * These tests are developed and tested against the Windows Server 2003 counterpart of winprint.
+ * While ReactOS implements the Standard Print Processor in a separate module winprint.dll,
+ * Windows Server 2003 puts it into the Local Print Spooler localspl.dll.
+ *
+ * To test against Windows, simply run these tests under Windows Server 2003, but copy its
+ * localspl.dll to winprint.dll in advance.
+ *
+ * winspool.drv also provides functions that go into winprint.dll, but as these tests show,
+ * they behave slightly different in terms of error codes due to the involved RPC and routing.
+ */
+
+#define __ROS_LONG64__
+
+#define STANDALONE
+#include <apitest.h>
+
+extern void func_EnumPrintProcessorDatatypesW(void);
+
+const struct test winetest_testlist[] =
+{
+ { "EnumPrintProcessorDatatypesW", func_EnumPrintProcessorDatatypesW },
+
+ { 0, 0 }
+};
--- /dev/null
+
+list(APPEND SOURCE
+ ClosePrinter.c
+ EnumPrinters.c
+ EnumPrintProcessorDatatypes.c
+ GetPrintProcessorDirectory.c
+ IsValidDevmode.c
+ OpenPrinter.c
+ StartDocPrinter.c
+ testlist.c)
+
+add_executable(winspool_apitest ${SOURCE})
+target_link_libraries(winspool_apitest wine ${PSEH_LIB})
+set_module_type(winspool_apitest win32cui)
+add_importlibs(winspool_apitest winspool msvcrt kernel32 ntdll)
+add_cd_file(TARGET winspool_apitest DESTINATION reactos/bin FOR all)
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler DLL API Tests
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Tests for ClosePrinter
+ * COPYRIGHT: Copyright 2015 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(ClosePrinter)
+{
+ SetLastError(0xDEADBEEF);
+ ok(!ClosePrinter(NULL), "ClosePrinter returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_HANDLE, "ClosePrinter returns error %lu!\n", GetLastError());
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler DLL API Tests
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Tests for EnumPrintProcessorDatatypesA/EnumPrintProcessorDatatypesW
+ * COPYRIGHT: Copyright 2015 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(EnumPrintProcessorDatatypes)
+{
+ DWORD cbNeeded;
+ DWORD cbTemp;
+ DWORD dwReturned;
+ PDATATYPES_INFO_1W pDatatypesInfo1;
+
+ // Try with an invalid level, this needs to be caught first.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintProcessorDatatypesW(NULL, NULL, 0, NULL, 0, NULL, NULL), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_LEVEL, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+
+ // Now try with valid level, but no pcbNeeded and no pcReturned.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintProcessorDatatypesW(NULL, NULL, 1, NULL, 0, NULL, NULL), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+ ok(GetLastError() == RPC_X_NULL_REF_POINTER, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+
+ // Now try with pcbNeeded and pcReturned, but give no Print Processor.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintProcessorDatatypesW(NULL, NULL, 1, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+ ok(GetLastError() == ERROR_UNKNOWN_PRINTPROCESSOR, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+
+ // Same error has to occur when looking for an invalid Print Processor.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintProcessorDatatypesW(NULL, L"invalid", 1, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+ ok(GetLastError() == ERROR_UNKNOWN_PRINTPROCESSOR, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+
+ // Now get the required buffer size by supplying all information. This needs to fail with ERROR_INSUFFICIENT_BUFFER.
+ // This also verifies that the function is really doing a case-insensitive lookup.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintProcessorDatatypesW(NULL, L"wInPrInT", 1, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+ ok(cbNeeded > 0, "cbNeeded is 0!\n");
+ ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
+ // Same error has to occur with a size to small.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintProcessorDatatypesW(NULL, L"wInPrInT", 1, NULL, 1, &cbNeeded, &dwReturned), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error %lu!\n", GetLastError());
+ ok(cbNeeded > 0, "cbNeeded is 0!\n");
+ ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
+ // Now provide the demanded size, but no buffer.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintProcessorDatatypesW(NULL, L"wInPrInT", 1, NULL, cbNeeded, &cbTemp, &dwReturned), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_USER_BUFFER, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+ ok(cbTemp == 0, "cbTemp is %lu!\n", cbTemp);
+ ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
+ // This also has to fail the same way when no Print Processor was given at all.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintProcessorDatatypesW(NULL, NULL, 1, NULL, cbNeeded, &cbTemp, &dwReturned), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_USER_BUFFER, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+ ok(cbTemp == 0, "cbTemp is %lu!\n", cbTemp);
+ ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
+ // Finally use the function as intended and aim for success!
+ pDatatypesInfo1 = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
+ SetLastError(0xDEADBEEF);
+ ok(EnumPrintProcessorDatatypesW(NULL, L"wInPrInT", 1, (PBYTE)pDatatypesInfo1, cbNeeded, &cbNeeded, &dwReturned), "EnumPrintProcessorDatatypesW returns FALSE!\n");
+ ok(GetLastError() == ERROR_SUCCESS, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+ HeapFree(GetProcessHeap(), 0, pDatatypesInfo1);
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler DLL API Tests
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Tests for EnumPrintersA/EnumPrintersW
+ * COPYRIGHT: Copyright 2015 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(EnumPrinters)
+{
+ DWORD cbNeeded;
+ DWORD cbTemp;
+ DWORD dwReturned;
+ PVOID pMem;
+ DWORD i;
+ DWORD dwValidLevels[] = { 0, 1, 2, 4, 5 };
+
+ // Level 5 is the highest supported under Windows Server 2003. Higher levels need to fail and leave the variables untouched!
+ cbNeeded = 0xDEADBEEF;
+ dwReturned = 0xDEADBEEF;
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintersW(0, NULL, 6, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_LEVEL, "EnumPrintersW returns error %lu!\n", GetLastError());
+ ok(cbNeeded == 0xDEADBEEF, "cbNeeded is %lu!\n", cbNeeded);
+ ok(dwReturned == 0xDEADBEEF, "dwReturned is %lu!\n", dwReturned);
+
+ // Same goes for level 3.
+ cbNeeded = 0xDEADBEEF;
+ dwReturned = 0xDEADBEEF;
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintersW(0, NULL, 3, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_LEVEL, "EnumPrintersW returns error %lu!\n", GetLastError());
+ ok(cbNeeded == 0xDEADBEEF, "cbNeeded is %lu!\n", cbNeeded);
+ ok(dwReturned == 0xDEADBEEF, "dwReturned is %lu!\n", dwReturned);
+
+ // Try for all valid levels. Level 0 is valid here and returns the PRINTER_INFO_STRESS structure (documented in MS-RPRN).
+ for (i = 0; i < sizeof(dwValidLevels) / sizeof(DWORD); i++)
+ {
+ // Try with no valid arguments at all.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintersW(0, NULL, dwValidLevels[i], NULL, 0, NULL, NULL), "EnumPrintersW returns TRUE for Level %lu!\n", dwValidLevels[i]);
+ ok(GetLastError() == RPC_X_NULL_REF_POINTER, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), dwValidLevels[i]);
+
+ // It has to succeed if we supply the required pointers and query no information.
+ SetLastError(0xDEADBEEF);
+ ok(EnumPrintersW(0, NULL, dwValidLevels[i], NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns FALSE for Level %lu!\n", dwValidLevels[i]);
+ ok(GetLastError() == ERROR_SUCCESS, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), dwValidLevels[i]);
+ ok(cbNeeded == 0, "cbNeeded is %lu for Level %lu!\n", cbNeeded, dwValidLevels[i]);
+ ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, dwValidLevels[i]);
+
+ // This constant is from Windows 9x/ME times and mustn't work anymore.
+ SetLastError(0xDEADBEEF);
+ ok(EnumPrintersW(PRINTER_ENUM_DEFAULT, NULL, dwValidLevels[i], NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns FALSE for Level %lu!\n", dwValidLevels[i]);
+ ok(GetLastError() == ERROR_SUCCESS, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), dwValidLevels[i]);
+ ok(cbNeeded == 0, "cbNeeded is %lu for Level %lu!\n", cbNeeded, dwValidLevels[i]);
+ ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, dwValidLevels[i]);
+
+ // Now things get interesting. Let's query the buffer size for information about the local printers.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, dwValidLevels[i], NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n", dwValidLevels[i]);
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), dwValidLevels[i]);
+ ok(cbNeeded > 0, "cbNeeded is 0 for Level %lu!\n", dwValidLevels[i]);
+ ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, dwValidLevels[i]);
+
+ // Same error has to occur with a size to small.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, dwValidLevels[i], NULL, 1, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n", dwValidLevels[i]);
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), dwValidLevels[i]);
+ ok(cbNeeded > 0, "cbNeeded is 0 for Level %lu!\n", dwValidLevels[i]);
+ ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, dwValidLevels[i]);
+
+ // Now provide the demanded size, but no buffer.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, dwValidLevels[i], NULL, cbNeeded, &cbTemp, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n", dwValidLevels[i]);
+ ok(GetLastError() == ERROR_INVALID_USER_BUFFER, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), dwValidLevels[i]);
+ ok(cbTemp == 0, "cbTemp is %lu for Level %lu!\n", cbTemp, dwValidLevels[i]);
+ ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, dwValidLevels[i]);
+
+ // Finally use the function as intended and aim for success!
+ pMem = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
+ SetLastError(0xDEADBEEF);
+ ok(EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, dwValidLevels[i], pMem, cbNeeded, &cbTemp, &dwReturned), "EnumPrintersW returns FALSE for Level %lu!\n", dwValidLevels[i]);
+ ok(GetLastError() == ERROR_SUCCESS, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), dwValidLevels[i]);
+ HeapFree(GetProcessHeap(), 0, pMem);
+ }
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler DLL API Tests
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Tests for GetPrintProcessorDirectoryA/GetPrintProcessorDirectoryW
+ * COPYRIGHT: Copyright 2015 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(GetPrintProcessorDirectory)
+{
+ DWORD cbNeeded;
+ DWORD cbTemp;
+ PWSTR pwszBuffer;
+
+ // Try with an invalid level, this needs to be caught first.
+ SetLastError(0xDEADBEEF);
+ ok(!GetPrintProcessorDirectoryW(NULL, NULL, 0, NULL, 0, NULL), "GetPrintProcessorDirectoryW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_LEVEL, "GetPrintProcessorDirectoryW returns error %lu!\n", GetLastError());
+
+ // Now try with valid level, but no pcbNeeded.
+ SetLastError(0xDEADBEEF);
+ ok(!GetPrintProcessorDirectoryW(NULL, NULL, 1, NULL, 0, NULL), "GetPrintProcessorDirectoryW returns TRUE!\n");
+ ok(GetLastError() == RPC_X_NULL_REF_POINTER, "GetPrintProcessorDirectoryW returns error %lu!\n", GetLastError());
+
+ // Try with an invalid environment as well.
+ SetLastError(0xDEADBEEF);
+ ok(!GetPrintProcessorDirectoryW(NULL, L"invalid", 1, NULL, 0, &cbNeeded), "GetPrintProcessorDirectoryW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_ENVIRONMENT, "GetPrintProcessorDirectoryW returns error %lu!\n", GetLastError());
+ ok(cbNeeded == 0, "cbNeeded is %lu!\n", cbNeeded);
+
+ // Now get the required buffer size by supplying pcbNeeded. This needs to fail with ERROR_INSUFFICIENT_BUFFER.
+ SetLastError(0xDEADBEEF);
+ ok(!GetPrintProcessorDirectoryW(NULL, NULL, 1, NULL, 0, &cbNeeded), "GetPrintProcessorDirectoryW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetPrintProcessorDirectoryW returns error %lu!\n", GetLastError());
+ ok(cbNeeded > 0, "cbNeeded is 0!\n");
+
+ // Now provide the demanded size, but no buffer.
+ SetLastError(0xDEADBEEF);
+ ok(!GetPrintProcessorDirectoryW(NULL, NULL, 1, NULL, cbNeeded, &cbTemp), "GetPrintProcessorDirectoryW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_USER_BUFFER, "GetPrintProcessorDirectoryW returns error %lu!\n", GetLastError());
+ ok(cbTemp == 0, "cbNeeded is %lu!\n", cbNeeded);
+
+ // Same error has to occur with a size too small.
+ SetLastError(0xDEADBEEF);
+ ok(!GetPrintProcessorDirectoryW(NULL, NULL, 1, NULL, 1, &cbTemp), "GetPrintProcessorDirectoryW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_USER_BUFFER, "GetPrintProcessorDirectoryW returns error %lu!\n", GetLastError());
+ ok(cbTemp == 0, "cbNeeded is %lu!\n", cbNeeded);
+
+ // Finally use the function as intended and aim for success!
+ pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
+ SetLastError(0xDEADBEEF);
+ ok(GetPrintProcessorDirectoryW(NULL, NULL, 1, (PBYTE)pwszBuffer, cbNeeded, &cbNeeded), "GetPrintProcessorDirectoryW returns FALSE!\n");
+ ok(GetLastError() == ERROR_SUCCESS, "GetPrintProcessorDirectoryW returns error %lu!\n", GetLastError());
+ HeapFree(GetProcessHeap(), 0, pwszBuffer);
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler DLL API Tests
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Tests for IsValidDevmodeA/IsValidDevmodeW
+ * COPYRIGHT: Copyright 2016 Colin Finck <colin@reactos.org>
+ */
+
+#include <apitest.h>
+
+#define WIN32_NO_STATUS
+#include <windef.h>
+#include <winbase.h>
+#include <wingdi.h>
+#include <winspool.h>
+#include <wchar.h>
+
+typedef struct _MINIMUM_SIZE_TABLE
+{
+ DWORD dwField;
+ WORD wSize;
+}
+MINIMUM_SIZE_TABLE, *PMINIMUM_SIZE_TABLE;
+
+static MINIMUM_SIZE_TABLE MinimumSizeA[] = {
+ { DM_PANNINGHEIGHT, FIELD_OFFSET(DEVMODEA, dmPanningHeight) + RTL_FIELD_SIZE(DEVMODEA, dmPanningHeight) },
+ { DM_PANNINGWIDTH, FIELD_OFFSET(DEVMODEA, dmPanningWidth) + RTL_FIELD_SIZE(DEVMODEA, dmPanningWidth) },
+ { DM_DITHERTYPE, FIELD_OFFSET(DEVMODEA, dmDitherType) + RTL_FIELD_SIZE(DEVMODEA, dmDitherType) },
+ { DM_MEDIATYPE, FIELD_OFFSET(DEVMODEA, dmMediaType) + RTL_FIELD_SIZE(DEVMODEA, dmMediaType) },
+ { DM_ICMINTENT, FIELD_OFFSET(DEVMODEA, dmICMIntent) + RTL_FIELD_SIZE(DEVMODEA, dmICMIntent) },
+ { DM_ICMMETHOD, FIELD_OFFSET(DEVMODEA, dmICMMethod) + RTL_FIELD_SIZE(DEVMODEA, dmICMMethod) },
+ { DM_DISPLAYFREQUENCY, FIELD_OFFSET(DEVMODEA, dmDisplayFrequency) + RTL_FIELD_SIZE(DEVMODEA, dmDisplayFrequency) },
+ { DM_NUP, FIELD_OFFSET(DEVMODEA, dmNup) + RTL_FIELD_SIZE(DEVMODEA, dmNup) },
+ { DM_DISPLAYFLAGS, FIELD_OFFSET(DEVMODEA, dmDisplayFlags) + RTL_FIELD_SIZE(DEVMODEA, dmDisplayFlags) },
+ { DM_PELSHEIGHT, FIELD_OFFSET(DEVMODEA, dmPelsHeight) + RTL_FIELD_SIZE(DEVMODEA, dmPelsHeight) },
+ { DM_PELSWIDTH, FIELD_OFFSET(DEVMODEA, dmPelsWidth) + RTL_FIELD_SIZE(DEVMODEA, dmPelsWidth) },
+ { DM_BITSPERPEL, FIELD_OFFSET(DEVMODEA, dmBitsPerPel) + RTL_FIELD_SIZE(DEVMODEA, dmBitsPerPel) },
+ { DM_LOGPIXELS, FIELD_OFFSET(DEVMODEA, dmLogPixels) + RTL_FIELD_SIZE(DEVMODEA, dmLogPixels) },
+ { DM_FORMNAME, FIELD_OFFSET(DEVMODEA, dmFormName) + RTL_FIELD_SIZE(DEVMODEA, dmFormName) },
+ { DM_COLLATE, FIELD_OFFSET(DEVMODEA, dmCollate) + RTL_FIELD_SIZE(DEVMODEA, dmCollate) },
+ { DM_TTOPTION, FIELD_OFFSET(DEVMODEA, dmTTOption) + RTL_FIELD_SIZE(DEVMODEA, dmTTOption) },
+ { DM_YRESOLUTION, FIELD_OFFSET(DEVMODEA, dmYResolution) + RTL_FIELD_SIZE(DEVMODEA, dmYResolution) },
+ { DM_DUPLEX, FIELD_OFFSET(DEVMODEA, dmDuplex) + RTL_FIELD_SIZE(DEVMODEA, dmDuplex) },
+ { DM_COLOR, FIELD_OFFSET(DEVMODEA, dmColor) + RTL_FIELD_SIZE(DEVMODEA, dmColor) },
+ { DM_DISPLAYFIXEDOUTPUT, FIELD_OFFSET(DEVMODEA, dmDisplayFixedOutput) + RTL_FIELD_SIZE(DEVMODEA, dmDisplayFixedOutput) },
+ { DM_DISPLAYORIENTATION, FIELD_OFFSET(DEVMODEA, dmDisplayOrientation) + RTL_FIELD_SIZE(DEVMODEA, dmDisplayOrientation) },
+ { DM_POSITION, FIELD_OFFSET(DEVMODEA, dmPosition) + RTL_FIELD_SIZE(DEVMODEA, dmPosition) },
+ { DM_PRINTQUALITY, FIELD_OFFSET(DEVMODEA, dmPrintQuality) + RTL_FIELD_SIZE(DEVMODEA, dmPrintQuality) },
+ { DM_DEFAULTSOURCE, FIELD_OFFSET(DEVMODEA, dmDefaultSource) + RTL_FIELD_SIZE(DEVMODEA, dmDefaultSource) },
+ { DM_COPIES, FIELD_OFFSET(DEVMODEA, dmCopies) + RTL_FIELD_SIZE(DEVMODEA, dmCopies) },
+ { DM_SCALE, FIELD_OFFSET(DEVMODEA, dmScale) + RTL_FIELD_SIZE(DEVMODEA, dmScale) },
+ { DM_PAPERWIDTH, FIELD_OFFSET(DEVMODEA, dmPaperWidth) + RTL_FIELD_SIZE(DEVMODEA, dmPaperWidth) },
+ { DM_PAPERLENGTH, FIELD_OFFSET(DEVMODEA, dmPaperLength) + RTL_FIELD_SIZE(DEVMODEA, dmPaperLength) },
+ { DM_PAPERSIZE, FIELD_OFFSET(DEVMODEA, dmPaperSize) + RTL_FIELD_SIZE(DEVMODEA, dmPaperSize) },
+ { DM_ORIENTATION, FIELD_OFFSET(DEVMODEA, dmOrientation) + RTL_FIELD_SIZE(DEVMODEA, dmOrientation) },
+ { 0, FIELD_OFFSET(DEVMODEA, dmFields) + RTL_FIELD_SIZE(DEVMODEA, dmFields) }
+};
+
+static MINIMUM_SIZE_TABLE MinimumSizeW[] = {
+ { DM_PANNINGHEIGHT, FIELD_OFFSET(DEVMODEW, dmPanningHeight) + RTL_FIELD_SIZE(DEVMODEW, dmPanningHeight) },
+ { DM_PANNINGWIDTH, FIELD_OFFSET(DEVMODEW, dmPanningWidth) + RTL_FIELD_SIZE(DEVMODEW, dmPanningWidth) },
+ { DM_DITHERTYPE, FIELD_OFFSET(DEVMODEW, dmDitherType) + RTL_FIELD_SIZE(DEVMODEW, dmDitherType) },
+ { DM_MEDIATYPE, FIELD_OFFSET(DEVMODEW, dmMediaType) + RTL_FIELD_SIZE(DEVMODEW, dmMediaType) },
+ { DM_ICMINTENT, FIELD_OFFSET(DEVMODEW, dmICMIntent) + RTL_FIELD_SIZE(DEVMODEW, dmICMIntent) },
+ { DM_ICMMETHOD, FIELD_OFFSET(DEVMODEW, dmICMMethod) + RTL_FIELD_SIZE(DEVMODEW, dmICMMethod) },
+ { DM_DISPLAYFREQUENCY, FIELD_OFFSET(DEVMODEW, dmDisplayFrequency) + RTL_FIELD_SIZE(DEVMODEW, dmDisplayFrequency) },
+ { DM_NUP, FIELD_OFFSET(DEVMODEW, dmNup) + RTL_FIELD_SIZE(DEVMODEW, dmNup) },
+ { DM_DISPLAYFLAGS, FIELD_OFFSET(DEVMODEW, dmDisplayFlags) + RTL_FIELD_SIZE(DEVMODEW, dmDisplayFlags) },
+ { DM_PELSHEIGHT, FIELD_OFFSET(DEVMODEW, dmPelsHeight) + RTL_FIELD_SIZE(DEVMODEW, dmPelsHeight) },
+ { DM_PELSWIDTH, FIELD_OFFSET(DEVMODEW, dmPelsWidth) + RTL_FIELD_SIZE(DEVMODEW, dmPelsWidth) },
+ { DM_BITSPERPEL, FIELD_OFFSET(DEVMODEW, dmBitsPerPel) + RTL_FIELD_SIZE(DEVMODEW, dmBitsPerPel) },
+ { DM_LOGPIXELS, FIELD_OFFSET(DEVMODEW, dmLogPixels) + RTL_FIELD_SIZE(DEVMODEW, dmLogPixels) },
+ { DM_FORMNAME, FIELD_OFFSET(DEVMODEW, dmFormName) + RTL_FIELD_SIZE(DEVMODEW, dmFormName) },
+ { DM_COLLATE, FIELD_OFFSET(DEVMODEW, dmCollate) + RTL_FIELD_SIZE(DEVMODEW, dmCollate) },
+ { DM_TTOPTION, FIELD_OFFSET(DEVMODEW, dmTTOption) + RTL_FIELD_SIZE(DEVMODEW, dmTTOption) },
+ { DM_YRESOLUTION, FIELD_OFFSET(DEVMODEW, dmYResolution) + RTL_FIELD_SIZE(DEVMODEW, dmYResolution) },
+ { DM_DUPLEX, FIELD_OFFSET(DEVMODEW, dmDuplex) + RTL_FIELD_SIZE(DEVMODEW, dmDuplex) },
+ { DM_COLOR, FIELD_OFFSET(DEVMODEW, dmColor) + RTL_FIELD_SIZE(DEVMODEW, dmColor) },
+ { DM_DISPLAYFIXEDOUTPUT, FIELD_OFFSET(DEVMODEW, dmDisplayFixedOutput) + RTL_FIELD_SIZE(DEVMODEW, dmDisplayFixedOutput) },
+ { DM_DISPLAYORIENTATION, FIELD_OFFSET(DEVMODEW, dmDisplayOrientation) + RTL_FIELD_SIZE(DEVMODEW, dmDisplayOrientation) },
+ { DM_POSITION, FIELD_OFFSET(DEVMODEW, dmPosition) + RTL_FIELD_SIZE(DEVMODEW, dmPosition) },
+ { DM_PRINTQUALITY, FIELD_OFFSET(DEVMODEW, dmPrintQuality) + RTL_FIELD_SIZE(DEVMODEW, dmPrintQuality) },
+ { DM_DEFAULTSOURCE, FIELD_OFFSET(DEVMODEW, dmDefaultSource) + RTL_FIELD_SIZE(DEVMODEW, dmDefaultSource) },
+ { DM_COPIES, FIELD_OFFSET(DEVMODEW, dmCopies) + RTL_FIELD_SIZE(DEVMODEW, dmCopies) },
+ { DM_SCALE, FIELD_OFFSET(DEVMODEW, dmScale) + RTL_FIELD_SIZE(DEVMODEW, dmScale) },
+ { DM_PAPERWIDTH, FIELD_OFFSET(DEVMODEW, dmPaperWidth) + RTL_FIELD_SIZE(DEVMODEW, dmPaperWidth) },
+ { DM_PAPERLENGTH, FIELD_OFFSET(DEVMODEW, dmPaperLength) + RTL_FIELD_SIZE(DEVMODEW, dmPaperLength) },
+ { DM_PAPERSIZE, FIELD_OFFSET(DEVMODEW, dmPaperSize) + RTL_FIELD_SIZE(DEVMODEW, dmPaperSize) },
+ { DM_ORIENTATION, FIELD_OFFSET(DEVMODEW, dmOrientation) + RTL_FIELD_SIZE(DEVMODEW, dmOrientation) },
+ { 0, FIELD_OFFSET(DEVMODEW, dmFields) + RTL_FIELD_SIZE(DEVMODEW, dmFields) }
+};
+
+
+
+START_TEST(IsValidDevmodeA)
+{
+ DEVMODEA DevMode;
+ PMINIMUM_SIZE_TABLE pTable = MinimumSizeA;
+
+ // Give no Devmode at all, this has to fail without crashing.
+ SetLastError(0xDEADBEEF);
+ ok(!IsValidDevmodeA(NULL, sizeof(DEVMODEA)), "IsValidDevmodeA returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_DATA, "IsValidDevmodeA returns error %lu!\n", GetLastError());
+
+ // Give a zeroed Devmode, this has to fail, because dmSize isn't set.
+ ZeroMemory(&DevMode, sizeof(DEVMODEA));
+ SetLastError(0xDEADBEEF);
+ ok(!IsValidDevmodeA(&DevMode, sizeof(DEVMODEA)), "IsValidDevmodeA returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_DATA, "IsValidDevmodeA returns error %lu!\n", GetLastError());
+
+ // Now set only the dmSize member, IsValidDevmodeA should return TRUE now. The Last Error isn't touched again.
+ ZeroMemory(&DevMode, sizeof(DEVMODEA));
+ DevMode.dmSize = sizeof(DEVMODEA);
+ SetLastError(0xDEADBEEF);
+ ok(IsValidDevmodeA(&DevMode, sizeof(DEVMODEA)), "IsValidDevmodeA returns FALSE!\n");
+ ok(GetLastError() == 0xDEADBEEF, "IsValidDevmodeA returns error %lu!\n", GetLastError());
+
+ // IsValidDevmodeA should also succeed if the DevMode appears to be larger.
+ ZeroMemory(&DevMode, sizeof(DEVMODEA));
+ DevMode.dmSize = sizeof(DEVMODEA) + 1;
+ SetLastError(0xDEADBEEF);
+ ok(IsValidDevmodeA(&DevMode, sizeof(DEVMODEA) + 1), "IsValidDevmodeA returns FALSE!\n");
+ ok(GetLastError() == 0xDEADBEEF, "IsValidDevmodeA returns error %lu!\n", GetLastError());
+
+ // The DevmodeSize parameter may be larger than dmSize, but not the other way round!
+ ZeroMemory(&DevMode, sizeof(DEVMODEA));
+ DevMode.dmSize = sizeof(DEVMODEA);
+ SetLastError(0xDEADBEEF);
+ ok(IsValidDevmodeA(&DevMode, sizeof(DEVMODEA) + 1), "IsValidDevmodeA returns FALSE!\n");
+ ok(GetLastError() == 0xDEADBEEF, "IsValidDevmodeA returns error %lu!\n", GetLastError());
+
+ ZeroMemory(&DevMode, sizeof(DEVMODEA));
+ DevMode.dmSize = sizeof(DEVMODEA) + 1;
+ SetLastError(0xDEADBEEF);
+ ok(!IsValidDevmodeA(&DevMode, sizeof(DEVMODEA)), "IsValidDevmodeA returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_DATA, "IsValidDevmodeA returns error %lu!\n", GetLastError());
+
+ // dmDriverExtra is also taken into account.
+ ZeroMemory(&DevMode, sizeof(DEVMODEA));
+ DevMode.dmSize = sizeof(DEVMODEA);
+ DevMode.dmDriverExtra = 1;
+ SetLastError(0xDEADBEEF);
+ ok(!IsValidDevmodeA(&DevMode, sizeof(DEVMODEA)), "IsValidDevmodeA returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_DATA, "IsValidDevmodeA returns error %lu!\n", GetLastError());
+
+ SetLastError(0xDEADBEEF);
+ ok(IsValidDevmodeA(&DevMode, sizeof(DEVMODEA) + 1), "IsValidDevmodeA returns FALSE!\n");
+ ok(GetLastError() == 0xDEADBEEF, "IsValidDevmodeA returns error %lu!\n", GetLastError());
+
+ // dmSize must be a multiple of 4 if any dmDriverExtra is given.
+ for (DevMode.dmDriverExtra = 1; DevMode.dmDriverExtra <= 4; DevMode.dmDriverExtra++)
+ {
+ for (DevMode.dmSize = sizeof(DEVMODEA); DevMode.dmSize < sizeof(DEVMODEA) + 4; DevMode.dmSize++)
+ {
+ BOOL bExpected = (DevMode.dmSize % 4 == 0);
+ DWORD dwExpectedError = (bExpected ? 0xDEADBEEF : ERROR_INVALID_DATA);
+
+ SetLastError(0xDEADBEEF);
+ ok(IsValidDevmodeA(&DevMode, DevMode.dmSize + DevMode.dmDriverExtra) == bExpected, "IsValidDevmodeA returns %d!\n", !bExpected);
+ ok(GetLastError() == dwExpectedError, "IsValidDevmodeA returns error %lu!\n", GetLastError());
+ }
+ }
+
+ // IsValidDevmodeA also fixes missing null-terminations if the corresponding fields are used.
+ ZeroMemory(&DevMode, sizeof(DEVMODEA));
+ DevMode.dmSize = sizeof(DEVMODEA);
+ memset(DevMode.dmDeviceName, 'A', 32);
+ memset(DevMode.dmFormName, 'A', 32);
+ ok(IsValidDevmodeA(&DevMode, DevMode.dmSize), "IsValidDevmodeA returns FALSE!\n");
+ ok(DevMode.dmDeviceName[31] == '\0', "Expected dmDeviceName to be '\\0', but is '%c'\n", DevMode.dmDeviceName[31]);
+ ok(DevMode.dmFormName[31] == 'A', "Expected dmFormName to be 'A', but is '%c'\n", DevMode.dmDeviceName[31]);
+
+ ZeroMemory(&DevMode, sizeof(DEVMODEA));
+ DevMode.dmSize = sizeof(DEVMODEA);
+ DevMode.dmFields = DM_FORMNAME;
+ memset(DevMode.dmDeviceName, 'A', 32);
+ memset(DevMode.dmFormName, 'A', 32);
+ ok(IsValidDevmodeA(&DevMode, DevMode.dmSize), "IsValidDevmodeA returns FALSE!\n");
+ ok(DevMode.dmDeviceName[31] == '\0', "Expected dmDeviceName to be '\\0', but is '%c'\n", DevMode.dmDeviceName[31]);
+ ok(DevMode.dmFormName[31] == '\0', "Expected dmFormName to be '\\0', but is '%c'\n", DevMode.dmDeviceName[31]);
+
+ // Depending on which fields are given in dmFields, the minimum value for dmSize is different.
+ ZeroMemory(&DevMode, sizeof(DEVMODEA));
+
+ do
+ {
+ DevMode.dmFields = pTable->dwField;
+ DevMode.dmSize = pTable->wSize;
+
+ // This size should succeed!
+ ok(IsValidDevmodeA(&DevMode, DevMode.dmSize), "IsValidDevmodeA returns FALSE!\n");
+
+ // One byte less should not succeed!
+ DevMode.dmSize--;
+ ok(!IsValidDevmodeA(&DevMode, DevMode.dmSize), "IsValidDevmodeA returns TRUE!\n");
+
+ pTable++;
+ }
+ while (pTable->dwField);
+}
+
+START_TEST(IsValidDevmodeW)
+{
+ DEVMODEW DevMode;
+ PMINIMUM_SIZE_TABLE pTable = MinimumSizeW;
+
+ // Give no Devmode at all, this has to fail without crashing.
+ SetLastError(0xDEADBEEF);
+ ok(!IsValidDevmodeW(NULL, sizeof(DEVMODEW)), "IsValidDevmodeW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_DATA, "IsValidDevmodeW returns error %lu!\n", GetLastError());
+
+ // Give a zeroed Devmode, this has to fail, because dmSize isn't set.
+ ZeroMemory(&DevMode, sizeof(DEVMODEW));
+ SetLastError(0xDEADBEEF);
+ ok(!IsValidDevmodeW(&DevMode, sizeof(DEVMODEW)), "IsValidDevmodeW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_DATA, "IsValidDevmodeW returns error %lu!\n", GetLastError());
+
+ // Now set only the dmSize member, IsValidDevmodeW should return TRUE now. The Last Error isn't touched again.
+ ZeroMemory(&DevMode, sizeof(DEVMODEW));
+ DevMode.dmSize = sizeof(DEVMODEW);
+ SetLastError(0xDEADBEEF);
+ ok(IsValidDevmodeW(&DevMode, sizeof(DEVMODEW)), "IsValidDevmodeW returns FALSE!\n");
+ ok(GetLastError() == 0xDEADBEEF, "IsValidDevmodeW returns error %lu!\n", GetLastError());
+
+ // IsValidDevmodeW should also succeed if the DevMode appears to be larger.
+ ZeroMemory(&DevMode, sizeof(DEVMODEW));
+ DevMode.dmSize = sizeof(DEVMODEW) + 1;
+ SetLastError(0xDEADBEEF);
+ ok(IsValidDevmodeW(&DevMode, sizeof(DEVMODEW) + 1), "IsValidDevmodeW returns FALSE!\n");
+ ok(GetLastError() == 0xDEADBEEF, "IsValidDevmodeW returns error %lu!\n", GetLastError());
+
+ // The DevmodeSize parameter may be larger than dmSize, but not the other way round!
+ ZeroMemory(&DevMode, sizeof(DEVMODEW));
+ DevMode.dmSize = sizeof(DEVMODEW);
+ SetLastError(0xDEADBEEF);
+ ok(IsValidDevmodeW(&DevMode, sizeof(DEVMODEW) + 1), "IsValidDevmodeW returns FALSE!\n");
+ ok(GetLastError() == 0xDEADBEEF, "IsValidDevmodeW returns error %lu!\n", GetLastError());
+
+ ZeroMemory(&DevMode, sizeof(DEVMODEW));
+ DevMode.dmSize = sizeof(DEVMODEW) + 1;
+ SetLastError(0xDEADBEEF);
+ ok(!IsValidDevmodeW(&DevMode, sizeof(DEVMODEW)), "IsValidDevmodeW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_DATA, "IsValidDevmodeW returns error %lu!\n", GetLastError());
+
+ // dmDriverExtra is also taken into account.
+ ZeroMemory(&DevMode, sizeof(DEVMODEW));
+ DevMode.dmSize = sizeof(DEVMODEW);
+ DevMode.dmDriverExtra = 1;
+ SetLastError(0xDEADBEEF);
+ ok(!IsValidDevmodeW(&DevMode, sizeof(DEVMODEW)), "IsValidDevmodeW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_DATA, "IsValidDevmodeW returns error %lu!\n", GetLastError());
+
+ SetLastError(0xDEADBEEF);
+ ok(IsValidDevmodeW(&DevMode, sizeof(DEVMODEW) + 1), "IsValidDevmodeW returns FALSE!\n");
+ ok(GetLastError() == 0xDEADBEEF, "IsValidDevmodeW returns error %lu!\n", GetLastError());
+
+ // dmSize must be a multiple of 4 if any dmDriverExtra is given.
+ for (DevMode.dmDriverExtra = 1; DevMode.dmDriverExtra <= 4; DevMode.dmDriverExtra++)
+ {
+ for (DevMode.dmSize = sizeof(DEVMODEW); DevMode.dmSize < sizeof(DEVMODEW) + 4; DevMode.dmSize++)
+ {
+ BOOL bExpected = (DevMode.dmSize % 4 == 0);
+ DWORD dwExpectedError = (bExpected ? 0xDEADBEEF : ERROR_INVALID_DATA);
+
+ SetLastError(0xDEADBEEF);
+ ok(IsValidDevmodeW(&DevMode, DevMode.dmSize + DevMode.dmDriverExtra) == bExpected, "IsValidDevmodeW returns %d!\n", !bExpected);
+ ok(GetLastError() == dwExpectedError, "IsValidDevmodeW returns error %lu!\n", GetLastError());
+ }
+ }
+
+ // IsValidDevmodeW also fixes missing null-terminations if the corresponding fields are used.
+ ZeroMemory(&DevMode, sizeof(DEVMODEW));
+ DevMode.dmSize = sizeof(DEVMODEW);
+ wmemset(DevMode.dmDeviceName, L'A', 32);
+ wmemset(DevMode.dmFormName, L'A', 32);
+ ok(IsValidDevmodeW(&DevMode, DevMode.dmSize), "IsValidDevmodeW returns FALSE!\n");
+ ok(DevMode.dmDeviceName[31] == L'\0', "Expected dmDeviceName to be '\\0', but is '%C'\n", DevMode.dmDeviceName[31]);
+ ok(DevMode.dmFormName[31] == L'A', "Expected dmFormName to be 'A', but is '%C'\n", DevMode.dmDeviceName[31]);
+
+ ZeroMemory(&DevMode, sizeof(DEVMODEW));
+ DevMode.dmSize = sizeof(DEVMODEW);
+ DevMode.dmFields = DM_FORMNAME;
+ wmemset(DevMode.dmDeviceName, L'A', 32);
+ wmemset(DevMode.dmFormName, L'A', 32);
+ ok(IsValidDevmodeW(&DevMode, DevMode.dmSize), "IsValidDevmodeW returns FALSE!\n");
+ ok(DevMode.dmDeviceName[31] == L'\0', "Expected dmDeviceName to be '\\0', but is '%C'\n", DevMode.dmDeviceName[31]);
+ ok(DevMode.dmFormName[31] == L'\0', "Expected dmFormName to be '\\0', but is '%C'\n", DevMode.dmDeviceName[31]);
+
+ // Depending on which fields are given in dmFields, the minimum value for dmSize is different.
+ ZeroMemory(&DevMode, sizeof(DEVMODEW));
+
+ do
+ {
+ DevMode.dmFields = pTable->dwField;
+ DevMode.dmSize = pTable->wSize;
+
+ // This size should succeed!
+ ok(IsValidDevmodeW(&DevMode, DevMode.dmSize), "IsValidDevmodeW returns FALSE!\n");
+
+ // One byte less should not succeed!
+ DevMode.dmSize--;
+ ok(!IsValidDevmodeW(&DevMode, DevMode.dmSize), "IsValidDevmodeW returns TRUE!\n");
+
+ pTable++;
+ }
+ while (pTable->dwField);
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler DLL API Tests
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Tests for OpenPrinterA/OpenPrinterW
+ * COPYRIGHT: Copyright 2015 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(OpenPrinter)
+{
+ HANDLE hPrinter;
+
+ // Give no handle at all, this has to fail
+ SetLastError(0xDEADBEEF);
+ ok(!OpenPrinterW(NULL, NULL, NULL), "OpenPrinterW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "OpenPrinterW returns error %lu!\n", GetLastError());
+
+ // Open a handle to the local print server
+ SetLastError(0xDEADBEEF);
+ ok(OpenPrinterW(NULL, &hPrinter, NULL), "OpenPrinterW returns FALSE!\n");
+ ok(GetLastError() == ERROR_SUCCESS, "OpenPrinterW returns error %lu!\n", GetLastError());
+ ClosePrinter(hPrinter);
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler DLL API Tests
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Tests for StartDocPrinterA/StartDocPrinterW
+ * COPYRIGHT: Copyright 2015 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(StartDocPrinter)
+{
+ DWORD dwResult;
+ DOCINFOW docInfo = { 0 };
+
+ SetLastError(0xDEADBEEF);
+ dwResult = StartDocPrinterW(NULL, 0, NULL);
+ ok(dwResult == 0, "StartDocPrinterW returns %lu!\n", dwResult);
+ ok(GetLastError() == ERROR_INVALID_HANDLE, "StartDocPrinter returns error %lu!\n", GetLastError());
+
+ SetLastError(0xDEADBEEF);
+ dwResult = StartDocPrinterW(NULL, 1, NULL);
+ ok(dwResult == 0, "StartDocPrinterW returns %lu!\n", dwResult);
+ ok(GetLastError() == ERROR_INVALID_HANDLE, "StartDocPrinter returns error %lu!\n", GetLastError());
+
+ SetLastError(0xDEADBEEF);
+ dwResult = StartDocPrinterW(NULL, 0, (LPBYTE)&docInfo);
+ ok(dwResult == 0, "StartDocPrinterW returns %lu!\n", dwResult);
+ ok(GetLastError() == ERROR_INVALID_HANDLE, "StartDocPrinter returns error %lu!\n", GetLastError());
+
+ SetLastError(0xDEADBEEF);
+ dwResult = StartDocPrinterW(NULL, 1, (LPBYTE)&docInfo);
+ ok(dwResult == 0, "StartDocPrinterW returns %lu!\n", dwResult);
+ ok(GetLastError() == ERROR_INVALID_HANDLE, "StartDocPrinter returns error %lu!\n", GetLastError());
+
+ /// ERROR_INVALID_LEVEL with correct handle but invalid Level
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Print Spooler DLL API Tests
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE: Test list
+ * COPYRIGHT: Copyright 2015-2016 Colin Finck <colin@reactos.org>
+ */
+
+#define __ROS_LONG64__
+
+#define STANDALONE
+#include <apitest.h>
+
+extern void func_ClosePrinter(void);
+extern void func_EnumPrinters(void);
+extern void func_EnumPrintProcessorDatatypes(void);
+extern void func_GetPrintProcessorDirectory(void);
+extern void func_IsValidDevmodeA(void);
+extern void func_IsValidDevmodeW(void);
+extern void func_OpenPrinter(void);
+extern void func_StartDocPrinter(void);
+
+const struct test winetest_testlist[] =
+{
+ { "ClosePrinter", func_ClosePrinter },
+ { "EnumPrinters", func_EnumPrinters },
+ { "EnumPrintProcessorDatatypes", func_EnumPrintProcessorDatatypes },
+ { "GetPrintProcessorDirectory", func_GetPrintProcessorDirectory },
+ { "IsValidDevmodeA", func_IsValidDevmodeA },
+ { "IsValidDevmodeW", func_IsValidDevmodeW },
+ { "OpenPrinter", func_OpenPrinter },
+ { "StartDocPrinter", func_StartDocPrinter },
+
+ { 0, 0 }
+};
add_subdirectory(winhttp)
add_subdirectory(wininet)
add_subdirectory(winmm)
-add_subdirectory(winspool)
+#add_subdirectory(winspool)
add_subdirectory(wintrust)
add_subdirectory(wlanapi)
add_subdirectory(wldap32)