PrintDialogで選択したプリンターで印刷するには?

解決


ちびクマ  2004-08-03 06:30:28  No: 84900  IP: [192.*.*.*]

プリンタダイアログを表示し、デフォルトプリンタ以外のプリンターを選択して印刷したいのですが、どのようにしたらユーザーが選択したプリンタ名を取得できるのでしょうか?
任意のプリンターを選択して印刷することは出来ているのですが、
肝心のユーザーが指定したプリンタ名が手に入らないのです。
MFCにある、CPrinterDlg::GetDeviceName()のようなものはないのでしょうか???
散々探してみたのですが、見つかりませんでした。
(皆さん、質問しなくても簡単に分かるってことかしら…? ^_^;)

開発環境は、VB6.0です。
よろしくお願いします。

編集    削除
魔界の仮面弁士  2004-08-03 07:26:04  No: 84901  IP: [192.*.*.*]

PrintDialog というので、VB.NET かと思ってしまいました。(^_^;)
(.NET には、System.Windows.Forms.PrintDialog というクラスがあります)

> どのようにしたらユーザーが選択したプリンタ名を取得できるのでしょうか?
コモンダイアログ コントロールの『PrinterDefault プロパティ』を
True に設定しておいてみてください。

これを設定しておけば、ユーザーの選択に合わせて、システム既定のプリンタの設定が
変更されますので、あとは、Printer オブジェクトを使って処理できます。
デバイス名なら、Printer.DeviceName ですね。


> MFCにある、CPrinterDlg::GetDeviceName()のようなものはないのでしょうか???
コモンダイアログコントロールではなく、PageSetupDlg APIを使って
設定画面を呼び出すようにすれば、同等の機能を作成できます。

PAGESETUPDLG構造体のhDevModeメンバからDEVMODE構造体を得た後、
DEVMODE構造体のdmDeviceNameメンバを参照する…という流れになります。

編集    削除
ちびクマ  2004-08-03 22:20:21  No: 84902  IP: [192.*.*.*]

魔界の仮面弁士さん、ご回答ありがとうございます。

>PrintDialog というので、VB.NET かと思ってしまいました。(^_^;)
>(.NET には、System.Windows.Forms.PrintDialog というクラスがあります)

あっ、そうなんですか…。(゜ロ゜ノ)ノ゛ ←無知
コモンダイアログの…と書くべきでしたね。
失礼いたしました。

> どのようにしたらユーザーが選択したプリンタ名を取得できるのでしょうか?
コモンダイアログ コントロールの『PrinterDefault プロパティ』を
True に設定しておいてみてください。

これを設定すると、設定したプリンターがデフォルトプリンターになってしまうので、Falseにしてました。
確かに、ここをTrueにすると、Printerオブジェクトで印刷できますね。

ちょっと記憶があいまいなのですが、以前のこの手の画面って、
プリンタの選択をするたけでデフォルトプリンタの設定まで変更しなかったと思うのですが、XPではこれが標準なのでしょうか?
別のアプリケーションではどうなのかな、と思って、
メモ帳の印刷ダイアログをみてみたら、
こちらはプリンタの選択をしても、デフォルトの設定は
変更されませんでした。
そして「適用」のボタンが更に追加されています。
印刷ダイアログで、デフォルトプリンタの設定は変更せずに、プリンタの選択だけ行いたいのですが、可能でしょうか?
メモ帳はコモンダイアログを使わずに独自に実装しているのでしょうか??
または…変更はされているんだけど、
強制的にもとのプリンタがデフォルトプリンタになるように
設定を戻しているとか…??

ちなみに、PrinterDefaultプロパティをまったく設定しないと、
プリンタを選択して印刷後、もう一度印刷ダイアログを呼び出して
別のプリンタを選択して印刷しても、最初に選択されたプリンタで
印刷が出てしまうという症状がでます。
これも、PrinterDefaultプロパティをTrueにすることで回避されます。


>コモンダイアログコントロールではなく、PageSetupDlg APIを使って
>設定画面を呼び出すようにすれば、同等の機能を作成できます。

うーん…これ見た目がまったく違うのでちょっと駄目そうです。
既に画面レイアウトだけ仕様がFIXしちゃってまして…とほほ。


大変申し訳ありませんが、引き続き何かご存知でしたら
ご教授いただければ幸いです。
ありがとうございました。

編集    削除
魔界の仮面弁士  2004-08-03 23:04:22  No: 84903  IP: [192.*.*.*]

> プリンタの選択をするたけでデフォルトプリンタの設定まで
> 変更しなかったと思うのですが、XPではこれが標準なのでしょうか?

VBでは、PrinterDefaultプロパティにて「規定のプリンタも変更させる」と
いう事が可能になっていますが、アプリケーションの動作としては、
あまり行儀の良い事ではありませんね。(^^;)
殆どのアプリは、規定のプリンタの設定は変更しないでしょう。


> 印刷ダイアログで、デフォルトプリンタの設定は変更せずに、
> プリンタの選択だけ行いたいのですが、可能でしょうか?
PrinterDefault = False の状態でも、プリンタの設定はできますが、
その場合、Printerオブジェクトは変更されませんから、コントロールの
hDC プロパティに渡されるハンドルに対して、RichTextBox.SelPrint 等で
印刷を行う事になります。

もし、設定項目が「プリンタの選択」だけで、用紙の設定等は行わないなら、
Printersコレクションを列挙してDeviceName の一覧を読み取り、
それを選択させるような画面を自作すれば良いのですが…今回は
そういうわけにもいかないようですね。

> うーん…これ見た目がまったく違うのでちょっと駄目そうです。
とすると、PrintDlg APIですかね。
# Windows 2000以降では、hwndOwner を指定するかどうかで、
# 見た目が大きく変化します。

編集    削除
ちびクマ  2004-08-04 03:34:21  No: 84904  IP: [192.*.*.*]

魔界の仮面弁士さん、再RESありがとうございます。

>殆どのアプリは、規定のプリンタの設定は変更しないでしょう。

そ、そうですよね。やはり。
Windowsの付属アプリ「メモ帳」でさえそんなことしないのですから…。

>hDC プロパティに渡されるハンドルに対して、RichTextBox.SelPrint 等で
>印刷を行う事になります。

Printerオブジェクトに対する描画周りは既にコーディング済みなので、
できれば変えたくなくて…(わがままでスイマセン…^^;)
工数オーバーなんで…

>とすると、PrintDlg APIですかね。
># Windows 2000以降では、hwndOwner を指定するかどうかで、
># 見た目が大きく変化します。

あっ、そうなんですか…。
先ほどはとりあえず見た目だけ確認しようと思い、
google(Image)でPrintDlgをググって出てきたイメージで
見た目を確認しただけだったので、
「あー、見た目が違う…」と思って諦めてしまいました。
hwndOwnerを指定してやればコモンダイアログと
同じ見た目になるんですね!!(嬉)

PrintDlg APIのサンプルを探してみたところ、
こちらのサイト様にありまして、
http://210.233.22.220/VBlabo/commonDLG/J042959.htm
見た目がOKなのは確認しました。
で、このコード中のNewPrinterNameに
プリンタ名が取り出せているのですが…。
更に一つ問題が。DEVMODEの制限で32文字までしか帰ってこないのです。
上記のサイトに、

>DEVMODE 構造体の仕様により 32 文字を越えるプリンタ名は
>取得できません。
>この場合 EnumPrinters API 関数を利用してプリンタ情報を
>取得することが可能です。

とあるのですが、これはどうやればいいのでしょうか?
また、どういう意味でしょうか…
EnumPrintersってプリンタを列挙するAPIですよね???
さっぱり意図が…。

32文字以下のものに関しては取り出した後、
こちらのサイト様のサンプルを参考にさせていただいて作ったコードで
無事プリンターを指定することが出来ました。
http://www.bcap.co.jp/hanafusa/VBHLP/print03.htm
(でも、XPではプリンタ名の頭に「自動」とか付いていたりするのですが、
こういうのも付いたままで指定できるかどうかはまだ疑問です。)

引き続きご指導いただけないでしょうか?
よろしくお願い申し上げます。

# プリンターを選択するだけの処理に
# こんなに苦労するとはおもわなかったなぁ。(T△T)
# 完全に工数オーバーだ…(泣)

編集    削除
魔界の仮面弁士  2004-08-04 04:21:14  No: 84905  IP: [192.*.*.*]

>> 殆どのアプリは、規定のプリンタの設定は変更しないでしょう。
> そ、そうですよね。やはり。
> Windowsの付属アプリ「メモ帳」でさえそんなことしないのですから…。

逃げの手ですが、

1. プログラム側で、「規定のプリンタ」を覚えておく。
2. PrinterDefault = True で、プリンタを切り替えさせてしまう。
3. Printer.DeviceName を使って、プリンタ名を取得。
4. APIを使って、「規定のプリンタ」の設定を元に戻す。

のような方法も、良く利用されますよ。

編集    削除
ちびクマ  2004-08-04 04:47:43  No: 84906  IP: [192.*.*.*]

魔界の仮面弁士さん、再RESありがとうございます。
たびたびスイマセン。

>逃げの手ですが、
>1. プログラム側で、「規定のプリンタ」を覚えておく。
>2. PrinterDefault = True で、プリンタを切り替えさせてしまう。
>3. Printer.DeviceName を使って、プリンタ名を取得。
>4. APIを使って、「規定のプリンタ」の設定を元に戻す。
>のような方法も、良く利用されますよ。

はは…やっぱりそうですか。
既に実験済みで、これで出来ることも確認済みしてあります。
でも…ちょーっと気持ち悪いですよね…。
これは最後の手段にとっておきます…。(でも採用の可能性大…)

ありがとうございます。(^_^)

編集    削除
ちびクマ  2004-08-04 20:18:01  No: 84907  IP: [192.*.*.*]

ちょっと事情がありまして、

>PrinterDefault = False の状態でも、プリンタの設定はできますが、
>その場合、Printerオブジェクトは変更されませんから、コントロールの
>hDC プロパティに渡されるハンドルに対して、RichTextBox.SelPrint 等で
>印刷を行う事になります。

この場合も模索しております。
このときに得られるhDC を使って、TextOutなどを使って描画できることを確認したのですが、
Printerオブジェクトが使えないと、余白の計算が出来ないという壁にぶつかってしまいました。
私が現在知っている余白の計算方法は、

LeftMargin = Printer.ScaleX(GetDeviceCaps(Printer.hDC, PHYSICALOFFSETX), vbPixels, vbMillimeters)

とやるか、

LeftMargin = Round(GetDeviceCaps(Printer.hDC, PHYSICALOFFSETX) * Printer.TwipsPerPixelX / 56.7, 1)

とやるか、なのですが、
(どちらにしても計算の深い意味はよく理解できていません…^_^;)
Printer.TwipsPerPixelXの値が手に入らなくてこまっております。

PrinterDefault = Falseの状態で、flags = cdlPDReturnDCのときに得られるhDCを使って、Printer.TwipsPerPixelXを得るにはどうしたらよいのでしょうか?

(hDCがPrinterオブジェクトのように使えればいいのに…。)


引き続き、ご指導をよろしくお願い申し上げます!!

編集    削除
ちびクマ  2004-08-04 20:58:10  No: 84908  IP: [192.*.*.*]

自己レス。

こちらに紹介がありました。
http://hp.vector.co.jp/authors/VA015238/progtips.html
Borland C++ Builderスタイルなので、VBスタイルに移植したらなんとか。(^^;)

お騒がせしました。
これでなんとかなりそうな目鼻立ちがつきましたので、
ここで解決としたいと思います。
PrinterDefault = Falseの状態で手に入れたDCに対しての描画なら、
デフォルトプリンタが切り替わってしまうことも無いしこちらの方式で行こうかなぁと思います。
魔界の仮面弁士さん、なんどもご回答いただきまして、
ありがとうございました。

編集    削除