APIを用いてデスクトップのスクリーン画面を取得してみたいと思います。デスクトップ画面の画像は、スクリーンセーバーなどのソフトウェアで使われることがあると思います。画像を保存するツールなどにも使えそうです。画像の取得には画像をコピーするAPI関数で実現することができますが、そのためにはいろいろと前知識が必要になりますので、まずは、それらから説明していきましょう。GDIWindowsは、グラフィックスの描画のためにGDI(グラフィックス・デバイス・インターフェース)というグラフィックス描画機能を提供しています。このGDIは、gdi32.dllによって提供されるさまざまなAPI関数と、描画のための情報を管理しているデバイスコンテキスト(DC)によって構成されています。ウィンドウにAPIを使って文字や絵を描画したり、画像コピーを行ったりするには、それぞれの機能を果たすAPI関数を使うことになります。このとき、GDIの提供するAPI関数を使うためには、引数として操作先のデバイスコンテキストのハンドルが必要になります。デバイスコンテキストとはWindowsが描画のための情報を内部的に管理しているメモリ上のデータベースのことです。これはWindowsの持つオブジェクトの1つで、アプリケーションはハンドルと呼ばれる値によりデバイスコンテキストを識別します。デバイスコンテキストは一般的に“DC”と略記されます。デバイスコンテキストのハンドルを表すデータ型がHDC型と定義されているため、デバイスコンテキストのハンドルのことを“HDC”と略記することがあります。HSPウィンドウのデバイスコンテキストHSP画面の描画の内部動作ここで、HSPの画面への描画がどのように行われているのかを、少し詳しく見ていくことにしましょう。本来、Windowsアプリケーションのウィンドウには、ウィンドウを再描画する必要が生じると(例えば、他のウィンドウに隠れていたウィンドウが前面に現れると)、Windowsから「ウィンドウのこの部分を再描画してほしい」というメッセージ(WM_PAINTメッセージ)が送られます。このとき、アプリケーションはウィンドウを描き直さなくてはいけないのです。そこで、HSPでは、実際にデスクトップ上に表示されているウィンドウとは別に、メモリ上に仮想的な画面(ビットマップ)を用意しておいて、再描画の必要性が生じたら、メモリ上の画面を実際のウィンドウ画面にコピーするという手続きをとっています。HSPでmesやboxfやgcopyなどといった描画関連命令を実行したとき、これらの描画操作はまずメモリ上のビットマップ画面に対して行われ、デフォルトでは、変更部分がただちにウィンドウ画面にコピーされるようになっています。0を実行することにより、描画命令実行時にメモリ画面からウィンドウ画面への自動的なコピーが行われないようにすることもできます。0でウィンドウ画面へのコピーを無効にしている状態でメモリ画面に対してさまざまな描画を行い、すべての描画が終了した時点でredrawを実行してウィンドウ画面にコピーするという手続きをとることができます。この手続きにより、描画時の画面のちらつきを防いだり、描画を高速化させたりすることができるのです。0を実行して描画を行っても実際のウィンドウ画面には反映されませんが、この状態でHSPのウィンドウをいったん他のウィンドウに隠してからもう一度前面に表示させると、隠れていた部分だけは自動的に再描画されますね。これは、WindowsからHSPのウィンドウにWM_PAINTメッセージが送られ、その部分の画像がメモリ画面からウィンドウ画面にコピーされたことを表しています。これまではscreen命令やbgscr命令で作成される画面は「実際に表示されるウィンドウ」で、buffer命令で作成される画面は「メモリ上の仮想画面」であるという印象を持っていたと思います。正確には、screen命令やbgscr命令で作成される画面は「メモリ上の仮想画面」プラス「実際に表示されるウィンドウ」で構成されているということです。実際に表示されているウィンドウにはメモリ上の画面がコピーされるようになっているのです。hdcHSPでGDIの機能を使うからには、HSPの画面に対して操作できなければ意味がありません。そのため、HSPの画面に割り当てられているデバイスコンテキストのハンドルを取得する必要があります。HSPでは、現在描画を行っている画面に割り当てられているデバイスコンテキストのハンドルを、システム変数hdcという形で参照できるようになっています。描画中の画面のデバイスコンテキストが必要な場合は、このシステム変数を使います。ここで、注意しなければならないことがあります。システム変数hdcから取得したデバイスコンテキストは、実際のウィンドウに割り当てられているデバイスコンテキストではなく、メモリ上の仮想画面を管理しているデバイスコンテキストであるということです。そのため、APIを使って描画を行ったとき、実際に表示されているウィンドウに反映させるためにはredraw命令を実行する必要があるのです。0を実行した状態で描画命令を実行することと同じなのです。したがって、その操作を実際に表示されているウィンドウに反映させるためには、redraw命令を実行して強制的に再描画を行わなければいけません。ウィンドウが表示されているときだけ実行すれば十分ですが。今回は、デスクトップスクリーンの画面とHSP画面の間でコピーを行うので、HSP画面のデバイスコンテキストだけでなく、スクリーン画面のデバイスコンテキストのハンドルもまた取得しておく必要があります。スクリーン画面のデバイスコンテキストは、CreateDC関数の第1引数に文字列"DISPLAY"を指定することによって“作成”するという形をとります。CreateDC関数はgdi32.dllによって提供されている関数で、以下のように定義されています。指定することにより、デスクトップのスクリーン画面のデバイスコンテキストを取得することができます。これでデスクトップウィンドウのデバイスコンテキストを取得することができたので、画像のコピーなど、デバイスコンテキストに対する処理を行います。デバイスコンテキスト間での画像のコピーさて、実際にコピーを行ってみましょう。コピーを行うには、gdi32.dllが提供するBitBlt関数を呼び出します。この関数は、指定された長方形領域に対応する色データのビットブロック転送を行うための関数で、次のように定義されています。nYDestは、転送先のデバイスコンテキストのハンドルおよび座標を指定します。nHeightには、それぞれビットブロック転送を行う画像の幅と高さを指定します。nYSourceは、転送先のデバイスコンテキストのハンドルおよび座標を指定します。9番目のdwRasterパラメータは、ラスターオペレーションコード(転送元および転送先の色データをどのように結合するかを定義する値)です。window)』と呼ばれる半透明のウィンドウが画面に表示されている場合、BitBlt関数のラスターオペレーションコードにSRCCOPYフラグを指定するだけでは、そのウィンドウのイメージがコピーされません。組み合わせて指定する必要があります。デバイスコンテキストの破棄CreateDC関数で作成されたデバイスコンテキストは、必要な操作が完了したらすぐにDeleteDC関数で破棄しなければいけません。これを怠ると、システム全体に致命的な影響を及ぼす可能性があります。DeleteDC関数もまたgdi32.dllによって提供されている関数で、以下のように定義されています。DC);hDCパラメータは、破棄するデバイスコンテキストのハンドルを指定します。このハンドルは、CreateDC関数の戻り値として返されたものです。実際にコピーしてみるサンプルスクリプト現在のスクリーン画面の画像をビットマップファイルとして保存するプログラムです。ginfo関数(正確にはginfo_dispxマクロとginfo_dispyマクロ)でデスクトップ画面のサイズを取得し、上記の手順にしたがってHSP画面へのコピーを行っています。レイヤードウィンドウ(半透明ウィンドウ)が存在する場合にも対応できるようにCAPTUREBLTフラグも合わせて指定しています。refstr}end上のスクリプトを実行させてみましょう。デスクトップ画面をビットマップファイルとして保存することができます。BitBlt関数の引数で転送元と転送先とを入れ替えると、HSPウィンドウに描画されている画像をデスクトップ上に直接コピーできてしまいます。0のようにして、全画面表示のウィンドウを表示させることで、画面をいったん消したほうがいいでしょう。