[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/gnuplot/gnuplot/master/src/win/wprinter.c [Back]  [Original]

/* GNUPLOT - win/wprinter.c */
/*[
 * Copyright 1992, 1993, 1998, 2004   Maurice Castro, Russell Lang
 *
 * Permission to use, copy, and distribute this software and its
 * documentation for any purpose with or without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.
 *
 * Permission to modify the software is granted, but not the right to
 * distribute the complete modified source code.  Modifications are to
 * be distributed as patches to the released version.  Permission to
 * distribute binaries produced by compiling modified sources is granted,
 * provided you
 *   1. distribute the corresponding source modifications from the
 *    released version in the form of a patch file along with the binaries,
 *   2. add special version identification to distinguish your version
 *    in addition to the base release version number,
 *   3. provide your name and address as the primary contact for the
 *    support of your modified version, and
 *   4. retain our contact information in regard to use of the base
 *    software.
 * Permission to distribute the released version of the source code along
 * with corresponding source modifications in the form of a patch file is
 * granted with same provisions 2 through 4 for binary distributions.
 *
 * This software is provided "as is" without express or implied warranty
 * to the extent permitted by applicable law.
]*/

/*
 * AUTHORS
 *
 *   Maurice Castro
 *   Russell Lang
 */

/* Dump a file to the printer */

#include "syscfg.h"

#define STRICT
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "wgnuplib.h"
#include "wresourc.h"
#include "wcommon.h"

static GP_LPPRINT prlist = NULL;
HGLOBAL hDevNames = NULL;
HGLOBAL hDevMode = NULL;

static GP_LPPRINT PrintFind(HDC hdc);


/* COM object for PrintDlgEx callbacks, implemented in C
*/
typedef struct {
    IPrintDialogCallback callback;
    IObjectWithSite site;

    IUnknown * pUnkSite_;
    IPrintDialogServices * services_;
    GP_LPPRINT lpr_;
} PrintingCallbackHandler;

// IUnknown
HRESULT STDMETHODCALLTYPE
QueryInterface(IPrintDialogCallback * This, REFIID riid, void ** object)
{
    if (IsEqualIID(riid, &IID_IUnknown)) {
	*object = (void *) This;
    } else if (IsEqualIID(riid, &IID_IPrintDialogCallback)) {
	*object = (void *) &((PrintingCallbackHandler *)This)->callback;
    } else if (IsEqualIID(riid, &IID_IObjectWithSite)) {
	*object = (void *) &((PrintingCallbackHandler *)This)->site;
    } else {
	return E_NOINTERFACE;
    }
    return S_OK;
}

static ULONG STDMETHODCALLTYPE
AddRef(IPrintDialogCallback * This)
{
    return 1;
}

static ULONG STDMETHODCALLTYPE
Release(IPrintDialogCallback * This)
{
    return 1;
}

// IPrintDialogCallback
static HRESULT STDMETHODCALLTYPE
InitDone(IPrintDialogCallback * This)
{
    /* the general page is initialised, but not shown yet */
    PrintingCallbackHandler * Base = (PrintingCallbackHandler *) ((char *) This - offsetof(PrintingCallbackHandler, callback));
#if 0
    IPrintDialogServices * services = Base->services_;
    if (services != NULL) {
    }
#endif
    Base->lpr_->bDriverChanged = TRUE;
    /* always return false to enable default actions */
    return S_FALSE;
}

static HRESULT STDMETHODCALLTYPE
SelectionChange(IPrintDialogCallback * This)
{
    /* the user has selected a different printer */
    PrintingCallbackHandler * Base = (PrintingCallbackHandler *) ((char *) This - offsetof(PrintingCallbackHandler, callback));
#if 0
    IPrintDialogServices * services = Base->services_;
    if (services != NULL) {
    }
#endif
    Base->lpr_->bDriverChanged = TRUE;
    /* always return false to enable default actions */
    return S_FALSE;
}

static HRESULT STDMETHODCALLTYPE
HandleMessage(IPrintDialogCallback * This, HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT * pResult)
{
    // WM_INITDIALOG: lParam points to PRINTDLGEX struct
    /* enable default message handling */
    return S_FALSE;
}

static HRESULT STDMETHODCALLTYPE
SetSite(IObjectWithSite * This, IUnknown * pUnkSite)
{
    PrintingCallbackHandler * Base = (PrintingCallbackHandler *) ((char *) This - offsetof(PrintingCallbackHandler, site));
    if (Base->pUnkSite_ != NULL) {
	Base->pUnkSite_->lpVtbl->Release(Base->pUnkSite_);
	Base->pUnkSite_ = NULL;
    }
    if (pUnkSite == NULL) {
	if (Base->services_ != NULL) {
	    Base->services_->lpVtbl->Release(Base->services_);
	    Base->services_ = NULL;
	}
    } else {
	Base->pUnkSite_ = pUnkSite;
	pUnkSite->lpVtbl->AddRef(pUnkSite);
	if (Base->services_ == NULL) {
	    pUnkSite->lpVtbl->QueryInterface(pUnkSite, &IID_IPrintDialogServices, (void **) &(Base->services_));
	    Base->lpr_->services = Base->services_;
	}
    }
    return S_OK;
}

static HRESULT STDMETHODCALLTYPE
GetSite(IObjectWithSite * This, REFIID riid, void ** ppvSite)
{
    /* according to documentation this _must_ be implemented */
    PrintingCallbackHandler * Base = (PrintingCallbackHandler *) ((char *) This - offsetof(PrintingCallbackHandler, site));
    *ppvSite = Base->pUnkSite_;
    return (Base->pUnkSite_ != NULL) ? S_OK : E_FAIL;
}

static IPrintDialogCallbackVtbl IPrintDialogCallback_Vtbl = {
    QueryInterface, AddRef, Release, InitDone, SelectionChange, HandleMessage
};

static IObjectWithSiteVtbl IObjectWithSite_Vtbl = {
    (HRESULT(STDMETHODCALLTYPE *)(IObjectWithSite *, const IID *const, void **)) QueryInterface,
    (ULONG (STDMETHODCALLTYPE *)(IObjectWithSite *)) AddRef,
    (ULONG (STDMETHODCALLTYPE *)(IObjectWithSite *)) Release,
    SetSite,
    GetSite
};

static void
PrintingCallbackInit(PrintingCallbackHandler * This, GP_LPPRINT lpr)
{
    memset(This, 0, sizeof(PrintingCallbackHandler));
    This->callback.lpVtbl = &IPrintDialogCallback_Vtbl;
    This->site.lpVtbl = &IObjectWithSite_Vtbl;
    This->lpr_ = lpr;
}

static void
PrintingCallbackFini(PrintingCallbackHandler * This)
{
    if (This->services_ != NULL)
	This->services_->lpVtbl->Release(This->services_);
}

void *
PrintingCallbackCreate(GP_LPPRINT lpr)
{
    PrintingCallbackHandler * callback = (PrintingCallbackHandler *) malloc(sizeof(PrintingCallbackHandler));
    /* initialize COM object for the printing dialog callback */
    PrintingCallbackInit(callback, lpr);
    return callback;
}


void
PrintingCallbackFree(void * callback)
{
    PrintingCallbackFini((PrintingCallbackHandler *) callback);
    free(callback);
}


void PrintingCleanup(void)
{
    if (hDevNames) GlobalFree(hDevNames);
    if (hDevMode)  GlobalFree(hDevMode);
}


INT_PTR CALLBACK
PrintSizeDlgProc(HWND hdlg, UINT wmsg, WPARAM wparam, LPARAM lparam)
{
    TCHAR buf[8];
    HWND hPropSheetDlg = GetParent(hdlg);
    GP_LPPRINT lpr = (GP_LPPRINT) GetWindowLongPtr(hdlg, GWLP_USERDATA);

    switch (wmsg) {
    case WM_INITDIALOG:
	lpr = (GP_LPPRINT) ((PROPSHEETPAGE *) lparam)->lParam;
	SetWindowLongPtr(hdlg, GWLP_USERDATA, (LONG_PTR) lpr);
	wsprintf(buf, TEXT("%d"), lpr->pdef.x);
	SetDlgItemText(hdlg, PSIZE_DEFX, buf);
	wsprintf(buf, TEXT("%d"), lpr->pdef.y);
	SetDlgItemText(hdlg, PSIZE_DEFY, buf);
	wsprintf(buf, TEXT("%d"), lpr->poff.x);
	SetDlgItemText(hdlg, PSIZE_OFFX, buf);
	wsprintf(buf, TEXT("%d"), lpr->poff.y);
	SetDlgItemText(hdlg, PSIZE_OFFY, buf);
	wsprintf(buf, TEXT("%d"), lpr->psize.x);
	SetDlgItemText(hdlg, PSIZE_X, buf);
	wsprintf(buf, TEXT("%d"), lpr->psize.y);
	SetDlgItemText(hdlg, PSIZE_Y, buf);
	CheckDlgButton(hdlg, PSIZE_DEF, TRUE);
	EnableWindow(GetDlgItem(hdlg, PSIZE_X), FALSE);
	EnableWindow(GetDlgItem(hdlg, PSIZE_Y), FALSE);
	return TRUE;
    case WM_COMMAND:
	switch (LOWORD(wparam)) {
	case PSIZE_DEF:
	    if (HIWORD(wparam) == BN_CLICKED) {
		EnableWindow(GetDlgItem(hdlg, PSIZE_X), FALSE);
		EnableWindow(GetDlgItem(hdlg, PSIZE_Y), FALSE);
		PropSheet_Changed(hPropSheetDlg, hdlg);
	    }
	    return FALSE;
	case PSIZE_OTHER:
	    if (HIWORD(wparam) == BN_CLICKED) {
		EnableWindow(GetDlgItem(hdlg, PSIZE_X), TRUE);
		EnableWindow(GetDlgItem(hdlg, PSIZE_Y), TRUE);
		PropSheet_Changed(hPropSheetDlg, hdlg);
	    }
	    return FALSE;
	case PSIZE_X:
	case PSIZE_Y:
	case PSIZE_OFFX:
	case PSIZE_OFFY:
	    if (HIWORD(wparam) == EN_UPDATE)
		PropSheet_Changed(hPropSheetDlg, hdlg);
	    return FALSE;
	} /* switch (wparam) */
	break;
    case WM_NOTIFY:
	switch (((LPNMHDR) lparam)->code) {
	case PSN_APPLY:  /* apply changes */
	    /* FIXME: Need to check for valid input.
	    */
	    if (SendDlgItemMessage(hdlg, PSIZE_OTHER, BM_GETCHECK, 0, 0L)) {
		SendDlgItemMessage(hdlg, PSIZE_X, WM_GETTEXT, 7, (LPARAM) buf);
		GetInt(buf, (LPINT)&lpr->psize.x);
		SendDlgItemMessage(hdlg, PSIZE_Y, WM_GETTEXT, 7, (LPARAM) buf);
		GetInt(buf, (LPINT)&lpr->psize.y);
	    } else {
		lpr->psize.x = lpr->pdef.x;
		lpr->psize.y = lpr->pdef.y;
	    }
	    SendDlgItemMessage(hdlg, PSIZE_OFFX, WM_GETTEXT, 7, (LPARAM) buf);
	    GetInt(buf, (LPINT)&lpr->poff.x);
	    SendDlgItemMessage(hdlg, PSIZE_OFFY, WM_GETTEXT, 7, (LPARAM) buf);
	    GetInt(buf, (LPINT)&lpr->poff.y);

	    if (lpr->psize.x psize.x = lpr->pdef.x;
	    if (lpr->psize.y psize.y = lpr->pdef.y;

	    PropSheet_UnChanged(hPropSheetDlg, hdlg);
	    SetWindowLongPtr(hdlg, DWLP_MSGRESULT, PSNRET_NOERROR);
	    return TRUE;
	}
	case PSN_SETACTIVE: /* display: initialize according to printer */
	    if (lpr->psize.x < 0 || lpr->bDriverChanged) {
		/* FIXME: also if settings changed (paper size, orientation) */
		IPrintDialogServices * services = (IPrintDialogServices *) lpr->services;

		/* Set size to full paper size of current printer */
		if (services) {
		    LPTSTR lpPrinterName = NULL;
		    LPTSTR lpPortName = NULL;
		    LPDEVMODE lpDevMode = NULL;
		    UINT size;
		    HRESULT hr;

		    /* Note:  The Windows 8.1 SDK says that these functions expect LPWSTR
			      arguments, in contrast to the MSDN documentation, MinGW, and
			      what was actually seen in a debugger on Windows 10.
			      So warnings about type mismatch can be safely ignored.
		    */
		    size = 0;
		    hr = services->lpVtbl->GetCurrentPrinterName(services, NULL, &size);
		    if (SUCCEEDED(hr) && size > 0) {
			lpPrinterName = (LPTSTR) malloc(size * sizeof(TCHAR));
			hr = services->lpVtbl->GetCurrentPrinterName(services, lpPrinterName, &size);
		    }

		    size = 0;
		    hr = services->lpVtbl->GetCurrentPortName(services, NULL, &size);
		    if (SUCCEEDED(hr) && size > 0) {
			lpPortName = (LPTSTR) malloc(size * sizeof(TCHAR));
			hr = services->lpVtbl->GetCurrentPortName(services, lpPortName, &size);
		    }

		    size = 0;
		    hr = services->lpVtbl->GetCurrentDevMode(services, NULL, &size);
		    if (SUCCEEDED(hr) && size > 0) {
			lpDevMode = (LPDEVMODE) malloc(size * sizeof(TCHAR));
			hr = services->lpVtbl->GetCurrentDevMode(services, lpDevMode, &size);
		    }

		    if (SUCCEEDED(hr) && size > 0 && lpPortName != NULL && lpPrinterName != NULL) {
			HDC printer = CreateDC(TEXT("WINSPOOL"), lpPrinterName, lpPortName, lpDevMode);
			lpr->psize.x = GetDeviceCaps(printer, HORZSIZE);
			lpr->psize.y = GetDeviceCaps(printer, VERTSIZE);
			DeleteDC(printer);
		    }

		    free(lpPrinterName);
		    free(lpPortName);
		    free(lpDevMode);
		}
	    }
	    if (lpr->psize.x < 0) {
		/* something went wrong */
		lpr->psize.x = lpr->pdef.x;
		lpr->psize.y = lpr->pdef.y;
	    }
	    /* apply changes */
	    wsprintf(buf, TEXT("%d"), lpr->psize.x);
	    SetDlgItemText(hdlg, PSIZE_X, buf);
	    wsprintf(buf, TEXT("%d"), lpr->psize.y);
	    SetDlgItemText(hdlg, PSIZE_Y, buf);
	    lpr->bDriverChanged = FALSE;

	    SetWindowLongPtr(hdlg, DWLP_MSGRESULT, 0); /* accept activation */
	    return TRUE;
	break;
    } /* switch (msg) */
    return FALSE;
}


/* Win32 doesn't support OpenJob() etc. so we must use some old code
 * which attempts to sneak the output through a Windows printer driver */
void
PrintRegister(GP_LPPRINT lpr)
{
    GP_LPPRINT next;
    next = prlist;
    prlist = lpr;
    lpr->next = next;
}


static GP_LPPRINT
PrintFind(HDC hdc)
{
    GP_LPPRINT current;
    current = prlist;
    while (current && (current->hdcPrn != hdc)) {
	current = current->next;
    }
    return current;
}


void
PrintUnregister(GP_LPPRINT lpr)
{
    GP_LPPRINT prev = NULL;
    GP_LPPRINT current = prlist;
    while (current && (current != lpr)) {
	prev = current;
	current = current->next;
    }
    if (current && (current == lpr)) {
	/* unhook it */
	if (prev)
	    prev->next = current->next;
	else
	    prlist = current->next;
    }
}


INT_PTR CALLBACK
PrintDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    GP_LPPRINT lpr;

    lpr = (GP_LPPRINT) GetWindowLongPtr(hDlg, GWLP_USERDATA);
    switch (message) {
    case WM_INITDIALOG:
	lpr = (GP_LPPRINT) lParam;
	lpr->hDlgPrint = hDlg;
	SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR) lpr);
	SetWindowText(hDlg, lpr->szTitle);
	EnableMenuItem(GetSystemMenu(hDlg, FALSE), SC_CLOSE, MF_GRAYED);
	SetFocus(GetDlgItem(hDlg, IDCANCEL));
	return TRUE;
    case WM_COMMAND:
	lpr->bUserAbort = TRUE;
	lpr->hDlgPrint = 0;
	EnableWindow(GetParent(hDlg), TRUE);
	EndDialog(hDlg, FALSE);
	return TRUE;
    }
    return FALSE;
}


BOOL CALLBACK
PrintAbortProc(HDC hdcPrn, int code)
{
    MSG msg;
    GP_LPPRINT lpr = PrintFind(hdcPrn);
    while (!lpr->bUserAbort && PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
	if (!lpr->hDlgPrint || !IsDialogMessage(lpr->hDlgPrint, &msg)) {
	    TranslateMessage(&msg);
	    DispatchMessage(&msg);
	}
    }
    return !lpr->bUserAbort;
}


void
DumpPrinter(HWND hwnd, LPTSTR szAppName, LPTSTR szFileName)
{
    PRINTDLGEX pd;
    DEVNAMES * pDevNames;
    LPCTSTR szDevice;
    GP_PRINT pr;
    HANDLE printer;
    DOC_INFO_1 di;
    DWORD jobid;
    HRESULT hr;
    LPSTR buf;
    int count;
    FILE *f;
    long lsize;
    long ldone;
    TCHAR pcdone[10];

    if ((f = _tfopen(szFileName, TEXT("rb"))) == NULL)
	return;
    fseek(f, 0L, SEEK_END);
    lsize = ftell(f);
    if (lsize hInstance;
    pd.Flags |= PD_ENABLEPRINTTEMPLATE;

    if ((hr = PrintDlgEx(&pd)) != S_OK) {
	DWORD error = CommDlgExtendedError();
	fprintf(stderr, "\nError:  Opening the print dialog failed with error code %04x (%04x).\n", hr, error);
    }

    if (pd.dwResultAction == PD_RESULT_PRINT) {
	pDevNames = (DEVNAMES *) GlobalLock(pd.hDevNames);
	szDevice = (LPCTSTR)pDevNames + pDevNames->wDeviceOffset;
	if (!OpenPrinter((LPTSTR)szDevice, &printer, NULL))
		printer = NULL;
	GlobalUnlock(pd.hDevNames);
	/* We no longer free these structures, but preserve them for the next time
	GlobalFree(pd.hDevMode);
	GlobalFree(pd.hDevNames);
	*/
	hDevNames = pd.hDevNames;
	hDevMode = pd.hDevMode;

	if (printer == NULL)
	    return;	/* abort */

	pr.hdcPrn = printer;
	PrintRegister(&pr);
	if ((buf = (LPSTR) malloc(4096)) != NULL) {
	    EnableWindow(hwnd, FALSE);
	    pr.bUserAbort = FALSE;
	    pr.szTitle = szAppName;
	    pr.hDlgPrint = CreateDialogParam(hdllInstance, TEXT("CancelDlgBox"),
						hwnd, PrintDlgProc, (LPARAM) &pr);
	    SendMessage(GetDlgItem(pr.hDlgPrint, CANCEL_PROGRESS), PBM_SETRANGE32, 0, lsize);

	    di.pDocName = szAppName;
	    di.pOutputFile = NULL;
	    di.pDatatype = TEXT("RAW");
	    if ((jobid = StartDocPrinter(printer, 1, (LPBYTE) &di)) > 0) {
		while (pr.hDlgPrint && !pr.bUserAbort &&
		       (count = fread(buf, 1, 4096, f)) != 0 ) {
		    int ret;
		    DWORD dwBytesWritten;

		    ret = WritePrinter(printer, buf, count, &dwBytesWritten);
		    ldone += count;
		    if (dwBytesWritten > 0) {
			wsprintf(pcdone, TEXT("%d%% done"), (int)(ldone * 100 / lsize));
			SetWindowText(GetDlgItem(pr.hDlgPrint, CANCEL_PCDONE), pcdone);
			SendMessage(GetDlgItem(pr.hDlgPrint, CANCEL_PROGRESS), PBM_SETPOS, ldone, 0);
		    } else if (ret == 0) {
			SetWindowText(GetDlgItem(pr.hDlgPrint, CANCEL_PCDONE), TEXT("Error writing to printer!"));
			pr.bUserAbort  = TRUE;
		    }

		    /* handle window messages */
		    PrintAbortProc(printer, 0);
		}
		if (pr.bUserAbort) {
		    if (SetJob(printer, jobid, 0, NULL, JOB_CONTROL_DELETE) == 0) {
			SetWindowText(GetDlgItem(pr.hDlgPrint, CANCEL_PCDONE), TEXT("Error: Failed to cancel print job!"));
			fprintf(stderr, "Error: Failed to cancel print job!\n");
		    }
		}
		EndDocPrinter(printer);
		if (!pr.bUserAbort) {
		    EnableWindow(hwnd, TRUE);
		    DestroyWindow(pr.hDlgPrint);
		}
		free(buf);
	    }
	}
	ClosePrinter(printer);
	PrintUnregister(&pr);
    }
    fclose(f);
}

Web Proxy Viewer  |  New URL  |  Original Page