350 lines
8.7 KiB
C
350 lines
8.7 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1990 - 1995 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
msgbox.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module provides all the public exported APIs relating to Printer
|
||
|
management for the Local Print Providor
|
||
|
|
||
|
LocalAddPrinterConnection
|
||
|
LocalDeletePrinterConnection
|
||
|
LocalPrinterMessageBox
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Dave Snipp (DaveSn) 15-Mar-1991
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
#define NOMINMAX
|
||
|
|
||
|
#include <precomp.h>
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
LocalAddPrinterConnection(
|
||
|
LPWSTR pName
|
||
|
)
|
||
|
{
|
||
|
SetLastError(ERROR_INVALID_NAME);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
LocalDeletePrinterConnection(
|
||
|
LPWSTR pName
|
||
|
)
|
||
|
{
|
||
|
SetLastError(ERROR_INVALID_NAME);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
LocalPrinterMessageBox(
|
||
|
HANDLE hPrinter,
|
||
|
DWORD Error,
|
||
|
HWND hWnd,
|
||
|
LPWSTR pText,
|
||
|
LPWSTR pCaption,
|
||
|
DWORD dwType
|
||
|
)
|
||
|
{
|
||
|
PSPOOL pSpool = (PSPOOL)hPrinter;
|
||
|
|
||
|
if (!pSpool ||
|
||
|
pSpool->signature != SJ_SIGNATURE) {
|
||
|
SetLastError(ERROR_INVALID_HANDLE);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return MyMessageBox(hWnd, pSpool, Error, pText, pCaption, dwType, FALSE);
|
||
|
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
MyMessageBox(
|
||
|
HWND hWnd,
|
||
|
PSPOOL pSpool,
|
||
|
DWORD Error,
|
||
|
LPWSTR pText,
|
||
|
LPWSTR pCaption,
|
||
|
DWORD dwType,
|
||
|
BOOL bInternal
|
||
|
)
|
||
|
{
|
||
|
PINIJOB pIniJob = NULL;
|
||
|
LPWSTR pErrorString, pDocumentName;
|
||
|
HANDLE hToken;
|
||
|
WCHAR szUnnamed[80];
|
||
|
DWORD dwJobStatus;
|
||
|
|
||
|
if (pSpool->pIniJob)
|
||
|
pIniJob = pSpool->pIniJob;
|
||
|
else if (pSpool->pIniPort)
|
||
|
pIniJob = pSpool->pIniPort->pIniJob;
|
||
|
|
||
|
if (pIniJob) {
|
||
|
|
||
|
EnterSplSem();
|
||
|
|
||
|
dwJobStatus = pIniJob->Status;
|
||
|
|
||
|
switch (Error) {
|
||
|
case ERROR_OUT_OF_PAPER:
|
||
|
|
||
|
pIniJob->Status |= JOB_PAPEROUT;
|
||
|
pIniJob->pIniPrinter->cErrorOutOfPaper++;
|
||
|
break;
|
||
|
|
||
|
case ERROR_NOT_READY:
|
||
|
|
||
|
pIniJob->Status |= JOB_OFFLINE;
|
||
|
pIniJob->pIniPrinter->cErrorNotReady++;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
pIniJob->Status |= JOB_ERROR;
|
||
|
pIniJob->pIniPrinter->cJobError++;
|
||
|
pIniJob->pIniPrinter->dwLastError = Error;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if( dwJobStatus != pIniJob->Status ){
|
||
|
|
||
|
SetPrinterChange(pIniJob->pIniPrinter,
|
||
|
pIniJob,
|
||
|
NVJobStatus,
|
||
|
PRINTER_CHANGE_SET_JOB,
|
||
|
pIniJob->pIniPrinter->pIniSpooler );
|
||
|
}
|
||
|
|
||
|
LeaveSplSem();
|
||
|
|
||
|
if (pIniJob->Status & JOB_REMOTE && dwEnableNetPopups) {
|
||
|
|
||
|
if (!(pIniJob->Status & JOB_NOTIFICATION_SENT)) {
|
||
|
SendJobAlert(pIniJob);
|
||
|
pIniJob->Status |= JOB_NOTIFICATION_SENT;
|
||
|
}
|
||
|
MyMessageBeep(MB_ICONEXCLAMATION);
|
||
|
|
||
|
if( !bInternal ) {
|
||
|
|
||
|
Sleep(10000);
|
||
|
Error = IDOK;
|
||
|
return Error;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pText) {
|
||
|
|
||
|
Error = MessageBox(hWnd, pText, pCaption, dwType);
|
||
|
|
||
|
} else if (pErrorString = GetErrorString(Error)) {
|
||
|
|
||
|
hToken = RevertToPrinterSelf();
|
||
|
|
||
|
pDocumentName = pIniJob->pDocument;
|
||
|
|
||
|
if (!pDocumentName) {
|
||
|
*szUnnamed = L'\0';
|
||
|
LoadString( hInst, IDS_UNNAMED, szUnnamed,
|
||
|
sizeof szUnnamed / sizeof *szUnnamed );
|
||
|
pDocumentName = szUnnamed;
|
||
|
}
|
||
|
|
||
|
if (pSpool->pIniPort) {
|
||
|
|
||
|
Error = Message(NULL,
|
||
|
MB_ICONSTOP | MB_RETRYCANCEL | MB_SETFOREGROUND,
|
||
|
IDS_LOCALSPOOLER,
|
||
|
IDS_ERROR_WRITING_TO_PORT,
|
||
|
pSpool->pIniPort->pName,
|
||
|
pDocumentName,
|
||
|
pErrorString);
|
||
|
} else {
|
||
|
|
||
|
Error = Message(NULL,
|
||
|
MB_ICONSTOP | MB_RETRYCANCEL | MB_SETFOREGROUND,
|
||
|
IDS_LOCALSPOOLER,
|
||
|
IDS_ERROR_WRITING_TO_DISK,
|
||
|
pDocumentName,
|
||
|
pErrorString);
|
||
|
}
|
||
|
|
||
|
ImpersonatePrinterClient(hToken);
|
||
|
FreeSplStr(pErrorString);
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
PWCHAR pPrinterName;
|
||
|
|
||
|
//
|
||
|
// There is no pIniJob or pIniPort, so we can't be very informative:
|
||
|
//
|
||
|
if (pErrorString = GetErrorString(Error)) {
|
||
|
|
||
|
if (pSpool->pIniPrinter)
|
||
|
pPrinterName = pSpool->pIniPrinter->pName;
|
||
|
|
||
|
if (!pPrinterName) {
|
||
|
|
||
|
*szUnnamed = L'\0';
|
||
|
LoadString( hInst, IDS_UNNAMED, szUnnamed,
|
||
|
COUNTOF( szUnnamed ));
|
||
|
pPrinterName = szUnnamed;
|
||
|
}
|
||
|
|
||
|
Error = Message(NULL,
|
||
|
MB_ICONSTOP | MB_RETRYCANCEL | MB_SETFOREGROUND,
|
||
|
IDS_LOCALSPOOLER,
|
||
|
IDS_ERROR_WRITING_GENERAL,
|
||
|
pSpool->pIniPrinter->pName,
|
||
|
pErrorString);
|
||
|
|
||
|
FreeSplStr(pErrorString);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Error == IDCANCEL) {
|
||
|
EnterSplSem();
|
||
|
pSpool->Status |= SPOOL_STATUS_CANCELLED;
|
||
|
if (pIniJob)
|
||
|
pIniJob->Status |= JOB_PENDING_DELETION;
|
||
|
LeaveSplSem();
|
||
|
SplOutSem();
|
||
|
SetLastError(ERROR_PRINT_CANCELLED);
|
||
|
|
||
|
}
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Exclusively for use of the following routines. This is done so we would not have
|
||
|
// to store LastError in PSPOOL.
|
||
|
typedef struct _AUTORETRYTHDINFO {
|
||
|
PSPOOL pSpool;
|
||
|
DWORD LastError;
|
||
|
} AUTORETRYTHDINFO;
|
||
|
typedef AUTORETRYTHDINFO *PAUTORETRYTHDINFO;
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------------
|
||
|
// SpoolerBMThread
|
||
|
//
|
||
|
// Thread start up routine for the spooler error message box thread. Exit
|
||
|
// code is the return ID from MessageBox.
|
||
|
//
|
||
|
// ------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
SpoolerMBThread(
|
||
|
PAUTORETRYTHDINFO pThdInfo
|
||
|
)
|
||
|
{
|
||
|
DWORD rc;
|
||
|
|
||
|
rc = MyMessageBox( NULL, pThdInfo->pSpool, pThdInfo->LastError, NULL, NULL, 0, TRUE );
|
||
|
|
||
|
FreeSplMem( pThdInfo );
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
|
||
|
#define _ONE_SECOND 1000 // in milliseconds
|
||
|
#define SPOOL_WRITE_RETRY_INTERVAL_IN_SECOND 5 // seconds
|
||
|
|
||
|
// ------------------------------------------------------------------------
|
||
|
// PromptWriteError
|
||
|
//
|
||
|
// we'll start a seperate thread to bring up
|
||
|
// the message box while we'll (secretly) automatically retry on this
|
||
|
// current thread, until user has chosen to retry or cancel. Call the error UI
|
||
|
// on the main thread if printing direct.
|
||
|
//
|
||
|
// ------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
PromptWriteError(
|
||
|
PSPOOL pSpool,
|
||
|
PHANDLE phThread,
|
||
|
PDWORD pdwThreadId
|
||
|
|
||
|
)
|
||
|
{
|
||
|
DWORD Error = GetLastError();
|
||
|
DWORD dwExitCode;
|
||
|
DWORD dwWaitCount = 0;
|
||
|
|
||
|
|
||
|
SplOutSem();
|
||
|
|
||
|
// start a seperate thread to display the message box
|
||
|
// so we can continue to retry here
|
||
|
// or simply sleep for 5 seconds if we have already done so
|
||
|
|
||
|
if( !*phThread ) {
|
||
|
|
||
|
// start a thread to bring up the message box
|
||
|
|
||
|
PAUTORETRYTHDINFO pThdInfo;
|
||
|
|
||
|
pThdInfo = (PAUTORETRYTHDINFO)AllocSplMem( sizeof(AUTORETRYTHDINFO));
|
||
|
|
||
|
if ( pThdInfo == NULL ) {
|
||
|
DBGMSG( DBG_WARNING, ("PromptWriteError failed to allocate AUTORETRYTHDINFO %d\n", GetLastError() ));
|
||
|
goto _DoItOnCurrentThread;
|
||
|
}
|
||
|
|
||
|
pThdInfo->pSpool = pSpool;
|
||
|
pThdInfo->LastError = Error;
|
||
|
|
||
|
if (!(*phThread = CreateThread(NULL, 8*1024,
|
||
|
(LPTHREAD_START_ROUTINE)SpoolerMBThread,
|
||
|
pThdInfo, 0, pdwThreadId))) {
|
||
|
|
||
|
DBGMSG(DBG_WARNING, ("PromptWriteError: CreateThread Failed.\n"));
|
||
|
FreeSplMem( pThdInfo );
|
||
|
goto _DoItOnCurrentThread;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while (1) {
|
||
|
|
||
|
// we've already started a MB thread, check if user has terminated
|
||
|
// the message box
|
||
|
|
||
|
if (GetExitCodeThread( *phThread, &dwExitCode) && (dwExitCode != STILL_ACTIVE)) {
|
||
|
|
||
|
// if the thread has been terminated, find out the exit code
|
||
|
// which is the return ID from MessageBox, then close the
|
||
|
// thread handle.
|
||
|
|
||
|
CloseHandle( *phThread );
|
||
|
*phThread = 0;
|
||
|
return dwExitCode;
|
||
|
}
|
||
|
|
||
|
if (dwWaitCount++ >= SPOOL_WRITE_RETRY_INTERVAL_IN_SECOND)
|
||
|
break;
|
||
|
|
||
|
Sleep(_ONE_SECOND);
|
||
|
}
|
||
|
|
||
|
return IDRETRY;
|
||
|
|
||
|
|
||
|
_DoItOnCurrentThread:
|
||
|
return MyMessageBox(NULL, pSpool, Error, NULL, NULL, 0, TRUE );
|
||
|
|
||
|
}
|