- 題名: API DeletePrinterの使用について
- 日時: 2010/06/30 21:10:29
- ID: 26997
- この記事の返信元:
- (なし)
- この記事への返信:
- [26998] Re[1]: API DeletePrinterの使用について2010/07/01 8:08:40
- [27001] Re[1]: API DeletePrinterの使用について2010/07/01 21:59:54
- ツリーを表示
■No26997に返信(ぷりんさんの記事)
> 実際のコードを下記に載せますので、いけない点をご指摘頂けないでしょうか?
検証できる環境が手元に無いので、机上デバッグのみで指摘していきます。
> アクセス拒否(GetLastError()エラー番号:5)が発生してしまい、
提示されたコードでは、Err.LastDllError を利用されているようですので、
既に御存知なのかとは思いますが、VB からは GetLastError API ではなく、
Err.LastDllError もしくは Marshal.GetLastWin32Error() を利用すべきです。
> Private Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" _
> (ByVal PrinterName As String, ByRef hPrinter As IntPtr, ByVal pDefault As PRINTER_DEFAULTS) As Boolean
VB6 当時ならいざ知らず、Win9x 系 OS がほぼ使われなくなった現在では
「Alias "〜A"」の ANSI 系 API を利用する意味は無いはずです。
通常は、Unicode バージョンを利用するようにしましょう。
> Private Declare Function ClosePrinter Lib "winspool.drv" _
> (ByVal hPrinter As IntPtr) As Int32
OpenPrinter の戻り値を Boolean として、ClosePrinter/DeletePrinter の戻り値を
Int32 にしているのは何故でしょうか?
これらの戻り値は、いずれも "BOOL" として定義されています。
.NET でマーシャリングする場合には、
As <MarshalAs(UnmanagedType.Bool)> Boolean
とした方が良いでしょう。
> Structure PRINTER_DEFAULTS
この型は文字列の受け渡しを伴うため、
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
の属性を付与しておいた方が良いと思います。
それと、この型は Class で宣言してください。Structure でも間違いではありませんが、
その場合には OpenPrinter の第3引数を ByRef に変更する必要があります。
ちなみに、OpenPrinter に PRINTER_DEFAULTS を渡さない(NULL 指定)としたい場合には、
pDefault 引数を「ByVal + クラス」で宣言しておいて Nothing を渡すようにするか、
あるいは ByVal IntPtr のオーバーロードを用意しておき、IntPtr.Zero を渡すようにします。
> Structure PRINTER_DEFAULTS
> Dim pDatatype As Integer
> Dim pDevMode As Integer
> Dim DesiredAccess As Integer
> End Structure
すべて Integer 型で宣言されていますね。
本来は、それぞれ "LPTSTR"、"LPDEVMODE"、"ACCESS_MASK" 型です。
最初のメンバーは As String または As IntPtr、
次のメンバーは As DEVMODE または As IntPtr です。
(ただし、DEVMODE の宣言は面倒なので、IntPtr で済ませてしまうのも手かも)
最後のメンバーは、As Integer で良さそうです(あるいは ACCESS_MASK 列挙体)。
> MsgBox("[" & Err.LastDllError & "] " & Err.Description, MsgBoxStyle.Critical + MsgBoxStyle.OKOnly, "エラー")
本題とは無関係ですが、MsgBox の第2引数は「+ 演算子」ではなく「Or 演算子」で繋ぐべきです。
> Dim x As Int32 = DeletePrinter(hPrinter)
> ClosePrinter(hPrinter)
これだと、OpenPrinter が失敗したときにも hPrinter が処理されてしまう気がします。
分類:[.NET]
初めて投稿させて頂きます。よろしくお願いします。
プリンタドライバのインストール、アンインストールを行うプログラムを作成しています。プリンタキューを削除するのに、APIのDeletePrinter関数を使っていますが、アクセス拒否(GetLastError()エラー番号:5)が発生してしまい、削除ができません。丸一日悩みましたが、どこがいけないのかわかりません。実際のコードを下記に載せますので、いけない点をご指摘頂けないでしょうか?
よろしくお願いいたします。
*************************************************************
Private Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" _
(ByVal PrinterName As String, ByRef hPrinter As IntPtr, ByVal pDefault As PRINTER_DEFAULTS) As Boolean
Private Declare Function ClosePrinter Lib "winspool.drv" _
(ByVal hPrinter As IntPtr) As Int32
Public Declare Function DeletePrinter Lib "winspool.drv" _
(ByVal hPrinter As IntPtr) As Int32
Structure PRINTER_DEFAULTS
Dim pDatatype As Integer
Dim pDevMode As Integer
Dim DesiredAccess As Integer
End Structure
Public Const STANDARD_RIGHTS_REQUIRED As Integer = &HF0000
Public Const PRINTER_ACCESS_ADMINISTER As Integer = &H4
Public Const PRINTER_ACCESS_USE As Integer = &H8
Public Const PRINTER_ALL_ACCESS As Boolean = (STANDARD_RIGHTS_REQUIRED Or PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)
Public sub Main()
Dim hPrinter As IntPtr
Dim udtPrinterDefaults As PRINTER_DEFAULTS
'プリンタアクセス権を指定
With udtPrinterDefaults
.DesiredAccess = PRINTER_ALL_ACCESS
End With
'プリンタのハンドルを取得する
If Not OpenPrinter("HITACHI SP-Component", hPrinter, udtPrinterDefaults) Then
MsgBox("[" & Err.LastDllError & "] " & Err.Description, MsgBoxStyle.Critical + MsgBoxStyle.OKOnly, "エラー")
End If
'プリンタキューの削除
Dim x As Int32 = DeletePrinter(hPrinter)
If x = 0 Then
MsgBox("[" & Err.LastDllError & "] " & Err.Description, MsgBoxStyle.Critical + MsgBoxStyle.OKOnly, "エラー")
End If
'プリンタのハンドルを閉じる
ClosePrinter(hPrinter)
End Sub
*************************************************************