砂嵐プログラミング その3 の続きです。
2種類の方法で、とうとう7行プログラミングを達成 しました~♪
(※ 2ちゃんねるに掲載されていた元コードのままでは、VC++2005でコンパイルエラーが発生した為、コンパイルが通る様、若干修正を加えてあります^^;)
7行プログラミング(砂嵐)type1
#include <windows.h>
char*k,y[1<<20];int a=640,b=400,c,r,m[8];BITMAPINFO t={40,a,b,1,24};HWND g;int
WINAPI WinMain(HINSTANCE i,HINSTANCE,LPSTR,int){WNDCLASS w={67,DefWindowProc,0
,0,i,0,0,0,0,"T"};RegisterClass(&w);HDC v=GetDC(g=CreateWindow("T","砂",513<<19,
99,99,a,b,0,0,i,0));while(GetMessage((MSG*)m,g,0,0)!=-1){if(m[1]==15){for(k=y
;k<y+a*b*3;k+=3)*k=*(k+1)=*(k+2)=(r=r*9+5)>>16;SetDIBitsToDevice(v,0,0,a,b,0,0
,0,b,y,&t,0);}else DispatchMessage((MSG*)m);InvalidateRect(g,0,0);}return 0;}
適当にインデント・改行を入れて、見やすくしたものがこちら↓
#include <windows.h>
char * k, y[1<<20];
int a = 640, b = 400, c, r, m[8];
BITMAPINFO t = {40, a, b, 1, 24};
HWND g;
int WINAPI WinMain (HINSTANCE i, HINSTANCE, LPSTR, int)
{
WNDCLASS w = {67, DefWindowProc, 0, 0, i, 0, 0, 0, 0, "T"};
RegisterClass(&w);
HDC v = GetDC(
g = CreateWindow("T","砂", 513 << 19, 99, 99, a, b, 0, 0, i, 0)
);
while (GetMessage((MSG*)m,g,0,0) != -1) {
if (m[1] == 15) {
for (k = y; k < y+a*b*3; k += 3)
*k = *(k+1) = *(k+2) = (r=r*9+5) >> 16;
SetDIBitsToDevice(v, 0, 0, a, b, 0, 0, 0, b, y, &t, 0);
}
else
DispatchMessage((MSG*)m);
InvalidateRect(g, 0, 0);
}
return 0;
}
ウィンドウクラス.styleの「67」は、「 CS_CLASSDC | CS_VREDRAW | CS_HREDRAW 」という意味です。
CS_CLASSDCを指定する理由は、ウィンドウクラスに所属するデバイスコンテキストを取得し、メモリ解放の処理をしなくても、メモリがリークするのを防ぐためです。
※ ウィンドウクラスのスタイルに、
CS_CLASSDC, CS_OWNDC, CS_PARENTDC のいずれかを指定すると、(デバイスコンテキストの取得時に、)ウィンドウクラスに所属するデバイスコンテキストのハンドルが取得される
らしいです。⇒ 詳細はMSDNを参照)
そして、ウィンドウクラス.lpfnWndProcに DefWindowProcを指定し、ウィンドウプロシージャをコーディングする手間を省きます。
GetMessage()のwhileループ内で、エラーではない場合(GetMessage()は、エラー時に-1を返します)、砂嵐の描画処理を行います。
7行プログラミング(砂嵐)type2
続いて、別のやり方。
#include <windows.h>
HDC v;char*k,y[1<<20];int a=640,b=400,c,i,r,m[8];BITMAPINFO t={40,a,b,1,24};
HWND g;int WINAPI WinMain(HINSTANCE i,HINSTANCE,LPSTR,int){WNDCLASS w={67,
DefWindowProc,0,0,i,0,0,0,0,"T"};RegisterClass(&w);v=GetDC(g=CreateWindow("T",
0,268959744,0,0,a,b,0,0,i,0));for(;;){if(PeekMessage((MSG*)m,0,0,0,1))
DispatchMessage((MSG*)m);else{if(!IsWindow(g))return 0;for(k=y;k<y+a*b*3;k+=3)
*k=*(k+1)=*(k+2)=(r=r*9+5)>>16;SetDIBitsToDevice(v,0,0,a,b,0,0,0,b,y,&t,0);}}}
適当にインデント・改行を入れて、見やすくしたものがこちら↓
#include <windows.h>
HDC v;
char * k, y[1<<20];
int a = 640, b = 400, c, i, r, m[8];
BITMAPINFO t={40,a,b,1,24};
HWND g;
int WINAPI WinMain(HINSTANCE i, HINSTANCE, LPSTR, int)
{
WNDCLASS w = {67, DefWindowProc, 0, 0, i, 0, 0, 0, 0, "1"};
RegisterClass(&w);
v = GetDC(
g = CreateWindow("1", 0, 268959744, 0, 0, a, b, 0, 0, i, 0)
);
for (;;) {
if (PeekMessage((MSG*)m,0,0,0,1))
DispatchMessage((MSG*)m);
else {
if (!IsWindow(g))
return 0;
for (k = y; k < y+a*b*3; k += 3)
*k = *(k+1) = *(k+2) = (r = r*9+5) >> 16;
SetDIBitsToDevice(v, 0, 0, a, b, 0, 0, 0, b, y, &t ,0);
}
}
}
CreateWindow()の第3パラメータである「268959744」は、「WS_VISIBLE | WS_SYSMENU」と等価です。
また、PeekMessage()の第5パラメータである「1」は、「PM_REMOVE」と等価です (← winuser.h参照)。
さて、MSDNでPeekMessage関数について調べてみると、
PeekMessage()の第2パラメータにNULLを指定すると、
「PeekMessage()を呼び出した現在のスレッドに所属する任意のウィンドウに関連付けられているメッセージを取得します」
との事。
そして、PeekMessage()のBOOL型戻り値は、「成功/失敗」ではなく「メッセージ取得/未取得」であり、
WM_PAINTメッセージに関しては、PeekMessage()はメッセージキューから削除しないとの事です。
PeekMessage()のこれらの挙動から、上記のtype2コードが動作する仕組みが判明します^^;)