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

プリンタの用紙の種類をプログラムで設定したい

環境/言語:[C# .NET 2.0]
分類:[.NET]

はじめまして

プリンタの設定をアプリから設定する方法で教えてください。

foreach (PaperSize ps in printDoc.PrinterSettings.PaperSizes)
{
// A4用紙に設定する
if (ps.Kind == PaperKind.A4){
printDoc.DefaultPageSettings.PaperSize = ps;
break;
}
}
上記では、用紙サイズをセットできますが、このような方法で用紙の種類
を設定できますでしょうか?

たとえば、普通紙や厚紙など変更したいのですが。

よろしくお願いします。

C# Windows 7/Vista VS2005
■No28144に返信(esuさんの記事)
> 上記では、用紙サイズをセットできますが、このような方法で用紙の種類
> を設定できますでしょうか?
> たとえば、普通紙や厚紙など変更したいのですが。

同じ要領で、給紙トレイを設定するのが一般的ですね。
ありがとうございます。

でもトレイでなくトレイの用紙の種類を設定を変更したいのです。
厚紙とか普通紙、写真用の紙とか

給紙トレイは、
printDoc.DefaultPageSettings.PaperSource = printDoc.PrinterSettings.PaperSources[ToreyNum];

で可能と思います。 ToreiNum は、トレイ1、手差し、自動給紙など

よろしくお願いします。
■No28152に返信(esuさんの記事)

DEVMODE構造体の内容を書き換える必要があるかもです。

> DEVMODE構造体の内容を書き換える必要があるかもです。
DEVMODE構造体について調べてみましたが、この構造体の中のどれが用紙の種類なんでしょうか?
http://pc-idiot.three-atmarks.com/archives/192
をコピペしましたがどこで、DEVMODE構造体の値に参照できるのかわかりません。
関数自体は、正常に取得できているようです。
下記がそのコードの全体です。
また、プリントプロパティの表示なしで下記を実行したいのですが、可能ですか?


[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 32)]
public string dmDeviceName;
public short dmSpecVersion;
public short dmDriverVersion;
public short dmSize;
public short dmDriverExtra;
public int dmFields;
public short dmOrientation;
public short dmPaperSize;
public short dmPaperLength;
public short dmPaperWidth;
public short dmScale;
public short dmCopies;
public short dmDefaultSource;
public short dmPrintQuality;
public short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 32)]
public string dmFormName;
public short dmUnusedPadding;
public short dmBitsPerPel;
public int dmPelsWidth;
public int dmPelsHeight;
public int dmDisplayFlags;
public int dmDisplayFrequency;
}
[DllImport("winspool.drv", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool OpenPrinter([In, MarshalAs(UnmanagedType.LPWStr)] string pPrinterName, out IntPtr phPrinter, IntPtr pDefault);
[DllImport("winspool.drv", SetLastError = true)]
private static extern int ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.drv", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter, [In, MarshalAs(UnmanagedType.LPWStr)] string pDeviceName, IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GlobalLock(IntPtr hMem);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GlobalUnlock(IntPtr hMem);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GlobalFree(IntPtr hMem);


private class OldWindow : System.Windows.Forms.IWin32Window
{
private readonly System.IntPtr _handle;
public OldWindow(System.IntPtr handle)
{
_handle = handle;
}
#region IWin32Window Members
System.IntPtr System.Windows.Forms.IWin32Window.Handle
{
get { return _handle; }
}
#endregion
}
public static DialogResult ShowPrinterProperties(IWin32Window window, PrintDocument pd)
{
IntPtr hPrinter = IntPtr.Zero;
IntPtr hDevMode = IntPtr.Zero;
IntPtr pDevModeOutput = IntPtr.Zero;

try
{
// プリンタのハンドル取得
if (!OpenPrinter(pd.PrinterSettings.PrinterName, out hPrinter, IntPtr.Zero))
{
throw new Win32Exception();
}
// DEVMODE構造体のハンドルを取得
hDevMode = pd.PrinterSettings.GetHdevmode(pd.DefaultPageSettings);
// ハンドルからポインタ取得
IntPtr pDevMode = GlobalLock(hDevMode);
if (pDevMode == IntPtr.Zero)
{
throw new Win32Exception();
}
// プロパティの格納に必要なサイズを取得
int size = DocumentProperties(window.Handle, hPrinter, pd.PrinterSettings.PrinterName, IntPtr.Zero, IntPtr.Zero, 0);
if (size < 0)
{ throw new Win32Exception(); }
// メモリの確保
pDevModeOutput = Marshal.AllocHGlobal(size);
// プロパティダイアログの表示
int ret = DocumentProperties(window.Handle, hPrinter, pd.PrinterSettings.PrinterName, pDevModeOutput, pDevMode, 14);
if (ret == 1) // IDOK
{
// 設定を反映
pd.PrinterSettings.SetHdevmode(pDevModeOutput);
return DialogResult.OK;
}
else if (ret == 2)
//IDCANCEL
{ return DialogResult.Cancel; }
else { throw new Win32Exception(); }
}
finally
{
// 解放
Marshal.FreeHGlobal(pDevModeOutput);
GlobalUnlock(hDevMode);
GlobalFree(hDevMode);
ClosePrinter(hPrinter);
}
}

呼び出しは
System.Windows.Forms.IWin32Window win = new OldWindow(PrintSelectForm._PrintSelectFormInstatns.Handle);

ShowPrinterProperties(win, printDoc); <- System.Drawing.Printing.PrintDocument printDocです
■No28156に返信(esuさんの記事)
> DEVMODE構造体について調べてみましたが、この構造体の中のどれが用紙の種類なんでしょうか?

DEVMODE のプライベートデータ領域だと思います。

手元の「EPSON LP-S7500」で用紙設定を切り替えながら試してみたところ、
DEVMODE (計220バイト) は変化しませんでしたが、dmDriverExtra に
672 がセットされていたので、DEVMODE 後続のエリアを読み取ってみました。

どうやらこのドライバーには 672 バイトのプライベートデータがあり、
その中の 3 バイト(オフセット 0x10、0x212、0x244 からの各 1 バイト)が
用紙設定に応じて変化するようです。


> また、プリントプロパティの表示なしで下記を実行したいのですが、可能ですか?
PrintDocument 経由で印刷したいのであれば、
PrinterSettings / PageSettings クラスの SetHdevmode メソッドで
DEVMODE 構造体を割り当てることができるようです。試していませんが。
2011/02/14(Mon) 12:10:18 編集(投稿者)

# 最初の投稿では、Marshal.ReadIntPtr を使っていましたが、
# GlobalLock (と GlobalUnlock) に変更しています。

■No28157に返信(魔界の仮面弁士さんの記事)
> DEVMODE のプライベートデータ領域だと思います。

DEVMODE.dmDriverExtra の値を、複数のドライバーで比較してみました。

・NEC MutliWriter 9700C …… 606 バイト
・EPSON LP-S7500  …………… 672 バイト
・EPSON EP-301  ……………… 796 バイト
・Canon iR3250  …………… 1,868 バイト

やはりプライベート領域だけに、その構造はドライバーごとに異なるようです。


参考までに、当方のテストコードを掲載しておきます。

----- Form1.cs から抜粋 -----
private void button1_Click(object sender, EventArgs e)
{
    if (printDialog1.ShowDialog() == DialogResult.Cancel)
    {
        return;
    }

    PrinterSettings prtSet = printDialog1.PrinterSettings;
    IntPtr devMode = prtSet.GetHdevmode(prtSet.DefaultPageSettings);
    IntPtr devPtr = Sample.GlobalLock(devMode);

    Sample.DEVMODE dm = (Sample.DEVMODE)Marshal.PtrToStructure(devPtr, typeof(Sample.DEVMODE));
    if (dm.dmDriverExtra >= 0)
    {
        byte[] prvData = new byte[dm.dmDriverExtra];
        Marshal.Copy((IntPtr)((int)devPtr + dm.dmSize), prvData, 0, dm.dmDriverExtra);

        System.IO.File.WriteAllBytes(@"C:\privateData.bin", prvData);
    }
    Sample.GlobalUnlock(devPtr);  // 戻り値が true なら正常
    Sample.GlobalFree(devPtr);  // 戻り値が IntPtr.Zero なら正常
}

----- Sample.cs -----
using System;
using System.Text;
using System.Runtime.InteropServices;
public class Sample
{
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr GlobalLock(IntPtr hMem);  // 追加

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs( UnmanagedType.Bool)]
    public static extern bool GlobalUnlock(IntPtr hMem);  // 追加

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
    public static extern IntPtr GlobalFree(IntPtr handle);

    [Flags]
    public enum DevModeFields : int
    {
        DM_ORIENTATION = 0x1,               //dmOrientation
        DM_PAPERSIZE = 0x2,                 //dmPaperSize
        DM_PAPERLENGTH = 0x4,               //dmPaperLength
        DM_PAPERWIDTH = 0x8,                //dmPaperWidth
        DM_SCALE = 0x10,                    //dmScale
        DM_POSITION = 0x20,                 //dmPosition ((WINVER >= 0x0500))
        DM_NUP = 0x40,                      //dmNup ((WINVER >= 0x0500))
        DM_DISPLAYORIENTATION = 0x80,       //dmDisplayOrientation ((WINVER >= 0x0501))
        DM_COPIES = 0x100,                  //dmCopies
        DM_DEFAULTSOURCE = 0x200,           //dmDefaultSource
        DM_PRINTERQUALITY = 0x400,          //dmPrinterQuality
        DM_COLOR = 0x800,                   //dmColor
        DM_DUPLEX = 0x1000,                 //dmDuplex
        DM_YRESOLUTION = 0x2000,            //dmYResolution
        DM_TTOPTION = 0x4000,               //dmTTOption
        DM_COLLATE = 0x8000,                //dmCollate
        DM_FORMNAME = 0x10000,              //dmFormName
        DM_LOGPIXELS = 0x20000,             //dmLogPixels
        DM_BITSPERPEL = 0x40000,            //dmBitsPerPel
        DM_PELSWIDTH = 0x80000,             //dmPelsWidth
        DM_PELSHEIGHT = 0x100000,           //dmDisplayFlags
        DM_DISPLAYFREQUENCY = 0x400000,     //dmDisplayFrequency
        DM_ICMMETHOD = 0x800000,            //dmICMMethod ((WINVER >= 0x0400))
        DM_ICMINTENT = 0x1000000,           //dmICMintent ((WINVER >= 0x0400))
        DM_MEDIATYPE = 0x2000000,           //dmMediaType ((WINVER >= 0x0400))
        DM_DITHERTYPE = 0x4000000,          //dmDitherType ((WINVER >= 0x0400))
        DM_PANNINGWIDTH = 0x08000000,       //dmPanningWidth ((WINVER >= 0x0400))
        DM_PANNINGHEIGHT = 0x10000000,      //dmPanningHeight ((WINVER >= 0x0400))
        DM_DISPLAYFIXEDOUTPUT = 0x20000000, //dmDisplayFixedOutput ((WINVER >= 0x0501))
        DM_ICCMODEL = 0x40000000,           //dmICCModel
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct POINTL
    {
        public int x;
        public int y;
        public override string ToString()
        {
            return "{POINTL: " + string.Format("{0}, {1}", x, y) + "}";
        }
    }

    [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
    public struct DEVMODE
    {
        [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 32)]
        [FieldOffset(0)] public string dmDeviceName;
        [FieldOffset(64)] public short dmSpecVersion;
        [FieldOffset(66)] public short dmDriverVersion;
        [FieldOffset(68)] public short dmSize;
        [FieldOffset(70)] public short dmDriverExtra;
        [FieldOffset(72)] public DevModeFields dmFields;

        //-- begin [union-1]
        //--  with [union-1-1] printer only fields
        [FieldOffset(74)] public short dmOrientation;
        [FieldOffset(76)] public short dmPaperSize;
        [FieldOffset(78)] public short dmPaperLength;
        [FieldOffset(80)] public short dmPaperWidth;
        [FieldOffset(82)] public short dmScale;
        [FieldOffset(84)] public short dmCopies;
        [FieldOffset(86)] public short dmDefaultSource;
        [FieldOffset(88)] public short dmPrintQuality;
        //--  with [union-1-2] display only fields
        [FieldOffset(74)] public POINTL dmPosition;
        [FieldOffset(82)] public int dmDisplayOrientation;
        [FieldOffset(86)] public int dmDisplayFixedOutput;
        //-- endof [union-1]

        [FieldOffset(90)] public short dmColor;
        [FieldOffset(92)] public short dmDuplex;
        [FieldOffset(94)] public short dmYResolution;
        [FieldOffset(96)] public short dmTTOption;
        [FieldOffset(98)] public short dmCollate;
        [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 32)]
        [FieldOffset(100)] public string dmFormName;
        [FieldOffset(164)] public short dmLogPixels;
        [FieldOffset(166)] public int dmBitsPerPel;
        [FieldOffset(170)] public int dmPelsWidth;
        [FieldOffset(174)] public int dmPelsHeight;

        //-- begin [union-2]
        //--  with [union-2-1]
        [FieldOffset(178)] public int dmDisplayFlags;
        //--  with [union-2-2]
        [FieldOffset(178)] public int dmNup;
        //-- endof [union-2]

        [FieldOffset(182)] public int dmDisplayFrequency;
        [FieldOffset(186)] public int dmICMMethod;        // ((WINVER >= 0x0400))
        [FieldOffset(188)] public int dmICMIntent;        // ((WINVER >= 0x0400))
        [FieldOffset(192)] public int dmMediaType;        // ((WINVER >= 0x0400))
        [FieldOffset(196)] public int dmDitherType;       // ((WINVER >= 0x0400))
        [FieldOffset(200)] public int dmICCManufacturer;  // ((WINVER >= 0x0400))
        [FieldOffset(204)] public int dmICCModel;         // ((WINVER >= 0x0400))
        [FieldOffset(208)] public int dmPanningWidth;     // ((WINVER >= 0x0500) || (_WIN32_WINNT >= 0x0400))
        [FieldOffset(212)] public int dmPanningHeight;    // ((WINVER >= 0x0500) || (_WIN32_WINNT >= 0x0400))
        // FieldOffset(216)] public int something;
    }
}

>>DEVMODE のプライベートデータ領域だと思います。
>
プライベート領域というこで、また機種依存となると、買い替えや故障代替えなど考えるとちょっと大変そうですね。

その前に、ご提示いただいたコードがかなりレベルが高く

> その中の 3 バイト(オフセット 0x10、0x212、0x244 からの各 1 バイト)が
> 用紙設定に応じて変化するようです
私のレベルでは触らないほうが無難なようです。

教えていただいたのに残念ですが、プリンタプロパティを用紙変更が必要な時だけ表示させることで対応したいと思います。

ちなみに当方のプリンタ
RICOH IPSiO SP C721 .... 1016
RICOH IPSiO SP C221SF DDST .... 2237
RICOH IPSiO CX6100D RPCS .... 1016
でした

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