redpr.c
来自「虚拟打印端口」· C语言 代码 · 共 586 行 · 第 1/2 页
C
586 行
/* Copyright (C) 1997-1998, 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.
*/
/* RedPr program */
/* Windows PRint program */
/* A Win32 command line program for sending files to a printer.
* RedPr writes to the Windows printer queue and is better than
* using "COPY /B filename LPT1:"
*
* Printer names may be either the Windows 95/NT printer name
* such as "Apple LaserWriter II NT", or a port name such
* as "LPT1:". If a port name is used, RedPr will replace it
* with the name of the first printer to use that port.
*
* Examples:
* RedPr -P"Apple LaserWriter II NT" file.ps
* RedPr -pLPT1: file.ps
* Actually, -P and -p are interchangeable. RedPr first looks
* for a printer with the given name. If that fails it tries to
* find a printer which uses the given port.
*/
/* This program was originally written to read from a PostScript
* printer connected to a Windows 95 printer port.
* This may not work because the PostScript language monitor
* may take charge of reading from the port, and not pass anything
* back to ReadPrinter.
* We are hoping that DOC_INFO_2 dwMode=DI_CHANNEL will override this.
*
* On 1997-12-05, MSDN Online Library said DOC_INFO_2 structure was
* not supported by Windows NT. This structure is required in the
* StartDocPrinter() call to get a clear bi-directional channel
* to the printer.
* Bi-directional is not available under Windows NT.
*/
/* Added wildcard support for filenames, 1998-12-02 */
#define STRICT
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#define PRINT_BUF_SIZE 4096
BOOL bidirectional = FALSE;
BOOL verbose = FALSE;
BOOL is_winnt = FALSE;
#ifndef DI_CHANNEL
/* DI_CHANNEL is used by DOC_INFO_2 */
typedef struct _DOC_INFO_2A {
LPSTR pDocName;
LPSTR pOutputFile;
LPSTR pDatatype;
DWORD dwMode;
DWORD JobId;
} DOC_INFO_2A, *PDOC_INFO_2A, *LPDOC_INFO_2A;
typedef struct _DOC_INFO_2W {
LPWSTR pDocName;
LPWSTR pOutputFile;
LPWSTR pDatatype;
DWORD dwMode;
DWORD JobId;
} DOC_INFO_2W, *PDOC_INFO_2W, *LPDOC_INFO_2W;
#ifdef UNICODE
typedef DOC_INFO_2W DOC_INFO_2;
typedef PDOC_INFO_2W PDOC_INFO_2;
typedef LPDOC_INFO_2W LPDOC_INFO_2;
#else
typedef DOC_INFO_2A DOC_INFO_2;
typedef PDOC_INFO_2A PDOC_INFO_2;
typedef LPDOC_INFO_2A LPDOC_INFO_2;
#endif // UNICODE
#define DI_CHANNEL 1 // start direct read/write channel,
#endif
BOOL
enum_printers(PRINTER_INFO_2 **ppri2, LPDWORD pcount, BOOL display);
void
usage(void)
{
PRINTER_INFO_2 *pri2;
DWORD count;
fprintf(stdout, "RED PRint for Win32 by Ghostgum Software Pty Ltd. 1998-12-05\n");
fprintf(stdout, "Usage: RedPr [-P\042printer\042] [-pport] [-b] [-h] [-v] filename ...\n");
fprintf(stdout, " -P\042printer\042 See below for printer names.\n");
fprintf(stdout, " -pport See below for port names.\n");
fprintf(stdout, " -b Bi-directional. Attempt to read from printer.\n");
fprintf(stdout, " -h Help\n");
fprintf(stdout, " -v Verbose. Display debugging messages.\n");
fprintf(stdout, "\n");
/* display list of printers */
if (enum_printers(&pri2, &count, TRUE))
free(pri2);
}
void
write_error(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) {
fputs((LPTSTR)lpMessageBuffer, stdout);
LocalFree(LocalHandle(lpMessageBuffer));
fputs("\r\n", stdout);
}
}
/* Obtain a list of available printers */
/* Return a malloc'd list pointed to by ppri2 */
/* If display==TRUE, display list on stdout */
BOOL
enum_printers(PRINTER_INFO_2 **ppri2, LPDWORD pcount, BOOL display)
{
unsigned int i;
DWORD needed;
PRINTER_INFO_2 *pri2;
char *enumbuffer;
/* enumerate all available printers */
EnumPrinters(PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL, NULL,
2, NULL, 0, &needed, pcount);
if (needed == 0) {
/* no printers */
fprintf(stdout, "No printers installed");
return FALSE;
}
enumbuffer = malloc(needed);
if (enumbuffer == (char *)NULL) {
fprintf(stdout, "Out of memory");
return FALSE;
}
if (!EnumPrinters(PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL, NULL,
2, (LPBYTE)enumbuffer, needed, &needed, pcount)) {
DWORD err = GetLastError();
free(enumbuffer);
fprintf(stdout, "EnumPrinters() failed, error = %d",
err);
write_error(err);
return FALSE;
}
pri2 = (PRINTER_INFO_2 *)enumbuffer;
/* Windows NT doesn't identify the default printer in
* PRINTER_INFO_2 Attributes. Instead we need to query
* the registry to find the default printer for the
* current user.
*/
if (is_winnt) {
HKEY hkey;
TCHAR defprint[256];
defprint[0] = '\0';
if (RegOpenKeyEx(HKEY_CURRENT_USER,
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows",
0, KEY_READ, &hkey) == ERROR_SUCCESS) {
DWORD cbData = sizeof(defprint);
DWORD keytype = REG_SZ;
RegQueryValueEx(hkey, "Device", 0, &keytype,
(LPBYTE)defprint, &cbData);
strtok(defprint, ",");
}
for (i=0; i<*pcount; i++) {
if (lstrcmp(pri2[i].pPrinterName, defprint) == 0)
pri2[i].Attributes |= PRINTER_ATTRIBUTE_DEFAULT;
}
}
if (display || verbose) {
fprintf(stdout, "Printers (default is *):\n");
for (i=0; i<*pcount; i++) {
fprintf(stdout, "%c \042%s\042 on %s\n",
pri2[i].Attributes & PRINTER_ATTRIBUTE_DEFAULT ? '*' : ' ',
pri2[i].pPrinterName, pri2[i].pPortName);
}
}
*ppri2 = pri2;
return TRUE;
}
void
read_printer(HANDLE hprinter)
{
/* Timeouts for printer ports have both a timeout constant
* and a per character timeout. Use a small read buffer to
* try reduce the time taken to return from ReadPrinter().
*/
char read_buffer[16];
/* assume we will read no more than double what we send */
int try_count = 2 * PRINT_BUF_SIZE / sizeof(read_buffer);
DWORD read_count = 1;
/* keep trying to read until an error
* or ReadPrinter returns 0 bytes,
* or we have called ReadPrinter enough times to
* read PRINT_BUFFER_SIZE bytes.
*/
while (bidirectional && try_count && read_count) {
try_count--;
if (ReadPrinter(hprinter, (LPVOID)read_buffer, sizeof(read_buffer),
&read_count)) {
fwrite(read_buffer, 1, read_count, stdout);
if (verbose)
fprintf(stdout, "\nRead %d bytes from printer\n", read_count);
}
else {
DWORD error = GetLastError();
bidirectional = FALSE;
if (error == ERROR_INVALID_FLAGS) {
fprintf(stdout, "Printer is not bi-directional\n");
if (verbose)
fprintf(stdout, "Error = %d\n", error);
}
else if (error == ERROR_PRINT_CANCELLED) {
/* this isn't an error */
if (verbose) {
fprintf(stdout, "ReadPrinter: Job has finished\n");
fprintf(stdout, "Error = %d\n", error);
}
}
else {
fprintf(stdout, "ReadPrinter() failed, error = %d\n",
error);
write_error(error);
}
}
}
}
int
print_file(char *filename, char *printer_name)
{
DWORD count;
char *buffer;
FILE *f;
HANDLE hprinter;
DOC_INFO_1 dci1;
DOC_INFO_2 dci2;
DWORD written;
DWORD JobId;
DWORD error;
if ((buffer = malloc(PRINT_BUF_SIZE)) == (char *)NULL)
return FALSE;
if ((f = fopen(filename, "rb")) == (FILE *)NULL) {
fprintf(stdout, "Can't find file \042%s\042\n", filename);
free(buffer);
return FALSE;
}
/* open a printer */
if (!OpenPrinter(printer_name, &hprinter, NULL)) {
error = GetLastError();
if (verbose)
fprintf(stdout,
"OpenPrinter() failed for \042%s\042, error = %d\n",
printer_name, error);
write_error(error);
fprintf(stdout, "Unknown printer\n");
free(buffer);
return FALSE;
}
/* from here until ClosePrinter, should AbortPrinter on error */
if (!is_winnt && bidirectional) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?