Leaked source code of windows server 2003
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

/*++
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