티스토리 뷰


WinForm에서는 친절하게도 PrintDialog라는 창을 통해 Print 설정을 조절할 수 있게 해주고 있습니다.


여기서 "기본설정"이라는 버튼을 누르면 또 이런 창이 뜨죠.


프린터 드라이버에서 지원하는 인쇄 기본 설정을 할 수 있는 창입니다.
이 글에서는 Winform에서 제공하는 PrintDialog창을 사용하지 않고, 이 창을 띄워보려는 건데요.
방법은 Win32 API의 DocumentProperties함수를 사용하면 됩니다.
        const int PRINTER_ACCESS_ADMINISTER = 0x00000004;
        const int PRINTER_ACCESS_USE = 0x00000008;
        const int STANDARD_RIGHTS_REQUIRED = 0x000F0000;
        const int PRINTER_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE;

        [StructLayout(LayoutKind.Sequential)]
        struct PRINTER_DEFAULTS
        {
            public IntPtr pDatatype;
            public IntPtr pDevMode;
            public int DesiredAccess;
        }

        [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
        static extern int OpenPrinter(string pPrinterName, out IntPtr phPrinter, ref PRINTER_DEFAULTS pDefault);

        [DllImport("winspool.drv", SetLastError = true)]
        static extern int ClosePrinter(IntPtr hPrinter);

        [DllImport("winspool.drv", EntryPoint = "DocumentPropertiesW", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter, [MarshalAs(UnmanagedType.LPWStr)] string pDeviceName, IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode);

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

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

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

        private void OpenPrinterPropertiesDialog()
        {
            // 현재 프린터 셋팅의 DefaultPageSettings에 대한 DEVMODE 구조체에 대한 핸들을 만든다.
            IntPtr hDevMode = PrinterSettings.GetHdevmode(PrinterSettings.DefaultPageSettings);
            IntPtr pDevMode = GlobalLock(hDevMode);
            IntPtr pPrinter = IntPtr.Zero;
            IntPtr nullPointer = IntPtr.Zero;

            PRINTER_DEFAULTS defaults = new PRINTER_DEFAULTS();
            defaults.DesiredAccess = PRINTER_ALL_ACCESS;

            // 현재 프린터 셋팅의 프린터 이름에 해당하는 프린터 핸들을 구한다.
            OpenPrinter(PrinterSettings.PrinterName, out pPrinter, ref defaults);

            // DocumentProperties 함수의 마지막 Parameter(fMode)의 값이 0이면 프린터 드라이버의 DEVMODE 구조체에 요구되는 크기를 반환한다.
            int sizeNeeded = DocumentProperties(this.Handle, pPrinter, PrinterSettings.PrinterName, pDevMode, pDevMode, 0);

            // DEVMODE 구조체 크기만큼 메모리를 할당한다. Printer 기본설정창에서 셋팅된 DEVMODE값을 받을 포인터.
            IntPtr devModeData = Marshal.AllocHGlobal(sizeNeeded);

            // fMode는 DM_IN_BUFFER | DM_IN_PROMPT | DM_OUT_BUFFER 이다. DM_IN_PROMPT는 Print Setup Property창을 보여주고 선택된 값을 저장한다.
            int result = DocumentProperties(this.Handle, pPrinter, PrinterSettings.PrinterName, devModeData, pDevMode, 14);

            // 열린 프린터 핸들을 닫는다.
            ClosePrinter(pPrinter);

            GlobalUnlock(hDevMode);
            
            // 현재 프린터 셋팅에 새로 설정된 DEVMODE 구조체를 저장한다.
            PrinterSettings.SetHdevmode(devModeData);
            PrinterSettings.DefaultPageSettings.SetHdevmode(devModeData);
            
            // 할당된 메모리를 해제한다.
            GlobalFree(hDevMode);
            Marshal.FreeHGlobal(devModeData);
        }