2010年4月16日金曜日

.NET プリンターのプロパティ画面を表示するには

.NET VistaではPageSetupDialogでプリンタ設定ボタンが表示されないで書いた
プリンターのプロパティ画面を表示する方法ですが、プリンタを変更するとプリンタドライバに依存するDEVMODE 構造体部分がメモリ確保されていないためエラーになることがあり
Marshal.AllocCoTaskMemを使った方法に訂正します。


Imports System.Runtime.InteropServices

Public Class Form1
    <DllImport("winspool.drv", CharSet:=CharSet.Auto, SetLastError:=True)> _
    Private Shared Function OpenPrinter( _
    <MarshalAs(UnmanagedType.LPTStr)> ByVal pPrinterName As String, ByRef hPrinter As IntPtr, ByVal pDefault As IntPtr) As Int32
    End Function

    <DllImport("winspool.drv", SetLastError:=True)> _
    Private Shared Function ClosePrinter(ByVal hPrinter As IntPtr) As Int32
    End Function

    <DllImport("winspool.drv", SetLastError:=True)> _
    Private Shared Function DocumentProperties ( _
        ByVal hwnd As IntPtr, _
        ByVal hPrinter As IntPtr, _
        <MarshalAs(UnmanagedType.LPTStr)> ByVal pDeviceName As String, _
        ByVal pDevModeOut As IntPtr, _
        ByVal pDevModeIn As IntPtr, _
        ByVal fMode As Int32) As Int32
    End Function

    Private Const DM_OUT_BUFFER As Short = 2
    Private Const DM_IN_PROMPT As Short = 4
    Private Const DM_IN_BUFFER As Short = 8

    <DllImport("kernel32", SetLastError:=True)> _
    Private Shared Function GlobalLock(ByVal hmem As IntPtr) As IntPtr
    End Function
    
    <DllImport("kernel32", SetLastError:=True)> _
    Private Shared Function GlobalFree(ByVal hmem As IntPtr) As Int32
    End Function
    
    <DllImport("kernel32", SetLastError:=True)> _
    Private Shared Function GlobalUnlock(ByVal hMem As IntPtr) As Int32
    End Function


    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim printer As New Printing.PrinterSettings
        Dim ret As Boolean = ShowPrinterProperty(Me.Handle, printer) 
    End Sub
        
    Private Function ShowPrinterProperty(ByVal hwnd As IntPtr, ByVal printer As Printing.PrinterSettings) As Boolean
        Dim ret As Int32

        'プリンタのハンドルを取得する
        Dim hPrinter As IntPtr = IntPtr.Zero
        ret = OpenPrinter(printer.PrinterName, hPrinter, IntPtr.Zero)
        If (ret = 0 OrElse hPrinter = IntPtr.Zero) Then
            Return False
        End If

        Try

            'プリンタのDEVMODE構造体のサイズを取得する
            Dim iDevModeSize As Integer = DocumentProperties(IntPtr.Zero, hPrinter, printer.PrinterName, IntPtr.Zero, IntPtr.Zero, 0)

            'Input用のDEVMODE構造体のハンドルを取得する
            Dim hDevModeIn As IntPtr = printer.GetHdevmode()
            Dim pDevModeIn As IntPtr = GlobalLock(hDevModeIn)

            'OutOut用のDEVMODE構造体のメモリを確保する
            Dim pDevModeOut As IntPtr = Marshal.AllocCoTaskMem(iDevModeSize)
            Try

                '設定画面を開く
                ret = DocumentProperties(hwnd, hPrinter, printer.PrinterName, pDevModeOut, pDevModeIn, DM_IN_PROMPT Or DM_IN_BUFFER Or DM_OUT_BUFFER)
                If (ret = 1) Then
                    printer.SetHdevmode(pDevModeOut)
                End If

                '
                Return True

            Finally
                GlobalUnlock(hDevModeIn)
                GlobalFree(hDevModeIn)
                Marshal.FreeCoTaskMem(pDevModeOut)
            End Try
        Finally
            ClosePrinter(hPrinter)
        End Try
    End Function
End Class

0 件のコメント: