From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/provider.c | 65 ++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 15 deletions(-)
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index dd6b6b9cf45..82ab5299129 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -234,6 +234,8 @@ typedef struct { LONG ref;
WCHAR *port; + WCHAR *print_proc; + WCHAR *datatype;
CRITICAL_SECTION jobs_cs; struct list jobs; @@ -521,13 +523,32 @@ static printer_info_t *find_printer_info(const WCHAR *name, unsigned int len) return NULL; }
+static WCHAR * reg_query_value(HKEY key, const WCHAR *name) +{ + DWORD size, type; + WCHAR *ret; + + if (RegQueryValueExW(key, name, 0, &type, NULL, &size) != ERROR_SUCCESS + || type != REG_SZ) + return NULL; + + ret = malloc(size); + if (!ret) + return NULL; + + if (RegQueryValueExW(key, name, 0, NULL, (BYTE *)ret, &size) != ERROR_SUCCESS) + { + free(ret); + return NULL; + } + return ret; +} + 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); info = find_printer_info(name, -1); @@ -541,32 +562,44 @@ 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) { LeaveCriticalSection(&printers_cs); return NULL; }
- if ((info = calloc(1, sizeof(*info))) && (info->name = wcsdup(name)) && - (info->port = wcsdup(port))) + info = calloc(1, sizeof(*info)); + if (!info) { - info->ref = 1; - list_add_head(&printers, &info->entry); - InitializeCriticalSection(&info->jobs_cs); - list_init(&info->jobs); + LeaveCriticalSection(&printers_cs); + RegCloseKey(hprinter); + return NULL; } - else if (info) + + info->name = wcsdup(name); + info->port = reg_query_value(hprinter, L"Port"); + info->print_proc = reg_query_value(hprinter, L"Print Processor"); + info->datatype = reg_query_value(hprinter, L"Datatype"); + RegCloseKey(hprinter); + + if (!info->name || !info->port || !info->print_proc || !info->datatype) { free(info->name); + free(info->port); + free(info->print_proc); + free(info->datatype); free(info); - info = NULL; + + LeaveCriticalSection(&printers_cs); + return NULL; } - LeaveCriticalSection(&printers_cs);
+ info->ref = 1; + list_add_head(&printers, &info->entry); + InitializeCriticalSection(&info->jobs_cs); + list_init(&info->jobs); + + LeaveCriticalSection(&printers_cs); return info; }
@@ -594,6 +627,8 @@ static void release_printer_info(printer_info_t *info)
free(info->name); free(info->port); + free(info->print_proc); + free(info->datatype); DeleteCriticalSection(&info->jobs_cs); while (!list_empty(&info->jobs)) {
From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/provider.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index 82ab5299129..69f01850edd 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -835,14 +835,8 @@ static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname) lstrcatW(regroot, name); if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) { /* Get the Driver from the Registry */ - if (driver == NULL) { - DWORD namesize; - if (RegQueryValueExW(hroot, L"Driver", NULL, NULL, NULL, - &namesize) == ERROR_SUCCESS) { - driver = malloc(namesize); - RegQueryValueExW(hroot, L"Driver", NULL, NULL, (BYTE*)driver, &namesize); - } - } + if (!driver) + driver = reg_query_value(hroot, L"Driver"); } else WARN("%s not found\n", debugstr_w(regroot));
From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/provider.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index 69f01850edd..babc17afa31 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -223,6 +223,7 @@ typedef struct { DWORD id; WCHAR *filename; WCHAR *port; + WCHAR *datatype; WCHAR *document_title; DEVMODEW *devmode; HANDLE hf; @@ -608,6 +609,7 @@ static void free_job(job_info_t *job) list_remove(&job->entry); free(job->filename); free(job->port); + free(job->datatype); free(job->document_title); free(job->devmode); CloseHandle(job->hf); @@ -3215,6 +3217,7 @@ static job_info_t* add_job(printer_t *printer, DOC_INFO_1W *info, BOOL create) job->hf = NULL; } job->document_title = wcsdup(info->pDocName); + job->datatype = wcsdup(info->pDatatype); job->devmode = dup_devmode(printer->devmode);
EnterCriticalSection(&printer->info->jobs_cs);
From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/provider.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index babc17afa31..97f77c32ba5 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -275,7 +275,8 @@ typedef struct { typedef struct { handle_header_t header; printer_info_t *info; - LPWSTR name; + WCHAR *name; + WCHAR *datatype; DEVMODEW *devmode; job_info_t *doc; } printer_t; @@ -1841,6 +1842,8 @@ static HANDLE printer_alloc_handle(const WCHAR *name, const WCHAR *basename, return NULL; }
+ if (def && def->pDatatype) + printer->datatype = wcsdup(def->pDatatype); if (def && def->pDevMode) printer->devmode = dup_devmode(def->pDevMode);
@@ -3772,6 +3775,7 @@ static BOOL WINAPI fpClosePrinter(HANDLE hprinter)
release_printer_info(printer->info); free(printer->name); + free(printer->datatype); free(printer->devmode); free(printer); }
From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/provider.c | 198 ++++++++++++++++++++++++++++++--------- 1 file changed, 155 insertions(+), 43 deletions(-)
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index 97f77c32ba5..3effd3da9a1 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -292,7 +292,7 @@ static LONG last_job_id; static const WCHAR fmt_driversW[] = L"System\CurrentControlSet\control\Print\Environments\%s\Drivers%s"; static const WCHAR fmt_printprocessorsW[] = - L"System\CurrentControlSet\Control\Print\Environments\%s\Print Processors"; + L"System\CurrentControlSet\Control\Print\Environments\%s\Print Processors\"; static const WCHAR monitorsW[] = L"System\CurrentControlSet\Control\Print\Monitors\"; static const WCHAR printersW[] = L"System\CurrentControlSet\Control\Print\Printers"; static const WCHAR winnt_cv_portsW[] = L"Software\Microsoft\Windows NT\CurrentVersion\Ports"; @@ -3557,19 +3557,127 @@ static BOOL WINAPI fpGetJob(HANDLE hprinter, DWORD job_id, DWORD level, return ret; }
+typedef struct { + HMODULE hmod; + WCHAR *name; + BOOL (WINAPI *enum_datatypes)(WCHAR *, WCHAR *, DWORD, + BYTE *, DWORD, DWORD *, DWORD *); + HANDLE (WINAPI *open)(WCHAR *, PRINTPROCESSOROPENDATA *); + BOOL (WINAPI *print)(HANDLE, WCHAR *); + BOOL (WINAPI *close)(HANDLE); +} printproc_t; + +static printproc_t * print_proc_load(const WCHAR *name) +{ + WCHAR *reg_path, path[2 * MAX_PATH]; + printproc_t *ret; + DWORD size, len; + LSTATUS status; + HKEY hkey; + + size = sizeof(fmt_printprocessorsW) + + (wcslen(env_arch.envname) + wcslen(name)) * sizeof(WCHAR); + reg_path = malloc(size); + if (!reg_path) + return NULL; + swprintf(reg_path, size / sizeof(WCHAR), fmt_printprocessorsW, env_arch.envname); + wcscat(reg_path, name); + + status = RegOpenKeyW(HKEY_LOCAL_MACHINE, reg_path, &hkey); + free(reg_path); + if (status != ERROR_SUCCESS) + return NULL; + + if (!fpGetPrintProcessorDirectory(NULL, NULL, 1, (BYTE *)path, sizeof(path) - 1, &size)) + { + RegCloseKey(hkey); + return NULL; + } + len = size / sizeof(WCHAR); + path[len - 1] = '\'; + + size = sizeof(path) - len * sizeof(WCHAR); + status = RegQueryValueExW(hkey, L"Driver", NULL, NULL, (BYTE *)(path + len), &size); + RegCloseKey(hkey); + if (status != ERROR_SUCCESS) + return NULL; + + ret = malloc(sizeof(*ret)); + if (!ret) + return NULL; + + TRACE("loading print processor: %s\n", debugstr_w(path)); + + ret->hmod = LoadLibraryW(path); + if (!ret->hmod) + { + free(ret); + return NULL; + } + + ret->enum_datatypes = (void *)GetProcAddress(ret->hmod, "EnumPrintProcessorDatatypesW"); + ret->open = (void *)GetProcAddress(ret->hmod, "OpenPrintProcessor"); + ret->print = (void *)GetProcAddress(ret->hmod, "PrintDocumentOnPrintProcessor"); + ret->close = (void *)GetProcAddress(ret->hmod, "ClosePrintProcessor"); + if (!ret->enum_datatypes || !ret->open || !ret->print || !ret->close) + { + FreeLibrary(ret->hmod); + free(ret); + return NULL; + } + + ret->name = wcsdup(name); + return ret; +} + +static BOOL print_proc_check_datatype(printproc_t *pp, const WCHAR *datatype) +{ + DATATYPES_INFO_1W *types; + DWORD size, no, i; + + if (!datatype) + return FALSE; + + pp->enum_datatypes(NULL, pp->name, 1, NULL, 0, &size, &no); + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return FALSE; + + types = malloc(size); + if (!types) + return FALSE; + + if (!pp->enum_datatypes(NULL, pp->name, 1, (BYTE *)types, size, &size, &no)) + { + free(types); + return FALSE; + } + + for (i = 0; i < no; i++) + { + if (!wcscmp(types[i].pName, datatype)) + break; + } + free(types); + return i < no; +} + +static void print_proc_unload(printproc_t *pp) +{ + FreeLibrary(pp->hmod); + free(pp->name); + free(pp); +} + static BOOL WINAPI fpScheduleJob(HANDLE hprinter, DWORD job_id) { - BOOL ret_startdoc = FALSE, ret_open = FALSE, ret = TRUE; printer_t *printer = (printer_t *)hprinter; + WCHAR output[1024], name[1024], *datatype; + PRINTPROCESSOROPENDATA pp_data; const WCHAR *port_name, *port; - WCHAR output[1024]; - DOC_INFO_1W info; job_info_t *job; - monitor_t *mon; - BYTE buf[4096]; - HANDLE hport; - DWORD r, w; - HANDLE hf; + printproc_t *pp; + BOOL ret = TRUE; + HANDLE hpp; HKEY hkey;
TRACE("%p %ld\n", hprinter, job_id); @@ -3594,18 +3702,6 @@ static BOOL WINAPI fpScheduleJob(HANDLE hprinter, DWORD job_id) 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) - { - WARN("can't open spool file: %s\n", debugstr_w(job->filename)); - DeleteFileW(job->filename); - free_job(job); - LeaveCriticalSection(&printer->info->jobs_cs); - return FALSE; - } - - /* TODO: use print processor */ port_name = port; if ((isalpha(port[0]) && port[1] == ':') || !wcsncmp(port, L"FILE:", ARRAY_SIZE(L"FILE:") - 1)) @@ -3623,37 +3719,53 @@ static BOOL WINAPI fpScheduleJob(HANDLE hprinter, DWORD job_id) RegCloseKey(hkey); }
- if (!(mon = monitor_load_by_port(port_name)) || !mon->monitor.pfnOpenPort || - !mon->monitor.pfnStartDocPort || !mon->monitor.pfnWritePort || - !mon->monitor.pfnEndDocPort || !mon->monitor.pfnClosePort) + pp = print_proc_load(printer->info->print_proc); + if (!pp) { - FIXME("port not supported: %s\n", debugstr_w(port_name)); - ret = FALSE; + WARN("failed to load %s print processor\n", debugstr_w(printer->info->print_proc)); + pp = print_proc_load(L"winprint"); } + if (!pp) + return FALSE;
- if (ret) - ret = ret_open = mon->monitor.pfnOpenPort(mon->hmon, (WCHAR *)port_name, &hport); + if (job->datatype) + datatype = job->datatype; + else if (printer->datatype) + datatype = printer->datatype; + else + datatype = printer->info->datatype;
- if (ret) + if (!print_proc_check_datatype(pp, datatype)) { - 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); + WARN("%s datatype not supported by %s\n", debugstr_w(datatype), + debugstr_w(printer->info->print_proc)); + print_proc_unload(pp); + return FALSE; }
- while (ret && ReadFile(hf, buf, sizeof(buf), &r, NULL) && r) - ret = mon->monitor.pfnWritePort(hport, buf, r, &w) && r == w; + swprintf(name, ARRAY_SIZE(name), L"%s, Port", port_name); + pp_data.pDevMode = job->devmode; + pp_data.pDatatype = datatype; + pp_data.pParameters = NULL; + pp_data.pDocumentName = job->document_title; + pp_data.JobId = job->id; + pp_data.pOutputFile = (WCHAR *)port; + pp_data.pPrinterName = printer->name; + hpp = pp->open(name, &pp_data); + if (!hpp) + { + WARN("OpenPrintProcessor failed %ld\n", GetLastError()); + print_proc_unload(pp); + return FALSE; + }
- if (ret_startdoc) - mon->monitor.pfnEndDocPort(hport); - if (ret_open) - mon->monitor.pfnClosePort(hport); - if (mon) - monitor_unload(mon); + swprintf(name, ARRAY_SIZE(name), L"%s, Job %d", printer->name, job->id); + ret = pp->print(hpp, name); + if (!ret) + WARN("PrintDocumentOnPrintProcessor failed %ld\n", GetLastError()); + pp->close(hpp); + print_proc_unload(pp);
- CloseHandle(hf); DeleteFileW(job->filename); free_job(job); LeaveCriticalSection(&printer->info->jobs_cs);
From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/provider.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-)
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index 3effd3da9a1..321d85107af 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -3899,6 +3899,35 @@ static BOOL WINAPI fpClosePrinter(HANDLE hprinter) return TRUE; }
+static BOOL WINAPI fpSeekPrinter(HANDLE hprinter, LARGE_INTEGER distance, + LARGE_INTEGER *pos, DWORD method, BOOL bwrite) +{ + job_t *job = (job_t *)hprinter; + + TRACE("(%p %I64d %p %lx %x)\n", hprinter, distance.QuadPart, pos, method, bwrite); + + if (!job) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (job->header.type != HANDLE_JOB) + { + FIXME("handle %x not supported\n", job->header.type); + return FALSE; + } + + if (bwrite) + { + if (pos) + pos->QuadPart = 0; + return TRUE; + } + + return SetFilePointerEx(job->hf, distance, pos, method); +} + static const PRINTPROVIDOR backend = { fpOpenPrinter, fpSetJob, @@ -3971,7 +4000,7 @@ static const PRINTPROVIDOR backend = { NULL, /* fpEnumPrinterKey */ NULL, /* fpDeletePrinterDataEx */ NULL, /* fpDeletePrinterKey */ - NULL, /* fpSeekPrinter */ + fpSeekPrinter, NULL, /* fpDeletePrinterDriverEx */ NULL, /* fpAddPerMachineConnection */ NULL, /* fpDeletePerMachineConnection */
From: Piotr Caban piotr@codeweavers.com
--- dlls/winspool.drv/info.c | 18 ++++++++++++++++++ dlls/winspool.drv/winspool.drv.spec | 1 + 2 files changed, 19 insertions(+)
diff --git a/dlls/winspool.drv/info.c b/dlls/winspool.drv/info.c index 8abfc9b0887..602237fc5d7 100644 --- a/dlls/winspool.drv/info.c +++ b/dlls/winspool.drv/info.c @@ -7640,3 +7640,21 @@ HANDLE WINAPI GetSpoolFileHandle( HANDLE printer ) FIXME( "%p: stub\n", printer ); return INVALID_HANDLE_VALUE; } + +/***************************************************************************** + * SeekPrinter [WINSPOOL.@] + */ +BOOL WINAPI SeekPrinter(HANDLE printer, LARGE_INTEGER distance, + LARGE_INTEGER *pos, DWORD method, BOOL bwrite) +{ + HANDLE handle = get_backend_handle(printer); + + TRACE("(%p %I64d %p %lx %x)\n", printer, distance.QuadPart, pos, method, bwrite); + + if (!handle) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + return backend->fpSeekPrinter(handle, distance, pos, method, bwrite); +} diff --git a/dlls/winspool.drv/winspool.drv.spec b/dlls/winspool.drv/winspool.drv.spec index 39c2613a4a0..1ca94e18c40 100644 --- a/dlls/winspool.drv/winspool.drv.spec +++ b/dlls/winspool.drv/winspool.drv.spec @@ -162,6 +162,7 @@ @ stdcall ResetPrinterA(long ptr) @ stdcall ResetPrinterW(long ptr) @ stdcall ScheduleJob(long long) +@ stdcall SeekPrinter(long int64 ptr long long) @ stub SetAllocFailCount @ stdcall SetFormA(long str long ptr) @ stdcall SetFormW(long wstr long ptr)
Huw Davies (@huw) commented about dlls/localspl/provider.c:
- HKEY hkey;
- size = sizeof(fmt_printprocessorsW) +
(wcslen(env_arch.envname) + wcslen(name)) * sizeof(WCHAR);
- reg_path = malloc(size);
- if (!reg_path)
return NULL;
- swprintf(reg_path, size / sizeof(WCHAR), fmt_printprocessorsW, env_arch.envname);
- wcscat(reg_path, name);
- status = RegOpenKeyW(HKEY_LOCAL_MACHINE, reg_path, &hkey);
- free(reg_path);
- if (status != ERROR_SUCCESS)
return NULL;
- if (!fpGetPrintProcessorDirectory(NULL, NULL, 1, (BYTE *)path, sizeof(path) - 1, &size))
Not that it really matters, but the `-1` looks a bit odd here, I'd suggest just passing `sizeof(path)`.