Win32开发流程(完整)

本文详细介绍了Win32应用程序开发的基本流程,包括WinMain入口点、窗口类设计与注册、窗口创建与显示、消息循环和消息响应。通过一个简单的示例,解释了创建窗口类、注册窗口类、创建和显示窗口、处理消息等关键步骤,帮助读者理解Windows编程的基础知识。
摘要由CSDN通过智能技术生成

编写一个Win32应用程序的大致流程,不管你的程序有多么复杂,多么变态,其基本思路和流程是不变的。这就好比你写书法的时候,特别是写楷书,我不管你用的是欧体、颜体,还是柳体,你都得遵守“永字八法”基本规则。

那么,我们要编写一个Win32应用程序,要经过哪几个步骤呢?

你不妨想一想,你有一家工厂是生产女性服装的,如果你要生产一批新式服装(例如某种冬装),你会有哪些流程?

首先,如果我们确定要做这么一款服式,我们要请设计师来把服装设计好,然后打版,打版就是生成基本样本,以后工人就按照这个样本做就行了。

其次,注册产品,向上级主管申报,登记后就转入车间或下游加工企业开工。

再次,为了展示你的新产品的特色,你要举办一场服装表演。

接着、持续更新,发现产品存在的问题,不断改进修正。

最后,推向市场。

我们开发Win32应用程序也是遵守这样的规范。不过,我想现在很少人用Win32在实际开发中,毕竟它的开发效率是相当地低下,所以,曾被某些人误认为只适用于开发木马程序。其实,也不一定的,不要太邪恶了。

MFC对Win API函数的封装,后来出现了托管C++,你可以用于写WinForm程序,这样可以提高开发效率。

如果你有足够的时间,如果你还在学习编程,如果你是刚进入大学的年轻有为者,你不用急,因为你会有更多的时间磨炼,你应当考虑多学一点C类语言,C++的学习你会发现你能学到很多其他语言中学不到的知识,特别是接触到不少原理性的东西,能加深你对编程哲学的认知。

 

一、WinMain入口点

我们在学习标准C++的时候,都知道每个应用程序运行时都会先进入入口点函数main,而当从main函数跳出时程序就结束了。在Windows编程里面,也是一样的,只是我们的入口点函数不叫main,叫WinMain,这个函数不同于main,我们不能乱来,它的定义必须与声明保持一致。

我建议各位安装VS的时候,都顺便更新帮助文档到本地硬盘,这样我们可以方便查找。有一点要注意,目前DestTop Develop的文档基本上是英文的,做好心理准备。

WinMain函数怎么写呢,不用记的,到MSDN文档一搜,直接复制就行了。

  1. int CALLBACK WinMain(  
  2.     _In_  HINSTANCE hInstance,  
  3.     _In_  HINSTANCE hPrevInstance,  
  4.     _In_  LPSTR lpCmdLine,  
  5.     _In_  int nCmdShow  
  6.   );  


这个函数带了一个CALLBACK,说明它是一个回调函数,那么这个CALLBACK是啥呢。我们先不管,我们先动写一个Windows,让大家有一个更直观的认识。

1、启动你的开发工具,版本任意。

2、从菜单栏中依次【文件】【新建】【项目】,在新建项目窗口中,选择Win32-Win32应用程序。

 

2、点击确定后,会弹出一个向导,单击【下一步】。项目类型选择Windows应用程序,附加选项选择空项目,我们要自己编写实现代码。

 

3、单击完成,项目创建成功。打开【解决方案资源管理器】,在“源文件”文件夹上右击,从菜单中找到【添加】【新建项】,注意,是源文件,不要搞到头文件去了。

在新建项窗口中选C++代码文件,.cpp后缀的,不要选错了,选成头文件,不然无法编译,因为头文件是不参与编译的。文件名随便。

 

包含Windows.h头文件,这个是最基本的。

  1. #include <Windows.h>  


然后是入口点,这个我们直接把MSDN的声明Ctrl + C,然后Ctrl + V上去就行了。

  1. int CALLBACK WinMain(  
  2.     _In_  HINSTANCE hInstance,  
  3.     _In_  HINSTANCE hPrevInstance,  
  4.     _In_  LPSTR lpCmdLine,  
  5.     _In_  int nCmdShow  
  6.   )  
  7. {  
  8.   
  9.     return 0;  
  10. }  


WinMain返回整型,返回0就行了,其实是进程的退出码,一定要0,不要写其他,因为0表示正常退出,其他值表示非正常退出。

刚才我们提到这个函数带了CALLBACK,那么,它是什么?很简单,你回到IDE,在CALLBACK上右击,选【转到定义】,看看吧。

我们看到它其实是一个宏,原型如下:

  1. #define CALLBACK    __stdcall  

这时候我们发现了,它其实就是__stdcall,那么这个__stdcall是什么呢?它是和__cdecl关键字对应的,这些资料,你网上搜一下就有了,如果你觉得不好理解,你不妨这样认为,__stdcall是专门用来调用Win API 的,反正MSDN上也是这样说的,它其实是遵循Pascal的语法调用标准,相对应地,__cdecl是C语言的调用风格,这个也是编译器选项。
打开项目属性,找到节点C/C++\高级,然后查看一下调用约定,我们看到默认是选择C风格调用的,所以,WIN API 函数才用上关键字__stdcall,如果你实在不懂,也没关系,这个东西一般不影响我们写代码,但属性窗口中的编译器选项不要乱改,改掉了可能会导致一些问题。

 

那么CALLBACK有什么特别呢?一句话:函数不是我们调用的,但函数只定义了模型没有具体处理,而代码处理权在被调用者手里。怎么说呢,我们完全把它理解为.NET中的委托,我想这样就好理解了,委托只声明了方法的参数和返回值,并没有具体处理代码。

WinMain是由系统调用的,而WinMain中的代码如何写,那操作系统就不管了。就好像我告诉你明天有聚会,一起去爬山,反正我是通知你了,至于去不去那是你决定了。

接下来看看入口点函数的参数。

注意,我们平时看到很多如HANDLE,HINSTANCE,HBRUSH,WPARAM。LPARAM,HICON,HWND等一大串数据类型,也许我们会说,怎么Windows开发有那么多数据类型。其实你错了,人总是被眼睛所看到的东西欺骗,Win API 中根本没有什么新的数据类型,全都是标准C++中的类型,说白了,这些东西全是数字来的。如果你不信,自己可以研究一下。

它定义这些名字,只是方便使用罢了,比如下面这样:

  1. int hWindow;  
  2. int hIcon;  
  3. int theAppInstance;  

第一个变量指的是窗口的句柄,第二个指的是一个图标的句柄,第三个是当前应用程序的实例句柄,你看看,如果我们所有的句柄都是int,我们就无法判断那些类型是专门用来表示光标资源,不知道哪些类型是专用来表示位图的句柄了,但是,如果我们这样:

  1. #defin HBRUSH  int64  

这样就很直观,我一看这名就知道是Brush Handlers,哦,我就明白它是专门用来管理内存中的画刷资源的,看,这就很明了,所以,通常这些新定义的类型或者宏,都是取有意义的名字。比如消息,它也是一个数字,如果我说115代表叫你去滚,但光是一个115谁知道你什么意思,但是,如果我们为它定义一个宏:

  1. #define WM_GET_OUT    115  

这样,只要我SendMessage(hwnd,  WM_GET_OUT, NULL, NULL),你就会收到一条消息,滚到一边去。

 

WinMain的第一个参数是当前应用程序的实例句柄,第二个参数是前一个实例,比如我把kill.exe运行了两个实例,进程列表中会有两个kill.exe,这时候第一次运行的实例号假设为0001,就传递第一个参数hInstance,第二次运行的假设实例号为0002,就传给了hPrevInstance参数。

lpCmdLine参数从名字上就猜到了,就是命令行参数,那LPSTR是啥呢,它其实就是一个字符串,你可以跟入定义就知道了,它其实就是char*,指向char的指针,记得我上一篇文章中说的指针有创建数组的功能吗?对,其实这里传入的命令行参数应该是char[ ],这就是我在第一篇文章中要说指针的原因。

这里告诉大家一个技巧,我们怎么知道哪些参数是指针类型呢,因为不是所有参数都有 * 标识。技巧还是在命名上,以后,只要我们看到P开头的,或者LP开头的,都是指针类型

比如LPWSTR,LPCTSTR,LPRECT等等。

最后一个参数nCmdShow是主窗口的显示方式。它定义了以下宏。

Value Meaning
SW_HIDE 0

Hides the window and activates another window.

SW_MAXIMIZE 3

Maximizes the specified window.

SW_MINIMIZE 6

Minimizes the specified window and activates the next top-level window in the Z order.

SW_RESTORE 9

Activates and displays the window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when restoring a minimized window.

SW_SHOW 5

Activates the window and displays it in its current size and position.

SW_SHOWMAXIMIZED 3

Activates the window and displays it as a maximized window.

SW_SHOWMINIMIZED 2

Activates the window and displays it as a minimized window.

SW_SHOWMINNOACTIVE 7

Displays the window as a minimized window. This value is similar toSW_SHOWMINIMIZED, except the window is not activated.

SW_SHOWNA 8

Displays the window in its current size and position. This value is similar toSW_SHOW, except the window is not activated.

SW_SHOWNOACTIVATE 4

Displays a window in its most recent size and position. This value is similar toSW_SHOWNORMAL, except the window is not activated.

SW_SHOWNORMAL 1

Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time.


这个参数是操作系统传入的,我们无法修改它。那么,应用程序在运行时,是如何决定这个参数的呢?看看这个,不用我介绍了吧,你一定很熟悉。


我们写了WinMain,但我们还要在WinMain前面预先定义一个WindowProc函数。C++与C#,Java这些语言不同,你只需记住,C++编译器的解析是从左到右,从上到下的,如果某函数要放到代码后面来实现,但在此之前要使用,那么你必须先声明一下,不然编译时会找不到。这里因为我们通常会把WindowProc实现放在WinMain之后,但是在WinMain中设计窗口类时要用到它的指针,这时候,我们必须在WinMain之前声明WindowProc。

同样地,WindowProc的定义我们不用记,到MSDN直接抄就行了。

  1. #include <Windows.h>  
  2. // 必须要进行前导声明  
  3. LRESULT CALLBACK WindowProc(  
  4.     _In_  HWND hwnd,  
  5.     _In_  UINT uMsg,  
  6.     _In_  WPARAM wParam,  
  7.     _In_  LPARAM lParam  
  8. );  
  9.   
  10. int CALLBACK WinMain(  
  11.     _In_  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值