Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1023 lines
25 KiB

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
util.c
Abstract:
This module provides all the utility functions for the Routing Layer and
the local Print Providor
Author:
Dave Snipp (DaveSn) 15-Mar-1991
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#include <winddiui.h>
//
// Lowercase, just like win31 for WM_WININICHANGE
//
WCHAR *szDevices=L"devices";
WCHAR *szWindows=L"windows";
#define NUM_INTERACTIVE_RIDS 1
extern DWORD RouterCacheSize;
extern PROUTERCACHE RouterCacheTable;
typedef struct _DEVMODECHG_INFO {
DWORD signature;
HANDLE hDrvModule;
FARPROC pfnConvertDevMode;
} DEVMODECHG_INFO, *PDEVMODECHG_INFO;
#define DMC_SIGNATURE 'DMC' /* 'DMC' is the signature value */
DWORD
RouterIsOlderThan(
DWORD i,
DWORD j
);
BOOL
DeleteSubKeyTree(
HKEY ParentHandle,
WCHAR SubKeyName[]
)
{
LONG Error;
DWORD Index;
HKEY KeyHandle;
BOOL RetValue;
WCHAR ChildKeyName[ MAX_PATH ];
DWORD ChildKeyNameLength;
Error = RegOpenKeyEx(
ParentHandle,
SubKeyName,
0,
KEY_READ | KEY_WRITE,
&KeyHandle
);
if (Error != ERROR_SUCCESS) {
SetLastError(Error);
return(FALSE);
}
ChildKeyNameLength = MAX_PATH;
Index = 0; // Don't increment this Index
while ((Error = RegEnumKeyEx(
KeyHandle,
Index,
ChildKeyName,
&ChildKeyNameLength,
NULL,
NULL,
NULL,
NULL
)) == ERROR_SUCCESS) {
RetValue = DeleteSubKeyTree( KeyHandle, ChildKeyName );
if (RetValue == FALSE) {
// Error -- couldn't delete the sub key
RegCloseKey(KeyHandle);
return(FALSE);
}
ChildKeyNameLength = MAX_PATH;
}
Error = RegCloseKey(
KeyHandle
);
if (Error != ERROR_SUCCESS) {
return(FALSE);
}
Error = RegDeleteKey(
ParentHandle,
SubKeyName
);
if (Error != ERROR_SUCCESS) {
return(FALSE);
}
// Return Success - the key has successfully been deleted
return(TRUE);
}
LPWSTR RemoveOrderEntry(
LPWSTR szOrderString,
DWORD cbStringSize,
LPWSTR szOrderEntry,
LPDWORD pcbBytesReturned
)
{
LPWSTR lpMem, psz, temp;
if (szOrderString == NULL) {
*pcbBytesReturned = 0;
return(NULL);
}
if (lpMem = AllocSplMem( cbStringSize)) {
temp = szOrderString;
psz = lpMem;
while (*temp) {
if (!lstrcmpi(temp, szOrderEntry)) { // we need to remove
temp += lstrlen(temp)+1; // this entry in Order
continue;
}
lstrcpy(psz,temp);
psz += lstrlen(temp)+1;
temp += lstrlen(temp)+1;
}
*psz = L'\0';
*pcbBytesReturned = ((psz - lpMem)+1)*sizeof(WCHAR);
return(lpMem);
}
*pcbBytesReturned = 0;
return(lpMem);
}
LPWSTR AppendOrderEntry(
LPWSTR szOrderString,
DWORD cbStringSize,
LPWSTR szOrderEntry,
LPDWORD pcbBytesReturned
)
{
LPWSTR lpMem, temp, psz;
DWORD cb = 0;
BOOL bExists = FALSE;
if ((szOrderString == NULL) && (szOrderEntry == NULL)) {
*pcbBytesReturned = 0;
return(NULL);
}
if (szOrderString == NULL) {
cb = wcslen(szOrderEntry)*sizeof(WCHAR)+ sizeof(WCHAR) + sizeof(WCHAR);
if (lpMem = AllocSplMem(cb)){
wcscpy(lpMem, szOrderEntry);
*pcbBytesReturned = cb;
} else {
*pcbBytesReturned = 0;
}
return lpMem;
}
if (lpMem = AllocSplMem( cbStringSize + wcslen(szOrderEntry)*sizeof(WCHAR)
+ sizeof(WCHAR))){
temp = szOrderString;
psz = lpMem;
while (*temp) {
if (!lstrcmpi(temp, szOrderEntry)) { // Make sure we don't
bExists = TRUE; // duplicate entries
}
lstrcpy(psz, temp);
psz += lstrlen(temp)+ 1;
temp += lstrlen(temp)+1;
}
if (!bExists) { // if it doesn't exist
lstrcpy(psz, szOrderEntry); // add the entry
psz += lstrlen(szOrderEntry)+1;
}
*psz = L'\0'; // the second null character
*pcbBytesReturned = ((psz - lpMem) + 1)* sizeof(WCHAR);
}
return(lpMem);
}
typedef struct {
DWORD dwType;
DWORD dwMessage;
WPARAM wParam;
LPARAM lParam;
} MESSAGE, *PMESSAGE;
VOID
SendMessageThread(
PMESSAGE pMessage);
BOOL
BroadcastMessage(
DWORD dwType,
DWORD dwMessage,
WPARAM wParam,
LPARAM lParam)
{
HANDLE hThread;
DWORD ThreadId;
PMESSAGE pMessage;
BOOL bReturn = FALSE;
pMessage = AllocSplMem(sizeof(MESSAGE));
if (pMessage) {
pMessage->dwType = dwType;
pMessage->dwMessage = dwMessage;
pMessage->wParam = wParam;
pMessage->lParam = lParam;
//
// BUGBUG mattfe Nov 8 93
// We should have a queue of events to broadcast and then have a
// single thread pulling them off the queue until there is nothing
// left and then that thread could go away.
//
// The current design can lead to a huge number of threads being
// created and torn down in both this and csrss process.
//
hThread = CreateThread(NULL, 4096,
(LPTHREAD_START_ROUTINE)SendMessageThread,
(LPVOID)pMessage,
0,
&ThreadId);
if (hThread) {
CloseHandle(hThread);
bReturn = TRUE;
} else {
FreeSplMem(pMessage);
}
}
return bReturn;
}
// The Broadcasts are done on a separate thread, the reason it CSRSS
// will create a server side thread when we call user and we don't want
// that to be pared up with the RPC thread which is in the spooss server.
// We want it to go away the moment we have completed the SendMessage.
// We also call SendNotifyMessage since we don't care if the broadcasts
// are syncronous this uses less resources since usually we don't have more
// than one broadcast.
VOID
SendMessageThread(
PMESSAGE pMessage)
{
switch (pMessage->dwType) {
case BROADCAST_TYPE_MESSAGE:
SendNotifyMessage(HWND_BROADCAST,
pMessage->dwMessage,
pMessage->wParam,
pMessage->lParam);
break;
case BROADCAST_TYPE_CHANGEDEFAULT:
//
// Same order and strings as win31.
//
SendNotifyMessage(HWND_BROADCAST,
WM_WININICHANGE,
0,
(LPARAM)szDevices);
SendNotifyMessage(HWND_BROADCAST,
WM_WININICHANGE,
0,
(LPARAM)szWindows);
break;
}
FreeSplMem(pMessage);
ExitThread(0);
}
BOOL
IsInteractiveUser(VOID)
{
HANDLE hToken;
BOOL bStatus;
DWORD dwError;
PSID pTestSid = NULL;
PSID pCurSid;
LPVOID pToken = NULL;
DWORD cbSize = 0;
DWORD cbRequired = 0;
DWORD i;
BOOL bRet = FALSE;
SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
unsigned int uType;
dwError = I_RpcBindingInqTransportType(NULL, &uType);
if ( dwError == RPC_S_NO_CALL_ACTIVE ) {
//
// KM call
//
return TRUE;
} else if ( dwError != ERROR_SUCCESS ) {
//
// This should not fail. So we'll assert on chk bld and
// continue looking at SIDS on fre builds
//
SPLASSERT( dwError != ERROR_SUCCESS);
} else if ( uType != TRANSPORT_TYPE_LPC ) {
//
// Not LRPC so call is remote
//
return FALSE;
}
bStatus = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken);
if (!bStatus) {
// Couldn't open the thread's token, nothing much we can do
DBGMSG(DBG_TRACE,("Error: couldn't open the thread's Access token %d\n", GetLastError()));
return(FALSE);
}
bStatus = GetTokenInformation(hToken, TokenGroups, pToken, 0, &cbSize);
// we have to fail because we have no memory allocated
if (!bStatus) {
dwError = GetLastError();
// If the error is not because of memory, quit now
if (dwError != ERROR_INSUFFICIENT_BUFFER)
goto Done;
// else we failed because of memory
// so allocate memory and continue
if ((pToken = AllocSplMem( cbSize)) == NULL) {
// Couldn't allocate memory, return
DBGMSG(DBG_TRACE,("Error: couldn't allocate memory for the token\n"));
goto Done;
}
}
bStatus = GetTokenInformation(hToken, TokenGroups, pToken,
cbSize, &cbRequired);
if (!bStatus) {
// Failed again!! Nothing much we can do, quit
DBGMSG(DBG_TRACE,("Error: we blew it the second time!!\n"));
goto Done;
}
if ( !AllocateAndInitializeSid(&sia,
1,
SECURITY_NETWORK_RID,
0, 0, 0, 0, 0, 0, 0,
&pTestSid) ) {
DBGMSG(DBG_TRACE,
("Error: could not AllocateAndInitializeSid -%d\n",
GetLastError()));
goto Done;
}
for (i = 0; i < (((TOKEN_GROUPS *)pToken)->GroupCount); i++) {
pCurSid = ((TOKEN_GROUPS *)pToken)->Groups[i].Sid;
if ( EqualSid(pTestSid, pCurSid) ) {
goto Done;
}
}
//
// No match for network sid
//
bRet = TRUE;
Done:
if ( pTestSid )
FreeSid(pTestSid);
FreeSplMem(pToken);
CloseHandle(hToken);
return bRet;
}
LPPROVIDOR
FindEntryinRouterCache(
LPWSTR pPrinterName
)
{
DWORD i;
if (!pPrinterName)
return NULL;
DBGMSG(DBG_TRACE, ("FindEntryinRouterCache with %ws\n", pPrinterName));
if (RouterCacheSize == 0 ) {
DBGMSG(DBG_TRACE, ("FindEntryInRouterCache with %ws returning -1 (zero cache)\n", pPrinterName));
return NULL;
}
for (i = 0; i < RouterCacheSize; i++ ) {
if (RouterCacheTable[i].bAvailable) {
if (!_wcsicmp(RouterCacheTable[i].pPrinterName, pPrinterName)) {
//
// update the time stamp so that it is current and not old
//
GetSystemTime(&RouterCacheTable[i].st);
//
//
//
DBGMSG(DBG_TRACE, ("FindEntryinRouterCache returning with %d\n", i));
return RouterCacheTable[i].pProvidor;
}
}
}
DBGMSG(DBG_TRACE, ("FindEntryinRouterCache returning with -1\n"));
return NULL;
}
DWORD
AddEntrytoRouterCache(
LPWSTR pPrinterName,
LPPROVIDOR pProvidor
)
{
DWORD LRUEntry = (DWORD)-1;
DWORD i;
DBGMSG(DBG_TRACE, ("AddEntrytoRouterCache with %ws\n", pPrinterName));
if (RouterCacheSize == 0 ) {
DBGMSG(DBG_TRACE, ("AddEntrytoRouterCache with %ws returning -1 (zero cache)\n", pPrinterName));
return (DWORD)-1;
}
for (i = 0; i < RouterCacheSize; i++ ) {
if (!RouterCacheTable[i].bAvailable) {
//
// Found an available entry; use it
// fill in the name of the printer and the providor
// that supports this printer.
//
break;
} else {
if ((LRUEntry == -1) || (i == RouterIsOlderThan(i, LRUEntry))){
LRUEntry = i;
}
}
}
if (i == RouterCacheSize) {
//
// We have no available entries so we need to use
// the LRUEntry which is busy
//
FreeSplStr(RouterCacheTable[LRUEntry].pPrinterName);
RouterCacheTable[LRUEntry].bAvailable = FALSE;
i = LRUEntry;
}
if ((RouterCacheTable[i].pPrinterName = AllocSplStr(pPrinterName)) == NULL){
//
// Alloc failed so we're kinda hosed so return -1
//
return (DWORD)-1;
}
RouterCacheTable[i].bAvailable = TRUE;
RouterCacheTable[i].pProvidor = pProvidor;
//
// update the time stamp so that we know when this entry was made
//
GetSystemTime(&RouterCacheTable[i].st);
DBGMSG(DBG_TRACE, ("AddEntrytoRouterCache returning with %d\n", i));
return i;
}
VOID
DeleteEntryfromRouterCache(
LPWSTR pPrinterName
)
{
DWORD i;
if (RouterCacheSize == 0) {
DBGMSG(DBG_TRACE, ("DeleteEntryfromRouterCache with %ws returning -1 (zero cache)\n", pPrinterName));
return;
}
DBGMSG(DBG_TRACE, ("DeleteEntryFromRouterCache with %ws\n", pPrinterName));
for (i = 0; i < RouterCacheSize; i++ ) {
if (RouterCacheTable[i].bAvailable) {
if (!_wcsicmp(RouterCacheTable[i].pPrinterName, pPrinterName)) {
//
// reset the available flag on this node
//
FreeSplStr(RouterCacheTable[i].pPrinterName);
RouterCacheTable[i].pProvidor = NULL;
RouterCacheTable[i].bAvailable = FALSE;
DBGMSG(DBG_TRACE, ("DeleteEntryFromRouterCache returning after deleting the %d th entry\n", i));
return;
}
}
}
DBGMSG(DBG_TRACE, ("DeleteEntryFromRouterCache returning after not finding an entry to delete\n"));
}
DWORD
RouterIsOlderThan(
DWORD i,
DWORD j
)
{
SYSTEMTIME *pi, *pj;
DWORD iMs, jMs;
DBGMSG(DBG_TRACE, ("RouterIsOlderThan entering with i %d j %d\n", i, j));
pi = &(RouterCacheTable[i].st);
pj = &(RouterCacheTable[j].st);
DBGMSG(DBG_TRACE, ("Index i %d - %d:%d:%d:%d:%d:%d:%d\n",
i, pi->wYear, pi->wMonth, pi->wDay, pi->wHour, pi->wMinute, pi->wSecond, pi->wMilliseconds));
DBGMSG(DBG_TRACE,("Index j %d - %d:%d:%d:%d:%d:%d:%d\n",
j, pj->wYear, pj->wMonth, pj->wDay, pj->wHour, pj->wMinute, pj->wSecond, pj->wMilliseconds));
if (pi->wYear < pj->wYear) {
DBGMSG(DBG_TRACE, ("RouterIsOlderThan returns %d\n", i));
return(i);
} else if (pi->wYear > pj->wYear) {
DBGMSG(DBG_TRACE, ("RouterIsOlderThan returns %d\n", j));
return(j);
} else if (pi->wMonth < pj->wMonth) {
DBGMSG(DBG_TRACE, ("RouterIsOlderThan returns %d\n", i));
return(i);
} else if (pi->wMonth > pj->wMonth) {
DBGMSG(DBG_TRACE, ("RouterIsOlderThan returns %d\n", j));
return(j);
} else if (pi->wDay < pj->wDay) {
DBGMSG(DBG_TRACE, ("RouterIsOlderThan returns %d\n", i));
return(i);
} else if (pi->wDay > pj->wDay) {
DBGMSG(DBG_TRACE, ("RouterIsOlderThan returns %d\n", j));
return(j);
} else {
iMs = ((((pi->wHour * 60) + pi->wMinute)*60) + pi->wSecond)* 1000 + pi->wMilliseconds;
jMs = ((((pj->wHour * 60) + pj->wMinute)*60) + pj->wSecond)* 1000 + pj->wMilliseconds;
if (iMs <= jMs) {
DBGMSG(DBG_TRACE, ("RouterIsOlderThan returns %d\n", i));
return(i);
} else {
DBGMSG(DBG_TRACE, ("RouterIsOlderThan returns %d\n", j));
return(j);
}
}
}
BOOL
OpenPrinterToken(
PHANDLE phToken)
{
NTSTATUS Status;
Status = NtOpenThreadToken(
NtCurrentThread(),
TOKEN_IMPERSONATE,
TRUE,
phToken
);
if ( !NT_SUCCESS(Status) ) {
SetLastError(Status);
return FALSE;
}
return TRUE;
}
BOOL
SetPrinterToken(
HANDLE hToken)
{
NTSTATUS Status;
Status = NtSetInformationThread(
NtCurrentThread(),
ThreadImpersonationToken,
(PVOID)&hToken,
(ULONG)sizeof(HANDLE)
);
if ( !NT_SUCCESS(Status) ) {
SetLastError(Status);
return FALSE;
}
return TRUE;
}
BOOL
ClosePrinterToken(
HANDLE hToken)
{
NTSTATUS Status;
Status = NtClose(hToken);
if ( !NT_SUCCESS(Status) ) {
SetLastError(Status);
return FALSE;
}
return TRUE;
}
HANDLE
RevertToPrinterSelf(
VOID)
{
HANDLE NewToken, OldToken;
NTSTATUS Status;
NewToken = NULL;
Status = NtOpenThreadToken(
NtCurrentThread(),
TOKEN_IMPERSONATE,
TRUE,
&OldToken
);
if ( !NT_SUCCESS(Status) ) {
SetLastError(Status);
return FALSE;
}
Status = NtSetInformationThread(
NtCurrentThread(),
ThreadImpersonationToken,
(PVOID)&NewToken,
(ULONG)sizeof(HANDLE)
);
if ( !NT_SUCCESS(Status) ) {
SetLastError(Status);
return FALSE;
}
return OldToken;
}
BOOL
ImpersonatePrinterClient(
HANDLE hToken)
{
NTSTATUS Status;
Status = NtSetInformationThread(
NtCurrentThread(),
ThreadImpersonationToken,
(PVOID)&hToken,
(ULONG)sizeof(HANDLE)
);
if ( !NT_SUCCESS(Status) ) {
SetLastError(Status);
return FALSE;
}
NtClose(hToken);
return TRUE;
}
VOID
UnloadDriverFile(
IN OUT HANDLE hDevModeChgInfo
)
/*++
Description:
Does a FreeLibrary on the driver file and frees memory
Arguments:
hDevModeChgInfo - A handle returned by LoadDriverFiletoConvertDevmode
Return Vlaue:
None
--*/
{
PDEVMODECHG_INFO pDevModeChgInfo = (PDEVMODECHG_INFO) hDevModeChgInfo;
SPLASSERT(pDevModeChgInfo &&
pDevModeChgInfo->signature == DMC_SIGNATURE);
if ( pDevModeChgInfo && pDevModeChgInfo->signature == DMC_SIGNATURE ) {
if ( pDevModeChgInfo->hDrvModule )
FreeLibrary(pDevModeChgInfo->hDrvModule);
FreeSplMem((LPVOID)pDevModeChgInfo);
}
}
HANDLE
LoadDriverFiletoConvertDevmode(
IN LPWSTR pDriverFile
)
/*++
Description:
Does a LoadLibrary on the driver file given. This will give a handle
which can be used to do devmode conversion later using
CallDrvDevModeConversion.
Caller should call UnloadDriverFile to do a FreeLibrary and free memory
Note: Driver will call OpenPrinter to spooler
Arguments:
pDriverFile - Full path of the driver file to do a LoadLibrary
Return Value:
A handle value to be used to make calls to CallDrvDevModeConversion,
NULL on error
--*/
{
PDEVMODECHG_INFO pDevModeChgInfo = NULL;
BOOL bFail = TRUE;
DWORD dwNeeded;
UINT uOldErrorMode;
SPLASSERT(pDriverFile != NULL);
pDevModeChgInfo = (PDEVMODECHG_INFO) AllocSplMem(sizeof(*pDevModeChgInfo));
if ( !pDevModeChgInfo ) {
DBGMSG(DBG_WARNING, ("printer.c: Memory allocation failed for DEVMODECHG_INFO\n"));
goto Cleanup;
}
pDevModeChgInfo->signature = DMC_SIGNATURE;
uOldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
pDevModeChgInfo->hDrvModule = LoadLibrary(pDriverFile);
(VOID)SetErrorMode(uOldErrorMode);
if ( !pDevModeChgInfo->hDrvModule ) {
DBGMSG(DBG_WARNING,("LoadDriverFiletoConvertDevmode: Can't load driver file %ws\n", pDriverFile));
goto Cleanup;
}
//
// Some third party driver may not be providing DrvConvertDevMode
//
pDevModeChgInfo->pfnConvertDevMode = GetProcAddress(pDevModeChgInfo->hDrvModule,
"DrvConvertDevMode");
if ( !pDevModeChgInfo->pfnConvertDevMode )
goto Cleanup;
bFail = FALSE;
Cleanup:
if ( bFail ) {
if ( pDevModeChgInfo )
UnloadDriverFile((HANDLE)pDevModeChgInfo);
return (HANDLE) NULL;
} else
return (HANDLE) pDevModeChgInfo;
}
DWORD
CallDrvDevModeConversion(
IN HANDLE hDevModeChgInfo,
IN LPWSTR pszPrinterName,
IN LPBYTE pDevMode1,
IN OUT LPBYTE *ppDevMode2,
IN OUT LPDWORD pdwOutDevModeSize,
IN DWORD dwConvertMode,
IN BOOL bAlloc
)
/*++
Description:
Does deve mode conversion by calling driver
If bAlloc is TRUE routine will do the allocation using AllocSplMem
Note: Driver is going to call OpenPrinter.
Arguments:
hDevModeChgInfo - Points to DEVMODECHG_INFO
pszPrinterName - Printer name
pInDevMode - Input devmode (will be NULL for CDM_DRIVER_DEFAULT)
*pOutDevMode - Points to output devmode
pdwOutDevModeSize - Output devmode size on succesful return
if !bAlloc this will give input buffer size
dwConvertMode - Devmode conversion mode to give to driver
bAllocate - Tells the routine to do allocation to *pOutPrinter
If bAllocate is TRUE and no devmode conversion is required
call will fail.
Return Value:
Returns last error
--*/
{
DWORD dwLastError = ERROR_SUCCESS;
LPDEVMODE pInDevMode = (LPDEVMODE)pDevMode1,
*ppOutDevMode = (LPDEVMODE *) ppDevMode2;
PDEVMODECHG_INFO pDevModeChgInfo = (PDEVMODECHG_INFO) hDevModeChgInfo;
if ( !pDevModeChgInfo ||
pDevModeChgInfo->signature != DMC_SIGNATURE ||
!pDevModeChgInfo->pfnConvertDevMode ) {
SPLASSERT(pDevModeChgInfo &&
pDevModeChgInfo->signature == DMC_SIGNATURE &&
pDevModeChgInfo->pfnConvertDevMode);
return ERROR_INVALID_PARAMETER;
}
DBGMSG(DBG_INFO,("Convert DevMode %d\n", dwConvertMode));
#if DBG
#else
try {
#endif
if ( bAlloc ) {
//
// If we have to do allocation first find size neeeded
//
*pdwOutDevModeSize = 0;
*ppOutDevMode = NULL;
(*pDevModeChgInfo->pfnConvertDevMode)(pszPrinterName,
pInDevMode,
NULL,
pdwOutDevModeSize,
dwConvertMode);
dwLastError = GetLastError();
if ( dwLastError != ERROR_INSUFFICIENT_BUFFER ) {
DBGMSG(DBG_WARNING,
("CallDrvDevModeConversion: Unexpected error %d\n",
GetLastError()));
if (dwLastError == ERROR_SUCCESS) {
SPLASSERT(dwLastError != ERROR_SUCCESS);
// if driver doesn't fail the above call, it is a broken driver and probably
// failed a HeapAlloc, which doesn't SetLastError()
SetLastError(dwLastError = ERROR_NOT_ENOUGH_MEMORY);
}
#if DBG
goto Cleanup;
#else
leave;
#endif
}
*ppOutDevMode = AllocSplMem(*pdwOutDevModeSize);
if ( !*ppOutDevMode ) {
dwLastError = GetLastError();
#if DBG
goto Cleanup;
#else
leave;
#endif
}
}
if ( !(*pDevModeChgInfo->pfnConvertDevMode)(
pszPrinterName,
pInDevMode,
ppOutDevMode ? *ppOutDevMode
: NULL,
pdwOutDevModeSize,
dwConvertMode) ) {
dwLastError = GetLastError();
if (dwLastError == ERROR_SUCCESS) {
SPLASSERT(dwLastError != ERROR_SUCCESS);
// if driver doesn't fail the above call, it is a broken driver and probably
// failed a HeapAlloc, which doesn't SetLastError()
SetLastError(dwLastError = ERROR_NOT_ENOUGH_MEMORY);
}
} else {
dwLastError = ERROR_SUCCESS;
}
#if DBG
Cleanup:
#else
} except(1) {
DBGMSG(DBG_ERROR,
("CallDrvDevModeConversion: Exception from driver\n"));
dwLastError = GetExceptionCode();
SetLastError(dwLastError);
}
#endif
//
// If we allocated mmeory free it and zero the pointer
//
if ( dwLastError != ERROR_SUCCESS && bAlloc && *ppOutDevMode ) {
FreeSplMem(*ppOutDevMode);
*ppOutDevMode = 0;
*pdwOutDevModeSize = 0;
}
if ( dwLastError != ERROR_SUCCESS &&
dwLastError != ERROR_INSUFFICIENT_BUFFER ) {
DBGMSG(DBG_WARNING, ("DevmodeConvert unexpected error %d\n", dwLastError));
}
if ( dwLastError == ERROR_SUCCESS &&
*pdwOutDevModeSize != (DWORD) ((*ppOutDevMode)->dmSize
+ (*ppOutDevMode)->dmDriverExtra) ) {
DBGMSG(DBG_ERROR,
("Driver says outsize is %d, really %d\n", *pdwOutDevModeSize,
(*ppOutDevMode)->dmSize + (*ppOutDevMode)->dmDriverExtra));
*pdwOutDevModeSize = (DWORD) ((*ppOutDevMode)->dmSize +
(*ppOutDevMode)->dmDriverExtra);
}
return dwLastError;
}