DOBON.NET DOBON.NETプログラミング掲示板過去ログ

用紙サイズの幅と長さを取得したい。

環境/言語:[Windows XP VB.Net 2003]
分類:[.NET]

現在、.Net Framework の PrinterSettings.PaperSizes クラスで、指定したプリンタの全ての用紙サイズの幅と長さを取得しておりますが、非常に時間が掛かる(114種の用紙サイズで20秒位)為、 Win32 API で実現しようと考えております。

DeviceCapabilities という関数で
 (1)用紙サイズ番号の取得(第三引数に DC_PAPERS を指定)
 (2)用紙サイズ名称の取得(第三引数に DC_PAPERNAMES を指定)
 (3)用紙サイズの幅と長さの取得(第三引数に DC_PAPERSIZE を指定)

上記(1)、(2)は出来ましたが、(3)が出来ません。

ソースは以下のようになっております。


#Region "Win32 API"

'プリンタデバイスドライバの能力を取得する(各用紙サイズの番号取得用)
Private Declare Function DeviceCapabilities1 Lib "winspool.drv" Alias "DeviceCapabilitiesA" _
(ByVal pDevice As String, _
ByVal pPortt As String, _
ByVal fwCapability As Short, _
ByVal pOutput() As Short, _
ByVal pDevMode As System.IntPtr) As Integer

'プリンタデバイスドライバの能力を取得する(各用紙サイズの名称取得用)
Private Declare Function DeviceCapabilities2 Lib "winspool.drv" Alias "DeviceCapabilitiesA" _
(ByVal pDevice As String, _
ByVal pPortt As String, _
ByVal fwCapability As Short, _
ByVal pOutput As String, _
ByVal pDevMode As System.IntPtr) As Integer

'プリンタデバイスドライバの能力を取得する(各用紙サイズの寸法取得用)
Private Declare Function DeviceCapabilities3 Lib "winspool.drv" Alias "DeviceCapabilitiesA" _
(ByVal pDevice As String, _
ByVal pPortt As String, _
ByVal fwCapability As Short, _
ByVal pOutput() As PointST, _
ByVal pDevMode As System.IntPtr) As Integer

#End Region


'用紙サイズ数取得(領域確保用)
intPaperSizeCount = DeviceCapabilities1(strPrinterName, "", DC_PAPERS, Nothing, System.IntPtr.Zero)
If intPaperSizeCount = -1 Then
Return Nothing
End If


'領域確保
ReDim stPaperSize(intPaperSizeCount - 1) '用紙サイズ構造体配列
ReDim shoPaperSizeNumber(intPaperSizeCount - 1) '用紙サイズ番号
strPaperSizeNameAll = New String(Char.Parse(" "), intPaperSizeCount * 64) '用紙サイズ名称(全用紙サイズ取り出し用)
ReDim stPaperPoint(intPaperSizeCount - 1) 'ポイント構造体配列


'プリンター名称メンバー変数の値をローカル変数へ複写
strPrinterName = m_strPrinterName


'用紙サイズ番号取得
intRet = DeviceCapabilities1(strPrinterName, "", DC_PAPERS, shoPaperSizeNumber, System.IntPtr.Zero)
If intRet = -1 Then
Return Nothing
End If


'プリンター名称メンバー変数の値をローカル変数へ複写
strPrinterName = m_strPrinterName


'用紙サイズ名称取得
intRet = DeviceCapabilities2(strPrinterName, "", DC_PAPERNAMES, strPaperSizeNameAll, System.IntPtr.Zero)
If intRet = -1 Then
Return Nothing
End If


'プリンター名称メンバー変数の値をローカル変数へ複写
strPrinterName = m_strPrinterName


'用紙サイズ寸法取得
intRet = DeviceCapabilities3(strPrinterName, "", DC_PAPERSIZE, stPaperPoint, System.IntPtr.Zero)
If intRet = -1 Then
Return Nothing
End If
■No19696に返信(鈴木 雅夫さんの記事)

ソースを公開する場合は、そのまま実行して試せるぐらいになっていないと難し
いと思います。
ちょっと見てみましたが、定義が抜けている部分がありました。
(DC_PAPERS とか PointST とか)

その辺を補った上で調べてみましたが、DeviceCapabilities3 はそのままでは機
能していないと思われます。
たぶん、pOutput() を IntPtr にして、Marshal.HGlobal で確保したメモリへ設
定してもらったものをループで Marshal.PtrToStructure メソッドを利用してコ
ピーしつつ設定という形になるのかと。
# ちょっとやってみましたが、結構面倒くさいですね(前にも同じようなことやっ
# たことあるけど)。

ぐちゃーっと書いた汚いコードですが、こんな感じになるのかなと。

    <StructLayout(LayoutKind.Explicit)> _
    Private Structure PointST
        <FieldOffset(0)> Private X As Int32
        <FieldOffset(4)> Private Y As Int32
    End Structure

    'プリンタデバイスドライバの能力を取得する(各用紙サイズの番号取得用)
    Private Declare Function DeviceCapabilities1 Lib "winspool.drv" Alias "DeviceCapabilitiesA" _
                                                                (ByVal pDevice As String, _
                                                                 ByVal pPortt As String, _
                                                                 ByVal fwCapability As Short, _
                                                                 ByVal pOutput() As Short, _
                                                                 ByVal pDevMode As System.IntPtr) As Integer

    'プリンタデバイスドライバの能力を取得する(各用紙サイズの寸法取得用)
    Private Declare Function DeviceCapabilities3 Lib "winspool.drv" Alias "DeviceCapabilitiesA" _
                                                                (ByVal pDevice As String, _
                                                                 ByVal pPortt As String, _
                                                                 ByVal fwCapability As Short, _
                                                                 ByVal p As IntPtr, _
                                                                 ByVal pDevMode As System.IntPtr) As Integer

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim strPrinterName As String = "プリンタの名前"
        Dim intPaperSizeCount As Integer
        Const DC_PAPERS As Integer = 2
        Const DC_PAPERSIZE As Integer = 3

        ' 用紙サイズ数取得(領域確保用)
        intPaperSizeCount = DeviceCapabilities1(strPrinterName, "", DC_PAPERS, Nothing, System.IntPtr.Zero)
        If intPaperSizeCount = -1 Then
            Return
        End If

        Dim pointStSize As Integer = Marshal.SizeOf(GetType(PointST))
        Dim p As IntPtr = IntPtr.Zero

        Try
            p = Marshal.AllocHGlobal(intPaperSizeCount * pointStSize)

            ' 用紙サイズ寸法取得
            Dim intRet As Integer = DeviceCapabilities3(strPrinterName, "", DC_PAPERSIZE, p, System.IntPtr.Zero)
            If intRet = -1 Then
                Return
            End If

            Dim p2 As IntPtr = p
            For i As Integer = 0 To intPaperSizeCount - 1
                Dim stPoint As PointST
                stPoint = DirectCast(Marshal.PtrToStructure(p2, stPoint.GetType()), PointST)
                Console.WriteLine("{0} {1}mm {2}mm", i, stPoint.X / 10, stPoint.Y / 10)
                p2 = New IntPtr(p2.ToInt32() + pointStSize)
            Next
        Finally
            If p <> IntPtr.Zero Then
                Marshal.FreeHGlobal(p)
            End If
        End Try
    End Sub

あんまりテストしてないので、変なところあったらツッコミよろしくお願いします orz
ぽぴ王子 様

先程、ぽぴ王子様が教えてくださったソースで実行してみたところ、見事、用紙サイズの幅と長さを取得する事が出来ました。
御蔭様で、スケジュール通りに完了しそうです。

ソースコードに不備があり、大変失礼致しました事を深くお詫び申し上げると同時に、貴重な時間を私の為に割いて下さいまして、心より感謝申し上げます。

又何かありました時には、宜しく御願い致します。
解決済み!
>非常に時間が掛かる(114種の用紙サイズで20秒位)為、
とのことだったのですが、どれくらい速度に違いがあったのかとても
興味があります。
解決済み!
■No19700に返信(Blueさんの記事)

> >非常に時間が掛かる(114種の用紙サイズで20秒位)為、
> とのことだったのですが、どれくらい速度に違いがあったのかとても
> 興味があります。

僕も少し気になったので、PrinterSettings クラスを使った方法も試してみましたが、
ほとんど差はみられませんでした(両方とも一瞬)。
ただ、こちらの環境では用紙が25種類ぐらいしかないのでまた違うのかもしれませ
ん。

スレ主さんのところでどの程度差がみられたのか、僕もとても気になります。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板