Visual Basic 2008でプリンタ設定
投稿者 モル  (社会人)
投稿日時
2010/7/8 15:56:30
'モジュール
Public Type PRINTER_DEFAULTS
pDatatype As String
pDevMode As Long
DesiredAccess As Long
End Type
'http://www.winapi-database.com/Struct/DEVMODE.html
Public Const CCHFORMNAME = 32
Public Const CCHDEVICENAME = 32
Public Type DEVMODE
dmDeviceName As String * CCHDEVICENAME 'デバイス名の文字列
dmSpecVersion As Integer 'DEVMODEのバージョン(Win3.1 = &H30A)
dmDriverVersion As Integer 'ドライバのバージョン
dmSize As Integer 'DEVMODE構造体のバイト数
dmDriverExtra As Integer 'DEVMODE構造体に続くデータのバイト数
dmFields As Long 'DEVMODE構造体の有効なエントリ数を指定
dmOrientation As Integer '用紙の向きを指定する定数
dmPaperSize As Integer '用紙サイズ
dmPaperLength As Integer '用紙の長さ(10mm単位)(dmPaperSizeに優先)
dmPaperWidth As Integer '用紙の幅(10mm単位)(dmPaperSizeに優先)
dmScale As Integer '用紙の拡大倍率(x/100単位)
dmCopies As Integer 'コピー数
dmDefaultSource As Integer 'デフォルトのピン番号
dmPrinterQuality As Integer '印刷品質
dmColor As Integer 'カラーモード
dmDuplex As Integer '両面印刷の設定
dmYResolution As Integer 'Y方向の印刷品質(Dot/inch)
dmTTOption As Integer 'TrueTypeフォントの印刷方法
dmCollate As Integer 'ページそろえの設定
dmFormname As String * CCHFORMNAME 'フォーム名(WindowsNT系のみ)
dmUnusedPadding As Integer '未使用
dmBitsPerPel As Integer 'ピクセルあたりのビット数
dmPelsWidth As Long '幅(単位:ピクセル)
dmPelsHeight As Long '高さ(単位:ピクセル)
dmDisplayFlags As Long 'ディスプレイモードを指定する定数
dmDisplayFrequency As Long 'ディスプレイの動作周波数
End Type
Public Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" _
(ByVal pPrinterName As String, phPrinter As Long, pDefault As PRINTER_DEFAULTS) As Long
Public Declare Function SetPrinter Lib "winspool.drv" Alias "SetPrinterA" _
(ByVal hPrinter As Long, ByVal Level As Long, pPrinter As Any, ByVal Command As Long) As Long
Public Declare Function GetPrinter Lib "winspool.drv" Alias "GetPrinterA" _
(ByVal hPrinter As Long, ByVal Level As Long, pPrinter As Any, ByVal cbBuf As Long, pcbNeeded As Long) As Long
Public Declare Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" (hpvDest As Any, hpvSource As Any, ByVal cbCopy As Long)
Public Declare Function ClosePrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long
Public Const DMORIENT_PORTAIT = 1 '縦向き
Public Const STANDARD_RIGHTS_REQUIRED = &HF0000
Public Const PRINTER_ACCESS_ADMINISTER = &H4
Public Const PRINTER_ACCESS_USE = &H8
Public Const PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)
Public Const DM_PAPERSIZE = &H2 'dmPaperSize
Public Const DM_PAPERLENGTH = &H4 'dmPaperLength
Public Const DM_PAPERWIDTH = &H8 'dmPaperWidth
投稿者 モル  (社会人)
投稿日時
2010/7/8 15:57:07
'フォーム
Private Sub Command1_Click()
Dim PrinterName As String
Dim pd As PRINTER_DEFAULTS
Dim PrinterHandle As Long
Dim Result As Long
Dim Needed As Long
Dim pi2_buffer() As Long
Dim pFullDevMode As Long
Dim MyDevMode As DEVMODE
PrinterName = Printer.DeviceName
If PrinterName = "" Then Exit Sub
Me.MousePointer = 11
pd.pDatatype = vbNullString
pd.pDevMode = 0&
pd.DesiredAccess = PRINTER_ALL_ACCESS
Result = OpenPrinter(PrinterName, PrinterHandle, pd)
Result = GetPrinter(PrinterHandle, 2, ByVal 0&, 0, Needed)
ReDim pi2_buffer((Needed \ 4))
Result = GetPrinter(PrinterHandle, 2, pi2_buffer(0), Needed, Needed)
pFullDevMode = pi2_buffer(7)
Call CopyMemory(MyDevMode, ByVal pFullDevMode, Len(MyDevMode))
With MyDevMode
.dmOrientation = DMORIENT_PORTAIT '縦向き
.dmPaperSize = 256
.dmPaperLength = 4000
.dmPaperWidth = 2500
.dmFields = DM_PAPERSIZE Or DM_PAPERWIDTH Or DM_PAPERLENGTH
End With
Call CopyMemory(ByVal pFullDevMode, MyDevMode, Len(MyDevMode))
Result = SetPrinter(PrinterHandle, 2, pi2_buffer(0), 0&)
Call ClosePrinter(PrinterHandle)
Me.MousePointer = 0
End Sub
投稿者 モル  (社会人)
投稿日時
2010/7/8 15:59:37
'モジュール
Public Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" _
(ByVal PrinterName As String, ByRef hPrinter As IntPtr, ByVal pDefault As PRINTER_DEFAULTS) As Boolean
Public Declare Function GetPrinter Lib "winspool.drv" Alias "GetPrinterA" _
(ByVal hPrinter As IntPtr, ByVal dwLevel As Integer, _
ByVal pPrinter As IntPtr, ByVal cbBuf As Integer, ByRef pcbNeeded As Integer) As Boolean
Public Declare Sub CopyMemory1 Lib "KERNEL32" Alias "RtlMoveMemory" _
(ByVal hpvDest As DEVMODE, ByVal hpvSource As IntPtr, ByVal cbCopy As Long)
Public Declare Sub CopyMemory2 Lib "KERNEL32" Alias "RtlMoveMemory" _
(ByVal hpvDest As IntPtr, ByVal hpvSource As DEVMODE, ByVal cbCopy As Long)
Public Declare Function SetPrinter Lib "winspool.drv" Alias "SetPrinterA" (ByVal hPrinter As IntPtr, _
ByVal Level As Integer, ByRef pPrinter As PRINTER_INFO_2, ByVal Command_Renamed As Integer) As Boolean
Public Declare Function ClosePrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Boolean
Public Structure PRINTER_DEFAULTS
Public pDatatype As String
Public pDevMode As Long
Public DesiredAccess As Long
End Structure
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
Public Const CCHFORMNAME = 32
Public Const CCHDEVICENAME = 32
Public Structure DEVMODE
<VBFixedString(CCHDEVICENAME)> Public dmDeviceName As String
Public dmSpecVersion As Integer
Public dmDriverVersion As Integer
Public dmSize As Integer
Public dmDriverExtra As Integer
Public dmFields As Long
Public dmOrientation As Integer
Public dmPaperSize As Integer
Public dmPaperLength As Integer
Public dmPaperWidth As Integer
Public dmScale As Integer
Public dmCopies As Integer
Public dmDefaultSource As Integer
Public dmPrinterQuality As Integer
Public dmColor As Integer
Public dmDuplex As Integer
Public dmYResolution As Integer
Public dmTTOption As Integer
Public dmCollate As Integer
<VBFixedString(CCHFORMNAME)> Public dmFormname As String
Public dmUnusedPadding As Integer
Public dmBitsPerPel As Integer
Public dmPelsWidth As Long
Public dmPelsHeight As Long
Public dmDisplayFlags As Long
Public dmDisplayFrequency As Long
End Structure
Public Const DMORIENT_PORTAIT = 1
Public Const STANDARD_RIGHTS_REQUIRED = &HF0000
Public Const PRINTER_ACCESS_ADMINISTER = &H4
Public Const PRINTER_ACCESS_USE = &H8
Public Const PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)
Public Const DM_PAPERSIZE = &H2 'dmPaperSize
Public Const DM_PAPERLENGTH = &H4 'dmPaperLength
Public Const DM_PAPERWIDTH = &H8 'dmPaperWidth
投稿者 モル  (社会人)
投稿日時
2010/7/8 16:00:09
'フォーム
Imports System.Runtime.InteropServices
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim PD As New System.Drawing.Printing.PrintDocument
Dim PrinterName As String
Dim PrnD As PRINTER_DEFAULTS
Dim PrinterHandle As Long
Dim Result As Long
Dim Needed As Integer
Dim pPrinterInfo As IntPtr = IntPtr.Zero 'Dim pi2_buffer() As Long
Dim PrinterInfo As PRINTER_INFO_2
Dim pFullDevMode As Long
Dim MyDevMode As DEVMODE = Nothing
PrinterName = PD.PrinterSettings.PrinterName
If PrinterName = "" Then Exit Sub
PrnD.pDatatype = Nothing
PrnD.pDevMode = 0&
PrnD.DesiredAccess = PRINTER_ALL_ACCESS
Call OpenPrinter(PrinterName, PrinterHandle, PrnD)
Call GetPrinter(PrinterHandle, 2, IntPtr.Zero, 0, Needed)
'メモリを割り当てる
pPrinterInfo = Marshal.AllocHGlobal(Needed)
Call GetPrinter(PrinterHandle, 2, pPrinterInfo, Needed, Needed)
PrinterInfo = CType(Marshal.PtrToStructure( _
pPrinterInfo, GetType(PRINTER_INFO_2)), PRINTER_INFO_2)
pFullDevMode = PrinterInfo.pDevMode
'??? この辺りから?
Call CopyMemory1(MyDevMode, pFullDevMode, Len(MyDevMode))
With MyDevMode
.dmOrientation = DMORIENT_PORTAIT '縦向き
.dmPaperSize = 256
.dmPaperLength = 4000
.dmPaperWidth = 2500
.dmFields = DM_PAPERSIZE Or DM_PAPERWIDTH Or DM_PAPERLENGTH
End With
Call CopyMemory2(pFullDevMode, MyDevMode, Len(MyDevMode))
Result = SetPrinter(PrinterHandle, 2, PrinterInfo, IntPtr.Zero)
'??? /この辺りまで?
Call ClosePrinter(PrinterHandle)
Me.Cursor = Cursors.Default
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
End Sub
End Class
投稿者 (--;  (高校生)
投稿日時
2010/7/8 16:32:39
SPAMかと思った。
> 上手くいきませんでした。
なにがどううまくいってないんですか?
ソース自体は問題ないようですけど。
どういう動作を期待して、どこでエラーになって、エラーはこういうもので、っていうのを出してください。
> 上手くいきませんでした。
なにがどううまくいってないんですか?
ソース自体は問題ないようですけど。
どういう動作を期待して、どこでエラーになって、エラーはこういうもので、っていうのを出してください。
投稿者 daive  (社会人)
投稿日時
2010/7/8 16:38:58
VB2005/2008/2010では、 .NETの機能を使ったプログラムを書くことになるので、
APIありきの考えは、捨ててください。
APIでないと、出来ない部分が無いとは、言いませんが、
.NETサポートが有る部分は、.NETを使うようにしてください。
’
参照サイト
MSDNの印刷関係
’
DOBON.NET > プログラミング道 > .NET Tips
画像、印刷編メニュー
’
秀和:Visual Basic 2008逆引き大全555の極意
秀和:Visual Basic 2008 逆引き大全 至高の技 データベース+印刷/帳票 編
位は、持っておいても良い本です。
APIありきの考えは、捨ててください。
APIでないと、出来ない部分が無いとは、言いませんが、
.NETサポートが有る部分は、.NETを使うようにしてください。
’
参照サイト
MSDNの印刷関係
’
DOBON.NET > プログラミング道 > .NET Tips
画像、印刷編メニュー
’
秀和:Visual Basic 2008逆引き大全555の極意
秀和:Visual Basic 2008 逆引き大全 至高の技 データベース+印刷/帳票 編
位は、持っておいても良い本です。
投稿者 モル  (社会人)
投稿日時
2010/7/8 17:06:00
貴重なご意見ありがとうございます。
(--;さん、返信ありがとうございます。
VB6の方では実行後、コンパネからプリンタドライバをプロパティで確認すると変わっているのを確認できるのですが、VB2008の方はエラーは確かに起きませんが、設定が変わっていないので上手くいきませんと書かせてもらいました。
動作はVB6のように実行したら用紙名がユーザー定義になり、用紙サイズが横4000mm縦25000mmと入って縦向き設定になることです。
daiveさん、返信ありがとうございます。
>DOBON.NET > プログラミング道 > .NET Tips
は参考にさせてもらってますが、取得だけで設定の方法が見つけれませんでしたので・・・
「VB2005逆引き大全500の極意」なら所持しています。
ですが、コチラの本にはやりたい内容の設定はありませんでした。
内部だけで簡潔させたいので、プリンタのプロパティ画面のようなのを表示して画面上で変更・・・といったやり方はしない方向で実装したいと思っております。
.Net Frameworkでやる方法があればもちろんやりたいのですが、色々サイトめぐりはしておりますがどうにも解決出来ませんでしたので投稿させていただきました。
(--;さん、返信ありがとうございます。
VB6の方では実行後、コンパネからプリンタドライバをプロパティで確認すると変わっているのを確認できるのですが、VB2008の方はエラーは確かに起きませんが、設定が変わっていないので上手くいきませんと書かせてもらいました。
動作はVB6のように実行したら用紙名がユーザー定義になり、用紙サイズが横4000mm縦25000mmと入って縦向き設定になることです。
daiveさん、返信ありがとうございます。
>DOBON.NET > プログラミング道 > .NET Tips
は参考にさせてもらってますが、取得だけで設定の方法が見つけれませんでしたので・・・
「VB2005逆引き大全500の極意」なら所持しています。
ですが、コチラの本にはやりたい内容の設定はありませんでした。
内部だけで簡潔させたいので、プリンタのプロパティ画面のようなのを表示して画面上で変更・・・といったやり方はしない方向で実装したいと思っております。
.Net Frameworkでやる方法があればもちろんやりたいのですが、色々サイトめぐりはしておりますがどうにも解決出来ませんでしたので投稿させていただきました。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2010/7/8 17:59:19
> Alias "OpenPrinterA"
VB6 当時とは異なり、VB.NET の場合、ANSI 系 API を固定的に呼び出すメリットはほぼありません。
通常は Auto 指定にするか、Unicode 版の API を利用するようにしましょう。
Declare Auto Function OpenPrinter Lib "winspool.drv" (ByVal ~~
以下、Auto 指定の宣言がされた場合という前提で回答します。
> Declare Function OpenPrinter
第 3 引数は、「PRINTER_DEFAULTS への参照」が求められています。
今回は、第 3 引数を ByVal にしているのですから、PRINTER_DEFAULTS を Structure で
宣言するのは誤りです。PRINTER_DEFAULTS を Class に変更してください。
なお、戻り値は As Boolean で構いませんが、この場合の推奨表現は
「As <MarshalAs(UnmanagedType.Bool)> Boolean」となります。
http://msdn.microsoft.com/ja-jp/library/ms182206.aspx
> Declare Function GetPrinter
第 3 引数は、「PRINTER_INFO_2 への参照」です。こちらは、OpenPrinter のような
間違いは無いようですね(ByRef + Structure または ByVal + Class であれば OK)。
> Alias "RtlMoveMemory"
Marshal.StructureToPtr メソッド / Marshal.PtrToStructure メソッドと RtlMoveMemory を
併用されているのは何故でしょうか。Marshal クラスだけで充分な気がします。
> Public Declare Sub CopyMemory1 Lib "KERNEL32" Alias "RtlMoveMemory"
> Public Declare Sub CopyMemory2 Lib "KERNEL32" Alias "RtlMoveMemory"
VB.NET ではオーバーロードが可能なため、それぞれに別名をつける必要はありません。
> Public Structure PRINTER_DEFAULTS
メンバーの型宣言が間違っています。32bit OS で動かす場合は、As Long にはなりません。
<MarshalAs(UnmanagedType.LPTStr)>String, IntPtr, Integer にするか、あるいは
IntPtr, IntPtr, Integer などにしておきましょう。
http://dobon.net/cgi-bin/vbbbs/cbbs.cgi?mode=all&namber=26997&space=0&type=0&no=0
> Public Structure PRINTER_INFO_2
PRINTER_INFO_2 は文字列の受け渡しを伴うため、クラス(もしくは構造体)に
以下の属性を付与して、CharSet を明示しましょう。PRINTER_DEFAULTS も同様です。
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
> Public Const CCHFORMNAME = 32
> Public Const CCHDEVICENAME = 32
Const にも As を宣言しましょう。
> Public Structure DEVMODE
こちらも StructLayout をつけておいた方が良いでしょう。今回は共用体(union)を
使わないので、LayoutKind.Sequential で良さそうですね。
> <VBFixedString(CCHDEVICENAME)> Public dmDeviceName As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCHDEVICENAME)> を付与しましょう。
これは、dmFormname メンバーについても言える事です。
VBFixedString 属性は、Declare で呼び出すアンマネージ API に対しては役に立ちません。
この属性が意味を持つのは、一部のマネージ API に対してだけです(FilePut など)。
VB6 当時とは異なり、VB.NET の場合、ANSI 系 API を固定的に呼び出すメリットはほぼありません。
通常は Auto 指定にするか、Unicode 版の API を利用するようにしましょう。
Declare Auto Function OpenPrinter Lib "winspool.drv" (ByVal ~~
以下、Auto 指定の宣言がされた場合という前提で回答します。
> Declare Function OpenPrinter
第 3 引数は、「PRINTER_DEFAULTS への参照」が求められています。
今回は、第 3 引数を ByVal にしているのですから、PRINTER_DEFAULTS を Structure で
宣言するのは誤りです。PRINTER_DEFAULTS を Class に変更してください。
なお、戻り値は As Boolean で構いませんが、この場合の推奨表現は
「As <MarshalAs(UnmanagedType.Bool)> Boolean」となります。
http://msdn.microsoft.com/ja-jp/library/ms182206.aspx
> Declare Function GetPrinter
第 3 引数は、「PRINTER_INFO_2 への参照」です。こちらは、OpenPrinter のような
間違いは無いようですね(ByRef + Structure または ByVal + Class であれば OK)。
> Alias "RtlMoveMemory"
Marshal.StructureToPtr メソッド / Marshal.PtrToStructure メソッドと RtlMoveMemory を
併用されているのは何故でしょうか。Marshal クラスだけで充分な気がします。
> Public Declare Sub CopyMemory1 Lib "KERNEL32" Alias "RtlMoveMemory"
> Public Declare Sub CopyMemory2 Lib "KERNEL32" Alias "RtlMoveMemory"
VB.NET ではオーバーロードが可能なため、それぞれに別名をつける必要はありません。
> Public Structure PRINTER_DEFAULTS
メンバーの型宣言が間違っています。32bit OS で動かす場合は、As Long にはなりません。
<MarshalAs(UnmanagedType.LPTStr)>String, IntPtr, Integer にするか、あるいは
IntPtr, IntPtr, Integer などにしておきましょう。
http://dobon.net/cgi-bin/vbbbs/cbbs.cgi?mode=all&namber=26997&space=0&type=0&no=0
> Public Structure PRINTER_INFO_2
PRINTER_INFO_2 は文字列の受け渡しを伴うため、クラス(もしくは構造体)に
以下の属性を付与して、CharSet を明示しましょう。PRINTER_DEFAULTS も同様です。
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
> Public Const CCHFORMNAME = 32
> Public Const CCHDEVICENAME = 32
Const にも As を宣言しましょう。
> Public Structure DEVMODE
こちらも StructLayout をつけておいた方が良いでしょう。今回は共用体(union)を
使わないので、LayoutKind.Sequential で良さそうですね。
> <VBFixedString(CCHDEVICENAME)> Public dmDeviceName As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCHDEVICENAME)> を付与しましょう。
これは、dmFormname メンバーについても言える事です。
VBFixedString 属性は、Declare で呼び出すアンマネージ API に対しては役に立ちません。
この属性が意味を持つのは、一部のマネージ API に対してだけです(FilePut など)。
投稿者 モル  (社会人)
投稿日時
2010/7/8 18:10:17
魔界の仮面弁士さん、ご意見+ご指摘ありがとうございます。
まだまだ勉強不足ゆえ、使い方を誤ったまま使用していた所が多々あるのですね。。。
それぞれを確認しつつ修正していきたいと思います。
.Net Frameworkが使えると、私のやりたい事は全て出来るのでしょうか?
せっかくの.Netへの移行なのでAPIより.Netを使いたいのは山々なのですが。。。
ご助言などいただけると幸いです。
まだまだ勉強不足ゆえ、使い方を誤ったまま使用していた所が多々あるのですね。。。
それぞれを確認しつつ修正していきたいと思います。
.Net Frameworkが使えると、私のやりたい事は全て出来るのでしょうか?
せっかくの.Netへの移行なのでAPIより.Netを使いたいのは山々なのですが。。。
ご助言などいただけると幸いです。
早速ですがVisual Basic 2008でプリンタ情報の設定の仕方でお聞きしたい事があります。
Visual Basic6では問題なく出来たのですが(API使用)、これをVisual Basic 2008に直したいのですが上手くいきませんでした。
しっかり理解しきれていない部分もあるので変換しきれないのだと思ってはいるのですが、何か方法がございましたら教えてくださると助かります。
APIを使わない方法など、ご意見などよろしくお願いします。
以下長いですがコードを貼らせてもらいます。