You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2110 lines
61 KiB
2110 lines
61 KiB
/*****************************************************************************\
|
|
* MODULE: webpnp.cxx
|
|
*
|
|
* This module contains routines which read/write printer-configuration
|
|
* data to a BIN-File. The file format is depicted below. The file begins
|
|
* with a header indicating the number of (pData) items. THIS DOES NOT
|
|
* include the DEVMODEW in its item-count. So, at a minimum, this code
|
|
* could result in the setting of a DEVMODE, or just setting the printer
|
|
* data, depending upon the header information.
|
|
*
|
|
*
|
|
* DEVBIN_HEAD DEVBIN_INFO ...-> DEVBIN_INFO
|
|
* --------------------------------------------------------------------------
|
|
* | | cbSize | cbSize |
|
|
* | bDevMode |------------------------------|------------------------------|
|
|
* | cItems | | | | cbData | | | | cbData |
|
|
* | | Type | Key | Name |----------| Type | Key | Name |----------|
|
|
* | | | | | DevModeW | | | | pData 0 |
|
|
* --------------------------------------------------------------------------
|
|
*
|
|
* The usage scenario is for webWritePrinterInfo() to query a printer and
|
|
* write out the DEVMODEW and Printer-Configuration data to this file-format.
|
|
* On a call to webReadPrinterInfo(), a particular printer is opened, and
|
|
* the BIN-File is read. The printer is then reset to the information
|
|
* contained in the BIN-File. This is accomplished by doing a GetPrinter(2)
|
|
* on the opened-printer, then re-configuring the PRINT_INFO_2 information
|
|
* and reseting the the printer through SetPrinter(2).
|
|
*
|
|
* Likewise, if there exists printer-data, the information is set to the
|
|
* opened printer through SetPrinterData() calls.
|
|
*
|
|
*
|
|
* NOTE: The DEVMODE is always the FIRST entry in this file following the
|
|
* DEVBIN_HEAD.
|
|
*
|
|
* NOTE: The (cItems) only refers to the (Printer-Data) fields. It does
|
|
* not count the DEVMODEW.
|
|
*
|
|
* NOTE: The processing for ICM-Profile enumeration is performed in unicode
|
|
* strings and only converted to TCHAR type strings on callbacks to
|
|
* the caller of the enum API. This is desirable to maintain a level
|
|
* of consistency when dealing with text.
|
|
*
|
|
*
|
|
* Copyright (C) 1996-1997 Microsoft Corporation
|
|
* Copyright (C) 1996-1997 Hewlett Packard
|
|
*
|
|
* history:
|
|
* 25-Feb-1997 <chriswil> created.
|
|
*
|
|
\*****************************************************************************/
|
|
|
|
#include "spllibp.hxx"
|
|
#include <winspool.h>
|
|
#include <winsplp.h>
|
|
#include <icm.h>
|
|
#include <wininet.h>
|
|
|
|
/***************************************\
|
|
* Static Strings.
|
|
\***************************************/
|
|
static CONST WCHAR s_wszCopyFiles[] = L"CopyFiles";
|
|
static CONST WCHAR s_wszDir[] = L"Directory";
|
|
static CONST WCHAR s_wszFil[] = L"Files";
|
|
static CONST WCHAR s_wszMod[] = L"Module";
|
|
static CONST CHAR s_szGCFP[] = "GenerateCopyFilePaths";
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_GAlloc (Local Routine)
|
|
*
|
|
* Allocates a block of memory.
|
|
*
|
|
\*****************************************************************************/
|
|
inline LPVOID web_GAlloc(
|
|
DWORD cbSize)
|
|
{
|
|
return new BYTE[cbSize];
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_GFree (Local Routine)
|
|
*
|
|
* Deletes the memory-block allocated via web_GAlloc().
|
|
*
|
|
\*****************************************************************************/
|
|
inline BOOL web_GFree(
|
|
LPVOID lpMem)
|
|
{
|
|
delete [] lpMem;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_AlignSize (Local Routine)
|
|
*
|
|
* Returns size (bytes) of the memory-block. This returns a 64 bit aligned
|
|
* value.
|
|
*
|
|
\*****************************************************************************/
|
|
inline DWORD web_AlignSize(
|
|
DWORD cbSize)
|
|
{
|
|
return ((cbSize & 7) ? cbSize + (8 - (cbSize & 7)) : cbSize);
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_StrSizeW (Local Routine)
|
|
*
|
|
* Returns size (bytes) of the string. This includes the NULL terminator.
|
|
*
|
|
\*****************************************************************************/
|
|
inline DWORD web_StrSizeW(
|
|
LPCWSTR lpszStr)
|
|
{
|
|
return ((lstrlenW(lpszStr) + 1) * sizeof(WCHAR));
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_NextStrW (Local Routine)
|
|
*
|
|
* Returns pointer to the next-item in a string array.
|
|
*
|
|
\*****************************************************************************/
|
|
inline LPWSTR web_NextStrW(
|
|
LPCWSTR lpszStr)
|
|
{
|
|
return ((LPWSTR)lpszStr + (lstrlenW(lpszStr) + 1));
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_NextItem (Local Routine)
|
|
*
|
|
* Returns pointer to the next-item in the BIN-File.
|
|
*
|
|
\*****************************************************************************/
|
|
inline LPDEVBIN_INFO web_NextItem(
|
|
LPDEVBIN_INFO lpInfo)
|
|
{
|
|
return (LPDEVBIN_INFO)(((LPBYTE)lpInfo) + lpInfo->cbSize);
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_MBtoWC (Local Routine)
|
|
*
|
|
* Converts a MultiByte string to a Unicode string.
|
|
*
|
|
\*****************************************************************************/
|
|
inline DWORD web_MBtoWC(
|
|
LPWSTR lpszWC,
|
|
LPCSTR lpszMB,
|
|
DWORD cbSize)
|
|
{
|
|
cbSize = (DWORD)MultiByteToWideChar(CP_ACP,
|
|
MB_PRECOMPOSED,
|
|
lpszMB,
|
|
-1,
|
|
lpszWC,
|
|
(int)(cbSize / sizeof(WCHAR)));
|
|
|
|
return (cbSize * sizeof(WCHAR));
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_WCtoTC (Local Routine)
|
|
*
|
|
* Converts a Unicode string to a string appropriate for the built library.
|
|
* The size must account for the NULL terminator when specifying size.
|
|
*
|
|
\*****************************************************************************/
|
|
inline LPTSTR web_WCtoTC(
|
|
LPCWSTR lpwszWC,
|
|
DWORD cchWC)
|
|
{
|
|
LPTSTR lpszTC;
|
|
DWORD cbSize;
|
|
|
|
|
|
cbSize = cchWC * sizeof(TCHAR);
|
|
|
|
if (lpszTC = (LPTSTR)web_GAlloc(cbSize)) {
|
|
|
|
#ifdef UNICODE
|
|
|
|
//
|
|
// Use CopyMemory, not lstrcpyn. This allows strings
|
|
// with nulls in them...(e.g. MULTI_SZ regsitry values
|
|
//
|
|
CopyMemory(lpszTC, lpwszWC, cbSize);
|
|
|
|
#else
|
|
|
|
WideCharToMultiByte(CP_ACP,
|
|
WC_DEFAULTCHAR,
|
|
lpwszWC,
|
|
cchWC,
|
|
lpszTC,
|
|
cchWC,
|
|
NULL,
|
|
NULL);
|
|
#endif
|
|
|
|
}
|
|
|
|
return lpszTC;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_OpenDirectoryW (Local Routine)
|
|
*
|
|
* Open a handle to a directory.
|
|
*
|
|
\*****************************************************************************/
|
|
inline HANDLE web_OpenDirectoryW(
|
|
LPCWSTR lpwszDir)
|
|
{
|
|
return CreateFileW(lpwszDir,
|
|
0,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_OpenFileRead (Local Routine)
|
|
*
|
|
* Open a file for reading.
|
|
*
|
|
\*****************************************************************************/
|
|
inline HANDLE web_OpenFileRead(
|
|
LPCTSTR lpszName)
|
|
{
|
|
return CreateFile(lpszName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_OpenFileWrite (Local Routine)
|
|
*
|
|
* Open a file for writing.
|
|
*
|
|
\*****************************************************************************/
|
|
inline HANDLE web_OpenFileWrite(
|
|
LPCTSTR lpszName)
|
|
{
|
|
return CreateFile(lpszName,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_LockMap (Local Routine)
|
|
*
|
|
* Locks the map-view.
|
|
*
|
|
\*****************************************************************************/
|
|
inline LPVOID web_LockMap(
|
|
HANDLE hMap)
|
|
{
|
|
LPWEB_FILEMAP lpMap;
|
|
LPVOID lpPtr = NULL;
|
|
|
|
if (lpMap = (LPWEB_FILEMAP)hMap)
|
|
lpPtr = MapViewOfFile(lpMap->hMap, FILE_MAP_READ, 0, 0, 0);
|
|
|
|
return lpPtr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_UnlockMap (Local Routine)
|
|
*
|
|
* Unlocks the map-view.
|
|
*
|
|
\*****************************************************************************/
|
|
inline BOOL web_UnlockMap(
|
|
LPVOID lpPtr)
|
|
{
|
|
return UnmapViewOfFile(lpPtr);
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_OpenMap (Local Routine)
|
|
*
|
|
* Opens a file-mapping object.
|
|
*
|
|
\*****************************************************************************/
|
|
HANDLE web_OpenMap(
|
|
LPCTSTR lpszFile)
|
|
{
|
|
LPWEB_FILEMAP lpMap;
|
|
DWORD cbSize;
|
|
|
|
|
|
if (lpMap = (LPWEB_FILEMAP)web_GAlloc(sizeof(WEB_FILEMAP))) {
|
|
|
|
lpMap->hFile = web_OpenFileRead(lpszFile);
|
|
|
|
if (lpMap->hFile && (lpMap->hFile != INVALID_HANDLE_VALUE)) {
|
|
|
|
if (cbSize = GetFileSize(lpMap->hFile, NULL)) {
|
|
|
|
lpMap->hMap = CreateFileMapping(lpMap->hFile,
|
|
NULL,
|
|
PAGE_READONLY,
|
|
0,
|
|
cbSize,
|
|
NULL);
|
|
|
|
if (lpMap->hMap)
|
|
return (HANDLE)lpMap;
|
|
}
|
|
|
|
CloseHandle(lpMap->hFile);
|
|
}
|
|
|
|
web_GFree(lpMap);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_CloseMap (Local Routine)
|
|
*
|
|
* Closes file-mapping object.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL web_CloseMap(
|
|
HANDLE hMap)
|
|
{
|
|
LPWEB_FILEMAP lpMap;
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
if (lpMap = (LPWEB_FILEMAP)hMap) {
|
|
|
|
CloseHandle(lpMap->hMap);
|
|
CloseHandle(lpMap->hFile);
|
|
|
|
bRet = web_GFree(lpMap);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_GAllocStrW (Local Routine)
|
|
*
|
|
* Allocates a unicode string buffer.
|
|
*
|
|
\*****************************************************************************/
|
|
LPWSTR web_GAllocStrW(
|
|
LPCWSTR lpszStr)
|
|
{
|
|
LPWSTR lpszMem;
|
|
DWORD cbSize;
|
|
|
|
if (lpszStr == NULL)
|
|
return NULL;
|
|
|
|
cbSize = web_StrSizeW(lpszStr);
|
|
|
|
if (lpszMem = (LPWSTR)web_GAlloc(cbSize))
|
|
CopyMemory(lpszMem, lpszStr, cbSize);
|
|
|
|
return lpszMem;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_LoadModuleW
|
|
*
|
|
* Loads the module by first looking in the path. If this fails it attempts
|
|
* to load from the driver-directory.
|
|
*
|
|
\*****************************************************************************/
|
|
HMODULE web_LoadModuleW(
|
|
LPCWSTR lpwszMod)
|
|
{
|
|
HMODULE hLib = NULL;
|
|
|
|
hLib = LoadLibraryW(lpwszMod);
|
|
|
|
return hLib;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_FindRCharW
|
|
*
|
|
* Searches for the first occurence of (cch) in a string in reverse order.
|
|
*
|
|
\*****************************************************************************/
|
|
LPWSTR web_FindRCharW(
|
|
LPWSTR lpszStr,
|
|
WCHAR cch)
|
|
{
|
|
int nLimit;
|
|
|
|
if (nLimit = lstrlenW(lpszStr)) {
|
|
|
|
lpszStr += nLimit;
|
|
|
|
while ((*lpszStr != cch) && nLimit--)
|
|
lpszStr--;
|
|
|
|
if (nLimit >= 0)
|
|
return lpszStr;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_GetDrvDirW
|
|
*
|
|
* Returns: LPWSTR - the printer driver dir, minus the architecture subdir.
|
|
* Example: Returns something like "%WINDIR%\SYSTEM32\SPOOL\DRIVERS"
|
|
*
|
|
\*****************************************************************************/
|
|
LPWSTR web_GetDrvDirW(VOID)
|
|
{
|
|
LPWSTR lpwszDrvDir;
|
|
LPWSTR lpwszFind;
|
|
DWORD cbSize;
|
|
|
|
//
|
|
// Call once to get size of buffer needed.
|
|
//
|
|
cbSize = 0;
|
|
GetPrinterDriverDirectoryW(NULL, NULL, 1, NULL, 0, &cbSize);
|
|
|
|
//
|
|
// Alloc a buffer.
|
|
//
|
|
if (cbSize && (lpwszDrvDir = (LPWSTR)web_GAlloc(cbSize)) ) {
|
|
//
|
|
// Get the driver directory.
|
|
//
|
|
if (GetPrinterDriverDirectoryW(NULL,
|
|
NULL,
|
|
1,
|
|
(LPBYTE)lpwszDrvDir,
|
|
cbSize,
|
|
&cbSize)) {
|
|
|
|
//
|
|
// Find the parent-directory of the driver-path.
|
|
//
|
|
if (lpwszFind = web_FindRCharW(lpwszDrvDir, L'\\')) {
|
|
|
|
*lpwszFind = L'\0';
|
|
|
|
return lpwszDrvDir;
|
|
}
|
|
}
|
|
//
|
|
// Free memory if we fail.
|
|
//
|
|
web_GFree(lpwszDrvDir);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_BuildNameW
|
|
*
|
|
* Takes path, name, extension strings and builds a fully-qualified
|
|
* string representing the file. This can also be used to build other
|
|
* names.
|
|
*
|
|
\*****************************************************************************/
|
|
LPWSTR web_BuildNameW(
|
|
LPCWSTR lpwszPath,
|
|
LPCWSTR lpwszName,
|
|
LPCWSTR lpwszExt)
|
|
{
|
|
DWORD cch;
|
|
LPWSTR lpwszFull;
|
|
|
|
//
|
|
// Calculate the size necessary to hold the full-path filename.
|
|
//
|
|
cch = lstrlenW(L"\\");
|
|
cch += (lpwszPath ? lstrlenW(lpwszPath) : 0);
|
|
cch += (lpwszName ? lstrlenW(lpwszName) : 0);
|
|
cch += (lpwszExt ? lstrlenW(lpwszExt) : 0);
|
|
|
|
|
|
if (lpwszFull = (LPWSTR)web_GAlloc(((cch + 1) * sizeof(WCHAR)))) {
|
|
|
|
if (lpwszPath) {
|
|
|
|
if (lpwszExt)
|
|
StringCchPrintfW(lpwszFull, cch+1, L"%s\\%s%s", lpwszPath, lpwszName, lpwszExt);
|
|
else
|
|
StringCchPrintfW(lpwszFull, cch+1, L"%s\\%s", lpwszPath, lpwszName);
|
|
|
|
} else {
|
|
|
|
if (lpwszExt)
|
|
StringCchPrintfW(lpwszFull, cch+1, L"%s%s", lpwszName, lpwszExt);
|
|
else
|
|
StringCchPrintfW(lpwszFull, cch+1, L"%s", lpwszName);
|
|
}
|
|
}
|
|
|
|
return lpwszFull;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_GetCurDirW
|
|
*
|
|
* Returns string indicating current-directory.
|
|
*
|
|
\*****************************************************************************/
|
|
LPWSTR web_GetCurDirW(VOID)
|
|
{
|
|
DWORD cbSize;
|
|
LPWSTR lpwszDir = NULL;
|
|
|
|
|
|
cbSize = GetCurrentDirectoryW(0, NULL);
|
|
|
|
if (cbSize && (lpwszDir = (LPWSTR)web_GAlloc((cbSize * sizeof(WCHAR)))))
|
|
GetCurrentDirectoryW(cbSize, lpwszDir);
|
|
|
|
return lpwszDir;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_MakeFullKeyW (Local Routine)
|
|
*
|
|
* Creates a full registry-key from the key/sub-key strings.
|
|
*
|
|
\*****************************************************************************/
|
|
LPWSTR web_MakeFullKeyW(
|
|
LPCWSTR lpszKey,
|
|
LPCWSTR lpszSKey)
|
|
{
|
|
DWORD cbSize;
|
|
LPWSTR lpszFKey = NULL;
|
|
|
|
|
|
if (lpszKey && lpszSKey) {
|
|
|
|
cbSize = web_StrSizeW(lpszKey) + web_StrSizeW(lpszSKey) + sizeof(WCHAR);
|
|
|
|
if (lpszFKey = (LPWSTR)web_GAlloc(cbSize)) {
|
|
|
|
if (*lpszKey)
|
|
StringCbPrintfW(lpszFKey, cbSize, L"%ws\\%ws", lpszKey, lpszSKey);
|
|
else
|
|
StringCbPrintfW(lpszFKey, cbSize, L"%ws", lpszSKey);
|
|
}
|
|
}
|
|
|
|
return lpszFKey;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_KeyExistsW (Local Routine)
|
|
*
|
|
* Checks to see if the printer-key exists.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL web_KeyExistsW(
|
|
HANDLE hPrinter,
|
|
LPCWSTR lpszKey)
|
|
{
|
|
DWORD cbSize;
|
|
DWORD dwRet;
|
|
|
|
|
|
cbSize = 0;
|
|
dwRet = EnumPrinterKeyW(hPrinter, lpszKey, NULL, 0, &cbSize);
|
|
|
|
return (cbSize && (dwRet == ERROR_MORE_DATA));
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_EnumPrinterSubKeysW (Local Routine)
|
|
*
|
|
* Returns an array of printer-keys for the specified key.
|
|
*
|
|
\*****************************************************************************/
|
|
LPWSTR web_EnumPrinterSubKeysW(
|
|
HANDLE hPrinter,
|
|
LPCWSTR lpszKey)
|
|
{
|
|
DWORD cbSize;
|
|
DWORD dwRet;
|
|
LPWSTR aszSKeys;
|
|
|
|
//
|
|
// Determine the size necessary for enumerating all the
|
|
// sub-keys for this key.
|
|
//
|
|
cbSize = 0;
|
|
dwRet = EnumPrinterKeyW(hPrinter, lpszKey, NULL, 0, &cbSize);
|
|
|
|
//
|
|
// If OK, then proceed to the enumeration.
|
|
//
|
|
if (cbSize && (dwRet == ERROR_MORE_DATA)) {
|
|
//
|
|
// Allocate the space for retrieving the keys.
|
|
//
|
|
if (aszSKeys = (LPWSTR)web_GAlloc(cbSize)) {
|
|
//
|
|
// Enumerate the sub-keys for this level in (lpszKey).
|
|
//
|
|
dwRet = EnumPrinterKeyW(hPrinter, lpszKey, aszSKeys, cbSize, &cbSize);
|
|
|
|
if (dwRet == ERROR_SUCCESS)
|
|
return aszSKeys;
|
|
|
|
web_GFree(aszSKeys);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_EnumPrinterDataW (Local Routine)
|
|
*
|
|
* Returns an array of printer-data-values for the specified key.
|
|
*
|
|
\*****************************************************************************/
|
|
LPPRINTER_ENUM_VALUES web_EnumPrinterDataW(
|
|
HANDLE hPrinter,
|
|
LPCWSTR lpszKey,
|
|
LPDWORD lpcItems)
|
|
{
|
|
DWORD cbSize;
|
|
DWORD dwRet;
|
|
LPPRINTER_ENUM_VALUES apevData;
|
|
|
|
//
|
|
// Set the enumerated items to zero.
|
|
//
|
|
*lpcItems = 0;
|
|
|
|
//
|
|
// Determine the size necessary to store the enumerated data.
|
|
//
|
|
cbSize = 0;
|
|
dwRet = EnumPrinterDataExW(hPrinter, lpszKey, NULL, 0, &cbSize, lpcItems);
|
|
|
|
//
|
|
// If OK, then proceed to enumerate and write the values to the
|
|
// BIN-File.
|
|
//
|
|
if (cbSize && (dwRet == ERROR_MORE_DATA)) {
|
|
|
|
if (apevData = (LPPRINTER_ENUM_VALUES)web_GAlloc(cbSize)) {
|
|
//
|
|
// Enumerate all values for the specified key. This
|
|
// returns an array of value-structs.
|
|
//
|
|
dwRet = EnumPrinterDataExW(hPrinter,
|
|
lpszKey,
|
|
(LPBYTE)apevData,
|
|
cbSize,
|
|
&cbSize,
|
|
lpcItems);
|
|
|
|
if (dwRet == ERROR_SUCCESS)
|
|
return apevData;
|
|
|
|
web_GFree(apevData);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_GetPrtNameW
|
|
*
|
|
* Returns a Wide-Char string representing the printer-name.
|
|
*
|
|
\*****************************************************************************/
|
|
LPWSTR web_GetPrtNameW(
|
|
HANDLE hPrinter)
|
|
{
|
|
DWORD cbSize;
|
|
DWORD cbNeed;
|
|
LPPRINTER_INFO_2W lppi;
|
|
LPWSTR lpszPrtName = NULL;
|
|
|
|
//
|
|
// Get the necessary size for the printer-info-struct.
|
|
//
|
|
cbSize = 0;
|
|
GetPrinterW(hPrinter, 2, NULL, 0, &cbSize);
|
|
|
|
//
|
|
// Allocate storage for holding the print-info structure.
|
|
//
|
|
if (cbSize && (lppi = (LPPRINTER_INFO_2W)web_GAlloc(cbSize))) {
|
|
|
|
if (GetPrinterW(hPrinter, 2, (LPBYTE)lppi, cbSize, &cbNeed)) {
|
|
|
|
lpszPrtName = web_GAllocStrW(lppi->pPrinterName);
|
|
}
|
|
|
|
web_GFree(lppi);
|
|
}
|
|
|
|
return lpszPrtName;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_GetPrtDataW (Local Routine)
|
|
*
|
|
* Returns data for the specified key.
|
|
*
|
|
\*****************************************************************************/
|
|
LPBYTE web_GetPrtDataW(
|
|
HANDLE hPrinter,
|
|
LPCWSTR lpszKey,
|
|
LPCWSTR lpszVal)
|
|
{
|
|
DWORD dwType;
|
|
DWORD cbSize;
|
|
DWORD dwRet;
|
|
LPBYTE lpData;
|
|
|
|
|
|
cbSize = 0;
|
|
GetPrinterDataExW(hPrinter, lpszKey, lpszVal, &dwType, NULL, 0, &cbSize);
|
|
|
|
if (cbSize && (lpData = (LPBYTE)web_GAlloc(cbSize))) {
|
|
|
|
dwRet = GetPrinterDataExW(hPrinter,
|
|
lpszKey,
|
|
lpszVal,
|
|
&dwType,
|
|
lpData,
|
|
cbSize,
|
|
&cbSize);
|
|
|
|
if (dwRet == ERROR_SUCCESS)
|
|
return lpData;
|
|
|
|
web_GFree(lpData);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_CreateDirW (Local Routine)
|
|
*
|
|
* Creates the specified directory, if it doesn't exist.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL web_CreateDirW(
|
|
LPCWSTR lpwszDir)
|
|
{
|
|
HANDLE hDir;
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
hDir = web_OpenDirectoryW(lpwszDir);
|
|
|
|
if (hDir && (hDir != INVALID_HANDLE_VALUE)) {
|
|
|
|
CloseHandle(hDir);
|
|
|
|
bRet = TRUE;
|
|
|
|
} else {
|
|
|
|
bRet = CreateDirectoryW(lpwszDir, NULL);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_GetICMDirW (Local Routine)
|
|
*
|
|
* Loads the ICM-Module and returns the target color-directory. If the
|
|
* module isn't loaded then return NULL indicating there is no color
|
|
* modules to load.
|
|
*
|
|
\*****************************************************************************/
|
|
LPWSTR web_GetICMDirW(
|
|
HANDLE hPrinter,
|
|
DWORD dwCliInfo,
|
|
LPCWSTR lpwszDir,
|
|
LPCWSTR lpwszKey)
|
|
{
|
|
HMODULE hLib;
|
|
LPWSTR lpwszMod;
|
|
WEBGENCOPYFILEPATHPROC pfn;
|
|
SPLCLIENT_INFO_1 sci;
|
|
LPWSTR lpwszSrc;
|
|
LPWSTR lpwszDst;
|
|
LPWSTR lpwszDrv;
|
|
LPWSTR lpwszPrtName;
|
|
DWORD cbSrc;
|
|
DWORD cbDst;
|
|
DWORD dwRet;
|
|
LPWSTR lpwszRet = NULL;
|
|
|
|
|
|
//
|
|
// Load associated module. (e.g. color module)
|
|
//
|
|
if (lpwszMod = (LPWSTR)web_GetPrtDataW(hPrinter, lpwszKey, s_wszMod)) {
|
|
|
|
if (hLib = web_LoadModuleW(lpwszMod)) {
|
|
//
|
|
// Call into module to normalize the source/target
|
|
// paths.
|
|
//
|
|
if (pfn = (WEBGENCOPYFILEPATHPROC)GetProcAddress(hLib, s_szGCFP)) {
|
|
|
|
if (lpwszPrtName = web_GetPrtNameW(hPrinter)) {
|
|
|
|
if (lpwszDrv = web_GetDrvDirW()) {
|
|
|
|
cbSrc = (MAX_PATH + INTERNET_MAX_HOST_NAME_LENGTH + 1) * sizeof(WCHAR);
|
|
cbDst = (MAX_PATH + 1) * sizeof(WCHAR);
|
|
|
|
if (lpwszSrc = (LPWSTR)web_GAlloc(cbSrc)) {
|
|
|
|
if (lpwszDst = (LPWSTR)web_GAlloc(cbDst)) {
|
|
|
|
sci.dwSize = sizeof(SPLCLIENT_INFO_1);
|
|
sci.pMachineName = NULL;
|
|
sci.pUserName = NULL;
|
|
sci.dwBuildNum = 0;
|
|
sci.dwMajorVersion = webGetOSMajorVer(dwCliInfo);
|
|
sci.dwMinorVersion = webGetOSMinorVer(dwCliInfo);
|
|
|
|
StringCbPrintfW(lpwszSrc, cbSrc, L"%s\\%s", lpwszDrv, lpwszDir);
|
|
StringCbCopyW(lpwszDst, cbDst, lpwszDir);
|
|
|
|
dwRet = (*pfn)(lpwszPrtName,
|
|
lpwszDir,
|
|
(LPBYTE)&sci,
|
|
1,
|
|
lpwszSrc,
|
|
&cbSrc,
|
|
lpwszDst,
|
|
&cbDst,
|
|
COPYFILE_FLAG_SERVER_SPOOLER);
|
|
|
|
if (dwRet == ERROR_SUCCESS) {
|
|
|
|
lpwszRet = web_GAllocStrW(lpwszDst);
|
|
}
|
|
|
|
web_GFree(lpwszDst);
|
|
}
|
|
|
|
web_GFree(lpwszSrc);
|
|
}
|
|
|
|
web_GFree(lpwszDrv);
|
|
}
|
|
|
|
web_GFree(lpwszPrtName);
|
|
}
|
|
}
|
|
|
|
FreeLibrary(hLib);
|
|
}
|
|
|
|
web_GFree(lpwszMod);
|
|
}
|
|
|
|
return lpwszRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_BuildCopyDirW (Local Routine)
|
|
*
|
|
* This routine builds the src or dst directory for the CopyFiles. It does the
|
|
* following things:
|
|
*
|
|
* 1) loads optional module (if exists) and calls into it to adjust pathnames
|
|
* 2) builds fully-qualified CopyFiles directory
|
|
* 3) return the directory name
|
|
*
|
|
* Upon return this will represent the true path to the ICM profiles for the
|
|
* specified key.
|
|
*
|
|
\*****************************************************************************/
|
|
LPWSTR web_BuildCopyDirW(
|
|
HANDLE hPrinter,
|
|
DWORD dwCliInfo,
|
|
LPCWSTR lpwszKey)
|
|
{
|
|
LPWSTR lpwszDir;
|
|
LPWSTR lpwszDrvDir;
|
|
LPWSTR lpwszICM;
|
|
LPWSTR lpwszRet = NULL;
|
|
|
|
//
|
|
// Return the directory-value for the specified ICM key.
|
|
//
|
|
if (lpwszDir = (LPWSTR)web_GetPrtDataW(hPrinter, lpwszKey, s_wszDir)) {
|
|
//
|
|
// Return the printer-driver-directory-root.
|
|
//
|
|
if (lpwszDrvDir = web_GetDrvDirW()) {
|
|
//
|
|
// If called from the server, then call into the color-module
|
|
// to get the target-directory. Otherwise, just return the
|
|
// driver directory.
|
|
//
|
|
lpwszICM = web_GetICMDirW(hPrinter, dwCliInfo, lpwszDir, lpwszKey);
|
|
|
|
//
|
|
// If the module loaded and return a valid target-directory, then
|
|
// we can return this as our path to the ICM profiles.
|
|
//
|
|
if (lpwszICM != NULL) {
|
|
lpwszRet = web_BuildNameW( lpwszDrvDir, lpwszICM, NULL);
|
|
web_GFree(lpwszICM); // Free up the memory allocated in web_GetICMDirW
|
|
}
|
|
|
|
|
|
web_GFree(lpwszDrvDir);
|
|
}
|
|
|
|
web_GFree(lpwszDir);
|
|
}
|
|
|
|
return lpwszRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_CopyFilesW (Local Routine)
|
|
*
|
|
* This routine copies the point & print "CopyFiles" for the given key.
|
|
* It copies files from the web point & print setup-source to the directory
|
|
* specified by the "Directory" value under given key.
|
|
*
|
|
* Use : Processed in the context of the print-client.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL web_CopyFilesW(
|
|
HANDLE hPrinter,
|
|
LPCWSTR lpwszDir,
|
|
LPCWSTR lpwszKey)
|
|
{
|
|
LPWSTR awszFiles;
|
|
LPWSTR lpwszFile;
|
|
LPWSTR lpwszCurDir;
|
|
LPWSTR lpwszSrcFile;
|
|
LPWSTR lpwszDstFile;
|
|
LPWSTR lpwszPrtName;
|
|
BOOL bRet = FALSE;
|
|
|
|
//
|
|
// Get the files under the specified ICM key.
|
|
//
|
|
if (awszFiles = (LPWSTR)web_GetPrtDataW(hPrinter, lpwszKey, s_wszFil)) {
|
|
//
|
|
// Get our current-directory.
|
|
//
|
|
if (lpwszCurDir = web_GetCurDirW()) {
|
|
|
|
if (lpwszPrtName = web_GetPrtNameW(hPrinter)) {
|
|
//
|
|
// For each file in the list, we will need to build our source
|
|
// and destination directories to copy our ICM profiles.
|
|
//
|
|
for (bRet = TRUE, lpwszFile = awszFiles; bRet && *lpwszFile; ) {
|
|
|
|
bRet = FALSE;
|
|
|
|
if (lpwszSrcFile = web_BuildNameW(lpwszCurDir, lpwszFile, NULL)) {
|
|
|
|
if (lpwszDstFile = web_BuildNameW(lpwszDir, lpwszFile, NULL)) {
|
|
//
|
|
// Copy the ICM profile to the target directory.
|
|
//
|
|
bRet = CopyFileW(lpwszSrcFile, lpwszDstFile, FALSE);
|
|
|
|
web_GFree(lpwszDstFile);
|
|
}
|
|
|
|
web_GFree(lpwszSrcFile);
|
|
}
|
|
|
|
lpwszFile = web_NextStrW(lpwszFile);
|
|
}
|
|
|
|
web_GFree(lpwszPrtName);
|
|
}
|
|
|
|
web_GFree(lpwszCurDir);
|
|
}
|
|
|
|
web_GFree(awszFiles);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_TraverseCopyFilesW (Local Routine)
|
|
*
|
|
* This routine recursively traverses the printer-registry-settings for
|
|
* the CopyFiles keys.
|
|
*
|
|
* Use : Processed in the context of the print-client.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL web_TraverseCopyFilesW(
|
|
HANDLE hPrinter,
|
|
LPCWSTR lpwszDir,
|
|
LPCWSTR lpwszKey)
|
|
{
|
|
LPWSTR awszSKeys;
|
|
LPWSTR lpwszSKey;
|
|
LPWSTR lpwszFKey;
|
|
LPWSTR lpwszFDir;
|
|
DWORD dwType;
|
|
DWORD dwCliInfo;
|
|
BOOL bRet = FALSE;
|
|
|
|
//
|
|
// Get the array of keys under the specified key in the registry.
|
|
//
|
|
if (awszSKeys = web_EnumPrinterSubKeysW(hPrinter, lpwszKey)) {
|
|
//
|
|
// For each sub-key in the array, we need to build the path of
|
|
// where we'll place the ICM files.
|
|
//
|
|
for (bRet = TRUE, lpwszSKey = awszSKeys; *lpwszSKey && bRet; ) {
|
|
|
|
bRet = FALSE;
|
|
//
|
|
// The enum-routine returns a relative path, so we must build
|
|
// a fully-qualified registry-path.
|
|
//
|
|
if (lpwszFKey = web_MakeFullKeyW(lpwszKey, lpwszSKey)) {
|
|
|
|
dwCliInfo = webCreateOSInfo();
|
|
|
|
if (lpwszFDir = web_BuildCopyDirW(hPrinter, dwCliInfo, lpwszFKey)) {
|
|
//
|
|
// Create the ICM directory if it doesn't exist. Proceed
|
|
// to traverse the ICM-keys for more sub-keys.
|
|
//
|
|
if (web_CreateDirW(lpwszFDir))
|
|
bRet = web_TraverseCopyFilesW(hPrinter, lpwszFDir, lpwszFKey);
|
|
|
|
web_GFree(lpwszFDir);
|
|
}
|
|
|
|
web_GFree(lpwszFKey);
|
|
}
|
|
|
|
lpwszSKey = web_NextStrW(lpwszSKey);
|
|
}
|
|
|
|
//
|
|
// Free up the array.
|
|
//
|
|
web_GFree(awszSKeys);
|
|
|
|
//
|
|
// Process the ICM files for the specified key. If this
|
|
// is our top-level key (CopyFiles), then don't bother
|
|
// with the initialization. i.e. there should be no
|
|
// (module, files, directory) keys at this level.
|
|
//
|
|
if (bRet && lstrcmpiW(lpwszKey, s_wszCopyFiles))
|
|
bRet = web_CopyFilesW(hPrinter, lpwszDir, lpwszKey);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_WriteHeader (Local Routine)
|
|
*
|
|
* Outputs the header for the BIN-file. The parameters to this routine
|
|
* specify whether there is a DEVMODE contained in the file, as well as a
|
|
* count of all the device-data-items.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL web_WriteHeader(
|
|
HANDLE hFile,
|
|
DWORD cItems,
|
|
BOOL bDevMode)
|
|
{
|
|
DWORD dwWr = 0;
|
|
DEVBIN_HEAD dbh;
|
|
BOOL bRet;
|
|
|
|
//
|
|
// Setup the header information.
|
|
//
|
|
dbh.cItems = cItems;
|
|
dbh.bDevMode = bDevMode;
|
|
|
|
//
|
|
// Make sure our header is positioned at the beginning of the file.
|
|
//
|
|
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
|
|
|
|
//
|
|
// Write out the header. Check to make sure that all was written
|
|
// succesfully.
|
|
//
|
|
bRet = WriteFile(hFile, &dbh, sizeof(DEVBIN_HEAD), &dwWr, NULL);
|
|
|
|
return ((bRet && (dwWr != sizeof(DEVBIN_HEAD))) ? FALSE : bRet);
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_ReadDevMode (Local Routine)
|
|
*
|
|
* Reads the devmode-structure from the BIN-File and sets the printer with
|
|
* the information. Since our data from the BIN-File is in the format
|
|
* of UNICODE, we must take care to only use (W) functions.
|
|
*
|
|
* Use : Processed in the context of the print-client.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL web_ReadDevMode(
|
|
LPDEVBIN_HEAD lpdbh,
|
|
HANDLE hPrinter,
|
|
LPCTSTR lpszPrtName)
|
|
{
|
|
LPDEVBIN_INFO lpdbi;
|
|
LPPRINTER_INFO_2W lppi;
|
|
LPDEVMODEW lpdm;
|
|
DWORD cbSize;
|
|
DWORD cbNeed;
|
|
BOOL bRet = FALSE;
|
|
|
|
//
|
|
// Set our pointer past the header. The DEVMODE always occupies the
|
|
// first entry in our item-list.
|
|
//
|
|
lpdbi = (LPDEVBIN_INFO)(lpdbh + 1);
|
|
|
|
//
|
|
// First let's see how big our buffer will need to
|
|
// be in order to hold the PRINTER_INFO_2W.
|
|
//
|
|
cbSize = 0;
|
|
GetPrinterW(hPrinter, 2, NULL, 0, &cbSize);
|
|
|
|
//
|
|
// Allocate storage for holding the print-info structure as well
|
|
// as the new devmode data we will be copying.
|
|
//
|
|
if (cbSize && (lppi = (LPPRINTER_INFO_2W)web_GAlloc(cbSize + lpdbi->cbData))) {
|
|
//
|
|
// Retrieve our current printer-settings.
|
|
//
|
|
if (GetPrinterW(hPrinter, 2, (LPBYTE)lppi, cbSize, &cbNeed)) {
|
|
//
|
|
// If our printer has a DEVMODE, then we can continue on
|
|
// with initializing it with our BIN-File DEVMODE. Otherwise,
|
|
// there's no sense setting a devmode to a printer that
|
|
// doesn't have one...return TRUE in this case.
|
|
//
|
|
if (lppi->pDevMode) {
|
|
//
|
|
// Set the new devmode pointer. We will be appending our
|
|
// DEVMODE (from the file) to the PRINTER_INFO_2 structure
|
|
// that we have just grabbed. Reset the pointers to
|
|
// reflect the new-position of the DEVMODE.
|
|
//
|
|
lppi->pDevMode = (LPDEVMODEW)(((LPBYTE)lppi) + cbSize);
|
|
lpdm = lppi->pDevMode;
|
|
|
|
//
|
|
// Copy our new devmode to the printer-info struct.
|
|
// This is appended on to the structure.
|
|
//
|
|
// Since this data was obtained by file, the pointer
|
|
// is actually a byte offset.
|
|
//
|
|
CopyMemory(lpdm,
|
|
((LPBYTE)lpdbi) + lpdbi->pData,
|
|
lpdbi->cbData);
|
|
|
|
//
|
|
// Copy the new printer-name to the DEVMODE. Since our
|
|
// routines deal strictly with unicode, we need to do
|
|
// the correct conversion in case this library was built
|
|
// as ansi.
|
|
//
|
|
#ifdef UNICODE
|
|
|
|
StringCchCopy(lpdm->dmDeviceName, CCHDEVICENAME, lpszPrtName);
|
|
#else
|
|
lpdm->dmDeviceName[CCHDEVICENAME - 1] = (WCHAR)0;
|
|
|
|
web_MBtoWC(lpdm->dmDeviceName,
|
|
lpszPrtName,
|
|
sizeof(lpdm->dmDeviceName) - sizeof(WCHAR));
|
|
#endif
|
|
//
|
|
// Write out our new printer-settings.
|
|
//
|
|
bRet = SetPrinterW(hPrinter, 2, (LPBYTE)lppi, 0);
|
|
|
|
} else {
|
|
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
web_GFree(lppi);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_ReadDevData (Local Routine)
|
|
*
|
|
* Reads the device-configuration-data from the BIN-File and sets the
|
|
* printer with the information.
|
|
*
|
|
* Use : Processed in the context of the print-client.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL web_ReadDevData(
|
|
LPDEVBIN_HEAD lpdbh,
|
|
HANDLE hPrinter)
|
|
{
|
|
LPDEVBIN_INFO lpdbi;
|
|
LPWSTR lpszKey;
|
|
LPWSTR lpszVal;
|
|
LPBYTE lpbData;
|
|
DWORD idx;
|
|
DWORD dwRet;
|
|
BOOL bRet;
|
|
|
|
PWSTR lpszNewKey = NULL;
|
|
PWSTR lpszNewVal = NULL;
|
|
PBYTE lpbNewData = NULL;
|
|
|
|
//
|
|
// Set our pointer past the header. The DEVMODE always occupies the
|
|
// first entry (If a DEVMODE exists).
|
|
//
|
|
lpdbi = (LPDEVBIN_INFO)(lpdbh + 1);
|
|
|
|
//
|
|
// If there's a DEVMODE, skip over it and point to the Printer-Data
|
|
// entries.
|
|
//
|
|
if (lpdbh->bDevMode)
|
|
lpdbi = web_NextItem(lpdbi);
|
|
|
|
//
|
|
// Loop through our items and set the data to the registry.
|
|
//
|
|
for (idx = 0, bRet = TRUE; (idx < lpdbh->cItems) && bRet; idx++) {
|
|
//
|
|
// Remarshall the byte-offsets into pointers.
|
|
//
|
|
lpszKey = (LPWSTR)(((LPBYTE)lpdbi) + lpdbi->pKey);
|
|
lpszVal = (LPWSTR)(((LPBYTE)lpdbi) + lpdbi->pValue);
|
|
lpbData = (LPBYTE)(((LPBYTE)lpdbi) + lpdbi->pData);
|
|
|
|
//
|
|
// We have to copy the data into a new buffer to avoid 64 bit mis-alignment.
|
|
//
|
|
lpszNewKey = new WCHAR[(lpdbi->pValue - lpdbi->pKey) / sizeof (WCHAR)];
|
|
lpszNewVal = new WCHAR[(lpdbi->pData - lpdbi->pValue) / sizeof (WCHAR)];
|
|
lpbNewData = new BYTE[lpdbi->cbData];
|
|
|
|
if (!lpszNewKey || !lpszVal || !lpbData)
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
else
|
|
{
|
|
CopyMemory (lpszNewKey, lpszKey, lpdbi->pValue - lpdbi->pKey);
|
|
CopyMemory (lpszNewVal, lpszVal, lpdbi->pData - lpdbi->pValue);
|
|
CopyMemory (lpbNewData, lpbData, lpdbi->cbData);
|
|
}
|
|
|
|
if (bRet)
|
|
{
|
|
//
|
|
// Set the printer-data. Since our file-format
|
|
// deals with UNICODE-strings, we will use the
|
|
// Wide-API.
|
|
//
|
|
dwRet = SetPrinterDataExW(hPrinter,
|
|
lpszNewKey,
|
|
lpszNewVal,
|
|
lpdbi->dwType,
|
|
lpbNewData,
|
|
lpdbi->cbData);
|
|
//
|
|
// If the data is set-correctly, then continue on
|
|
// to the next-item. Otherwise, set us up to return
|
|
// false.
|
|
//
|
|
if (dwRet == ERROR_SUCCESS) {
|
|
|
|
lpdbi = web_NextItem(lpdbi);
|
|
|
|
} else {
|
|
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
|
|
if (lpszNewKey)
|
|
{
|
|
delete [] lpszNewKey;
|
|
lpszNewKey = NULL;
|
|
}
|
|
|
|
if (lpszNewVal)
|
|
{
|
|
delete [] lpszNewVal;
|
|
lpszNewVal = NULL;
|
|
}
|
|
|
|
if (lpbNewData)
|
|
{
|
|
delete [] lpbNewData;
|
|
lpbNewData = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Once the registry is initialized with the printer-data, we need
|
|
// to parse the printer-data-registry for the ICM (CopyFiles), to
|
|
// initialize ICM profiles.
|
|
//
|
|
if (bRet && web_KeyExistsW(hPrinter, s_wszCopyFiles))
|
|
bRet = web_TraverseCopyFilesW(hPrinter, NULL, s_wszCopyFiles);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_WriteDevMode (Local Routine)
|
|
*
|
|
* Output the DEVMODEW struct to the BIN-File. Since we are storing this
|
|
* to a file, we make sure that our format is consistent across various
|
|
* processes. Our choice is to use UNICODE API as a means to query and store
|
|
* the DEVMODE information.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL web_WriteDevMode(
|
|
HANDLE hFile,
|
|
HANDLE hPrinter,
|
|
LPBOOL lpbDevMode)
|
|
{
|
|
DWORD cbSize;
|
|
DWORD cbNeed;
|
|
DWORD cbDevMode;
|
|
DWORD dwWr;
|
|
LPDEVBIN_INFO lpdbi;
|
|
LPPRINTER_INFO_2W lppi;
|
|
BOOL bRet = FALSE;
|
|
|
|
//
|
|
// Set the default return for a devmode.
|
|
//
|
|
*lpbDevMode = FALSE;
|
|
|
|
//
|
|
// Retrieve the size to store the printer-info-2 struct.
|
|
//
|
|
cbSize = 0;
|
|
GetPrinterW(hPrinter, 2, NULL, 0, &cbSize);
|
|
|
|
//
|
|
// Allocate the printer-info-2 struct and proceed
|
|
// to pull out the devmode information.
|
|
//
|
|
if (cbSize && (lppi = (LPPRINTER_INFO_2W)web_GAlloc(cbSize))) {
|
|
//
|
|
// Retreive the printer-info-2 and write out the
|
|
// DEVMODEW part of this structure.
|
|
//
|
|
if (GetPrinterW(hPrinter, 2, (LPBYTE)lppi, cbSize, &cbNeed)) {
|
|
//
|
|
// Allocate space for the devmode and our header information.
|
|
// Align this on DWORD boundries.
|
|
//
|
|
if (lppi->pDevMode) {
|
|
//
|
|
// The DEVMODE will need to include driver-specific
|
|
// information if such is stored in this DEVMODE.
|
|
//
|
|
cbDevMode = lppi->pDevMode->dmSize +
|
|
lppi->pDevMode->dmDriverExtra;
|
|
|
|
//
|
|
// Calculate the DWORD aligned size that we will need
|
|
// to store our DEVMODE information to file.
|
|
//
|
|
cbSize = web_AlignSize(sizeof(DEVBIN_INFO) + cbDevMode);
|
|
|
|
//
|
|
// Get the DEVMODE from the PRINTER_INFO_2 struct. and
|
|
// write to file. We want to take care to
|
|
//
|
|
if (lpdbi = (LPDEVBIN_INFO)web_GAlloc(cbSize)) {
|
|
//
|
|
// Setup our memory-block. The DEVMODEW will
|
|
// occupy the first item in the array. Since
|
|
// it's not associated with printer-data-information,
|
|
// we will not store any (NAME and TYPE).
|
|
//
|
|
// Since this structure will inevitably be written
|
|
// to file, we must marshall the pointers and store
|
|
// only byte-offsets.
|
|
//
|
|
lpdbi->cbSize = cbSize;
|
|
lpdbi->dwType = 0;
|
|
lpdbi->pKey = 0;
|
|
lpdbi->pValue = 0;
|
|
lpdbi->pData = sizeof(DEVBIN_INFO);
|
|
lpdbi->cbData = cbDevMode;
|
|
|
|
CopyMemory(((LPBYTE)lpdbi) + lpdbi->pData,
|
|
lppi->pDevMode,
|
|
cbDevMode);
|
|
|
|
//
|
|
// Write the information to file. Check the return
|
|
// to verify bytes were written correctly.
|
|
//
|
|
bRet = WriteFile(hFile, lpdbi, cbSize, &dwWr, NULL);
|
|
|
|
if (bRet && (dwWr != cbSize))
|
|
bRet = FALSE;
|
|
|
|
//
|
|
// Indicate that a devmode was written.
|
|
//
|
|
*lpbDevMode = TRUE;
|
|
|
|
|
|
web_GFree(lpdbi);
|
|
}
|
|
|
|
} else {
|
|
|
|
bRet = TRUE;
|
|
*lpbDevMode = FALSE;
|
|
}
|
|
}
|
|
|
|
web_GFree(lppi);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_WriteKeyItem (Local Routine)
|
|
*
|
|
* Writes one item to the file.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL web_WriteKeyItem(
|
|
HANDLE hFile,
|
|
LPCWSTR lpszKey,
|
|
LPPRINTER_ENUM_VALUES lpPEV)
|
|
{
|
|
DWORD cbKeySize;
|
|
DWORD cbKey;
|
|
DWORD cbName;
|
|
DWORD cbSize;
|
|
DWORD dwWr;
|
|
LPDEVBIN_INFO lpdbi;
|
|
BOOL bWrite = FALSE;
|
|
|
|
//
|
|
// Calculate aligned sizes for the key-name and key-value strings.
|
|
//
|
|
cbKeySize = web_StrSizeW(lpszKey);
|
|
cbKey = web_AlignSize(cbKeySize);
|
|
cbName = web_AlignSize(lpPEV->cbValueName);
|
|
|
|
//
|
|
// Calculate size necessary to hold our DEVBIN_INFO information
|
|
// which is written to file.
|
|
//
|
|
cbSize = sizeof(DEVBIN_INFO) + cbKey + cbName + web_AlignSize (lpPEV->cbData);
|
|
|
|
//
|
|
// Allocate space for the structure.
|
|
//
|
|
if (lpdbi = (LPDEVBIN_INFO)web_GAlloc(cbSize)) {
|
|
//
|
|
// Initialize the structure elements. Since this information
|
|
// is written to file, we must take care to convert the
|
|
// pointers to byte-offsets.
|
|
//
|
|
lpdbi->cbSize = cbSize;
|
|
lpdbi->dwType = lpPEV->dwType;
|
|
lpdbi->pKey = sizeof(DEVBIN_INFO);
|
|
lpdbi->pValue = lpdbi->pKey + cbKey;
|
|
lpdbi->pData = lpdbi->pValue + cbName;
|
|
lpdbi->cbData = lpPEV->cbData;
|
|
|
|
CopyMemory(((LPBYTE)lpdbi) + lpdbi->pKey , lpszKey , cbKeySize);
|
|
CopyMemory(((LPBYTE)lpdbi) + lpdbi->pValue, lpPEV->pValueName, lpPEV->cbValueName);
|
|
CopyMemory(((LPBYTE)lpdbi) + lpdbi->pData , lpPEV->pData , lpPEV->cbData);
|
|
|
|
bWrite = WriteFile(hFile, lpdbi, lpdbi->cbSize, &dwWr, NULL);
|
|
|
|
if (bWrite && (dwWr != lpdbi->cbSize))
|
|
bWrite = FALSE;
|
|
|
|
web_GFree(lpdbi);
|
|
}
|
|
|
|
return bWrite;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_WriteKeyData (Local Routine)
|
|
*
|
|
* Outputs the Printer-Configuration-Data to the BIN-File. This writes
|
|
* all info for the specified key.
|
|
*
|
|
* returns: number of items written to file.
|
|
* (-1) if an error occurs.
|
|
*
|
|
\*****************************************************************************/
|
|
int web_WriteKeyData(
|
|
HANDLE hFile,
|
|
HANDLE hPrinter,
|
|
LPCWSTR lpszKey)
|
|
{
|
|
LPPRINTER_ENUM_VALUES apevData;
|
|
BOOL bWr;
|
|
int idx;
|
|
int nItems = -1;
|
|
|
|
//
|
|
// Only write data if we are given a valid-key.
|
|
//
|
|
if ((lpszKey == NULL) || (*lpszKey == (WCHAR)0))
|
|
return 0;
|
|
|
|
//
|
|
// Enumerate all data for the specified key and write to the file.
|
|
//
|
|
if (apevData = web_EnumPrinterDataW(hPrinter, lpszKey, (LPDWORD)&nItems)) {
|
|
//
|
|
// Write all the values for this key.
|
|
//
|
|
for (idx = 0, bWr = TRUE; (idx < nItems) && bWr; idx++)
|
|
bWr = web_WriteKeyItem(hFile, lpszKey, apevData + idx);
|
|
|
|
if (bWr == FALSE)
|
|
nItems = -1;
|
|
|
|
web_GFree(apevData);
|
|
}
|
|
|
|
return nItems;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_WriteDevData (Local Routine)
|
|
*
|
|
* Recursively traverses the printer registry and writes out the settings
|
|
* to file.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL web_WriteDevData(
|
|
HANDLE hFile,
|
|
HANDLE hPrinter,
|
|
LPCWSTR lpszKey,
|
|
LPDWORD lpcItems)
|
|
{
|
|
LPWSTR aszSKeys;
|
|
LPWSTR lpszSKey;
|
|
LPWSTR lpszFKey;
|
|
DWORD dwRet;
|
|
INT cItems;
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
if (aszSKeys = web_EnumPrinterSubKeysW(hPrinter, lpszKey)) {
|
|
|
|
for (bRet = TRUE, lpszSKey = aszSKeys; *lpszSKey && bRet; ) {
|
|
|
|
if (lpszFKey = web_MakeFullKeyW(lpszKey, lpszSKey)) {
|
|
|
|
bRet = web_WriteDevData(hFile, hPrinter, lpszFKey, lpcItems);
|
|
|
|
web_GFree(lpszFKey);
|
|
}
|
|
|
|
lpszSKey = web_NextStrW(lpszSKey);
|
|
}
|
|
|
|
//
|
|
// Free up the array.
|
|
//
|
|
web_GFree(aszSKeys);
|
|
|
|
//
|
|
// Write the keys/values to the file.
|
|
//
|
|
if (bRet) {
|
|
|
|
cItems = web_WriteKeyData(hFile, hPrinter, lpszKey);
|
|
|
|
if (cItems >= 0)
|
|
*lpcItems += cItems;
|
|
else
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* web_ICMEnumCallBack (Local Routine)
|
|
*
|
|
* This routine takes the UNICODE (lpwszDir, lpwszFile) and converts it to
|
|
* the appropriate string prior to making the callback to the caller.
|
|
*
|
|
* Use : Processed in the context of the print-server.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL web_ICMEnumCallBack(
|
|
LPCWSTR lpwszDir,
|
|
LPCWSTR lpwszFile,
|
|
FARPROC fpEnum,
|
|
LPVOID lpParm)
|
|
{
|
|
LPTSTR lpszDir;
|
|
LPTSTR lpszFile;
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
if (lpszDir = web_WCtoTC(lpwszDir, lstrlenW(lpwszDir) + 1)) {
|
|
|
|
if (lpszFile = web_WCtoTC(lpwszFile, lstrlenW(lpwszFile) + 1)) {
|
|
|
|
bRet = (*(WEBENUMICMPROC)fpEnum)(lpszDir, lpszFile, lpParm);
|
|
|
|
web_GFree(lpszFile);
|
|
}
|
|
|
|
web_GFree(lpszDir);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_EnumFilesW (Local Routine)
|
|
*
|
|
* This routine enums the point & print "files" under the "copyfiles" path
|
|
* for the printer. This is called once we're at the end of a sub-key list
|
|
* in the registry.
|
|
*
|
|
* Use : Processed in the context of the print-server.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL web_EnumFilesW(
|
|
HANDLE hPrinter,
|
|
DWORD dwCliInfo,
|
|
LPCWSTR lpwszKey,
|
|
FARPROC fpEnum,
|
|
LPVOID lpParm)
|
|
{
|
|
LPWSTR awszFiles;
|
|
LPWSTR lpwszFile;
|
|
LPWSTR lpwszDir;
|
|
BOOL bRet = FALSE;
|
|
|
|
//
|
|
// For this ICM key, we will grab the list of ICM profiles that are
|
|
// necessary.
|
|
//
|
|
if (awszFiles = (LPWSTR)web_GetPrtDataW(hPrinter, lpwszKey, s_wszFil)) {
|
|
//
|
|
// Get the src-directory for the ICM profiles under the given key.
|
|
//
|
|
if (lpwszDir = web_BuildCopyDirW(hPrinter, dwCliInfo, lpwszKey)) {
|
|
|
|
for (bRet = TRUE, lpwszFile = awszFiles; *lpwszFile && bRet; ) {
|
|
//
|
|
// Make the callback to the caller. In order to do this,
|
|
// we must make sure our strings are in the appropriate
|
|
// format according to what the caller expects (ie. unicode
|
|
// or ansi).
|
|
//
|
|
bRet = web_ICMEnumCallBack(lpwszDir, lpwszFile, fpEnum, lpParm);
|
|
|
|
lpwszFile = web_NextStrW(lpwszFile);
|
|
}
|
|
|
|
web_GFree(lpwszDir);
|
|
}
|
|
|
|
web_GFree(awszFiles);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* web_EnumCopyFilesW (similar to TraverseCopyFiles) (Local Routine)
|
|
*
|
|
* This routine recursively traverses the printer-registry-settings for
|
|
* the CopyFiles keys. Since the API's used in this routine are only
|
|
* available in UNICODE, this should be a (W) type routine.
|
|
*
|
|
* Use : Processed in the context of the print-server.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL web_EnumCopyFilesW(
|
|
HANDLE hPrinter,
|
|
DWORD dwCliInfo,
|
|
LPCWSTR lpwszKey,
|
|
FARPROC fpEnum,
|
|
LPVOID lpParm)
|
|
{
|
|
LPWSTR awszSKeys;
|
|
LPWSTR lpwszSKey;
|
|
LPWSTR lpwszFKey;
|
|
DWORD dwType;
|
|
BOOL bRet = FALSE;
|
|
|
|
//
|
|
// Returns an array of keys stored under the printer registry.
|
|
//
|
|
if (awszSKeys = web_EnumPrinterSubKeysW(hPrinter, lpwszKey)) {
|
|
//
|
|
// For each key, look to see if it contains other sub-keys. We
|
|
// recursively traverse the registry until we hit a key with
|
|
// no sub-keys.
|
|
//
|
|
for (bRet = TRUE, lpwszSKey = awszSKeys; *lpwszSKey && bRet; ) {
|
|
|
|
bRet = FALSE;
|
|
//
|
|
// Since the enum-routine only returns relative key-values,
|
|
// we need to build the fully-qualified key-path.
|
|
//
|
|
if (lpwszFKey = web_MakeFullKeyW(lpwszKey, lpwszSKey)) {
|
|
|
|
bRet = web_EnumCopyFilesW(hPrinter,
|
|
dwCliInfo,
|
|
lpwszFKey,
|
|
fpEnum,
|
|
lpParm);
|
|
|
|
web_GFree(lpwszFKey);
|
|
}
|
|
|
|
//
|
|
// Next key in list.
|
|
//
|
|
lpwszSKey = web_NextStrW(lpwszSKey);
|
|
}
|
|
|
|
//
|
|
// Free up the array.
|
|
//
|
|
web_GFree(awszSKeys);
|
|
|
|
//
|
|
// Process the files for the specified key. If this
|
|
// is our top-level key (CopyFiles), then don't bother
|
|
// with the initialization. i.e. there should be no
|
|
// (module, files, directory) keys at this level.
|
|
//
|
|
if (bRet && lstrcmpiW(lpwszKey, s_wszCopyFiles))
|
|
bRet = web_EnumFilesW(hPrinter, dwCliInfo, lpwszKey, fpEnum, lpParm);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* webEnumPrinterInfo
|
|
*
|
|
* This routine enumerates the information stored in the registery. Depending
|
|
* upon the (dwType) passed in, it can enumerate different types of information.
|
|
*
|
|
* Use : Called from the Printer-Server to enumerate the copyfiles sections
|
|
* of the registry. This also provides a callback to allow the caller
|
|
* to trap the profiles so they may be added to the CAB list.
|
|
*
|
|
* Use : Called from the printer-server to enumerate ICM information.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL webEnumPrinterInfo(
|
|
HANDLE hPrinter,
|
|
DWORD dwCliInfo,
|
|
DWORD dwType,
|
|
FARPROC fpEnum,
|
|
LPVOID lpParm)
|
|
{
|
|
BOOL bEnum = TRUE;
|
|
|
|
//
|
|
// Call enumeration functions for various enumeration types.
|
|
//
|
|
switch (dwType) {
|
|
|
|
case WEB_ENUM_ICM:
|
|
if (web_KeyExistsW(hPrinter, s_wszCopyFiles))
|
|
bEnum = web_EnumCopyFilesW(hPrinter, dwCliInfo, s_wszCopyFiles, fpEnum, lpParm);
|
|
break;
|
|
|
|
default:
|
|
case WEB_ENUM_KEY: // NOT IMPLEMENTED
|
|
bEnum = FALSE;
|
|
}
|
|
|
|
return bEnum;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* webWritePrinterInfo
|
|
*
|
|
* This routine reads the DEVMODE and Configuration-Data from the specified
|
|
* printer, and writes this to a .BIN file.
|
|
*
|
|
* Use : Called from the printer-server to write the registry settings to file.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL webWritePrinterInfo(
|
|
HANDLE hPrinter,
|
|
LPCTSTR lpszBinFile)
|
|
{
|
|
HANDLE hFile;
|
|
BOOL bDevMode;
|
|
DWORD cItems;
|
|
BOOL bRet = FALSE;
|
|
|
|
//
|
|
// Open the BIN file for writing.
|
|
//
|
|
hFile = web_OpenFileWrite(lpszBinFile);
|
|
|
|
if (hFile && (hFile != INVALID_HANDLE_VALUE)) {
|
|
//
|
|
// Output the header. This basically reserves
|
|
// space at the beginning of the file to store
|
|
// the item-count.
|
|
//
|
|
if (web_WriteHeader(hFile, 0, FALSE)) {
|
|
//
|
|
// Write out the devmode-info.
|
|
//
|
|
if (web_WriteDevMode(hFile, hPrinter, &bDevMode)) {
|
|
//
|
|
// Write out devdata-info. The (cItems) indicates how
|
|
// many driver-specific entries were written.
|
|
//
|
|
cItems = 0;
|
|
if (web_WriteDevData(hFile, hPrinter, L"", &cItems))
|
|
bRet = web_WriteHeader(hFile, cItems, bDevMode);
|
|
}
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* webReadPrinterInfo
|
|
*
|
|
* This routine reads the DEVMODE and Configuration-Data from the specified
|
|
* BIN-File, and sets the printer-handle with the attributes.
|
|
*
|
|
* Use : Called from the printer-client to initialize the registry.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL webReadPrinterInfo(
|
|
HANDLE hPrinter,
|
|
LPCTSTR lpszPrtName,
|
|
LPCTSTR lpszBinFile)
|
|
{
|
|
HANDLE hMap;
|
|
LPDEVBIN_HEAD lpdbh;
|
|
BOOL bRet = FALSE;
|
|
|
|
//
|
|
// Open the BIN file for writing.
|
|
//
|
|
if (hMap = web_OpenMap(lpszBinFile)) {
|
|
|
|
if (lpdbh = (LPDEVBIN_HEAD)web_LockMap(hMap)) {
|
|
//
|
|
// Only if we have a DevMode should we write out the information.
|
|
//
|
|
if (!lpdbh->bDevMode || web_ReadDevMode(lpdbh, hPrinter, lpszPrtName)) {
|
|
//
|
|
// Only if we have printer-data items should we proceed
|
|
// to write out the information.
|
|
//
|
|
if (!lpdbh->cItems || web_ReadDevData(lpdbh, hPrinter)) {
|
|
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
web_UnlockMap((LPVOID)lpdbh);
|
|
}
|
|
|
|
web_CloseMap(hMap);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* WebPnpEntry
|
|
*
|
|
* This routine is called by PrintWizard prior to installing the printer.
|
|
* Currently, we can find no value to this, but it is a nice balance to the
|
|
* WebPnpPostEntry() routine.
|
|
*
|
|
* Use : Called from the print-client prior to printer installation.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL WebPnpEntry(
|
|
LPCTSTR lpszCmdLine)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
PrinterExists(
|
|
HANDLE hPrinter)
|
|
{
|
|
DWORD cbNeeded;
|
|
DWORD Error;
|
|
BOOL rc = FALSE;
|
|
LPPRINTER_INFO_2 pPrinter;
|
|
DWORD cbPrinter;
|
|
|
|
cbPrinter = 0x400;
|
|
pPrinter = (PPRINTER_INFO_2) web_GAlloc ( cbPrinter );
|
|
|
|
if( !pPrinter )
|
|
return FALSE;
|
|
|
|
if( !GetPrinter( hPrinter, 2, (LPBYTE)pPrinter, cbPrinter, &cbNeeded ) )
|
|
{
|
|
Error = GetLastError( );
|
|
|
|
if( Error == ERROR_INSUFFICIENT_BUFFER )
|
|
{
|
|
web_GFree (pPrinter);
|
|
pPrinter = (PPRINTER_INFO_2)web_GAlloc ( cbNeeded );
|
|
|
|
if( pPrinter )
|
|
{
|
|
cbPrinter = cbNeeded;
|
|
|
|
if( GetPrinter( hPrinter, 2, (LPBYTE)pPrinter, cbPrinter, &cbNeeded ) )
|
|
{
|
|
rc = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else if( Error == ERROR_INVALID_HANDLE )
|
|
{
|
|
SetLastError( ERROR_INVALID_PRINTER_NAME );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = TRUE;
|
|
}
|
|
|
|
|
|
if( pPrinter )
|
|
{
|
|
web_GFree ( pPrinter );
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* WebPnpPostEntry
|
|
*
|
|
* This routine is called via PrintWizard after a printer has been added. This
|
|
* provides the oportunity for the web-pnp-installer to initialize the
|
|
* registry settings and files according to the information provided in the
|
|
* BIN-File. The (fConnection) flag indicates whether the printer was
|
|
* installed via RPC or HTTP. If it was RPC, then it's not necessary to do
|
|
* any printer-settings.
|
|
*
|
|
* Use : Called from the print-client after printer installation.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL WebPnpPostEntry(
|
|
BOOL fConnection,
|
|
LPCTSTR lpszBinFile,
|
|
LPCTSTR lpszPortName,
|
|
LPCTSTR lpszPrtName)
|
|
{
|
|
HANDLE hPrinter;
|
|
PRINTER_DEFAULTS pd;
|
|
BOOL bRet = TRUE;
|
|
|
|
|
|
if (fConnection == FALSE) {
|
|
//
|
|
// Setup the printer-defaults to
|
|
// allow printer-changes.
|
|
//
|
|
pd.pDatatype = NULL;
|
|
pd.pDevMode = NULL;
|
|
pd.DesiredAccess = PRINTER_ALL_ACCESS;
|
|
|
|
//
|
|
// Open the printer specified.
|
|
//
|
|
if (OpenPrinter((LPTSTR)lpszPrtName, &hPrinter, &pd)) {
|
|
|
|
if (!PrinterExists(hPrinter) && GetLastError () == ERROR_ACCESS_DENIED) {
|
|
ConfigurePort( NULL, GetDesktopWindow (), (LPTSTR) lpszPortName);
|
|
}
|
|
|
|
bRet = webReadPrinterInfo(hPrinter, lpszPrtName, lpszBinFile);
|
|
|
|
ClosePrinter(hPrinter);
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|