1.2句柄及 WinMain函数

来源:互联网 发布:淘宝商品被下架 编辑:程序博客网 时间:2024/05/07 08:10
***********************************************
*  本文由小鸟飞飞整理发表 <samboy@sohu.com>  *
*  首发网站:蓝丽网              *
*  其他网站转载请保留以上信息,谢谢!     *
************************************************
关 于句柄
  在Windows编程中我们时刻接触到一个称为句柄(HANDLE)的东西。可以这样去理解句柄,Windows程序中产生的任何资源 (要占用某一块或大或小的内存),如图标,光标,窗口,应用程序的实例(已加载到内存运行中的程序)。操作系统每产生一个这样的资源时,都要将它们放入相 应的内存,并为这些内存指定一个唯一的标识号,这个标识号即该资源的句柄。

  操作系统要管理和操作这些资源,都是通过句柄来找到对应的 资源的。按资源的类型,又可将句柄细分成图标句柄(HICON),光标句柄(HCURSOR),窗口句柄(HWND),应用程序实例句柄 (HINSTANCE),等等各种类型的句柄。操作系统给每一个窗口指定的一个唯一的标识号即窗口句柄。

WinMain函数
   WinMain是Windows程序的入口点函数,同dos程序的入口点函数main的作用相同,当WinMain函数结束或返回时,Windows应用 程序结束。WinMain函数的原型如下:

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
);

  该函数接受四个参数,这些参数都 是系统调用WinMain函数时,传递给应用程序的。

  第一个参数hInstance表示该程序的当前运行的实例句柄。同一应用程序在 同一计算机上可运行多份实例,每启动一个这样的实例,操作系统都要给该实例分配一个标识号,即实例句柄,随后系统调用程序中的WinMain函数,并将该 实例句柄传递给参数hInstance。

  第二个参数hPrevInstance表示当前实例的上一个正在运行的,由同一个应用程序所 产生的实例的句柄,即当前实例的"哥哥"的句柄。如果该值为NULL,则表示当前实例是该程序正在运行的第一份实例,是“长子”,是“老大”。如果该值不 为NULL,只能表示当前实例不是该程序正在运行的第一份实例,不是“长子”,不是“老大”,但到底是“老几”,就无从得知了。这个参数到底有什么作用 呢?如果想让我们的程序只能有一份实例运行,不能同时有多份实例运行,我们可以在WinMain函数的开始部分加上如下代码实现。

if(hPrevInstance) return 0;

  我们再来看看if(hPrevInstance) return 0;的作用,如果hPrevInstance为NULL(即0),说明当前运行的实例是程序的第一个实例,WinMain函数将不返回,程序正常向下运 行。只要hPrevInstance不为NULL,说明已经有同样程序的实例在运行,WinMain函数将返回,当前实例启动后立马结束,这样就保证了只 有程序的一个实例可以运行。

  第三个参数lpCmdLine是一个字符串,里面包含有传递给应用程序的参数串,如:双击C盘下的 1.txt文件方式启动notepad.exe程序,传递给notepad.exe程序的参数串即"c:\1.txt",不包含应用程序名本身。要在VC 开发环境中给应用程序传递参数,请选择菜单Project->Settings...,在弹出的Project Settings对话框中选择Debug标签,在该标签页的Program arguments编辑框中输入你想传递给应用程序的参数。我们在WinMain函数的入口点设置一运行断点,以调试方式启动程序运行至该断点处,将鼠标 移动到参数lpCmdLine上,在弹出的黄色小浮框中便能观察到该变量的值。在我们的程序调试中,经常要用到这种方法查看变量的值和状态。

   第四个参数nCmdShow指定的程序的窗口应该如何显示,如最大化,最小化,隐藏等。

  WinMain函数前的修饰符WINAPI 的解释,我们使用goto definition功能,发现WINAPI其实就是__stdcall。

  __stdcall与 __cdecl是两种不同的函数调用习惯,定义了参数的传递顺序、堆栈清除等。关于它们的详细信息请参看msdn。由于除了那些可变参数的API函数外, 其余的API函数都是__stdcall习惯。由于VC++程序默认的编译选项是__cdecl,所以在VC++中调用这些__stdcall习惯的 API函数,必须在声明这些函数的原型时加上__stdcall修饰符,以便对该函数的调用使用__stdcall习惯。我们曾有这样的经验,在 Delphi(默认的编译选项是__stdcall)中编写的dll中的函数,在VC++中被调用时,总是造成程序崩溃,在函数的原型声明中加上 __stdcall修饰符,便解决了这个问题。回调函数也必须是__stdcall调用习惯,在这里是用CALLBACK来标识的,否则,在NT4.0环 境,程序将崩溃,但win98和win2000却没有这种现象。

  Winmain函数的程序代码按功能划分主要有两部分:1.产生并显 示程序的主窗口。窗口创建并显示后,用户便可以在窗口上进行各种操作了,用户的操作及程序状态的变化都以消息的形式放到了应用程序的消息队列中。2.从消 息队列循环取走消息,并将消息派发到窗口过程函数中去处理。当消息循环取到一条WM_QUIT消息时,将结束循环,WinMain函数返回,结束整个程序 的运行。
如果WinMain在消息循环之前返回,程序没有正常运行,返回值为0。如果在消息循环之后返回,返回值为WM_QIUT消息的 wParam参数。
0 0
原创粉丝点击