From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/provider.c | 198 +++++++++++++++++---------------------- 1 file changed, 86 insertions(+), 112 deletions(-)
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index b33abd723c9..2b29426b0e1 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -193,14 +193,7 @@ typedef struct { LPWSTR dllname; PMONITORUI monitorUI; MONITOR2 monitor; - BOOL (WINAPI *old_EnumPorts)(LPWSTR,DWORD,LPBYTE,DWORD,LPDWORD,LPDWORD); - BOOL (WINAPI *old_OpenPort)(LPWSTR,PHANDLE); - BOOL (WINAPI *old_OpenPortEx)(LPWSTR,LPWSTR,PHANDLE,struct _MONITOR *); - BOOL (WINAPI *old_AddPort)(LPWSTR,HWND,LPWSTR); - BOOL (WINAPI *old_AddPortEx)(LPWSTR,DWORD,LPBYTE,LPWSTR); - BOOL (WINAPI *old_ConfigurePort)(LPWSTR,HWND,LPWSTR); - BOOL (WINAPI *old_DeletePort)(LPWSTR,HWND,LPWSTR); - BOOL (WINAPI *old_XcvOpenPort)(LPCWSTR,ACCESS_MASK,PHANDLE); + const MONITOREX *monitorex; HANDLE hmon; HMODULE hdll; DWORD refcount; @@ -529,6 +522,48 @@ static MONITORREG monreg = QueryValue };
+static BOOL WINAPI monitor2_EnumPorts(HANDLE hmon, WCHAR *name, DWORD level, + BYTE *buf, DWORD size, DWORD *needed, DWORD *count) +{ + return ((MONITOREX*)hmon)->Monitor.pfnEnumPorts(name, level, + buf, size, needed, count); +} + +static BOOL WINAPI monitor2_OpenPort(HANDLE hmon, WCHAR *name, HANDLE *hport) +{ + return ((MONITOREX*)hmon)->Monitor.pfnOpenPort(name, hport); +} + +static BOOL WINAPI monitor2_AddPort(HANDLE hmon, WCHAR *name, + HWND hwnd, WCHAR *monitor_name) +{ + return ((MONITOREX*)hmon)->Monitor.pfnAddPort(name, hwnd, monitor_name); +} + +static BOOL WINAPI monitor2_AddPortEx(HANDLE hmon, WCHAR *name, DWORD level, + BYTE *buf, WCHAR *monitor_name) +{ + return ((MONITOREX*)hmon)->Monitor.pfnAddPortEx(name, level, buf, monitor_name); +} + +static BOOL WINAPI monitor2_ConfigurePort(HANDLE hmon, WCHAR *name, + HWND hwnd, WCHAR *port_name) +{ + return ((MONITOREX*)hmon)->Monitor.pfnConfigurePort(name, hwnd, port_name); +} + +static BOOL WINAPI monitor2_DeletePort(HANDLE hmon, WCHAR *name, + HWND hwnd, WCHAR *port_name) +{ + return ((MONITOREX*)hmon)->Monitor.pfnDeletePort(name, hwnd, port_name); +} + +static BOOL WINAPI monitor2_XcvOpenPort(HANDLE hmon, const WCHAR *obj, + ACCESS_MASK granted_access, HANDLE *hxcv) +{ + return ((MONITOREX*)hmon)->Monitor.pfnXcvOpenPort(obj, granted_access, hxcv); +} + /****************************************************************** * monitor_load [internal] * @@ -664,35 +699,39 @@ static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname) } } else if (pInitializePrintMonitor && regroot) { - MONITOREX *pmonitorEx;
- pmonitorEx = pInitializePrintMonitor(regroot); + pm->monitorex = pInitializePrintMonitor(regroot); TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n", - pmonitorEx, debugstr_w(driver), debugstr_w(regroot)); - if (pmonitorEx) + pm->monitorex, debugstr_w(driver), debugstr_w(regroot)); + if (pm->monitorex) { - /* Layout of MONITOREX and MONITOR2 mostly matches */ - memcpy(&pm->monitor, pmonitorEx, min(pmonitorEx->dwMonitorSize + sizeof(void *), sizeof(pm->monitor))); - /* MONITOREX.dwMonitorSize doesn't include the size field, while MONITOR2.cbSize does */ - pm->monitor.cbSize += sizeof(void *); - - pm->old_EnumPorts = pmonitorEx->Monitor.pfnEnumPorts; - pm->old_OpenPort = pmonitorEx->Monitor.pfnOpenPort; - pm->old_OpenPortEx = pmonitorEx->Monitor.pfnOpenPortEx; - pm->old_AddPort = pmonitorEx->Monitor.pfnAddPort; - pm->old_AddPortEx = pmonitorEx->Monitor.pfnAddPortEx; - pm->old_ConfigurePort = pmonitorEx->Monitor.pfnConfigurePort; - pm->old_DeletePort = pmonitorEx->Monitor.pfnDeletePort; - pm->old_XcvOpenPort = pmonitorEx->Monitor.pfnXcvOpenPort; - - pm->monitor.pfnEnumPorts = NULL; - pm->monitor.pfnOpenPort = NULL; - pm->monitor.pfnOpenPortEx = NULL; - pm->monitor.pfnAddPort = NULL; - pm->monitor.pfnAddPortEx = NULL; - pm->monitor.pfnConfigurePort = NULL; - pm->monitor.pfnDeletePort = NULL; - pm->monitor.pfnXcvOpenPort = NULL; + pm->hmon = (HANDLE)pm->monitorex; + + pm->monitor.cbSize = sizeof(pm->monitor); + if (pm->monitorex->Monitor.pfnEnumPorts) + pm->monitor.pfnEnumPorts = monitor2_EnumPorts; + if (pm->monitorex->Monitor.pfnOpenPort) + pm->monitor.pfnOpenPort = monitor2_OpenPort; + pm->monitor.pfnStartDocPort = pm->monitorex->Monitor.pfnStartDocPort; + pm->monitor.pfnWritePort = pm->monitorex->Monitor.pfnWritePort; + pm->monitor.pfnReadPort = pm->monitorex->Monitor.pfnReadPort; + pm->monitor.pfnEndDocPort = pm->monitorex->Monitor.pfnEndDocPort; + pm->monitor.pfnClosePort = pm->monitorex->Monitor.pfnClosePort; + if (pm->monitorex->Monitor.pfnAddPort) + pm->monitor.pfnAddPort = monitor2_AddPort; + if (pm->monitorex->Monitor.pfnAddPortEx) + pm->monitor.pfnAddPortEx = monitor2_AddPortEx; + if (pm->monitorex->Monitor.pfnConfigurePort) + pm->monitor.pfnConfigurePort = monitor2_ConfigurePort; + if (pm->monitorex->Monitor.pfnDeletePort) + pm->monitor.pfnDeletePort = monitor2_DeletePort; + pm->monitor.pfnGetPrinterDataFromPort = + pm->monitorex->Monitor.pfnGetPrinterDataFromPort; + pm->monitor.pfnSetPortTimeOuts = pm->monitorex->Monitor.pfnSetPortTimeOuts; + if (pm->monitorex->Monitor.pfnXcvOpenPort) + pm->monitor.pfnXcvOpenPort = monitor2_XcvOpenPort; + pm->monitor.pfnXcvDataPort = pm->monitorex->Monitor.pfnXcvDataPort; + pm->monitor.pfnXcvClosePort = pm->monitorex->Monitor.pfnXcvClosePort; } }
@@ -787,8 +826,6 @@ static monitor_t * monitor_loadui(monitor_t * pm) /* building (",XcvMonitor %s",pm->name) not needed yet */ if (pm->monitor.pfnXcvOpenPort) res = pm->monitor.pfnXcvOpenPort(pm->hmon, L"", SERVER_ACCESS_ADMINISTER, &hXcv); - else if (pm->old_XcvOpenPort) - res = pm->old_XcvOpenPort(L"", SERVER_ACCESS_ADMINISTER, &hXcv); TRACE("got %lu with %p\n", res, hXcv); if (res) { res = pm->monitor.pfnXcvDataPort(hXcv, L"MonitorUI", NULL, 0, (BYTE *) buffer, sizeof(buffer), &len); @@ -1105,19 +1142,6 @@ static DWORD get_local_printprocessors(LPWSTR regpathW, LPBYTE pPPInfo, DWORD cb return needed; }
-static BOOL wrap_EnumPorts(monitor_t *pm, LPWSTR name, DWORD level, LPBYTE buffer, - DWORD size, LPDWORD needed, LPDWORD returned) -{ - if (pm->monitor.pfnEnumPorts) - return pm->monitor.pfnEnumPorts(pm->hmon, name, level, buffer, size, needed, returned); - - if (pm->old_EnumPorts) - return pm->old_EnumPorts(name, level, buffer, size, needed, returned); - - WARN("EnumPorts is not implemented by monitor\n"); - return FALSE; -} - /****************************************************************** * enumerate the local Ports from all loaded monitors (internal) * @@ -1154,16 +1178,18 @@ static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf
LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry) { - if (pm->monitor.pfnEnumPorts || pm->old_EnumPorts) { + if (pm->monitor.pfnEnumPorts) { pi_needed = 0; pi_returned = 0; - res = wrap_EnumPorts(pm, NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned); + res = pm->monitor.pfnEnumPorts(pm->hmon, NULL, level, pi_buffer, + pi_allocated, &pi_needed, &pi_returned); if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { /* Do not use realloc (we do not need the old data in the buffer) */ free(pi_buffer); pi_buffer = malloc(pi_needed); pi_allocated = (pi_buffer) ? pi_needed : 0; - res = wrap_EnumPorts(pm, NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned); + res = pm->monitor.pfnEnumPorts(pm->hmon, NULL, level, + pi_buffer, pi_allocated, &pi_needed, &pi_returned); } TRACE("(%s) got %ld with %ld (need %ld byte for %ld entries)\n", debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned); @@ -1451,10 +1477,6 @@ static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault) printer->pm->monitor.pfnXcvOpenPort(printer->pm->hmon, &printername[len], pDefault ? pDefault->DesiredAccess : 0, &printer->hXcv); - else if (printer->pm->old_XcvOpenPort) - printer->pm->old_XcvOpenPort(&printername[len], - pDefault ? pDefault->DesiredAccess : 0, - &printer->hXcv); if (printer->hXcv == NULL) { printer_free(printer); SetLastError(ERROR_INVALID_PARAMETER); @@ -1773,18 +1795,6 @@ static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors) return (res); }
-static BOOL wrap_AddPort(monitor_t *pm, LPWSTR name, HWND hwnd, LPWSTR monitor_name) -{ - if (pm->monitor.pfnAddPort) - return pm->monitor.pfnAddPort(pm->hmon, name, hwnd, monitor_name); - - if (pm->old_AddPort) - return pm->old_AddPort(name, hwnd, monitor_name); - - WARN("AddPort is not implemented by monitor\n"); - return FALSE; -} - /****************************************************************************** * fpAddPort [exported through PRINTPROVIDOR] * @@ -1823,8 +1833,8 @@ static BOOL WINAPI fpAddPort(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName) }
pm = monitor_load(pMonitorName, NULL); - if (pm && (pm->monitor.pfnAddPort || pm->old_AddPort)) { - res = wrap_AddPort(pm, pName, hWnd, pMonitorName); + if (pm && pm->monitor.pfnAddPort) { + res = pm->monitor.pfnAddPort(pm->hmon, pName, hWnd, pMonitorName); TRACE("got %ld with %lu (%s)\n", res, GetLastError(), debugstr_w(pm->dllname)); } else @@ -1851,18 +1861,6 @@ static BOOL WINAPI fpAddPort(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName) return res; }
-static BOOL wrap_AddPortEx(monitor_t *pm, LPWSTR name, DWORD level, LPBYTE buffer, LPWSTR monitor_name) -{ - if (pm->monitor.pfnAddPortEx) - return pm->monitor.pfnAddPortEx(pm->hmon, name, level, buffer, monitor_name); - - if (pm->old_AddPortEx) - return pm->old_AddPortEx(name, level, buffer, monitor_name); - - WARN("AddPortEx is not implemented by monitor\n"); - return FALSE; -} - /****************************************************************************** * fpAddPortEx [exported through PRINTPROVIDOR] * @@ -1912,9 +1910,9 @@ static BOOL WINAPI fpAddPortEx(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR
/* load the Monitor */ pm = monitor_load(pMonitorName, NULL); - if (pm && (pm->monitor.pfnAddPortEx || pm->old_AddPortEx)) + if (pm && pm->monitor.pfnAddPortEx) { - res = wrap_AddPortEx(pm, pName, level, pBuffer, pMonitorName); + res = pm->monitor.pfnAddPortEx(pm->hmon, pName, level, pBuffer, pMonitorName); TRACE("got %ld with %lu (%s)\n", res, GetLastError(), debugstr_w(pm->dllname)); } else @@ -1989,18 +1987,6 @@ static BOOL WINAPI fpClosePrinter(HANDLE hPrinter) return FALSE; }
-static BOOL wrap_ConfigurePort(monitor_t *pm, LPWSTR name, HWND hwnd, LPWSTR port_name) -{ - if (pm->monitor.pfnConfigurePort) - return pm->monitor.pfnConfigurePort(pm->hmon, name, hwnd, port_name); - - if (pm->old_ConfigurePort) - return pm->old_ConfigurePort(name, hwnd, port_name); - - WARN("ConfigurePort is not implemented by monitor\n"); - return FALSE; -} - /****************************************************************************** * fpConfigurePort [exported through PRINTPROVIDOR] * @@ -2039,11 +2025,11 @@ static BOOL WINAPI fpConfigurePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName) }
pm = monitor_load_by_port(pPortName); - if (pm && (pm->monitor.pfnConfigurePort || pm->old_ConfigurePort)) + if (pm && 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 = wrap_ConfigurePort(pm, pName, hWnd, pPortName); + res = pm->monitor.pfnConfigurePort(pm->hmon, pName, hWnd, pPortName); TRACE("got %ld with %lu\n", res, GetLastError()); } else @@ -2145,18 +2131,6 @@ static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMo return FALSE; }
-static BOOL wrap_DeletePort(monitor_t *pm, LPWSTR name, HWND hwnd, LPWSTR port_name) -{ - if (pm->monitor.pfnDeletePort) - return pm->monitor.pfnDeletePort(pm->hmon, name, hwnd, port_name); - - if (pm->old_ConfigurePort) - return pm->old_DeletePort(name, hwnd, port_name); - - WARN("DeletePort is not implemented by monitor\n"); - return FALSE; -} - /***************************************************************************** * fpDeletePort [exported through PRINTPROVIDOR] * @@ -2195,11 +2169,11 @@ static BOOL WINAPI fpDeletePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName) }
pm = monitor_load_by_port(pPortName); - if (pm && (pm->monitor.pfnDeletePort || pm->old_DeletePort)) + if (pm && 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 = wrap_DeletePort(pm, pName, hWnd, pPortName); + res = pm->monitor.pfnDeletePort(pm->hmon, pName, hWnd, pPortName); TRACE("got %ld with %lu\n", res, GetLastError()); } else
From: Piotr Caban piotr@codeweavers.com
The structure will be used to store printer information shared between all printer handles (like printer name, attributes, job queue). --- dlls/localspl/provider.c | 101 +++++++++++++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 20 deletions(-)
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index 2b29426b0e1..25a67e3ae36 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -176,6 +176,15 @@ static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug = }; static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
+static CRITICAL_SECTION printers_cs; +static CRITICAL_SECTION_DEBUG printers_cs_debug = +{ + 0, 0, &printers_cs, + { &printers_cs_debug.ProcessLocksList, &printers_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": printers_cs") } +}; +static CRITICAL_SECTION printers_cs = { &printers_cs_debug, -1, 0, 0, 0, 0 }; + /* ############################### */
typedef struct { @@ -208,8 +217,14 @@ typedef struct { } printenv_t;
typedef struct { + WCHAR *name; + struct list entry; + LONG ref; +} printer_info_t; + +typedef struct { + printer_info_t *info; LPWSTR name; - LPWSTR printername; monitor_t * pm; HANDLE hXcv; } printer_t; @@ -219,6 +234,8 @@ typedef struct { static struct list monitor_handles = LIST_INIT( monitor_handles ); static monitor_t * pm_localport;
+static struct list printers = LIST_INIT(printers); + static const WCHAR fmt_driversW[] = L"System\CurrentControlSet\control\Print\Environments\%s\Drivers%s"; static const WCHAR fmt_printprocessorsW[] = @@ -436,6 +453,65 @@ static void monitor_unloadall(void) LeaveCriticalSection(&monitor_handles_cs); }
+static printer_info_t* get_printer_info(const WCHAR *name) +{ + HKEY hkey, hprinter = NULL; + printer_info_t *info; + LSTATUS ret; + + EnterCriticalSection(&printers_cs); + LIST_FOR_EACH_ENTRY(info, &printers, printer_info_t, entry) + { + if (!wcscmp(info->name, name)) + { + InterlockedIncrement(&info->ref); + LeaveCriticalSection(&printers_cs); + return info; + } + } + + ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkey); + if (ret == ERROR_SUCCESS) + ret = RegOpenKeyW(hkey, name, &hprinter); + RegCloseKey(hkey); + RegCloseKey(hprinter); + if (ret != ERROR_SUCCESS) + { + LeaveCriticalSection(&printers_cs); + return NULL; + } + + if ((info = calloc(1, sizeof(*info))) && (info->name = wcsdup(name))) + { + info->ref = 1; + list_add_head(&printers, &info->entry); + } + else if (info) + { + free(info); + info = NULL; + } + LeaveCriticalSection(&printers_cs); + + return info; +} + +static void release_printer_info(printer_info_t *info) +{ + if (!info) + return; + + if (!InterlockedDecrement(&info->ref)) + { + EnterCriticalSection(&printers_cs); + list_remove(&info->entry); + LeaveCriticalSection(&printers_cs); + + free(info->name); + free(info); + } +} + static LONG WINAPI CreateKey(HANDLE hcKey, LPCWSTR pszSubKey, DWORD dwOptions, REGSAM samDesired, PSECURITY_ATTRIBUTES pSecurityAttributes, PHANDLE phckResult, PDWORD pdwDisposition, HANDLE hSpooler) @@ -1397,7 +1473,7 @@ static VOID printer_free(printer_t * printer)
monitor_unload(printer->pm);
- free(printer->printername); + release_printer_info(printer->info); free(printer->name); free(printer); } @@ -1412,8 +1488,6 @@ 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)) { @@ -1434,9 +1508,6 @@ static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault) printer = calloc(1, sizeof(printer_t)); if (!printer) goto end;
- /* clone the base name. This is NULL for the printserver */ - printer->printername = wcsdup(printername); - /* clone the full name */ printer->name = wcsdup(name); if (name && (!printer->name)) { @@ -1486,24 +1557,14 @@ static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault) } 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->info = get_printer_info(printername); + if (!printer->info) + { printer_free(printer); SetLastError(ERROR_INVALID_PRINTER_NAME); printer = NULL; goto end; } - RegCloseKey(hkeyPrinter); - RegCloseKey(hkeyPrinters); } } else
From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/provider.c | 151 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 150 insertions(+), 1 deletion(-)
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index 25a67e3ae36..c6028144f58 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -216,10 +216,23 @@ typedef struct { LPCWSTR versionsubdir; } printenv_t;
+#define MAX_JOB_ID 99999 + +typedef struct { + struct list entry; + DWORD id; + WCHAR *filename; + WCHAR *document_title; + DEVMODEW *devmode; +} job_t; + typedef struct { WCHAR *name; struct list entry; LONG ref; + + CRITICAL_SECTION jobs_cs; + struct list jobs; } printer_info_t;
typedef struct { @@ -227,6 +240,7 @@ typedef struct { LPWSTR name; monitor_t * pm; HANDLE hXcv; + DEVMODEW *devmode; } printer_t;
/* ############################### */ @@ -235,6 +249,7 @@ static struct list monitor_handles = LIST_INIT( monitor_handles ); static monitor_t * pm_localport;
static struct list printers = LIST_INIT(printers); +static LONG last_job_id;
static const WCHAR fmt_driversW[] = L"System\CurrentControlSet\control\Print\Environments\%s\Drivers%s"; @@ -485,6 +500,8 @@ static printer_info_t* get_printer_info(const WCHAR *name) { info->ref = 1; list_add_head(&printers, &info->entry); + InitializeCriticalSection(&info->jobs_cs); + list_init(&info->jobs); } else if (info) { @@ -496,6 +513,15 @@ static printer_info_t* get_printer_info(const WCHAR *name) return info; }
+static void free_job(job_t *job) +{ + list_remove(&job->entry); + free(job->filename); + free(job->document_title); + free(job->devmode); + free(job); +} + static void release_printer_info(printer_info_t *info) { if (!info) @@ -508,10 +534,26 @@ static void release_printer_info(printer_info_t *info) LeaveCriticalSection(&printers_cs);
free(info->name); + DeleteCriticalSection(&info->jobs_cs); + while (!list_empty(&info->jobs)) + { + job_t *job = LIST_ENTRY(list_head(&info->jobs), job_t, entry); + free_job(job); + } free(info); } }
+static DEVMODEW * dup_devmode(const DEVMODEW *dm) +{ + DEVMODEW *ret; + + if (!dm) return NULL; + ret = malloc(dm->dmSize + dm->dmDriverExtra); + if (ret) memcpy(ret, dm, dm->dmSize + dm->dmDriverExtra); + return ret; +} + static LONG WINAPI CreateKey(HANDLE hcKey, LPCWSTR pszSubKey, DWORD dwOptions, REGSAM samDesired, PSECURITY_ATTRIBUTES pSecurityAttributes, PHANDLE phckResult, PDWORD pdwDisposition, HANDLE hSpooler) @@ -1475,6 +1517,7 @@ static VOID printer_free(printer_t * printer)
release_printer_info(printer->info); free(printer->name); + free(printer->devmode); free(printer); }
@@ -1572,6 +1615,9 @@ static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault) TRACE("using the local printserver\n"); }
+ if (pDefault && pDefault->pDevMode) + printer->devmode = dup_devmode(pDefault->pDevMode); + end:
TRACE("==> %p\n", printer); @@ -2824,6 +2870,109 @@ static BOOL WINAPI fpEnumForms( HANDLE printer, DWORD level, BYTE *form, DWORD s return TRUE; }
+static size_t get_spool_filename(DWORD job_id, WCHAR *buf, size_t len) +{ + static const WCHAR spool_path[] = L"spool\PRINTERS\"; + size_t ret; + + ret = GetSystemDirectoryW(NULL, 0) + ARRAY_SIZE(spool_path) + 10; + if (len < ret) + return ret; + + ret = GetSystemDirectoryW(buf, ret); + if (buf[ret - 1] != '\') + buf[ret++] = '\'; + memcpy(buf + ret, spool_path, sizeof(spool_path)); + ret += ARRAY_SIZE(spool_path) - 1; + swprintf(buf + ret, 10, L"%05d.SPL", job_id); + ret += 10; + return ret; +} + +static job_t* add_job(printer_t *printer, DOC_INFO_1W *info) +{ + DWORD job_id, last_id; + size_t len; + job_t *job; + + job = calloc(1, sizeof(*job)); + if (!job) + return NULL; + len = get_spool_filename(0, NULL, 0); + job->filename = malloc(len * sizeof(WCHAR)); + if (!job->filename) + { + free(job); + return NULL; + } + + while (1) + { + last_id = last_job_id; + job_id = last_id < MAX_JOB_ID ? last_id + 1 : 1; + if (InterlockedCompareExchange(&last_job_id, job_id, last_id) == last_id) + break; + } + + job->id = job_id; + get_spool_filename(job_id, job->filename, len); + job->document_title = wcsdup(info->pDocName); + job->devmode = dup_devmode(printer->devmode); + + EnterCriticalSection(&printer->info->jobs_cs); + list_add_tail(&printer->info->jobs, &job->entry); + LeaveCriticalSection(&printer->info->jobs_cs); + return job; +} + +static BOOL WINAPI fpAddJob(HANDLE hprinter, DWORD level, BYTE *data, DWORD size, DWORD *needed) +{ + ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W *)data; + printer_t *printer = (printer_t *)hprinter; + DOC_INFO_1W doc_info; + job_t *job; + size_t len; + + TRACE("(%p %ld %p %ld %p)\n", hprinter, level, data, size, needed); + + if (!printer || !printer->info) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (level != 1) + { + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + + if (!needed) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + len = get_spool_filename(0, NULL, 0); + *needed = sizeof(*addjob) + len * sizeof(WCHAR); + if (size < *needed) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + memset(&doc_info, 0, sizeof(doc_info)); + doc_info.pDocName = (WCHAR *)L"Local Downlevel Document"; + job = add_job(printer, &doc_info); + if (!job) + return FALSE; + + addjob->JobId = job->id; + addjob->Path = (WCHAR *)(addjob + 1); + memcpy(addjob->Path, job->filename, len * sizeof(WCHAR)); + return TRUE; +} + static const PRINTPROVIDOR backend = { fpOpenPrinter, NULL, /* fpSetJob */ @@ -2851,7 +3000,7 @@ static const PRINTPROVIDOR backend = { NULL, /* fpAbortPrinter */ NULL, /* fpReadPrinter */ NULL, /* fpEndDocPrinter */ - NULL, /* fpAddJob */ + fpAddJob, NULL, /* fpScheduleJob */ NULL, /* fpGetPrinterData */ NULL, /* fpSetPrinterData */
From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/provider.c | 43 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-)
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index c6028144f58..0365c5d1f44 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -222,6 +222,7 @@ typedef struct { struct list entry; DWORD id; WCHAR *filename; + WCHAR *port; WCHAR *document_title; DEVMODEW *devmode; } job_t; @@ -241,6 +242,7 @@ typedef struct { monitor_t * pm; HANDLE hXcv; DEVMODEW *devmode; + job_t *doc; } printer_t;
/* ############################### */ @@ -517,6 +519,7 @@ static void free_job(job_t *job) { list_remove(&job->entry); free(job->filename); + free(job->port); free(job->document_title); free(job->devmode); free(job); @@ -2905,6 +2908,13 @@ static job_t* add_job(printer_t *printer, DOC_INFO_1W *info) free(job); return NULL; } + job->port = wcsdup(info->pOutputFile); + if (info->pOutputFile && !job->port) + { + free(job->filename); + free(job); + return NULL; + }
while (1) { @@ -2973,6 +2983,37 @@ static BOOL WINAPI fpAddJob(HANDLE hprinter, DWORD level, BYTE *data, DWORD size return TRUE; }
+static DWORD WINAPI fpStartDocPrinter(HANDLE hprinter, DWORD level, BYTE *doc_info) +{ + printer_t *printer = (printer_t *)hprinter; + DOC_INFO_1W *info = (DOC_INFO_1W *)doc_info; + + TRACE("(%p %ld %p {pDocName = %s, pOutputFile = %s, pDatatype = %s})\n", + hprinter, level, doc_info, debugstr_w(info->pDocName), + debugstr_w(info->pOutputFile), debugstr_w(info->pDatatype)); + + if (!printer || !printer->info) + { + SetLastError(ERROR_INVALID_HANDLE); + return 0; + } + + if (level < 1 || level > 3) + { + SetLastError(ERROR_INVALID_LEVEL); + return 0; + } + + if (printer->doc) + { + SetLastError(ERROR_INVALID_PRINTER_STATE); + return 0; + } + + printer->doc = add_job(printer, info); + return printer->doc ? printer->doc->id : 0; +} + static const PRINTPROVIDOR backend = { fpOpenPrinter, NULL, /* fpSetJob */ @@ -2993,7 +3034,7 @@ static const PRINTPROVIDOR backend = { fpGetPrintProcessorDirectory, NULL, /* fpDeletePrintProcessor */ NULL, /* fpEnumPrintProcessorDatatypes */ - NULL, /* fpStartDocPrinter */ + fpStartDocPrinter, NULL, /* fpStartPagePrinter */ NULL, /* fpWritePrinter */ NULL, /* fpEndPagePrinter */
From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/provider.c | 90 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-)
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index 0365c5d1f44..e4226bf97e5 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -3014,9 +3014,97 @@ static DWORD WINAPI fpStartDocPrinter(HANDLE hprinter, DWORD level, BYTE *doc_in return printer->doc ? printer->doc->id : 0; }
+static job_t * get_job(printer_info_t *info, DWORD job_id) +{ + job_t *job; + + LIST_FOR_EACH_ENTRY(job, &info->jobs, job_t, entry) + { + if(job->id == job_id) + return job; + } + return NULL; +} + +static BOOL WINAPI fpSetJob(HANDLE hprinter, DWORD job_id, + DWORD level, BYTE *data, DWORD command) +{ + printer_t *printer = (printer_t *)hprinter; + BOOL ret = FALSE; + job_t *job; + + TRACE("(%p, %ld, %ld, %p, %ld)\n", hprinter, job_id, level, data, command); + FIXME("Ignoring everything other than document title\n"); + + if (!printer || !printer->info) + { + SetLastError(ERROR_INVALID_HANDLE); + return 0; + } + + EnterCriticalSection(&printer->info->jobs_cs); + job = get_job(printer->info, job_id); + if (!job) + { + LeaveCriticalSection(&printer->info->jobs_cs); + return FALSE; + } + + switch(level) + { + case 0: + ret = TRUE; + break; + case 1: + { + JOB_INFO_1W *info1 = (JOB_INFO_1W *)job; + WCHAR *title = wcsdup(info1->pDocument); + + if (title) + { + free(job->document_title); + job->document_title = title; + ret = TRUE; + } + break; + } + case 2: + { + JOB_INFO_2W *info2 = (JOB_INFO_2W *)job; + WCHAR *title = wcsdup(info2->pDocument); + DEVMODEW *devmode = dup_devmode(info2->pDevMode); + + if (!title || !devmode) + { + free(title); + free(devmode); + } + else + { + free(job->document_title); + free(job->devmode); + job->document_title = title; + job->devmode = devmode; + ret = TRUE; + } + break; + } + case 3: + FIXME("level 3 stub\n"); + ret = TRUE; + break; + default: + SetLastError(ERROR_INVALID_LEVEL); + break; + } + + LeaveCriticalSection(&printer->info->jobs_cs); + return ret; +} + static const PRINTPROVIDOR backend = { fpOpenPrinter, - NULL, /* fpSetJob */ + fpSetJob, NULL, /* fpGetJob */ NULL, /* fpEnumJobs */ NULL, /* fpAddPrinter */
From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/provider.c | 125 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-)
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index e4226bf97e5..589023b800c 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -3102,10 +3102,133 @@ static BOOL WINAPI fpSetJob(HANDLE hprinter, DWORD job_id, return ret; }
+static BOOL WINAPI fpGetJob(HANDLE hprinter, DWORD job_id, DWORD level, + BYTE *data, DWORD size, DWORD *needed) +{ + printer_t *printer = (printer_t *)hprinter; + BOOL ret = TRUE; + DWORD s = 0; + job_t *job; + WCHAR *p; + + TRACE("%p %ld %ld %p %ld %p\n", hprinter, job_id, level, data, size, needed); + + if (!printer || !printer->info) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!needed) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + EnterCriticalSection(&printer->info->jobs_cs); + job = get_job(printer->info, job_id); + if (!job) + { + LeaveCriticalSection(&printer->info->jobs_cs); + return FALSE; + } + + switch(level) + { + case 1: + s = sizeof(JOB_INFO_1W); + s += job->document_title ? (wcslen(job->document_title) + 1) * sizeof(WCHAR) : 0; + s += printer->info->name ? + (wcslen(printer->info->name) + 1) * sizeof(WCHAR) : 0; + + if (size >= s) + { + JOB_INFO_1W *info = (JOB_INFO_1W *)data; + + p = (WCHAR *)(info + 1); + memset(info, 0, sizeof(*info)); + info->JobId = job->id; + if (job->document_title) + { + info->pDocument = p; + wcscpy(p, job->document_title); + p += wcslen(job->document_title) + 1; + } + if (printer->info->name) + { + info->pPrinterName = p; + wcscpy(p, printer->info->name); + } + } + break; + case 2: + s = sizeof(JOB_INFO_2W); + s += job->document_title ? (wcslen(job->document_title) + 1) * sizeof(WCHAR) : 0; + s += printer->info->name ? + (wcslen(printer->info->name) + 1) * sizeof(WCHAR) : 0; + if (job->devmode) + { + /* align DEVMODE to a DWORD boundary */ + s += (4 - (s & 3)) & 3; + s += job->devmode->dmSize + job->devmode->dmDriverExtra; + } + + if (size >= s) + { + JOB_INFO_2W *info = (JOB_INFO_2W *)data; + + p = (WCHAR *)(info + 1); + memset(info, 0, sizeof(*info)); + info->JobId = job->id; + if (job->document_title) + { + info->pDocument = p; + wcscpy(p, job->document_title); + p += wcslen(job->document_title) + 1; + } + if (printer->info->name) + { + info->pPrinterName = p; + wcscpy(p, printer->info->name); + p += wcslen(printer->info->name) + 1; + } + if (job->devmode) + { + DEVMODEW *devmode = (DEVMODEW *)(data + s - job->devmode->dmSize + - job->devmode->dmDriverExtra); + info->pDevMode = devmode; + memcpy(devmode, job->devmode, job->devmode->dmSize + job->devmode->dmDriverExtra); + } + } + break; + case 3: + FIXME("level 3 stub\n"); + s = sizeof(JOB_INFO_3); + + if (size >= s) + memset(data, 0, sizeof(JOB_INFO_3)); + break; + default: + SetLastError(ERROR_INVALID_LEVEL); + ret = FALSE; + break; + } + + LeaveCriticalSection(&printer->info->jobs_cs); + + *needed = s; + if (size < s) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + ret = FALSE; + } + return ret; +} + static const PRINTPROVIDOR backend = { fpOpenPrinter, fpSetJob, - NULL, /* fpGetJob */ + fpGetJob, NULL, /* fpEnumJobs */ NULL, /* fpAddPrinter */ NULL, /* fpDeletePrinter */
From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/provider.c | 101 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 2 deletions(-)
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index 589023b800c..d26c710fd6e 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -232,6 +232,8 @@ typedef struct { struct list entry; LONG ref;
+ WCHAR *port; + CRITICAL_SECTION jobs_cs; struct list jobs; } printer_info_t; @@ -474,7 +476,9 @@ static printer_info_t* get_printer_info(const WCHAR *name) { HKEY hkey, hprinter = NULL; printer_info_t *info; + WCHAR port[MAX_PATH]; LSTATUS ret; + DWORD size;
EnterCriticalSection(&printers_cs); LIST_FOR_EACH_ENTRY(info, &printers, printer_info_t, entry) @@ -491,6 +495,9 @@ static printer_info_t* get_printer_info(const WCHAR *name) if (ret == ERROR_SUCCESS) ret = RegOpenKeyW(hkey, name, &hprinter); RegCloseKey(hkey); + size = sizeof(port); + if (ret == ERROR_SUCCESS) + ret = RegQueryValueExW(hprinter, L"Port", 0, NULL, (BYTE*)port, &size); RegCloseKey(hprinter); if (ret != ERROR_SUCCESS) { @@ -498,7 +505,8 @@ static printer_info_t* get_printer_info(const WCHAR *name) return NULL; }
- if ((info = calloc(1, sizeof(*info))) && (info->name = wcsdup(name))) + if ((info = calloc(1, sizeof(*info))) && (info->name = wcsdup(name)) && + (info->port = wcsdup(port))) { info->ref = 1; list_add_head(&printers, &info->entry); @@ -507,6 +515,7 @@ static printer_info_t* get_printer_info(const WCHAR *name) } else if (info) { + free(info->name); free(info); info = NULL; } @@ -537,6 +546,7 @@ static void release_printer_info(printer_info_t *info) LeaveCriticalSection(&printers_cs);
free(info->name); + free(info->port); DeleteCriticalSection(&info->jobs_cs); while (!list_empty(&info->jobs)) { @@ -3225,6 +3235,93 @@ static BOOL WINAPI fpGetJob(HANDLE hprinter, DWORD job_id, DWORD level, return ret; }
+static BOOL WINAPI fpScheduleJob(HANDLE hprinter, DWORD job_id) +{ + BOOL ret_startdoc = FALSE, ret_open = FALSE, ret = TRUE; + printer_t *printer = (printer_t *)hprinter; + const WCHAR *port_name, *port; + DOC_INFO_1W info; + monitor_t *mon; + BYTE buf[4096]; + HANDLE hport; + DWORD r, w; + job_t *job; + HANDLE hf; + + TRACE("%p %ld\n", hprinter, job_id); + + if (!printer || !printer->info) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + EnterCriticalSection(&printer->info->jobs_cs); + job = get_job(printer->info, job_id); + if (!job) + { + LeaveCriticalSection(&printer->info->jobs_cs); + return FALSE; + } + + port = job->port; + if (!port) + port = printer->info->port; + TRACE("need to schedule job %ld filename %s to port %s\n", job->id, + debugstr_w(job->filename), debugstr_w(port)); + + hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, 0, NULL); + if (hf == INVALID_HANDLE_VALUE) + { + DeleteFileW(job->filename); + free_job(job); + LeaveCriticalSection(&printer->info->jobs_cs); + } + + /* TODO: use print processor */ + if (isalpha(port[0]) && port[1] == ':') + port_name = L"FILE:"; + else + port_name = port; + + if (!(mon = monitor_load_by_port(port_name)) || !mon->monitor.pfnOpenPort || + !mon->monitor.pfnStartDocPort || !mon->monitor.pfnWritePort || + !mon->monitor.pfnEndDocPort || !mon->monitor.pfnClosePort) + { + FIXME("port not supported: %s\n", debugstr_w(port_name)); + ret = FALSE; + } + + if (ret) + ret = ret_open = mon->monitor.pfnOpenPort(mon->hmon, (WCHAR *)port_name, &hport); + + if (ret) + { + info.pDocName = job->document_title; + info.pOutputFile = (WCHAR *)port; + info.pDatatype = NULL; + ret = ret_startdoc = mon->monitor.pfnStartDocPort(hport, printer->info->name, + job_id, 1, (BYTE *)&info); + } + + while (ret && ReadFile(hf, buf, sizeof(buf), &r, NULL) && r) + ret = mon->monitor.pfnWritePort(hport, buf, r, &w) && r == w; + + if (ret_startdoc) + mon->monitor.pfnEndDocPort(hport); + if (ret_open) + mon->monitor.pfnClosePort(hport); + if (mon) + monitor_unload(mon); + + CloseHandle(hf); + DeleteFileW(job->filename); + free_job(job); + LeaveCriticalSection(&printer->info->jobs_cs); + return ret; +} + static const PRINTPROVIDOR backend = { fpOpenPrinter, fpSetJob, @@ -3253,7 +3350,7 @@ static const PRINTPROVIDOR backend = { NULL, /* fpReadPrinter */ NULL, /* fpEndDocPrinter */ fpAddJob, - NULL, /* fpScheduleJob */ + fpScheduleJob, NULL, /* fpGetPrinterData */ NULL, /* fpSetPrinterData */ NULL, /* fpWaitForPrinterChange */
From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/provider.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index d26c710fd6e..fcddd2a7018 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -3322,6 +3322,30 @@ static BOOL WINAPI fpScheduleJob(HANDLE hprinter, DWORD job_id) return ret; }
+static BOOL WINAPI fpEndDocPrinter(HANDLE hprinter) +{ + printer_t *printer = (printer_t *)hprinter; + BOOL ret; + + TRACE("%p\n", hprinter); + + if (!printer || !printer->info) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!printer->doc) + { + SetLastError(ERROR_SPL_NO_STARTDOC); + return FALSE; + } + + ret = fpScheduleJob(hprinter, printer->doc->id); + printer->doc = NULL; + return ret; +} + static const PRINTPROVIDOR backend = { fpOpenPrinter, fpSetJob, @@ -3348,7 +3372,7 @@ static const PRINTPROVIDOR backend = { NULL, /* fpEndPagePrinter */ NULL, /* fpAbortPrinter */ NULL, /* fpReadPrinter */ - NULL, /* fpEndDocPrinter */ + fpEndDocPrinter, fpAddJob, fpScheduleJob, NULL, /* fpGetPrinterData */
This merge request was approved by Huw Davies.