From 2c71f23d1e32572daf461f768c6b8ec7ab75d8b1 Mon Sep 17 00:00:00 2001 From: Chris Maynard Date: Sat, 15 Jun 2013 12:57:32 +0000 Subject: Make use of text metrics and devmode data to properly format a page for printing. Fixes https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=7543 #BACKPORT(1.10,1.8) svn path=/trunk/; revision=49946 --- ui/win32/print_win32.c | 344 ++++++++++++++++++++++++++----------------------- 1 file changed, 183 insertions(+), 161 deletions(-) (limited to 'ui/win32/print_win32.c') diff --git a/ui/win32/print_win32.c b/ui/win32/print_win32.c index 788f764004..649430dd0d 100644 --- a/ui/win32/print_win32.c +++ b/ui/win32/print_win32.c @@ -23,10 +23,10 @@ * * * This original code was from the Technet Article Q139652 : - * HOWTO: Print a Document + * HOWTO: Print a Document + * You can now find it at http://support.microsoft.com/kb/139652 */ - #include #include @@ -48,211 +48,233 @@ information. See - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/prntspol_62ia.asp + http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/prntspol_62ia.asp for information on printer APIs. */ -static BOOL CALLBACK abort_proc( HDC hDC, int Error ); -static HDC get_printer_dc(void); -static void init_doc_struct( DOCINFO* di, char* docname); -static void print_file( const char* file_name, HDC hdc); +static BOOL CALLBACK abort_proc(HDC hDC, int Error); +static HDC get_printer_dc(short *width, short *height); +static void init_doc_struct(DOCINFO* di, char* docname); +static void print_file(const char* file_name, HDC hdc, int width, int height); void print_mswin(const char *file_name) +{ + HDC hDC; + DOCINFO di; + short int width, height; + + HWND hWndParent = HWND_DESKTOP; /* would be better to be a real window */ + + /* Need a printer DC to print to. */ + hDC = get_printer_dc(&width, &height); + + /* Did you get a good DC?, Cancel will return NULL also, so what to do? */ + if (!hDC) { + return; + } + + /* You always have to use an AbortProc(). */ + if (SetAbortProc(hDC, abort_proc) == SP_ERROR) { + MessageBox(NULL, "Error setting up AbortProc", + "Error", MB_APPLMODAL | MB_OK); + return; + } + + /* Init the DOCINFO and start the document. */ + init_doc_struct(&di, "MyDoc"); + StartDoc(hDC, &di); + + /* Print one page. */ + StartPage(hDC); + print_file(file_name, hDC, width, height); + EndPage(hDC); - { - HDC hDC; - DOCINFO di; - - HWND hWndParent = HWND_DESKTOP; /* would be better to be a real window */ - - /* Need a printer DC to print to. */ - hDC = get_printer_dc(); - - /* Did you get a good DC?, Cancel will return NULL also, so what to do? */ - if( !hDC) - { - return; - } - - /* You always have to use an AbortProc(). */ - if( SetAbortProc( hDC, abort_proc ) == SP_ERROR ) - { - MessageBox( NULL, "Error setting up AbortProc", - "Error", MB_APPLMODAL | MB_OK); - return; - } - - /* Init the DOCINFO and start the document. */ - init_doc_struct( &di, "MyDoc"); - StartDoc( hDC, &di ); - - /* Print one page. */ - StartPage( hDC ); - print_file(file_name, hDC ); - EndPage( hDC ); - - /* Indicate end of document. */ - EndDoc( hDC ); - - /* Clean up */ - DeleteDC( hDC ); - } - - /*===============================*/ - /* Obtain printer device context */ - /* ==============================*/ - static HDC get_printer_dc(void) - { - PRINTDLG pdlg; - - /* - * XXX - can this be done without a Windows print dialog? - * - * "CreateDC()" creates a device context, and you can - * apparently specify WINSPL16 as the driver name on - * Windows OT, or the name of a "print provider", such as - * "WINSPOOL" on Windows NT, to get a context for a printer. - * - * The device name would be the printer name as shown by the - * Print Manager; is there a way to enumerate those? - */ - - /* Initialize the PRINTDLG structure. */ - memset( &pdlg, 0, sizeof( PRINTDLG ) ); - pdlg.lStructSize = sizeof( PRINTDLG ); - /* Set the flag to return printer DC. */ - pdlg.Flags = - /* return the device context we need */ - PD_RETURNDC | - /* disable the "Pages" radio button */ - PD_NOPAGENUMS | - /* disable the "Selection" radio button */ - PD_NOSELECTION | - /* let device print multiple pages (if requested) */ - PD_USEDEVMODECOPIESANDCOLLATE; - - /* Invoke the printer dialog box. */ - PrintDlg( &pdlg ); - - /* hDC member of the PRINTDLG structure contains the printer DC. */ - return pdlg.hDC; - } - - /*===============================*/ - /* The Abort Procudure */ - /* ==============================*/ - static BOOL CALLBACK abort_proc( HDC hDC, int Error ) - { - MSG msg; - while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) - { - TranslateMessage( &msg ); - DispatchMessage( &msg ); - } - return TRUE; - } - - /*===============================*/ - /* Initialize DOCINFO structure */ - /* ==============================*/ - static void init_doc_struct( DOCINFO* di, char* docname) - { - /* Always zero it before using it. */ - memset( di, 0, sizeof( DOCINFO ) ); - /* Fill in the required members. */ - di->cbSize = sizeof( DOCINFO ); - di->lpszDocName = docname; - } - - /*===============================*/ - /* Drawing on the DC */ - /* ==============================*/ -static void print_file( const char *file_name, HDC hdc) { - - #define max_buf_size 1024 - #define max_lines 66 - #define y_offset 5 - #define x_offset 5 + /* Indicate end of document. */ + EndDoc(hDC); + + /* Clean up */ + DeleteDC(hDC); +} + +/* Obtain printer device context */ +static HDC get_printer_dc(short *width, short *height) +{ + PRINTDLG pdlg; + PDEVMODE returnedDevmode; + + /* + * XXX - can this be done without a Windows print dialog? + * + * "CreateDC()" creates a device context, and you can + * apparently specify WINSPL16 as the driver name on + * Windows OT, or the name of a "print provider", such as + * "WINSPOOL" on Windows NT, to get a context for a printer. + * + * The device name would be the printer name as shown by the + * Print Manager; is there a way to enumerate those? + */ + + /* Initialize the PRINTDLG structure. */ + memset(&pdlg, 0, sizeof(PRINTDLG)); + pdlg.lStructSize = sizeof(PRINTDLG); + /* Set the flag to return printer DC. */ + pdlg.Flags = + PD_RETURNDC | /* return the device context we need */ + PD_NOPAGENUMS | /* disable the "Pages" radio button */ + PD_NOSELECTION | /* disable the "Selection" radio button */ + PD_USEDEVMODECOPIESANDCOLLATE; /* let device print multiple pages */ + + /* Invoke the printer dialog box. */ + if (PrintDlg(&pdlg)) { + /* http://msdn.microsoft.com/en-us/library/windows/desktop/dd162931%28v=vs.85%29.aspx */ + returnedDevmode = (PDEVMODE)GlobalLock(pdlg.hDevMode); + + if (returnedDevmode->dmOrientation == DMORIENT_LANDSCAPE) { + *width = returnedDevmode->dmPaperLength; + *height = returnedDevmode->dmPaperWidth; + } + else { /* assume DMORIENT_PORTRAIT */ + *width = returnedDevmode->dmPaperWidth; + *height = returnedDevmode->dmPaperLength; + } + + GlobalUnlock(pdlg.hDevMode); + + if (pdlg.hDevMode) + GlobalFree(pdlg.hDevMode); + if (pdlg.hDevNames) + GlobalFree(pdlg.hDevNames); + } + + /* hDC member of the PRINTDLG structure contains the printer DC. */ + return pdlg.hDC; +} + +/* The Abort Procedure */ +static BOOL CALLBACK abort_proc(HDC hDC, int Error) +{ + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return TRUE; +} + +/* Initialize DOCINFO structure */ +static void init_doc_struct(DOCINFO* di, char* docname) +{ + /* Always zero it before using it. */ + memset(di, 0, sizeof(DOCINFO)); + /* Fill in the required members. */ + di->cbSize = sizeof(DOCINFO); + di->lpszDocName = docname; +} + +/* Drawing on the DC */ +static void print_file(const char *file_name, HDC hdc, int width, int height) +{ + #define MAX_BUF_SIZE 1024 /* An arbitrary maximum */ + #define X_OFFSET 5 + #define Y_OFFSET 5 FILE* fh1; size_t results; - int cnt=0, y_pos = y_offset, y_cnt = 0; - char buf[ max_buf_size]; + int cnt=0, y_pos = Y_OFFSET, y_cnt = 0; + char buf[MAX_BUF_SIZE]; char ch; TEXTMETRIC tm; + int max_chars_per_line, max_lines_per_page; + SetMapMode(hdc, MM_LOMETRIC); GetTextMetrics(hdc, &tm); - SetMapMode (hdc, MM_TEXT); + max_chars_per_line = MIN(width / (tm.tmMaxCharWidth + 1), MAX_BUF_SIZE); + max_lines_per_page = height / (tm.tmHeight + 1); + SetMapMode(hdc, MM_TEXT); + GetTextMetrics(hdc, &tm); - fh1 = ws_fopen( file_name, "r" ); - if( !fh1 ) { - MessageBox( NULL, "Open failed on input file", - "Error", MB_APPLMODAL | MB_OK); + fh1 = ws_fopen(file_name, "r"); + if (!fh1) { + MessageBox(NULL, "Open failed on input file", + "Error", MB_APPLMODAL | MB_OK); return; } - while ((results = fread( &ch, 1, 1, fh1 )) != 0) { - + while ((results = fread(&ch, 1, 1, fh1)) != 0) { /* end of page (form feed)? */ - if ( ch == 0x0c){ + if (ch == 0x0c) { /* send buffer */ buf[cnt] = 0; - TextOut(hdc, x_offset,y_pos, buf, (int) strlen(buf)); - y_pos += tm.tmHeight; - cnt = 0; + TextOut(hdc, X_OFFSET,y_pos, buf, (int) strlen(buf)); + y_pos += tm.tmHeight; + cnt = 0; /* reset page */ - EndPage( hdc ); - StartPage( hdc ); - y_pos = y_offset; + EndPage(hdc); + StartPage(hdc); + y_pos = Y_OFFSET; y_cnt = 0; continue; } /* end of line (line feed)? */ - if ( ch == 0x0a){ + if (ch == 0x0a) { /* send buffer */ - buf[ cnt] = 0; - TextOut(hdc, x_offset,y_pos, buf, (int) strlen(buf)); - y_pos += tm.tmHeight; - cnt = 0; + buf[cnt] = 0; + TextOut(hdc, X_OFFSET,y_pos, buf, (int) strlen(buf)); + y_pos += tm.tmHeight; + cnt = 0; /* last line on page? -> reset page */ - if ( ++y_cnt == max_lines){ - EndPage( hdc ); - StartPage( hdc ); - y_pos = y_offset; + if (++y_cnt == max_lines_per_page) { + EndPage(hdc); + StartPage(hdc); + y_pos = Y_OFFSET; y_cnt = 0; - } + } continue; } /* buffer full? */ - if ( cnt == ( max_buf_size - 1)) { + if (cnt == (max_chars_per_line - 1)) { /* send buffer */ - buf[ cnt] = 0; - TextOut(hdc, x_offset, y_pos, buf, (int) strlen(buf)); + buf[cnt] = 0; + TextOut(hdc, X_OFFSET, y_pos, buf, (int) strlen(buf)); y_pos += tm.tmHeight; cnt = 0; /* last line on page? -> reset page */ - if ( ++y_cnt == max_lines){ - EndPage( hdc ); - StartPage( hdc ); - y_pos = y_offset; - y_cnt = 0; - } + if (++y_cnt == max_lines_per_page) { + EndPage(hdc); + StartPage(hdc); + y_pos = Y_OFFSET; + y_cnt = 0; + } continue; - } + } - buf[ cnt++] = ch; + buf[cnt++] = ch; } /* while */ /* Print the remaining text if needed */ - if ( cnt > 0) { - buf[ cnt] = 0; - TextOut(hdc, 0,y_pos, buf, (int) strlen(buf)); + if (cnt > 0) { + buf[cnt] = 0; + TextOut(hdc, 0,y_pos, buf, (int) strlen(buf)); } fclose(fh1); } + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=4 expandtab: + * :indentSize=4:tabSize=4:noTabs=true: + */ + -- cgit v1.2.1