views:

799

answers:

1

Good Day,

According to the following page:

http://msdn.microsoft.com/en-us/library/ms646964(VS.85).aspx

underneath the first graphic, "If the user clicks the OK button, PrintDlg returns TRUE and the PRINTDLG structure to return informmation about the user's selection".

In this case, my custom print dialog is nearly working, but I'm trying to extract the information about printer name, orientation, etc... My understanding is that in order to retrieve the printer name, I need to examine the hDevMode value from the PRINTDLG structure to see the printer name. Is there a function that will allow me to extract that info?

My code is like (where pdlg is my defined instance of the PRINTDLG structure):

        bool f = false;
        try
        {
            f = PrintDlg(ref pdlg);
            DEVMODE dm = pdlg.hDevMode;
            int k = 0;
        } catch (Exception ex) 
        {
            // hopefully it doesn't fail
        }

If someone has any pearlsof wisdom out there, I would sure appreciate any tips..

TIA,

coson

+1  A: 

The following shows how to extract the printer name and driver. The key is to do a GlobalLock on hDevNames, Marshal.PtrToStructure it into the CLR version of the struct, and then access its content. Remember to GlobalUnlock when done.

You could do something similar with hDevMode, which will get you information about the printer metrics and setup. You can find a C# declaration of the DEVMODE struct here.

using System;
using System.Runtime.InteropServices;

namespace ConsoleApplication3 {
    class Program {

        // Win32 struct declarations
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]
        [System.Runtime.InteropServices.ComVisible(false)]
        internal class PRINTDLG {
            public Int32 lStructSize;
            public IntPtr hwndOwner;
            public IntPtr hDevMode;
            public IntPtr hDevNames;
            public IntPtr hDC = IntPtr.Zero;
            public Int32 Flags;
            public Int16 FromPage = 0;
            public Int16 ToPage = 0;
            public Int16 MinPage = 0;
            public Int16 MaxPage = 0;
            public Int16 Copies = 0;
            public IntPtr hInstance = IntPtr.Zero;
            public IntPtr lCustData = IntPtr.Zero;
            public IntPtr lpfnPrintHook;
            public IntPtr lpfnSetupHook = IntPtr.Zero;
            public IntPtr lpPrintTemplateName = IntPtr.Zero;
            public IntPtr lpSetupTemplateName = IntPtr.Zero;
            public IntPtr hPrintTemplate = IntPtr.Zero;
            public IntPtr hSetupTemplate = IntPtr.Zero;
        }

        [StructLayout(LayoutKind.Sequential)]
        public class DEVNAMES {
            public short wDriverOffset;
            public short wDeviceOffset;
            public short wOutputOffset;
            public short wDefault;
        }

        // import PrintDlg, GlobalLock and GlobalUnlock
        [DllImport("comdlg32.dll", CharSet = CharSet.Auto)]
        private static extern bool PrintDlg([In, Out] PRINTDLG lppd);

        [DllImport("kernel32.dll")]
        private static extern IntPtr GlobalLock(IntPtr hMem);

        [DllImport("kernel32.dll")]
        private static extern bool GlobalUnlock(IntPtr hMem);

        static void Main(string[] args) {
            // show the printer dialog box
            PRINTDLG pd    = new PRINTDLG();
            pd.lStructSize = Marshal.SizeOf(pd);
            PrintDlg(pd);

            // here's the meat -- extract the printer information
            // out of pd.hDevNames...
            DEVNAMES devNames  = new DEVNAMES();

            // lock hDevNames into memory and get a pointer to it
            IntPtr   pDevNames = GlobalLock(pd.hDevNames);

            // marshal into a DEVNAME struct
            Marshal.PtrToStructure(pDevNames, devNames);

            // pull out the device and driver strings; hopefully not much of
            // that in DEVMODE
            string sDevice  = Marshal.PtrToStringUni((IntPtr) (
                pDevNames.ToInt32() +
                    devNames.wDeviceOffset * Marshal.SystemDefaultCharSize));
            string sDriver  = Marshal.PtrToStringUni((IntPtr) (
                pDevNames.ToInt32() +
                    devNames.wDriverOffset * Marshal.SystemDefaultCharSize));
            string sOutput  = Marshal.PtrToStringUni((IntPtr) (
                pDevNames.ToInt32() +
                    devNames.wOutputOffset * Marshal.SystemDefaultCharSize));

            // done -- release the global memory handle
            GlobalUnlock(pd.hDevNames);
        }
    }
}
Oren Trutner
Thank you so much. There is an issue attempting to open up DEVMODE.devName if the printer in question is longer than 32 characters. I was able to get additional information out, but that field ultimately couldn't be used, so I went with this
coson