redmon.c

来自「虚拟打印端口」· C语言 代码 · 共 2,160 行 · 第 1/5 页

C
2,160
字号
/* Copyright (C) 1997-2001, Ghostgum Software Pty Ltd.  All rights reserved.
  
  This file is part of RedMon.
  
  This program is distributed with NO WARRANTY OF ANY KIND.  No author
  or distributor accepts any responsibility for the consequences of using it,
  or for whether it serves any particular purpose or works at all, unless he
  or she says so in writing.  Refer to the RedMon Free Public Licence 
  (the "Licence") for full details.
  
  Every copy of RedMon must include a copy of the Licence, normally in a 
  plain ASCII text file named LICENCE.  The Licence grants you the right 
  to copy, modify and redistribute RedMon, but only under certain conditions 
  described in the Licence.  Among other things, the Licence requires that 
  the copyright notice and this notice be preserved on all copies.
*/

/* redmon.c */

/*
 * This is the redirection part of the RedMon port monitor.
 * 
 * This is a Port Monitor for 
 *   Windows 95, 98
 *   Windows NT 3.5
 *   Windows NT 4.0
 *   Windows NT 5.0 (Windows 2000 Professional) - needs more testing
 *
 * The monitor name is "Redirected Port" .
 * A write to any port provided by this monitor will be
 * redirected to a program using a pipe to stdin.
 *
 * An example is redirecting the output from the 
 * PostScript printer driver to Ghostscript, which then
 * writes to a non-PostScript printer.
 *
 * For efficiency reasons, don't use the C run time library. 
 *
 * The Windows NT version must use Unicode, so Windows NT
 * specific code is conditionally compiled with a combination
 * of UNICODE, NT35, NT40 and NT50.
 */

/* Publicly accessibly functions in this Port Monitor are prefixed with
 * the following:
 *   rXXX   Windows 95 / NT3.51 / NT4
 *   rsXXX  Windows NT5 port monitor server
 *   rcXXX  Windows NT5 port monitor client (UI)
 */

#define STRICT
#include <windows.h>
#include "portmon.h"
#include "redmon.h"
#ifdef BETA
#include <time.h>
#endif

/* to write a log file for debugging RedMon, uncomment the following line */
/*
#define DEBUG_REDMON
*/

/* Constant globals */
const TCHAR copyright[] = COPYRIGHT;
const TCHAR version[] = VERSION;

/* port configuration */
#define COMMANDKEY TEXT("Command")
#define ARGKEY TEXT("Arguments")
#define PRINTERKEY TEXT("Printer")
#define OUTPUTKEY TEXT("Output")
#define SHOWKEY TEXT("ShowWindow")
#define RUNUSERKEY TEXT("RunUser")
#define DELAYKEY TEXT("Delay")
#define LOGUSEKEY TEXT("LogFileUse")
#define LOGNAMEKEY TEXT("LogFileName")
#define LOGDEBUGKEY TEXT("LogFileDebug")
#define PRINTERRORKEY TEXT("PrintError")
#define LASTUSERKEY TEXT("LastUser")
#define LASTFILEKEY TEXT("LastFile")
#define REDMONUSERKEY TEXT("Software\\Ghostgum\\RedMon")
typedef struct reconfig_s {
    DWORD dwSize;	/* sizeof this structure */
    DWORD dwVersion;	/* version number of RedMon */
    TCHAR szPortName[MAXSTR];
    TCHAR szDescription[MAXSTR];
    TCHAR szCommand[MAXSTR];
    TCHAR szArguments[MAXSTR];
    TCHAR szPrinter[MAXSTR];
    DWORD dwOutput;
    DWORD dwShow;
    DWORD dwRunUser;
    DWORD dwDelay;
    DWORD dwLogFileUse;
    TCHAR szLogFileName[MAXSTR];
    DWORD dwLogFileDebug;
    DWORD dwPrintError;
};

struct redata_s {
    /* Members required by all RedMon implementations */
    HANDLE hPort;		/* handle to this structure */
    HANDLE hMonitor;		/* provided by NT5.0 OpenPort */
    RECONFIG config;		/* configuration stored in registry */
    TCHAR portname[MAXSHORTSTR];    /* Name obtained during OpenPort  */

    /* Details obtained during StartDocPort  */
    TCHAR command[1024];
    TCHAR pPrinterName[MAXSTR];	/* Printer name for RedMon port */
    TCHAR pDocName[MAXSTR];	/* Document Name (from StartDocPort) */
    DWORD JobId;
    TCHAR pUserName[MAXSTR];	/* User Name (from StartDocPort job info) */
    TCHAR pMachineName[MAXSTR];	/* Machine Name (from StartDocPort job info) */

    /* For running process */
    BOOL started;		/* true if process started */
    BOOL error;			/* true if process terminates early */
    HGLOBAL environment;	/* environment strings for process */
    HANDLE hChildStdinRd;
    HANDLE hChildStdinWr;	/* We write to this one */
    HANDLE hChildStdoutRd; 	/* We read from this one */
    HANDLE hChildStdoutWr;
    HANDLE hChildStderrRd; 	/* We read from this one */
    HANDLE hChildStderrWr;
#ifdef SAVESTD
    HANDLE hSaveStdin;
    HANDLE hSaveStdout;
    HANDLE hSaveStderr;
#endif
    HANDLE hPipeRd; 	/* We read printer output from this one */
    HANDLE hPipeWr;
    PROCESS_INFORMATION piProcInfo;
    /*  */
#ifdef OLD
    TCHAR logname[MAXSTR];
#endif
    HANDLE hLogFile;
    HANDLE hmutex;	/* To control access to pipe and file handles */
    HANDLE primary_token;  	/* primary token for caller */
    TCHAR pSessionId[MAXSTR];	/* session-id for WTS support */

    /* for write thread */
    HANDLE write_event;	/* To unblock write thread */
    BOOL write;		/* TRUE if write thread should keep running */
    HANDLE write_hthread;
    DWORD write_threadid;
    LPBYTE write_buffer;	/* data to write */
    DWORD write_buffer_length;	/* number of bytes of data to write */
    BOOL write_flag;		/* TRUE if WriteFile was successful */
    DWORD write_written;	/* number of bytes written */

    /* for output to second printer queue */
    TCHAR tempname[MAXSTR];	/* temporary file name  */
    HANDLE printer;		/* handle to a printer */ 
    DWORD printer_bytes;
    BYTE pipe_buf[PIPE_BUF_SIZE]; /* buffer for use in flush_stdout */
};

void write_error(REDATA *prd, DWORD err);
void write_string_to_log(REDATA *prd, LPCTSTR buf);
void redmon_cancel_job(REDATA *prd);
BOOL start_redirect(REDATA * prd);
void reset_redata(REDATA *prd);
BOOL check_process(REDATA *prd);
UINT APIENTRY GetSaveHookProc(HWND hDlg, UINT message, 
	WPARAM wParam, LPARAM lParam);
BOOL CALLBACK LogfileDlgProc(HWND hDlg, UINT message, 
	WPARAM wParam, LPARAM lParam);
int create_tempfile(LPTSTR filename, DWORD len);
int redmon_printfile(REDATA * prd, TCHAR *filename);
BOOL redmon_open_printer(REDATA *prd);
BOOL redmon_abort_printer(REDATA *prd);
BOOL redmon_close_printer(REDATA *prd);
BOOL redmon_write_printer(REDATA *prd, BYTE *ptr, DWORD len);
BOOL get_job_info(REDATA *prd);
BOOL make_env(REDATA * prd);
BOOL query_session_id(REDATA * prd);
BOOL get_filename_as_user(REDATA * prd);
BOOL redmon_print_error(REDATA *prd);

/* we don't rely on the import library having XcvData,
 * since we may be compiling with VC++ 5.0 */
BOOL WINAPI XcvData(HANDLE hXcv, LPCWSTR pszDataName, 
    PBYTE pInputData, DWORD cbInputData, 
    PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded,
    PDWORD pdwStatus);


#define PORTSNAME TEXT("Ports")
#define BACKSLASH TEXT("\\")
#define DEFAULT_DELAY 300   /* seconds */
#define MINIMUM_DELAY 15
#define PRINT_BUF_SIZE 16384

/* environment variables set for the program */
#define REDMON_PORT     TEXT("REDMON_PORT=")
#define REDMON_JOB      TEXT("REDMON_JOB=")
#define REDMON_PRINTER  TEXT("REDMON_PRINTER=")
#define REDMON_MACHINE  TEXT("REDMON_MACHINE=")
#define REDMON_USER     TEXT("REDMON_USER=")
#define REDMON_DOCNAME  TEXT("REDMON_DOCNAME=")
#define REDMON_FILENAME  TEXT("REDMON_FILENAME=")
#define REDMON_SESSIONID  TEXT("REDMON_SESSIONID=")
#define REDMON_TEMP     TEXT("TEMP=")
#define REDMON_TMP      TEXT("TMP=")



/* mutex used for controlling access to log file and pipe handles */
void
request_mutex(REDATA *prd)
{
    if ((prd->hmutex != NULL) && (prd->hmutex != INVALID_HANDLE_VALUE))
        WaitForSingleObject(prd->hmutex, 30000);
}

void
release_mutex(REDATA *prd)
{
    if ((prd->hmutex != NULL) && (prd->hmutex != INVALID_HANDLE_VALUE))
	ReleaseMutex(prd->hmutex);
}


#ifdef BETA
int
beta_expired(void)
{
  time_t today = time(NULL);
  struct tm *t;
  t = localtime(&today);
  if (t->tm_year+1900 < BETA_YEAR)
    return 0;
  if (t->tm_year+1900 > BETA_YEAR)
    return 1;    /* beta copy has expired */
  if (t->tm_mon+1 < BETA_MONTH)
    return 0;
  if (t->tm_mon+1 > BETA_MONTH)
    return 1;    /* beta copy has expired */
  if (t->tm_mday < BETA_DAY)
    return 0;
  return 1;    /* beta copy has expired */
}

int beta(void)
{
  if (beta_expired()) {
    TCHAR buf[MAXSTR];
    TCHAR title[MAXSTR];
    LoadString(hdll, IDS_BETAEXPIRED, buf, sizeof(buf)/sizeof(TCHAR)-1);
    LoadString(hdll, IDS_TITLE, title, sizeof(title)/sizeof(TCHAR)-1);
    MessageBox(HWND_DESKTOP, buf, title, MB_OK | MB_ICONHAND);
    return 1;
  }
  return 0;
}
#endif /* BETA */

/* The log file is single byte characters only */
/* Write a single character or wide character string to the log file,
 * converting it to single byte characters */
void write_string_to_log(REDATA *prd, LPCTSTR buf)
{
DWORD cbWritten;
#ifdef UNICODE
int count;
CHAR cbuf[256];
BOOL UsedDefaultChar;
#endif
    if (prd->hLogFile == INVALID_HANDLE_VALUE)
	return;

    request_mutex(prd);
#ifdef UNICODE
    while (lstrlen(buf)) {
	count = min(lstrlen(buf), sizeof(cbuf));
	WideCharToMultiByte(CP_ACP, 0, buf, count,
		cbuf, sizeof(cbuf), NULL, &UsedDefaultChar);
	buf += count;
	WriteFile(prd->hLogFile, cbuf, count, &cbWritten, NULL);
    }
#else
    WriteFile(prd->hLogFile, buf, lstrlen(buf), &cbWritten, NULL);
#endif
    FlushFileBuffers(prd->hLogFile);
    release_mutex(prd);
}

void
write_error(REDATA *prd, DWORD err)
{
LPVOID lpMessageBuffer;
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
	FORMAT_MESSAGE_FROM_SYSTEM,
	NULL, err,
	MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* user default language */
	(LPTSTR) &lpMessageBuffer, 0, NULL);
    if (lpMessageBuffer) {
	write_string_to_log(prd, (LPTSTR)lpMessageBuffer);
	LocalFree(LocalHandle(lpMessageBuffer));
	write_string_to_log(prd, TEXT("\r\n"));
    }
}

DWORD
redmon_sizeof_config(void)
{
    return sizeof(RECONFIG);
}

BOOL redmon_validate_config(RECONFIG *config)
{
    if (config == NULL)
	return FALSE;
    if (config->dwSize != sizeof(RECONFIG))
	return FALSE;
    if (config->dwVersion != VERSION_NUMBER)
	return FALSE;
    return TRUE;
}

LPTSTR redmon_init_config(RECONFIG *config)
{
    memset(config, 0, sizeof(RECONFIG));
    config->dwSize = sizeof(RECONFIG);
    config->dwVersion = VERSION_NUMBER;
    config->dwOutput = OUTPUT_SELF;
    config->dwShow = FALSE;
    config->dwRunUser = FALSE;
    config->dwDelay = DEFAULT_DELAY;
#ifdef BETA
    config->dwLogFileDebug = TRUE;  /* beta versions default to debug enabled */
#else
    config->dwLogFileDebug = FALSE;
#endif
    LoadString(hdll, IDS_MONITORNAME, config->szDescription, 
	sizeof(config->szDescription)/sizeof(TCHAR)-1);
    return config->szPortName;
}

/* read the configuration from the registry */
BOOL redmon_get_config(HANDLE hMonitor, LPCTSTR portname, RECONFIG *config)
{
    LONG rc = ERROR_SUCCESS;
    HANDLE hkey;
    TCHAR buf[MAXSTR];
    DWORD cbData;
    DWORD dwType;
#ifdef DEBUG_REDMON
    syslog(TEXT("redmon_get_config "));
    syslog(portname);
    syslog(TEXT("\r\n"));
    syslog(TEXT("  hMonitor="));
    syshex((DWORD)hMonitor);
    syslog(TEXT("\r\n"));
#endif
    redmon_init_config(config);
    lstrcpyn(config->szPortName, portname, sizeof(config->szPortName)-1);

    lstrcpy(buf, PORTSNAME);
    lstrcat(buf, BACKSLASH);
    lstrcat(buf, portname);
    rc = RedMonOpenKey(hMonitor, buf, KEY_READ, &hkey);
    if (rc != ERROR_SUCCESS) {
#ifdef DEBUG_REDMON
	syslog(TEXT("Failed to open registry key "));
	syslog(buf);
	syslog(TEXT("\r\n"));
#endif
	return FALSE;
    }

    cbData = sizeof(config->szDescription)-sizeof(TCHAR);
    rc = RedMonQueryValue(hMonitor, hkey, DESCKEY, &dwType, 
	(PBYTE)(config->szDescription), &cbData);
    cbData = sizeof(config->szCommand)-sizeof(TCHAR);
    rc = RedMonQueryValue(hMonitor, hkey, COMMANDKEY, &dwType, 
	(PBYTE)(config->szCommand), &cbData);
    cbData = sizeof(config->szArguments)-sizeof(TCHAR);
    rc = RedMonQueryValue(hMonitor, hkey, ARGKEY, &dwType, 
	(PBYTE)(config->szArguments), &cbData);
    cbData = sizeof(config->szPrinter)-sizeof(TCHAR);
    rc = RedMonQueryValue(hMonitor, hkey, PRINTERKEY, &dwType, 
	(PBYTE)(config->szPrinter), &cbData);
    cbData = sizeof(config->dwOutput);
    rc = RedMonQueryValue(hMonitor, hkey, OUTPUTKEY, &dwType, 
	(PBYTE)(&config->dwOutput), &cbData);
    if (config->dwOutput > OUTPUT_LAST)
	config->dwOutput = OUTPUT_SELF;
    cbData = sizeof(config->dwShow);
    rc = RedMonQueryValue(hMonitor, hkey, SHOWKEY, &dwType, 
	(PBYTE)(&config->dwShow), &cbData);
    cbData = sizeof(config->dwRunUser);
    rc = RedMonQueryValue(hMonitor, hkey, RUNUSERKEY, &dwType, 
	(PBYTE)(&config->dwRunUser), &cbData);
    cbData = sizeof(config->dwDelay);
    rc = RedMonQueryValue(hMonitor, hkey, DELAYKEY, &dwType, 
	(PBYTE)(&config->dwDelay), &cbData);
    cbData = sizeof(config->dwLogFileUse);
    rc = RedMonQueryValue(hMonitor, hkey, LOGUSEKEY, &dwType, 
	(PBYTE)(&config->dwLogFileUse), &cbData);
    cbData = sizeof(config->szLogFileName)-sizeof(TCHAR);
    rc = RedMonQueryValue(hMonitor, hkey, LOGNAMEKEY, &dwType, 
	(PBYTE)(config->szLogFileName), &cbData);
    cbData = sizeof(config->dwLogFileDebug);
    rc = RedMonQueryValue(hMonitor, hkey, LOGDEBUGKEY, &dwType, 
	(PBYTE)(&config->dwLogFileDebug), &cbData);
    cbData = sizeof(config->dwPrintError);
    rc = RedMonQueryValue(hMonitor, hkey, PRINTERRORKEY, &dwType, 
	(PBYTE)(&config->dwPrintError), &cbData);
    RedMonCloseKey(hMonitor, hkey);
    return TRUE;
}


/* write the configuration to the registry */
BOOL redmon_set_config(HANDLE hMonitor, RECONFIG *config)
{
    LONG rc = ERROR_SUCCESS;
    HANDLE hkey;
    TCHAR buf[MAXSTR];

    if (!redmon_validate_config(config))
	return FALSE;

    lstrcpy(buf, PORTSNAME);
    lstrcat(buf, BACKSLASH);
    lstrcat(buf, config->szPortName);
    rc = RedMonOpenKey(hMonitor, buf, KEY_WRITE, &hkey);
    if (rc != ERROR_SUCCESS)
	return FALSE;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?