forked from osmocom/wireshark
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
This commit is contained in:
parent
6fd601bc3b
commit
2c71f23d1e
|
@ -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 <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -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;
|
||||
|
||||
{
|
||||
HDC hDC;
|
||||
DOCINFO di;
|
||||
HWND hWndParent = HWND_DESKTOP; /* would be better to be a real window */
|
||||
|
||||
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);
|
||||
|
||||
/* 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
|
||||
|
||||
FILE* fh1;
|
||||
size_t results;
|
||||
int cnt=0, y_pos = y_offset, y_cnt = 0;
|
||||
char buf[ max_buf_size];
|
||||
char ch;
|
||||
TEXTMETRIC tm;
|
||||
|
||||
GetTextMetrics(hdc, &tm);
|
||||
SetMapMode (hdc, MM_TEXT);
|
||||
|
||||
|
||||
fh1 = ws_fopen( file_name, "r" );
|
||||
if( !fh1 ) {
|
||||
MessageBox( NULL, "Open failed on input file",
|
||||
"Error", MB_APPLMODAL | MB_OK);
|
||||
/* Did you get a good DC?, Cancel will return NULL also, so what to do? */
|
||||
if (!hDC) {
|
||||
return;
|
||||
}
|
||||
|
||||
while ((results = fread( &ch, 1, 1, fh1 )) != 0) {
|
||||
/* 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);
|
||||
|
||||
/* 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];
|
||||
char ch;
|
||||
TEXTMETRIC tm;
|
||||
int max_chars_per_line, max_lines_per_page;
|
||||
|
||||
SetMapMode(hdc, MM_LOMETRIC);
|
||||
GetTextMetrics(hdc, &tm);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
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:
|
||||
*/
|
||||
|
||||
|
|
Loading…
Reference in New Issue