diff --git a/channels/printer/client/CMakeLists.txt b/channels/printer/client/CMakeLists.txt index ea2f0df22..58d44f99e 100644 --- a/channels/printer/client/CMakeLists.txt +++ b/channels/printer/client/CMakeLists.txt @@ -18,39 +18,23 @@ define_channel_client("printer") set(${MODULE_PREFIX}_SRCS - printer_main.c - printer_main.h) - -if(WITH_CUPS) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} - printer_cups.c - printer_cups.h) - - include_directories(${CUPS_INCLUDE_DIR}) - add_definitions(-DWITH_CUPS) -endif() - -if(WIN32 AND NOT UWP) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} - printer_win.c - printer_win.h) -endif() + printer_main.c) add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DeviceServiceEntry") - - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) - -if(WITH_CUPS) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${CUPS_LIBRARIES}) -endif() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT BUILTIN_CHANNELS AND BUILD_SHARED_LIBS) install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") + +if(WITH_CUPS) + add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "cups" "") +endif() + +if(WIN32 AND NOT UWP) + add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "win" "") +endif() diff --git a/channels/printer/client/cups/CMakeLists.txt b/channels/printer/client/cups/CMakeLists.txt new file mode 100644 index 000000000..f7363da37 --- /dev/null +++ b/channels/printer/client/cups/CMakeLists.txt @@ -0,0 +1,32 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2019 Armin Novak +# Copyright 2019 Thincast Technologies GmbH +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +define_channel_client_subsystem("printer" "cups" "") + +set(${MODULE_PREFIX}_SRCS + printer_cups.c) + +include_directories(..) +include_directories(${CUPS_INCLUDE_DIR}) +add_definitions(-DWITH_CUPS) + +add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${CUPS_LIBRARIES}) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/printer/client/printer_cups.c b/channels/printer/client/cups/printer_cups.c similarity index 73% rename from channels/printer/client/printer_cups.c rename to channels/printer/client/cups/printer_cups.c index 8af8752c3..6683de5c2 100644 --- a/channels/printer/client/printer_cups.c +++ b/channels/printer/client/cups/printer_cups.c @@ -37,9 +37,7 @@ #include -#include "printer_main.h" - -#include "printer_cups.h" +#include typedef struct rdp_cups_printer_driver rdpCupsPrinterDriver; typedef struct rdp_cups_printer rdpCupsPrinter; @@ -50,6 +48,7 @@ struct rdp_cups_printer_driver rdpPrinterDriver driver; int id_sequence; + size_t references; }; struct rdp_cups_printer @@ -67,16 +66,16 @@ struct rdp_cups_print_job int printjob_id; }; -static void printer_cups_get_printjob_name(char* buf, int size) +static void printer_cups_get_printjob_name(char* buf, size_t size, size_t id) { time_t tt; struct tm* t; tt = time(NULL); t = localtime(&tt); - sprintf_s(buf, size - 1, "FreeRDP Print Job %d%02d%02d%02d%02d%02d", + sprintf_s(buf, size - 1, "FreeRDP Print %04d-%02d-%02d %02d-%02d-%02d - Job %"PRIdz, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, - t->tm_hour, t->tm_min, t->tm_sec); + t->tm_hour, t->tm_min, t->tm_sec, id); } /** @@ -126,7 +125,7 @@ static void printer_cups_close_printjob(rdpPrintJob* printjob) { char buf[100]; - printer_cups_get_printjob_name(buf, sizeof(buf)); + printer_cups_get_printjob_name(buf, sizeof(buf), printjob->id); if (cupsPrintFile(printjob->printer->name, (const char*) cups_printjob->printjob_object, buf, 0, NULL) == 0) { @@ -188,7 +187,7 @@ static rdpPrintJob* printer_cups_create_printjob(rdpPrinter* printer, UINT32 id) return NULL; } - printer_cups_get_printjob_name(buf, sizeof(buf)); + printer_cups_get_printjob_name(buf, sizeof(buf), cups_printjob->printjob.id); cups_printjob->printjob_id = cupsCreateJob((http_t*) cups_printjob->printjob_object, printer->name, buf, 0, NULL); @@ -230,11 +229,29 @@ static void printer_cups_free_printer(rdpPrinter* printer) if (cups_printer->printjob) cups_printer->printjob->printjob.Close((rdpPrintJob*) cups_printer->printjob); + if (printer->backend) + printer->backend->ReleaseRef(printer->backend); free(printer->name); free(printer->driver); free(printer); } +static void printer_cups_add_ref_printer(rdpPrinter* printer) +{ + if (printer) + printer->references++; +} + +static void printer_cups_release_ref_printer(rdpPrinter* printer) +{ + if (!printer) + return; + if (printer->references <= 1) + printer_cups_free_printer(printer); + else + printer->references--; +} + static rdpPrinter* printer_cups_new_printer(rdpCupsPrinterDriver* cups_driver, const char* name, const char* driverName, BOOL is_default) { @@ -244,6 +261,8 @@ static rdpPrinter* printer_cups_new_printer(rdpCupsPrinterDriver* cups_driver, if (!cups_printer) return NULL; + cups_printer->printer.backend = &cups_driver->driver; + cups_printer->printer.id = cups_driver->id_sequence++; cups_printer->printer.name = _strdup(name); if (!cups_printer->printer.name) @@ -266,9 +285,26 @@ static rdpPrinter* printer_cups_new_printer(rdpCupsPrinterDriver* cups_driver, cups_printer->printer.CreatePrintJob = printer_cups_create_printjob; cups_printer->printer.FindPrintJob = printer_cups_find_printjob; - cups_printer->printer.Free = printer_cups_free_printer; + cups_printer->printer.AddRef = printer_cups_add_ref_printer; + cups_printer->printer.ReleaseRef = printer_cups_release_ref_printer; - return (rdpPrinter*) cups_printer; + + cups_printer->printer.AddRef(&cups_printer->printer); + cups_printer->printer.backend->AddRef(cups_printer->printer.backend); + return &cups_printer->printer; +} + +static void printer_cups_release_enum_printers(rdpPrinter** printers) +{ + rdpPrinter** cur = printers; + + while((cur != NULL) && ((*cur) != NULL)) + { + if ((*cur)->ReleaseRef) + (*cur)->ReleaseRef(*cur); + cur++; + } + free(printers); } static rdpPrinter** printer_cups_enum_printers(rdpPrinterDriver* driver) @@ -291,8 +327,17 @@ static rdpPrinter** printer_cups_enum_printers(rdpPrinterDriver* driver) { if (dest->instance == NULL) { - printers[num_printers++] = printer_cups_new_printer((rdpCupsPrinterDriver*) driver, + rdpPrinter* current = printers[num_printers]; + current = printer_cups_new_printer((rdpCupsPrinterDriver*) driver, dest->name, NULL, dest->is_default); + if (!current) + { + printer_cups_release_enum_printers(printers); + printers = NULL; + break; + } + + printers[num_printers++] = current; } } cupsFreeDests(num_dests, dests); @@ -309,11 +354,35 @@ static rdpPrinter* printer_cups_get_printer(rdpPrinterDriver* driver, cups_driver->id_sequence == 1 ? TRUE : FALSE); } +static void printer_cups_add_ref_driver(rdpPrinterDriver* driver) +{ + rdpCupsPrinterDriver* cups_driver = (rdpCupsPrinterDriver*) driver; + if (cups_driver) + cups_driver->references++; +} + +/* Singleton */ static rdpCupsPrinterDriver* cups_driver = NULL; -rdpPrinterDriver* printer_cups_get_driver(void) +static void printer_cups_release_ref_driver(rdpPrinterDriver* driver) { - if (cups_driver == NULL) + rdpCupsPrinterDriver* cups_driver = (rdpCupsPrinterDriver*) driver; + if (cups_driver->references <= 1) + { + free(cups_driver); + cups_driver = NULL; + } + else + cups_driver->references--; +} + +#ifdef BUILTIN_CHANNELS +rdpPrinterDriver *cups_freerdp_printer_client_subsystem_entry(void) +#else +FREERDP_API rdpPrinterDriver *freerdp_printer_client_subsystem_entry(void) +#endif +{ + if (!cups_driver) { cups_driver = (rdpCupsPrinterDriver*) calloc(1, sizeof(rdpCupsPrinterDriver)); @@ -321,11 +390,15 @@ rdpPrinterDriver* printer_cups_get_driver(void) return NULL; cups_driver->driver.EnumPrinters = printer_cups_enum_printers; + cups_driver->driver.ReleaseEnumPrinters = printer_cups_release_enum_printers; cups_driver->driver.GetPrinter = printer_cups_get_printer; + cups_driver->driver.AddRef = printer_cups_add_ref_driver; + cups_driver->driver.ReleaseRef = printer_cups_release_ref_driver; + cups_driver->id_sequence = 1; + cups_driver->driver.AddRef(&cups_driver->driver); } - return (rdpPrinterDriver*) cups_driver; + return &cups_driver->driver; } - diff --git a/channels/printer/client/printer_cups.h b/channels/printer/client/printer_cups.h deleted file mode 100644 index 876cb47d7..000000000 --- a/channels/printer/client/printer_cups.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Print Virtual Channel - CUPS driver - * - * Copyright 2010-2011 Vic Lee - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FREERDP_CHANNEL_PRINTER_CLIENT_CUPS_H -#define FREERDP_CHANNEL_PRINTER_CLIENT_CUPS_H - -#include "printer_main.h" - -rdpPrinterDriver* printer_cups_get_driver(void); - -#endif /* FREERDP_CHANNEL_PRINTER_CLIENT_CUPS_H */ - diff --git a/channels/printer/client/printer_main.c b/channels/printer/client/printer_main.c index 9b76de366..d8848a241 100644 --- a/channels/printer/client/printer_main.c +++ b/channels/printer/client/printer_main.c @@ -42,15 +42,7 @@ #include "../printer.h" -#ifdef WITH_CUPS -#include "printer_cups.h" -#endif - -#include "printer_main.h" - -#if defined(_WIN32) && !defined(_UWP) -#include "printer_win.h" -#endif +#include #include @@ -863,7 +855,7 @@ static UINT printer_free(DEVICE* device) _aligned_free(printer_dev->pIrpList); if (printer_dev->printer) - printer_dev->printer->Free(printer_dev->printer); + printer_dev->printer->ReleaseRef(printer_dev->printer); Stream_Free(printer_dev->device.data, TRUE); free(printer_dev); @@ -875,7 +867,7 @@ static UINT printer_free(DEVICE* device) * * @return 0 on success, otherwise a Win32 error code */ -UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, +static UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, rdpPrinter* printer) { PRINTER_DEVICE* printer_dev; @@ -945,39 +937,69 @@ UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, goto error_out; } + printer->AddRef(printer); return CHANNEL_RC_OK; error_out: printer_free(&printer_dev->device); return error; } -#ifdef BUILTIN_CHANNELS -#define DeviceServiceEntry printer_DeviceServiceEntry -#else -#define DeviceServiceEntry FREERDP_API DeviceServiceEntry -#endif +static rdpPrinterDriver* printer_load_backend(const char* backend) +{ + typedef rdpPrinterDriver* (*backend_load_t)(void); + + backend_load_t entry = (backend_load_t)freerdp_load_channel_addin_entry("printer", backend, NULL, 0); + if (!entry) + return NULL; + + return entry(); +} /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) +UINT +#ifdef BUILTIN_CHANNELS +printer_DeviceServiceEntry +#else +FREERDP_API DeviceServiceEntry +#endif + (PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) { int i; char* name; char* driver_name; - rdpPrinter* printer; - rdpPrinter** printers; - RDPDR_PRINTER* device; + RDPDR_PRINTER* device = NULL; rdpPrinterDriver* driver = NULL; - UINT error; -#ifdef WITH_CUPS - driver = printer_cups_get_driver(); -#endif -#if defined(_WIN32) && !defined(_UWP) - driver = printer_win_get_driver(); -#endif + UINT error = CHANNEL_RC_OK; + size_t pos; + + if (!pEntryPoints || !pEntryPoints->device) + return ERROR_INVALID_PARAMETER; + + device = (RDPDR_PRINTER*) pEntryPoints->device; + name = device->Name; + driver_name = device->DriverName; + + /* Secondary argument is one of the following: + * + * ... name of a printer driver + * : ... name of a printer driver and local printer backend to use + */ + if (driver_name) + { + char* sep = strstr(driver_name, ":"); + if (sep) + { + const char* backend = sep + 1; + *sep = '\0'; + driver = printer_load_backend(backend); + } + } + else + driver = printer_load_backend(""); if (!driver) { @@ -985,47 +1007,52 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) return CHANNEL_RC_INITIALIZATION_ERROR; } - device = (RDPDR_PRINTER*) pEntryPoints->device; - name = device->Name; - driver_name = device->DriverName; - if (name && name[0]) { - printer = driver->GetPrinter(driver, name, driver_name); + rdpPrinter* printer = driver->GetPrinter(driver, name, driver_name); if (!printer) { WLog_ERR(TAG, "Could not get printer %s!", name); - return CHANNEL_RC_INITIALIZATION_ERROR; + error = CHANNEL_RC_INITIALIZATION_ERROR; + goto fail; } if (!printer_save_default_config(pEntryPoints->rdpcontext->settings, printer)) - return CHANNEL_RC_INITIALIZATION_ERROR; + { + error = CHANNEL_RC_INITIALIZATION_ERROR; + printer->ReleaseRef(printer); + goto fail; + } if ((error = printer_register(pEntryPoints, printer))) { WLog_ERR(TAG, "printer_register failed with error %"PRIu32"!", error); - return error; + printer->ReleaseRef(printer); + goto fail; } } else { - printers = driver->EnumPrinters(driver); + rdpPrinter** printers = driver->EnumPrinters(driver); + rdpPrinter** current = printers; - for (i = 0; printers[i]; i++) + for (i = 0; current[i]; i++) { - printer = printers[i]; + rdpPrinter* printer = current[i]; if ((error = printer_register(pEntryPoints, printer))) { WLog_ERR(TAG, "printer_register failed with error %"PRIu32"!", error); - free(printers); - return error; + break; } } - free(printers); + driver->ReleaseEnumPrinters(printers); } - return CHANNEL_RC_OK; + fail: + driver->ReleaseRef(driver); + + return error; } diff --git a/channels/printer/client/printer_win.h b/channels/printer/client/printer_win.h deleted file mode 100644 index 22777d0af..000000000 --- a/channels/printer/client/printer_win.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Print Virtual Channel - win driver - * - * Copyright 2012 Gerald Richter - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FREERDP_CHANNEL_PRINTER_CLIENT_WIN_H -#define FREERDP_CHANNEL_PRINTER_CLIENT_WIN_H - -#include - -rdpPrinterDriver* printer_win_get_driver(void); - -#define PRINTER_TAG CHANNELS_TAG("printer.client") -#ifdef WITH_DEBUG_WINPR -#define DEBUG_WINPR(...) WLog_DBG(PRINTER_TAG, __VA_ARGS__) -#else -#define DEBUG_WINPR(...) do { } while (0) -#endif - -#endif /* FREERDP_CHANNEL_PRINTER_CLIENT_WIN_H */ - diff --git a/channels/printer/client/win/CMakeLists.txt b/channels/printer/client/win/CMakeLists.txt new file mode 100644 index 000000000..aa648fda7 --- /dev/null +++ b/channels/printer/client/win/CMakeLists.txt @@ -0,0 +1,29 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2019 Armin Novak +# Copyright 2019 Thincast Technologies GmbH +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +define_channel_client_subsystem("printer" "win" "") + +set(${MODULE_PREFIX}_SRCS + printer_win.c) + +include_directories(..) + +add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/printer/client/printer_win.c b/channels/printer/client/win/printer_win.c similarity index 65% rename from channels/printer/client/printer_win.c rename to channels/printer/client/win/printer_win.c index 665a8519d..1be9365ed 100644 --- a/channels/printer/client/printer_win.c +++ b/channels/printer/client/win/printer_win.c @@ -34,9 +34,14 @@ #include #include -#include "printer_main.h" +#include -#include "printer_win.h" +#define PRINTER_TAG CHANNELS_TAG("printer.client") +#ifdef WITH_DEBUG_WINPR +#define DEBUG_WINPR(...) WLog_DBG(PRINTER_TAG, __VA_ARGS__) +#else +#define DEBUG_WINPR(...) do { } while (0) +#endif typedef struct rdp_win_printer_driver rdpWinPrinterDriver; typedef struct rdp_win_printer rdpWinPrinter; @@ -46,7 +51,8 @@ struct rdp_win_printer_driver { rdpPrinterDriver driver; - int id_sequence; + size_t id_sequence; + size_t references; }; struct rdp_win_printer @@ -66,16 +72,26 @@ struct rdp_win_print_job int printjob_id; }; -static void printer_win_get_printjob_name(char* buf, int size) +static WCHAR* printer_win_get_printjob_name(size_t id) { time_t tt; struct tm* t; + WCHAR* str; + size_t len = 1024; + int rc; tt = time(NULL); t = localtime(&tt); - sprintf_s(buf, size - 1, "FreeRDP Print Job %d%02d%02d%02d%02d%02d", + + str = calloc(len, sizeof(WCHAR)); + if (!str) + return NULL; + + rc = swprintf_s(str, len, L"FreeRDP Print %04d-%02d-%02d% 02d-%02d-%02d - Job %lu\0", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, - t->tm_hour, t->tm_min, t->tm_sec); + t->tm_hour, t->tm_min, t->tm_sec, id); + + return str; } /** @@ -83,15 +99,21 @@ static void printer_win_get_printjob_name(char* buf, int size) * * @return 0 on success, otherwise a Win32 error code */ -static UINT printer_win_write_printjob(rdpPrintJob* printjob, BYTE* data, int size) +static UINT printer_win_write_printjob(rdpPrintJob* printjob, const BYTE* data, size_t size) { - rdpWinPrintJob* win_printjob = (rdpWinPrintJob*) printjob; - - LPVOID pBuf = data; + rdpWinPrinter* printer; + LPCVOID pBuf = data; DWORD cbBuf = size; DWORD pcWritten; - if(!WritePrinter(((rdpWinPrinter*)printjob->printer)->hPrinter, pBuf, cbBuf, &pcWritten)) + if (!printjob || !data) + return ERROR_BAD_ARGUMENTS; + + printer = (rdpWinPrinter*)printjob->printer; + if (!printer) + return ERROR_BAD_ARGUMENTS; + + if(!WritePrinter(printer->hPrinter, pBuf, cbBuf, &pcWritten)) return ERROR_INTERNAL_ERROR; return CHANNEL_RC_OK; } @@ -99,19 +121,28 @@ static UINT printer_win_write_printjob(rdpPrintJob* printjob, BYTE* data, int si static void printer_win_close_printjob(rdpPrintJob* printjob) { rdpWinPrintJob* win_printjob = (rdpWinPrintJob*) printjob; + rdpWinPrinter* win_printer; - if (!EndPagePrinter(((rdpWinPrinter*) printjob->printer)->hPrinter)) + if (!printjob) + return; + + win_printer = (rdpWinPrinter*)printjob->printer; + if (!win_printer) + return; + + if (!EndPagePrinter(win_printer->hPrinter)) { } - if (!ClosePrinter(((rdpWinPrinter*) printjob->printer)->hPrinter)) + if (!ClosePrinter(win_printer->hPrinter)) { } - ((rdpWinPrinter*) printjob->printer)->printjob = NULL; + win_printer->printjob = NULL; + free(win_printjob->di.pDocName); free(win_printjob); } @@ -129,7 +160,7 @@ static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32 id) win_printjob->printjob.id = id; win_printjob->printjob.printer = printer; - win_printjob->di.pDocName = L"FREERDPjob"; + win_printjob->di.pDocName = printer_win_get_printjob_name(id); win_printjob->di.pDatatype= NULL; win_printjob->di.pOutputFile = NULL; @@ -137,12 +168,14 @@ static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32 id) if (!win_printjob->handle) { + free(win_printjob->di.pDocName); free(win_printjob); return NULL; } if (!StartPagePrinter(win_printer->hPrinter)) { + free(win_printjob->di.pDocName); free(win_printjob); return NULL; } @@ -152,7 +185,7 @@ static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32 id) win_printer->printjob = win_printjob; - return (rdpPrintJob*) win_printjob; + return &win_printjob->printjob; } static rdpPrintJob* printer_win_find_printjob(rdpPrinter* printer, UINT32 id) @@ -175,11 +208,30 @@ static void printer_win_free_printer(rdpPrinter* printer) if (win_printer->printjob) win_printer->printjob->printjob.Close((rdpPrintJob*) win_printer->printjob); + if (printer->backend) + printer->backend->ReleaseRef(printer->backend); + free(printer->name); free(printer->driver); free(printer); } +static void printer_win_add_ref_printer(rdpPrinter* printer) +{ + if (printer) + printer->references++; +} + +static void printer_win_release_ref_printer(rdpPrinter* printer) +{ + if (!printer) + return; + if (printer->references <= 1) + printer_win_free_printer(printer); + else + printer->references--; +} + static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, const WCHAR* name, const WCHAR* drivername, BOOL is_default) { @@ -192,6 +244,7 @@ static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, if (!win_printer) return NULL; + win_printer->printer.backend = &win_driver->driver; win_printer->printer.id = win_driver->id_sequence++; if (ConvertFromUnicode(CP_UTF8, 0, name, -1, &win_printer->printer.name, 0, NULL, NULL) < 1) { @@ -208,7 +261,8 @@ static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, win_printer->printer.CreatePrintJob = printer_win_create_printjob; win_printer->printer.FindPrintJob = printer_win_find_printjob; - win_printer->printer.Free = printer_win_free_printer; + win_printer->printer.AddRef = printer_win_add_ref_printer; + win_printer->printer.ReleaseRef = printer_win_release_ref_printer; if (!OpenPrinter(name, &(win_printer->hPrinter), NULL)) { @@ -254,7 +308,22 @@ static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, return NULL; } - return (rdpPrinter*)win_printer; + win_printer->printer.AddRef(&win_printer->printer); + win_printer->printer.backend->AddRef(win_printer->printer.backend); + return &win_printer->printer; +} + +static void printer_win_release_enum_printers(rdpPrinter** printers) +{ + rdpPrinter** cur = printers; + + while((cur != NULL) && ((*cur) != NULL)) + { + if ((*cur)->ReleaseRef) + (*cur)->ReleaseRef(*cur); + cur++; + } + free(printers); } static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver) @@ -291,8 +360,16 @@ static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver) for (i = 0; i < (int) returned; i++) { - printers[num_printers++] = printer_win_new_printer((rdpWinPrinterDriver*)driver, + rdpPrinter* current = printers[num_printers]; + current = printer_win_new_printer((rdpWinPrinterDriver*)driver, prninfo[i].pPrinterName, prninfo[i].pDriverName, 0); + if (!current) + { + printer_win_release_enum_printers(printers); + printers = NULL; + break; + } + printers[num_printers++] = current; } GlobalFree(prninfo); @@ -303,9 +380,16 @@ static rdpPrinter* printer_win_get_printer(rdpPrinterDriver* driver, const char* name, const char* driverName) { WCHAR* driverNameW = NULL; + WCHAR* nameW = NULL; rdpWinPrinterDriver* win_driver = (rdpWinPrinterDriver*)driver; rdpPrinter *myPrinter = NULL; + if (name) + { + ConvertToUnicode(CP_UTF8, 0, name, -1, &nameW, 0); + if (!driverNameW) + return NULL; + } if (driverName) { ConvertToUnicode(CP_UTF8, 0, driverName, -1, &driverNameW, 0); @@ -313,29 +397,64 @@ static rdpPrinter* printer_win_get_printer(rdpPrinterDriver* driver, return NULL; } - myPrinter = printer_win_new_printer(win_driver, name, driverNameW, + myPrinter = printer_win_new_printer(win_driver, nameW, driverNameW, win_driver->id_sequence == 1 ? TRUE : FALSE); free(driverNameW); + free(nameW); return myPrinter; } + +static void printer_win_add_ref_driver(rdpPrinterDriver* driver) +{ + rdpWinPrinterDriver* win = (rdpWinPrinterDriver*) driver; + if (win) + win->references++; +} + +/* Singleton */ static rdpWinPrinterDriver* win_driver = NULL; -rdpPrinterDriver* printer_win_get_driver(void) +static void printer_win_release_ref_driver(rdpPrinterDriver* driver) +{ + rdpWinPrinterDriver* win = (rdpWinPrinterDriver*) driver; + if (win->references <= 1) + { + free(win); + win_driver = NULL; + } + else + win->references--; +} + +#ifdef BUILTIN_CHANNELS +rdpPrinterDriver *win_freerdp_printer_client_subsystem_entry(void) +#else +FREERDP_API rdpPrinterDriver *freerdp_printer_client_subsystem_entry(void) +#endif { if (!win_driver) { win_driver = (rdpWinPrinterDriver*) calloc(1, sizeof(rdpWinPrinterDriver)); + if (!win_driver) return NULL; win_driver->driver.EnumPrinters = printer_win_enum_printers; + win_driver->driver.ReleaseEnumPrinters = printer_win_release_enum_printers; win_driver->driver.GetPrinter = printer_win_get_printer; + win_driver->driver.AddRef = printer_win_add_ref_driver; + win_driver->driver.ReleaseRef = printer_win_release_ref_driver; + win_driver->id_sequence = 1; + win_driver->driver.AddRef(&win_driver->driver); } - return (rdpPrinterDriver*) win_driver; + return &win_driver->driver; } + + + diff --git a/channels/printer/client/printer_main.h b/include/freerdp/client/printer.h similarity index 55% rename from channels/printer/client/printer_main.h rename to include/freerdp/client/printer.h index 07bd60854..0f1ee74f9 100644 --- a/channels/printer/client/printer_main.h +++ b/include/freerdp/client/printer.h @@ -20,8 +20,8 @@ * limitations under the License. */ -#ifndef FREERDP_CHANNEL_PRINTER_CLIENT_MAIN_H -#define FREERDP_CHANNEL_PRINTER_CLIENT_MAIN_H +#ifndef FREERDP_CHANNEL_PRINTER_CLIENT_PRINTER_H +#define FREERDP_CHANNEL_PRINTER_CLIENT_PRINTER_H #include @@ -29,33 +29,44 @@ typedef struct rdp_printer_driver rdpPrinterDriver; typedef struct rdp_printer rdpPrinter; typedef struct rdp_print_job rdpPrintJob; -typedef rdpPrinter** (*pcEnumPrinters) (rdpPrinterDriver* driver); -typedef rdpPrinter* (*pcGetPrinter) (rdpPrinterDriver* driver, const char* name, const char* driverName); +typedef void (*pcReferencePrinterDriver)(rdpPrinterDriver* driver); +typedef rdpPrinter** (*pcEnumPrinters)(rdpPrinterDriver* driver); +typedef void (*pcReleaseEnumPrinters)(rdpPrinter** printers); + +typedef rdpPrinter* (*pcGetPrinter)(rdpPrinterDriver* driver, const char* name, + const char* driverName); +typedef void (*pcReferencePrinter)(rdpPrinter* printer); struct rdp_printer_driver { pcEnumPrinters EnumPrinters; + pcReleaseEnumPrinters ReleaseEnumPrinters; pcGetPrinter GetPrinter; + + pcReferencePrinterDriver AddRef; + pcReferencePrinterDriver ReleaseRef; }; -typedef rdpPrintJob* (*pcCreatePrintJob) (rdpPrinter* printer, UINT32 id); -typedef rdpPrintJob* (*pcFindPrintJob) (rdpPrinter* printer, UINT32 id); -typedef void (*pcFreePrinter) (rdpPrinter* printer); +typedef rdpPrintJob* (*pcCreatePrintJob)(rdpPrinter* printer, UINT32 id); +typedef rdpPrintJob* (*pcFindPrintJob)(rdpPrinter* printer, UINT32 id); struct rdp_printer { - int id; + size_t id; char* name; char* driver; BOOL is_default; + size_t references; + rdpPrinterDriver* backend; pcCreatePrintJob CreatePrintJob; pcFindPrintJob FindPrintJob; - pcFreePrinter Free; + pcReferencePrinter AddRef; + pcReferencePrinter ReleaseRef; }; -typedef UINT (*pcWritePrintJob) (rdpPrintJob* printjob, const BYTE* data, size_t size); -typedef void (*pcClosePrintJob) (rdpPrintJob* printjob); +typedef UINT (*pcWritePrintJob)(rdpPrintJob* printjob, const BYTE* data, size_t size); +typedef void (*pcClosePrintJob)(rdpPrintJob* printjob); struct rdp_print_job { @@ -66,4 +77,4 @@ struct rdp_print_job pcClosePrintJob Close; }; -#endif /* FREERDP_CHANNEL_PRINTER_CLIENT_MAIN_H */ +#endif /* FREERDP_CHANNEL_PRINTER_CLIENT_PRINTER_H */