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.
1844 lines
49 KiB
1844 lines
49 KiB
/*++
|
|
|
|
Copyright (c) 1997-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
umpd.c
|
|
|
|
Abstract:
|
|
|
|
User-mode printer driver support
|
|
|
|
Environment:
|
|
|
|
Windows NT 5.0
|
|
|
|
Revision History:
|
|
|
|
06/30/97 -davidx-
|
|
Created it.
|
|
|
|
09/17/97 -davidx-
|
|
Clean up km-um thunking.
|
|
|
|
--*/
|
|
|
|
extern "C"
|
|
{
|
|
#include "precomp.h"
|
|
#include "winddi.h"
|
|
#include "psapi.h"
|
|
#include "proxyport.h"
|
|
|
|
static PUMPD gCachedUMPDList = NULL; // cached list of user-mode printer drivers
|
|
}
|
|
|
|
#include "umpd.hxx"
|
|
|
|
#define IA64_PAGE_SIZE 0x2000
|
|
#define PP_SHAREDSECTION_SIZE IA64_PAGE_SIZE
|
|
|
|
PVOID
|
|
MyGetPrinterDriver(
|
|
HANDLE hPrinter,
|
|
DWORD dwLevel
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wrapper function for spooler's GetPrinterDriver API
|
|
|
|
Arguments:
|
|
|
|
hPrinter - Handle to the printer
|
|
dwLevel - Level of DRIVER_INFO_x structure the caller is interested in
|
|
|
|
Return Value:
|
|
|
|
Pointer to a DRIVER_INFO_x structure, NULL if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD cbNeeded;
|
|
PVOID pv;
|
|
INT retries = 0;
|
|
|
|
//
|
|
// Start with a default buffer size to avoid always
|
|
// having to call GetPrinterDriver twice.
|
|
//
|
|
|
|
cbNeeded = 2 * MAX_PATH * sizeof(WCHAR);
|
|
|
|
while (retries++ < 2)
|
|
{
|
|
if (! (pv = LOCALALLOC(cbNeeded)))
|
|
{
|
|
WARNING("Memory allocation failed.\n");
|
|
return NULL;
|
|
}
|
|
|
|
if (fpGetPrinterDriverW(hPrinter, NULL, dwLevel, (LPBYTE)pv, cbNeeded, &cbNeeded))
|
|
return pv;
|
|
|
|
//
|
|
// If GetPrinterDriver failed not for insufficient buffer,
|
|
// skip the retry
|
|
//
|
|
|
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
retries++;
|
|
|
|
LOCALFREE(pv);
|
|
}
|
|
|
|
WARNING("GetPrinterDriver failed.\n");
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PWSTR
|
|
DuplicateString(
|
|
PCWSTR pSrc
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate memory and make a duplicate of the source string
|
|
|
|
Arguments:
|
|
|
|
pSrc - String to be duplicated
|
|
|
|
Return Value:
|
|
|
|
Pointer to the duplicated string
|
|
NULL if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSTR pDest;
|
|
INT cb;
|
|
|
|
ASSERTGDI(pSrc != NULL, "Duplicate NULL string!\n");
|
|
|
|
cb = (wcslen(pSrc) + 1) * sizeof(WCHAR);
|
|
|
|
if (pDest = (PWSTR) LOCALALLOC(cb))
|
|
{
|
|
CopyMemory(pDest, pSrc, cb);
|
|
return pDest;
|
|
}
|
|
else
|
|
{
|
|
WARNING("DuplicateString: out-of-memory.\n");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
PDRIVER_INFO_5W
|
|
DuplicateDriverInfo5W(PDRIVER_INFO_5W inDriverInfo)
|
|
{
|
|
ULONG size = sizeof(DRIVER_INFO_5W);
|
|
PDRIVER_INFO_5W pDriverInfo;
|
|
PWSTR pStr;
|
|
ULONG len;
|
|
|
|
size += (inDriverInfo->pName == NULL ? 0 : (wcslen(inDriverInfo->pName) + 1) * sizeof(WCHAR));
|
|
size += (inDriverInfo->pEnvironment == NULL ? 0 : (wcslen(inDriverInfo->pEnvironment) + 1) * sizeof(WCHAR));
|
|
size += (inDriverInfo->pDriverPath == NULL ? 0 : (wcslen(inDriverInfo->pDriverPath) + 1) * sizeof(WCHAR));
|
|
size += (inDriverInfo->pDataFile == NULL ? 0 : (wcslen(inDriverInfo->pDataFile) + 1) * sizeof(WCHAR));
|
|
size += (inDriverInfo->pConfigFile == NULL ? 0 : (wcslen(inDriverInfo->pConfigFile) + 1) * sizeof(WCHAR));
|
|
|
|
if(pDriverInfo = (PDRIVER_INFO_5W) LOCALALLOC(size))
|
|
{
|
|
*pDriverInfo = *inDriverInfo;
|
|
|
|
pStr = (PWSTR) (pDriverInfo + 1);
|
|
|
|
if(pDriverInfo->pName)
|
|
{
|
|
len = wcslen(pDriverInfo->pName) + 1;
|
|
RtlCopyMemory(pStr, pDriverInfo->pName, len * sizeof(WCHAR));
|
|
pDriverInfo->pName = pStr;
|
|
pStr += len;
|
|
}
|
|
|
|
if(pDriverInfo->pEnvironment)
|
|
{
|
|
len = wcslen(pDriverInfo->pEnvironment) + 1;
|
|
RtlCopyMemory(pStr, pDriverInfo->pEnvironment, len * sizeof(WCHAR));
|
|
pDriverInfo->pEnvironment = pStr;
|
|
pStr += len;
|
|
}
|
|
|
|
if(pDriverInfo->pDriverPath)
|
|
{
|
|
len = wcslen(pDriverInfo->pDriverPath) + 1;
|
|
RtlCopyMemory(pStr, pDriverInfo->pDriverPath, len * sizeof(WCHAR));
|
|
pDriverInfo->pDriverPath = pStr;
|
|
pStr += len;
|
|
}
|
|
|
|
if(pDriverInfo->pDataFile)
|
|
{
|
|
len = wcslen(pDriverInfo->pDataFile) + 1;
|
|
RtlCopyMemory(pStr, pDriverInfo->pDataFile, len * sizeof(WCHAR));
|
|
pDriverInfo->pDataFile = pStr;
|
|
pStr += len;
|
|
}
|
|
|
|
if(pDriverInfo->pConfigFile)
|
|
{
|
|
len = wcslen(pDriverInfo->pConfigFile) + 1;
|
|
RtlCopyMemory(pStr, pDriverInfo->pConfigFile, len * sizeof(WCHAR));
|
|
pDriverInfo->pConfigFile = pStr;
|
|
pStr += len;
|
|
}
|
|
}
|
|
|
|
return pDriverInfo;
|
|
}
|
|
|
|
PUMPD
|
|
FindUserModePrinterDriver(
|
|
PCWSTR pDriverDllName,
|
|
DWORD dwDriverVersion,
|
|
BOOL bUseVersion
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Search the cached list of user-mode printer drivers and
|
|
see if the specified driver is found
|
|
|
|
Arguments:
|
|
|
|
pDriverDllName - Specifies the name of the driver DLL to be found
|
|
dwDriverVersion - Current version number of the driver
|
|
bUseVersion - Flag for using the version check
|
|
|
|
Return Value:
|
|
|
|
Pointer to the UMPD structure corresponding to the specified driver
|
|
NULL if the specified driver is not in the cached list
|
|
|
|
Note:
|
|
|
|
This function must be called inside a critical section:
|
|
|
|
ENTERCRITICALSECTION(&semUMPD);
|
|
...
|
|
LEAVECRITICALSECTION(&semUMPD);
|
|
|
|
--*/
|
|
|
|
{
|
|
PUMPD pUMPD = gCachedUMPDList;
|
|
|
|
while (pUMPD != NULL &&
|
|
pUMPD->pDriverInfo2 != NULL &&
|
|
_wcsicmp(pDriverDllName, pUMPD->pDriverInfo2->pDriverPath) != 0)
|
|
{
|
|
pUMPD = pUMPD->pNext;
|
|
}
|
|
|
|
// Do the version check if neccesary
|
|
if (bUseVersion && pUMPD)
|
|
{
|
|
if (dwDriverVersion != pUMPD->dwDriverVersion)
|
|
{
|
|
// We have a version mismatch. Remove artificial increments on this
|
|
// driver.
|
|
if (pUMPD->bArtificialIncrement)
|
|
{
|
|
pUMPD->bArtificialIncrement = FALSE;
|
|
|
|
if (UnloadUserModePrinterDriver(pUMPD, FALSE, 0))
|
|
{
|
|
pUMPD = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return pUMPD;
|
|
}
|
|
|
|
BOOL
|
|
GdiArtificialDecrementDriver(
|
|
LPWSTR pDriverDllName,
|
|
DWORD dwDriverAttributes
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove the artificial increment on the driver, if any.
|
|
|
|
Arguments:
|
|
|
|
pDriverDllName - Specifies the name of the driver DLL to be found
|
|
dwDriverAttributes - User/Kernel mode printer driver
|
|
|
|
Return Value:
|
|
|
|
TRUE if the driver file is no longer loaded in the spooler
|
|
FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
PUMPD pUMPD;
|
|
BOOL bReturn = FALSE;
|
|
|
|
if (!pDriverDllName || !*pDriverDllName)
|
|
{
|
|
// Nothing to unload
|
|
return bReturn;
|
|
}
|
|
|
|
if (dwDriverAttributes & DRIVER_KERNELMODE)
|
|
{
|
|
// Unload kernel mode driver
|
|
return NtGdiUnloadPrinterDriver(pDriverDllName,
|
|
(wcslen(pDriverDllName) + 1) * sizeof(WCHAR));
|
|
}
|
|
|
|
ENTERCRITICALSECTION(&semUMPD);
|
|
|
|
pUMPD = gCachedUMPDList;
|
|
|
|
while (pUMPD != NULL &&
|
|
_wcsicmp(pDriverDllName, pUMPD->pDriverInfo2->pDriverPath) != 0)
|
|
{
|
|
pUMPD = pUMPD->pNext;
|
|
}
|
|
|
|
if (pUMPD)
|
|
{
|
|
if (pUMPD->bArtificialIncrement)
|
|
{
|
|
pUMPD->bArtificialIncrement = FALSE;
|
|
bReturn = UnloadUserModePrinterDriver(pUMPD, FALSE, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bReturn = TRUE;
|
|
}
|
|
|
|
LEAVECRITICALSECTION(&semUMPD);
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
BOOL
|
|
LoadUserModePrinterDriverEx(
|
|
PDRIVER_INFO_5W pDriverInfo5,
|
|
LPWSTR pwstrPrinterName,
|
|
PUMPD *ppUMPD,
|
|
PRINTER_DEFAULTSW *pdefaults,
|
|
HANDLE hPrinter
|
|
)
|
|
{
|
|
PDRIVER_INFO_2W pDriverInfo2;
|
|
HINSTANCE hInst = NULL;
|
|
BOOL bResult = FALSE;
|
|
PUMPD pUMPD = NULL;
|
|
ProxyPort * pp = NULL;
|
|
KERNEL_PVOID umpdCookie = NULL;
|
|
BOOL bFreeDriverInfo2 = TRUE;
|
|
|
|
if ((pDriverInfo2 = (PDRIVER_INFO_2W) DuplicateDriverInfo5W(pDriverInfo5)) == NULL)
|
|
return FALSE;
|
|
|
|
//
|
|
// Check the list of cached user-mode printer drivers
|
|
// and see if the requested printer driver is already loaded
|
|
//
|
|
|
|
ENTERCRITICALSECTION(&semUMPD);
|
|
|
|
if (*ppUMPD = FindUserModePrinterDriver(pDriverInfo5->pDriverPath,
|
|
pDriverInfo5->dwDriverVersion,
|
|
TRUE))
|
|
{
|
|
if (gbWOW64)
|
|
{
|
|
pUMPD = *ppUMPD;
|
|
|
|
ASSERTGDI(pUMPD->pp, "LoadUserModePrinterDriver NULL proxyport\n");
|
|
|
|
PROXYPORT proxyport(pUMPD->pp);
|
|
|
|
if (proxyport.bValid())
|
|
{
|
|
umpdCookie = proxyport.LoadDriver(pDriverInfo5, pwstrPrinterName, pdefaults, hPrinter);
|
|
|
|
if (pUMPD->umpdCookie == umpdCookie)
|
|
{
|
|
// 64-bit UMPD matches the 32-bit one
|
|
|
|
bResult = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WARNING("LoadUserModePrinterDriveEx: umpdCookie doesn't match\n");
|
|
}
|
|
}
|
|
else
|
|
WARNING("LoadUserModePrinterDriverEx: invalid proxyport\n");
|
|
}
|
|
else
|
|
{
|
|
// x86 or native ia64 printing, don't need to anything
|
|
|
|
bResult = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Can't find UMPD, first time load the printer driver
|
|
|
|
if (gbWOW64)
|
|
{
|
|
PROXYPORT proxyport(PP_SHAREDSECTION_SIZE);
|
|
|
|
if (pp = proxyport.GetPort())
|
|
{
|
|
umpdCookie = proxyport.LoadDriver(pDriverInfo5, pwstrPrinterName, pdefaults, hPrinter);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hInst = LoadLibraryExW(pDriverInfo2->pDriverPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
|
}
|
|
|
|
if (hInst || umpdCookie)
|
|
{
|
|
if (pUMPD = (PUMPD) LOCALALLOC(sizeof(UMPD)))
|
|
{
|
|
ZeroMemory(pUMPD, sizeof(UMPD));
|
|
|
|
pUMPD->dwSignature = UMPD_SIGNATURE;
|
|
pUMPD->hInst = hInst;
|
|
pUMPD->pDriverInfo2 = pDriverInfo2;
|
|
pUMPD->bArtificialIncrement = TRUE;
|
|
pUMPD->dwDriverVersion = pDriverInfo5->dwDriverVersion;
|
|
pUMPD->iRefCount = 1; // aritficial ref count to keep the printer driver around
|
|
// till the process goes away
|
|
pUMPD->pp = pp;
|
|
pUMPD->umpdCookie = umpdCookie;
|
|
|
|
*ppUMPD = pUMPD;
|
|
bResult = TRUE;
|
|
|
|
bFreeDriverInfo2 = FALSE;
|
|
|
|
//
|
|
// Add the newly loaded driver to the list of
|
|
// cached user-mode printer drivers
|
|
//
|
|
|
|
pUMPD->pNext = gCachedUMPDList;
|
|
gCachedUMPDList = pUMPD;
|
|
}
|
|
}
|
|
|
|
if (!bResult)
|
|
{
|
|
if (pp)
|
|
{
|
|
PROXYPORT proxyport(pp);
|
|
|
|
if (umpdCookie)
|
|
proxyport.UnloadDriver(umpdCookie, 0, FALSE);
|
|
|
|
proxyport.Close();
|
|
}
|
|
|
|
if (hInst)
|
|
FreeLibrary(hInst);
|
|
}
|
|
}
|
|
|
|
if (bResult)
|
|
(*ppUMPD)->iRefCount++;
|
|
|
|
LEAVECRITICALSECTION(&semUMPD);
|
|
|
|
if (bFreeDriverInfo2)
|
|
LOCALFREE(pDriverInfo2);
|
|
|
|
if (!bResult)
|
|
{
|
|
WARNING("LoadUserModePrinterDriverEx failed\n");
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
BOOL
|
|
LoadUserModePrinterDriver(
|
|
HANDLE hPrinter,
|
|
LPWSTR pwstrPrinterName,
|
|
PUMPD *ppUMPD,
|
|
PRINTER_DEFAULTSW *pdefaults
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Load user-mode printer driver DLL
|
|
|
|
Arguments:
|
|
|
|
hPrinter - Handle to the current printer
|
|
ppUMPD - Return a pointer to a UMPD structure
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE if there is an error
|
|
|
|
If the printer uses a user-mode printer driver, *ppUMPD will be a pointer
|
|
to a UMPD structure. If the printer uses a kernel-mode printer driver,
|
|
*ppUMPD will be NULL.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDRIVER_INFO_5W pDriverInfo5;
|
|
BOOL bResult;
|
|
HMODULE hModule;
|
|
WCHAR moduleName[256];
|
|
|
|
*ppUMPD = NULL;
|
|
|
|
//
|
|
// Get printer driver information
|
|
//
|
|
|
|
if ((pDriverInfo5 = (PDRIVER_INFO_5W)MyGetPrinterDriver(hPrinter, 5)) == NULL)
|
|
return FALSE;
|
|
|
|
if (pDriverInfo5->dwDriverAttributes & DRIVER_KERNELMODE)
|
|
{
|
|
LOCALFREE(pDriverInfo5);
|
|
return TRUE;
|
|
}
|
|
|
|
bResult = LoadUserModePrinterDriverEx(pDriverInfo5, pwstrPrinterName, ppUMPD, pdefaults, hPrinter);
|
|
|
|
LOCALFREE(pDriverInfo5);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL
|
|
UnloadUserModePrinterDriver(
|
|
PUMPD pUMPD,
|
|
BOOL bNotifySpooler,
|
|
HANDLE hPrinter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unload user-mode printer driver module and notify the spooler if necessary
|
|
|
|
Arguments:
|
|
|
|
pUMPD - Pointer to user-mode printer driver information
|
|
bNotifySpooler - Call into the spooler to notify driver unloading
|
|
|
|
Return Value:
|
|
|
|
TRUE if the driver instance was freed (i.e ref cnt == 0)
|
|
FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
PUMPD *ppStartUMPD;
|
|
|
|
ASSERTGDI(VALID_UMPD(pUMPD), "Corrupted UMPD structure.\n");
|
|
ASSERTGDI(pUMPD->iRefCount > 0, "Bad UMPD reference count.\n");
|
|
|
|
if (gbWOW64)
|
|
{
|
|
PROXYPORT proxyport(pUMPD->pp);
|
|
|
|
if (proxyport.bValid())
|
|
{
|
|
proxyport.UnloadDriver(pUMPD->umpdCookie, hPrinter, bNotifySpooler);
|
|
}
|
|
}
|
|
|
|
ENTERCRITICALSECTION(&semUMPD);
|
|
|
|
if (pUMPD->iRefCount > 0)
|
|
{
|
|
pUMPD->iRefCount--;
|
|
}
|
|
|
|
if (pUMPD->iRefCount != 0 || pUMPD->pHandleList != NULL)
|
|
{
|
|
LEAVECRITICALSECTION(&semUMPD);
|
|
return FALSE;
|
|
}
|
|
|
|
// Remove the UMPD node from umpd cache list
|
|
|
|
for (ppStartUMPD = &gCachedUMPDList;
|
|
*ppStartUMPD;
|
|
ppStartUMPD = &((*ppStartUMPD)->pNext))
|
|
{
|
|
if (*ppStartUMPD == pUMPD)
|
|
{
|
|
*ppStartUMPD = pUMPD->pNext;
|
|
break;
|
|
}
|
|
}
|
|
|
|
LEAVECRITICALSECTION(&semUMPD);
|
|
|
|
if (gbWOW64)
|
|
{
|
|
PROXYPORT proxyport(pUMPD->pp);
|
|
|
|
if (proxyport.bValid())
|
|
proxyport.Close();
|
|
}
|
|
else
|
|
{
|
|
PFN pfn = pUMPD->apfn[INDEX_DrvDisableDriver];
|
|
|
|
if (pfn)
|
|
{
|
|
pfn();
|
|
}
|
|
|
|
FreeLibrary(pUMPD->hInst);
|
|
}
|
|
|
|
if (bNotifySpooler && pUMPD->pDriverInfo2->pDriverPath)
|
|
{
|
|
(*fpSplDriverUnloadComplete)(pUMPD->pDriverInfo2->pDriverPath);
|
|
}
|
|
|
|
LOCALFREE(pUMPD->pDriverInfo2);
|
|
LOCALFREE(pUMPD);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
PUMPD
|
|
UMPDDrvEnableDriver(
|
|
PWSTR pDriverDllName,
|
|
ULONG iEngineVersion
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Client-side stub for DrvEnableDriver
|
|
|
|
Arguments:
|
|
|
|
iDriverDllName - Name of the user-mode printer driver DLL
|
|
iEngineVersion - Same parameter as that for DrvEnableDriver
|
|
|
|
Return Value:
|
|
|
|
Pointer to the UMPD structure corresponding to the specified driver
|
|
NULL if there is an error
|
|
|
|
Note:
|
|
|
|
The pointer value returned by this function will be passed back from
|
|
the kernel-mode side to the user-mode side for each subsequent DDI call.
|
|
|
|
--*/
|
|
|
|
{
|
|
PUMPD pUMPD;
|
|
DRVENABLEDATA ded;
|
|
|
|
ENTERCRITICALSECTION(&semUMPD);
|
|
|
|
//
|
|
// Find the specified user-mode printer driver
|
|
//
|
|
|
|
pUMPD = FindUserModePrinterDriver(pDriverDllName, 0, FALSE);
|
|
|
|
if(pUMPD == NULL)
|
|
{
|
|
WARNING("failed to find printer driver\n");
|
|
return NULL;
|
|
}
|
|
|
|
if(pUMPD->hInst == NULL)
|
|
{
|
|
WARNING("driver library not loaded\n");
|
|
return NULL;
|
|
}
|
|
|
|
ASSERTGDI(pUMPD != NULL, "Non-existent user-mode printer driver.\n");
|
|
|
|
if (! (pUMPD->dwFlags & UMPDFLAG_DRVENABLEDRIVER_CALLED))
|
|
{
|
|
PFN_DrvEnableDriver pfn;
|
|
|
|
//
|
|
// If we haven't called DrvEnableDriver for this driver, do it now
|
|
//
|
|
|
|
if ((pfn = (PFN_DrvEnableDriver) GetProcAddress(pUMPD->hInst, "DrvEnableDriver")) &&
|
|
pfn(iEngineVersion, sizeof(ded), &ded))
|
|
{
|
|
PDRVFN pdrvfn;
|
|
ULONG count;
|
|
|
|
//
|
|
// Convert driver entrypoint function table to a more convenient format
|
|
//
|
|
|
|
for (pdrvfn = ded.pdrvfn, count = ded.c; count--; pdrvfn++)
|
|
{
|
|
if (pdrvfn->iFunc < INDEX_LAST)
|
|
pUMPD->apfn[pdrvfn->iFunc] = pdrvfn->pfn;
|
|
else
|
|
{
|
|
WARNING("Unrecognized DDI entrypoint index.\n");
|
|
}
|
|
}
|
|
|
|
pUMPD->dwFlags |= UMPDFLAG_DRVENABLEDRIVER_CALLED;
|
|
}
|
|
else
|
|
{
|
|
WARNING("DrvEnableDriver failed.\n");
|
|
pUMPD = NULL;
|
|
}
|
|
}
|
|
|
|
LEAVECRITICALSECTION(&semUMPD);
|
|
|
|
return pUMPD;
|
|
}
|
|
|
|
extern "C"
|
|
int DocumentEventEx(
|
|
PUMPD pUMPD,
|
|
HANDLE hPrinter,
|
|
HDC hdc,
|
|
int iEsc,
|
|
ULONG cjIn,
|
|
PVOID pvIn,
|
|
ULONG cjOut,
|
|
PVOID pvOut
|
|
)
|
|
{
|
|
int iRet;
|
|
|
|
if (WOW64PRINTING(pUMPD))
|
|
{
|
|
PROXYPORT proxyport(pUMPD->pp);
|
|
|
|
iRet = proxyport.DocumentEvent(pUMPD->umpdCookie, hPrinter,
|
|
hdc, iEsc, cjIn, pvIn, cjOut, pvOut);
|
|
}
|
|
else
|
|
{
|
|
iRet = (*fpDocumentEvent)(hPrinter, hdc, iEsc, cjIn, pvIn, cjOut, pvOut);
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
extern "C"
|
|
DWORD StartDocPrinterWEx(
|
|
PUMPD pUMPD,
|
|
HANDLE hPrinter,
|
|
DWORD level,
|
|
LPBYTE pDocInfo)
|
|
{
|
|
if (WOW64PRINTING(pUMPD) && level == 1)
|
|
{
|
|
PROXYPORT proxyport(pUMPD->pp);
|
|
|
|
return proxyport.StartDocPrinterW(pUMPD->umpdCookie,hPrinter, level, pDocInfo);
|
|
}
|
|
else
|
|
return (*fpStartDocPrinterW)(hPrinter, level, pDocInfo);
|
|
}
|
|
|
|
extern "C"
|
|
BOOL EndDocPrinterEx(PUMPD pUMPD, HANDLE hPrinter)
|
|
{
|
|
if (WOW64PRINTING(pUMPD))
|
|
{
|
|
PROXYPORT proxyport(pUMPD->pp);
|
|
|
|
return proxyport.EndDocPrinter(pUMPD->umpdCookie, hPrinter);
|
|
}
|
|
else
|
|
return (*fpEndDocPrinter)(hPrinter);
|
|
}
|
|
|
|
extern "C"
|
|
BOOL StartPagePrinterEx(PUMPD pUMPD, HANDLE hPrinter)
|
|
{
|
|
if (WOW64PRINTING(pUMPD))
|
|
{
|
|
PROXYPORT proxyport(pUMPD->pp);
|
|
|
|
return proxyport.StartPagePrinter(pUMPD->umpdCookie, hPrinter);
|
|
}
|
|
else
|
|
return (*fpStartPagePrinter)(hPrinter);
|
|
}
|
|
|
|
extern "C"
|
|
BOOL EndPagePrinterEx(PUMPD pUMPD, HANDLE hPrinter)
|
|
{
|
|
if (WOW64PRINTING(pUMPD))
|
|
{
|
|
PROXYPORT proxyport(pUMPD->pp);
|
|
|
|
return proxyport.EndPagePrinter(pUMPD->umpdCookie, hPrinter);
|
|
}
|
|
else
|
|
return (*fpEndPagePrinter)(hPrinter);
|
|
}
|
|
|
|
extern "C"
|
|
BOOL AbortPrinterEx(PLDC pldc, BOOL bEMF)
|
|
{
|
|
if (!bEMF && WOW64PRINTING(pldc->pUMPD))
|
|
{
|
|
PROXYPORT proxyport(pldc->pUMPD->pp);
|
|
|
|
return proxyport.AbortPrinter(pldc->pUMPD->umpdCookie, pldc->hSpooler);
|
|
}
|
|
else
|
|
return (*fpAbortPrinter)(pldc->hSpooler);
|
|
}
|
|
|
|
extern "C"
|
|
BOOL ResetPrinterWEx(PLDC pldc, PRINTER_DEFAULTSW *pPtrDef)
|
|
{
|
|
BOOL bRet = TRUE;
|
|
|
|
if (WOW64PRINTING(pldc->pUMPD))
|
|
{
|
|
if (!(pldc->fl & LDC_META_PRINT))
|
|
{
|
|
// either RAW printing or
|
|
// ResetDC called before StartDoc, don't know
|
|
// whether it is going RAW or EMF yet
|
|
|
|
PROXYPORT proxyport(pldc->pUMPD->pp);
|
|
|
|
bRet = proxyport.ResetPrinterW(pldc->pUMPD->umpdCookie, pldc->hSpooler, pPtrDef);
|
|
|
|
}
|
|
|
|
if (bRet && !(pldc->fl & LDC_PRINT_DIRECT))
|
|
{
|
|
// either EMF printing or
|
|
// ResetDC called before StartDoc, we need to
|
|
// call ResetPrinter on both 32-bit and 64-bit
|
|
// printer handles.
|
|
|
|
bRet = (*fpResetPrinterW)(pldc->hSpooler, pPtrDef);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
bRet = (*fpResetPrinterW)(pldc->hSpooler, pPtrDef);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
extern "C"
|
|
BOOL
|
|
QueryColorProfileEx(
|
|
PLDC pldc,
|
|
PDEVMODEW pDevMode,
|
|
ULONG ulQueryMode,
|
|
PVOID pvProfileData,
|
|
ULONG * pcjProfileSize,
|
|
FLONG * pflProfileFlag)
|
|
{
|
|
if (!(pldc->fl & LDC_META_PRINT) && WOW64PRINTING(pldc->pUMPD))
|
|
{
|
|
PROXYPORT proxyport(pldc->pUMPD->pp);
|
|
|
|
return proxyport.QueryColorProfile(pldc->pUMPD->umpdCookie,
|
|
pldc->hSpooler,
|
|
pDevMode,
|
|
ulQueryMode,
|
|
pvProfileData,
|
|
pcjProfileSize,
|
|
pflProfileFlag);
|
|
}
|
|
else
|
|
return (*fpQueryColorProfile)(pldc->hSpooler,
|
|
pDevMode,
|
|
ulQueryMode,
|
|
pvProfileData,
|
|
pcjProfileSize,
|
|
pflProfileFlag);
|
|
}
|
|
|
|
|
|
PPORT_MESSAGE
|
|
PROXYPORT::InitMsg(
|
|
PPROXYMSG Msg,
|
|
SERVERPTR pvIn,
|
|
ULONG cjIn,
|
|
SERVERPTR pvOut,
|
|
ULONG cjOut
|
|
)
|
|
{
|
|
Msg->h.u1.s1.DataLength = (short) (sizeof(*Msg) - sizeof(Msg->h));
|
|
Msg->h.u1.s1.TotalLength = (short) (sizeof(*Msg));
|
|
|
|
Msg->h.u2.ZeroInit = 0;
|
|
|
|
if(pvOut == 0) cjOut = 0;
|
|
|
|
Msg->cjIn = cjIn;
|
|
Msg->pvIn = pvIn;
|
|
|
|
Msg->cjOut = cjOut;
|
|
Msg->pvOut = pvOut;
|
|
|
|
return( (PPORT_MESSAGE)Msg );
|
|
}
|
|
|
|
BOOL
|
|
PROXYPORT::CheckMsg(
|
|
NTSTATUS Status,
|
|
PPROXYMSG Msg,
|
|
SERVERPTR pvOut,
|
|
ULONG cjOut
|
|
)
|
|
{
|
|
ULONG cbData = Msg->h.u1.s1.DataLength;
|
|
|
|
if (cbData == (sizeof(*Msg) - sizeof(Msg->h)))
|
|
{
|
|
if(pvOut != Msg->pvOut)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
if(cjOut != Msg->cjOut)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
// do nothing
|
|
|
|
}
|
|
else
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
NTSTATUS
|
|
PROXYPORT::SendRequest(
|
|
SERVERPTR pvIn,
|
|
ULONG cjIn,
|
|
SERVERPTR pvOut,
|
|
ULONG cjOut
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PROXYMSG Request;
|
|
PROXYMSG Reply;
|
|
|
|
InitMsg( &Request, pvIn, cjIn, pvOut, cjOut );
|
|
|
|
Status = NtRequestWaitReplyPort( pp->PortHandle,
|
|
(PPORT_MESSAGE)&Request,
|
|
(PPORT_MESSAGE)&Reply
|
|
);
|
|
|
|
if (!NT_SUCCESS( Status ))
|
|
{
|
|
return( Status );
|
|
}
|
|
|
|
if (Reply.h.u2.s2.Type == LPC_REPLY)
|
|
{
|
|
if (!CheckMsg( Status, &Reply, pvOut, cjOut ))
|
|
{
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
#define ALIGN_UMPD_BUFFER(cj) (((cj) + (sizeof(KERNEL_PVOID) -1)) & ~(sizeof(KERNEL_PVOID)-1))
|
|
|
|
SERVERPTR
|
|
PROXYPORT::HeapAlloc(ULONG inSize)
|
|
{
|
|
KPBYTE ptr;
|
|
|
|
if(pp->ClientMemoryAllocSize + ALIGN_UMPD_BUFFER(inSize) > pp->ClientMemorySize)
|
|
return 0;
|
|
|
|
ptr = pp->ClientMemoryBase + pp->ClientMemoryAllocSize + pp->ServerMemoryDelta;
|
|
|
|
pp->ClientMemoryAllocSize += ALIGN_UMPD_BUFFER(inSize);
|
|
|
|
return (SERVERPTR) ptr;
|
|
}
|
|
|
|
|
|
PROXYPORT::PROXYPORT(ULONGLONG inMaxSize)
|
|
{
|
|
NTSTATUS Status;
|
|
PORT_VIEW ClientView;
|
|
ULONG MaxMessageLength;
|
|
LARGE_INTEGER MaximumSize;
|
|
UNICODE_STRING PortName;
|
|
SECURITY_QUALITY_OF_SERVICE DynamicQos;
|
|
WCHAR awcPortName[MAX_PATH] = {0};
|
|
DWORD CurrSessionId;
|
|
DWORD CurrProcessId = GetCurrentProcessId();
|
|
|
|
ProcessIdToSessionId(CurrProcessId,&CurrSessionId);
|
|
wsprintfW(awcPortName, L"%s_%x", L"\\RPC Control\\UmpdProxy", CurrSessionId);
|
|
|
|
DynamicQos.Length = 0;
|
|
DynamicQos.ImpersonationLevel = SecurityImpersonation;
|
|
DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
|
DynamicQos.EffectiveOnly = TRUE;
|
|
|
|
|
|
if ((pp = (ProxyPort *) LOCALALLOC(sizeof(ProxyPort))) == NULL ||
|
|
!NT_SUCCESS((NTSTATUS)INITIALIZECRITICALSECTION(&pp->semPort)))
|
|
{
|
|
WARNING("PROXYPORT::PROXYPORT mem alloc OR critical section init failed\n");
|
|
|
|
if (pp)
|
|
LOCALFREE(pp);
|
|
|
|
pp = NULL;
|
|
return;
|
|
}
|
|
|
|
pp->ClientMemoryBase = 0;
|
|
pp->ClientMemorySize = 0;
|
|
pp->ClientMemoryAllocSize = 0;
|
|
pp->PortHandle = NULL;
|
|
pp->ServerMemoryBase = 0;
|
|
pp->ServerMemoryDelta = 0;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
RtlInitUnicodeString( &PortName, awcPortName );
|
|
|
|
MaximumSize.QuadPart = inMaxSize;
|
|
|
|
ZeroMemory(&ClientView.SectionHandle, sizeof(ClientView.SectionHandle));
|
|
|
|
Status = NtCreateSection( (PHANDLE)&ClientView.SectionHandle,
|
|
SECTION_MAP_READ | SECTION_MAP_WRITE,
|
|
NULL,
|
|
&MaximumSize,
|
|
PAGE_READWRITE,
|
|
SEC_COMMIT,
|
|
NULL
|
|
);
|
|
|
|
if (NT_SUCCESS( Status ))
|
|
{
|
|
ClientView.Length = sizeof( ClientView );
|
|
ClientView.SectionOffset = 0;
|
|
ClientView.ViewSize = (LPC_SIZE_T) inMaxSize;
|
|
ClientView.ViewBase = 0;
|
|
ClientView.ViewRemoteBase = 0;
|
|
|
|
if (BLOADSPOOLER &&
|
|
(*fpLoadSplWow64)(NULL) == ERROR_SUCCESS)
|
|
{
|
|
Status = NtConnectPort( &pp->PortHandle,
|
|
&PortName,
|
|
&DynamicQos,
|
|
&ClientView,
|
|
NULL,
|
|
(PULONG)&MaxMessageLength,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if (NT_SUCCESS( Status ))
|
|
{
|
|
pp->SectionHandle = (HANDLE)ClientView.SectionHandle;
|
|
pp->ClientMemoryBase = (KPBYTE)ClientView.ViewBase;
|
|
pp->ClientMemorySize = (SIZE_T)inMaxSize;
|
|
pp->ServerMemoryBase = (KPBYTE)ClientView.ViewRemoteBase;
|
|
pp->ServerMemoryDelta = pp->ServerMemoryBase -
|
|
pp->ClientMemoryBase;
|
|
|
|
NtRegisterThreadTerminatePort(pp->PortHandle);
|
|
}
|
|
else
|
|
{
|
|
WARNING("PROXYPORT::PROXYPORT: NtConnectPort failed\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
WARNING("PROXYPORT::PROXYPORT failed to load spooler or splwow64\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("PROXYPORT::PROXYPORT: failed to create section\n");
|
|
}
|
|
|
|
if(!NT_SUCCESS( Status ))
|
|
{
|
|
if ((HANDLE)ClientView.SectionHandle)
|
|
{
|
|
NtClose((HANDLE)ClientView.SectionHandle);
|
|
}
|
|
|
|
DELETECRITICALSECTION(&pp->semPort);
|
|
LOCALFREE(pp);
|
|
|
|
pp = NULL;
|
|
}
|
|
else
|
|
{
|
|
// grab port access
|
|
|
|
ENTERCRITICALSECTION(&pp->semPort);
|
|
}
|
|
}
|
|
|
|
void
|
|
PROXYPORT::Close()
|
|
{
|
|
if (pp->SectionHandle)
|
|
{
|
|
if (!CloseHandle(pp->SectionHandle))
|
|
{
|
|
WARNING("PROXYPORT::Close failed to close the section handle\n");
|
|
}
|
|
}
|
|
|
|
if (pp->PortHandle != NULL)
|
|
{
|
|
if (!CloseHandle( pp->PortHandle ))
|
|
{
|
|
WARNING("PROXYPORT::Close failed to close the port handle\n");
|
|
}
|
|
}
|
|
|
|
LEAVECRITICALSECTION(&pp->semPort);
|
|
DELETECRITICALSECTION(&pp->semPort);
|
|
LOCALFREE(pp);
|
|
|
|
pp = NULL;
|
|
}
|
|
|
|
void vUMPDWow64Shutdown()
|
|
{
|
|
PUMPD pUMPD = gCachedUMPDList;
|
|
|
|
while(pUMPD)
|
|
{
|
|
if (pUMPD->pp)
|
|
{
|
|
PROXYPORT proxyPort(pUMPD->pp);
|
|
|
|
proxyPort.Shutdown();
|
|
}
|
|
pUMPD = pUMPD->pNext;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
PROXYPORT::ThunkMemBlock(
|
|
KPBYTE * ptr,
|
|
ULONG size)
|
|
{
|
|
BOOL bRet = TRUE;
|
|
|
|
if (*ptr)
|
|
{
|
|
SERVERPTR sp = HeapAlloc(size);
|
|
CLIENTPTR cp = ServerToClientPtr(sp);
|
|
|
|
if (cp)
|
|
{
|
|
RtlCopyMemory((PVOID)cp, (PVOID)*ptr, size);
|
|
*ptr = sp;
|
|
}
|
|
else
|
|
bRet = FALSE;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BOOL
|
|
PROXYPORT::ThunkStr(LPWSTR * ioLpstr)
|
|
{
|
|
BOOL bRet = TRUE;
|
|
|
|
if(*ioLpstr != NULL)
|
|
{
|
|
bRet = ThunkMemBlock((KPBYTE *) ioLpstr, (wcslen(*ioLpstr) + 1) * sizeof(WCHAR));
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
KERNEL_PVOID
|
|
PROXYPORT::LoadDriver(
|
|
PDRIVER_INFO_5W pDriverInfo,
|
|
LPWSTR pwstrPrinterName,
|
|
PRINTER_DEFAULTSW* pdefaults,
|
|
HANDLE hPrinter32
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
SERVERPTR spInput;
|
|
SERVERPTR spOutput;
|
|
LOADDRIVERINPUT* pInput;
|
|
KERNEL_PVOID umpdCookie = NULL;
|
|
|
|
HeapInit();
|
|
|
|
if (!(spInput = HeapAlloc(sizeof(LOADDRIVERINPUT))) ||
|
|
!(spOutput = HeapAlloc(sizeof(KERNEL_PVOID))))
|
|
return NULL;
|
|
|
|
pInput = (LOADDRIVERINPUT *) ServerToClientPtr(spInput);
|
|
|
|
pInput->driverInfo.cVersion = pDriverInfo->cVersion;
|
|
pInput->driverInfo.pName = (KLPWSTR)pDriverInfo->pName;
|
|
pInput->driverInfo.pEnvironment = (KLPWSTR)pDriverInfo->pEnvironment;
|
|
pInput->driverInfo.pDriverPath = (KLPWSTR)pDriverInfo->pDriverPath;
|
|
pInput->driverInfo.pDataFile = (KLPWSTR)pDriverInfo->pDataFile;
|
|
pInput->driverInfo.pConfigFile = (KLPWSTR)pDriverInfo->pConfigFile;
|
|
pInput->driverInfo.dwDriverAttributes = pDriverInfo->dwDriverAttributes;
|
|
pInput->driverInfo.dwConfigVersion = pDriverInfo->dwConfigVersion;
|
|
pInput->driverInfo.dwDriverVersion = pDriverInfo->dwDriverVersion;
|
|
pInput->clientPid = GetCurrentProcessId();
|
|
pInput->hPrinter32 = HandleToUlong(hPrinter32);
|
|
|
|
pInput->pPrinterName = (KLPWSTR)pwstrPrinterName;
|
|
|
|
pInput->defaults.pDatatype = (KLPWSTR)pdefaults->pDatatype;
|
|
pInput->defaults.pDevMode = (KPBYTE)pdefaults->pDevMode;
|
|
pInput->defaults.DesiredAccess = pdefaults->DesiredAccess;
|
|
|
|
if (!ThunkStr((LPWSTR *)&pInput->driverInfo.pName) ||
|
|
!ThunkStr((LPWSTR *)&pInput->driverInfo.pEnvironment) ||
|
|
!ThunkStr((LPWSTR *)&pInput->driverInfo.pDriverPath) ||
|
|
!ThunkStr((LPWSTR *)&pInput->driverInfo.pDataFile) ||
|
|
!ThunkStr((LPWSTR *)&pInput->driverInfo.pConfigFile) ||
|
|
!ThunkStr((LPWSTR *)&pInput->pPrinterName) ||
|
|
!ThunkStr((LPWSTR *)&pInput->defaults.pDatatype) ||
|
|
!ThunkMemBlock(&pInput->defaults.pDevMode, sizeof(DEVMODEW))
|
|
)
|
|
return NULL;
|
|
|
|
pInput->umpdthdr.umthdr.ulType = INDEX_LoadUMPrinterDrv;
|
|
|
|
Status = SendRequest(spInput, sizeof(LOADDRIVERINPUT),
|
|
spOutput, sizeof(KERNEL_PVOID));
|
|
|
|
if (NT_SUCCESS( Status ))
|
|
{
|
|
umpdCookie = *((KERNEL_PVOID *) ServerToClientPtr(spOutput));
|
|
}
|
|
|
|
return umpdCookie;
|
|
}
|
|
|
|
void
|
|
PROXYPORT::UnloadDriver(
|
|
KERNEL_PVOID umpdCookie,
|
|
HANDLE hPrinter32,
|
|
BOOL bNotifySpooler
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
SERVERPTR spInput;
|
|
UNLOADDRIVERINPUT * pInput;
|
|
|
|
HeapInit();
|
|
|
|
if (spInput = HeapAlloc(sizeof(UNLOADDRIVERINPUT)))
|
|
{
|
|
pInput = (UNLOADDRIVERINPUT *) ServerToClientPtr(spInput);
|
|
|
|
pInput->umpdCookie = umpdCookie;
|
|
pInput->clientPid = GetCurrentProcessId();
|
|
pInput->hPrinter32 = HandleToUlong(hPrinter32);
|
|
pInput->bNotifySpooler = bNotifySpooler;
|
|
|
|
pInput->umpdthdr.umthdr.ulType = INDEX_UnloadUMPrinterDrv;
|
|
|
|
Status = SendRequest(spInput, sizeof(spInput), 0, 0);
|
|
}
|
|
}
|
|
|
|
int
|
|
PROXYPORT::DocumentEvent(
|
|
KERNEL_PVOID umpdCookie,
|
|
HANDLE hPrinter32,
|
|
HDC hdc,
|
|
INT iEsc,
|
|
ULONG cjIn,
|
|
PVOID pvIn,
|
|
ULONG cjOut,
|
|
PVOID pvOut
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
SERVERPTR spInput;
|
|
SERVERPTR spOutput;
|
|
DOCUMENTEVENTINPUT* pInput;
|
|
CLIENTPTR cppvIn = NULL;
|
|
INT iRet = DOCUMENTEVENT_FAILURE;
|
|
ULONG cjAlloc = 0;
|
|
DEVMODEW *pdmCopy = NULL;
|
|
|
|
HeapInit();
|
|
|
|
if (!(spInput = HeapAlloc(sizeof(DOCUMENTEVENTINPUT))) ||
|
|
!(pInput = (DOCUMENTEVENTINPUT *) ServerToClientPtr(spInput)) ||
|
|
!(spOutput = HeapAlloc(sizeof(int))))
|
|
{
|
|
return DOCUMENTEVENT_FAILURE;
|
|
}
|
|
|
|
pInput->umpdthdr.umthdr.ulType = INDEX_DocumentEvent;
|
|
pInput->umpdthdr.umthdr.cjSize = sizeof(*pInput);
|
|
pInput->umpdCookie = umpdCookie;
|
|
pInput->clientPid = GetCurrentProcessId();
|
|
pInput->hPrinter32 = HandleToUlong(hPrinter32);
|
|
pInput->hdc = (KHDC)hdc;
|
|
pInput->iEsc = iEsc;
|
|
pInput->cjIn = cjIn;
|
|
pInput->pvIn = NULL;
|
|
pInput->cjOut = cjOut;
|
|
pInput->pvOut = NULL;
|
|
pInput->pdmCopy = NULL;
|
|
|
|
// thunk input data
|
|
|
|
if (cjIn && pvIn)
|
|
{
|
|
if (iEsc == DOCUMENTEVENT_CREATEDCPRE)
|
|
{
|
|
cjAlloc = sizeof(DOCEVENT_CREATEDCPRE_UMPD);
|
|
}
|
|
else if (iEsc == DOCUMENTEVENT_CREATEDCPOST ||
|
|
iEsc == DOCUMENTEVENT_RESETDCPRE ||
|
|
iEsc == DOCUMENTEVENT_RESETDCPOST ||
|
|
iEsc == DOCUMENTEVENT_STARTDOCPRE)
|
|
{
|
|
cjAlloc = sizeof(KPBYTE);
|
|
}
|
|
else if (iEsc == DOCUMENTEVENT_ESCAPE)
|
|
{
|
|
cjAlloc = sizeof(DOCEVENT_ESCAPE_UMPD);
|
|
}
|
|
|
|
// allocate heap
|
|
|
|
if (cjAlloc)
|
|
{
|
|
if (!(pInput->pvIn = HeapAlloc(cjAlloc)))
|
|
{
|
|
return DOCUMENTEVENT_FAILURE;
|
|
}
|
|
|
|
pInput->cjIn = cjAlloc;
|
|
cppvIn = ServerToClientPtr(pInput->pvIn);
|
|
}
|
|
|
|
switch (iEsc)
|
|
{
|
|
case DOCUMENTEVENT_CREATEDCPRE:
|
|
{
|
|
DOCEVENT_CREATEDCPRE_UMPD *pDocEvent = (DOCEVENT_CREATEDCPRE_UMPD*)cppvIn;
|
|
DOCEVENT_CREATEDCPRE *pDocEventIn = (DOCEVENT_CREATEDCPRE*)pvIn;
|
|
|
|
pDocEvent->pszDriver = (KPBYTE)0;
|
|
pDocEvent->pszDevice = (KPBYTE)pDocEventIn->pszDevice;
|
|
pDocEvent->pdm = (KPBYTE)pDocEventIn->pdm;
|
|
pDocEvent->bIC = pDocEventIn->bIC;
|
|
|
|
if (!ThunkStr((LPWSTR*)&pDocEvent->pszDevice) ||
|
|
!ThunkMemBlock(&pDocEvent->pdm, sizeof(DEVMODEW)))
|
|
{
|
|
return DOCUMENTEVENT_FAILURE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DOCUMENTEVENT_RESETDCPRE:
|
|
{
|
|
*((KPBYTE*)cppvIn) = (KPBYTE)(*((DEVMODEW**)pvIn));
|
|
|
|
if (!ThunkMemBlock((KPBYTE*)cppvIn, sizeof(DEVMODEW)))
|
|
return DOCUMENTEVENT_FAILURE;
|
|
}
|
|
break;
|
|
|
|
case DOCUMENTEVENT_STARTDOCPRE:
|
|
{
|
|
SERVERPTR spTemp;
|
|
DOCINFOW_UMPD *pDocInfo;
|
|
DOCINFOW *pDocInfoIn = *((DOCINFOW**)pvIn);
|
|
|
|
if (!(spTemp = HeapAlloc(sizeof(DOCINFOW_UMPD))))
|
|
return DOCUMENTEVENT_FAILURE;
|
|
|
|
*((KPBYTE*)cppvIn) = spTemp;
|
|
pDocInfo = (DOCINFOW_UMPD*)ServerToClientPtr(spTemp);
|
|
|
|
pDocInfo->cbSize = pDocInfoIn->cbSize;
|
|
pDocInfo->lpszDocName = (KLPWSTR)pDocInfoIn->lpszDocName;
|
|
pDocInfo->lpszOutput = (KLPWSTR)pDocInfoIn->lpszOutput;
|
|
pDocInfo->lpszDatatype = (KLPWSTR)pDocInfoIn->lpszDatatype;
|
|
pDocInfo->fwType = pDocInfoIn->fwType;
|
|
|
|
if (!ThunkStr((LPWSTR*)&pDocInfo->lpszDocName) ||
|
|
!ThunkStr((LPWSTR*)&pDocInfo->lpszOutput) ||
|
|
!ThunkStr((LPWSTR*)&pDocInfo->lpszDatatype))
|
|
{
|
|
return DOCUMENTEVENT_FAILURE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DOCUMENTEVENT_CREATEDCPOST:
|
|
case DOCUMENTEVENT_RESETDCPOST:
|
|
{
|
|
if (*((PDEVMODEW *)pvIn))
|
|
{
|
|
KPBYTE *ppdmDrv = (KPBYTE*)(*((PBYTE*)pvIn) + sizeof(DEVMODEW));
|
|
|
|
*((KPBYTE*)cppvIn) = *ppdmDrv;
|
|
|
|
LOCALFREE(*(PBYTE*)pvIn);
|
|
}
|
|
else
|
|
{
|
|
*((KPBYTE*)cppvIn) = NULL;
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case DOCUMENTEVENT_STARTDOCPOST:
|
|
{
|
|
pInput->pvIn = (KPBYTE)pvIn;
|
|
|
|
if (!ThunkMemBlock(&pInput->pvIn, sizeof(LONG)))
|
|
return DOCUMENTEVENT_FAILURE;
|
|
}
|
|
break;
|
|
|
|
case DOCUMENTEVENT_ESCAPE:
|
|
{
|
|
DOCEVENT_ESCAPE_UMPD *pEscape = (DOCEVENT_ESCAPE_UMPD*)cppvIn;
|
|
DOCEVENT_ESCAPE *pEscapeIn = (DOCEVENT_ESCAPE*)pvIn;
|
|
|
|
pEscape->iEscape = pEscapeIn->iEscape;
|
|
pEscape->cjInput = pEscapeIn->cjInput;
|
|
pEscape->pvInData = (KPBYTE)pEscapeIn->pvInData;
|
|
|
|
if (!ThunkMemBlock(&pEscape->pvInData, (ULONG)pEscapeIn->cjInput))
|
|
return DOCUMENTEVENT_FAILURE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return DOCUMENTEVENT_FAILURE;
|
|
}
|
|
}
|
|
|
|
if (cjOut && pvOut)
|
|
{
|
|
if (iEsc == DOCUMENTEVENT_CREATEDCPRE || iEsc == DOCUMENTEVENT_RESETDCPRE)
|
|
{
|
|
if (!(pInput->pvOut = HeapAlloc(sizeof(KPBYTE))) ||
|
|
!(pInput->pdmCopy = HeapAlloc(sizeof(DEVMODEW))) ||
|
|
!(pdmCopy = (DEVMODEW*)LOCALALLOC(sizeof(DEVMODEW) + sizeof(KPBYTE))))
|
|
{
|
|
return DOCUMENTEVENT_FAILURE;
|
|
}
|
|
|
|
*((KPBYTE*)ServerToClientPtr(pInput->pvOut)) = 0;
|
|
pInput->cjOut = sizeof(KPBYTE);
|
|
}
|
|
else if (iEsc == DOCUMENTEVENT_ESCAPE)
|
|
{
|
|
if (!(pInput->pvOut = HeapAlloc(cjOut)))
|
|
return DOCUMENTEVENT_FAILURE;
|
|
}
|
|
}
|
|
|
|
Status = SendRequest(spInput, sizeof(DOCUMENTEVENTINPUT), spOutput, sizeof(int));
|
|
|
|
if (NT_SUCCESS( Status ))
|
|
{
|
|
iRet = *((int *) ServerToClientPtr(spOutput));
|
|
|
|
if (iRet != DOCUMENTEVENT_FAILURE)
|
|
{
|
|
if (iEsc == DOCUMENTEVENT_CREATEDCPRE || iEsc == DOCUMENTEVENT_RESETDCPRE)
|
|
{
|
|
PDEVMODEW *ppvOut = (PDEVMODEW*)pvOut;
|
|
KPBYTE kpdm = *((KPBYTE*)ServerToClientPtr(pInput->pvOut));
|
|
|
|
ASSERTGDI(pvOut, "ProxyPort::DocumentEvent pvOut NULL\n");
|
|
|
|
*ppvOut = kpdm ? pdmCopy : NULL;
|
|
|
|
if (kpdm)
|
|
{
|
|
RtlCopyMemory(pdmCopy, (PVOID)ServerToClientPtr(pInput->pdmCopy), sizeof(DEVMODEW));
|
|
|
|
KPBYTE *ppdmDrv = (KPBYTE*)((PBYTE)pdmCopy + sizeof(DEVMODEW));
|
|
|
|
*ppdmDrv = kpdm;
|
|
}
|
|
else
|
|
{
|
|
LOCALFREE(pdmCopy);
|
|
}
|
|
}
|
|
else if (iEsc == DOCUMENTEVENT_ESCAPE)
|
|
{
|
|
if (cjOut && pvOut)
|
|
RtlCopyMemory(pvOut, (PVOID)ServerToClientPtr(pInput->pvOut), cjOut);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DocumentEvent failed \n");
|
|
}
|
|
}
|
|
|
|
if (iRet == DOCUMENTEVENT_FAILURE && pdmCopy)
|
|
{
|
|
LOCALFREE(pdmCopy);
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
|
|
DWORD
|
|
PROXYPORT::StartDocPrinterW(
|
|
KERNEL_PVOID umpdCookie,
|
|
HANDLE hPrinter32,
|
|
DWORD level,
|
|
LPBYTE pDocInfo
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
SERVERPTR spInput;
|
|
SERVERPTR spOutput;
|
|
STARTDOCPRINTERWINPUT* pInput;
|
|
CLIENTPTR cppDocInfo;
|
|
|
|
HeapInit();
|
|
|
|
if (!(spInput = HeapAlloc(sizeof(STARTDOCPRINTERWINPUT))) ||
|
|
!(spOutput = HeapAlloc(sizeof(DWORD))))
|
|
return 0;
|
|
|
|
pInput = (STARTDOCPRINTERWINPUT *) ServerToClientPtr(spInput);
|
|
|
|
pInput->umpdthdr.umthdr.ulType = INDEX_StartDocPrinterW;
|
|
pInput->umpdthdr.umthdr.cjSize = sizeof(*pInput);
|
|
pInput->umpdCookie = umpdCookie;
|
|
pInput->clientPid = GetCurrentProcessId();
|
|
pInput->hPrinter32 = HandleToUlong(hPrinter32);
|
|
pInput->level = level;
|
|
pInput->lastError = 0;
|
|
pInput->docInfo.pDocName = (KLPWSTR)((DOC_INFO_1W*)pDocInfo)->pDocName;
|
|
pInput->docInfo.pOutputFile = (KLPWSTR)((DOC_INFO_1W*)pDocInfo)->pOutputFile;
|
|
pInput->docInfo.pDatatype = (KLPWSTR)((DOC_INFO_1W*)pDocInfo)->pDatatype;
|
|
|
|
// GDI only uses level 1 and level 3
|
|
if (level == 3)
|
|
pInput->docInfo.dwFlags = ((DOC_INFO_3W*)pDocInfo)->dwFlags;
|
|
else
|
|
pInput->docInfo.dwFlags = 0;
|
|
|
|
if (!ThunkStr((LPWSTR *)&pInput->docInfo.pDocName) ||
|
|
!ThunkStr((LPWSTR *)&pInput->docInfo.pOutputFile) ||
|
|
!ThunkStr((LPWSTR *)&pInput->docInfo.pDatatype))
|
|
return 0;
|
|
|
|
Status = SendRequest(spInput, sizeof(STARTDOCPRINTERWINPUT), spOutput, sizeof(DWORD));
|
|
|
|
if (!NT_SUCCESS( Status ))
|
|
return 0;
|
|
else
|
|
{
|
|
if (pInput->lastError)
|
|
GdiSetLastError(pInput->lastError);
|
|
return (*((DWORD *) ServerToClientPtr(spOutput)));
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
PROXYPORT::StartPagePrinter(KERNEL_PVOID umpdCookie, HANDLE hPrinter32)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
SERVERPTR spInput;
|
|
SERVERPTR spOutput;
|
|
UMPDSIMPLEINPUT* pInput;
|
|
|
|
HeapInit();
|
|
|
|
if (!(spInput = HeapAlloc(sizeof(UMPDSIMPLEINPUT))) ||
|
|
!(spOutput = HeapAlloc(sizeof(BOOL))))
|
|
return FALSE;
|
|
|
|
pInput = (UMPDSIMPLEINPUT *) ServerToClientPtr(spInput);
|
|
|
|
pInput->umpdthdr.umthdr.ulType = INDEX_StartPagePrinter;
|
|
pInput->umpdthdr.umthdr.cjSize = sizeof(UMPDSIMPLEINPUT);
|
|
pInput->umpdCookie = umpdCookie;
|
|
pInput->clientPid = GetCurrentProcessId();
|
|
pInput->hPrinter32 = HandleToUlong(hPrinter32);
|
|
|
|
Status = SendRequest(spInput, sizeof(UMPDSIMPLEINPUT), spOutput, sizeof(BOOL));
|
|
|
|
if (!NT_SUCCESS( Status ))
|
|
return FALSE;
|
|
|
|
return (*((BOOL*)ServerToClientPtr(spOutput)));
|
|
}
|
|
|
|
BOOL
|
|
PROXYPORT::EndPagePrinter(KERNEL_PVOID umpdCookie, HANDLE hPrinter32)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
SERVERPTR spInput;
|
|
SERVERPTR spOutput;
|
|
UMPDSIMPLEINPUT* pInput;
|
|
|
|
HeapInit();
|
|
|
|
if (!(spInput = HeapAlloc(sizeof(UMPDSIMPLEINPUT))) ||
|
|
!(spOutput = HeapAlloc(sizeof(BOOL))))
|
|
return FALSE;
|
|
|
|
pInput = (UMPDSIMPLEINPUT *) ServerToClientPtr(spInput);
|
|
|
|
pInput->umpdthdr.umthdr.ulType = INDEX_EndPagePrinter;
|
|
pInput->umpdthdr.umthdr.cjSize = sizeof(UMPDSIMPLEINPUT);
|
|
pInput->umpdCookie = umpdCookie;
|
|
pInput->clientPid = GetCurrentProcessId();
|
|
pInput->hPrinter32 = HandleToUlong(hPrinter32);
|
|
|
|
Status = SendRequest(spInput, sizeof(UMPDSIMPLEINPUT), spOutput, sizeof(BOOL));
|
|
|
|
if (!NT_SUCCESS( Status ))
|
|
return FALSE;
|
|
|
|
return (*((BOOL*)ServerToClientPtr(spOutput)));
|
|
}
|
|
|
|
BOOL
|
|
PROXYPORT::EndDocPrinter(KERNEL_PVOID umpdCookie, HANDLE hPrinter32)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
SERVERPTR spInput;
|
|
SERVERPTR spOutput;
|
|
UMPDSIMPLEINPUT* pInput;
|
|
|
|
HeapInit();
|
|
|
|
if (!(spInput = HeapAlloc(sizeof(UMPDSIMPLEINPUT))) ||
|
|
!(spOutput = HeapAlloc(sizeof(BOOL))))
|
|
return FALSE;
|
|
|
|
pInput = (UMPDSIMPLEINPUT *) ServerToClientPtr(spInput);
|
|
|
|
pInput->umpdthdr.umthdr.ulType = INDEX_EndDocPrinter;
|
|
pInput->umpdthdr.umthdr.cjSize = sizeof(UMPDSIMPLEINPUT);
|
|
pInput->umpdCookie = umpdCookie;
|
|
pInput->clientPid = GetCurrentProcessId();
|
|
pInput->hPrinter32 = HandleToUlong(hPrinter32);
|
|
|
|
Status = SendRequest(spInput, sizeof(UMPDSIMPLEINPUT), spOutput, sizeof(BOOL));
|
|
|
|
if (!NT_SUCCESS( Status ))
|
|
return FALSE;
|
|
|
|
return (*((BOOL*)ServerToClientPtr(spOutput)));
|
|
}
|
|
|
|
|
|
BOOL
|
|
PROXYPORT::AbortPrinter(KERNEL_PVOID umpdCookie, HANDLE hPrinter32)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
SERVERPTR spInput;
|
|
SERVERPTR spOutput;
|
|
UMPDSIMPLEINPUT* pInput;
|
|
|
|
HeapInit();
|
|
|
|
if (!(spInput = HeapAlloc(sizeof(UMPDSIMPLEINPUT))) ||
|
|
!(spOutput = HeapAlloc(sizeof(BOOL))))
|
|
return FALSE;
|
|
|
|
pInput = (UMPDSIMPLEINPUT *) ServerToClientPtr(spInput);
|
|
|
|
pInput->umpdthdr.umthdr.ulType = INDEX_AbortPrinter;
|
|
pInput->umpdthdr.umthdr.cjSize = sizeof(UMPDSIMPLEINPUT);
|
|
pInput->umpdCookie = umpdCookie;
|
|
pInput->clientPid = GetCurrentProcessId();
|
|
pInput->hPrinter32 = HandleToUlong(hPrinter32);
|
|
|
|
Status = SendRequest(spInput, sizeof(UMPDSIMPLEINPUT), spOutput, sizeof(BOOL));
|
|
|
|
if (!NT_SUCCESS( Status ))
|
|
return FALSE;
|
|
|
|
return (*((BOOL*)ServerToClientPtr(spOutput)));
|
|
}
|
|
|
|
BOOL
|
|
PROXYPORT::ResetPrinterW(KERNEL_PVOID umpdCookie, HANDLE hPrinter32, PRINTER_DEFAULTSW *pPtrDef)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
SERVERPTR spInput;
|
|
SERVERPTR spOutput;
|
|
RESETPRINTERWINPUT* pInput;
|
|
|
|
HeapInit();
|
|
|
|
if (!(spInput = HeapAlloc(sizeof(RESETPRINTERWINPUT))) ||
|
|
!(spOutput = HeapAlloc(sizeof(BOOL))))
|
|
return FALSE;
|
|
|
|
pInput = (RESETPRINTERWINPUT *) ServerToClientPtr(spInput);
|
|
|
|
pInput->umpdthdr.umthdr.ulType = INDEX_ResetPrinterW;
|
|
pInput->umpdthdr.umthdr.cjSize = sizeof(RESETPRINTERWINPUT);
|
|
pInput->umpdCookie = umpdCookie;
|
|
pInput->clientPid = GetCurrentProcessId();
|
|
pInput->hPrinter32 = HandleToUlong(hPrinter32);
|
|
|
|
pInput->ptrDef.pDatatype = (KLPWSTR)pPtrDef->pDatatype;
|
|
pInput->ptrDef.pDevMode = (KPBYTE)pPtrDef->pDevMode;
|
|
pInput->ptrDef.DesiredAccess = pPtrDef->DesiredAccess;
|
|
|
|
if (!ThunkStr((LPWSTR *)&pInput->ptrDef.pDatatype) ||
|
|
!ThunkMemBlock(&pInput->ptrDef.pDevMode, sizeof(DEVMODEW)))
|
|
return FALSE;
|
|
|
|
Status = SendRequest(spInput, sizeof(RESETPRINTERWINPUT), spOutput, sizeof(BOOL));
|
|
|
|
if (!NT_SUCCESS( Status ))
|
|
return FALSE;
|
|
|
|
return (*((BOOL*)ServerToClientPtr(spOutput)));
|
|
}
|
|
|
|
BOOL
|
|
PROXYPORT::QueryColorProfile(
|
|
KERNEL_PVOID umpdCookie,
|
|
HANDLE hPrinter32,
|
|
PDEVMODEW pDevMode,
|
|
ULONG ulQueryMode,
|
|
PVOID pvProfileData,
|
|
ULONG* pcjProfileSize,
|
|
FLONG* pflProfileFlag
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
SERVERPTR spInput;
|
|
SERVERPTR spOutput;
|
|
QUERYCOLORPROFILEINPUT* pInput;
|
|
|
|
HeapInit();
|
|
|
|
if (!(spInput = HeapAlloc(sizeof(QUERYCOLORPROFILEINPUT))) ||
|
|
!(spOutput = HeapAlloc(sizeof(BOOL))))
|
|
return -1;
|
|
|
|
pInput = (QUERYCOLORPROFILEINPUT*) ServerToClientPtr(spInput);
|
|
|
|
pInput->umpdthdr.umthdr.ulType = INDEX_QueryColorProfile;
|
|
pInput->umpdthdr.umthdr.cjSize = sizeof(QUERYCOLORPROFILEINPUT);
|
|
pInput->umpdCookie = umpdCookie;
|
|
pInput->clientPid = GetCurrentProcessId();
|
|
pInput->hPrinter32 = HandleToUlong(hPrinter32);
|
|
|
|
pInput->pDevMode = pDevMode;
|
|
pInput->ulQueryMode = ulQueryMode;
|
|
pInput->cjProfileSize = *pcjProfileSize;
|
|
pInput->flProfileFlag = *pflProfileFlag;
|
|
pInput->lastError = 0;
|
|
|
|
if (!(pInput->pvProfileData = HeapAlloc(*pcjProfileSize)) ||
|
|
!ThunkMemBlock((KPBYTE*)&pInput->pDevMode, sizeof(DEVMODEW)))
|
|
return -1;
|
|
|
|
Status = SendRequest(spInput, sizeof(QUERYCOLORPROFILEINPUT), spOutput, sizeof(BOOL));
|
|
|
|
if (!NT_SUCCESS( Status ))
|
|
return -1;
|
|
else
|
|
{
|
|
if (pInput->lastError)
|
|
GdiSetLastError(pInput->lastError);
|
|
return (*((BOOL*)ServerToClientPtr(spOutput)));
|
|
}
|
|
}
|