C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[6]: Win32API SetPrinter 用紙サイズの変更


(過去ログ 96 を表示中)

[トピック内 8 記事 (1 - 8 表示)]  << 0 >>

■57499 / inTopicNo.1)  Win32API SetPrinter 用紙サイズの変更
  
□投稿者/ ひろし (1回)-(2011/03/01(Tue) 19:42:29)

分類:[.NET 全般] 

開発環境はWindows7、VB.NET2008になります。
よろしくお願いいたします。

印刷ダイアログなどを表示せずにプログラム中で、プリンタの用紙設定を(ユーザー定義用紙へ)変更して印刷するプログラムを考えています。
OpenPrinter、GetPrinter、ClosePrinterは正常動作しているようなのですが、SetPrinterのみ戻り値に0が返ってきて用紙変更ができません。

ソースは以下になります。
http://dobon.net/vb/bbs/log3-31/19342.htmlなど他のサイトを参考にしました。

 Public Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal infoPrinterName As String, ByRef phPrinter As Integer, <MarshalAs(UnmanagedType.Struct)> ByRef pDefault As PRINTER_DEFAULTS) As Integer
 Public Declare Function ClosePrinter Lib "winspool.drv" Alias "ClosePrinter" (ByVal hPrinter As Integer) As Integer
 Public Declare Function GetPrinter Lib "winspool.drv" Alias "GetPrinterA" (ByVal hPrinter As Integer, ByVal Level As Integer, ByVal infoPrinter As IntPtr, ByVal cbBuf As Integer, ByRef pcbNeeded As Integer) As Integer
 Public Declare Function SetForm Lib "winspool.drv" Alias "SetFormA" (ByVal hPrinter As Integer, ByVal pFormName As String, ByVal Level As Integer, ByVal pForm As IntPtr) As Integer
 
 Sub Main()
  Try
  ' 変数を宣言する。
  Dim hPrinter As Integer
  Dim returnValue As Integer
  Dim pDefault As New PRINTER_DEFAULTS
  Dim byteNeeded As Integer
  Dim pPrinter As IntPtr
  Dim infoPrinter As PRINTER_INFO_2
  Dim devMode As DEVMODE
 
  ' アクセス権を設定する。
  With pDefault
  .DesiredAccess = PRINTER_ALL_ACCESS
  End With
 
  ' プリンターを開く。
  returnValue = OpenPrinter("FX DocuPrint 350JM", _
  hPrinter, _
  pDefault)
  Debug.Print("OpenPrinter:" & returnValue)
 
  ' バッファサイズを取り出す。
  returnValue = GetPrinter(hPrinter, _
  2, _
  IntPtr.Zero, _
  0, _
  byteNeeded)
 
  ' メモリ割当て。
  pPrinter = Marshal.AllocHGlobal(byteNeeded)
 
  ' プリンタ情報を読取する。
  returnValue = GetPrinter(hPrinter, _
  2, _
  pPrinter, _
  byteNeeded, _
  byteNeeded)
  Debug.Print("GetPrinter:" & returnValue)
 
  ' 用紙サイズの変更をする。
  infoPrinter = CType(Marshal.PtrToStructure(pPrinter, GetType(PRINTER_INFO_2)), PRINTER_INFO_2)
  devMode = CType(Marshal.PtrToStructure(infoPrinter.pDevMode, GetType(DEVMODE)), DEVMODE)
 
  With devMode
  .dmPaperSize = DMPAPER_A4
  End With
 
  Marshal.StructureToPtr(devMode, infoPrinter.pDevMode, True)
  Marshal.StructureToPtr(infoPrinter, pPrinter, True)
 
  ' プリンタ情報の書込をする。
  returnValue = SetPrinter(hPrinter, _
  2, _
  pPrinter, _
  0)
  Debug.Print("SetPrinter:" & returnValue)
 
  ' 閉じる。
  returnValue = ClosePrinter(hPrinter)
  Debug.Print("ClosePrinter:" & returnValue)
 
  ' メモリ開放。
  Marshal.FreeHGlobal(pPrinter)
 
  Exit Sub
  Catch ex As Exception
  Debug.Print(ex.ToString)
  End Try
 End Sub

いろいろ調べているのですが、原因がわからず手間取っています。
お分かりになる方、アドバイスいただけると助かります。よろしくお願いいたします。


引用返信 編集キー/
■57500 / inTopicNo.2)  Re[1]: Win32API SetPrinter 用紙サイズの変更
□投稿者/ 魔界の仮面弁士 (2116回)-(2011/03/01(Tue) 20:27:31)
No57499 (ひろし さん) に返信
> プリンタの用紙設定を(ユーザー定義用紙へ)変更して印刷するプログラムを考えています。
PrinterSettings クラスでは駄目ですか?

> OpenPrinter、GetPrinter、ClosePrinterは正常動作しているようなのですが、
プリンター名に Shift_JIS (CP932)で表現できない文字列が現れた場合に備え、
できれば A 系関数ではなく、W 系関数を使った方が良いかと思います。今回はどちらでも良いですが。

> SetPrinterのみ
その肝心の SetPrinter API の Declare 宣言が記載されていません…。
たとえば、ByVal と ByRef を間違っているという事はありませんか?

> アドバイスいただけると助かります
定数その他、不足しているコードが多くて試すことができません…。
せめて、問題になっている箇所(SetPrinter と PRINTER_INFO_2)ぐらいは提示してください。

> 戻り値に0が返ってきて用紙変更ができません。
その時、Err.LastDllError もしくは Marshal.GetLastWin32Error() は何を返していましたか?

> <MarshalAs(UnmanagedType.Struct)> ByRef pDefault As PRINTER_DEFAULTS
PRINTER_DEFAULTS は Class として宣言していますか? それとも Structure として宣言していますか?

> ' 変数を宣言する。
> Dim hPrinter As Integer
ハンドル系は、Integer ではなく IntPtr で受けるべきかと。
引用返信 編集キー/
■57503 / inTopicNo.3)  Re[2]: Win32API SetPrinter 用紙サイズの変更
□投稿者/ ひろし (2回)-(2011/03/01(Tue) 23:03:44)
早々にご連絡いただき有難うございます。

> 定数その他、不足しているコードが多くて試すことができません…。
> せめて、問題になっている箇所(SetPrinter と PRINTER_INFO_2)ぐらいは提示してください。

 ソースが汚かったので抜粋したときに漏れてしまいました。すみません...

>>プリンタの用紙設定を(ユーザー定義用紙へ)変更して印刷するプログラムを考えています。
> PrinterSettings クラスでは駄目ですか?

 PDFを印刷するつもりですので、PrinterSettings クラス考えていないです。
 System.Drawing.Printing でPDFを印刷することができるのであればよいのですが...

>>戻り値に0が返ってきて用紙変更ができません。
> その時、Err.LastDllError もしくは Marshal.GetLastWin32Error() は何を返していましたか?

 戻り値しかみていませんでした。早速、試してみたところ両方とも「5」を返していました。
 こちらの内容については後で調べてみます。

以下、ソースになります。

 Public Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal infoPrinterName As String, ByRef phPrinter As Integer, <MarshalAs(UnmanagedType.Struct)> ByRef pDefault As PRINTER_DEFAULTS) As Integer
 Public Declare Function ClosePrinter Lib "winspool.drv" Alias "ClosePrinter" (ByVal hPrinter As Integer) As Integer
 Public Declare Function GetPrinter Lib "winspool.drv" Alias "GetPrinterA" (ByVal hPrinter As Integer, ByVal Level As Integer, ByVal infoPrinter As IntPtr, ByVal cbBuf As Integer, ByRef pcbNeeded As Integer) As Integer
 Public Declare Function SetPrinter Lib "winspool.drv" Alias "SetPrinterA" (ByVal hPrinter As Integer, ByVal Level As Integer, ByVal infoPrinter As IntPtr, ByVal Command As Integer) As Integer

 <StructLayout(LayoutKind.Sequential)> _
 Public Structure PRINTER_DEFAULTS
  Public pDatatype As String
  Public pDevMode As DEVMODE
  Public DesiredAccess As Integer
 End Structure
 
 <StructLayout(LayoutKind.Sequential)> _
 Public Structure DEVMODE
  <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCHDEVICENAME)> _
  Public dmDeviceName As String
  Public dmSpecVersion As Integer
  Public dmDriverVersion As Integer
  Public dmSize As Integer
  Public dmDriverExtra As Integer
  Public dmFields As Integer
  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 dmPrintQuality As Integer
  Public dmColor As Integer
  Public dmDuplex As Integer
  Public dmYResolution As Integer
  Public dmTTOption As Integer
  Public dmCollate As Integer
  <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCHFORMNAME)> _
  Public dmFormName As String
  Public dmUnusedPadding As Integer
  Public dmBitsPerPel As Integer
  Public dmPelsWidth As Integer
  Public dmPelsHeight As Integer
  Public dmDisplayFlags As Integer
  Public dmDisplayFrequency As Integer
 End Structure
 
 <StructLayout(LayoutKind.Sequential)> _
 Public Structure PRINTER_INFO_2
  Public pServerName As String
  Public infoPrinterName 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 DEVMODE
  Public pDevMode As IntPtr
  Public pSepFile As String
  Public pPrintProcessor As String
  Public pDatatype As String
  Public pParameters As String
  'Public pSecurityDescriptor As SECURITY_DESCRIPTOR
  Public pSecurityDescriptor As IntPtr
  Public Attributes As Integer
  Public Priority As Integer
  Public DefaultPriority As Integer
  Public StartTime As Integer
  Public UntilTime As Integer
  Public Status As Integer
  Public cJobs As Integer
  Public AveragePPM As Integer
 End Structure
 
 Public Const CCHFORMNAME = 32
 Public Const CCHDEVICENAME = 32
 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 DMPAPER_A4 = 9

 Sub Main()
  Try
  ' 変数を宣言する。
  Dim hPrinter As Integer
  Dim returnValue As Integer
  Dim pDefault As New PRINTER_DEFAULTS
  Dim byteNeeded As Integer
  Dim pPrinter As IntPtr
  Dim infoPrinter As PRINTER_INFO_2
  Dim devMode As DEVMODE
 
  ' アクセス権を設定する。
  With pDefault
  .DesiredAccess = PRINTER_ALL_ACCESS
  End With
 
  ' プリンターを開く。
  returnValue = OpenPrinter("FX DocuPrint 350JM", _
  hPrinter, _
  pDefault)
  Debug.Print("OpenPrinter:" & returnValue)
 
  ' バッファサイズを取り出す。
  returnValue = GetPrinter(hPrinter, _
  2, _
  IntPtr.Zero, _
  0, _
  byteNeeded)
 
  ' メモリ割当て。
  pPrinter = Marshal.AllocHGlobal(byteNeeded)
 
  ' プリンタ情報を読取する。
  returnValue = GetPrinter(hPrinter, _
  2, _
  pPrinter, _
  byteNeeded, _
  byteNeeded)
  Debug.Print("GetPrinter:" & returnValue)
 
  ' 用紙サイズの変更をする。
  infoPrinter = CType(Marshal.PtrToStructure(pPrinter, GetType(PRINTER_INFO_2)), PRINTER_I
  devMode = CType(Marshal.PtrToStructure(infoPrinter.pDevMode, GetType(DEVMODE)), DEVMODE)
 
  With devMode
  .dmPaperSize = DMPAPER_A4
  End With
 
  Marshal.StructureToPtr(devMode, infoPrinter.pDevMode, True)
  Marshal.StructureToPtr(infoPrinter, pPrinter, True)
 
  ' プリンタ情報の書込をする。
  returnValue = SetPrinter(hPrinter, _
  2, _
  pPrinter, _
  0)
 Debug.Print("SetPrinter:" & returnValue)

 ' 閉じる。
 returnValue = ClosePrinter(hPrinter)
 Debug.Print("ClosePrinter:" & returnValue)

 ' メモリ開放。
 Marshal.FreeHGlobal(pPrinter)

 Exit Sub
 Catch ex As Exception
 Debug.Print(ex.ToString)
 End Try
 End Sub

ご迷惑をおかけしますが、よろしくお付き合いください。
よろしくお願いします。

引用返信 編集キー/
■57519 / inTopicNo.4)  Re[3]: Win32API SetPrinter 用紙サイズの変更
□投稿者/ 魔界の仮面弁士 (2117回)-(2011/03/02(Wed) 19:28:33)
No57503 (ひろし さん) に返信
> 戻り値しかみていませんでした。早速、試してみたところ両方とも「5」を返していました。
『アクセスが拒否されました。』の意味です。


> 以下、ソースになります。
VBA からの API 呼び出しと、VB.NET からの API 呼び出しを混同されている印象を受けます。

VBA においては、
  Integer  … 16bit
  Long     … 32bit
  LongLong … 64bit
  LongPtr  … 32bit または 64bit
というデータ幅を持ちますが、VB.NET においては
  Short    … 16bit  (Int16)
  Integer  … 32bit  (Int32)
  Long     … 64bit  (Int64)
  IntPtr   … 32bit または 64bit
ですので、サンプルコード等を流用される際には注意してください。


たとえば、アクセス権を指定しようとしている箇所ですが、
>  ' アクセス権を設定する。
>  With pDefault
>    .DesiredAccess = PRINTER_ALL_ACCESS
>  End With
左辺の PRINTER_DEFAULTS.DesiredAccess は Int32 型で宣言しているのに、
右辺は Int64 な値を代入しています。宣言を見直してください。


また、DEVMODE 構造体の宣言も同様の理由でオフセットがずれていますので、
これでは正しい値を得られないでしょう。たとえば
http://msdn.microsoft.com/en-us/library/dd183565%28VS.85%29.aspx
においては、dmSpecVersion や dmDriverVersion は WORD 型(16bit幅)ですが、
提示されたコードはそうなっていません。


API の宣言と呼び出し方が正しければ、GetPrinter 後の dmPaperSize には
現在の用紙サイズが格納されているはずです。DMPAPER_A4 をセットする前に、
dmPaperSize が正しく得られているかを確認してみてください。
(dmFields のビットフラグを確認する事も忘れずに…)

引用返信 編集キー/
■57528 / inTopicNo.5)  Re[4]: Win32API SetPrinter 用紙サイズの変更
□投稿者/ ひろし (3回)-(2011/03/03(Thu) 11:25:17)
おはようございます。

>>以下、ソースになります。
> VBA からの API 呼び出しと、VB.NET からの API 呼び出しを混同されている印象を受けます。

 サンプルコードから流用していたので...意識していませんでした。
 API の宣言は http://www.codegod.de/WebAppCodeGod/Win32APIViewer.aspx を参考にしていました。

> > 戻り値しかみていませんでした。早速、試してみたところ両方とも「5」を返していました。
> 『アクセスが拒否されました。』の意味です。

 同様の事例?がないか調べてみたところ、http://qanda.rakuten.ne.jp/qa5629663.html にありました。
 最初にご指摘いただいた API の宣言のところに問題があるようですね。
 http://hanatyan.sakura.ne.jp/freesoft/win32api.htm を参考に API の宣言を見直ししたところ
 正常動作が確認できました。

魔界の仮面弁士さんにご指摘いただいた全てを理解できたわけではないので、もう少し自分で調べてから
解決にしようと思います。お付き合いいただきありがとうございます。

参考までに後でちょんプロを記載しておきます。とりあえず、自分の環境下では問題なく動作しました。
引用返信 編集キー/
■57529 / inTopicNo.6)  Re[5]: Win32API SetPrinter 用紙サイズの変更
□投稿者/ ひろし (4回)-(2011/03/03(Thu) 11:25:52)
 Imports System.Runtime.InteropServices
 
 Public Class Form1
 
  'Public Const DMPAPER_A4 = 9
  Public Const DC_PAPERS As Integer = 2
  Public Const DC_PAPERNAMES As Integer = 16
  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 Integer = (STANDARD_RIGHTS_REQUIRED Or PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)
 
  <DllImport("winspool.drv", CharSet:=CharSet.Auto)> _
  Private Shared Function OpenPrinter( _
  ByVal pPrinterName As String, _
  ByRef hPrinter As IntPtr, _
  ByRef pDefault As PRINTER_DEFAULTS) As Boolean
  End Function
 
  <DllImport("winspool.drv", CharSet:=CharSet.Auto)> _
  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
 
  <DllImport("winspool.drv", CharSet:=CharSet.Auto)> _
  Private Shared Function SetPrinter( _
  ByVal hPrinter As IntPtr, _
  ByVal dwLevel As Integer, _
  ByVal pPrinter As IntPtr, _
  ByVal Command As Integer) As Boolean
  End Function
 
  <DllImport("winspool.drv", CharSet:=CharSet.Auto)> _
  Private Shared Function ClosePrinter( _
  ByVal hPrinter As IntPtr) As Boolean
  End Function
 
  Declare Function DeviceCapabilities Lib "winspool.drv" Alias "DeviceCapabilitiesA" ( _
  ByVal pDevice As String, _
  ByVal pPort As String, _
  ByVal fwCapability As Short, _
  ByVal pOutput() As Short, _
  ByVal pDevMode As IntPtr) As Integer
 
  Declare Function DeviceCapabilities Lib "winspool.drv" Alias "DeviceCapabilitiesA" ( _
  ByVal pDevice As String, _
  ByVal pPort As String, _
  ByVal fwCapability As Short, _
  ByVal pOutput As String, _
  ByVal pDevMode As IntPtr) As Integer
 
  Friend Structure PRINTER_DEFAULTS
  Public pDatatype As IntPtr
  Public pDevMode As IntPtr
  Public DesiredAccess As Integer
  End Structure
 
  <Serializable(), StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
  Friend 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
 
  <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
  Friend Structure DevMode
  <VBFixedString(32), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> _
  Public dmDeviceName As String
  Public dmSpecVersion As Short
  Public dmDriverVersion As Short
  Public dmSize As Short
  Public dmDriverExtra As Short
  Public dmFields As Integer
  Public dmOrientation As Short
  Public dmPaperSize As Short
  Public dmPaperLength As Short
  Public dmPaperWidth As Short
  Public dmScale As Short
  Public dmCopies As Short
  Public dmDefaultSource As Short
  Public dmPrintQuality As Short
  Public dmColor As Short
  Public dmDuplex As Short
  Public dmYResolution As Short
  Public dmTTOption As Short
  Public dmCollate As Short
  <VBFixedString(32), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> _
  Public dmFormName As String
  Public dmUnusedPadding As Short
  Public dmBitsPerPel As Short
  Public dmPelsWidth As Integer
  Public dmPelsHeight As Integer
  Public dmDisplayFlags As Integer
  Public dmDisplayFrequency As Integer
  End Structure
 
  Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
  Try
  ' バッファサイズを取り出す。
  Dim nameCount As Integer
  nameCount = DeviceCapabilities("TEC B-858-R", String.Empty, DC_PAPERNAMES, vbNullString, IntPtr.Zero)
 
  ' 用紙名を取り出す。
  Dim paperNames As String = New String(" "c, nameCount * 64)
  Dim paperIndex As Integer = 0
  Dim hEncoding As System.Text.Encoding = System.Text.Encoding.GetEncoding("Shift-JIS")
  Dim paperName As String
  DeviceCapabilities("TEC B-858-R", String.Empty, DC_PAPERNAMES, paperNames, IntPtr.Zero)
  For i As Integer = 0 To nameCount - 1
  paperName = hEncoding.GetString(hEncoding.GetBytes(paperNames), i * 64, 64)
  If paperName.Trim.CompareTo("USER") = 0 Then
  paperIndex = i
  Exit For
  End If
  Next
 
  ' バッファサイズを取り出す。
  Dim numberCount As Integer
  numberCount = DeviceCapabilities("TEC B-858-R", String.Empty, DC_PAPERS, 0, IntPtr.Zero)
 
  ' 用紙番号を取り出す。
  Dim paperNumbers(numberCount - 1) As Short
  DeviceCapabilities("TEC B-858-R", String.Empty, DC_PAPERS, paperNumbers, IntPtr.Zero)
 
  ' アクセス権を設定する。
  Dim pDefault As New PRINTER_DEFAULTS
  With pDefault
  .DesiredAccess = PRINTER_ALL_ACCESS
  End With
 
  ' プリンターを開く。
  Dim hPrinter As IntPtr
  Dim returnValue As Boolean
  returnValue = OpenPrinter("TEC B-858-R", _
  hPrinter, pDefault)
  Debug.Print("OpenPrinter:" & returnValue)
 
  ' バッファサイズを取り出す。
  Dim byteNeeded As Integer
  returnValue = GetPrinter(hPrinter, _
  2, IntPtr.Zero, 0, byteNeeded)
 
  ' メモリの割当て。
  Dim pPrinter As IntPtr
  pPrinter = Marshal.AllocHGlobal(byteNeeded)
 
  ' プリンター情報を読み取りする。
  returnValue = GetPrinter(hPrinter, _
  2, pPrinter, byteNeeded, byteNeeded)
  Debug.Print("GetPrinter:" & returnValue)
 
  ' 構造体にメモリのデータをコピーする。
  Dim infoPrinter As PRINTER_INFO_2
  Dim modeDev As DevMode
  infoPrinter = CType(Marshal.PtrToStructure(pPrinter, GetType(PRINTER_INFO_2)), PRINTER_INFO_2)
  modeDev = CType(Marshal.PtrToStructure(infoPrinter.pDevMode, GetType(DevMode)), DevMode)
 
  ' 用紙サイズを変更する。
  modeDev.dmPaperSize = paperNumbers(paperIndex)
 
  ' メモリに構造体のデータをコピー する。
  Marshal.StructureToPtr(modeDev, infoPrinter.pDevMode, True)
  Marshal.StructureToPtr(infoPrinter, pPrinter, True)
 
  ' プリンター情報を書き込みする。
  returnValue = SetPrinter(hPrinter, _
  2, pPrinter, 0)
  Debug.Print("SetPrinter:" & returnValue)
 
  ' プリンターを閉じる。
  returnValue = ClosePrinter(hPrinter)
  Debug.Print("ClosePrinter:" & returnValue)
 
  ' メモリを開放する。
  Marshal.FreeHGlobal(pPrinter)
 
  Exit Sub
  Catch ex As Exception
  Debug.Print(ex.ToString)
  End Try
  End Sub
 End Class
引用返信 編集キー/
■57530 / inTopicNo.7)  Re[5]: Win32API SetPrinter 用紙サイズの変更
□投稿者/ 魔界の仮面弁士 (2118回)-(2011/03/03(Thu) 12:12:11)
No57528 (ひろし さん) に返信
> API の宣言を見直ししたところ正常動作が確認できました。
おぉ、良かったです。


> 参考までに後でちょんプロを記載しておきます。
> とりあえず、自分の環境下では問題なく動作しました。
実際のコードではエラー処理も考慮しておいてくださいね。

サンプルゆえに省略してあるだけとは思いますが、提示されたコードだけでは、
OpenPrinter 等の呼び出しに失敗した場合の処理が考慮されていませんし、
例外発生時に pPrinter が解放されないといった問題を生じる事になりますので。


> ByRef pDefault As PRINTER_DEFAULTS) As Boolean
できれば戻り値を
 As <MarshalAs(UnmanagedType.Bool)> Boolean
にしておく事をお奨めします。

API においては、
 BOOL 型 …… 4バイト
 VARIANT_BOOL …… 2バイト
 BOOLEAN 型 …… 1バイト
 bool 型 …… 1バイト
です。OpenPrinter の戻り値は BOOL なので 4 バイトですね。


これが VBA の場合は、API 側のサイズに合わせて
 Long  …… 4バイト
 Boolean …… 2バイト
 Byte  …… 1バイト
を切り替えて使う事になります。

一方、VB.NET の場合はいずれも「Boolean 型」でマーシャリングできます。
そしてこの場合、マーシャリングのサイズを明示するために、
 <MarshalAs(UnmanagedType.Bool)>
 <MarshalAs(UnmanagedType.VariantBool)>
 <MarshalAs(UnmanagedType.U1)>
のいずれかの属性を付与しておくことが推奨されています。
http://msdn.microsoft.com/ja-jp/library/ms182206.aspx


ちなみに MarshalAs属性を指定しなかった場合、Boolean 型は
.NET Framework では 4 バイト(UnmanagedType.Bool 相当)にマーシャリングされ、
.NET Compact Framework では 1 バイト(UnmanagedType.U1 相当)になります。
http://msdn.microsoft.com/ja-jp/library/t2t3725f%28VS.90%29.aspx
引用返信 編集キー/
■57545 / inTopicNo.8)  Re[6]: Win32API SetPrinter 用紙サイズの変更
□投稿者/ ひろし (5回)-(2011/03/03(Thu) 16:45:38)
早々にご連絡いただき、ありがとうございます。

>>参考までに後でちょんプロを記載しておきます。
>>とりあえず、自分の環境下では問題なく動作しました。
> 実際のコードではエラー処理も考慮しておいてくださいね。
>
> サンプルゆえに省略してあるだけとは思いますが、提示されたコードだけでは、
> OpenPrinter 等の呼び出しに失敗した場合の処理が考慮されていませんし、
> 例外発生時に pPrinter が解放されないといった問題を生じる事になりますので。

 はい。実際には、エラー時のハンドリングが必要ですね。
 他にもご指摘いただいているところで反映漏れがありますが...
 これらについては後でゆっくりやろうと思います。

今回はアドバイスいただき、ありがとうございます。助かりました。
また機会がありましたら、よろしくお願いいたします。では。

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -