30
Win32 API 看視窗運作 with C language 最後更新日期: 2013 年 4 月 10 日

Win32 api看視窗運作

Embed Size (px)

Citation preview

Page 1: Win32 api看視窗運作

Win32 API 看視窗運作

with C language

最後更新日期: 2013 年 4 月 10 日

Page 2: Win32 api看視窗運作

聲明

課程不包含以下部份:物件導向、 C++ 、軟體工

程、 MFC

Page 3: Win32 api看視窗運作

什麼是 Win32 API• 視窗作業系統應用程序介面( Windows API ),有非正

式的簡稱法為 WinAPI• 是微軟對於 Windows 作業系統中可用的核心應用程序編

程介面的稱法。• 它被設計為各種語言的程序調用,也是應用軟體與

Windows 系統最直接的交互方式。• 大多數驅動程序所需要的對 Windows 系統的更底層次訪

問介面,由所用版本的 Windows 的 Native API 來提供介面。

• Windows 有一個軟體開發包( SDK, software development kit )提供相應的文件和工具,以使程式設計師開發使用 Windows API 的軟體和利用 Windows 技術。

Page 4: Win32 api看視窗運作

程式的運作

PC PC

Program

Program

OS(Windows)

OS(DOS)

User User

Program

Program

Program

Page 5: Win32 api看視窗運作

C in DOS#include <stdio.h>int main () { printf ("hello, world\n")

; return 0 ; }

// 顯示 hello, world

程式進入點

Page 6: Win32 api看視窗運作

C with Win32API(1)#include <windows.h> int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { MessageBox (NULL, TEXT ("Hello, Windows 98!"), TEXT ("HelloMsg"), 0); return 0 ; }

°õ¦æÀÉ

程式進入點

Page 7: Win32 api看視窗運作

C with Win32API(1)#include <windows.h>

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

{ HDC hdc ; PAINTSTRUCT ps ; RECT rect ; switch (message) { case WM_CREATE: PlaySound (TEXT ("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC) ; return 0 ;

case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; GetClientRect (hwnd, &rect) ; DrawText (hdc, TEXT ("Hello, Windows 95"), -1, &rect, DT_SINGLELINE |

DT_CENTER | DT_VCENTER) ; EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY: PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ;}

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)

{ static TCHAR szAppName[] = TEXT ("HelloWin") ; HWND hwnd ; MSG msg ; WNDCLASS 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.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ;

if (!RegisterClass (&wndclass)) { MessageBox ( NULL, TEXT ("This program requires Windows NT!"),

szAppName, MB_ICONERROR) ; return 0 ; } hwnd = CreateWindow( szAppName, // window class name TEXT ("The Hello Program"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL) ; // creation parameters ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ;}

Page 8: Win32 api看視窗運作

#include <windows.h>

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

{ HDC hdc ; PAINTSTRUCT ps ; RECT rect ; switch (message) { case WM_CREATE: PlaySound (TEXT ("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC) ; return 0 ;

case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; GetClientRect (hwnd, &rect) ; DrawText (hdc, TEXT ("Hello, Windows 9"), -1, &rect, DT_SINGLELINE |

DT_CENTER | DT_VCENTER) ; EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY: PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ;}

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)

{ static TCHAR szAppName[] = TEXT ("HelloWin") ; HWND hwnd ; MSG msg ; WNDCLASS 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.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ;

if (!RegisterClass (&wndclass)) { MessageBox ( NULL, TEXT ("This program requires Windows NT!"),

szAppName, MB_ICONERROR) ; return 0 ; } hwnd = CreateWindow( szAppName, // window class name TEXT ("The Hello Program"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL) ; // creation parameters ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ;}

程式進入點

創造視窗

繪製視窗

銷毀視窗

視窗訊息處理副程式

註冊視窗

設定視窗型式指定視窗訊息處理副程式

建立視窗(背景執行)

顯示視窗(畫出來)

訊息處理迴圈

C with Win32API(1)

Page 9: Win32 api看視窗運作

°õ¦æÀÉ

Page 10: Win32 api看視窗運作

程式進入點int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){ static TCHAR szAppName[] = TEXT ("HelloWin") ; WNDCLASS wndclass ; HWND hwnd ; MSG msg ;

typedef struct tagWNDCLASSA{ UINT style ; WNDPROC lpfnWndProc ; int cbClsExtra ; int cbWndExtra ; HINSTANCE hInstance ; HICON hIcon ; HCURSOR hCursor ; HBRUSH hbrBackground ; LPCSTR lpszMenuName ; LPCSTR lpszClassName ;}WNDCLASSA, * PWNDCLASSA, NEAR * NPWNDCLASSA, FAR * LPWNDCLASSA ;

typedef struct tagWNDCLASSW { UINT style ; WNDPROC lpfnWndProc ; int cbClsExtra ; int cbWndExtra ; HINSTANCE hInstance ; HICON hIcon ; HCURSOR hCursor ; HBRUSH hbrBackground ; LPCWSTR lpszMenuName ; LPCWSTR lpszClassName ;}WNDCLASSW, * PWNDCLASSW, NEAR * NPWNDCLASSW, FAR * LPWNDCLASSW ;

視窗類別結構記錄視窗可設定的屬性用什麼型態與使用者互動

1. 設定 2. 註冊1. 建立 2. 顯示1. 等 2. 處理

Page 11: Win32 api看視窗運作

其中,這個 style

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){ static TCHAR szAppName[] = TEXT ("HelloWin") ; WNDCLASS wndclass ; HWND hwnd ; MSG msg ;

設定視窗型式

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.lpszMenuName = NULL ;wndclass.lpszClassName = szAppName ;

LoadIcon 載入圖示供程式使用。LoadCursor 載入滑鼠游標供程式使用。

每當視窗的水平方向大小 (CS_HREDRAW) 或者垂直方向大小 (CS_VREDRAW) 改變之後,視窗要完全重畫。

設定視窗訊息處理程式為 WndProc

執行實體代號

視窗的背景顏色。 指定視窗類別功能表。

自訂一個類別名稱,等等建立視窗時靠這個類別名稱來 link 。

另一個 callback 程式

Page 12: Win32 api看視窗運作

wndclass.style

CS_DBLCLKS.exe

Cs_owndc.exe

CS_CLASSDC.exe

#define CS_VREDRAW 0x0001

#define CS_HREDRAW 0x0002

#define CS_DBLCLKS 0x0008

#define CS_OWNDC 0x0020

#define CS_CLASSDC 0x0040

#define CS_PARENTDC 0x0080

#define CS_NOCLOSE 0x0200

#define CS_SAVEBITS 0x0800

#define CS_BYTEALIGNCLIENT 0x1000

#define CS_BYTEALIGNWINDOW 0x2000

#define CS_GLOBALCLASS 0x4000

#define CS_IME 0x00010000

CS_PARENTDC.exe

CS_NOCLOSE.exe

CS_SAVEBITS.exe

CS_BYTEALIGNCLIENT.exe

CS_BYTEALIGNWINDOW.exe

CS_GLOBALCLASS.exe

設定視窗型式

Page 13: Win32 api看視窗運作

樣式 樣式的作用

CS_BYTEALIGNCLI

ENT

將視窗程式區域以記憶體區隔( byte boundary )水平對齊來增加描繪圖形介面的速度,會影響視窗的 度及水平位置。 寬

CS_BYTEALIGNWI

NDOW

將視窗以記憶體區隔水平對齊,會影響視窗的 度及水平位置。 寬

CS_CLASSDC 分配一個裝置組態( device context 或 DC )給所有由同一 class 製出來的視窗共用,在多緒的程式中只有當一個緒可以使用完後再換另一個緒使用。

CS_DBLCLKS 當使用者雙擊滑鼠時訊息會傳送到 window procedure 告訴視窗。

CS_DROPSHADO

W

只在 Windows XP 下有效,用來 動陰影效果。 啟

CS_GLOBALCLASS 允許 class 被其他同時在執行時的程式使用,最常被用在 DLL 中建造使用者控制項。

CS_HREDRAW 如果水平大小改變,重畫整個視窗。

CS_NOCLOSE 將視窗的 Close 表單選項及 Close 按鈕的功能取消。

CS_OWNDC 分配給由 window class 製作的各視窗一個個別的裝置組態( device context 或 DC )。

CS_PARENTDC 將此定義的 window class 所製作的視窗顯示在父視窗中。

CS_SAVEBITS將此 window class 的視窗所 住的圖案或視窗存成 擋 bitmap 的型式,當此視窗由螢幕

移除時,系統可以用存好的 bitmap 來重新顯示原有的視窗圖形。使用這個方式可以省下重畫視窗的時間,增加系統的效能。

CS_VREDRAW 如垂直大小改變,重畫整個畫面。

wndclass.style設定視窗型式

Page 14: Win32 api看視窗運作

註冊視窗類別if (!RegisterClass (&wndclass)){ MessageBox ( NULL, TEXT ("This program requires Windows NT!"),

szAppName, MB_ICONERROR) ; return 0 ;}

RegisterClass (&wndclass) 註冊這個視窗類別。

Page 15: Win32 api看視窗運作

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){ static TCHAR szAppName[] = TEXT ("HelloWin") ; WNDCLASS wndclass ; HWND hwnd ; MSG msg ;

建立視窗

hwnd = CreateWindow( szAppName, // window class name TEXT ("The Hello Program"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance

handle NULL) ; // creation parameters

「建立的視窗」聯結「視窗類別」的方式。

建立的視窗是一個普通的重疊式視窗。它含有一個標題列,標題列左邊有一個系統功能表按鈕,標題列右邊有縮小、放大和關閉圖示,四周還有一個表示視窗大小的邊框。

視窗位置及大小採用預設尺寸。

「父視窗代號」的參數 「視窗功能表代號」 「程式執行實體代號」設定為執行實體代號 稍後程式中可能引用到的資料

一組代表視窗的代碼記錄視窗的抽象屬性與使用者互動的時候

其中,這個 Common Window Styles

Page 16: Win32 api看視窗運作

Common Window Styles#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED| WS_CAPTION | WS_SYSMENU |WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX

)

#define WS_POPUPWINDOW (WS_POPUP | \ WS_BORDER | \ WS_SYSMENU)

#define WS_CHILDWINDOW (WS_CHILD)

#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED| WS_CAPTION | WS_SYSMENU |WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX )

#define WS_POPUPWINDOW (WS_POPUP | \ WS_BORDER | \ WS_SYSMENU)

#define WS_CHILDWINDOW (WS_CHILD)

了!不能改大小

Page 17: Win32 api看視窗運作

執行到這裡… .

還是還沒顯示視窗

Page 18: Win32 api看視窗運作

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){ static TCHAR szAppName[] = TEXT ("HelloWin") ; WNDCLASS wndclass ; HWND hwnd ; MSG msg ;

顯示視窗

ShowWindow (hwnd, iCmdShow) ; 在顯示器上顯示視窗。 覆蓋視窗顯示的區域 視窗第一眼呈現的樣子。

UpdateWindow (hwnd) ; 重畫顯示區域。 也就是「畫」 這個動作

其中,這個 iCmdShow

Page 19: Win32 api看視窗運作

iCmdShow

Sw_hide.exe

SW_SHOWNORMAL.exe

SW_SHOWMINIMIZED.exe

#define SW_HIDE 0 不顯示,背景執行

#define SW_SHOWNORMAL 1 一般大小顯示

#define SW_NORMAL 1 一般大小顯示 (類似 9 )

#define SW_SHOWMINIMIZED 2 最小化顯示 (類似 6 )

#define SW_SHOWMAXIMIZED 3 最大化顯示

#define SW_MAXIMIZE 3 最大化顯示

#define SW_SHOWNOACTIVATE 4 無 Focus (類似 8 )

#define SW_SHOW 5 顯示

#define SW_MINIMIZE 6 最小化顯示(類似 2 )

#define SW_SHOWMINNOACTIVE 7 最小化 + 無 Focus

視窗只顯示在工作列上

#define SW_SHOWNA 8 無 Focus (類似 4 )

#define SW_RESTORE 9 一般大小顯示(類似 1 )

#define SW_SHOWDEFAULT 10 一般大小顯示(類似 1 )

#define SW_FORCEMINIMIZE 11 不顯示,背景執行

#define SW_MAX 11

SW_SHOWMAXIMIZED.exe

Sw_show.exe

SW_SHOWMINNOACTIVE.exe

SW_FORCEMINIMIZE.exe

SW_SHOWNOACTIVATE.exe

SW_MINIMIZE.exe

SW_SHOWNA.exe

SW_RESTORE.exe

SW_SHOWDEFAULT.exe

Page 20: Win32 api看視窗運作

訊息處理迴圈

while (GetMessage (&msg, NULL, 0, 0)){ TranslateMessage (&msg) ; DispatchMessage (&msg) ;}

其中,這個 msg

Page 21: Win32 api看視窗運作

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){ static TCHAR szAppName[] = TEXT ("HelloWin") ; WNDCLASS wndclass ; HWND hwnd ; MSG msg ;

訊息結構typedef struct tagMSG{ HWND hwnd ; UINT message ; WPARAM wParam ; LPARAM lParam ; DWORD time ; POINT pt ; } MSG, * PMSG ; typedef struct tagPOINT

{ LONG x ; LONG y ; }POINT, * PPOINT;

訊息參數

訊息名稱(代號)

訊息放入訊息佇列中的時間。

Page 22: Win32 api看視窗運作

訊息處理迴圈

while (GetMessage (&msg, NULL, 0, 0)){ TranslateMessage (&msg) ; DispatchMessage (&msg) ;}

鍵盤轉換,也就是翻譯年 糕

WindowsXP

WinMain WinProc

msg msg

WinProc2

msg

Page 23: Win32 api看視窗運作

最重要的…

訊息處理程式

Page 24: Win32 api看視窗運作

視窗訊息處理程式LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ HDC hdc ; PAINTSTRUCT ps ; RECT rect ;

switch (message) { case WM_CREATE: PlaySound (TEXT ("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC) ; return 0 ;

case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ;

GetClientRect (hwnd, &rect) ;

DrawText (hdc, TEXT ("Hello, Windows 95"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;

EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY: PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ;}

Page 25: Win32 api看視窗運作

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ HDC hdc ; PAINTSTRUCT ps ; RECT rect ;

switch (message) { case WM_CREATE: PlaySound (TEXT ("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC) ; return 0 ;

case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ;

GetClientRect (hwnd, &rect) ;

DrawText (hdc, TEXT ("Hello, Windows 95"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;

EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY: PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ;}

視窗訊息處理程式

Page 26: Win32 api看視窗運作

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ HDC hdc ; PAINTSTRUCT ps ; RECT rect ;

switch (message) { case WM_CREATE: PlaySound (TEXT ("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC) ; return 0 ;

case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ;

GetClientRect (hwnd, &rect) ;

DrawText (hdc, TEXT ("Hello, Windows 95"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;

EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY: PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ;}

視窗開 。啟

畫出視窗要畫的「字和圖」(所有看見的東西都由這裡負責)

依使用者的操作結束視窗程式

視窗訊息處理程式

其它預設的動作

CALLBACK:Windows 自動呼叫的程式

Page 27: Win32 api看視窗運作

視窗訊息處理程式case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; // 開始繪圖

GetClientRect (hwnd, &rect) ; // 抓取視窗本身的顯示範圍矩形

DrawText (hdc, // 指定處理的視窗 TEXT (“Hello, Windows 95”), // 字串 -1, // 字串長度,若為 -1 則偵測 ’ \0’ (字串結束符

號) &rect, // 繪字範圍 DT_SINGLELINE | DT_CENTER | DT_VCENTER // 對齊方式 ) ;

EndPaint (hwnd, &ps) ; // 結束繪圖 return 0 ;

繪圖範圍

Page 28: Win32 api看視窗運作

°õ¦æÀÉ

Page 29: Win32 api看視窗運作

視窗訊息處理程式

PC

WinMain OS(Windows)

User

WinPorc1

WinPorc2

WinPorc3

Page 30: Win32 api看視窗運作

refreance