【C#】標準コントロールに存在しないプリンターの設定ダイアログを表示する方法

C#
この記事は約15分で読めます。

.NETでテキストエディタを作成してて、そろそろ印刷関連を作ろっかなぁーってなって、どれどれどんな感じなん?って他のエディタを見ると、当たり前のように利用している「 プリンターの設定ダイアログ」が表示できないことに気付くと思います。そうなんです。.NETには無いんです…。

なぜ無いのか不明ですが、作成方法を紹介します。.NETの標準コントロールには存在しないため CommonDialog を継承して作成します。

プリンターの設定ダイアログ

このダイアログです。ほとんどのテキストエディタで利用している印刷プリンタとページ設定を同時に行うダイアログです。今見るとちょっと古い感じがしますね。

標準ダイアログ

以下は標準で利用できる印刷系のダイアログです。組み合わせればプリンターの設定ダイアログと同様にはなります。

印刷ダイアログ

PrintDialog クラスで表示可能なダイアログです。印刷するプリンタ、ページ範囲や部数を設定できます。

ページ設定ダイアログ

PageSetupDialog クラスで表示可能なダイアログです。印刷するプリンタ、ページ範囲や部数を設定できます。用紙サイズや印刷の向きを設定できます。

プリンターの設定ダイアログのソース

32bit と 64bit の OS 用にほぼ同じコードが書かれています。違いは PrintDlg を呼び出す構造体の定義が違うのみです。

using System;
using System.Runtime.InteropServices;
using System.Drawing.Printing;
using System.Windows.Forms;

namespace Test {
    /// <summary>
    /// OTZPrintDialog
    /// </summary>
    public class OTZPrintDialog : CommonDialog {

        private PageSettings pageSettings;
        private PrintDocument printDocument;
        private PrinterSettings printerSettings;
        private const int PD_PRINTSETUP = 0x40;
        private const int PD_ENABLESETUPHOOK = 0x2000;
        private delegate IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)]
        private struct PRINTDLG_32 {
            public int lStructSize;
            public IntPtr hwndOwner;
            public IntPtr hDevMode;
            public IntPtr hDevNames;
            public IntPtr hDC;
            public int Flags;
            public short nFromPage;
            public short nToPage;
            public short nMinPage;
            public short nMaxPage;
            public short nCopies;
            public IntPtr hInstance;
            public IntPtr lCustData;
            public WndProc lpfnPrintHook;
            public WndProc lpfnSetupHook;
            public string lpPrintTemplateName;
            public string lpSetupTemplateName;
            public IntPtr hPrintTemplate;
            public IntPtr hSetupTemplate;
            //public PRINTDLG_32() {
            //}
        }

        //[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 8)]
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        private struct PRINTDLG_64 {
            public int lStructSize;
            public IntPtr hwndOwner;
            public IntPtr hDevMode;
            public IntPtr hDevNames;
            public IntPtr hDC;
            public int Flags;
            public short nFromPage;
            public short nToPage;
            public short nMinPage;
            public short nMaxPage;
            public short nCopies;
            public IntPtr hInstance;
            public IntPtr lCustData;
            public WndProc lpfnPrintHook;
            public WndProc lpfnSetupHook;
            public string lpPrintTemplateName;
            public string lpSetupTemplateName;
            public IntPtr hPrintTemplate;
            public IntPtr hSetupTemplate;
            //public PRINTDLG_64() {
            //}
        }

        [DllImport("comdlg32.dll", EntryPoint = "PrintDlgW", CharSet = CharSet.Unicode, SetLastError = true)]
        private static extern bool PrintDlg(ref PRINTDLG_32 lpPrintdlg);

        [DllImport("comdlg32.dll", EntryPoint = "PrintDlgW", CharSet = CharSet.Unicode, SetLastError = true)]
        private static extern bool PrintDlg(ref PRINTDLG_64 lpPrintdlg);

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

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public OTZPrintDialog() {
            this.Reset();
        }

        /// <summary>
        /// Document
        /// </summary>
        public PrintDocument Document {
            get { return this.printDocument; }
            set {
                this.printDocument = value;
                if (this.printDocument != null) {
                    this.pageSettings = this.printDocument.DefaultPageSettings;
                    this.printerSettings = this.printDocument.PrinterSettings;
                }
            }
        }

        /// <summary>
        /// Reset
        /// </summary>
        public override void Reset() {
            pageSettings = null;
            printDocument = null;
            printerSettings = null;
        }

        /// <summary>
        /// ダイアログ表示
        /// </summary>
        /// <param name="hwndOwner"></param>
        /// <returns></returns>
        protected override bool RunDialog(IntPtr hwndOwner) {
            WndProc hookProcPtr = new WndProc(this.HookProc);
            // 32bitの場合
            if (IntPtr.Size == 4) {
                PRINTDLG_32 printDlg = new PRINTDLG_32();
                try {
                    printDlg.lStructSize = Marshal.SizeOf(printDlg);
                    printDlg.hwndOwner = hwndOwner;
                    printDlg.lpfnSetupHook = hookProcPtr;
                    printDlg.nFromPage = (short)this.printerSettings.FromPage;
                    printDlg.nToPage = (short)this.printerSettings.ToPage;
                    printDlg.nMinPage = (short)this.printerSettings.MinimumPage;
                    printDlg.nMaxPage = (short)this.printerSettings.MaximumPage;
                    printDlg.nCopies = this.printerSettings.Copies;
                    if (this.printerSettings == null) {
                        printDlg.hDevMode = this.printerSettings.GetHdevmode();
                    } else {
                        printDlg.hDevMode = this.printerSettings.GetHdevmode(this.pageSettings);
                    }
                    printDlg.hDevNames = this.printerSettings.GetHdevnames();
                    printDlg.Flags = PD_PRINTSETUP | PD_ENABLESETUPHOOK;
                    // ダイアログ表示
                    if (PrintDlg(ref printDlg)) {
                        Cursor.Current = Cursors.WaitCursor;
                        this.printerSettings.SetHdevmode(printDlg.hDevMode);
                        this.printerSettings.SetHdevnames(printDlg.hDevNames);
                        this.pageSettings.SetHdevmode(printDlg.hDevMode);
                        return true;
                    }
                    return false;
                } finally {
                    if (printDlg.hDevMode != IntPtr.Zero) {
                        GlobalFree(printDlg.hDevMode);
                    }
                    if (printDlg.hDevNames != IntPtr.Zero) {
                        GlobalFree(printDlg.hDevNames);
                    }
                }

                // 64bitの場合
            } else {
                PRINTDLG_64 printDlg = new PRINTDLG_64();
                try {
                    printDlg.lStructSize = Marshal.SizeOf(printDlg);
                    printDlg.hwndOwner = hwndOwner;
                    printDlg.lpfnSetupHook = hookProcPtr;
                    printDlg.nFromPage = (short)this.printerSettings.FromPage;
                    printDlg.nToPage = (short)this.printerSettings.ToPage;
                    printDlg.nMinPage = (short)this.printerSettings.MinimumPage;
                    printDlg.nMaxPage = (short)this.printerSettings.MaximumPage;
                    printDlg.nCopies = this.printerSettings.Copies;
                    if (this.printerSettings == null) {
                        printDlg.hDevMode = this.printerSettings.GetHdevmode();
                    } else {
                        printDlg.hDevMode = this.printerSettings.GetHdevmode(this.pageSettings);
                    }
                    printDlg.hDevNames = this.printerSettings.GetHdevnames();
                    printDlg.Flags = PD_PRINTSETUP | PD_ENABLESETUPHOOK;
                    // ダイアログ表示
                    if (PrintDlg(ref printDlg)) {
                        Cursor.Current = Cursors.WaitCursor;
                        this.printerSettings.SetHdevmode(printDlg.hDevMode);
                        this.printerSettings.SetHdevnames(printDlg.hDevNames);
                        this.pageSettings.SetHdevmode(printDlg.hDevMode);
                        return true;
                    }
                    return false;
                } finally {
                    if (printDlg.hDevMode != IntPtr.Zero) {
                        GlobalFree(printDlg.hDevMode);
                    }
                    if (printDlg.hDevNames != IntPtr.Zero) {
                        GlobalFree(printDlg.hDevNames);
                    }
                }
            }
        }
    }
}

利用方法

標準の印刷ダイアログと同じ方法で表示できます。このダイアログで設定した内容の取得方法も標準と同じです。

OTZPrintDialog dialog = new OTZPrintDialog();
dialog.Document = new PrintDocument();
if (dialog.ShowDialog() == DialogResult.OK) {
    // プリンタ名
    Debug.WriteLine(dialog.Document.PrinterSettings.PrinterName);
}

おわりに

ソースコードは GitHub でも公開しています。

コメント

タイトルとURLをコピーしました