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.
1426 lines
36 KiB
1426 lines
36 KiB
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
print.c
|
|
|
|
Abstract:
|
|
|
|
This file implements basic printer functionality
|
|
|
|
Author:
|
|
|
|
Asaf Shaar (asafs) 28-Nov-1999
|
|
|
|
Environment:
|
|
|
|
User Mode
|
|
|
|
--*/
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <tchar.h>
|
|
#include <WinSpool.h>
|
|
|
|
#include <faxutil.h>
|
|
#include <faxreg.h>
|
|
#include <shlobj.h>
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wrapper function for EnumPrinters API
|
|
|
|
Arguments:
|
|
|
|
pServerName - Server name (NULL for current server)
|
|
dwLevel - Specifies PRINTER_INFO level to be returned
|
|
pcPrinters - Returns the number of printers found
|
|
dwFlags - Specifies the type of printer objects to be enumerated
|
|
|
|
level -
|
|
pCount -
|
|
|
|
Return Value:
|
|
|
|
Pointer to an array of PRINTER_INFO_x structures
|
|
NULL if there is an error
|
|
|
|
--*/
|
|
|
|
PVOID
|
|
MyEnumPrinters(
|
|
LPTSTR pServerName,
|
|
DWORD dwLevel,
|
|
PDWORD pcPrinters,
|
|
DWORD dwFlags
|
|
)
|
|
{
|
|
PBYTE pPrinterInfo = NULL;
|
|
DWORD cb = 0;
|
|
DWORD Error = ERROR_SUCCESS;
|
|
|
|
if (!dwFlags)
|
|
{
|
|
dwFlags = PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS;
|
|
}
|
|
|
|
if (!EnumPrinters(dwFlags, pServerName, dwLevel, NULL, 0, &cb, pcPrinters))
|
|
{
|
|
Error = GetLastError();
|
|
|
|
if ( Error == ERROR_INSUFFICIENT_BUFFER && (pPrinterInfo = (PBYTE) MemAlloc(cb)) != NULL)
|
|
{
|
|
if (EnumPrinters(dwFlags, pServerName, dwLevel, pPrinterInfo, cb, &cb, pcPrinters))
|
|
{
|
|
return pPrinterInfo;
|
|
}
|
|
Error = GetLastError();
|
|
}
|
|
}
|
|
|
|
MemFree(pPrinterInfo);
|
|
SetLastError(Error);
|
|
return NULL;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the name of the first Fax printer on the local machine:
|
|
for LOCAL fax printer use GetFirstLocalFaxPrinterName.
|
|
for REMOTE fax printer use GetFirstRemoteFaxPrinterName.
|
|
|
|
Arguments:
|
|
|
|
OUT lptstrPrinterName - A buffer to hold the returned printer name.
|
|
IN dwPrintNameInChars - The size of the buffer in characters (including the space for terminating null)
|
|
Return Value:
|
|
TRUE if the function succeeded and found a fax printer.
|
|
FALSE if the function failed or did not find a fax printer.
|
|
If a printer was not found then GetLastError() will report ERROR_PRINTER_NOT_FOUND.
|
|
|
|
--*/
|
|
BOOL
|
|
GetFirstFaxPrinterName(
|
|
OUT LPTSTR lptstrPrinterName,
|
|
IN DWORD dwMaxLenInChars,
|
|
IN DWORD dwFlag)
|
|
{
|
|
PPRINTER_INFO_2 pPrinterInfo = NULL;
|
|
DWORD dwNumPrinters;
|
|
DWORD dwPrinter;
|
|
DWORD ec = ERROR_SUCCESS;
|
|
|
|
DEBUG_FUNCTION_NAME(TEXT("GetFirstFaxPrinterName"));
|
|
|
|
SetLastError (ERROR_SUCCESS);
|
|
pPrinterInfo = (PPRINTER_INFO_2) MyEnumPrinters(NULL,
|
|
2,
|
|
&dwNumPrinters,
|
|
dwFlag
|
|
);
|
|
if (!pPrinterInfo)
|
|
{
|
|
//
|
|
// Either error on no printers
|
|
//
|
|
ec = GetLastError();
|
|
if (ERROR_SUCCESS == ec)
|
|
{
|
|
//
|
|
// Not an error - no printers
|
|
//
|
|
SetLastError (ERROR_PRINTER_NOT_FOUND);
|
|
return FALSE;
|
|
}
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("MyEnumPrinters() failed (ec: %ld)"),
|
|
ec);
|
|
goto Error;
|
|
}
|
|
|
|
for (dwPrinter=0; dwPrinter < dwNumPrinters; dwPrinter++)
|
|
{
|
|
if (!_tcscmp(pPrinterInfo[dwPrinter].pDriverName,FAX_DRIVER_NAME))
|
|
{
|
|
memset(lptstrPrinterName,0,dwMaxLenInChars*sizeof(TCHAR));
|
|
_tcsncpy(lptstrPrinterName,pPrinterInfo[dwPrinter].pPrinterName,dwMaxLenInChars-1);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
ec = ERROR_PRINTER_NOT_FOUND;
|
|
goto Error;
|
|
|
|
|
|
Error:
|
|
Assert (ERROR_SUCCESS != ec);
|
|
Exit:
|
|
MemFree(pPrinterInfo);
|
|
pPrinterInfo = NULL;
|
|
if (ERROR_SUCCESS != ec)
|
|
{
|
|
SetLastError(ec);
|
|
return FALSE;
|
|
}
|
|
return (ERROR_SUCCESS == ec);
|
|
|
|
}
|
|
|
|
BOOL
|
|
GetFirstLocalFaxPrinterName(
|
|
OUT LPTSTR lptstrPrinterName,
|
|
IN DWORD dwMaxLenInChars)
|
|
{
|
|
return GetFirstFaxPrinterName(lptstrPrinterName,dwMaxLenInChars,PRINTER_ENUM_LOCAL);
|
|
}
|
|
|
|
BOOL
|
|
GetFirstRemoteFaxPrinterName(
|
|
OUT LPTSTR lptstrPrinterName,
|
|
IN DWORD dwMaxLenInChars)
|
|
{
|
|
return GetFirstFaxPrinterName(lptstrPrinterName,dwMaxLenInChars,PRINTER_ENUM_CONNECTIONS);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
// Function: GetPrinterInfo
|
|
// Description: Returns a pointer to PRINTER_INFO_2 of the specified printer name.
|
|
// If the printer was not found or there was an error than the function
|
|
// return NULL. To get extended error information, call GetLastError().
|
|
//
|
|
// Remarks: The caller must release the allocated memory with MemFree()
|
|
//
|
|
// Args: LPTSTR lptstrPrinterName : The name of the printer.
|
|
//
|
|
// Author: AsafS
|
|
|
|
|
|
|
|
PPRINTER_INFO_2
|
|
GetFaxPrinterInfo(
|
|
LPCTSTR lptstrPrinterName
|
|
)
|
|
{
|
|
DEBUG_FUNCTION_NAME(TEXT("GetPrinterInfo"))
|
|
DWORD ec = ERROR_SUCCESS;
|
|
|
|
PPRINTER_INFO_2 pPrinterInfo = NULL;
|
|
DWORD dwNeededSize = 0;
|
|
BOOL result = FALSE;
|
|
|
|
HANDLE hPrinter = NULL;
|
|
|
|
if (!OpenPrinter(
|
|
(LPTSTR) lptstrPrinterName,
|
|
&hPrinter,
|
|
NULL))
|
|
{
|
|
ec = GetLastError();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("A printer with %s name was not found (ec: %ld)."),
|
|
lptstrPrinterName,
|
|
GetLastError()
|
|
);
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
result = GetPrinter(
|
|
hPrinter,
|
|
2,
|
|
NULL,
|
|
0,
|
|
&dwNeededSize
|
|
);
|
|
|
|
if (!result)
|
|
{
|
|
if ( (ec = GetLastError()) != ERROR_INSUFFICIENT_BUFFER )
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("GetPrinter return an unexpected result or error (ec: %ld)."),
|
|
ec
|
|
);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
pPrinterInfo = (PPRINTER_INFO_2) MemAlloc(dwNeededSize);
|
|
if (!pPrinterInfo)
|
|
{
|
|
ec = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
result = GetPrinter(
|
|
hPrinter,
|
|
2,
|
|
(LPBYTE) pPrinterInfo,
|
|
dwNeededSize,
|
|
&dwNeededSize
|
|
);
|
|
|
|
if (!result)
|
|
{
|
|
ec = GetLastError();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("GetPrinter failed in second call (ec: %ld)."),
|
|
ec
|
|
);
|
|
MemFree(pPrinterInfo);
|
|
pPrinterInfo = NULL;
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
SetLastError(ec);
|
|
|
|
if (hPrinter)
|
|
{
|
|
if (!ClosePrinter(hPrinter))
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("ClosePrinter failed with %ld"),
|
|
GetLastError ()
|
|
);
|
|
}
|
|
}
|
|
return pPrinterInfo;
|
|
} // GetFaxPrinterInfo
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// Function:
|
|
// IsPrinterFaxPrinter
|
|
//
|
|
// Purpose: determines whether the input printer name is a valid
|
|
// fax printer by checking the driver name
|
|
//
|
|
// Params:
|
|
// LPTSTR PrinterName - printer name to evaluate
|
|
//
|
|
// Return Value:
|
|
// TRUE - printer is a valid fax printer
|
|
// FALSE - otherwise
|
|
//
|
|
// Author:
|
|
// Mooly Beery (MoolyB) 21-Aug-2001
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
BOOL IsPrinterFaxPrinter(LPTSTR PrinterName)
|
|
{
|
|
DWORD Rval = FALSE;
|
|
LPPRINTER_INFO_2 lpPrinterInfo = NULL;
|
|
|
|
DEBUG_FUNCTION_NAME(TEXT("IsPrinterFaxPrinter"))
|
|
|
|
lpPrinterInfo = GetFaxPrinterInfo(PrinterName);
|
|
if (lpPrinterInfo==NULL)
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,_T("GetFaxPrinterInfo failed with %ld."),GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
if (_tcscmp( lpPrinterInfo->pDriverName, FAX_DRIVER_NAME ) == 0)
|
|
{
|
|
Rval = TRUE;
|
|
}
|
|
else
|
|
{
|
|
Rval = FALSE;
|
|
}
|
|
|
|
MemFree( lpPrinterInfo );
|
|
return Rval;
|
|
}
|
|
|
|
|
|
DWORD
|
|
IsLocalFaxPrinterInstalled(
|
|
LPBOOL lpbLocalFaxPrinterInstalled
|
|
)
|
|
/*++
|
|
|
|
Routine name : IsLocalFaxPrinterInstalled
|
|
|
|
Routine description:
|
|
|
|
Checks if a local fax printer is installed and not marked for deletion.
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), Jul, 2000
|
|
|
|
Arguments:
|
|
|
|
lpbLocalFaxPrinterInstalled [out] - Result flag
|
|
|
|
Return Value:
|
|
|
|
Standard Win32 error code
|
|
|
|
--*/
|
|
{
|
|
TCHAR tszPrinterName[MAX_PATH * 3] = TEXT("\0");
|
|
DWORD dwErr;
|
|
PPRINTER_INFO_2 pi2 = NULL;
|
|
DEBUG_FUNCTION_NAME(TEXT("IsLocalFaxPrinterInstalled"))
|
|
|
|
if (!GetFirstLocalFaxPrinterName (tszPrinterName, sizeof (tszPrinterName) / sizeof (tszPrinterName[0])))
|
|
{
|
|
dwErr = GetLastError ();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("GetFirstLocalFaxPrinterName failed with %ld."),
|
|
dwErr);
|
|
if (ERROR_PRINTER_NOT_FOUND == dwErr)
|
|
{
|
|
//
|
|
// Local fax printer is not installed
|
|
//
|
|
*lpbLocalFaxPrinterInstalled = FALSE;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
Assert (ERROR_SUCCESS != dwErr);
|
|
return dwErr;
|
|
}
|
|
//
|
|
// Local fax printer is installed
|
|
// Let's see if it is PRINTER_STATUS_PENDING_DELETION.
|
|
// If so, let's return FALSE because the printer will be gone soon.
|
|
// If someone will call AddPrinter because we return FALSE, it's OK. See AddPrinter() remarks.
|
|
//
|
|
Assert (lstrlen (tszPrinterName));
|
|
pi2 = GetFaxPrinterInfo (tszPrinterName);
|
|
if (!pi2)
|
|
{
|
|
dwErr = GetLastError ();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("GetFaxPrinterInfo failed with %ld."),
|
|
dwErr);
|
|
//
|
|
// Printer is installed but somehow I can't get it's info - weird
|
|
//
|
|
Assert (ERROR_SUCCESS != dwErr);
|
|
return dwErr;
|
|
}
|
|
if ((pi2->Status) & PRINTER_STATUS_PENDING_DELETION)
|
|
{
|
|
//
|
|
// Printer is there but is marked for deletion
|
|
//
|
|
DebugPrintEx(
|
|
DEBUG_MSG,
|
|
TEXT("Printer %s is installed but marked for deletion. Reported as non-existant"),
|
|
tszPrinterName);
|
|
*lpbLocalFaxPrinterInstalled = FALSE;
|
|
}
|
|
else
|
|
{
|
|
*lpbLocalFaxPrinterInstalled = TRUE;
|
|
}
|
|
MemFree (pi2);
|
|
return ERROR_SUCCESS;
|
|
} // IsLocalFaxPrinterInstalled
|
|
|
|
|
|
DWORD
|
|
IsLocalFaxPrinterShared (
|
|
LPBOOL lpbShared
|
|
)
|
|
/*++
|
|
|
|
Routine name : IsLocalFaxPrinterShared
|
|
|
|
Routine description:
|
|
|
|
Detects if the local fax printer is shared
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), Jul, 2000
|
|
|
|
Arguments:
|
|
|
|
lpbShared [out] - Sharing flag
|
|
|
|
Return Value:
|
|
|
|
Standard Win32 error code
|
|
|
|
--*/
|
|
{
|
|
TCHAR tszPrinterName[MAX_PATH * 3];
|
|
DWORD dwErr;
|
|
PPRINTER_INFO_2 pInfo2;
|
|
DEBUG_FUNCTION_NAME(TEXT("IsLocalFaxPrinterShared"))
|
|
|
|
if (!GetFirstLocalFaxPrinterName (tszPrinterName, sizeof (tszPrinterName) / sizeof (tszPrinterName[0])))
|
|
{
|
|
dwErr = GetLastError ();
|
|
if (ERROR_PRINTER_NOT_FOUND == dwErr)
|
|
{
|
|
//
|
|
// Local fax printer is not installed
|
|
//
|
|
*lpbShared = FALSE;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("GetFirstLocalFaxPrinterName failed with %ld."),
|
|
dwErr);
|
|
return dwErr;
|
|
}
|
|
pInfo2 = GetFaxPrinterInfo (tszPrinterName);
|
|
if (!pInfo2)
|
|
{
|
|
dwErr = GetLastError ();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("GetFaxPrinterInfo failed with %ld."),
|
|
dwErr);
|
|
return dwErr;
|
|
}
|
|
*lpbShared = ((pInfo2->Attributes) & PRINTER_ATTRIBUTE_SHARED) ? TRUE : FALSE;
|
|
MemFree (pInfo2);
|
|
return ERROR_SUCCESS;
|
|
} // IsLocalFaxPrinterShared
|
|
|
|
DWORD
|
|
AddLocalFaxPrinter (
|
|
LPCTSTR lpctstrPrinterName,
|
|
LPCTSTR lpctstrPrinterDescription
|
|
)
|
|
/*++
|
|
|
|
Routine name : AddLocalFaxPrinter
|
|
|
|
Routine description:
|
|
|
|
Adds a local fax printer
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), Jul, 2000
|
|
|
|
Arguments:
|
|
|
|
lpctstrPrinterName [in] - Printer name
|
|
lpctstrPrinterDescription [in] - Printer comments (description)
|
|
|
|
Return Value:
|
|
|
|
Standard Win32 error code
|
|
|
|
Remarks:
|
|
|
|
This function should not be called if a local fax printer is installed.
|
|
|
|
--*/
|
|
{
|
|
DWORD ec = ERROR_SUCCESS;
|
|
HANDLE hPrinter = NULL;
|
|
PRINTER_INFO_2 PrinterInfo2 = {0};
|
|
BOOL bLocalPrinterInstalled;
|
|
BOOL bIsFaxPrinterShared = FALSE;
|
|
DWORD dwAttributes = PRINTER_ATTRIBUTE_LOCAL | PRINTER_ATTRIBUTE_FAX;
|
|
LPCTSTR lpctstrShareName = NULL;
|
|
|
|
DEBUG_FUNCTION_NAME(TEXT("AddLocalFaxPrinter"))
|
|
|
|
ec = IsLocalFaxPrinterInstalled (&bLocalPrinterInstalled);
|
|
if (ERROR_SUCCESS == ec && bLocalPrinterInstalled)
|
|
{
|
|
//
|
|
// Local fax printer already installed
|
|
//
|
|
return ec;
|
|
}
|
|
//
|
|
// Check if this is SKU supports fax sharing.
|
|
// If it does not - do not share printer.
|
|
//
|
|
if (IsFaxShared())
|
|
{
|
|
// We can share the printer on this SKU. Let's check if Fax is
|
|
// installed in Sharing enabled mode.
|
|
HKEY hFaxKey = OpenRegistryKey(HKEY_LOCAL_MACHINE,REGKEY_FAX_SETUP,FALSE,KEY_READ);
|
|
if (hFaxKey)
|
|
{
|
|
if (GetRegistryDword(hFaxKey,REGVAL_IS_SHARED_FAX_PRINTER))
|
|
{
|
|
DebugPrintEx(DEBUG_MSG, TEXT("Fax is installed in a mode that enables sharing"));
|
|
bIsFaxPrinterShared = TRUE;
|
|
}
|
|
else
|
|
{
|
|
DebugPrintEx(DEBUG_MSG, TEXT("Fax is installed in a mode that does not enable sharing"));
|
|
}
|
|
RegCloseKey(hFaxKey);
|
|
}
|
|
else
|
|
{
|
|
DebugPrintEx(DEBUG_WRN, TEXT("Failed to open REGKEY_FAX_SETUP, printer won't be shared (ec=%d)"),GetLastError());
|
|
}
|
|
}
|
|
|
|
if (bIsFaxPrinterShared)
|
|
{
|
|
dwAttributes |= PRINTER_ATTRIBUTE_SHARED;
|
|
lpctstrShareName = lpctstrPrinterName;
|
|
}
|
|
|
|
PrinterInfo2.pServerName = NULL;
|
|
PrinterInfo2.pPrinterName = (LPTSTR) lpctstrPrinterName;
|
|
PrinterInfo2.pPortName = FAX_MONITOR_PORT_NAME;
|
|
PrinterInfo2.pDriverName = FAX_DRIVER_NAME;
|
|
PrinterInfo2.pPrintProcessor = TEXT("WinPrint");
|
|
PrinterInfo2.pDatatype = TEXT("RAW");
|
|
PrinterInfo2.Attributes = dwAttributes;
|
|
PrinterInfo2.pShareName = (LPTSTR) lpctstrShareName;
|
|
PrinterInfo2.pComment = (LPTSTR) lpctstrPrinterDescription;
|
|
|
|
hPrinter = AddPrinter(NULL,
|
|
2,
|
|
(LPBYTE)&PrinterInfo2);
|
|
|
|
if (hPrinter == NULL)
|
|
{
|
|
ec = GetLastError();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("AddPrinter failed with %ld."),
|
|
ec);
|
|
}
|
|
else
|
|
{
|
|
if (IsFaxShared() && bIsFaxPrinterShared)
|
|
{
|
|
//
|
|
// Publish the printer in the DS
|
|
//
|
|
PRINTER_INFO_7 pi7;
|
|
pi7.pszObjectGUID = NULL;
|
|
pi7.dwAction = DSPRINT_PUBLISH;
|
|
|
|
if (!SetPrinter(hPrinter, // handle to printer object
|
|
7, // information level
|
|
(LPBYTE)&pi7, // printer data buffer
|
|
0 // printer-state command
|
|
))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,TEXT("SetPrinter failed with %ld."),GetLastError());
|
|
//
|
|
// In any case we do not want to fail the whole setup just because we were
|
|
// unable to publish the printer on the DS.
|
|
// common error codes are:
|
|
//
|
|
// ERROR_IO_PENDING means SetPrinter is trying to publish the printer in the
|
|
// background, we do not wait for it to succeed/fail.
|
|
//
|
|
// ERROR_DS_UNAVAILABLE means the DS is not accesible.
|
|
//
|
|
}
|
|
}
|
|
if (!ClosePrinter(hPrinter))
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("ClosePrinter failed with %ld."),
|
|
GetLastError ());
|
|
}
|
|
hPrinter = NULL;
|
|
RefreshPrintersAndFaxesFolder();
|
|
}
|
|
return ec;
|
|
} // AddLocalFaxPrinter
|
|
|
|
|
|
//*********************************************************************************
|
|
//* Name: ParamTagsToString()
|
|
//* Author: Ronen Barenboim
|
|
//* Date: March 23, 1999
|
|
//*********************************************************************************
|
|
//* DESCRIPTION:
|
|
//* Writes a collection of tag parameters and values in the format of a parameter
|
|
//* string into a caller provided buffer.
|
|
// Reports the size of the tagged string.
|
|
//* PARAMETERS:
|
|
//* lpTagMap
|
|
//* A pointer to an array of FAX_TAG_MAP_ENTRY structures that contain the
|
|
//* tag names and values.
|
|
//* dwTagCount
|
|
//* The number of entries in the tag map array.
|
|
//* lpTargetBuf
|
|
//* A pointer to a buffer where the tag value string will be placed.
|
|
//* The size of this buffer must be big enough to hold the resulting string
|
|
// including a terminating NULL char.
|
|
//* If this parameter is NULL the function will not generate the tag value
|
|
//* string and only report its size in *lpdwSize;
|
|
//* lpdwSize
|
|
//* A pointer to a DWORD that will accept the size of the resulting
|
|
//* tagged string in BYTES. The size DOES NOT INCLUDE the terminating NULL char.
|
|
//* RETURN VALUE:
|
|
//* NONE
|
|
//* REMARKS:
|
|
//* The format of the resulting string is:
|
|
//* Tag1Value1Tag2Value2....TagNValueN'\0'
|
|
//*********************************************************************************
|
|
void
|
|
ParamTagsToString(
|
|
FAX_TAG_MAP_ENTRY * lpTagMap,
|
|
DWORD dwTagCount,
|
|
LPTSTR lpTargetBuf,
|
|
LPDWORD lpdwSize)
|
|
{
|
|
DWORD index;
|
|
LPTSTR p;
|
|
|
|
DWORD dwSize = 0;
|
|
|
|
//
|
|
// Calculate string size WITHOUT termianting NULL
|
|
//
|
|
for (index=0; index <dwTagCount; index++)
|
|
{
|
|
if (lpTagMap[index].lptstrValue && !IsEmptyString(lpTagMap[index].lptstrValue))
|
|
{
|
|
dwSize += _tcslen(lpTagMap[index].lptstrTagName)*sizeof(TCHAR) + _tcslen(lpTagMap[index].lptstrValue)*sizeof(TCHAR);
|
|
}
|
|
}
|
|
|
|
if (lpTargetBuf)
|
|
{
|
|
//
|
|
// Check that size of the Target Buffer is not smaller then the calculated size
|
|
//
|
|
Assert(dwSize <= *lpdwSize);
|
|
//
|
|
// Assemble fax job parameters into a single tagged string at the target buffer
|
|
// there is a terminating NULL at the end of the string !!!
|
|
//
|
|
p=lpTargetBuf;
|
|
|
|
for (index=0; index < dwTagCount; index++)
|
|
{
|
|
if (lpTagMap[index].lptstrValue && !IsEmptyString(lpTagMap[index].lptstrValue))
|
|
{
|
|
_tcscpy(p, lpTagMap[index].lptstrTagName);
|
|
p += _tcslen(p); // The value string runs over the NULL char of the tag string
|
|
_tcscpy(p, lpTagMap[index].lptstrValue);
|
|
p += _tcslen(p);
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Return the size of the string
|
|
//
|
|
*lpdwSize = dwSize;
|
|
}
|
|
|
|
HRESULT
|
|
RefreshPrintersAndFaxesFolder ()
|
|
/*++
|
|
|
|
Routine name : RefreshPrintersAndFaxesFolder
|
|
|
|
Routine description:
|
|
|
|
Notifies the 'Printers and Faxes' shell folder to refresh itself
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), Mar, 2001
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
Standard HRESULT
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
LPITEMIDLIST pidlPF = NULL;
|
|
LPMALLOC pShellMalloc = NULL;
|
|
DEBUG_FUNCTION_NAME(TEXT("RefreshPrintersAndFaxesFolder"));
|
|
|
|
//
|
|
// First obtail the shell alloctaor
|
|
//
|
|
hr = SHGetMalloc (&pShellMalloc);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get the printer's folder PIDL
|
|
//
|
|
hr = SHGetSpecialFolderLocation(NULL, CSIDL_PRINTERS, &pidlPF);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Requets refresh
|
|
//
|
|
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_IDLIST | SHCNF_FLUSH | SHCNF_FLUSHNOWAIT, pidlPF, NULL);
|
|
//
|
|
// Release the returned PIDL by using the shell allocator
|
|
//
|
|
pShellMalloc->Free(pidlPF);
|
|
}
|
|
//
|
|
// Release the shell allocator
|
|
//
|
|
pShellMalloc->Release();
|
|
}
|
|
return hr;
|
|
} // RefreshPrintersAndFaxesFolder
|
|
|
|
#ifdef UNICODE
|
|
|
|
PPRINTER_NAMES
|
|
CollectPrinterNames (
|
|
LPDWORD lpdwNumPrinters,
|
|
BOOL bFilterOutFaxPrinters
|
|
)
|
|
/*++
|
|
|
|
Routine name : CollectPrinterNames
|
|
|
|
Routine description:
|
|
|
|
Creates a list of printer names for all visible local and remote printers
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), Apr, 2001
|
|
|
|
Arguments:
|
|
|
|
lpdwNumPrinters [out] - Number of elements in the list
|
|
bFilterOutFaxPrinters [in] - If TRUE, fax printers are not returned in the list
|
|
|
|
Return Value:
|
|
|
|
Allocated list of printers names. If NULL, an error has occurred - check LastError.
|
|
Use ReleasePrinterNames() to release allocated value.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwPrinter;
|
|
DWORD dwNumPrinters;
|
|
DWORD dwIndex = 0;
|
|
BOOL bSuccess = FALSE;
|
|
PPRINTER_INFO_2 pPrinterInfo = NULL;
|
|
PPRINTER_NAMES pRes = NULL;
|
|
DEBUG_FUNCTION_NAME(TEXT("ReleasePrinterNames"));
|
|
|
|
SetLastError (ERROR_SUCCESS);
|
|
pPrinterInfo = (PPRINTER_INFO_2) MyEnumPrinters(NULL, // Local machine
|
|
2, // Level 2
|
|
&dwNumPrinters, // [out] Number of printers found
|
|
0 // Both local and remote
|
|
);
|
|
if (!pPrinterInfo)
|
|
{
|
|
//
|
|
// Either error on no printers
|
|
//
|
|
DWORD ec = GetLastError();
|
|
if (ERROR_SUCCESS == ec)
|
|
{
|
|
//
|
|
// Not an error - no printers
|
|
//
|
|
SetLastError (ERROR_PRINTER_NOT_FOUND);
|
|
return NULL;
|
|
}
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("MyEnumPrinters() failed (ec: %ld)"),
|
|
ec);
|
|
return NULL;
|
|
}
|
|
|
|
Assert (dwNumPrinters > 0);
|
|
|
|
if (bFilterOutFaxPrinters)
|
|
{
|
|
//
|
|
// Counter number of printers w/out the fax printer(s)
|
|
//
|
|
DWORD dwNewPrintersCount = 0;
|
|
for (dwPrinter = 0; dwPrinter < dwNumPrinters; dwPrinter++)
|
|
{
|
|
if (_tcscmp(pPrinterInfo[dwPrinter].pDriverName,FAX_DRIVER_NAME))
|
|
{
|
|
//
|
|
// Not a fax printer
|
|
//
|
|
dwNewPrintersCount++;
|
|
}
|
|
}
|
|
if (!dwNewPrintersCount)
|
|
{
|
|
//
|
|
// Only fax printers - return NULL
|
|
//
|
|
SetLastError (ERROR_PRINTER_NOT_FOUND);
|
|
goto exit;
|
|
}
|
|
*lpdwNumPrinters = dwNewPrintersCount;
|
|
}
|
|
else
|
|
{
|
|
*lpdwNumPrinters = dwNumPrinters;
|
|
}
|
|
pRes = (PPRINTER_NAMES)MemAlloc (sizeof (PRINTER_NAMES) * (*lpdwNumPrinters));
|
|
if (!pRes)
|
|
{
|
|
goto exit;
|
|
}
|
|
memset (pRes, 0, sizeof (PRINTER_NAMES) * (*lpdwNumPrinters));
|
|
|
|
for (dwPrinter = 0; dwPrinter < dwNumPrinters; dwPrinter++)
|
|
{
|
|
if (bFilterOutFaxPrinters && !_tcscmp(pPrinterInfo[dwPrinter].pDriverName,FAX_DRIVER_NAME))
|
|
{
|
|
//
|
|
// This is a fax printer and filtering is on - skip it
|
|
//
|
|
continue;
|
|
}
|
|
|
|
pRes[dwIndex].lpcwstrDisplayName = StringDup (pPrinterInfo[dwPrinter].pPrinterName);
|
|
if (!pRes[dwIndex].lpcwstrDisplayName)
|
|
{
|
|
goto exit;
|
|
}
|
|
if (pPrinterInfo[dwPrinter].pServerName)
|
|
{
|
|
//
|
|
// Remote printer
|
|
//
|
|
WCHAR wszShare[MAX_PATH] = {0};
|
|
//
|
|
// Server name must begin with '\\'
|
|
//
|
|
Assert (lstrlen (pPrinterInfo[dwPrinter].pServerName) > 2)
|
|
Assert ((TEXT('\\') == pPrinterInfo[dwPrinter].pServerName[0]) &&
|
|
(TEXT('\\') == pPrinterInfo[dwPrinter].pServerName[1]));
|
|
//
|
|
// Share name cannot be NULL or empty string
|
|
//
|
|
Assert (pPrinterInfo[dwPrinter].pShareName && lstrlen(pPrinterInfo[dwPrinter].pShareName));
|
|
//
|
|
// Compose UNC path to print share
|
|
//
|
|
if (0 > _snwprintf (wszShare,
|
|
ARR_SIZE(wszShare) -1,
|
|
TEXT("%s\\%s"),
|
|
pPrinterInfo[dwPrinter].pServerName,
|
|
pPrinterInfo[dwPrinter].pShareName))
|
|
{
|
|
//
|
|
// Buffer too small
|
|
//
|
|
SetLastError (ERROR_GEN_FAILURE);
|
|
goto exit;
|
|
}
|
|
pRes[dwIndex].lpcwstrPath = StringDup (wszShare);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Local printer
|
|
//
|
|
pRes[dwIndex].lpcwstrPath = StringDup (pPrinterInfo[dwPrinter].pPrinterName);
|
|
}
|
|
if (!pRes[dwIndex].lpcwstrPath)
|
|
{
|
|
goto exit;
|
|
}
|
|
dwIndex++;
|
|
}
|
|
Assert (dwIndex == *lpdwNumPrinters);
|
|
bSuccess = TRUE;
|
|
|
|
exit:
|
|
MemFree (pPrinterInfo);
|
|
if (!bSuccess)
|
|
{
|
|
//
|
|
// Free data and return NULL
|
|
//
|
|
if (pRes)
|
|
{
|
|
ReleasePrinterNames (pRes, *lpdwNumPrinters);
|
|
pRes = NULL;
|
|
}
|
|
}
|
|
return pRes;
|
|
} // CollectPrinterNames
|
|
|
|
VOID
|
|
ReleasePrinterNames (
|
|
PPRINTER_NAMES pNames,
|
|
DWORD dwNumPrinters
|
|
)
|
|
/*++
|
|
|
|
Routine name : ReleasePrinterNames
|
|
|
|
Routine description:
|
|
|
|
Releases the list of printer names returned by CollectPrinterNames().
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), Apr, 2001
|
|
|
|
Arguments:
|
|
|
|
pNames [in] - List of printer names
|
|
dwNumPrinters [in] - Number of elements in the list
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DWORD dw;
|
|
DEBUG_FUNCTION_NAME(TEXT("ReleasePrinterNames"));
|
|
|
|
if (!dwNumPrinters)
|
|
{
|
|
return;
|
|
}
|
|
Assert (pNames);
|
|
for (dw = 0; dw < dwNumPrinters; dw++)
|
|
{
|
|
MemFree ((PVOID)(pNames[dw].lpcwstrDisplayName));
|
|
pNames[dw].lpcwstrDisplayName = NULL;
|
|
MemFree ((PVOID)(pNames[dw].lpcwstrPath));
|
|
pNames[dw].lpcwstrPath = NULL;
|
|
}
|
|
MemFree ((PVOID)pNames);
|
|
} // ReleasePrinterNames
|
|
|
|
LPCWSTR
|
|
FindPrinterNameFromPath (
|
|
PPRINTER_NAMES pNames,
|
|
DWORD dwNumPrinters,
|
|
LPCWSTR lpcwstrPath
|
|
)
|
|
{
|
|
DWORD dw;
|
|
DEBUG_FUNCTION_NAME(TEXT("FindPrinterNameFromPath"));
|
|
|
|
if (!pNames || !dwNumPrinters)
|
|
{
|
|
return NULL;
|
|
}
|
|
if (!lpcwstrPath)
|
|
{
|
|
return NULL;
|
|
}
|
|
for (dw = 0; dw < dwNumPrinters; dw++)
|
|
{
|
|
if (!lstrcmpi (pNames[dw].lpcwstrPath, lpcwstrPath))
|
|
{
|
|
return pNames[dw].lpcwstrDisplayName;
|
|
}
|
|
}
|
|
return NULL;
|
|
} // FindPrinterNameFromPath
|
|
|
|
LPCWSTR
|
|
FindPrinterPathFromName (
|
|
PPRINTER_NAMES pNames,
|
|
DWORD dwNumPrinters,
|
|
LPCWSTR lpcwstrName
|
|
)
|
|
{
|
|
DWORD dw;
|
|
DEBUG_FUNCTION_NAME(TEXT("FindPrinterPathFromName"));
|
|
|
|
if (!pNames || !dwNumPrinters)
|
|
{
|
|
return NULL;
|
|
}
|
|
if (!lpcwstrName)
|
|
{
|
|
return NULL;
|
|
}
|
|
for (dw = 0; dw < dwNumPrinters; dw++)
|
|
{
|
|
if (!lstrcmpi (pNames[dw].lpcwstrDisplayName, lpcwstrName))
|
|
{
|
|
return pNames[dw].lpcwstrPath;
|
|
}
|
|
}
|
|
return NULL;
|
|
} // FindPrinterPathFromName
|
|
|
|
#endif // UNICODE
|
|
|
|
BOOL
|
|
VerifyPrinterIsOnline (
|
|
LPCTSTR lpctstrPrinterName
|
|
)
|
|
/*++
|
|
|
|
Routine name : VerifyPrinterIsOnline
|
|
|
|
Routine description:
|
|
|
|
Verifies a printer is online and shared
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), Apr, 2001
|
|
|
|
Arguments:
|
|
|
|
lpctstrPrinterName [in] - Printer name
|
|
|
|
Return Value:
|
|
|
|
TRUE if printer is online and shared, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
HANDLE hPrinter = NULL;
|
|
PRINTER_DEFAULTS pd = {0};
|
|
DEBUG_FUNCTION_NAME(TEXT("VerifyPrinterIsOnline"));
|
|
|
|
Assert (lpctstrPrinterName);
|
|
//
|
|
// According to Mark Lawrence (NT PRINT), only by opening the printer in admistrator mode, we actually hit the wire.
|
|
//
|
|
pd.DesiredAccess = PRINTER_ACCESS_ADMINISTER;
|
|
if (!OpenPrinter ((LPTSTR)lpctstrPrinterName,
|
|
&hPrinter,
|
|
&pd))
|
|
{
|
|
DWORD dwRes = GetLastError ();
|
|
if (ERROR_ACCESS_DENIED == dwRes)
|
|
{
|
|
//
|
|
// Printer is there - we just can't admin it.
|
|
//
|
|
DebugPrintEx(
|
|
DEBUG_MSG,
|
|
TEXT("OpenPrinter(%s) failed with ERROR_ACCESS_DENIED - Printer is there - we just can't admin it"),
|
|
lpctstrPrinterName);
|
|
return TRUE;
|
|
}
|
|
if (ERROR_INVALID_PRINTER_NAME == dwRes)
|
|
{
|
|
//
|
|
// Printer is deleted
|
|
//
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("OpenPrinter(%s) failed with ERROR_INVALID_PRINTER_NAME - Printer is deleted"),
|
|
lpctstrPrinterName);
|
|
return FALSE;
|
|
}
|
|
if (RPC_S_SERVER_UNAVAILABLE == dwRes)
|
|
{
|
|
//
|
|
// Printer is not shared / server is unreachable
|
|
//
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("OpenPrinter(%s) failed with RPC_SERVER_UNAVAILABLE - Printer is not shared / server is unreachable"),
|
|
lpctstrPrinterName);
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Any other error - assume printer is not valid
|
|
//
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("OpenPrinter(%s) failed with %ld - assuming printer is not valid"),
|
|
lpctstrPrinterName,
|
|
dwRes);
|
|
return FALSE;
|
|
}
|
|
}
|
|
//
|
|
// Printer succesfully opened - it's online
|
|
//
|
|
DebugPrintEx(
|
|
DEBUG_MSG,
|
|
TEXT("OpenPrinter(%s) succeeded - Printer is there"),
|
|
lpctstrPrinterName);
|
|
ClosePrinter (hPrinter);
|
|
return TRUE;
|
|
} // VerifyPrinterIsOnline
|
|
|
|
|
|
VOID
|
|
FaxPrinterProperty(DWORD dwPage)
|
|
/*++
|
|
|
|
Routine name : FaxPrinterProperty
|
|
|
|
Routine description:
|
|
|
|
Opens fax printer properties sheet
|
|
|
|
Arguments:
|
|
|
|
dwPage [in] - Initial page number
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
HWND hWndFaxMon = NULL;
|
|
DEBUG_FUNCTION_NAME(TEXT("FaxPrinterProperty"));
|
|
|
|
hWndFaxMon = FindWindow(FAXSTAT_WINCLASS, NULL);
|
|
if (hWndFaxMon)
|
|
{
|
|
SetForegroundWindow(hWndFaxMon);
|
|
SendMessage(hWndFaxMon, WM_FAXSTAT_PRINTER_PROPERTY, dwPage, 0);
|
|
}
|
|
else
|
|
{
|
|
DebugPrintEx(DEBUG_ERR, TEXT("FindWindow(FAXSTAT_WINCLASS) failed with %d"), GetLastError());
|
|
}
|
|
} // FaxPrinterProperty
|
|
|
|
DWORD
|
|
SetLocalFaxPrinterSharing (
|
|
BOOL bShared
|
|
)
|
|
/*++
|
|
|
|
Routine name : SetLocalFaxPrinterSharing
|
|
|
|
Routine description:
|
|
|
|
Shares or un-shares the local fax printer
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), Jul, 2001
|
|
|
|
Arguments:
|
|
|
|
bShared [in] - Share the printer?
|
|
|
|
Return Value:
|
|
|
|
Standard Win32 error code
|
|
|
|
--*/
|
|
{
|
|
TCHAR tszFaxPrinterName[MAX_PATH *3];
|
|
HANDLE hPrinter = NULL;
|
|
BYTE aBuf[4096];
|
|
PRINTER_INFO_2 *pInfo = (PRINTER_INFO_2 *)aBuf;
|
|
PRINTER_DEFAULTS pd = {0};
|
|
DWORD dwRequiredSize;
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
|
|
DEBUG_FUNCTION_NAME(TEXT("SetLocalFaxPrinterSharing"));
|
|
|
|
if (!GetFirstLocalFaxPrinterName (tszFaxPrinterName, ARR_SIZE(tszFaxPrinterName)))
|
|
{
|
|
dwRes = GetLastError ();
|
|
DebugPrintEx(DEBUG_ERR, TEXT("GetFirstLocalFaxPrinterName failed with %d"), dwRes);
|
|
return dwRes;
|
|
}
|
|
pd.DesiredAccess = PRINTER_ALL_ACCESS;
|
|
if (!OpenPrinter (tszFaxPrinterName, &hPrinter, &pd))
|
|
{
|
|
dwRes = GetLastError ();
|
|
DebugPrintEx(DEBUG_ERR, TEXT("OpenPrinter failed with %d"), dwRes);
|
|
return dwRes;
|
|
}
|
|
if (!GetPrinter (hPrinter,
|
|
2,
|
|
(LPBYTE)pInfo,
|
|
sizeof (aBuf),
|
|
&dwRequiredSize))
|
|
{
|
|
dwRes = GetLastError ();
|
|
if (ERROR_INSUFFICIENT_BUFFER != dwRes)
|
|
{
|
|
//
|
|
// Real error
|
|
//
|
|
DebugPrintEx(DEBUG_ERR, TEXT("GetPrinter failed with %d"), dwRes);
|
|
goto exit;
|
|
}
|
|
pInfo = (PRINTER_INFO_2 *)MemAlloc (dwRequiredSize);
|
|
if (!pInfo)
|
|
{
|
|
dwRes = GetLastError ();
|
|
DebugPrintEx(DEBUG_ERR, TEXT("Failed to allocate %d bytes"), dwRequiredSize);
|
|
goto exit;
|
|
}
|
|
if (!GetPrinter (hPrinter,
|
|
2,
|
|
(LPBYTE)pInfo,
|
|
dwRequiredSize,
|
|
&dwRequiredSize))
|
|
{
|
|
dwRes = GetLastError ();
|
|
DebugPrintEx(DEBUG_ERR, TEXT("GetPrinter failed with %d"), dwRes);
|
|
goto exit;
|
|
}
|
|
}
|
|
dwRes = ERROR_SUCCESS;
|
|
if (bShared)
|
|
{
|
|
if (pInfo->Attributes & PRINTER_ATTRIBUTE_SHARED)
|
|
{
|
|
//
|
|
// Printer already shared
|
|
//
|
|
goto exit;
|
|
}
|
|
//
|
|
// Set the sharing bit
|
|
//
|
|
pInfo->Attributes |= PRINTER_ATTRIBUTE_SHARED;
|
|
}
|
|
else
|
|
{
|
|
if (!(pInfo->Attributes & PRINTER_ATTRIBUTE_SHARED))
|
|
{
|
|
//
|
|
// Printer already un-shared
|
|
//
|
|
goto exit;
|
|
}
|
|
//
|
|
// Clear the sharing bit
|
|
//
|
|
pInfo->Attributes &= ~PRINTER_ATTRIBUTE_SHARED;
|
|
}
|
|
if (!SetPrinter (hPrinter,
|
|
2,
|
|
(LPBYTE)pInfo,
|
|
0))
|
|
{
|
|
dwRes = GetLastError ();
|
|
DebugPrintEx(DEBUG_ERR, TEXT("SetPrinter failed with %d"), dwRes);
|
|
goto exit;
|
|
}
|
|
|
|
Assert (ERROR_SUCCESS == dwRes);
|
|
|
|
exit:
|
|
|
|
if (hPrinter)
|
|
{
|
|
ClosePrinter (hPrinter);
|
|
}
|
|
if ((LPBYTE)pInfo != aBuf)
|
|
{
|
|
MemFree (pInfo);
|
|
}
|
|
return dwRes;
|
|
} // SetLocalFaxPrinterSharing
|
|
|
|
|
|
DWORD
|
|
AddOrVerifyLocalFaxPrinter ()
|
|
/*++
|
|
|
|
Routine name : AddOrVerifyLocalFaxPrinter
|
|
|
|
Routine description:
|
|
|
|
This function verifies a local fax printer is installed.
|
|
If not installed, this function installs one.
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), June, 2002
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Standard Win32 error code
|
|
|
|
--*/
|
|
{
|
|
DWORD dwRes;
|
|
BOOL bLocalFaxPrinterInstalled;
|
|
BOOL bFaxInstalled;
|
|
DEBUG_FUNCTION_NAME(TEXT("AddOrVerifyLocalFaxPrinter"));
|
|
|
|
dwRes = IsFaxInstalled (&bFaxInstalled);
|
|
if (ERROR_SUCCESS != dwRes)
|
|
{
|
|
return dwRes;
|
|
}
|
|
if (!bFaxInstalled)
|
|
{
|
|
//
|
|
// The fax product (optional component) is not installed on the system.
|
|
// Bail out here
|
|
//
|
|
return ERROR_SUCCESS;
|
|
}
|
|
dwRes = IsLocalFaxPrinterInstalled(&bLocalFaxPrinterInstalled);
|
|
if (ERROR_SUCCESS != dwRes)
|
|
{
|
|
//
|
|
// Can't really tell if local fax printer is installed.
|
|
// Better install anyway, just to be on the safe side.
|
|
//
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("IsLocalFaxPrinterInstalled failed with %ld"),
|
|
dwRes);
|
|
bLocalFaxPrinterInstalled = FALSE;
|
|
}
|
|
if (bLocalFaxPrinterInstalled)
|
|
{
|
|
//
|
|
// Nothing more to do here
|
|
//
|
|
return ERROR_SUCCESS;
|
|
}
|
|
dwRes = AddLocalFaxPrinter (FAX_PRINTER_NAME, NULL);
|
|
if (ERROR_SUCCESS != dwRes)
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("AddLocalFaxPrinter failed with %ld"),
|
|
dwRes);
|
|
}
|
|
return dwRes;
|
|
} // AddOrVerifyLocalFaxPrinter
|
|
|