小心,进程句柄!
//=====================================================================
//TITLE:
// 小心,进程句柄!
//AUTHOR:
// norains
//DATE:
// Friday 20-August-2010
//Environment:
// NULL
//=====================================================================
最近在调试一个跨平台的界面库,突然发现,一直显示得很好的图片,居然在Windows CE6.0里面哑火了!出问题的是这行代码:
调用GetLastError,根据返回的数值确认是句柄有误。句柄有误?奇了怪了。要知道,这行代码已经已经在Windows CE 5.0和Windows XP这两个架构不同的系统测试过,完全是正常的,怎么一到Windows CE 6.0就哑火了?再仔细查看,发现问题出在于GetModuleHandle函数!
在说这问题之前,我们先看看程序的入口函数WinMain:
我们只需要注意第一个形参hInstance,这个是进程的句柄。问题点就来了,在Windows CE 5.0和Windows XP中,调用GetModuleHandle(NULL)的返回值,和hInstance的数值是完全相同的;而对于Windows CE 6.0,情况就截然相反,返回的是一个不知道从哪里来的数值,该数值和hInstance根本扯不上边。如果将GetModuleHandle(NULL)用hInstance的数值代替,比如:
那么在Windows CE 6.0中就能正常。
那么,究竟Windows CE 6.0中,GetModuleHandle(NULL)返回的是个什么东西?查看MSDN,发现有这么一段描述:If this parameter is NULL, GetModuleHandle returns the process identifier of the calling process.
如果是Windows CE 5.0,则是另外的解释:If this parameter is NULL, GetModuleHandle returns a handle to the file used to create the calling process.
结果很明显,在Windows CE 5.0中,当GetModuleHandle的形参为NULL时,返回的是进程的实例句柄,而在Widows CE 6.0,返回的却是进程的ID!似乎一切都迎刃而解了,但实际上还没完。在Windows CE 6.0中,虽然说返回的是进程ID,但这个ID却不知道用在何处!因为如果直接将这返回值赋予OpenProcess,那么函数调用失败,因为GetModuleHandle的返回值和GetProcessID返回的截然不同,而后者却是能用于OpenProcess中!那么,究竟在Windows CE 6.0中的GetModuleHandle(NULL)返回值有何作用?我也不知道。如果读者大人您知道,麻烦一定要告诉我。
先不讨论GetModuleHandle(NULL)的作用,我们还是先想想如何获得进程的实例句柄吧。难道我们一定要在WinMain函数中用一个全局变量保存hInstance数值,然后在整个程序中都用该全局变量?其实可以不用那么复杂,我们只要用GetCurrentProcessId替代就好。比如,之前的图片读取,可以如此:
但是这行代码只能在Windows CE 5.0和Windows CE 6.0中运行,如果是放到Windows XP中则又是一个哑火,因为GetCurrentProcessId在Windows XP中的返回值并不是hInstance所代表的数值。
最后,让我们以如下列表看看不同函数在不同系统中调用的迥异吧:
代码 |
WINCE5.0 |
WINCE6.0 |
WINXP |
hInstance |
0x63ab5fbe |
0x050d001a |
0x00400000 |
hGetModuleHandle = GetModuleHandle(NULL) |
0x63ab5fbe |
0x00000042 |
0x00400000 |
hGetCurrentProcess = GetCurrentProcess() |
0x00000042 |
0x00000042 |
0xffffffff |
dwGetCurrentProcessId = GetCurrentProcessId() |
0x63ab5fbe |
0x050d001a |
0x00001768 |
hOpenProcess_GetModuleHandle = OpenProcess(0, FALSE, (DWORD)hGetModuleHandle) |
0x63ab5fbe |
0x00000000 |
0x00000000 |
hOpenProcess_GetCurrentProcessId = OpenProcess(0, FALSE, dwGetCurrentProcessId) |
0x63ab5fbe |
0x004d4103 |
0x00000000 |
该表格的测试代码如下:
当然,还少不了实际调试时的IDE截图。
首先是Windows CE 6.0:
其次是Windows CE 5.0:
最后是Windows XP:
最后的最后,还是再一次看看LoadBitmap的调用。其实对于Windows CE 6.0,我们设置可以不用实例句柄,直接用NULL即可:
不过呢,这样的调用方式在不同系统又有不同表现哦,如下表所示:
系统 |
LoadBitmap(NULL,MAKEINTRESOURCE(IDB_BITMAP1)) |
Windows XP |
返回NULL,error code为1814,找不到映像文件中指定的资源名。 |
Windows CE 5.0 |
返回NULL,error code为6,句柄无效。 |
Windows CE 6.0 |
调用成功,能够正常获得图像句柄 |