I have the need to get a printers DEVMODE structure after my application has impersonated a user. This works fine as long as my Architecture matches that of the Windows, 32bit application running on a 32bit OS, and vice versa. However, any call I make to DocumentProperties fails with either an ERROR CODE: 5 (Access is denied) on Windows 10, or RPC error on Windows 7 after the impersonation on a 32bit version of my application running on a 64bit OS. Unfortunately, the customer is not able to run the 64bit version of my application due to other legacy applications that it needs to interact with.
Does anyone know of a work around to this issue?
Here is a small sample code that will demonstrate the issue. You will need to build it as a x86 application and run it on a 64bit OS to see the issue.
// DocumentPropertiesTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <string>
#include <iostream>
#include "Winspool.h"
#include "DocumentPropertiesTest.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// The one and only application object
CWinApp theApp;
using namespace std;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
HMODULE hModule = ::GetModuleHandle(NULL);
if (hModule != NULL)
{
// initialize MFC and print and error on failure
if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
nRetCode = 1;
}
else
{
wstring username;
wstring domainName;
wstring password;
wstring printername;
int lastError;
cout << "Please specify a valid username: ";
wcin >> username;
cout << "Please specify the computer or domain name for the user. Use \".\" for this computer: ";
wcin >> domainName;
cout << "Please specify the users password: ";
wcin >> password;
cout << "Please give the printer name: ";
wcin.ignore();
getline (wcin, printername);
HANDLE pHandle;
HANDLE pPrinter;
if (LogonUser(username.c_str(), domainName.c_str(), password.c_str(), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &pHandle) != 0)
{
if (ImpersonateLoggedOnUser(pHandle) != 0)
{
PRINTER_DEFAULTS printerDefaults;
printerDefaults.pDatatype = NULL;
printerDefaults.pDevMode = NULL;
printerDefaults.DesiredAccess = PRINTER_ALL_ACCESS;
if (::OpenPrinter((LPWSTR)(printername.c_str()), &pPrinter, NULL))
{
int dSize = ::DocumentPropertiesW(NULL, pPrinter, (LPWSTR)(printername.c_str()), NULL, NULL, 0);
if (dSize > 0)
{
}
else
{
lastError = ::GetLastError();
cout << "Failed DocumentProperties with Error code: " << lastError << endl;
}
::ClosePrinter(pPrinter);
}
else
{
lastError = ::GetLastError();
cout << "Failed OpenPrinter with Error code: " << lastError << endl;
}
RevertToSelf();
}
else
{
lastError = ::GetLastError();
cout << "Failed ImpersonateLogonUser with Error code: " << lastError << endl;
}
}
else
{
lastError = ::GetLastError();
cout << "Failed LogonUser with Error code: " << lastError << endl;
}
system("pause");
}
}
else
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: GetModuleHandle failed\n"));
nRetCode = 1;
}
return nRetCode;
}