portmon.c

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

C
2,232
字号
/* 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.
*/

/* portmon.c */

/*
 * 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
 *
 * This file contains the general port monitor code
 * but not the code that actually does the useful work.
 *
 * 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.5 / NT4
 *   rsXXX  Windows NT5 port monitor server
 *   rcXXX  Windows NT5 port monitor client (UI)
 */

#define STRICT
#include <windows.h>
#include "portmon.h"
#include "portrc.h"

/* These are our only global variables */
TCHAR rekey[MAXSTR];   /* Registry key name for our use */
HINSTANCE hdll;
#ifdef UNICODE
int ntver;	/* 351, 400, 500 */
#endif

/* REDATA must be defined */


/* 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("\\")


/*
 * Required functions for a 95/NT3.51/NT4 Port Monitor are:
 *   AddPort
 *   AddPortEx              (NT only)
 *   ClosePort
 *   ConfigurePort
 *   DeletePort
 *   EndDocPort
 *   EnumPorts
 *   GetPrinterDataFromPort
 *   InitializeMonitor        (NT 3.51 only)
 *   InitializeMonitorEx      (95 only)
 *   InitializePrintMonitor   (NT 4.0 only)
 *   InitializePrintMonitor2  (NT 5.0 only)
 *   InitializePrintMonitorUI (NT 5.0 only)
 *   OpenPort
 *   ReadPort
 *   SetPortOpenTimeouts
 *   StartDocPort
 *   WritePort
 */


#ifdef DEBUG_REDMON
void
syslog(LPCTSTR buf)
{
#ifdef UNICODE
    int count;
    CHAR cbuf[1024];
    int UsedDefaultChar;
#endif
    DWORD cbWritten;
    HANDLE hfile;
    if (buf == NULL)
	buf = TEXT("(null)");

    if ((hfile = CreateFileA("c:\\redmon.log", GENERIC_WRITE, 
	0 /* no file sharing */, NULL, OPEN_ALWAYS, 0, NULL)) 
		!= INVALID_HANDLE_VALUE) {
	SetFilePointer(hfile, 0, NULL, FILE_END);
#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(hfile, cbuf, count, &cbWritten, NULL);
	}
#else
	WriteFile(hfile, buf, lstrlen(buf), &cbWritten, NULL);
#endif
	CloseHandle(hfile);
    }
}

void
syserror(DWORD err)
{
LPVOID lpMessageBuffer;
TCHAR buf[MAXSTR];
    wsprintf(buf, TEXT(" error=%d\r\n"), err);
    syslog(buf);
    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) {
	syslog((LPTSTR)lpMessageBuffer);
	syslog(TEXT("\r\n"));
	LocalFree(LocalHandle(lpMessageBuffer));
    }
}

void syshex(DWORD num)
{
TCHAR buf[MAXSTR];
    wsprintf(buf, TEXT("0x%x"), num);
    syslog(buf);
}

void sysnum(DWORD num)
{
TCHAR buf[MAXSTR];
    wsprintf(buf, TEXT("%d"), num);
    syslog(buf);
}
#endif


void
show_help(HWND hwnd, int id)
{
    TCHAR buf[MAXSTR];
    TCHAR helpfile[MAXSTR];
    TCHAR *p;

    /* get help file name */
    GetModuleFileName(hdll, helpfile, sizeof(helpfile)/sizeof(TCHAR));
    p = helpfile + lstrlen(helpfile) - 1;
    while (p >= helpfile) {
	if (*p == '\\') {
	    p++;
	    break;
        }
	p--;
    }
    LoadString(hdll, IDS_HELPFILE, p, 
	sizeof(helpfile)/sizeof(TCHAR) - (int)(p-helpfile));

    /* get topic name */
    LoadString(hdll, id, buf, sizeof(buf)/sizeof(TCHAR) - 1);

    /* show help */
    WinHelp(hwnd, helpfile, HELP_KEY, (DWORD)buf);
}

LONG
RedMonOpenKey(HANDLE hMonitor, LPCTSTR pszSubKey, REGSAM samDesired,
	PHANDLE phkResult)
{
    LONG rc = ERROR_SUCCESS;
#ifdef DEBUG_REDMON
    syslog(TEXT("RedMonOpenKey "));
    syslog(pszSubKey);
    syslog(TEXT("\r\n"));
#endif
#ifdef NT50
    if (hMonitor) {
	/* NT50 */
	MONITORINIT *pMonitorInit = (MONITORINIT *)hMonitor;
	rc = pMonitorInit->pMonitorReg->fpOpenKey(
		pMonitorInit->hckRegistryRoot,
		pszSubKey,
		samDesired,
		phkResult,
		pMonitorInit->hSpooler);
    }
    else 
#endif
    {
	TCHAR buf[MAXSTR];
	lstrcpy(buf, rekey);
	if (pszSubKey) {
	    lstrcat(buf, BACKSLASH);
	    lstrcat(buf, pszSubKey);
	}
        rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf, 0, samDesired, 
		(PHKEY)phkResult);
    }
#ifdef DEBUG_REDMON
    if (rc)
	syserror(rc);
#endif
    return rc;
}

LONG
RedMonCloseKey(HANDLE hMonitor, HANDLE hcKey)
{
    LONG rc = ERROR_SUCCESS;
#ifdef DEBUG_REDMON
    syslog(TEXT("RedMonCloseKey\r\n"));
#endif
#ifdef NT50
    if (hMonitor) {
	/* NT50 */
	MONITORINIT *pMonitorInit = (MONITORINIT *)hMonitor;
	rc = pMonitorInit->pMonitorReg->fpCloseKey(
		hcKey, pMonitorInit->hSpooler);
    }
    else 
#endif
    {
	rc = RegCloseKey(hcKey);
    }
#ifdef DEBUG_REDMON
    if (rc)
	syserror(rc);
#endif
    return rc;
}

LONG
RedMonEnumKey(HANDLE hMonitor, HANDLE hcKey, DWORD dwIndex, LPTSTR pszName,
	PDWORD pcchName)
{
    LONG rc = ERROR_SUCCESS;
#ifdef DEBUG_REDMON
    syslog(TEXT("RedMonEnumKey "));
    sysnum(dwIndex);
    syslog(TEXT("\r\n"));
#endif
#ifdef NT50
    if (hMonitor) {
	/* NT50 */
	MONITORINIT *pMonitorInit = (MONITORINIT *)hMonitor;
	FILETIME ft;
	rc = pMonitorInit->pMonitorReg->fpEnumKey(
		hcKey, dwIndex, pszName, pcchName,
		&ft, pMonitorInit->hSpooler);
    }
    else 
#endif
    {
	rc = RegEnumKey(hcKey, dwIndex, pszName, *pcchName);
    }
#ifdef DEBUG_REDMON
    if (rc)
	syserror(rc);
    else {
	syslog(TEXT(" key="));
	syslog(pszName);
	syslog(TEXT("\r\n"));
    }
#endif
    return rc;
}

LONG
RedMonCreateKey(HANDLE hMonitor, HANDLE hcKey, LPCTSTR pszSubKey, 
    DWORD dwOptions, REGSAM samDesired, 
    PSECURITY_ATTRIBUTES pSecurityAttributes, 
    PHANDLE phckResult, PDWORD pdwDisposition)
{
    LONG rc = ERROR_SUCCESS;
#ifdef DEBUG_REDMON
    syslog(TEXT("RedMonCreateKey "));
    syslog(pszSubKey);
    syslog(TEXT("\r\n"));
#endif
#ifdef NT50
    if (hMonitor) {
	/* NT50 */
	MONITORINIT *pMonitorInit = (MONITORINIT *)hMonitor;
	rc = pMonitorInit->pMonitorReg->fpCreateKey(
		hcKey, pszSubKey, dwOptions,
		samDesired, pSecurityAttributes, phckResult,
		pdwDisposition, pMonitorInit->hSpooler);
    }
    else 
#endif
    {
	rc = RegCreateKeyEx(hcKey, pszSubKey, 0, 0, dwOptions,
		samDesired, pSecurityAttributes, (PHKEY)phckResult,
		pdwDisposition);
    }
#ifdef DEBUG_REDMON
    if (rc)
	syserror(rc);
#endif
    return rc;
}

LONG
RedMonDeleteKey(HANDLE hMonitor, HANDLE hcKey, LPCTSTR pszSubKey)
{
    LONG rc = ERROR_SUCCESS;
#ifdef DEBUG_REDMON
    syslog(TEXT("RedMonDeleteKey "));
    syslog(pszSubKey);
    syslog(TEXT("\r\n"));
#endif
#ifdef NT50
    if (hMonitor) {
	/* NT50 */
	MONITORINIT *pMonitorInit = (MONITORINIT *)hMonitor;
	rc = pMonitorInit->pMonitorReg->fpDeleteKey(
		hcKey, pszSubKey, pMonitorInit->hSpooler);
    }
    else 
#endif
    {
	rc = RegDeleteKey(hcKey, pszSubKey); 
    }
#ifdef DEBUG_REDMON
    if (rc)
	syserror(rc);
#endif
    return rc;
}


LONG
RedMonSetValue(HANDLE hMonitor, HANDLE hcKey, LPCTSTR pszValue, DWORD dwType, 
	const BYTE* pData, DWORD cbData)
{
    LONG rc = ERROR_SUCCESS;
#ifdef DEBUG_REDMON
    syslog(TEXT("RedMonSetValue "));
    syslog(pszValue);
    syslog(TEXT("\r\n"));
#endif
#ifdef NT50
    if (hMonitor) {
	/* NT50 */
	MONITORINIT *pMonitorInit = (MONITORINIT *)hMonitor;
	rc = pMonitorInit->pMonitorReg->fpSetValue(hcKey, pszValue,
		dwType, pData, cbData, pMonitorInit->hSpooler);
    }
    else 
#endif
    {
	rc = RegSetValueEx(hcKey, pszValue, 0, dwType,
		pData, cbData);
    }
#ifdef DEBUG_REDMON
    if (rc)
	syserror(rc);
#endif
    return rc;
}


LONG
RedMonQueryValue(HANDLE hMonitor, HANDLE hcKey, LPCTSTR pszValue, 
	PDWORD pType, PBYTE pData, PDWORD pcbData)
{
    LONG rc = ERROR_SUCCESS;
#ifdef DEBUG_REDMON
    syslog(TEXT("RedMonQueryValue "));
    syslog(pszValue);
    syslog(TEXT("\r\n"));
#endif
#ifdef NT50
    if (hMonitor) {
	/* NT50 */
	MONITORINIT *pMonitorInit = (MONITORINIT *)hMonitor;
	rc = pMonitorInit->pMonitorReg->fpQueryValue(
		hcKey, pszValue, pType, pData, pcbData,
		pMonitorInit->hSpooler);
    }
    else 
#endif
    {
	rc = RegQueryValueEx(hcKey, pszValue, 0, pType, 
	    pData, pcbData);
    }
#ifdef DEBUG_REDMON
    if (rc)
	syserror(rc);
#endif
    return rc;
}


/* NT50 */
BOOL WINAPI rsEnumPorts(HANDLE hMonitor, LPTSTR pName, DWORD Level, 
	LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
{
    HKEY hkey, hsubkey;
    TCHAR portname[MAXSHORTSTR], portdesc[MAXSHORTSTR];
    TCHAR monitorname[MAXSHORTSTR];
    TCHAR buf[MAXSTR];
    int needed;
    DWORD cbData, keytype;
    PORT_INFO_1 *pi1;
    PORT_INFO_2 *pi2;
    LPTSTR pstr;
    LONG rc;
    int i;

#ifdef DEBUG_REDMON
    syslog(TEXT("rsEnumPorts\r\n"));
    {TCHAR buf[MAXSTR];
    wsprintf(buf, TEXT("  hMonitor=0x%0x\r\n"), hMonitor);
    syslog(buf);
    }
    syslog(TEXT("  pName="));
    sysnum((DWORD)pName);
    syslog(TEXT("\r\n"));
#endif

    *pcbNeeded = 0;
    *pcReturned = 0;

    if (hMonitor == NULL) {
	if (pName != NULL)
	    return FALSE;
    }

    if ((Level < 1) || (Level > 2)) {
	SetLastError(ERROR_INVALID_LEVEL);
	return FALSE;
    }

    rc = RedMonOpenKey(hMonitor, PORTSNAME, KEY_READ, &hkey);
    if (rc != ERROR_SUCCESS)
	return TRUE;	/* There are no ports */

    LoadString(hdll, IDS_MONITORNAME, monitorname, 
	sizeof(monitorname)/sizeof(TCHAR)-1);

    /* First pass is to calculate the number of bytes needed */
    needed = 0;
    i = 0;
    cbData = sizeof(portname);
    rc = RedMonEnumKey(hMonitor, hkey, 0, portname, &cbData);
    while (rc == ERROR_SUCCESS) {
	needed += (lstrlen(portname) + 1) * sizeof(TCHAR);
	if (Level == 1) {
	    needed += sizeof(PORT_INFO_1);
	}
	else if (Level == 2) {
	    needed += sizeof(PORT_INFO_2);
	    needed += (lstrlen(monitorname) + 1) * sizeof(TCHAR);
	    lstrcpy(buf, PORTSNAME);
	    lstrcat(buf, BACKSLASH);
	    lstrcat(buf, portname);
	    rc = RedMonOpenKey(hMonitor, buf, KEY_READ, &hsubkey);
	    if (rc == ERROR_SUCCESS) {
		cbData = sizeof(portdesc);
		keytype = REG_SZ;
	        RedMonQueryValue(hMonitor, hsubkey, DESCKEY, &keytype, 
			(LPBYTE)portdesc, &cbData);
		if (rc == ERROR_SUCCESS)
		    needed += (lstrlen(portdesc) + 1) * sizeof(TCHAR);
		else
		    needed += 1 * sizeof(TCHAR);	/* empty string */
		RedMonCloseKey(hMonitor, hsubkey);
	    }
	    else {
		needed += 1 * sizeof(TCHAR);	/* empty string */
	    }
	}
	i++;
	cbData = sizeof(portname);
        rc = RedMonEnumKey(hMonitor, hkey, i, portname, &cbData);
    }
    *pcbNeeded = needed;
   
    if ((pPorts == NULL) || ((unsigned int)needed > cbBuf)) {
	RedMonCloseKey(hMonitor, hkey);
	SetLastError(ERROR_INSUFFICIENT_BUFFER);
	return FALSE;
    }

    /* Second pass to copy the data to the buffer */

    /* PORT_INFO_x structures must be placed at the beginning
     * of the buffer, and strings at the end of the buffer.
     * This is important!  It appears that one buffer is 
     * allocated, then each port monitor is called in turn to
     * add its entries to the buffer, between previous entries.
     */

    i = 0;
    pi1 = (PORT_INFO_1 *)pPorts;
    pi2 = (PORT_INFO_2 *)pPorts;
    pstr = (LPTSTR)(pPorts + cbBuf);
    cbData = sizeof(portname);
    rc = RedMonEnumKey(hMonitor, hkey, 0, portname, &cbData);
    while (rc == ERROR_SUCCESS) {
	if (Level == 1) {
	    pstr -= lstrlen(portname) + 1;
	    lstrcpy(pstr, portname);
	    pi1[i].pName = pstr;
	}
	else if (Level == 2){
	    pstr -= lstrlen(portname) + 1;
	    lstrcpy(pstr, portname);
	    pi2[i].pPortName = pstr;

	    pstr -= lstrlen(monitorname) + 1;
	    lstrcpy(pstr, monitorname);
	    pi2[i].pMonitorName = pstr;

	    lstrcpy(buf, PORTSNAME);
	    lstrcat(buf, BACKSLASH);
	    lstrcat(buf, portname);
	    rc = RedMonOpenKey(hMonitor, buf, KEY_READ, &hsubkey);
	    if (rc == ERROR_SUCCESS) {
		cbData = sizeof(portdesc);
		keytype = REG_SZ;
	        RedMonQueryValue(hMonitor, hsubkey, DESCKEY, &keytype, 
			(LPBYTE)portdesc, &cbData);
		if (rc != ERROR_SUCCESS)
		    portdesc[0] = '\0';
		RedMonCloseKey(hMonitor, hsubkey);
	    }
	    else {
		portdesc[0] = '\0';
	    }

	    pstr -= lstrlen(portdesc) + 1;
	    lstrcpy(pstr, portdesc);
	    pi2[i].pDescription = pstr;

⌨️ 快捷键说明

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