この特集のトップページへ
Chapter 7:プレゼンテーション層の構築

7.4.7 顧客情報の印刷処理
●Win32APIを使ってユーザーにプリンタを選択させる

○デフォルトプリンタを変更する
 List 7-56の処理によって,ユーザーに[プリンタの設定]ダイアログボックスを表示するところまでできたわけだ。あとは,ユーザーが選択したとおりにプリンタの設定を変更すればよいということになる。

 PrintDlg関数の呼び出しが終わり,ユーザーが[OK]ボタンを押すと,引数に指定したPRINTDLG構造体のhDevModeメンバにはユーザーが選択した用紙情報を示すDEVMODE構造体のメモリハンドルが,hDevNamesメンバにはユーザーが選択したプリンタ情報を示すDEVNAMES構造体のメモリハンドルが,それぞれ設定される。

 まずは,これらのメモリハンドルが指すメモリの内容をVisual Basicの変数にコピーして参照できるようにする。それには,先に説明したWin32 APIのGlobalLock関数,CopyMemory関数,GlobalUnlock関数を使い,次のようにすればよい。

' DEVMODE構造体の内容をvDevMode変数にコピーする
lpDevMode = GlobalLock(vPrintDlg.hDevMode)
CopyMemory vDevMode, ByVal lpDevMode, Len(vDevMode)
GlobalUnlock lpDevMode
' DEVNAMES構造体の内容をvDevNames変数にコピーする
lpDevNames = GlobalLock(vPrintDlg.hDevNames)
CopyMemory vDevNames, ByVal lpDevNames, Len(vDevNames)
GlobalUnlock lpDevNames

 以上の処理により,vDevMode変数にユーザーが選択した用紙情報が,vDevNames変数にユーザーが選択したプリンタ情報が,それぞれ格納されるようになる。

 この処理で,情報を変数にコピーしてしまったので,もうメモリハンドルが指すメモリエリアは解放してしまってよいだろう。メモリエリアを解放するには,Win32 APIのGlobalFree関数を使う。GlobalFree関数は,次のように定義される。

Public Declare Function GlobalFree Lib "kernel32" ( _
    ByVal hMem As Long) As Long

 GlobalFree関数は,引数に指定されたメモリハンドルが示すメモリエリアを解放するという機能を持つ。よって,次のようにすれば,vPrintDlg変数のhDevModeメンバが指しているメモリエリアと,hDevNamesメンバが指しているメモリエリアを,ともに解放することができる。もし,GlobalFree関数の呼び出しを忘れると,メモリリークが発生してしまうので注意してほしい。

GlobalFree vPrintDlg.hDevMode
GlobalFree vPrintDlg.hDevNames

 では次に,プリンタの選択方法から説明してゆこう。すでにこの段階でvDevNames変数には,ユーザーが選択したプリンタのデバイス名などが格納されている。DEVNAMES構造体は,Fig.7-65に示した構造になっているので,次のようにすると,ユーザーが選択したプリンタのデバイス名を取得することができる。

Dim NewDriverName
NewDeviceName = Mid(vDevNames.extData, _
                    vDevNames.wDeviceOffset - 8 + 1)
NewDeviceName = Left(NewDeviceName, _
                     InStr(NewDeviceName, Chr(0)) - 1)

 Mid関数やLeft関数が登場して少々見づらいが,Fig.7-65に示した構造に則り,extDataメンバが指している場所から指定されたバイト数分だけ進んだところを取得するというものである。なお,3行目のLeft関数は,最後のChr(0)を取り除くための処理である。

 以上の処理によって,ユーザーが選択したプリンタのデバイス名がNewDeviceName変数に格納される。

 ところで,Visual Basicにおいては,インストールされている全プリンタがPrintersコレクションに保持されている。そのため,Printersコレクションのなかから,上記で取得したNewDeviceName変数の内容と同じデバイス名のプリンタをデフォルトプリンタに設定することで,プリンタが切り替わるようになる。具体的には,ForEachステートメントを使い,次のようにする。

Dim prt As Printer
For Each prt In Printers
    If UCase(prt.DeviceName) = UCase(NewDeviceName) Then
        ' このプリンタをデフォルトプリンタとする
        Set Printer = prt
        Exit For
    End If
Next

 このように,Visual BasicではSetキーワードを使ってPrinterオブジェクトに新しいプリンタを設定することで,デフォルトプリンタが切り替わる構造になっている。


One Point!SetキーワードでPrinterオブジェクトに別のプリンタを設定しても,Windowsの[通常使うプリンタ]の設定は変更されない。設定はアプリケーションが実行されているあいだだけ有効である。

 以上でプリンタが切り替わったので,次は用紙の設定となる。ユーザーが選択した用紙の設定は,先に説明したようにvDevMode変数にコピーしてある。よって,この情報を読み取り,Printerオブジェクトの各種プロパティに設定すれば,用紙が切り替わるという寸法である。具体的な処理はList 7-57のようになる。

 List 7-57は,ちょうどList 7-54で示したデフォルトプリンタの状態をDEVMODE構造体に格納するのと逆の処理にあたる。この処理を実行することによって,デフォルトプリンタの用紙設定などが変更されることになる。なお,On Error Resume Nextステートメントを使って実行時エラーをトラップしているのは,プリンタの機種によっては,サポートしていないプロパティがあるためである。また,DEVMODE構造体は1/10ミリメートルを単位とするので,Printer.WidthプロパティとPrinter.Heightプロパティを設定するときには,10行目と11行目にあるように,ScaleXメソッドやScaleYメソッドを使って単位変換する必要がある。


One Point!List 7-57では,vDevMode変数のすべてのメンバに有効な値が格納されていることを想定しているが,場合によっては有効な値が格納されないこともある。より安全性を期すためには,vDevMode変数のdmFieldsメンバを調べ,値が設定されているものだけをPrinterオブジェクトのプロパティに設定したほうがよい(Table 7-19を参照)。
Prev 63/134 Next