mirror of https://github.com/lianthony/NT4.0
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.
746 lines
17 KiB
746 lines
17 KiB
/*++
|
|
|
|
Copyright (c) 1990 - 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
util.c
|
|
|
|
Abstract:
|
|
|
|
Client Side Utility Routines
|
|
|
|
|
|
Author:
|
|
|
|
Dave Snipp (DaveSn) 15-Mar-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <windows.h>
|
|
#include <winspool.h>
|
|
#include <lmerr.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <tchar.h>
|
|
#include <stdio.h>
|
|
|
|
#include "client.h"
|
|
#include "browse.h"
|
|
|
|
TCHAR *szNetMsgDll = TEXT("NETMSG.DLL");
|
|
|
|
LPVOID
|
|
DllAllocSplMem(
|
|
DWORD cb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will allocate local memory. It will possibly allocate extra
|
|
memory and fill this with debugging information for the debugging version.
|
|
|
|
Arguments:
|
|
|
|
cb - The amount of memory to allocate
|
|
|
|
Return Value:
|
|
|
|
NON-NULL - A pointer to the allocated memory
|
|
|
|
FALSE/NULL - The operation failed. Extended error status is available
|
|
using GetLastError.
|
|
|
|
--*/
|
|
{
|
|
LPDWORD pMem;
|
|
DWORD cbNew;
|
|
|
|
cb = DWORD_ALIGN_UP(cb);
|
|
|
|
cbNew = cb+2*sizeof(DWORD);
|
|
|
|
pMem=(LPDWORD)LocalAlloc(LPTR, cbNew);
|
|
|
|
if (!pMem) {
|
|
|
|
DBGMSG( DBG_WARNING, ("Memory Allocation failed for %d bytes\n", cbNew ));
|
|
return 0;
|
|
}
|
|
|
|
*pMem=cb;
|
|
*(LPDWORD)((LPBYTE)pMem+cbNew-sizeof(DWORD))=0xdeadbeef;
|
|
|
|
return (LPVOID)(pMem+1);
|
|
}
|
|
|
|
BOOL
|
|
DllFreeSplMem(
|
|
LPVOID pMem
|
|
)
|
|
{
|
|
DWORD cbNew;
|
|
LPDWORD pNewMem;
|
|
|
|
pNewMem = pMem;
|
|
pNewMem--;
|
|
|
|
cbNew = *pNewMem;
|
|
|
|
if (*(LPDWORD)((LPBYTE)pMem + cbNew) != 0xdeadbeef) {
|
|
DBGMSG(DBG_ERROR, ("DllFreeSplMem Corrupt Memory in winspool : %0lx\n", pNewMem));
|
|
return FALSE;
|
|
}
|
|
|
|
memset(pNewMem, 0x65, cbNew);
|
|
|
|
LocalFree((LPVOID)pNewMem);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
LPVOID
|
|
ReallocSplMem(
|
|
LPVOID pOldMem,
|
|
DWORD cbOld,
|
|
DWORD cbNew
|
|
)
|
|
{
|
|
LPVOID pNewMem;
|
|
|
|
pNewMem=AllocSplMem(cbNew);
|
|
|
|
if (pOldMem) {
|
|
|
|
if (cbOld)
|
|
memcpy(pNewMem, pOldMem, min(cbNew, cbOld));
|
|
|
|
FreeSplMem(pOldMem);
|
|
}
|
|
|
|
return pNewMem;
|
|
}
|
|
|
|
LPTSTR
|
|
AllocSplStr(
|
|
LPTSTR pStr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will allocate enough local memory to store the specified
|
|
string, and copy that string to the allocated memory
|
|
|
|
Arguments:
|
|
|
|
pStr - Pointer to the string that needs to be allocated and stored
|
|
|
|
Return Value:
|
|
|
|
NON-NULL - A pointer to the allocated memory containing the string
|
|
|
|
FALSE/NULL - The operation failed. Extended error status is available
|
|
using GetLastError.
|
|
|
|
--*/
|
|
{
|
|
LPTSTR pMem;
|
|
|
|
if (!pStr)
|
|
return 0;
|
|
|
|
if (pMem = AllocSplMem( _tcslen(pStr)*sizeof(TCHAR) + sizeof(TCHAR) ))
|
|
_tcscpy(pMem, pStr);
|
|
|
|
return pMem;
|
|
}
|
|
|
|
BOOL
|
|
DllFreeSplStr(
|
|
LPTSTR pStr
|
|
)
|
|
{
|
|
return pStr ?
|
|
DllFreeSplMem(pStr) :
|
|
FALSE;
|
|
}
|
|
|
|
BOOL
|
|
ReallocSplStr(
|
|
LPTSTR *ppStr,
|
|
LPTSTR pStr
|
|
)
|
|
{
|
|
LPWSTR pOldStr = *ppStr;
|
|
|
|
*ppStr=AllocSplStr(pStr);
|
|
FreeSplStr(pOldStr);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* EnumGeneric
|
|
*
|
|
* A function which calls the spooler Enum* APIs and handles all the
|
|
* memory reallocation stuff when it's needed.
|
|
* Saves lots of hassle.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* fnEnum - The Enum* function to be called (e.g. EnumPrinters).
|
|
*
|
|
* Level - The level of information requested.
|
|
*
|
|
* ppEnumData - The address of a pointer to a buffer of cbBuf length
|
|
* to receive the data, which must have been allocated by
|
|
* AllocSplMem. The buffer pointer may be NULL.
|
|
* If the buffer is not large enough, the function will reallocate.
|
|
*
|
|
* cbBuf - The initial length of the buffer pointed to by *ppEnumData.
|
|
*
|
|
* pcbReturned - A pointer to a DWORD to receive the size of the buffer
|
|
* returned.
|
|
*
|
|
* pcReturned - The count of objects returned in the buffer.
|
|
*
|
|
* Arg1, Arg2, Arg3 - Arguments specific to the Enum* function called,
|
|
* as commented below.
|
|
*
|
|
* Returns:
|
|
*
|
|
* TRUE if the function is successful.
|
|
* A return of false occurs if the specific Enum* call fails
|
|
* or if the attempt to reallocate the buffer fails.
|
|
*
|
|
* Author:
|
|
*
|
|
* andrewbe, August 1992
|
|
*
|
|
*/
|
|
#define COMMON_ARGS Level, (LPBYTE)*ppEnumData, cbBuf, pcbReturned, pcReturned
|
|
|
|
|
|
BOOL
|
|
EnumGeneric(
|
|
IN PROC fnEnum,
|
|
IN DWORD Level,
|
|
IN PBYTE *ppEnumData,
|
|
IN DWORD cbBuf,
|
|
OUT LPDWORD pcbReturned,
|
|
OUT LPDWORD pcReturned,
|
|
IN PVOID Arg1,
|
|
IN PVOID Arg2,
|
|
IN PVOID Arg3 )
|
|
{
|
|
BOOL rc;
|
|
BOOL UnknownFunction = FALSE;
|
|
DWORD cbRealloc;
|
|
|
|
if( fnEnum == (PROC)EnumPrinters )
|
|
rc = EnumPrinters( (DWORD)Arg1, (LPTSTR)Arg2, COMMON_ARGS );
|
|
// Flags Name
|
|
else if( fnEnum == (PROC)EnumJobs )
|
|
rc = EnumJobs( (HANDLE)Arg1, (DWORD)Arg2, (DWORD)Arg3, COMMON_ARGS );
|
|
// hPrinter FirstJob NoJobs
|
|
else if( fnEnum == (PROC)EnumPrinterDrivers )
|
|
rc = EnumPrinterDrivers( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS );
|
|
// pName pEnvironment
|
|
else if( fnEnum == (PROC)EnumForms )
|
|
rc = EnumForms( (HANDLE)Arg1, COMMON_ARGS );
|
|
// hPrinter
|
|
else if( fnEnum == (PROC)EnumMonitors )
|
|
rc = EnumMonitors( (LPTSTR)Arg1, COMMON_ARGS );
|
|
// pName
|
|
else if( fnEnum == (PROC)EnumPorts )
|
|
rc = EnumPorts( (LPTSTR)Arg1, COMMON_ARGS );
|
|
// pName
|
|
else if( fnEnum == (PROC)EnumPrintProcessors )
|
|
rc = EnumPrintProcessors( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS );
|
|
// pName pEnvironment
|
|
else
|
|
{
|
|
*ppEnumData = NULL;
|
|
UnknownFunction = TRUE;
|
|
}
|
|
|
|
|
|
if( ( rc == FALSE ) && ( UnknownFunction == FALSE ) )
|
|
{
|
|
if( GetLastError( ) == ERROR_INSUFFICIENT_BUFFER )
|
|
{
|
|
cbRealloc = *pcbReturned;
|
|
|
|
if( cbBuf == 0 )
|
|
*ppEnumData = AllocSplMem( cbRealloc );
|
|
else
|
|
*ppEnumData = ReallocSplMem( *ppEnumData, cbBuf, cbRealloc );
|
|
|
|
cbBuf = cbRealloc;
|
|
|
|
if( *ppEnumData )
|
|
{
|
|
if( fnEnum == (PROC)EnumPrinters )
|
|
rc = EnumPrinters( (DWORD)Arg1, (LPTSTR)Arg2, COMMON_ARGS );
|
|
// Flags Name
|
|
else if( fnEnum == (PROC)EnumJobs )
|
|
rc = EnumJobs( (HANDLE)Arg1, (DWORD)Arg2, (DWORD)Arg3, COMMON_ARGS );
|
|
// hPrinter FirstJob NoJobs
|
|
else if( fnEnum == (PROC)EnumPrinterDrivers )
|
|
rc = EnumPrinterDrivers( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS );
|
|
// pName pEnvironment
|
|
else if( fnEnum == (PROC)EnumForms )
|
|
rc = EnumForms( (HANDLE)Arg1, COMMON_ARGS );
|
|
// hPrinter
|
|
else if( fnEnum == (PROC)EnumMonitors )
|
|
rc = EnumMonitors( (LPTSTR)Arg1, COMMON_ARGS );
|
|
// pName
|
|
else if( fnEnum == (PROC)EnumPorts )
|
|
rc = EnumPorts( (LPTSTR)Arg1, COMMON_ARGS );
|
|
// pName
|
|
else if( fnEnum == (PROC)EnumPrintProcessors )
|
|
rc = EnumPrintProcessors( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS );
|
|
// pName pEnvironment
|
|
|
|
/* If things haven't worked out, free up the buffer.
|
|
* We do this because otherwise the caller will not know
|
|
* whether the pointer is valid any more,
|
|
* since ReallocSplMem might have failed.
|
|
*/
|
|
if( rc == FALSE )
|
|
{
|
|
if( *ppEnumData )
|
|
FreeSplMem( *ppEnumData );
|
|
*ppEnumData = NULL;
|
|
*pcbReturned = 0;
|
|
*pcReturned = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
if( *ppEnumData )
|
|
FreeSplMem( *ppEnumData );
|
|
*ppEnumData = NULL;
|
|
*pcbReturned = 0;
|
|
*pcReturned = 0;
|
|
rc = FALSE;
|
|
}
|
|
}
|
|
|
|
else
|
|
*pcbReturned = cbBuf;
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/* GetGeneric
|
|
*
|
|
* A function which calls the spooler Get* APIs and handles all the
|
|
* memory reallocation stuff when it's needed.
|
|
* Based on the EnumGeneric function.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* fnGet - The Get* function to be called (e.g. GetPrinters).
|
|
*
|
|
* Level - The level of information requested.
|
|
*
|
|
* ppGetData - The address of a pointer to a buffer of cbBuf length
|
|
* to receive the data, which must have been allocated by
|
|
* AllocSplMem. The buffer pointer may be NULL.
|
|
* If the buffer is not large enough, the function will reallocate.
|
|
*
|
|
* cbBuf - The initial length of the buffer pointed to by *ppGetData.
|
|
*
|
|
* pcbReturned - A pointer to a DWORD to receive the size of the buffer
|
|
* returned.
|
|
*
|
|
* Arg1, Arg2 - Arguments specific to the Get* function called,
|
|
* as commented below.
|
|
*
|
|
* Returns:
|
|
*
|
|
* TRUE if the function is successful.
|
|
* A return of false occurs if the specific Get* call fails
|
|
* or if the attempt to reallocate the buffer fails.
|
|
*
|
|
* Author:
|
|
*
|
|
* andrewbe, August 1992
|
|
*
|
|
*/
|
|
#define GET_ARGS Level, (LPBYTE)*ppGetData, cbBuf, pcbReturned
|
|
|
|
BOOL
|
|
GetGeneric(
|
|
IN PROC fnGet,
|
|
IN DWORD Level,
|
|
IN PBYTE *ppGetData,
|
|
IN DWORD cbBuf,
|
|
OUT LPDWORD pcbReturned,
|
|
IN PVOID Arg1,
|
|
IN PVOID Arg2 )
|
|
{
|
|
BOOL rc;
|
|
BOOL UnknownFunction = FALSE;
|
|
DWORD cbRealloc;
|
|
DWORD Error;
|
|
|
|
if( fnGet == (PROC)GetPrinter )
|
|
rc = GetPrinter( (HANDLE)Arg1, GET_ARGS );
|
|
// hPrinter
|
|
else
|
|
{
|
|
*ppGetData = NULL;
|
|
UnknownFunction = TRUE;
|
|
}
|
|
|
|
|
|
if( ( rc == FALSE ) && ( UnknownFunction == FALSE ) )
|
|
{
|
|
if( ( Error = GetLastError( ) ) == ERROR_INSUFFICIENT_BUFFER )
|
|
{
|
|
cbRealloc = *pcbReturned;
|
|
*ppGetData = ReallocSplMem( *ppGetData, cbBuf, cbRealloc );
|
|
cbBuf = cbRealloc;
|
|
|
|
if( *ppGetData )
|
|
{
|
|
if( fnGet == (PROC)GetPrinter )
|
|
rc = GetPrinter( (HANDLE)Arg1, GET_ARGS );
|
|
// hPrinter
|
|
|
|
/* If things haven't worked out, free up the buffer.
|
|
* We do this because otherwise the caller will not know
|
|
* whether the pointer is valid any more,
|
|
* since ReallocSplMem might have failed.
|
|
*/
|
|
if( rc == FALSE )
|
|
{
|
|
if( *ppGetData )
|
|
FreeSplMem( *ppGetData );
|
|
*ppGetData = NULL;
|
|
*pcbReturned = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
if( *ppGetData )
|
|
FreeSplMem( *ppGetData );
|
|
*ppGetData = NULL;
|
|
*pcbReturned = 0;
|
|
|
|
rc = FALSE;
|
|
}
|
|
}
|
|
|
|
else
|
|
*pcbReturned = cbBuf;
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
#define ENTRYFIELD_LENGTH 256
|
|
LPTSTR AllocDlgItemText(HWND hwnd, int id)
|
|
{
|
|
TCHAR string[ENTRYFIELD_LENGTH];
|
|
|
|
GetDlgItemText (hwnd, id, string, COUNTOF(string));
|
|
return ( *string ? AllocSplStr(string) : NULL );
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
LPTSTR
|
|
GetErrorString(
|
|
DWORD Error
|
|
)
|
|
{
|
|
TCHAR Buffer[1024];
|
|
LPTSTR pErrorString = NULL;
|
|
DWORD dwFlags;
|
|
HANDLE hModule;
|
|
|
|
if ((Error >= NERR_BASE) && (Error <= MAX_NERR)){
|
|
hModule = LoadLibrary(szNetMsgDll);
|
|
dwFlags = FORMAT_MESSAGE_FROM_HMODULE;
|
|
}
|
|
else {
|
|
hModule = NULL;
|
|
dwFlags = FORMAT_MESSAGE_FROM_SYSTEM;
|
|
}
|
|
|
|
if( FormatMessage( dwFlags, hModule,
|
|
Error, 0, Buffer,
|
|
COUNTOF(Buffer), NULL )
|
|
== 0 )
|
|
|
|
LoadString( hInst, IDS_UNKNOWN_ERROR, Buffer,
|
|
COUNTOF(Buffer));
|
|
|
|
pErrorString = AllocSplStr(Buffer);
|
|
|
|
if (hModule) {
|
|
FreeLibrary(hModule);
|
|
}
|
|
|
|
return pErrorString;
|
|
}
|
|
|
|
|
|
|
|
|
|
DWORD ReportFailure( HWND hwndParent,
|
|
DWORD idTitle,
|
|
DWORD idDefaultError )
|
|
{
|
|
DWORD ErrorID;
|
|
DWORD MsgType;
|
|
LPTSTR pErrorString;
|
|
|
|
ErrorID = GetLastError( );
|
|
|
|
MsgType = MSG_ERROR;
|
|
|
|
pErrorString = GetErrorString( ErrorID );
|
|
|
|
Message( hwndParent, MsgType, idTitle,
|
|
idDefaultError, pErrorString );
|
|
|
|
FreeSplStr( pErrorString );
|
|
|
|
|
|
return ErrorID;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
ValidatePrinterHandle(
|
|
HANDLE hPrinter
|
|
)
|
|
{
|
|
PSPOOL pSpool = hPrinter;
|
|
BOOL bReturnValue = FALSE;
|
|
|
|
try {
|
|
if ( pSpool && (pSpool->signature == SP_SIGNATURE)) {
|
|
bReturnValue = TRUE;
|
|
}
|
|
} except (1) {
|
|
}
|
|
|
|
if ( !bReturnValue ) {
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
}
|
|
|
|
return bReturnValue;
|
|
|
|
}
|
|
|
|
|
|
PSECURITY_DESCRIPTOR
|
|
BuildInputSD(
|
|
PSECURITY_DESCRIPTOR pPrinterSD,
|
|
PDWORD pSizeSD
|
|
)
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
SECURITY_DESCRIPTOR AbsoluteSD;
|
|
PSECURITY_DESCRIPTOR pRelative;
|
|
BOOL Defaulted = FALSE;
|
|
BOOL DaclPresent = FALSE;
|
|
BOOL SaclPresent = FALSE;
|
|
PSID pOwnerSid = NULL;
|
|
PSID pGroupSid = NULL;
|
|
PACL pDacl = NULL;
|
|
PACL pSacl = NULL;
|
|
DWORD SDLength = 0;
|
|
|
|
|
|
//
|
|
// Initialize *pSizeSD = 0;
|
|
//
|
|
|
|
*pSizeSD = 0;
|
|
if (!IsValidSecurityDescriptor(pPrinterSD)) {
|
|
return(NULL);
|
|
}
|
|
if (!InitializeSecurityDescriptor (&AbsoluteSD, SECURITY_DESCRIPTOR_REVISION1)) {
|
|
return(NULL);
|
|
}
|
|
|
|
if(!GetSecurityDescriptorOwner(pPrinterSD,
|
|
&pOwnerSid, &Defaulted)){
|
|
return(NULL);
|
|
}
|
|
SetSecurityDescriptorOwner(&AbsoluteSD,
|
|
pOwnerSid, Defaulted );
|
|
|
|
if(! GetSecurityDescriptorGroup( pPrinterSD,
|
|
&pGroupSid, &Defaulted )){
|
|
return(NULL);
|
|
}
|
|
SetSecurityDescriptorGroup( &AbsoluteSD,
|
|
pGroupSid, Defaulted );
|
|
|
|
if(!GetSecurityDescriptorDacl( pPrinterSD,
|
|
&DaclPresent, &pDacl, &Defaulted )){
|
|
return(NULL);
|
|
}
|
|
|
|
SetSecurityDescriptorDacl( &AbsoluteSD,
|
|
DaclPresent, pDacl, Defaulted );
|
|
|
|
if(!GetSecurityDescriptorSacl( pPrinterSD,
|
|
&SaclPresent, &pSacl, &Defaulted)){
|
|
return(NULL);
|
|
}
|
|
SetSecurityDescriptorSacl( &AbsoluteSD,
|
|
SaclPresent, pSacl, Defaulted );
|
|
|
|
SDLength = GetSecurityDescriptorLength( &AbsoluteSD);
|
|
pRelative = LocalAlloc(LPTR, SDLength);
|
|
if (!pRelative) {
|
|
return(NULL);
|
|
}
|
|
if (!MakeSelfRelativeSD (&AbsoluteSD, pRelative, &SDLength)) {
|
|
LocalFree(pRelative);
|
|
return(NULL);
|
|
}
|
|
|
|
*pSizeSD = SDLength;
|
|
return(pRelative);
|
|
}
|
|
|
|
|
|
PKEYDATA
|
|
CreateTokenList(
|
|
LPWSTR pKeyData
|
|
)
|
|
{
|
|
DWORD cTokens;
|
|
DWORD cb;
|
|
PKEYDATA pResult;
|
|
LPWSTR pDest;
|
|
LPWSTR psz = pKeyData;
|
|
LPWSTR *ppToken;
|
|
|
|
if (!psz || !*psz)
|
|
return NULL;
|
|
|
|
cTokens=1;
|
|
|
|
/* Scan through the string looking for commas,
|
|
* ensuring that each is followed by a non-NULL character:
|
|
*/
|
|
while ((psz = wcschr(psz, L',')) && psz[1]) {
|
|
|
|
cTokens++;
|
|
psz++;
|
|
}
|
|
|
|
cb = sizeof(KEYDATA) + (cTokens-1) * sizeof(LPWSTR) +
|
|
|
|
wcslen(pKeyData)*sizeof(WCHAR) + sizeof(WCHAR);
|
|
|
|
if (!(pResult = (PKEYDATA)AllocSplMem(cb)))
|
|
return NULL;
|
|
|
|
pResult->cb = cb;
|
|
|
|
/* Initialise pDest to point beyond the token pointers:
|
|
*/
|
|
pDest = (LPWSTR)((LPBYTE)pResult + sizeof(KEYDATA) +
|
|
(cTokens-1) * sizeof(LPWSTR));
|
|
|
|
/* Then copy the key data buffer there:
|
|
*/
|
|
wcscpy(pDest, pKeyData);
|
|
|
|
ppToken = pResult->pTokens;
|
|
|
|
|
|
/* Remember, wcstok has the side effect of replacing the delimiter
|
|
* by NULL, which is precisely what we want:
|
|
*/
|
|
psz = wcstok (pDest, L",");
|
|
|
|
while (psz) {
|
|
|
|
*ppToken++ = psz;
|
|
psz = wcstok (NULL, L",");
|
|
}
|
|
|
|
pResult->cTokens = cTokens;
|
|
|
|
return( pResult );
|
|
}
|
|
|
|
|
|
LPWSTR
|
|
GetPrinterPortList(
|
|
HANDLE hPrinter
|
|
)
|
|
{
|
|
LPBYTE pMem;
|
|
LPTSTR pPort;
|
|
DWORD dwPassed = 1024; //Try 1K to start with
|
|
LPPRINTER_INFO_2 pPrinter;
|
|
DWORD dwLevel = 2;
|
|
DWORD dwNeeded;
|
|
PKEYDATA pKeyData;
|
|
DWORD i = 0;
|
|
LPWSTR pPortNames = NULL;
|
|
|
|
|
|
pMem = AllocSplMem(dwPassed);
|
|
if (pMem == NULL) {
|
|
return FALSE;
|
|
}
|
|
if (!GetPrinter(hPrinter, dwLevel, pMem, dwPassed, &dwNeeded)) {
|
|
DBGMSG(DBG_TRACE, ("Last error is %d\n", GetLastError()));
|
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
|
return NULL;
|
|
}
|
|
pMem = ReallocSplMem(pMem, dwPassed, dwNeeded);
|
|
dwPassed = dwNeeded;
|
|
if (!GetPrinter(hPrinter, dwLevel, pMem, dwPassed, &dwNeeded)) {
|
|
FreeSplMem(pMem);
|
|
return (NULL);
|
|
}
|
|
}
|
|
pPrinter = (LPPRINTER_INFO_2)pMem;
|
|
|
|
//
|
|
// Fixes the null pPrinter->pPortName problem where
|
|
// downlevel may return null
|
|
//
|
|
|
|
if (!pPrinter->pPortName) {
|
|
FreeSplMem(pMem);
|
|
return(NULL);
|
|
}
|
|
|
|
pPortNames = AllocSplStr(pPrinter->pPortName);
|
|
FreeSplMem(pMem);
|
|
|
|
return(pPortNames);
|
|
}
|