diff --git a/channels/rdpdr/client/CMakeLists.txt b/channels/rdpdr/client/CMakeLists.txt index 854770647..a3fa82e1c 100644 --- a/channels/rdpdr/client/CMakeLists.txt +++ b/channels/rdpdr/client/CMakeLists.txt @@ -41,8 +41,8 @@ endif() install(TARGETS rdpdr DESTINATION ${FREERDP_PLUGIN_PATH}) add_subdirectory(disk) +add_subdirectory(printer) if(NOT WIN32) - add_subdirectory(printer) add_subdirectory(parallel) add_subdirectory(serial) endif() diff --git a/channels/rdpdr/client/printer/CMakeLists.txt b/channels/rdpdr/client/printer/CMakeLists.txt index ea4e19fa4..91dd64863 100644 --- a/channels/rdpdr/client/printer/CMakeLists.txt +++ b/channels/rdpdr/client/printer/CMakeLists.txt @@ -31,6 +31,13 @@ if(WITH_CUPS) add_definitions(-DWITH_CUPS) endif() +if(WIN32) + set(PRINTER_SRCS + ${PRINTER_SRCS} + printer_win.c + printer_win.h) +endif() + include_directories(..) add_library(printer ${PRINTER_SRCS}) diff --git a/channels/rdpdr/client/printer/printer_main.c b/channels/rdpdr/client/printer/printer_main.c index a4db9377b..2716472cf 100644 --- a/channels/rdpdr/client/printer/printer_main.c +++ b/channels/rdpdr/client/printer/printer_main.c @@ -40,6 +40,10 @@ #include "printer_main.h" +#ifdef WIN32 +#include "printer_win.h" +#endif + typedef struct _PRINTER_DEVICE PRINTER_DEVICE; struct _PRINTER_DEVICE { @@ -294,7 +298,11 @@ void printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, rdpPrinter* pri freerdp_thread_start(printer_dev->thread, printer_thread_func, printer_dev); } +#ifdef WITH_STATIC_PLUGINS +int printer_entry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) +#else int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) +#endif { rdpPrinterDriver* driver = NULL; rdpPrinter** printers; @@ -305,6 +313,9 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) #ifdef WITH_CUPS driver = printer_cups_get_driver(); +#endif +#ifdef WIN32 + driver = printer_win_get_driver(); #endif if (driver == NULL) { diff --git a/channels/rdpdr/client/printer/printer_win.c b/channels/rdpdr/client/printer/printer_win.c new file mode 100644 index 000000000..6b00704b4 --- /dev/null +++ b/channels/rdpdr/client/printer/printer_win.c @@ -0,0 +1,283 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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. + */ + +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include +#include + +#include "rdpdr_types.h" +#include "printer_main.h" + +#include "printer_win.h" + +typedef struct rdp_win_printer_driver rdpWinPrinterDriver; +typedef struct rdp_win_printer rdpWinPrinter; +typedef struct rdp_win_print_job rdpWinPrintJob; + +struct rdp_win_printer_driver +{ + rdpPrinterDriver driver; + + int id_sequence; +}; + +struct rdp_win_printer +{ + rdpPrinter printer; + HANDLE hPrinter; + rdpWinPrintJob* printjob; +}; + +struct rdp_win_print_job +{ + rdpPrintJob printjob; + DOC_INFO_1 di; + DWORD handle; + + void* printjob_object; + int printjob_id; +}; + +static void printer_win_get_printjob_name(char* buf, int size) +{ + time_t tt; + struct tm* t; + + DEBUG_WINPR(""); + + tt = time(NULL); + t = localtime(&tt); + snprintf(buf, size - 1, "FreeRDP Print Job %d%02d%02d%02d%02d%02d", + t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); + + DEBUG_WINPR("buf: %s", buf); + +} + +static void printer_win_write_printjob(rdpPrintJob* printjob, uint8* data, int size) +{ + rdpWinPrintJob* win_printjob = (rdpWinPrintJob*)printjob; + + LPVOID pBuf = data; + DWORD cbBuf = size; + DWORD pcWritten; + + if( ! WritePrinter( ((rdpWinPrinter*)printjob->printer)->hPrinter, pBuf, cbBuf, &pcWritten ) ) + DEBUG_WINPR("WritePrinter failed"); +; + +} + +static void printer_win_close_printjob(rdpPrintJob* printjob) +{ + rdpWinPrintJob* win_printjob = (rdpWinPrintJob*)printjob; + + DEBUG_WINPR(""); + + if ( ! EndPagePrinter( ((rdpWinPrinter*)printjob->printer)->hPrinter ) ) + DEBUG_WINPR("EndPagePrinter failed");; + if ( ! ClosePrinter( ((rdpWinPrinter*)printjob->printer)->hPrinter ) ) + DEBUG_WINPR("ClosePrinter failed");; + + ((rdpWinPrinter*)printjob->printer)->printjob = NULL; + xfree(win_printjob) ; +} + +static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, uint32 id) +{ + rdpWinPrinter* win_printer = (rdpWinPrinter*)printer; + rdpWinPrintJob* win_printjob; + + DEBUG_WINPR(""); + + if (win_printer->printjob != NULL) + return NULL; + + win_printjob = xnew(rdpWinPrintJob); + + win_printjob->printjob.id = id; + win_printjob->printjob.printer = printer; + win_printjob->di.pDocName = L"FREERDPjob"; + win_printjob->di.pDatatype= NULL; + win_printjob->di.pOutputFile = NULL; + + win_printjob->handle = StartDocPrinter(win_printer->hPrinter, 1, (LPBYTE)&(win_printjob->di) ); + if(! win_printjob->handle) DEBUG_WINPR("StartDocPrinter failed"); + if ( ! StartPagePrinter(win_printer->hPrinter) ) + DEBUG_WINPR("ClosePrinter failed"); + + + win_printjob->printjob.Write = printer_win_write_printjob; + win_printjob->printjob.Close = printer_win_close_printjob; + + + + win_printer->printjob = win_printjob; + + return (rdpPrintJob*)win_printjob; +} + +static rdpPrintJob* printer_win_find_printjob(rdpPrinter* printer, uint32 id) +{ + rdpWinPrinter* win_printer = (rdpWinPrinter*)printer; + + DEBUG_WINPR(""); + + if (win_printer->printjob == NULL) + return NULL; + if (win_printer->printjob->printjob.id != id) + return NULL; + + return (rdpPrintJob*)win_printer->printjob; +} + +static void printer_win_free_printer(rdpPrinter* printer) +{ + rdpWinPrinter* win_printer = (rdpWinPrinter*)printer; + + DEBUG_WINPR(""); + + if (win_printer->printjob) + win_printer->printjob->printjob.Close((rdpPrintJob*)win_printer->printjob); + xfree(printer->name); + xfree(printer); +} + +static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, const char* name, const wchar_t* drivername, boolean is_default) +{ + rdpWinPrinter* win_printer; + wchar_t wname[256]; + DWORD needed; + PRINTER_INFO_2 *prninfo=NULL; + size_t charsConverted; + DEBUG_WINPR(""); + + win_printer = xnew(rdpWinPrinter); + + win_printer->printer.id = win_driver->id_sequence++; + win_printer->printer.name = xstrdup(name); + win_printer->printer.is_default = is_default; + + win_printer->printer.CreatePrintJob = printer_win_create_printjob; + win_printer->printer.FindPrintJob = printer_win_find_printjob; + win_printer->printer.Free = printer_win_free_printer; + + swprintf(wname, 256, L"%hs", name); + OpenPrinter(wname, &(win_printer->hPrinter), NULL); + DEBUG_WINPR("handle: 0x%08X", win_printer->hPrinter); + + GetPrinter(win_printer->hPrinter, 2, (LPBYTE) prninfo, 0, &needed); + prninfo = (PRINTER_INFO_2*) GlobalAlloc(GPTR,needed); + GetPrinter(win_printer->hPrinter, 2, (LPBYTE) prninfo, needed, &needed); + + win_printer->printer.driver = xmalloc(1000); + wcstombs_s(&charsConverted, win_printer->printer.driver, 1000, prninfo->pDriverName, _TRUNCATE); + + return (rdpPrinter*)win_printer; +} + +static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver) +{ + rdpPrinter** printers; + int num_printers; + int i; + char pname[1000]; + size_t charsConverted; + + PRINTER_INFO_2 *prninfo=NULL; + DWORD needed, returned; + + DEBUG_WINPR(""); + + + //find required size for the buffer + EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed, &returned); + + + //allocate array of PRINTER_INFO structures + prninfo = (PRINTER_INFO_2*) GlobalAlloc(GPTR,needed); + + //call again + if ( !EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, (LPBYTE) prninfo, needed, &needed, &returned) ) { + DEBUG_WINPR("EnumPrinters failed"); + + } ; /* eRROR... */ + + DEBUG_WINPR("printers found: %d", returned); + + + printers = (rdpPrinter**)xzalloc(sizeof(rdpPrinter*) * (returned + 1)); + num_printers = 0; + + for (i = 0; i < (int)returned; i++) + { + wcstombs_s(&charsConverted, pname, 1000, prninfo[i].pPrinterName, _TRUNCATE); + printers[num_printers++] = printer_win_new_printer((rdpWinPrinterDriver*)driver, + pname, prninfo[i].pDriverName, 0); + } + + GlobalFree(prninfo); + return printers; +} + +static rdpPrinter* printer_win_get_printer(rdpPrinterDriver* driver, const char* name) +{ + rdpWinPrinterDriver* win_driver = (rdpWinPrinterDriver*)driver; + rdpPrinter *myPrinter = NULL; + + DEBUG_WINPR("printer %s", name); + + myPrinter = printer_win_new_printer(win_driver, name, L"", win_driver->id_sequence == 1 ? true : false); + + return myPrinter; +} + +static rdpWinPrinterDriver* win_driver = NULL; + +rdpPrinterDriver* printer_win_get_driver(void) +{ + DEBUG_WINPR(""); + + if (win_driver == NULL) + { + win_driver = xnew(rdpWinPrinterDriver); + + win_driver->driver.EnumPrinters = printer_win_enum_printers; + win_driver->driver.GetPrinter = printer_win_get_printer; + + win_driver->id_sequence = 1; + +//#ifdef _win_API_1_4 +// DEBUG_SVC("using win API 1.4"); +//#else +// DEBUG_SVC("using win API 1.2"); +//#endif + } + + return (rdpPrinterDriver*)win_driver; +} + diff --git a/channels/rdpdr/client/printer/printer_win.h b/channels/rdpdr/client/printer/printer_win.h new file mode 100644 index 000000000..5b694ac40 --- /dev/null +++ b/channels/rdpdr/client/printer/printer_win.h @@ -0,0 +1,37 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __PRINTER_WIN_H +#define __PRINTER_WIN_H + + +rdpPrinterDriver* printer_win_get_driver(void); + +#ifdef WITH_DEBUG_WINPR +#define DEBUG_WINPR(fmt, ...) DEBUG_CLASS(WINPR, fmt, ## __VA_ARGS__) +#else +#define DEBUG_WINPR(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#endif + +#endif + +#ifdef WIN32 +#define snprintf _snprintf +#endif + diff --git a/client/Windows/CMakeLists.txt b/client/Windows/CMakeLists.txt index 527ab1bba..d3ba988b8 100644 --- a/client/Windows/CMakeLists.txt +++ b/client/Windows/CMakeLists.txt @@ -36,7 +36,7 @@ add_executable(wfreerdp WIN32 ${FREERDP_CLIENT_WINDOWS_SRCS}) if(WITH_MONOLITHIC_BUILD) set(FREERDP_CLIENT_WINDOWS_LIBS ${FREERDP_CLIENT_WINDOWS_LIBS} freerdp) if(WITH_RDPDR) - set(FREERDP_CLIENT_WINDOWS_LIBS ${FREERDP_CLIENT_WINDOWS_LIBS} rdpdr disk) + set(FREERDP_CLIENT_WINDOWS_LIBS ${FREERDP_CLIENT_WINDOWS_LIBS} rdpdr disk printer) endif() else() set(FREERDP_CLIENT_WINDOWS_LIBS ${FREERDP_CLIENT_WINDOWS_LIBS} diff --git a/client/Windows/wfreerdp.c b/client/Windows/wfreerdp.c index f44572c11..04cfc7a35 100644 --- a/client/Windows/wfreerdp.c +++ b/client/Windows/wfreerdp.c @@ -636,6 +636,7 @@ static DWORD WINAPI kbd_thread_func(LPVOID lpParam) #ifdef WITH_RDPDR DEFINE_SVC_PLUGIN_ENTRY(rdpdr) ; DEFINE_DEV_PLUGIN_ENTRY(disk) ; +DEFINE_DEV_PLUGIN_ENTRY(printer) ; #endif @@ -699,6 +700,7 @@ INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine #ifdef WITH_RDPDR REGISTER_SVC_PLUGIN_ENTRY(rdpdr) ; REGISTER_DEV_PLUGIN_ENTRY(disk) ; + REGISTER_DEV_PLUGIN_ENTRY(printer) ; #endif if (!CreateThread(NULL, 0, kbd_thread_func, NULL, 0, NULL))