2

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;
}
Wizetux
  • 756
  • 3
  • 12
  • I would hazard a guess that this is a problem with the specific printer driver rather than a universal problem with Windows. It would be worth checking whether there is an updated driver that might fix it. Otherwise, it seems likely that the only solution is to split your program into two parts, a 32-bit component and a 64-bit component, interacting via IPC. – Harry Johnston Apr 14 '16 at 23:47
  • Harry, That is what I thought at first, but it behaves the same with even a Windows provided driver and even for the "Microsoft XPS Document Writer" printer. – Wizetux Apr 14 '16 at 23:49
  • Win8 and above broke some stuff in printing and as best I can tell Microsoft has no intention of fixing it. For example, both Notepad and Wordpad somehow pass invalid pointers to the print driver's StartDoc entry point, but Windows catches the access violation and returns an error instead. Very odd behavior. So this doesn't surprise me at all given that splwow64.exe is involved when 32-bit apps print on 64-bit WIndows. Everything involving splwow64 is weird and doesn't work right. – Carey Gregory Jun 14 '16 at 14:22

0 Answers0