DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

プリンタのポート、状態を取得する

通常使うプリンタを取得、設定する」と同じように、WMIのWin32_Printerを使ってプリンタの情報を取得できます。ポートはPortNameプロパティ、状態はPrinterStatusプロパティで取得できます。

また、P/InvokeでGetPrinter関数を呼び出すことにより、プリンタの情報を取得することもできます。ここではこの方法を紹介します。

下にプリンタの情報をPRINTER_INFO_2構造体で取得するためのメソッド(GetPrinterInfoメソッド)のサンプルを示します。

なおこのコードを書くために「Newsgroups:microsoft.public.dotnet.framework.interop / Subject:Solution: Printer Port and Driver Information (PRINTER_INFO_2)」と「The Code Project - Changing printer settings using C#」を参考にしました。

VB.NET
コードを隠すコードを選択
'Imports System.Runtime.InteropServices
'Imports System.ComponentModel

<DllImport("winspool.drv", CharSet:=CharSet.Auto, SetLastError:=True)> _
Private Shared Function OpenPrinter( _
    ByVal pPrinterName As String, ByRef hPrinter As IntPtr, _
    ByVal pDefault As IntPtr) As Boolean
End Function

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

<DllImport("winspool.drv", SetLastError:=True)> _
Private Shared Function GetPrinter( _
    ByVal hPrinter As IntPtr, ByVal dwLevel As Integer, _
    ByVal pPrinter As IntPtr, ByVal cbBuf As Integer, _
    ByRef pcbNeeded As Integer) As Boolean
End Function

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
Public Structure PRINTER_INFO_2
    Public pServerName As String
    Public pPrinterName As String
    Public pShareName As String
    Public pPortName As String
    Public pDriverName As String
    Public pComment As String
    Public pLocation As String
    Public pDevMode As IntPtr
    Public pSepFile As String
    Public pPrintProcessor As String
    Public pDatatype As String
    Public pParameters As String
    Public pSecurityDescriptor As IntPtr
    Public Attributes As System.UInt32
    Public Priority As System.UInt32
    Public DefaultPriority As System.UInt32
    Public StartTime As System.UInt32
    Public UntilTime As System.UInt32
    Public Status As System.UInt32
    Public cJobs As System.UInt32
    Public AveragePPM As System.UInt32
End Structure

''' <summary>
''' プリンタの情報をPRINTER_INFO_2で取得する
''' </summary>
''' <param name="printerName">プリンタ名</param>
''' <returns>プリンタの情報</returns>
Public Shared Function GetPrinterInfo( _
    ByVal printerName As String) As PRINTER_INFO_2
    'プリンタのハンドルを取得する
    Dim hPrinter As IntPtr
    If Not OpenPrinter(printerName, hPrinter, IntPtr.Zero) Then
        Throw New Win32Exception(Marshal.GetLastWin32Error())
    End If

    Dim pPrinterInfo As IntPtr = IntPtr.Zero
    Try
        '必要なバイト数を取得する
        Dim needed As Integer
        GetPrinter(hPrinter, 2, IntPtr.Zero, 0, needed)
        If needed <= 0 Then
            Throw New Exception("失敗しました。")
        End If
        'メモリを割り当てる
        pPrinterInfo = Marshal.AllocHGlobal(needed)

        'プリンタ情報を取得する
        Dim temp As Integer
        If Not GetPrinter(hPrinter, 2, pPrinterInfo, needed, temp) Then
            Throw New Win32Exception(Marshal.GetLastWin32Error())
        End If

        'PRINTER_INFO_2型にマーシャリングする
        Dim printerInfo As PRINTER_INFO_2 = _
            CType(Marshal.PtrToStructure( _
            pPrinterInfo, GetType(PRINTER_INFO_2)), PRINTER_INFO_2)

        '結果を返す
        Return printerInfo
    Finally
        '後始末をする
        ClosePrinter(hPrinter)
        Marshal.FreeHGlobal(pPrinterInfo)
    End Try
End Function
C#
コードを隠すコードを選択
//using System.Runtime.InteropServices;
//using System.ComponentModel;

[DllImport("winspool.drv", CharSet=CharSet.Auto, SetLastError=true)]
private static extern bool OpenPrinter(string pPrinterName,
    out IntPtr hPrinter, IntPtr pDefault);

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

[DllImport("winspool.drv", SetLastError=true)]
private static extern bool GetPrinter(IntPtr hPrinter,
    int dwLevel, IntPtr pPrinter, int cbBuf, out int pcbNeeded);

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public struct PRINTER_INFO_2
{
    public string pServerName;
    public string pPrinterName;
    public string pShareName;
    public string pPortName;
    public string pDriverName;
    public string pComment;
    public string pLocation;
    public IntPtr  pDevMode;
    public string pSepFile;
    public string pPrintProcessor;
    public string pDatatype;
    public string pParameters;
    public IntPtr pSecurityDescriptor;
    public uint Attributes;
    public uint Priority;
    public uint DefaultPriority;
    public uint StartTime;
    public uint UntilTime;
    public uint Status;
    public uint cJobs;
    public uint AveragePPM;
}

/// <summary>
/// プリンタの情報をPRINTER_INFO_2で取得する
/// </summary>
/// <param name="printerName">プリンタ名</param>
/// <returns>プリンタの情報</returns>
public static PRINTER_INFO_2 GetPrinterInfo(string printerName)
{
    //プリンタのハンドルを取得する
    IntPtr hPrinter;
    if (!OpenPrinter(printerName, out hPrinter, IntPtr.Zero))
    {
        throw new Win32Exception(Marshal.GetLastWin32Error());
    }

    IntPtr pPrinterInfo = IntPtr.Zero;
    try
    {
        //必要なバイト数を取得する
        int needed;
        GetPrinter(hPrinter, 2, IntPtr.Zero, 0, out needed);
        if (needed <= 0)
            throw new Exception("失敗しました。");

        //メモリを割り当てる
        pPrinterInfo = Marshal.AllocHGlobal(needed);

        //プリンタ情報を取得する
        int temp;
        if (!GetPrinter(hPrinter, 2, pPrinterInfo, needed, out temp))
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }

        //PRINTER_INFO_2型にマーシャリングする
        PRINTER_INFO_2 printerInfo =
            (PRINTER_INFO_2) Marshal.PtrToStructure(pPrinterInfo,
            typeof(PRINTER_INFO_2));

        //結果を返す
        return printerInfo;
    }
    finally
    {
        //後始末をする
        ClosePrinter(hPrinter);
        Marshal.FreeHGlobal(pPrinterInfo);
    }
}

GetPrinterInfoメソッドを使ってプリンタのポートと状態を取得する例を以下に示します。"PRINTER NAME"を適当なプリンタの名前に変えてください。

VB.NET
コードを隠すコードを選択
'プリンタ名
Dim printerName As String = "PRINTER NAME"
'プリンタ情報を取得する
Dim pinfo As PRINTER_INFO_2 = GetPrinterInfo(printerName)
'ポートを表示する
Console.WriteLine(("Port:" + pinfo.pPortName))
'状態を表示する
Console.WriteLine(("Status:" + pinfo.Status.ToString()))
C#
コードを隠すコードを選択
//プリンタ名
string printerName = "PRINTER NAME";
//プリンタ情報を取得する
PRINTER_INFO_2 pinfo = GetPrinterInfo(printerName);
//ポートを表示する
Console.WriteLine("Port:" + pinfo.pPortName);
//状態を表示する
Console.WriteLine("Status:" + pinfo.Status.ToString());

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • コードの先頭に記述されている「Imports ??? がソースファイルの一番上に書かれているものとする」(C#では、「using ???; がソースファイルの一番上に書かれているものとする」)の意味が分からないという方は、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。