印刷

Copyright © 2004 by Hirofumi Fujii
(LastUpdate:13-Jul-2004)

基本的な流れ

Windows における印刷は、基本的には画面に対する Graphics の描画と 同じである。Printer device context に対し、描画を行えばよい。違いは、 Job としてスプールさせることと、紙送りがあることである。

基本的な流れは、

  1. printer device context に対し、StartDoc()関数を呼び出す。
  2. StartPage() を呼び出す。
  3. 描画する。
  4. EndPage() を呼び出す。
  5. EndDoc() を呼び出す。
となる。印刷するページが複数ある時は、上記 2-4 を繰り返す。

Printer の指定

Printer を指定するには、通常 windows common dialog 関数の一つである PrintDlg() を使う。この時引数として渡す PRINTDLG構造体 の Flags メンバーに PD_RETURNDC を設定しておくと、ユーザが printer を 指定した時、対応する device context を生成して戻ってくるので便利である。 また、PD_RETURNDEFAULT も一緒に指定すると、dialog box を表示せずに 「通常使うプリンタ」の device context が得られるので、常に 「通常使うプリンタ」へ出力するプログラムにすることも容易にできる。


Job のキャンセル

印刷 Job は一般に時間がかかるので、途中でキャンセルする仕掛けが必要である。 これは、SetAbortProc() 関数に Callback 関数を渡すことで実現する。 SetAbortProc() 関数に引数として渡されるCallback 関数は、 BOOL 値を戻し、TRUE を戻せば続行、FALSE を 戻せば中止(キャンセル)となる。ドキュメントによれば印刷中は、約 2 秒に一回、 この関数が呼び出されるらしい。


例題プログラム

次の例は、指定された printer で、左上隅が(100,200)、右下隅が(300,500)の 長方形を印刷するプログラムである。なお、ここでは AbortProc() は常にTRUEを返している (つまり、この関数を削除して、かつ SetAbortProc() の行を削除してもよい)。 このソースコードを例えば prsample.c というファイルに書き出してコンパイル・リンクするには、

cl /W3 prsample.c comdlg32.lib gdi32.lib
とする。
/* prsample.c
**
** Sample program for print job.
**
** To compile and link,
**   cl /W3 prsample.c comdlg32.lib gdi32.lib
*/

#include <windows.h>
#include <tchar.h>
#include <commdlg.h>


BOOL CALLBACK AbortProc(HDC hdc, int iError)
{
  return TRUE;
}

void main()
{
  PRINTDLG pd;
  DOCINFO di;

  pd.lStructSize = sizeof(PRINTDLG);
  pd.hDevMode = (HANDLE)NULL;
  pd.hDevNames = (HANDLE)NULL;
  pd.Flags = PD_RETURNDC;
  pd.hwndOwner = (HWND)NULL;
  pd.hDC = (HDC)NULL;
  pd.nFromPage = 1;
  pd.nToPage = 1;
  pd.nMinPage = 0;
  pd.nMaxPage = 0;
  pd.nCopies = 1;
  pd.hInstance = (HANDLE)NULL;
  pd.lCustData = 0;
  pd.lpfnPrintHook = (LPPRINTHOOKPROC)NULL;
  pd.lpfnSetupHook = (LPSETUPHOOKPROC)NULL;
  pd.lpPrintTemplateName = (LPCTSTR)NULL;
  pd.lpSetupTemplateName = (LPCTSTR)NULL;
  pd.hPrintTemplate = (HANDLE)NULL;
  pd.hSetupTemplate = (HANDLE)NULL;

  if(!PrintDlg(&pd))
  {
    return;
  }

  SetAbortProc(pd.hDC, AbortProc);
  
  di.cbSize = sizeof(DOCINFO);
  di.lpszDocName = _T("Print Sample");
  di.lpszOutput = (LPCTSTR)NULL;
  di.lpszDatatype = (LPCTSTR)NULL;
  di.fwType = 0;

  if(StartDoc(pd.hDC, &di) <= 0)
  {
    DeleteDC(pd.hDC);
    return;
  }

  if(StartPage(pd.hDC) <= 0)
  {
    EndDoc(pd.hDC);
    DeleteDC(pd.hDC);
    return;
  }

  Rectangle(pd.hDC, 100, 200, 300, 500);

  EndPage(pd.hDC);
  EndDoc(pd.hDC);
  DeleteDC(pd.hDC);
}