Search code examples
c#printingwindows-server-2012-r2printer-control-languageprint-spooler-api

Printing a PCL file in Windows Server 2012 R2 using C#


Is there something specific about Windows Server 2012 R2 that stops a PCL file from being printed using the method below?

I used a code I found online to generate a dll file from the url below (you might to scroll a little down to see the answer posted by Abel). How to print a pcl file in c#?

I used the generated library file and used the following code to print the file

string fileName = definedPath + randomFileName.pcl
if(File.Exists(fileName))
{
    //PrintRaw is the name I gave to the dll file I generated 
    PrintRaw.RawFilePrint.SendFileToPrinter(installedPrinterName, fileName);
}

That segment of code prints the pcl file on normal windows OS but when I tried it in Windows Server 2012 R2 it didn't print.

I tracked the print job as far as checking C:\Windows\System32\spool\PRINTERS and I do see the print job there briefly before it disappears which is what I expected. But nothing happened after that except the machine slowed down drastically.

Here are stuff that might help. 1. The same file cannot be used by the code to print again because it "is used by another process" 2. All printers are installed and using the correct name (literally copy and paste the name) 3. The code prints file both from the print server and locally installed printer on Windows 7, 8.1 and 10.

Please help!


Solution

  • With Server 2012 the most likely explanation is the printer is using a version 4 driver, which supports raw printing for XPS documents only.

    You can detect a v4 driver with this code:

    bool IsV4Driver(wchar_t* printerName)
    {
        HANDLE handle;
        PRINTER_DEFAULTS defaults;
    
        defaults.DesiredAccess = PRINTER_ACCESS_USE;
        defaults.pDatatype = L"RAW";
        defaults.pDevMode = NULL;
    
        if (::OpenPrinter(printerName, &handle, &defaults) == 0)
        {
            return false;
        }
    
        DWORD version = GetVersion(handle);
    
        ::ClosePrinter(handle);
    
        return version == 4;
    }
    
    DWORD GetVersion(HANDLE handle)
    {
        DWORD needed;
    
        ::GetPrinterDriver(handle, NULL, 2, NULL, 0, &needed);
        if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
        {
            return -1;
        }
    
        std::vector<char> buffer(needed);
        if (::GetPrinterDriver(handle, NULL, 2, (LPBYTE) &buffer[0], needed, &needed) == 0)
        {
            return -1;
        }
    
        return ((DRIVER_INFO_2*) &buffer[0])->cVersion;
    }
    

    If it's a v4 driver, you have to use the XPS_PASS data type to bypass the XPS driver chain and send the file directly to the printer as shown in this MSDN example.