Win 32プログラミング学習ノート
前にwindowプログラミングも習いましたが、ばらばらで、知識体系が不完全です.これから、復習しながら新しい知識を学びます.
以下はvs 2010に書かれたプログラムです.
次のプログラムは、ウィンドウに文字列を入力し、マウスを左クリックしたときに円を描きます.
BeginPaint()とEndPaint()は、メッセージキュー内のWM_を削除できます.PAINTメッセージは、無効な領域を有効にします.GetDC()とReleaseDC()は削除しなくても無効領域を有効にすることができないので、プログラムがWM_をスキップするとPAINTの場合、無効な領域はまだ存在します.システムはWMを送信し続けます.PAINTメッセージ、そこでプログラムは絶えずWM_を処理しますPAINTメッセージ.BeginPaint、EndPaintに相当してGDI内部に、このウィンドウの再描画が必要な場所が再描画されたことを伝えます.これでWM_PAINT処理が完了してシステムに戻った後、システムはWM_を再送信しません.PAINT、GetDCはシステムにこのウィンドウを再描画する必要がある場所を教えていません.プログラムをシステムに戻した後、システムはあなたに再描画コマンドを通知してもおとなしく実行していないか、エラーを実行していないと思っています.だから、メッセージが空いている間に、WM_を送り続けます.PAINTはあなたに絵を描くように催促して、プログラムカードが死んだ.無効な領域:無効な領域とは、再描画が必要な領域を指し、無効な意味は、現在の内容は古く、時代遅れです.Aが新しくポップアップされたダイアログまたは既存のダイアログであると仮定すると、Aダイアログは元のアクティブなダイアログBの前に配置され、ダイアログBの一部または全部が上書きされ、ダイアログAが移動または閉じると、ダイアログBが元の上書きされた場所が再表示される.その部分が覆われている場所を無効領域と呼びます.1つのウィンドウメッセージが空いている場合にのみ、システムはこのウィンドウの無効な領域が空いていないかどうかをチェックします(WM_PAINTの優先度が最も低いです.つまり、システムが忙しい場合、ウィンドウとデスクトップが白くなり、リフレッシュできない、ドラッグの跡が残るなどの現象が発生する原因です).空でない場合、システムはWM_を送信しますPAINT.だから必ずBeginPaint、EndPaintで無効領域を空にしなければなりません.そうしないとWM_PAINTはずっと送信されます.なぜWINDOWSは無効な領域の概念を提出しますか?これは加速するためです.BeginPaintとEndPaintで使用されるデバイス記述子は現在の無効な領域内でのみ描画され、有効な領域内での描画は自動的にフィルタリングされるため、WIN GDIの描画速度は比較的遅いことが知られているので、1つの画素を節約して1つを節約することができ、けちを出さずに描画速度を効果的に速めることができます.BeginPaint、EndPaintは比較的「受動的」であり、ウィンドウの新規作成時と破壊された時にのみ再描画されることがわかります.GetDCは、どこを指しているのか、どこを打っているのかをアクティブに描くために使用されます.判断を加えずに描きますが、無効なエリアは関係ありません.ダイアログボックスは上書きされていません.破壊されていません.健康で、システムは再描画を要求していません.しかし、開発者は、時間を決めて外観を変えるウィンドウのように、WM_TIMER処理コード用GetDC.このときにBeginPaint,EndPaintを使うと,無効領域が空になるため,すべての描画操作がフィルタリングされる.例:
次のようになります. HDC hdc = BeginPaint(hWnd,&ps); --> HDC hdc = GetDC(hWnd); EndPaint(hWnd,&ps); --> ReleaseDC(hWnd,hdc); プログラムをコンパイルして実行すると、ウィンドウが空白で、ビットマップが描かれていないようです.しかし、必ずしもそうではありません.単一ステップのデバッグを採用すると、ビットマップが描かれていることがわかります.ただ、背景の色で消されています.GetDC()を使用する必要がある場合は、メッセージループ関数にWM_を追加する必要があります.ERASEBKGNDの処理: LRESULT CALLBACK MainWndProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam) { switch(wMsg) { case WM_PAINT: OnPaintMainWnd(hWnd,wMsg,wParam,lParam); break; case WM_ERASEBKGND return 0; } return DefWindowProc(hWnd,wMsg,wParam,lParam); } システムがWM_ERASEBKGNDをデフォルト処理しない限り、BeginPaint()の代わりにGetDC()を使用すれば正常に使用できる. これにより、BeginPaint()、EndPaint()、GetDC()、ReleaseDC()の違いがわかる.前のペアはWM_PAINT応答関数でしか使えず、背景を描く際には消されない.後のペアはどこでも利用できるが、WM_PAINT応答関数で使えば、次はWM_ERASEBKGNDメッセージの応答関数の背景で消される. 2.図面の点滅の問題 画面を大量に描画する場合、画面が点滅する問題が発生する可能性があります.この場合、デュアルバッファの方法を採用することができます.まず、メモリDCを作成し、メモリDCに描画し、最後にメモリDCの内容を表示DCにコピーして、描画を完了します.具体的な手順は複雑ではありません.コードと結びつけて説明します. PS:このコードも対応するWM_PAINTメッセージである.
PAINTSTRUCT ps;
以下はvs 2010に書かれたプログラムです.
#include<windows.h>
#include<stdio.h>
/**
* Unicode charset, 。
* :project->……property->configuration properties-> character set 。
*/
LRESULT CALLBACK WinLingProc(
HWND hwnd,
UINT uMsg,
WPARAM wPar,
LPARAM lPar
);
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
WNDCLASS wndcls;
wndcls.cbClsExtra = 0;
wndcls.cbWndExtra = 0;
wndcls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndcls.hCursor = LoadCursor(NULL,IDC_HAND);
wndcls.hIcon = LoadIcon(NULL,IDI_HAND);
wndcls.hInstance = hInstance;
wndcls.lpfnWndProc = WinLingProc;
wndcls.lpszClassName = L"ling";
wndcls.lpszMenuName = NULL;
wndcls.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wndcls);
HWND hwnd;
hwnd = CreateWindow(L"ling",L" ",WS_OVERLAPPEDWINDOW,
0,0,600,400,NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,1);
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WinLingProc(
HWND hwnd,
UINT uMsg,
WPARAM wPar,
LPARAM lPar
)
{
static int cxChar, cxCaps, cyChar, cyClient, iVscrollPos ;
HDC hdc ;
int i, y ;
PAINTSTRUCT ps ;
TCHAR szBuffer[10] ;
TEXTMETRIC tm ;
const int NUMLINES = 20;
switch(uMsg)
{
case WM_CREATE:
hdc = GetDC (hwnd) ;
GetTextMetrics (hdc, &tm) ;
cxChar = tm.tmAveCharWidth ;
cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ;
cyChar = tm.tmHeight + tm.tmExternalLeading ;
ReleaseDC (hwnd, hdc) ;
SetScrollRange(hwnd,SB_VERT,0,NUMLINES-1,FALSE);
SetScrollPos (hwnd, SB_VERT, iVscrollPos, TRUE) ;
break;
case WM_CHAR:
TCHAR szChar[20];
wsprintf(szChar ,L"the str is %d",wPar );
MessageBox(hwnd,szChar,L"lingyibin",0);
break;
case WM_LBUTTONDOWN:
MessageBox(hwnd,L"mouse clicked!",L"lingyibin",0);
HDC hdc;
hdc=GetDC(hwnd);
TextOut(hdc,0,50,L" ",wcslen(L" "));
ReleaseDC(hwnd,hdc);
break;
case WM_PAINT:
HDC hdc2;
PAINTSTRUCT ps;
hdc2 = BeginPaint(hwnd,&ps);
TextOut(hdc2,0,50,L" ",wcslen(L" "));
EndPaint(hwnd,&ps);
break;
case WM_CLOSE:
if(IDYES == MessageBox(hwnd,L" ?",L"ling",MB_YESNO))
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_SIZE:
cyClient = HIWORD (lPar) ;
return 0 ;
case WM_VSCROLL:
switch (LOWORD (wPar))
{
case SB_LINEUP:
iVscrollPos -= 1 ;
break ;
case SB_LINEDOWN:
iVscrollPos += 1 ;
break ;
case SB_PAGEUP:
iVscrollPos -= cyClient / cyChar ;
break ;
case SB_PAGEDOWN:
iVscrollPos += cyClient / cyChar ;
break ;
case SB_THUMBPOSITION:
iVscrollPos = HIWORD (wPar) ;
break ;
}
default:
return DefWindowProc(hwnd,uMsg,wPar,lPar);
}
}
次のプログラムは、ウィンドウに文字列を入力し、マウスを左クリックしたときに円を描きます.
#include<Windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam,LPARAM lParam)
{
HDC hdc;//
PAINTSTRUCT ps;
RECT rect;
POINT point;
switch(iMsg)
{
case WM_PAINT:
{
hdc = BeginPaint(hwnd,&ps);
GetClientRect(hwnd,&rect);
DrawText(hdc,"Hello,xiaoling!",-1, //-1 means print all of the characters in "Hello,xiaoling!"
&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
EndPaint(hwnd,&ps);
return 0;
}
case WM_LBUTTONDOWN:
{
hdc = GetDC(hwnd);
point.x = LOWORD(lParam);
point.y = HIWORD(lParam);
Ellipse(hdc,point.x-50,point.y-50,point.x+50,point.y+50);
ReleaseDC(hwnd,hdc);
return 0;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hwnd,iMsg,wParam,lParam);
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
static char szAppName[] = "HelloWin32";//
HWND hwnd;//
MSG msg;//
WNDCLASSEX wndclass;//
wndclass.cbSize = sizeof(wndclass);//
wndclass.style = CS_HREDRAW|CS_VREDRAW;// :
wndclass.lpfnWndProc = WndProc;//
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszClassName = szAppName;
wndclass.lpszMenuName = NULL;
wndclass.hIconSm = LoadIcon(NULL,IDI_APPLICATION);
RegisterClassEx(&wndclass);
hwnd=CreateWindow(szAppName,
"The Hello App",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd,nShowCmd);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
一つ注意すべきことは BeginPaintとGetDCの違いBeginPaint()とEndPaint()は、メッセージキュー内のWM_を削除できます.PAINTメッセージは、無効な領域を有効にします.GetDC()とReleaseDC()は削除しなくても無効領域を有効にすることができないので、プログラムがWM_をスキップするとPAINTの場合、無効な領域はまだ存在します.システムはWMを送信し続けます.PAINTメッセージ、そこでプログラムは絶えずWM_を処理しますPAINTメッセージ.BeginPaint、EndPaintに相当してGDI内部に、このウィンドウの再描画が必要な場所が再描画されたことを伝えます.これでWM_PAINT処理が完了してシステムに戻った後、システムはWM_を再送信しません.PAINT、GetDCはシステムにこのウィンドウを再描画する必要がある場所を教えていません.プログラムをシステムに戻した後、システムはあなたに再描画コマンドを通知してもおとなしく実行していないか、エラーを実行していないと思っています.だから、メッセージが空いている間に、WM_を送り続けます.PAINTはあなたに絵を描くように催促して、プログラムカードが死んだ.無効な領域:無効な領域とは、再描画が必要な領域を指し、無効な意味は、現在の内容は古く、時代遅れです.Aが新しくポップアップされたダイアログまたは既存のダイアログであると仮定すると、Aダイアログは元のアクティブなダイアログBの前に配置され、ダイアログBの一部または全部が上書きされ、ダイアログAが移動または閉じると、ダイアログBが元の上書きされた場所が再表示される.その部分が覆われている場所を無効領域と呼びます.1つのウィンドウメッセージが空いている場合にのみ、システムはこのウィンドウの無効な領域が空いていないかどうかをチェックします(WM_PAINTの優先度が最も低いです.つまり、システムが忙しい場合、ウィンドウとデスクトップが白くなり、リフレッシュできない、ドラッグの跡が残るなどの現象が発生する原因です).空でない場合、システムはWM_を送信しますPAINT.だから必ずBeginPaint、EndPaintで無効領域を空にしなければなりません.そうしないとWM_PAINTはずっと送信されます.なぜWINDOWSは無効な領域の概念を提出しますか?これは加速するためです.BeginPaintとEndPaintで使用されるデバイス記述子は現在の無効な領域内でのみ描画され、有効な領域内での描画は自動的にフィルタリングされるため、WIN GDIの描画速度は比較的遅いことが知られているので、1つの画素を節約して1つを節約することができ、けちを出さずに描画速度を効果的に速めることができます.BeginPaint、EndPaintは比較的「受動的」であり、ウィンドウの新規作成時と破壊された時にのみ再描画されることがわかります.GetDCは、どこを指しているのか、どこを打っているのかをアクティブに描くために使用されます.判断を加えずに描きますが、無効なエリアは関係ありません.ダイアログボックスは上書きされていません.破壊されていません.健康で、システムは再描画を要求していません.しかし、開発者は、時間を決めて外観を変えるウィンドウのように、WM_TIMER処理コード用GetDC.このときにBeginPaint,EndPaintを使うと,無効領域が空になるため,すべての描画操作がフィルタリングされる.例:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd,&ps);
//Create a DC that matches the device
HDC hdcMem = CreateCompatibleDC(hdc);
//Load the bitmap
HANDLE hBmp= LoadImage(g_hInst_MainWnd,MAKEINTRESOURCE(IDB_MAINWND),IMAGE_BITMAP,0,0,0);
//Select the bitmap into to the compatible device context
HGDIOBJ hOldSel = SelectObject(hdcMem,hBmp);
//Get the bitmap dimensions from the bitmap
BITMAP bmp;
GetObject(hBmp,sizeof(BITMAP),&bmp);
//Get the window area
RECT rc;
GetClientRect(hWnd,&rc);
//Copy the bitmap image from the memory DC to the screen DC
BitBlt(hdc,rc.left,rc.top,bmp.bmWidth,bmp.bmHeight,hdcMem,0,0,SRCCOPY);
//Restore original bitmap selection and destroy the memory DC
SelectObject(hdcMem,hOldSel);
DeleteDC(hdcMem);
EndPaint(hWnd,&ps);
return 0;
/////////////////////////
//========================================================================
//TITLE:
// EVC --BeginPaint() GetDC()
//AUTHOR:
// norains
//DATE:
// Tuesday 29-August-2006
//========================================================================
1.BeginPaint() GetDC()
EVC , , BeginPaint() GetDC() .
, .
:
LRESULT CALLBACK MainWndProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
{
......
switch(wMsg)
{
case WM_PAINT:
OnPaintMainWnd(hWnd,wMsg,wParam,lParam);
break;
......
}
return DefWindowProc(hWnd,wMsg,wParam,lParam);
......
}
WM_PAINT , :
LRESULT OnPaintMainWnd(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd,&ps);
//Create a DC that matches the device
HDC hdcMem = CreateCompatibleDC(hdc);
//Load the bitmap
HANDLE hBmp= LoadImage(g_hInst_MainWnd,MAKEINTRESOURCE(IDB_MAINWND),IMAGE_BITMAP,0,0,0);
//Select the bitmap into to the compatible device context
HGDIOBJ hOldSel = SelectObject(hdcMem,hBmp);
//Get the bitmap dimensions from the bitmap
BITMAP bmp;
GetObject(hBmp,sizeof(BITMAP),&bmp);
//Get the window area
RECT rc;
GetClientRect(hWnd,&rc);
//Copy the bitmap image from the memory DC to the screen DC
BitBlt(hdc,rc.left,rc.top,bmp.bmWidth,bmp.bmHeight,hdcMem,0,0,SRCCOPY);
//Restore original bitmap selection and destroy the memory DC
SelectObject(hdcMem,hOldSel);
DeleteDC(hdcMem);
EndPaint(hWnd,&ps);
return 0;
}
BeginPaint()とEndPaint()を組み合わせて使用する必要があることはよく知られており、この2つの関数もWM_にしか使用できません.PAINTメッセージの対応する関数の中で.もし私たちがWM_PAINTの応答関数で上記の2つの描画関数をGetDC()とReleaseDC()に置き換えるとどのような結果になりますか?次のようになります. HDC hdc = BeginPaint(hWnd,&ps); --> HDC hdc = GetDC(hWnd); EndPaint(hWnd,&ps); --> ReleaseDC(hWnd,hdc); プログラムをコンパイルして実行すると、ウィンドウが空白で、ビットマップが描かれていないようです.しかし、必ずしもそうではありません.単一ステップのデバッグを採用すると、ビットマップが描かれていることがわかります.ただ、背景の色で消されています.GetDC()を使用する必要がある場合は、メッセージループ関数にWM_を追加する必要があります.ERASEBKGNDの処理: LRESULT CALLBACK MainWndProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam) { switch(wMsg) { case WM_PAINT: OnPaintMainWnd(hWnd,wMsg,wParam,lParam); break; case WM_ERASEBKGND return 0; } return DefWindowProc(hWnd,wMsg,wParam,lParam); } システムがWM_ERASEBKGNDをデフォルト処理しない限り、BeginPaint()の代わりにGetDC()を使用すれば正常に使用できる. これにより、BeginPaint()、EndPaint()、GetDC()、ReleaseDC()の違いがわかる.前のペアはWM_PAINT応答関数でしか使えず、背景を描く際には消されない.後のペアはどこでも利用できるが、WM_PAINT応答関数で使えば、次はWM_ERASEBKGNDメッセージの応答関数の背景で消される. 2.図面の点滅の問題 画面を大量に描画する場合、画面が点滅する問題が発生する可能性があります.この場合、デュアルバッファの方法を採用することができます.まず、メモリDCを作成し、メモリDCに描画し、最後にメモリDCの内容を表示DCにコピーして、描画を完了します.具体的な手順は複雑ではありません.コードと結びつけて説明します. PS:このコードも対応するWM_PAINTメッセージである.
PAINTSTRUCT ps;
HDC hdc;
// DC
hdc = BeginPaint (hWnd, &ps);
// DC
HDC hdcMem = CreateCompatibleDC(hdc);
// bmp
HBITMAP hBmp = CreateCompatibleBitmap(hdc,SCREEN_WIDTH,SCREEN_HEIGHT);
// bmp DC
HGDIOBJ hOldSel = SelectObject(hdcMem,hBmp);
// , DC
Rectangle(hdcMem,0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
DrawMenuButton(hdcMem);
// DC DC ,
BitBlt(hdc,0,0,SCREEN_WIDTH,SCREEN_HEIGHT,hdcMem,0,0,SRCCOPY);
//
SelectObject(hdcMem,hOldSel);
DeleteDC(hdcMem);