本套教材将使用vs2013为开发工具,如果读者还不知如何下载安装vs2013可以到我之前写的文章上去查看
安装好后再安装程序开发人员的字典MSDN,VS2013的MSDN和经典的VC++6.0的安装方法略有不同,这里提供一种在线的安装方法
①打开vs2013后,点击“帮助”菜单栏->"添加和移除帮助内容",来到如图所示的界面
②在需要安装的文件点添加,选择完后点击屏幕右下角的“更新”即可开始下载,下载文件存放的目录在这里使用默认的,如果读者需要可以改为其他地方。
③一般来说下载速度都比较慢,可以选择夜间后者网速比较快的时候下载。完成后再下图所示的红色框内输入内容就可查找相关的帮助信息
下面以一个小程序来讲解如何使用vs2013来开发windows程序
①新建工程
打开工程类型选择对话框
选择Win32项目,并输入项目名和项目所在的位置,单击确定进入下一步,再单击“下一步”,来到如下界面
(注:win32项目是对应于win16来说的,由于早期的处理器是16位的所以开发了一台API函数win16,用于开发windows1.0到windows3.1下的编程。随着硬件的发展,操作系统也跟着发展,从win95,win98到windows NT都使用了win32的API函数,这点大家做一下了解即可。)
为了创建一个从无到有的过程,选中“空项目”复选框,完成即可完成项目的创建。
②为工程添加源文件
在下面的对话框中选择cpp类型的文件,文件名可以随意取一个,最后点击“添加即可”
我们所创建的文件以树状图的形式表示在主界面的右侧
假如读者发现自己的布局被改过并且无法改回原来的样子,可以在菜单栏的“窗口”->"重置窗口布局"处修改。
好,到此为止我们已经把工程的框架搭建出来了,下面就是编程实现的问题了。
③编程实现
熟悉控制台程序下编程的读者都知道,一个应用程序有一个执行的入口点main函数,然后在windows程序下编程我们程序的入口点改为了WinMain。我们可以在MSDN中找到关于WinMain函数的介绍
WinMain
The WinMain function is called by the system as the initial entry point for a Win32-based application.
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // pointer to command line
int nCmdShow // show state of window
);
(注:该文档在/ Platform SDK / User Interface Services / Windowing /Windows / Window Reference / Window Functions 中有说明。)
第一个参数hInstance是指向当前程序实例的一个实例句柄,好比该实例的一个标识符。第二个参数hPrevInstance是指向前一个实例的句柄,在win16程序设计中程式通过检查hPrevInstance 参数就能够确定自身的其他执行实体是否正在运行,然后达到某一些目的,在win32程序设计中已经丢弃了这种做法,只需设置为NULL即可。第三个参数是用于执行程序的命令行,利用它可以在启动时将档案载入记忆体。第四个参数指出了程序最初显示的方式,可以满屏显示,最大化显示等等。
windows程序顾名思义就是基于窗口的编程,学过操作系统的读者都知道,窗口的产生于显示是属于并不是操作系统独立完成的,而是属于应用程序的范畴。下面来了解一下windows的运行机制:
窗口的运行过程如上图的左边,它很像我们实际生活中创办一个公司一样,这里做一下对比方便大家了解。
在实际编程中注册窗口类我们用的函数是
ATOM RegisterClassEx(
CONST WNDCLASSEX *lpwcx // address of structure with class data);
输入的参数为WNDCLASSEX类型变量的地址,就像注册公司前需要填写各种表格一样,我们注册窗口前也要进行详细的设置。
要设置的参数有
参数名 | 说明 |
cbSize | 所要注册的窗口类的尺寸 |
style | 指定窗口样式,即水平尺寸改变时要重绘窗口或者垂直尺寸改变时要重绘窗口 |
lpfnWndProc | 指定窗口处理函数 |
cbClsExtra | 设定窗口类的额外字节伴随,设置为0即可 |
cbWndExtra | 设定窗口实例的额外字节伴随,设置为0即可 |
hInstance | 应用程序的实例句柄 |
hIcon | 应用程序的图标 |
hIconSm | 应用程序的小图标 |
hbrBackground | 应用程序背景画刷 |
hCursor | 设定光标进入窗口时的形状,可以自定义,也可以设置为NULL然后指定系统中形状 |
lpszMenuName | 应用程序菜单名 |
lpszClassName | 应用程序类名,可作为窗口类的标识 |
创建窗口调用的函数是
HWND CreateWindowEx(
DWORD dwExStyle, // extended window style
LPCTSTR lpClassName, // pointer to registered class name
LPCTSTR lpWindowName, // pointer to window name
DWORD dwStyle, // window style
int x, // horizontal position of window
int y, // vertical position of window
int nWidth, // window width
int nHeight, // window height
HWND hWndParent, // handle to parent or owner window
HMENU hMenu, // handle to menu, or child-window identifier
HINSTANCE hInstance, // handle to application instance
LPVOID lpParam // pointer to window-creation data
);
其中第一个参数指定了窗口创建的扩展样式。第二个参数为已经注册窗口类的类名。第三个参数为窗口名。第四个参数为窗口创建的样式。第五到第八个参数指定窗口的位置,可以使用默认值CW_USEDEFAULT。第九个参数为父窗口句柄。第十个参数为菜单栏句柄。第十一个参数为应用程序实例句柄。第十二个参数为可以通过一个指针来传递窗口创建参数。
窗口显示和更新使用的函数分别为:
::ShowWindow(hWnd,SW_SHOW);
::UpdateWindow(hWnd);
对于消息循环,我们只需把下面的程序片烂熟与心即可
MSG msg;
while (GetMessage(&msg, NULL, NULL, NULL))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
GetMessage用于从系统消息队列中取出消息,TranslateMessage用于翻译消息,DispatchMessage用于把消息传进窗口消息队列中。
还用一个很重要的只是点,就是窗口过程处理函数,它的格式为
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
WndProc为自定义的函数名,须和注册窗口类时使用的函数名一致。第一个参数为窗口句柄,表示消息从哪个窗口发出,第二个参数为具体的消息值,第三个和第四个参数为消息的附加参数。
一般而言,我们为了处理消息时能根据不同的消息做出不同的响应,在窗口过程函数中通常采用一个switch case的函数结构。
为了便于读者理解消息处理的过程,下图形象地展示了出来
(引用于http://blog.csdn.net/sshhbb/article/details/6076156)
好了,到此为止我们已经把win32的helloworld讲完了,下面是这个程序的代码:
#include<Windows.h>
#include"tchar.h"
//消息处理函数
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CLOSE:
::DestroyWindow(hWnd);
break;
case WM_DESTROY:
::PostQuitMessage(0);
break;
}
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}
int WINAPI _tWinMain(IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPTSTR lpCmdLine, IN int nShowCmd)
{
const TCHAR* pszClassName = _T("ITWnd");
WNDCLASSEX wcex;
//wcex.cbClsExtra = 0;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = (HICON)::LoadIcon(NULL,IDI_QUESTION);
wcex.hIconSm = (HICON)::LoadIcon(NULL, IDI_QUESTION);
wcex.hbrBackground =(HBRUSH) GetStockObject(GRAY_BRUSH);
wcex.hCursor = (HCURSOR)::LoadCursor(NULL,IDC_ARROW);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = pszClassName;
BOOL bRet=::RegisterClassEx(&wcex);
if (!bRet)
{
MessageBox(NULL,_T("註冊窗口類失敗"),_T("註冊窗口"),0);
return FALSE;
}
//非进队消息
HWND hWnd = CreateWindowEx(0,pszClassName,_T("IT學吧"),WS_VISIBLE|WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,//位置
NULL/*父窗口*/,NULL/*菜單句柄*/,hInstance/*當前實例句柄*/,NULL);
if (NULL == hWnd)
{
MessageBox(NULL,_T("创建窗口失败"),_T("创建窗口"),0);
return FALSE;
}
::ShowWindow(hWnd,SW_SHOW);
::UpdateWindow(hWnd);
MSG msg;
while (GetMessage(&msg, NULL, NULL, NULL))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return TRUE;
}
希望该篇文章对读者有一定的启发,好了我们下篇见~~