先日、API のリファレンスでCreateDCの解説を読んでいたら面白い記述を見つけました。第一引数に"DISPLAY" を渡すと「ディスプレイのデバイスコンテキスト」のハンドルが得られる、というのです。早速試してみると、このデバイスコンテキストは「Windowsの画面全体」のデバイスコンテキストのようでした。
そう、このデバイスコンテキストを使うと「ウインドウの外」であろうがWindowsの画面どこにでも描画できてしまうのです。
今回は、このデバイスコンテキストを使ってちょっとした「イタズラ」をしてみましょう。
ディスプレイのデバイスコンテキストを得るには、第一引数を"DISPLAY"、それ以外の引数をNULL にしてCreateDCを呼びます。
hdc=CreateDC("DISPLAY",NULL,NULL,NULL);
これで、hdcにデバイスコンテキストのハンドルが帰ってくるので後はGDI関数で描画するわけです。ただ、このhdc にGDIでいちいち描画するのも面倒だし、ピクセルを読み出すのに毎回GDI関数を使うのも非現実的ですね。
ここはデバイスコンテキストをもとにDIBSectionを作り、そのビットマップに画面全体をコピーしてしまいましょう(画面の大きさはGetDeviceCaps で得られます)。そうすれば、ビットマップに対してDIBと同様の参照・描画ができます。
そして、ビットマップをBitBlt などでhdcに描けばビットマップが「画面全体」に出力される(!)わけです。
iWidth=GetDeviceCaps(hdc,HORZRES); /* 画面の大きさ取得 */ iHeight=GetDeviceCaps(hdc,VERTRES); /* DIB と画面のDC からDIBSection を作成 */ hBMP=CreateDIBSection(hdc,lpDIB,DIB_RGB_COLORS,&lpBMP,NULL,0); hdcMem=CreateCompatibleDC(hdc); /* メモリDC を作成 */ SelectObject(hdcMem,hBMP); /* メモリDC にDIBSectionを選択 */ /* 画面全体をDIBSection のビットマップにコピー */ BitBlt(hdcMem,0,0,iWidth,iHeight,hdc,0,0,SRCCOPY);
今回は、こうして得られた画面全体のビットマップを「白黒化」
(参照・モノクロ(単一色)階調表現への変換)
してから再度画面に描画します。
for (i=0;i<iWidth*iHeight;i++) { /* ビットマップを白黒化 */ bRed=lpBMP[i*3+2]; // ピクセルのRGB成分を取得 bGreen=lpBMP[i*3+1]; bBlue=lpBMP[i*3]; bGray=(BYTE)(bRed*0.3+bGreen*0.59+bBlue*0.11); // 明るさを計算 lpBMP[i*3]=bGray; /* ピクセルを白黒化 */ lpBMP[i*3+1]=bGray; lpBMP[i*3+2]=bGray; } /* 白黒化したビットマップを画面のデバイスコンテキストに描画 */ BitBlt(hdc,0,0,iWidth,iHeight,hdcMem,0,0,SRCCOPY);
プログラム
今回のプログラムは、処理が終わったらすぐにプログラムを終了させるようになっています。ウインドウも作っていませんので、WinMain 以外の関数もありません。
実行すると、しばらくして画面全体が「白黒」になるのがわかるでしょう。鮮やかなビットマップなどを表示してからこのプログラムを実行すると、面白いと思います。
画面を元に戻すには、一度フルスクリーンのアプリケーションを起動して終了してください。それで画面全体がシステムによって再描画され元に戻るはずです。