- 締切済み
【VB6】印刷ダイアログの表示を繰り返すと異常終了
開発言語:VB6 お世話になります。 DEVMODE構造体とDEVNAME構造体に、プリンタや用紙サイズ、印刷の向きなどを指定し、Win32APIのPrintDialogで印刷ダイアログを表示しています。 この処理を何回か呼び出すと、プログラムが異常終了します。 異常終了する場所は、PrintDialogを呼び出した直後だと思われます。 いろいろ調べたのですが、原因がわかりません。 長くなりますが、ソースコードの一部を添付させて頂きます。 ご覧頂き、おかしい点などございましたらご指摘いただけるとありがたいです。 よろしくお願いします。 以下ソースコード ----------------------------------------------------------------------------------- PrintDlg.lStructSize = Len(PrintDlg) PrintDlg.hwndOwner = phwnd PrintDlg.flags = plngPrintFlags strDeviceName = Printer.DeviceName strDriverName = Printer.DriverName sngPaperBin = Printer.PaperBin strPortNo = Printer.Port If mstrDriverName <> "" And _ mstrDeviceName <> "" And _ mstrPortNo <> "" Or _ msngDefaultSource <> 0 Then For Each objPrinter In Printers If objPrinter.DeviceName = mstrDeviceName Then strDeviceName = mstrDeviceName strDriverName = mstrDriverName sngPaperBin = msngDefaultSource strPortNo = mstrPortNo Exit For End If Next End If udtPrinterDefaults.DesiredAccess = PRINTER_ACCESS_USE If OpenPrinter(Trim(strDeviceName), hPrinter, udtPrinterDefaults) <> 0 Then bufSize = DocumentProperties(NULLPTR, hPrinter, Trim(strDeviceName), NULLPTR, NULLPTR, 0) If bufSize < 1 Then MsgBox "プリンタ情報の取得に失敗しました。", vbCritical GoTo Exit_Proc Else ReDim aDevMode(bufSize - 1) Call DocumentProperties(NULLPTR, hPrinter, Trim(strDeviceName), aDevMode(0), NULLPTR, DM_OUT_BUFFER) Call CopyMemory(DevMode, aDevMode(0), Len(DevMode)) End If Call ClosePrinter(hPrinter) Else MsgBox Err.LastDllError MsgBox "プリンタの取得に失敗しました。", vbCritical GoTo Exit_Proc End If DevMode.dmPaperSize = mintPaperSize DevMode.dmOrientation = mintPaperOrnt DevMode.dmDefaultSource = sngPaperBin PrintDlg.hDevMode = GlobalAlloc(GMEM_MOVEABLE Or GMEM_ZEROINIT, Len(DevMode)) lpDevMode = GlobalLock(PrintDlg.hDevMode) If lpDevMode > 0 Then CopyMemory ByVal lpDevMode, DevMode, Len(DevMode) bReturn = GlobalUnlock(lpDevMode) End If With DevName .wDriverOffset = 8 .wDeviceOffset = .wDriverOffset + 1 + Len(strDriverName) .wOutputOffset = .wDeviceOffset + 1 + Len(strDeviceName) .wDefault = 0 .extra = strDriverName & Chr(0) & strDeviceName & Chr(0) & strPortNo & Chr(0) End With PrintDlg.hDevNames = GlobalAlloc(GMEM_MOVEABLE Or _ GMEM_ZEROINIT, Len(DevName)) lpDevName = GlobalLock(PrintDlg.hDevNames) If lpDevName > 0 Then CopyMemory ByVal lpDevName, DevName, Len(DevName) bReturn = GlobalUnlock(lpDevName) End If If PrintDialog(PrintDlg) Then mhDC = PrintDlg.hdc lpDevName = GlobalLock(PrintDlg.hDevNames) CopyMemory DevName, ByVal lpDevName, Len(DevName) bReturn = GlobalUnlock(lpDevName) GlobalFree PrintDlg.hDevNames lpDevMode = GlobalLock(PrintDlg.hDevMode) CopyMemory DevMode, ByVal lpDevMode, Len(DevMode) bReturn = GlobalUnlock(PrintDlg.hDevMode) GlobalFree PrintDlg.hDevMode mstrDriverName = Mid(DevName.extra, DevName.wDriverOffset - 8 + 1) mstrDriverName = Left(mstrDriverName, InStr(mstrDriverName, Chr(0)) - 1) mstrDeviceName = Mid(DevName.extra, DevName.wDeviceOffset - 8 + 1) mstrDeviceName = Left(mstrDeviceName, InStr(mstrDeviceName, Chr(0)) - 1) mstrPortNo = Mid(DevName.extra, DevName.wOutputOffset - 8 + 1) mstrPortNo = Left(mstrPortNo, InStr(mstrPortNo, Chr(0)) - 1) msngDefaultSource = DevMode.dmDefaultSource mintPaperOrnt = DevMode.dmOrientation mintPaperSize = DevMode.dmPaperSize gfShowPrinter = True End If
- みんなの回答 (3)
- 専門家の回答
みんなの回答
- MAXIMAX
- ベストアンサー率60% (50/83)
#2 です。なかなか解決できずに困っていらっしゃるようですね・・・・・・。 前者の方法も後者と効果は変わらないようにおもいますが、以下のような感じですね。 (DevMode の設定値変更後のコメントが付いている 3 行が追加変更です) ----- DevMode.dmPaperSize = mintPaperSize DevMode.dmOrientation = mintPaperOrnt DevMode.dmDefaultSource = sngPaperBin CopyMemory aDevMode(0), DevMode, Len(DevMode) ' 追加、DevMode を aDevMode に書き戻す PrintDlg.hDevMode = GlobalAlloc(GMEM_MOVEABLE Or GMEM_ZEROINIT, bufSize) ' バッファサイズを bufSize に lpDevMode = GlobalLock(PrintDlg.hDevMode) If lpDevMode > 0 Then CopyMemory ByVal lpDevMode, aDevMode(0), bufSize 'コピー元を aDevMode に、サイズを bufSize に bReturn = GlobalUnlock(lpDevMode) ----- aDevMode のサイズが DevMode と同じであれば意味はありません。ダイアログ表示後に取り出すデータは必要なとこだけ取り出せればいいので、DevMode に取り出すことで問題ないと思います。 解決できるといいですね・・・・・・・。
- MAXIMAX
- ベストアンサー率60% (50/83)
DEVMODE の扱いがちょっと気になりました。一応調べてみたほうがいいかも・・・・・・レベルなのですが、書きます。 DEVMODE というのはデバイスによってサイズが違うことになっているため、単一の DEVMODE 構造体で全体を表現することはできないことになっています。 DevMode 変数の構造がわからないのですが、おそらくどのデバイスでも共通部分の構造体のみが定義されているのではないかと推測しますが、デバイスが返す DEVMODE は、そのデバイス固有の Private エリアがあり、そのためサイズが一定しないことになっています(ソースで使われている DevMode という変数のサイズと、サイズを取得して ReDim した aDevMode のサイズが違うことがあると考えます)。 このため、aDevMode から DevMode だけ引き出し、内容を設定して hDevMode に DevMode のサイズ分だけ設定しているため、プライベートエリアの情報が欠落(というか範囲外のメモリなので不定値になってしまっている)と考えられます。 対処法は2つ考えられます。ひとつは DevMode を設定した後、DevMode をもう一度 aDevMode に書き戻し、hDevMode には aDevMode 分のサイズのメモリを確保・設定します。 もう一つはDevMode 構造体の最後に、必要以上の空の配列でも用意していおいて(要は余裕で aDevMode が入るであろうサイズ)、aDevMode をそっくり DevMode にコピーしてから DevMode を設定し、hDevMode に DevMode のサイズを確保・設定します(aDevMode 分のサイズでもいいはずですが、大きい分には構わないはず)。 という感じでは・・・・・・・、とちょっと推測します。おそらく、範囲外になっているプライベートエリアの部分が、最初は 0 フィルされていたのが実行中にダーティデータ化して誤動作しているのでは、と推測しています。 ちょっと長くてごめんなさい。一度確認してみてはいかがでしょうか??
- piroin654
- ベストアンサー率75% (692/917)
>PrintDlg.hDevMode = GlobalAlloc(GMEM_MOVEABLE Or GMEM_ZEROINIT, Len(DevMode)) >lpDevMode = GlobalLock(PrintDlg.hDevMode) これらのハンドルは解放されていますか。 思いつくのはこれぐらいですが。
お礼
回答を頂きありがとうございました。(お礼が遅くなり申し訳ありません) 最後に、以下の2行を追加してみましたが、ダメでした。 GlobalFree PrintDlg.hDevNames GlobalFree PrintDlg.hDevMode その後、いろいろ試しているのですが、未だ解決には至っておりません。 もし、また何かありましたらお願いします。
お礼
回答を頂きありがとうございました。(お礼が遅くなり申し訳ありません) > もう一つはDevMode 構造体の最後に、必要以上の空の配列でも用意していおいて(要は余裕で > aDevMode が入るであろうサイズ)、aDevMode をそっくり DevMode にコピーしてから DevMode > を設定し、hDevMode に DevMode のサイズを確保・設定します(aDevMode 分のサイズでもいいは > ずですが、大きい分には構わないはず)。 こちらを試してみました。 具体的には、DevMode 構造体の最後に、以下の1行を追加しました。 dmFiller(2048) As Byte が、うまくいきませんでした。 その後、いろいろ試しているのですが、未だ解決には至っておりません。 もし、また何かありましたらお願いします。
補足
引き続きご回答を頂けるとありがたいです。 >対処法は2つ考えられます。ひとつは DevMode を設定した後、DevMode をもう一度 aDevMode に書き戻し >hDevMode には aDevMode 分のサイズのメモリを確保・設定します。 ひとつめの方法、具体的にどのようなコーディングになりますでしょうか? お手数をおかけして申し訳ありませんが、ご教示いただけるとありがたいです。 よろしくお願いします。