- PR -

プリンタ詳細ダイアログで設定した情報をセーブ/ロードしたい

投稿者投稿内容
水穂和明
会議室デビュー日: 2001/12/25
投稿数: 6
お住まい・勤務地: 鳥取県米子市
投稿日時: 2007-12-28 11:55
VB2005を使ってプリンタダイアログを自前で作っています。
そこでプリンタ詳細ダイアログで設定した情報をファイルにセーブ/ロードしたいです。
下記の方法を試したところ機種依存部分もセーブしたかったのですができないようです。
また別の方法として、GetHdevmode()でDEVMODE構造体に保存してみたりしたのですがうまく動作しません。
どなたか、機種依存部分も保持した形でセーブ/ロードする方法をご存じの方がいらっしゃいませんでしょうか?
アドバイスを頂けると幸いです。

とりあえず、機種依存部分以外を保存/読み込みできるロジック。
コード:
    'PrinterSettingsをファイルに保存。
    Public Shared Sub SaveToBinaryFile( _
                    ByVal obj As PrinterSettings, ByVal path As String)
        Dim fs As FileStream
        Dim bf As BinaryFormatter

        fs = New FileStream(path, FileMode.Create, FileAccess.Write)
        bf = New BinaryFormatter()

        'シリアル化して書き込む
        bf.Serialize(fs, obj)

        fs.Close()
    End Sub

    'PrinterSettingsをファイルより読み込み。
    Public Shared Function LoadFromBinaryFile(ByVal path As String) _
                                                      As PrinterSettings
        Dim dsp As PrinterSettings '= New PrinterSettings
        Dim fs As FileStream
        Dim bf As BinaryFormatter

        fs = New FileStream(path, FileMode.Open, FileAccess.Read)
        bf = New BinaryFormatter()

        '読み込んで逆シリアル化する
        dsp = CType(bf.Deserialize(fs), PrinterSettings)
        fs.Close()

        Return dsp
    End Function



参考までにプリンタ詳細設定ダイアログを表示、値を保持するロジック。
コード:
    Public Function GetDevMode(ByVal Device As String) As Integer

        Dim ret As Integer
        Dim hPrinter As IntPtr
        Dim PtrDMOut As IntPtr
        Dim PtrDMIn As IntPtr
        Dim _PrinterName As String = Device

        PtrDMIn = _PS.GetHdevmode(_PS.DefaultPageSettings)
        PtrDMOut = _PS.GetHdevmode(_PS.DefaultPageSettings)

        Dim globalDevIn As IntPtr = GlobalLock(PtrDMIn)
        Dim globalDevOut As IntPtr = GlobalLock(PtrDMOut)

        Try
            'プリンタのハンドルを取得
            ret = OpenPrinter(_PrinterName, hPrinter, IntPtr.Zero)
            If ret = 0 Or hPrinter.Equals(IntPtr.Zero) Then
                Return 0
            End If

            'DialogBox 表示
            ret = DocumentProperties(Me.Handle, hPrinter, _PrinterName, _
                                     globalDevOut, globalDevIn, _
                                DM_IN_PROMPT Or DM_IN_BUFFER Or DM_OUT_BUFFER)

            If PtrDMOut.Equals(IntPtr.Zero) Then
                Return 0
            End If
            'DialogBoxでOKがクリックされた場合に設定内容を反映させる。
            If ret = 1 Then
                _PS.DefaultPageSettings.SetHdevmode(globalDevOut)
                _PS.SetHdevmode(globalDevOut)
                Me.Setvalues()
            End If

            Return ret

        Catch ex As Exception
            'エラー処理
        Finally
            GlobalUnlock(PtrDMIn)
            GlobalFree(PtrDMIn)
            GlobalUnlock(PtrDMOut)
            GlobalFree(PtrDMOut)

            If Not hPrinter.Equals(IntPtr.Zero) Then
                ClosePrinter(hPrinter)
            End If
        End Try

    End Function



よろしくお願いします。
//リゾナンス 水穂和明
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2008-01-03 21:18
おそらく、ドライバに直接尋ねることになると思います。

DDK のリファレンスをあたってみてください。ドライバが必ず実装しなければならない関数があると思います。その関数を呼び出すとかして、とれたものを保存するとかになるかと思います。
最後には、メーカーに聞かないと情報は出てこないと思います。
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2008-01-04 21:37
ドライバに直接尋ねる必要はないでしょう。

DEVMODE のプライベート領域が保存できていないのは、BinaryFormater に PrinterSettings インスタンスを与えてバイト配列化しているからだと思います。(この時点でパブリック領域しか保存されないはず。)

プライベート領域を保存・復元する場合は、PrinterSettings インスタンスではなく、DEVMODE 構造体を直接保存したらよいと思います。DEVMODE 構造体は末尾にプライベート領域があるためサイズが固定ではありません。DocumentProperties 関数の最後の引数に 0 を指定することで、プライベート領域も含めた必要サイズが分かります。また、DEVMODE 構造体の dmDriverExtra にもプライベート領域のサイズが入っています。

.NET のことは知らないのですが、PrinterSettings というクラスは、おそらく、パブリック領域を扱うためのクラスなのでしょう。(当たり前ですが、プライベート領域はプリンタ依存ですので標準クラスライブラリでクラス化するようなことはできません。) たぶん、PrinterSettings インスタンスはプライベート領域を保持しないのでありませんか?
Azulean
大ベテラン
会議室デビュー日: 2008/01/04
投稿数: 123
お住まい・勤務地: 大阪府
投稿日時: 2008-01-04 22:32
引用:

未記入さんの書き込み (2008-01-04 21:37) より:

.NET のことは知らないのですが、PrinterSettings というクラスは、おそらく、パブリック領域を扱うためのクラスなのでしょう。(当たり前ですが、プライベート領域はプリンタ依存ですので標準クラスライブラリでクラス化するようなことはできません。) たぶん、PrinterSettings インスタンスはプライベート領域を保持しないのでありませんか?


プライベート領域の面倒までは見てくれないように見受けられます。
GetHdevmodeメソッドがあるので、バイト数を調べて、自分でシリアライズする必要があるのだと思います(未確認)。

http://msdn2.microsoft.com/ja-jp/library/system.drawing.printing.printersettings.gethdevmode(VS.80).aspx
http://msdn2.microsoft.com/ja-jp/library/system.drawing.printing.printersettings.sethdevmode(VS.80).aspx
水穂和明
会議室デビュー日: 2001/12/25
投稿数: 6
お住まい・勤務地: 鳥取県米子市
投稿日時: 2008-01-06 16:50
引用:
DEVMODE 構造体は末尾にプライベート領域があるためサイズが固定ではありません。DocumentProperties 関数の最後の引数に 0 を指定することで、プライベート領域も含めた必要サイズが分かります。また、DEVMODE 構造体の dmDriverExtra にもプライベート領域のサイズが入っています。



ここらへんの知識がありませんでした。
ありがとうございます。

あとDEVMODEはGetHDevmode()とSetHDevmode()を使おうと考えております。
いま、テストできる環境がないので明日試してみたいと思います。
何か進展がありましたら報告させていただきます。
水穂和明
会議室デビュー日: 2001/12/25
投稿数: 6
お住まい・勤務地: 鳥取県米子市
投稿日時: 2008-01-07 15:18
今までのやりとりを踏まえて、保存/読み込みできるはずのロジックを組んでみたのですが、SetHdevmode()したあとメモリを破壊しているようでうまく先に進みません。
あと一歩かと思うのですがアドバイスいただけませんでしょうか?
コード:
    Public Shared Sub SaveToBinaryFile( _
                    ByVal obj As PrinterSettings, ByVal path As String)

        Dim PtrDevMode As IntPtr
        Dim testDevmode As New DEVMODE
        Dim bytReadBuf(2036) As Byte

        PtrDevMode = obj.GetHdevmode(obj.DefaultPageSettings)
        Dim globalDevOut As IntPtr = GlobalLock(PtrDevMode)
        testDevmode = CType(Marshal.PtrToStructure(globalDevOut, _
                                            GetType(DEVMODE)), DEVMODE)
        Dim lngSaveSize As Long = _
                         testDevmode.dmSize + testDevmode.dmDriverExtra
        ReDim bytReadBuf(lngSaveSize)
        Marshal.Copy(globalDevOut, bytReadBuf, 0, lngSaveSize)
        GlobalUnlock(PtrDevMode)
        GlobalFree(PtrDevMode)

        Dim fs As New FileStream("c:\\test.obj", _
                                FileMode.Create, FileAccess.Write)
        Dim bw As New BinaryWriter(fs)
        bw.Write(bytReadBuf, 0, lngSaveSize)
        bw.Close()
        fs.Close()

    End Sub


コード:
    Public Shared Function LoadFromBinaryFile(ByVal path As String) _
                                                      As PrinterSettings
        Dim dsp As New PrinterSettings()
        Dim testDevmode As New DEVMODE
        Dim bytReadBuf(2036) As Byte
        Dim PtrDevMode As IntPtr

        Dim fs As New FileStream(path, FileMode.Open, FileAccess.Read)
        Dim br As New BinaryReader(fs)


        PtrDevMode = dsp.GetHdevmode(dsp.DefaultPageSettings)
        Dim globalDevOut As IntPtr = GlobalLock(PtrDevMode)
        Dim ptr As IntPtr = _
                  Marshal.AllocHGlobal(Marshal.SizeOf(testDevmode))

        Try
            ReDim bytReadBuf(Marshal.SizeOf(testDevmode))
            bytReadBuf = br.ReadBytes(Marshal.SizeOf(testDevmode))

            Marshal.Copy(bytReadBuf, 0, ptr, Marshal.SizeOf(testDevmode))
            testDevmode = _
                DirectCast(Marshal.PtrToStructure(ptr, GetType(DEVMODE)), _
                           DEVMODE)
            Dim lngSaveSize As Long = _
                        testDevmode.dmSize + testDevmode.dmDriverExtra
            fs.Position = 0
            ReDim bytReadBuf(lngSaveSize)
            bytReadBuf = br.ReadBytes(lngSaveSize)

            Marshal.Copy(bytReadBuf, 0, globalDevOut, lngSaveSize)
            dsp.DefaultPageSettings.SetHdevmode(globalDevOut)
            dsp.SetHdevmode(globalDevOut)

        Catch ex As Exception
        Finally
            GlobalUnlock(PtrDevMode)
            GlobalFree(PtrDevMode)
            If IntPtr.Zero <> ptr Then
                Marshal.FreeHGlobal(ptr)
            End If
            br.Close()
            fs.Close()
        End Try

        Return dsp

    End Function



よろしくお願いします。
//リゾナンス 水穂和明
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2008-01-07 20:56
引用:

Dim testDevmode As New DEVMODE

Dim ptr As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(testDevmode))

Marshal.Copy(bytReadBuf, 0, ptr, Marshal.SizeOf(testDevmode))


LoadFromBinaryFile の、この辺がおかしいんじゃない? もう一度、同じこと言うけど、DEVMODE 構造体は末尾にプライベート領域があるためサイズが固定ではありません。プライベート領域の分もちゃんとメモリを確保して。プライベート領域の分もちゃんと読み込んで。
水穂和明
会議室デビュー日: 2001/12/25
投稿数: 6
お住まい・勤務地: 鳥取県米子市
投稿日時: 2008-01-07 22:00
引用の部分ですが…。
一度DEVMODE構造体のサイズ分のデータをファイルより読み込み、DEVMODE構造体のメンバよりサイズを求めてもう一度ファイルの先頭より(DEVMODE構造体のサイズ+プライベート領域のサイズ)のサイズでByte()に読み込んでいるつもりですが…。
コメントが入ってなくて大変読みにくいコードで申し訳ありませんでした。

ちなみにここら辺です。
引用:

Dim lngSaveSize As Long = _
testDevmode.dmSize + testDevmode.dmDriverExtra
fs.Position = 0
ReDim bytReadBuf(lngSaveSize)
bytReadBuf = br.ReadBytes(lngSaveSize)

Marshal.Copy(bytReadBuf, 0, globalDevOut, lngSaveSize)

スキルアップ/キャリアアップ(JOB@IT)