windows-nt/Source/XPSP1/NT/printscan/print/spooler/wpnpinst/dll32/libpriv.cxx
2020-09-26 16:20:57 +08:00

1682 lines
43 KiB
C++

/*****************************************************************************\
* MODULE: libpriv.cxx
*
* Contains the source code for internal routines used throughout the library.
*
*
* Copyright (C) 1996-1998 Hewlett Packard Company.
* Copyright (C) 1996-1998 Microsoft Corporation.
*
* History:
* 10-Oct-1997 GFS Initial checkin
* 10-Jun-1998 CHW Cleaned. Restructured.
*
\*****************************************************************************/
#include "libpriv.h"
#define strFree(pszStr) {if (pszStr) GlobalFree((HANDLE)pszStr);}
/*****************************************************************************\
* strAlloc
*
* Allocates a string from the heap. This pointer must be freed with
* a call to strFree().
*
\*****************************************************************************/
LPTSTR strAlloc(
LPCTSTR pszSrc)
{
DWORD cbSize;
LPTSTR pszDst = NULL;
cbSize = (pszSrc ? ((lstrlen(pszSrc) + 1) * sizeof(TCHAR)) : 0);
if (cbSize) {
if (pszDst = (LPTSTR)GlobalAlloc(GPTR, cbSize))
CopyMemory(pszDst, pszSrc, cbSize);
}
return pszDst;
}
/*****************************************************************************\
* strLoad
*
* Get string from resource based upon the ID passed in.
*
\*****************************************************************************/
LPTSTR strLoad(
UINT ids)
{
char szStr[RES_BUFFER];
if (LoadString(g_hLibInst, ids, szStr, sizeof(szStr)) == 0)
szStr[0] = TEXT('\0');
return strAlloc(szStr);
}
/*****************************************************************************\
* InitStrings
*
*
\*****************************************************************************/
BOOL InitStrings(VOID)
{
g_szFmtName = strLoad(IDS_FMTNAME);
g_szMsgOptions = strLoad(IDS_MSG_OPTIONS);
g_szMsgThunkFail = strLoad(IDS_THUNK32FAIL);
g_szPrinter = strLoad(IDS_PRINTER);
g_szMsgExists = strLoad(IDS_ALREADY_EXISTS);
g_szMsgOptCap = strLoad(IDS_MSG_OPTCAP);
return (g_szFmtName &&
g_szMsgOptions &&
g_szMsgThunkFail &&
g_szPrinter &&
g_szMsgExists &&
g_szMsgOptCap
);
}
/*****************************************************************************\
* FreeeStrings
*
*
\*****************************************************************************/
VOID FreeStrings(VOID)
{
strFree(g_szFmtName);
strFree(g_szMsgOptions);
strFree(g_szMsgThunkFail);
strFree(g_szPrinter);
strFree(g_szMsgExists);
strFree(g_szMsgOptCap);
}
/*****************************************************************************\
* prv_StrChr
*
* Looks for the first location where (c) resides.
*
\*****************************************************************************/
LPTSTR prv_StrChr(
LPCTSTR cs,
TCHAR c)
{
while (*cs != TEXT('\0')) {
if (*cs == c)
return (LPTSTR)cs;
cs++;
}
// Fail to find c in cs.
//
return NULL;
}
/****************************************************************************\
* prv_CheesyHash
*
* Hash function to convert a string to dword representation.
*
\****************************************************************************/
DWORD prv_CheesyHash(
LPCTSTR lpszIn)
{
LPDWORD lpdwIn;
DWORD cbLeft;
DWORD dwTmp;
DWORD dwRet = 0;
if (lpszIn && (cbLeft = (lstrlen(lpszIn) * sizeof(TCHAR)))) {
// Process in DWORDs as long as possible
//
for (lpdwIn = (LPDWORD)lpszIn; cbLeft > sizeof(DWORD); cbLeft -= sizeof(DWORD)) {
dwRet ^= *lpdwIn++;
}
// Process bytes for whatever's left of the string.
//
if (cbLeft) {
for (dwTmp = 0, lpszIn = (LPTSTR)lpdwIn; *lpszIn; lpszIn++) {
dwTmp |= (DWORD)(TCHAR)(*lpszIn);
dwTmp <<= 8;
}
dwRet ^= dwTmp;
}
}
return dwRet;
}
/*****************************************************************************\
* prv_ParseHostShare
*
* Parses the FriendlyName (http://host/printers/share/.printer) into its
* Host/Share components.
*
* This routine returns allocated pointers that must be freed by the caller.
*
\*****************************************************************************/
BOOL prv_ParseHostShare(
LPCTSTR lpszFriendly,
LPTSTR *lpszHost,
LPTSTR *lpszShare)
{
LPTSTR lpszPrt;
LPTSTR lpszTmp;
LPTSTR lpszPos;
BOOL bRet = FALSE;
// Initialize the return buffers to NULL.
//
*lpszHost = NULL;
*lpszShare = NULL;
// Parse the host-name and the share name. The (lpszFriendly) is
// currently in the format of http://host[:portnumber]/share. We will
// parse this from left->right since the share-name can be a path (we
// wouldn't really know the exact length). However, we do know the
// location for the host-name, and anything after that should be
// the share-name.
//
// First find the ':'. The host-name should begin two "//" after
// that.
//
if (lpszPrt = memAllocStr(lpszFriendly)) {
if (lpszPos = prv_StrChr(lpszPrt, TEXT(':'))) {
lpszPos++;
lpszPos++;
lpszPos++;
// Get past the host.
//
if (lpszTmp = prv_StrChr(lpszPos, TEXT('/'))) {
// HostName (includes http).
//
*lpszTmp = TEXT('\0');
*lpszHost = memAllocStr(lpszPrt);
*lpszTmp = TEXT('/');
// ShareName.
//
if (lpszPos = prv_StrChr(++lpszTmp, TEXT('/'))) {
lpszPos++;
if (lpszTmp = prv_StrChr(lpszPos, TEXT('/'))) {
*lpszTmp = TEXT('\0');
*lpszShare = memAllocStr(lpszPos);
*lpszTmp = TEXT('/');
bRet = TRUE;
} else {
goto BadFmt;
}
} else {
goto BadFmt;
}
} else {
goto BadFmt;
}
} else {
BadFmt:
DBG_MSG(DBG_LEV_WARN, (TEXT("WPNPIN32 : prv_ParseHostShare - Invalid name <%s>"), lpszFriendly));
if (*lpszHost)
memFreeStr(*lpszHost);
if (*lpszShare)
memFreeStr(*lpszShare);
*lpszHost = NULL;
*lpszShare = NULL;
}
memFreeStr(lpszPrt);
}
return bRet;
}
/****************************************************************************\
* prv_StrPBrk
*
* DBCS-Aware version of strpbrk.
*
* NOTE: If this is ever converted/compiled as unicode, then this function
* is broken. It would need to be unicode-aware.
*
* 26-Jun-1998 : ChrisWil
*
\****************************************************************************/
LPTSTR prv_StrPBrk(
LPCTSTR lpszSrch,
LPCTSTR lpszTrgt)
{
LPTSTR lpszPtr;
if (lpszSrch && lpszTrgt) {
for( ; *lpszSrch; lpszSrch = AnsiNext(lpszSrch)) {
for (lpszPtr = (LPTSTR)lpszTrgt; *lpszPtr; lpszPtr = AnsiNext(lpszPtr)) {
if (*lpszSrch == *lpszPtr) {
// First byte matches--see if we need to check
// second byte
//
if (IsDBCSLeadByte(*lpszPtr)) {
if(*(lpszSrch + 1) == *(lpszPtr + 1))
return (LPTSTR)lpszSrch;
} else {
return (LPTSTR)lpszSrch;
}
}
}
}
}
return NULL;
}
/****************************************************************************\
* prv_BuildUniqueID
*
* Create a unique ID based on lpszModel/lpszPort/Timer.
*
\****************************************************************************/
DWORD prv_BuildUniqueID(
LPCTSTR lpszModel,
LPCTSTR lpszPort)
{
return ((prv_CheesyHash(lpszModel) ^ prv_CheesyHash(lpszPort)) ^ GetTickCount());
}
/****************************************************************************\
* prv_IsNameInUse
*
* Return whether the name is already in use by the print-subsystem.
*
\****************************************************************************/
BOOL prv_IsNameInUse(
LPCTSTR lpszName)
{
HANDLE hPrinter;
if (OpenPrinter((LPTSTR)lpszName, &hPrinter, NULL)) {
ClosePrinter(hPrinter);
return TRUE;
}
return FALSE;
}
/****************************************************************************\
* prv_CreateUniqueName
*
* Create a unique friendly name for this printer. If (idx) is 0, then
* copy the name from the base to the (lpszDst). Otherwise, play some
* games with truncating the name so it will fit.
*
\****************************************************************************/
BOOL prv_CreateUniqueName(
LPTSTR lpszDst,
LPCTSTR lpszBaseName,
DWORD idx)
{
TCHAR szBaseName[_MAX_NAME_];
int nFormatLength;
BOOL bSuccess = FALSE;
if (idx) {
// Create a unique friendly name for each instance.
// Start with:
// "%s %d" After LoadMessage
// "Short Model Name 2" After wsprintf or
// "Very very long long Model Nam 2" After wsprintf
//
// Since wsprintf has no concept of limiting the string size,
// truncate the model name (in a DBCS-aware fashion) to
// the appropriate size, so the whole string fits in _MAX_NAME_ bytes.
// This may cause some name truncation, but only in cases where
// the model name is extremely long.
// nFormatLength is length of string without the model name.
// If wInstance is < 10, format length is 2 (space + digit).
// If wInstance is < 100, format length is 3. Else format
// length is 4. Add 1 to compensate for the terminating NULL,
// which is counted in the total buffer length, but not the string
// length,
//
if (idx < 10) {
nFormatLength = 9 + 1;
} else if (idx < 100) {
nFormatLength = 10 + 1;
} else {
nFormatLength = 11 + 1;
}
// Truncate the base name, if necessary,
// then build the output string.
//
lstrcpyn(szBaseName, lpszBaseName, sizeof(szBaseName) - nFormatLength);
// there is already a copy 1 (undecorated base name)
//
wsprintf(lpszDst, g_szFmtName, (LPTSTR)szBaseName, (int)idx + 1);
bSuccess = TRUE;
} else {
lstrcpyn(lpszDst, lpszBaseName, _MAX_NAME_);
bSuccess = TRUE;
}
return bSuccess;
}
/****************************************************************************\
* prv_FindUniqueName
*
* Find a unique name that isn't already in use by the print subsystem.
* Base the name on the friendly name and an instance count.
*
* This will alter the lpszFriendly; even if function fails.
*
\****************************************************************************/
BOOL prv_FindUniqueName(
LPTSTR lpszFriendly)
{
// Since our http:// name is too long for W95, we're going
// to try basing our name off of the model-name.
//
// 28-Jun-1998 : ChrisWil
DWORD idx;
TCHAR *pszBase = NULL;
BOOL bRes = FALSE;
pszBase = memAllocStr( lpszFriendly );
if (!pszBase)
{
goto Cleanup;
}
// Iterate until we have found a unique name we can use.
//
for (idx = 0; idx < MAX_NAMES; idx++) {
prv_CreateUniqueName(lpszFriendly, pszBase, idx);
if (!prv_IsNameInUse(lpszFriendly))
{
bRes = TRUE;
goto Cleanup;
}
}
Cleanup:
if (pszBase)
{
memFreeStr( pszBase );
}
return bRes;
}
/****************************************************************************\
* prv_IsThisDriverInstalled
*
* Get the list of all installed printer drivers, and check to see
* if the current driver is in the list. If the driver is already
* installed, ask the user if we should keep the old one or install
* over the top of it.
*
* returns: RET_OK : OK.
* RET_ALLOC_ERROR : Out of memory.
* RET_DRIVER_NOT_FOUND : Can't find driver.
*
\****************************************************************************/
DWORD prv_IsThisDriverInstalled(
LPSI lpsi)
{
DWORD cbNeed;
DWORD cbSize;
DWORD cDrvs;
DWORD i;
BOOL bRet;
int iRes;
LPDRIVER_INFO_1 lpdi1;
DWORD dwRet = RET_DRIVER_NOT_FOUND;
// Get the size necessary to store the drivers.
//
cbSize = 0;
cDrvs = 0;
EnumPrinterDrivers((LPTSTR)NULL,
(LPTSTR)NULL,
1,
NULL,
0,
&cbSize,
&cDrvs);
// If we have drivers, then we can look for our installed driver.
//
if (cbSize && (lpdi1 = (LPDRIVER_INFO_1)memAlloc(cbSize))) {
bRet = EnumPrinterDrivers(NULL,
NULL,
1,
(LPBYTE)lpdi1,
cbSize,
&cbNeed,
&cDrvs);
if (bRet) {
for (i = 0; i < cDrvs; i++) {
if (lstrcmpi(lpsi->szModel, lpdi1[i].pName) == 0) {
dwRet = RET_DRIVER_FOUND;
break;
}
}
}
// Free up our allocated buffer.
//
memFree(lpdi1, cbSize);
// If found, then we need to request from the user whether
// to replace the driver.
//
if (dwRet == RET_DRIVER_FOUND) {
iRes = MessageBox(NULL,
g_szMsgExists,
lpsi->szModel,
MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON1);
if (iRes == IDNO)
dwRet = RET_DRIVER_NOT_FOUND;
else
dwRet = RET_OK;
}
}
return dwRet;
}
/****************************************************************************\
* prv_BuildPrinterInfo
*
* Allocate and/or initialize a PRINTER_INFO_2 structure from LPSI. Store
* the pointer in lpsi->lpPrinterInfo2.
*
* returns: RET_OK : OK.
* RET_ALLOC_ERROR : Out of memory.
*
\****************************************************************************/
DWORD prv_BuildPrinterInfo(
LPSI lpsi)
{
LPPRINTER_INFO_2 lppi2;
// This code path is always executed just before we call
// AddPrinter. Fill in anything we don't already have.
//
// Allocate memory if we need it.
//
if (lpsi->lpPrinterInfo2 == NULL) {
lpsi->lpPrinterInfo2 = (LPBYTE)memAlloc(sizeof(PRINTER_INFO_2));
}
// Fill in the lppi2.
//
if (lppi2 = (LPPRINTER_INFO_2)lpsi->lpPrinterInfo2) {
lppi2->pPrinterName = lpsi->szFriendly;
lppi2->pPortName = lpsi->szPort;
lppi2->pDriverName = lpsi->szModel;
lppi2->pPrintProcessor = lpsi->szPrintProcessor;
lppi2->pDatatype = lpsi->szDefaultDataType;
lppi2->Priority = DEF_PRIORITY;
lppi2->Attributes = 0;
// Slow Machine?
//
if (0x0002 & GetSystemMetrics(SM_SLOWMACHINE))
lppi2->Attributes |= PRINTER_ATTRIBUTE_QUEUED;
// Point & Print case--make sure that the devmode we use to
// add the printer locally contains the local friendly name
// and not the friendly name it had on the server
//
if (lppi2->pDevMode) {
lstrcpyn((LPSTR)lppi2->pDevMode->dmDeviceName,
lpsi->szFriendly,
sizeof(lppi2->pDevMode->dmDeviceName));
}
} else {
return RET_ALLOC_ERR;
}
return RET_OK;
}
/****************************************************************************\
* prv_InstallPrinter
*
* Install the printer identified by LPSI. If the printer exists, then
* call SetPrinter(). Otherwise, call AddPrinter().
*
* returns: RET_OK : OK.
* RET_ALLOC_ERROR : Out of memory.
* RET_ADD_PRINTER_ERROR : Can't add printer.
*
\****************************************************************************/
DWORD prv_InstallPrinter(
LPSI lpsi)
{
DWORD dwRet;
PRINTER_INFO_5 pi5;
LPPRINTER_INFO_2 lppi2 = NULL;
HANDLE hPrinter = NULL;
BOOL bRes = FALSE;
// BuildPrinterInfo will allocate an lppi2 and attach it to lpsi
//
if ((dwRet = prv_BuildPrinterInfo(lpsi)) == RET_OK) {
lppi2 = (LPPRINTER_INFO_2)lpsi->lpPrinterInfo2;
dwRet = RET_ADD_PRINTER_ERROR;
hPrinter = AddPrinter(NULL, 2, (LPBYTE)lppi2);
DBG_ASSERT((hPrinter != NULL), (TEXT("WPNPIN32: prv_InstallPrinter - Failed AddPrinter")));
}
if (hPrinter) {
// Set the transmission & retry timeouts--remember that the
// subsystem values are in milliseconds!
//
ZeroMemory(&pi5, sizeof(PRINTER_INFO_5));
pi5.pPrinterName = lpsi->szFriendly;
pi5.DeviceNotSelectedTimeout = lpsi->wDNSTimeout * ONE_SECOND;
pi5.TransmissionRetryTimeout = lpsi->wRetryTimeout * ONE_SECOND;
pi5.pPortName = lppi2->pPortName;
pi5.Attributes = lppi2->Attributes;
SetPrinter(hPrinter, 5, (LPBYTE)&pi5, 0);
// Set the printer's unique ID so we can delete it correctly later
//
if (lpsi->dwUniqueID = prv_BuildUniqueID(lpsi->szModel, lpsi->szPort)) {
SetPrinterData(hPrinter,
(LPTSTR)g_szUniqueID,
REG_BINARY,
(LPBYTE)&lpsi->dwUniqueID,
sizeof(DWORD));
}
ClosePrinter(hPrinter);
dwRet = RET_OK;
}
// We don't need lpPrinterInfo2 anymore.
//
if (lpsi->lpPrinterInfo2) {
memFree(lpsi->lpPrinterInfo2, sizeof(PRINTER_INFO_2));
lpsi->lpPrinterInfo2 = NULL;
}
// We don't need lpDriverInfo3 anymore
//
if (lpsi->lpDriverInfo3) {
memFree(lpsi->lpDriverInfo3, memGetSize(lpsi->lpDriverInfo3));
lpsi->lpDriverInfo3 = NULL;
}
return dwRet;
}
/****************************************************************************\
* prv_BuildDriverInfo
*
* Allocate and initialize a DRIVER_INFO_3 for lpsi.
* driver dependent files be copied to the printer-driver-directory.
*
\****************************************************************************/
BOOL prv_BuildDriverInfo(
LPSI lpsi)
{
LPDRIVER_INFO_3 lpdi3;
// This code path is always executed before we call AddPrinterDriver.
// Set up any data that we don't already have. We always work with
// a DRIVER_INFO_3 on this pass.
//
// Allocate memory, if we need it.
//
if (lpsi->lpDriverInfo3 == NULL) {
lpsi->lpDriverInfo3 = (LPBYTE)memAlloc(sizeof(DRIVER_INFO_3));
}
// Fill in the lpdi3;
//
if (lpdi3 = (LPDRIVER_INFO_3)lpsi->lpDriverInfo3) {
lpdi3->cVersion = (DWORD)lpsi->dwDriverVersion;
lpdi3->pName = lpsi->szModel;
lpdi3->pEnvironment = (LPTSTR)g_szEnvironment;
lpdi3->pDriverPath = lpsi->szDriverFile;
lpdi3->pDataFile = lpsi->szDataFile;
lpdi3->pConfigFile = lpsi->szConfigFile;
lpdi3->pHelpFile = lpsi->szHelpFile;
lpdi3->pDefaultDataType = lpsi->szDefaultDataType;
if (lpsi->wFilesUsed && lpsi->lpFiles)
lpdi3->pDependentFiles = (LPSTR)lpsi->lpFiles;
else
lpdi3->pDependentFiles = NULL;
}
return (lpsi->lpDriverInfo3 ? TRUE : FALSE);
}
/****************************************************************************\
* prv_InstallPrinProcessor
*
* Copy the print processor file associated with this driver
* into the print processor directory and then add it to the
* print sub-system. Do not overwrite an existing print
* processor of the same name.
*
\****************************************************************************/
DWORD prv_InstallPrintProcessor(
LPSI lpsi,
LPCTSTR pszPath)
{
DWORD dwRet = RET_OK;
LPTSTR lpPrintProcessorDLL;
DWORD pcbNeeded;
TCHAR buf[_MAX_PATH_];
TCHAR *pszBuf = NULL;
TCHAR *pszTemp = NULL;
int cbLength = 0;
int cbBufLength = 0;
// Add the print processor if required
//
if (lpPrintProcessorDLL = prv_StrPBrk(lpsi->szPrintProcessor, g_szComma)) {
*lpPrintProcessorDLL++ = TEXT('\0');
lstrcpy(buf, g_szNull);
cbLength = lstrlen(pszPath) + lstrlen(g_szBackslash) + lstrlen(lpPrintProcessorDLL) + 1;
if (cbLength)
{
pszTemp = memAlloc( cbLength * sizeof(TCHAR) );
}
if (!pszTemp)
{
dwRet = RET_ALLOC_ERR;
goto Cleanup;
}
// get the source file
//
lstrcpy(pszTemp, pszPath);
lstrcat(pszTemp, g_szBackslash);
lstrcat(pszTemp, lpPrintProcessorDLL);
// The DLL must be in the PrintProcessorDirectory
//
GetPrintProcessorDirectory(NULL,
NULL,
1,
(LPBYTE)buf,
sizeof(buf),
&pcbNeeded);
cbBufLength = lstrlen(buf) + lstrlen(g_szBackslash) + lstrlen(lpPrintProcessorDLL) + 1;
if (cbBufLength)
{
pszBuf = memAlloc( cbBufLength * sizeof(TCHAR) );
}
if (!pszBuf)
{
dwRet = RET_ALLOC_ERR;
goto Cleanup;
}
lstrcpy(pszBuf, buf);
lstrcat(pszBuf, g_szBackslash);
lstrcat(pszBuf, lpPrintProcessorDLL);
// Copy the file, but don't overwrite an existing copy of it
//
CopyFile(lpPrintProcessorDLL, pszBuf, TRUE);
AddPrintProcessor(NULL,
(LPTSTR)g_szEnvironment,
lpPrintProcessorDLL,
lpsi->szPrintProcessor);
} else {
DBG_MSG(DBG_LEV_ERROR, (TEXT("WPNPIN32 : No PrintProcessor to add")));
}
Cleanup:
if (pszTemp)
{
memFree(pszTemp, cbLength * sizeof(TCHAR) );
}
if (pszBuf)
{
memFree(pszBuf, cbBufLength * sizeof(TCHAR) );
}
return dwRet;
}
/****************************************************************************\
* prv_GetDriverVersion
*
* Confirm that the driver identified in lpsi is indeed a
* valid printer driver, and determine which version it
* is. Leave the driver loaded for performance reasons
* (since it will get loaded at least twice more).
*
\****************************************************************************/
DWORD prv_GetDriverVersion(
LPSI lpsi,
LPTSTR pszPath)
{
UINT wOldErrorMode;
HINSTANCE hDrv = NULL;
TCHAR *pszTemp = NULL;
INT cbLength = 0;
DWORD idError = RET_INVALID_DLL;
wOldErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX);
cbLength = lstrlen(pszPath);
if (cbLength > 0) {
cbLength += lstrlen(g_szBackslash) + lstrlen(lpsi->szDriverFile) + 1;
pszTemp = memAlloc( cbLength * sizeof(TCHAR));
if (!pszTemp)
{
idError = RET_ALLOC_ERR;
goto Cleanup;
}
lstrcpy(pszTemp, pszPath);
lstrcat(pszTemp, g_szBackslash);
lstrcat(pszTemp, lpsi->szDriverFile);
} else {
cbLength = lstrlen(lpsi->szDriverFile) + 1;
pszTemp = memAlloc( cbLength * sizeof(TCHAR));
if (!pszTemp)
{
idError = RET_ALLOC_ERR;
goto Cleanup;
}
lstrcpy(pszTemp, lpsi->szDriverFile);
}
// Load the library.
//
hDrv = LoadLibrary(pszTemp);
SetErrorMode(wOldErrorMode);
if (hDrv) {
// We successfully loaded the DLL, now we want to confirm that it's
// a printer driver and get its version. We get ourselves into
// all sorts of trouble by calling into the driver before it's
// actually installed, so simply key off the exported functions.
//
idError = RET_OK;
if (GetProcAddress(hDrv, g_szExtDevModePropSheet)) {
lpsi->dwDriverVersion = 0x0400;
} else if (GetProcAddress(hDrv, g_szExtDevMode)) {
lpsi->dwDriverVersion = 0x0300;
} else if (GetProcAddress(hDrv, g_szDevMode)) {
lpsi->dwDriverVersion = 0x0200;
} else {
lpsi->dwDriverVersion = 0x0000;
idError = RET_INVALID_PRINTER_DRIVER;
}
FreeLibrary(hDrv);
}
Cleanup:
if (pszTemp)
{
memFree(pszTemp, cbLength * sizeof(TCHAR));
}
return idError;
}
/****************************************************************************\
* prv_UpdateICM
*
* Add color profiles to the registry.
*
\****************************************************************************/
BOOL prv_UpdateICM(
LPTSTR lpFiles)
{
TCHAR szPath[_MAX_PATH_];
TCHAR szColor[RES_BUFFER];
UINT wLength;
UINT wColorLength;
LPTSTR lpTemp = szPath;
LPTSTR lpLast = NULL;
BOOL bReturn = FALSE;
// Nothing to do if the dependent file list is NULL or empty
//
if (lpFiles && *lpFiles) {
// Add any color profiles that are referenced by this device.
// First, get the system directory & make sure that it ends
// in a backslash
//
wLength = GetSystemDirectory(szPath, sizeof(szPath));
while (lpLast = prv_StrPBrk(lpTemp, g_szBackslash)) {
lpTemp = lpLast + 1;
if (*lpTemp == TEXT('\0'))
break;
}
if (!lpLast) {
lstrcat(szPath, g_szBackslash);
wLength++;
}
lpLast = szPath + wLength;
// Get the comparison string for the path.
//
if (!LoadString(g_hLibInst, IDS_COLOR_PATH, szColor, RES_BUFFER)) {
lstrcpy(szColor, g_szColorPath);
}
wColorLength = lstrlen(szColor);
lpTemp = lpFiles;
// Now walk down the list of files & compare the beginning of the
// string to "COLOR\\". If it matches, assume that this is a color
// profile and notify the system that it's changing.
//
while (*lpTemp) {
UINT wTempLength = lstrlen(lpTemp);
if (wTempLength > wColorLength) {
BYTE bOldByte = lpTemp[wColorLength];
int nMatch;
lpTemp[wColorLength] = TEXT('\0');
nMatch = lstrcmpi(lpTemp, szColor);
lpTemp[wColorLength] = bOldByte;
if (!nMatch) {
lstrcpy(lpLast, lpTemp);
bReturn |= UpdateICMRegKey(0, 0, szPath, ICM_ADDPROFILE);
}
}
lpTemp += (wTempLength+1);
}
}
return bReturn;
}
/****************************************************************************\
* prv_InstallPrinterDriver
*
* Install a printer-driver into the subsystem. This requires that all
* driver dependent files be copied to the printer-driver-directory.
*
*
* returns: RET_OK : OK.
* RET_USER_CANCEL : User cancelled driver install.
* RET_BROWSE_ERROR : User hits cancel key in browse dialog.
*
\****************************************************************************/
DWORD prv_InstallPrinterDriver(
LPSI lpsi,
HWND hWnd)
{
BOOL bSuccess = FALSE;
DWORD dwResult = RET_OK;
CHAR szPath[_MAX_PATH_];
if (lpsi->wCommand == CMD_INSTALL_DRIVER) {
// Get the driver version
//
if ( _getcwd(szPath, _MAX_PATH_) == NULL)
lstrcpy(szPath, ".");
lpsi->dwDriverVersion = 0;
dwResult = prv_GetDriverVersion(lpsi, szPath);
if (dwResult != RET_OK) {
DBG_MSG(DBG_LEV_ERROR, (TEXT("WPNPIN32 : prv_GetDriverVersion Failed")));
// The AddPrinterDriver code will check the version
// number. I think.
//
lpsi->dwDriverVersion = 0x0400;
}
// Install the printprocessor if one is provided.
//
prv_InstallPrintProcessor(lpsi, szPath);
// Build the driver-info.
//
if (prv_BuildDriverInfo(lpsi)) {
if (!(bSuccess = AddPrinterDriver(NULL, 3, lpsi->lpDriverInfo3))) {
if (ERROR_PRINTER_DRIVER_ALREADY_INSTALLED == GetLastError()) {
bSuccess = TRUE;
}
}
}
if (bSuccess) {
prv_UpdateICM(((LPDRIVER_INFO_3)(lpsi->lpDriverInfo3))->pDependentFiles);
}
}
return RET_OK;
}
/*****************************************************************************\
* GetCommandLineArgs(LPSI, LPCTSTR)
*
* Parse the DAT file to retrieve Web PnP Install options.
*
* LPCWSTR is the name of the dat file. The dat file contains:
*
* /i
* /x Web Print calls
* /b Printer name lpsi*>szFriendly
* /f inf file lpsi*>INFfileName
* /r Port name lpsi*>szPort
* /m Printer model lpsi*>szModel
* /n Share name lpsi*>ShareName
* /a Bin file lpsi*>BinName
*
\*****************************************************************************/
int GetCommandLineArgs(
LPSI lpsi,
LPCTSTR lpDatFile)
{
int i;
int count = 0;
DWORD bytesRead = 0;
LPTSTR lpstrCmd;
HANDLE hFile = NULL;
WCHAR wideBuf[1024];
TCHAR buf[1024];
UCHAR ch;
DBG_MSG(DBG_LEV_INFO, (TEXT("The File to be Read - %s"), lpDatFile));
hFile = CreateFile(lpDatFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if ((hFile == NULL) || (hFile == INVALID_HANDLE_VALUE))
return 0;
i = ReadFile(hFile, (LPVOID)wideBuf, sizeof(wideBuf), &bytesRead, NULL);
CloseHandle(hFile);
if ( i == 0 || bytesRead == 0 )
return 0;
DBG_MSG(DBG_LEV_INFO, (TEXT("Number bytes read - %lu"), bytesRead));
// convert wide buffer to MBCS
//
lstrcpy(buf, g_szNull);
i = WideCharToMultiByte(CP_ACP,
0,
wideBuf,
-1,
buf,
sizeof(buf),
NULL,
NULL);
if (i == 0) {
DBG_MSG(DBG_LEV_ERROR, (TEXT("WPNPIN32: ParseCmdLineArgs: Faild MBCS convert")));
return 0; // 0 args parsed
}
// Our dat-file is in unicode format, so we need to skip over the FFFE
// signature at the beginning of the file.
//
lpstrCmd = buf;
ch = *lpstrCmd++;
ch = *lpstrCmd++;
// skip over any white space
//
while (isspace(ch))
ch = *lpstrCmd++;
DBG_MSG(DBG_LEV_INFO, (TEXT("UCHAR N: %#X"), ch));
// process each switch character '/' or '-' as encountered
//
while (ch == TEXT('/') || ch == TEXT('-')) {
ch = (UCHAR)tolower(*lpstrCmd++);
// process multiple switch characters as needed
//
switch (ch) {
case TEXT('a'): // .bin file name
ch = *lpstrCmd++;
// skip over any following white space
while (isspace(ch)) {
ch = *lpstrCmd++;
}
if (ch != TEXT('"')) {
DBG_MSG(DBG_LEV_WARN, (TEXT("WPNPIN32: Args - Invalid BinFile Name (/a)")));
return RET_INVALID_DAT_FILE;
} else {
// skip over quote
ch = *lpstrCmd++;
// copy the name
i = 0;
while (ch != TEXT('"') && ch != TEXT('\0')) {
lpsi->BinName[i++] = ch;
ch = *lpstrCmd++;
}
lpsi->BinName[i] = TEXT('\0');
if (ch != TEXT('\0'))
ch = *lpstrCmd++;
count++;
}
break;
case TEXT('b'): // printer name
ch = *lpstrCmd++;
// skip over any following white space
while (isspace(ch)) {
ch = *lpstrCmd++;
}
if (ch != TEXT('"')) {
DBG_MSG(DBG_LEV_WARN, (TEXT("WPNPIN32: Args - Invalid Printer Name (/b)")));
return RET_INVALID_DAT_FILE;
} else {
// skip over quote
ch = *lpstrCmd++;
// copy the name
i = 0;
while (ch != TEXT('"') && ch != TEXT('\0')) {
lpsi->szFriendly[i++] = ch;
ch = *lpstrCmd++;
}
lpsi->szFriendly[i] = TEXT('\0');
if (ch != TEXT('\0'))
ch = *lpstrCmd++;
count++;
}
break;
case TEXT('f'): // INF file name
ch = *lpstrCmd++;
// skip over any following white space
while (isspace(ch)) {
ch = *lpstrCmd++;
}
if (ch != TEXT('"')) {
DBG_MSG(DBG_LEV_WARN, (TEXT("WPNPIN32: Args - Invalid InfFile Name (/f)")));
return RET_INVALID_DAT_FILE;
} else {
// skip over quote
ch = *lpstrCmd++;
// copy the name
i = 0;
while (ch != TEXT('"') && ch != TEXT('\0'))
{
lpsi->INFfileName[i++] = ch;
ch = *lpstrCmd++;
}
lpsi->INFfileName[i] = TEXT('\0');
if (ch != '\0')
ch = *lpstrCmd++;
count++;
}
break;
case TEXT('i'): // unknown
ch = *lpstrCmd++; // 'f'
if (ch != TEXT('\0'))
ch = *lpstrCmd++; // space
count++;
break;
case TEXT('m'): // printer model
ch = *lpstrCmd++;
// skip over any following white space
while (isspace(ch)) {
ch = *lpstrCmd++;
}
if (ch != '"') {
DBG_MSG(DBG_LEV_WARN, (TEXT("WPNPIN32: Args - Invalid PrinterModel Name (/m)")));
return RET_INVALID_DAT_FILE;
} else {
// skip over quote
ch = *lpstrCmd++;
// copy the name
i = 0;
while (ch != TEXT('"') && ch != TEXT('\0'))
{
lpsi->szModel[i++] = ch;
ch = *lpstrCmd++;
}
lpsi->szModel[i] = TEXT('\0');
if (ch != TEXT('\0'))
ch = *lpstrCmd++;
count++;
}
break;
case TEXT('n'): // share name
ch = *lpstrCmd++;
// skip over any following white space
while (isspace(ch)) {
ch = *lpstrCmd++;
}
if (ch != TEXT('"')) {
DBG_MSG(DBG_LEV_WARN, (TEXT("WPNPIN32: Args - Invalid Share Name (/n)")));
return RET_INVALID_DAT_FILE;
} else {
// skip over quote
ch = *lpstrCmd++;
// copy the name
i = 0;
while (ch != TEXT('"') && ch != TEXT('\0'))
{
lpsi->ShareName[i++] = ch;
ch = *lpstrCmd++;
}
lpsi->ShareName[i] = TEXT('\0');
if (ch != TEXT('\0'))
ch = *lpstrCmd++;
count++;
}
break;
case TEXT('r'): // port name
ch = *lpstrCmd++;
// skip over any following white space
while (isspace(ch)) {
ch = *lpstrCmd++;
}
if (ch != TEXT('"')) {
DBG_MSG(DBG_LEV_WARN, (TEXT("WPNPIN32: Args - Invalid Port Name (/r)")));
return RET_INVALID_DAT_FILE;
} else {
// skip over quote
ch = *lpstrCmd++;
// copy the name
i = 0;
while (ch != TEXT('"') && ch != TEXT('\0'))
{
lpsi->szPort[i++] = ch;
ch = *lpstrCmd++;
}
lpsi->szPort[i] = TEXT('\0');
if (ch != TEXT('\0'))
ch = *lpstrCmd++;
count++;
}
break;
case TEXT('x'): // unknown
ch = *lpstrCmd++;
count++;
break;
case TEXT('?'): // help
MessageBox(NULL, g_szMsgOptions, g_szMsgOptCap, MB_OK);
break;
default: /* invalid option */
DBG_MSG(DBG_LEV_WARN, (TEXT("WPNPIN32: Args - Invalid Option")));
break;
} //switch
while (isspace(ch))
ch = *lpstrCmd++;
} // while / or -
return count;
}
/****************************************************************************\
* PrintLPSI
*
* Print out the contents of the LPSI structure.
*
\****************************************************************************/
VOID prv_PrintLPSI(
LPSI lpsi)
{
DBG_MSG(DBG_LEV_INFO, (TEXT("LPSI Structure Dump")));
DBG_MSG(DBG_LEV_INFO, (TEXT("-------------------")));
DBG_MSG(DBG_LEV_INFO, (TEXT("dwDriverVersion : %#lX"), lpsi->dwDriverVersion ));
DBG_MSG(DBG_LEV_INFO, (TEXT("dwUniqueID : %d") , lpsi->dwUniqueID ));
DBG_MSG(DBG_LEV_INFO, (TEXT("bNetPrinter : %d") , lpsi->bNetPrinter ));
DBG_MSG(DBG_LEV_INFO, (TEXT("wFilesUsed : %d") , lpsi->wFilesUsed ));
DBG_MSG(DBG_LEV_INFO, (TEXT("wFilesAllocated : %d") , lpsi->wFilesAllocated ));
DBG_MSG(DBG_LEV_INFO, (TEXT("wRetryTimeout : %d") , lpsi->wRetryTimeout ));
DBG_MSG(DBG_LEV_INFO, (TEXT("wDNSTimeout : %d") , lpsi->wDNSTimeout ));
DBG_MSG(DBG_LEV_INFO, (TEXT("bDontQueueFiles : %d") , lpsi->bDontQueueFiles ));
DBG_MSG(DBG_LEV_INFO, (TEXT("bNoTestPage : %d") , lpsi->bNoTestPage ));
DBG_MSG(DBG_LEV_INFO, (TEXT("hModelInf : %d") , lpsi->hModelInf ));
DBG_MSG(DBG_LEV_INFO, (TEXT("lpPrinterInfo2 : %d") , lpsi->lpPrinterInfo2 ));
DBG_MSG(DBG_LEV_INFO, (TEXT("lpDriverInfo3 : %d") , lpsi->lpDriverInfo3 ));
DBG_MSG(DBG_LEV_INFO, (TEXT("szFriendly : %s") , lpsi->szFriendly ));
DBG_MSG(DBG_LEV_INFO, (TEXT("szModel : %s") , lpsi->szModel ));
DBG_MSG(DBG_LEV_INFO, (TEXT("szDefaultDataType : %s") , lpsi->szDefaultDataType));
DBG_MSG(DBG_LEV_INFO, (TEXT("BinName : %s") , lpsi->BinName ));
DBG_MSG(DBG_LEV_INFO, (TEXT("ShareName : %s") , lpsi->ShareName ));
DBG_MSG(DBG_LEV_INFO, (TEXT("INFfileName : %s") , lpsi->INFfileName ));
DBG_MSG(DBG_LEV_INFO, (TEXT("szPort : %s") , lpsi->szPort ));
DBG_MSG(DBG_LEV_INFO, (TEXT("szDriverFile : %s") , lpsi->szDriverFile ));
DBG_MSG(DBG_LEV_INFO, (TEXT("szDataFile : %s") , lpsi->szDataFile ));
DBG_MSG(DBG_LEV_INFO, (TEXT("szConfigFile : %s") , lpsi->szConfigFile ));
DBG_MSG(DBG_LEV_INFO, (TEXT("szHelpFile : %s") , lpsi->szHelpFile ));
DBG_MSG(DBG_LEV_INFO, (TEXT("szPrintProcessor : %s") , lpsi->szPrintProcessor ));
DBG_MSG(DBG_LEV_INFO, (TEXT("szVendorSetup : %s") , lpsi->szVendorSetup ));
DBG_MSG(DBG_LEV_INFO, (TEXT("szVendorInstaller : %s") , lpsi->szVendorInstaller));
#if 0
DWORD cch;
PTSTR pszFile;
DBG_MSG(DBG_LEV_INFO, (TEXT("Files:")));
DBG_MSG(DBG_LEV_INFO, (TEXT("------")));
for (cch = 0, pszFile = lpsi->lpFiles; *pszFile; pszFile += cch)
DBG_MSG(DBG_LEV_INFO, (TEXT("%s"), pszFile);
#endif
}
/****************************************************************************\
* AddOnePrinter
*
* Add a single printer (including the driver and print-processor).
*
\****************************************************************************/
DWORD AddOnePrinter(
LPSI lpsi,
HWND hWnd)
{
DWORD dwResult = RET_OK;
DWORD cbNeeded;
TCHAR ch;
TCHAR srcINF[_MAX_PATH_];
#if 1 // Since our http:// name is too long for W95, we're going
// to try basing our name off of the model-name.
//
// 28-Jun-1998 : ChrisWil
lstrcpy(lpsi->szFriendly, lpsi->szModel);
#endif
// Build a unique-name from the friendly-name.
//
if (prv_FindUniqueName(lpsi->szFriendly)) {
// Determine if we need to add a new driver. If there is already a
// driver for this printer, ask if the user wants to re-install or
// use the old one.
//
if ((dwResult = prv_IsThisDriverInstalled(lpsi)) == RET_OK) {
lpsi->wCommand = 0;
} else if (dwResult == RET_DRIVER_NOT_FOUND) {
// Set it up to install the printer driver.
//
lpsi->wCommand = CMD_INSTALL_DRIVER;
dwResult = RET_OK;
DBG_MSG(DBG_LEV_INFO, (TEXT("WPNPIN32 : AddOnePrinter - Driver Will be installed")));
}
// We need info about the driver even if we don't plan to
// install/re-install it
//
if (dwResult == RET_OK) {
// Get current directory and prepend to INF file name
//
if ( _getcwd(srcINF, _MAX_PATH_) == NULL)
lstrcpy(srcINF, g_szDot);
lstrcat(srcINF, g_szBackslash);
lstrcat(srcINF, lpsi->INFfileName);
lstrcpy(lpsi->INFfileName, srcINF);
// Get the Printer driver directory and store in lpsi->szRes
// This is used for copying the files
//
GetPrinterDriverDirectory(NULL,
NULL,
1,
(LPBYTE)lpsi->szDriverDir,
sizeof(lpsi->szDriverDir),
&cbNeeded);
// Parse the INF file and store info in lpsi. This will
// add the driver to the print subsystem.
//
if ((dwResult = ParseINF16(lpsi)) != RET_OK) {
DBG_MSG(DBG_LEV_ERROR, (TEXT("WPNPIN32 : ParseINF16 - Failed")));
}
}
// Install the printer-driver. This routine will verify if the
// (lpsi->wCommand indicates whether the driver should be installed.
//
if (dwResult == RET_OK)
dwResult = prv_InstallPrinterDriver(lpsi, hWnd);
// Install the Printer.
//
if (dwResult == RET_OK)
dwResult = prv_InstallPrinter(lpsi);
} else {
DBG_MSG(DBG_LEV_ERROR, (TEXT("WPNPIN32 : AddOnePrinter : UniqueName failure")));
dwResult = RET_NO_UNIQUE_NAME;
}
// Debug output of LPSI.
//
prv_PrintLPSI(lpsi);
// Clean up memory.
//
if (lpsi->lpPrinterInfo2) {
memFree(lpsi->lpPrinterInfo2, memGetSize(lpsi->lpPrinterInfo2));
lpsi->lpPrinterInfo2 = NULL;
}
if (lpsi->lpDriverInfo3) {
memFree(lpsi->lpDriverInfo3, memGetSize(lpsi->lpDriverInfo3));
lpsi->lpDriverInfo3 = NULL;
}
if (lpsi->lpFiles) {
HP_GLOBAL_FREE(lpsi->lpFiles);
lpsi->lpFiles = NULL;
}
if (lpsi->lpVcpInfo) {
HP_GLOBAL_FREE(lpsi->lpVcpInfo);
lpsi->lpVcpInfo = NULL;
}
return dwResult;
}
/*****************************************************************************\
* prvMsgBox
*
* Displays a string-id in a messagebox.
*
\*****************************************************************************/
UINT prvMsgBox(
HWND hWnd,
LPCTSTR lpszCap,
UINT idTxt,
UINT fMB)
{
LPTSTR pszTxt;
UINT uRet = 0;
if (pszTxt = strLoad(idTxt)) {
uRet = MessageBox(hWnd, pszTxt, lpszCap, fMB);
strFree(pszTxt);
}
return uRet;
}