Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make RawPrinterHelper work in both XPS_PATH and RAW data types?

Tags:

c#

printing

I am using RawPrinterHelper for printing. And it works fine with Windows 7 and previous versions. When we tried it with a printer installed on Windows 8 pc, it did not work.

After reading this post I've learned that I have to set dataType variable to "XPS_PASS" instead of "RAW". Setting it to "XPS_PASS" works fine on windows 8 by the way.

But in my environment, there are windows 8s and windows 7s and XPs also.

Is it possible to make this switch programmatically?

How can I set pDataType variable to "RAW" for windows 7 and lower operating systems, and to "XPS_PASS" to windows 8?

Edit: After a couple of hours digging google I've found this article. Here it says:

  1. Call GetPrinterDriver to retrieve the DRIVER_INFO_8 struct.
  2. Check DRIVER_INFO_8::dwPrinterDriverAttributes for the PRINTER_DRIVER_XPS flag.
  3. Choose your datatype based on the presence or absence of the flag:

    • If the flag is set, use ‘XPS_PASS’
    • If the flag is not set, use ‘RAW’

I am not familiar with unmanaged code, but I've tried the followig:

[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int GetPrinterDriver(IntPtr hPrinter, string pEnvironment, uint Level, IntPtr pDriverInfo, int cbBuf, out int pcbNeeded);



 private static void GetPrinterDataType(IntPtr hPrinter )
    {
        IntPtr driverInfo = new IntPtr();
        driverInfo = IntPtr.Zero;
        int buf_len = 0;
        int IntPtrSize = Marshal.SizeOf(typeof(IntPtr));

        int a = GetPrinterDriver(hPrinter, "", 8, driverInfo, 0, out buf_len);

        driverInfo = Marshal.AllocHGlobal(buf_len);

        a = GetPrinterDriver(hPrinter, "", 8, driverInfo, buf_len, out buf_len);

        for (int i = 0; i <= 24; i++)
        {
            if (i == 12 || i == 15 || i == 11 || i == 14)
                continue;

            IntPtr ptr = Marshal.ReadIntPtr(driverInfo, IntPtrSize * i);
            Console.WriteLine("DRIVER INFO {0}: {1}", i, Marshal.PtrToStringUni(ptr));
        }

    }

I am calling this method after OpenPrinter() method of the RawPrinterHelper class. But the dwPrinterDriverAttributes (number 21) is empty.

Am I doing something wrong?

Output of the method

like image 821
fkucuk Avatar asked Dec 07 '25 20:12

fkucuk


1 Answers

Okay, I've managed to work out how to get a value showing for the dwPrinterDriverAttributes field.

I added this definition of the DRIVER_INFO_8 structure to my solution (found here).

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct DRIVER_INFO_8
{
    public uint cVersion;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pName;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pEnvironment;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pDriverPath;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pDataFile;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pConfigFile;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pHelpFile;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pDependentFiles;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pMonitorName;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pDefaultDataType;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pszzPreviousNames;
    FILETIME ftDriverDate;
    UInt64 dwlDriverVersion;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pszMfgName;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pszOEMUrl;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pszHardwareID;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pszProvider;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pszPrintProcessor;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pszVendorSetup;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pszzColorProfiles;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pszInfPath;
    public uint dwPrinterDriverAttributes;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string pszzCoreDriverDependencies;
    FILETIME ftMinInboxDriverVerDate;
    UInt64 dwlMinInboxDriverVerVersion;
}

Then I added this line of code to what you have above in your GetPrinterDriverDataType() method:

var info = (DRIVER_INFO_8)Marshal.PtrToStructure(driverInfo, typeof(DRIVER_INFO_8));

Now you will be able to see what the dwPrinterDriverAttributes field is populated with.

EDIT: Updated the protection level of dwPrinterDriverAttributes to be public so it can be accessed/viewed.

Also worth noting this (found here):

dwPrinterDriverAttributes: A bit field that specifies attributes of the printer driver.

So I've converted the uint to a BitArray and checked to see if the PRINTER_DRIVER_XPS flag/bit is set.

i.e.

PRINTER_DRIVER_XPS flag = 0x00000002

So we need to check the second bit. I do this with the following:

var value = (int)info.dwPrinterDriverAttributes;
BitArray b = new BitArray(new int[] { value } );
bool[] bits = new bool[b.Count];
b.CopyTo(bits, 0);

if (bits[1]) 
    Console.WriteLine("flag set");
else
    Console.WriteLine("flag not set");
like image 120
Adam Jones Avatar answered Dec 10 '25 11:12

Adam Jones



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!