Directx3D9学习之二:Windows编程之最简单窗口程序

Directx3D9学习之二:Windows编程之最简单窗口程序

一、一些基本知识介绍
由于D3D的编程要借助于windows的窗口来体现,所以也需要懂一些windows的编程知识(以前做得比较多的是linux与android方面的程序,因此也要学习一下下啦)。
一些windows编程的https://msdn.microsoft.com/en-us/library/ff381404(v=vs.85).aspx
Data type Size Signed?
BYTE 8 bits Unsigned
DWORD 32 bits Unsigned
INT32 32 bits Signed
INT64 64 bits Signed
LONG 32 bits Signed
LONGLONG 64 bits Signed
UINT32 32 bits Unsigned
UINT64 64 bits Unsigned
ULONG 32 bits Unsigned
ULONGLONG 64 bits Unsigned
WORD 16 bits Unsigned
WinDef.h中定义了BOOL值
#define FALSE    0 
#define TRUE     1

p代表“指针”
lp代表“长指针

  • DWORD_PTR
  • INT_PTR
  • LONG_PTR
  • ULONG_PTR
  • UINT_PTR

头文件WinNT.h定义了如下typedef (基于UTF-16编码,即是16bit),为了支持Unicode

typedef wchar_t WCHAR;
一般来说,会经常看到如下编码的宽字符,即是前面加个L:
wchar_t a = L'a';
wchar_t *str = L"hello";
其他一些相关的typedef
Typedef Definition
CHAR char
PSTR or LPSTR char*
PCSTR or LPCSTR const char*
PWSTR or LPWSTR wchar_t*
PCWSTR or LPCWSTR const wchar_t*
windows支持unicode与ANSI,较新的则只支持Unicode
  • SetWindowTextA takes an ANSI string.
  • SetWindowTextW takes a Unicode string.
#ifdef UNICODE
#define SetWindowText  SetWindowTextW
#else
#define SetWindowText  SetWindowTextA
#endif 
通过宏UNICODE来控制
Macro Unicode ANSI
TCHAR wchar_t char
TEXT("x") L"x" "x"
示范例子:


SetWindowTextW(L"My Application"); // Unicode function with wide-character string.

SetWindowTextA("My Application");  // ANSI function.
#ifdef _UNICODE
#define _tcslen     wcslen
#else
#define _tcslen     strlen
#endif 

二、windows窗口编程
1、窗口句柄
HWND,通常来自以下两个函数的返回值
CreateWindow and CreateWindowEx.
要操作窗口通常需要使用HWND作为参数传入函数使用,例如移动窗口MoveWindow
BOOL MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint);
另外句柄不是指针,不存在 *hwnd  
2、屏幕和窗口坐标
一般来说,windows的窗口都是以左上角为原点(0,0),另外一些坐标定义如图(图片来自msdn)
Directx3D9学习之二:Windows编程之最简单窗口程序_第1张图片
3、windows编程的入口点
WinMain or wWinMain
wWinMain为例子
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow);
hInstance:标识executable
hPrevInstance:现在已经没有使用,始终为0,以前用在16位的windows中。
pCmdLine:包含Unicode字符串的命令行参数
nCmdShow:一个flag,表示应用程序窗口的显示如:最大化,最小化或者正常。

4、创建一个窗口的过程
(1)注册一个窗口类
    // Register the window class.
    const wchar_t CLASS_NAME[]  = L"Sample Window Class";
    
    WNDCLASS wc = { };

    wc.lpfnWndProc   = WindowProc;
    wc.hInstance     = hInstance;
    wc.lpszClassName = CLASS_NAME;
lpfnWndProc:窗口过程,定义了绝多部分的动作
hInstance:来自wWinMain,实例句柄
lpszClassName:标识窗口类的字符串

传递WNDCLASS结构的地址给RegisterClass函数,注册窗口类到操作系统。
  RegisterClass(&wc);
(2)创建窗口新实例
调用CreateWindowEx
 HWND hwnd = CreateWindowEx(
        0,                              // Optional window styles.
        CLASS_NAME,                     // Window class

        L"Learn to Program Windows",    // Window text
        WS_OVERLAPPEDWINDOW,            // Window style

        // Size and position
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

        NULL,       // Parent window    
        NULL,       // Menu
        hInstance,  // Instance handle
        NULL        // Additional application data
        );

    if (hwnd == NULL)
    {
        return 0;
    }
第一个参数:
Optional window styles.
设定窗口中的一些可选行为(例如透明窗口),默认为0。
第二个参数:
Window class
定义窗口所创建的类型
第三个参数:
Window text
窗口标题,如果窗口存在标题栏则显示在其中。
第四个参数:
Window style

窗口的风格,定义了一些窗口外观和表现的标志组合,WS_OVERLAPPEDWINDO是几个标志结合的位或,包含最小化,最大化按钮,边框,标题栏等等

第五个参数:

Size and position

位置和大小 CW_USEDEFAULT 使用默认值

第六个参数:

Parent window 

父窗口。

第七个参数:

Menu

菜单

第八个参数:

Instance handle

实例句柄

第九个参数:

Additional application data

指向void*的任意数据结构,传递数据所用

最后CreateWindowEx 返回句柄创建新窗口,如果失败返回0.

(3)显示窗口

要显示窗口则将窗口句柄传递给ShowWindow函数

ShowWindow(hwnd, nCmdShow);

  hwnd  参数来自 CreateWindowEx 

nCmdShow参数用于最大化或者最小化窗口。操作系统将通过wWinMain函数传递该参数给程序


(4)窗口消息

窗口消息

MSG msg;GetMessage(&msg, NULL, 0, 0);

提取消息使用以下两个函数

TranslateMessage(&msg); DispatchMessage(&msg);


退出提取消息循环

退出提取消息循环

        PostQuitMessage(0);
  WM_QUIT是一个特殊的消息,它会令消息循环结束。消息循环的示例:
// Correct.

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

(4)窗口过程

The DispatchMessage function calls the window procedure of the window that is the target of the message. The window procedure has the following signature.

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
hwnd:窗口句柄
uMSg:消息代码
wParam、lParam:消息的其他数据

典型的窗口过程如下:

switch (uMsg)
{
case WM_SIZE: // Handle window resizing
    
// etc

}

一个典型的窗口过程可能需要处理几十条消息,因此它可能会变得非常长,这样可以将每个消息的逻辑处理封装到一个单独的函数中n,
然后再在switch中处理。
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_SIZE: 
        {
            int width = LOWORD(lParam);  // Macro to get the low-order word.
            int height = HIWORD(lParam); // Macro to get the high-order word.

            // Respond to the message:
            OnSize(hwnd, (UINT)wParam, width, height);
        }
        break;
        
    }
}

void OnSize(HWND hwnd, UINT flag, int width, int height);
{
    // Handle resizing
}
假如不处理窗口过程特定的消息,可以直接返回默认的DefWindowProc函数,
    return DefWindowProc(hwnd, uMsg, wParam, lParam);hui


(4)绘制窗口内容

  switch (uMsg)
    {

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

            // All painting occurs here, between BeginPaint and EndPaint.

            FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW+1));

            EndPaint(hwnd, &ps);
        }
        return 0;

    }
更新绘图有两种选择:
*只更新一部分
*更新全部区域

下面代码是更新整个区域,使用单一颜色,采用系统默认的COLOR_WINDOW,颜色取决于系统的配色方案
 FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW+1));

完成绘图后,需要调用EndPaint,清除更新区域,表示绘图已经完成

三、最后的完整代码
#ifndef UNICODE
#define UNICODE
#endif

#include 

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
	//Register the window class
	const wchar_t CLASS_NAME[] = L"Sample Window Class";
	WNDCLASS wc = { };
	wc.lpfnWndProc	= WindowProc;
	wc.hInstance	= hInstance;
	wc.lpszClassName	=	CLASS_NAME;

	RegisterClass(&wc);

	//Create the window.

	HWND hwnd = CreateWindowEx(
		0,				//Optional window styles.
		CLASS_NAME,		//Window class
		L"Learn to Program Windows",	//Window text
		WS_OVERLAPPEDWINDOW,	//Window style

		//Size and position
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

		NULL,				//Parent window
		NULL,				//Menu
		hInstance,			//Instance handle
		NULL				//Additional application data
		);

	if(hwnd == NULL)
	{
		return 0;
	}

	ShowWindow(hwnd, nCmdShow);

	//Run the message loop.

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

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
		case WM_PAINT:
			{
				PAINTSTRUCT ps;
				HDC hdc = BeginPaint(hwnd, &ps);
				FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW+1));
				EndPaint(hwnd, &ps);
			}
			return 0;
	}
	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}



你可能感兴趣的:(游戏开发学习)