プリンタの設定を初期値に戻すには?(その2)

[戻る]
確変 2011/08/22(月) 19:02:02
2010.01 にスピードスケートさんが「プリンタの設定を初期値に戻すには?」という質
問をされています。
こちらです。
http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+201001/10010003.txt

ここでは、ITO様のご回答を基に、スピードスケートさんが、次のコードを

DEVMODE *pDevMode = (DEVMODE*)(GlobalLock(m_lpPrintDlg.hDevMode));
pDC->ResetDC(pDevMode);
GlobalUnlock(m_lpPrintDlg.hDevMode);
GlobalFree(m_lpPrintDlg.hDevMode);

OnBeginPrinting()のところに書いて解決されたとなっています。

自分もこれと全く同じ目的なので、この通りにしたところ、複数部数印刷が行われませ
ん。(1部印刷して印刷が終わります。)
このコードは、OnBeginPrinting()のところに書いてはいけないような気がしますが、ど
うしたらいいか判りません。

どなたか、ご指導をよろしくお願いいたします。

maru 2011/08/23(火) 09:54:04
いまいち状況がよくわかっていないのですが、プリンタの設定を初期値にしたら、印刷
部数も1に戻ってしまうのではないでしょうか?

ITO 2011/08/23(火) 11:15:36
まず、
OS,VCのバージョンが分からないと先に進めません。

VC2008以降は印刷機能もかなり変わっているので調べないと分かりません。

確変 2011/08/23(火) 14:35:17
申し訳ありません。

OSは Windows 7 です。
VC2010 MFC SDI で作っております。

状況は次の通りです。

・メニューに「プリンタ側用紙サイズ自動変更」というのを設ける。
 これで m_bPrinterPaperSize を FALSE/TRUE に切り替える。

・OnInitialUpdate()に、次のコードを書く。

memset(&m_lpPrintDlg, 0, sizeof(m_lpPrintDlg));
m_lpPrintDlg.lStructSize = sizeof(m_lpPrintDlg);
m_lpPrintDlg.Flags = PD_RETURNDEFAULT;
::PrintDlg(&m_lpPrintDlg);

・OnPreparePrinting(CPrintInfo* pInfo)に、次のコードを書く。

PRINTDLG pd;
pd.lStructSize = (DWORD)sizeof(PRINTDLG);
BOOL bRet = AfxGetApp()->GetPrinterDeviceDefaults(&pd);
if (bRet) {
    LPDEVMODE lp = (LPDEVMODE)GlobalLock(pd.hDevMode);
    if (m_bPrinterPaperSize == TRUE) {
        lp->dmPaperSize = DMPAPER_USER;
        lp->dmPaperWidth = 1000; // 例
        lp->dmPaperLength = 1480; // 例
    }
    GlobalUnlock(pd.hDevMode);
}
return DoPreparePrinting(pInfo);

・OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)に、次のコードを書く。

if (m_bPrinterPaperSize == FALSE) {
    DEVMODE *pDevMode = (DEVMODE*)(GlobalLock(m_lpPrintDlg.hDevMode));
    pDC->ResetDC(pDevMode);
    GlobalUnlock(m_lpPrintDlg.hDevMode);
    GlobalFree(m_lpPrintDlg.hDevMode);
}

これで、プリンタ側用紙サイズは、デフォルトと指定値に切り替わるのですが、FALSEの
とき複数部数印刷が出来なくなります。

ITO 2011/08/23(火) 14:53:54
VC2005以前と違いますね。

以前の設定ですね。
OnPreparePrinting()内で

pInfo->m_bDirect = TRUE;
pInfo->SetMaxPage(pPage);

確変 2011/08/23(火) 15:34:01
ITO様、有り難うございます。
このコードを入れてやってみました。
pPage がよく解らないので、数字の 2 を入れました。2部印刷されます。
しかし、やはり、m_bDirect ではなく、その都度印刷ダイアログを出して、部数を指定
して印刷したいです。
よろしくお願いいたします。

ITO 2011/08/23(火) 16:41:03
 制御系のソフトが多かったので、印刷ダイアログは出さないで印刷していましたが、
印刷ダイアログを出す場合、自動的に枚数がセットされるはずです。

>・OnPreparePrinting(CPrintInfo* pInfo)に、次のコードを書く。

ここに追加したコードをコメントにしてみたらどうなりますか?

ITO 2011/08/23(火) 17:20:17
> ここに追加したコードをコメントにしてみたらどうなりますか?
訂正します。
> BOOL bRet = AfxGetApp()->GetPrinterDeviceDefaults(&pd);
これは印刷ダイアログを出す前に実行しないといけないのでは?


>PRINTDLG pd;
これは、OnInitialUpdate()の初めに実行する。
pdはメンバー変数、もしくはグローバル変数で設定しておく。
っていうよりせっかく
>::PrintDlg(&m_lpPrintDlg);
ここでPRINTDLGを設定しているのだからそのまま使えばいいのでは?

ITO 2011/08/23(火) 17:43:18
連投です。
>::PrintDlg(&m_lpPrintDlg);
bRet = ::PrintDlg(&m_lpPrintDlg);
にする

>PRINTDLG pd;
これは、コメント

>BOOL bRet = AfxGetApp()->GetPrinterDeviceDefaults(&pd);
これは、
 if(bRet == false) 
     bRet = AfxGetApp()->GetPrinterDeviceDefaults(&m_lpPrintDlg);
にかえる。
>    LPDEVMODE lp = (LPDEVMODE)GlobalLock(pd.hDevMode);
ここも
      LPDEVMODE lp = (LPDEVMODE)GlobalLock(m_lpPrintDlg.hDevMode);
こうですね。


>if (bRet) {
>    LPDEVMODE lp = (LPDEVMODE)GlobalLock(pd.hDevMode);
>    if (m_bPrinterPaperSize == TRUE) {
>        lp->dmPaperSize = DMPAPER_USER;
>        lp->dmPaperWidth = 1000; // 例
>        lp->dmPaperLength = 1480; // 例
>    }
>    GlobalUnlock(pd.hDevMode);

ここは、OnBeginPrintingですればいいのでは、
>        lp->dmPaperWidth = 1000; // 例
>        lp->dmPaperLength = 1480; // 例
この設定が消えてしまいます。

> GlobalFree(m_lpPrintDlg.hDevMode);
これを忘れずに実行。


実際にダイアログを起動して動かしたことがないですが、検討してみてください。

ITO 2011/08/23(火) 17:58:46
連投すみません、

>    LPDEVMODE lp = (LPDEVMODE)GlobalLock(pd.hDevMode);
ここも、
 LPDEVMODE lp = (LPDEVMODE)GlobalLock(m_lpPrintDlg.hDevMode);
です。

確変 2011/08/24(水) 08:58:26
1.
次の事項は理解できますので、そのように変更しました。

・PRINTDLG pd;はやめて、OnInitialUpdate で設定した m_lpPrintDlg を使う。
・そのため、OnInitialUpdate の中では
bRet = ::PrintDlg(&m_lpPrintDlg);
とし(bRet はメンバー変数)、
OnPreparePrinting で、
if(bRet == false) bRet = AfxGetApp()->GetPrinterDeviceDefaults(&m_lpPrintDlg);
とする。

2.
if (bRet) {
    LPDEVMODE lp = (LPDEVMODE)GlobalLock(m_lpPrintDlg.hDevMode);
    if (m_bPrinterPaperSize == TRUE) {
        lp->dmPaperSize = DMPAPER_USER;
        lp->dmPaperWidth = 1000; // 例
        lp->dmPaperLength = 1480; // 例
    }
    GlobalUnlock(m_lpPrintDlg.hDevMode);
    GlobalFree(m_lpPrintDlg.hDevMode); ←これを追加
}
ですが、
この追加の1行があると、印刷を行った後アプリケーションを終了したときに
Debug Assertion Failed
File: f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\winutil.cpp
Line: 183
となります。
OnPreparePrinting、OnBeginPrinting のどちらに書いた場合も同じです。
この1行がなくても、メモリーリークの警告は出ません。

3.
元々の質問の目的は、メニューで m_bPrinterPaperSize を TRUE から FALSE に切り替
えたとき、プリンターのデフォルト設定に戻したいのです。
ResetDC で戻りはしますが、複数部数の印刷が行われなくなります。
OnInitialUpdate で格納した m_lpPrintDlg から、デフォルトの用紙サイズを取得でき
ればいいと思うのですが、どんなコードを書けばいいかが解りません。

よろしくお願いいたします。

ITO 2011/08/24(水) 10:54:19
> この追加の1行があると、印刷を行った後アプリケーションを終了したときに
> Debug Assertion Failed
VCのバージョンの違いがあるかもしれません。
削除して下さい。

枚数だけ取れればいいのですか?
OnPreparePrintingで
 UINT pPage = pInfo->GetMaxPage();
で取れないですか?
ダイアログが立ち上がっていれば、取れるはずです。


> 元々の質問の目的は、メニューで m_bPrinterPaperSize を TRUE から FALSE 
> に切り替えたとき、プリンターのデフォルト設定に戻したいのです。
> ResetDC で戻りはしますが、複数部数の印刷が行われなくなります。
GetPrinterDeviceDefaultsがデフォルトの設定です。

if(bRet == false) bRet = AfxGetApp()->GetPrinterDeviceDefaults(&m_lpPrintDlg);
で m_bPrinterPaperSize == trueをORにすればいいのでは?

確変 2011/08/24(水) 21:15:17
話がややこしくなってしまって済みません。

> 枚数だけ取れればいいのですか?
違います。印刷部数のことは一旦忘れてください。

if (m_bPrinterPaperSize == TRUE) {
    lp->dmPaperWidth = 1000; // 例
    lp->dmPaperLength = 1480; // 例
}
else {
    lp->dmPaperWidth = プリンタのデフォルトの値;
    lp->dmPaperLength = プリンタのデフォルトの値;
}
としたいのです。
そのため、プリンタのデフォルトの寸法(幅と長さ)を、アプリケーション起動時に
(すなわち OnInitialUpdate の中で)取得したいのですが、その方法が解らないので
す。
よろしくお願いいたします。

ITO 2011/08/25(木) 15:52:34
----- OnInitialUpdate() -----

PRINTDLG pd;
pd.lStructSize = (DWORD)sizeof(PRINTDLG);
BOOL bRet = AfxGetApp()->GetPrinterDeviceDefaults(&pd);
if (bRet) {
    LPDEVMODE lp = (LPDEVMODE)GlobalLock(pd.hDevMode);
   PR_Width  = lp->dmPaperWidth; // 保存用
    PR_Length = lp->dmPaperLength; // 保存用
    }
    GlobalUnlock(pd.hDevMode);
}
 pdとlpはOnInitialUpdate()でのみ使います。

で
  lp->dmPaperWidth = プリンタのデフォルトの値;
    lp->dmPaperLength = プリンタのデフォルトの値;
が取得できませんか?

確変 2011/08/25(木) 18:54:50
[[解決]]
出来ました!
完璧に解決しました。
ITO様、ありがとうございました。

解ってしまえば簡単なことでしたが、質問の仕方がまずくて遠回りをしてしましまし
た。反省、反省。

これからもご指導よろしくお願いいたします。

古いスレッドには追加発言できません。