読者です 読者をやめる 読者になる 読者になる

プリントダイアログを出さずに印刷する話

MFCな話。

印刷する時はプリントダイアログを使ってDEVMODE構造体を作り、それを用いてdcを更新してごにょごにょする。

CPrintDialog dlg(FALSE);
if ( dlg.DoModal() == IDCANCEL ) {
    return FALSE;
}
DEVMODE* mode = (DEVMODE*)::GlobalLock(dlg.m_pd.hDevMode);
// ...

ダイアログを出さずに印刷する場合は、デフォルトのDEVMODE構造体を作っておき、それに色々な設定をする。

CPrintDialog dlg(FALSE);
dlg.GetDefaults();
DEVMODE* mode = (DEVMODE*)::GlobalLock(dlg.m_pd.hDevMode);
mode->dmOrientation = DMORIENT_LANDSCAPE;
// ...

// DEVMODEで設定出来る内容:DEVMODE structure (Windows)

なのだが、プリンタ固有の機能、例えばフチなし印刷だとか写真モードだとかはドライバ依存で、そう言う機能へのアクセス方法がよくわからない。

いろいろ調べると、そう言ったデータはDEVMODEに続くメモリ領域に保存されているらしい。それをデータとして取り出してどうにか保持すれば、初回(データを作る際)はともかくそれ以降は、ダイアログを出さずそのデータを流用出来るのではないか。と考えてやってみたら成功した。

DEVMODEに続く領域、というのがどれくらいかは、その大きさがDEVMODE構造体内にdmDriverExtraとして保持されている。従って、DEVMODEの先頭を指し示すポインタを起点に、DEVMODE構造体のサイズ+dmDriverExtra分読めば良い。

とりあえずファイルに書き出してみる。

CPrintDialog dlg(FALSE);
if (dlg.DoModal() == IDCANCEL) {
    return FALSE;
}
CFile file( PATH_TO_SAVED_DEVMODE, CFile::modeWrite | CFile::shareDenyWrite | CFile::modeCreate);
DEVMODE* mode = (DEVMODE*)::GlobalLock(dlg.m_pd.hDevMode);
file.Write( mode, sizeof( DEVMODE ) + mode->dmDriverExtra );
file.Close();
// ...

再利用時、ファイルから読み出してDEVMODEを作れば、ダイアログを出す必要が無い。

CFile file(PATH_TO_SAVED_DEVMODE, CFile::modeRead | CFile::shareDenyWrite );
DEVMODE tmp;
file.Read( &tmp, sizeof( DEVMODE ) );
file.Seek( 0, CFile::begin );
DEVMODE* mode = (DEVMODE*)malloc( sizeof( DEVMODE ) + tmp.dmDriverExtra );
file.Read( mode, sizeof( DEVMODE ) + tmp.dmDriverExtra );
file.Close();
// ...
free( mode );
// ...

dmDriverExtraを取得するために、一時的なDEVMODEを作っている。その後先頭にシークし直し、全体が入る領域を確保してから読み出している。