再论句柄(HANDLE) 再论大白鹅的战斗力

//jiachao Ren Ideas

是时候讨论句柄是什么了?当然真正清楚的是微软,我就是猜猜,呵呵。

不妥的说法:

1.句柄是一个指针,指向它标识的资源。

2.句柄是指向指针的指针…

这样的说法不如说句柄就是一个资源的标识更准确,因为句柄不是指针。

来看看:VC6 winnt.h头文件中的一段内容:

#ifdef STRICT

typedef void*HANDLE;

#define DECLARE_HANDLE(name) structname##__ { int unused; }; typedef struct name##__*name

#else

typedef PVOIDHANDLE;

#define DECLARE_HANDLE(name) typedefHANDLE name

#endif

typedef HANDLE*PHANDLE;

多么的让人联想到句柄是指针啊,呵呵,不要看表面。我在C语言课中讲过这个问题,这里重新再拿出来说说,这里含有一个非常牛的技巧,是的,就像STL的萃取机一样精彩。

现在环境是这样的,要定义一个数据类型,它需要满足几个基本要求:

1.可以标识一个资源。(当然整数很不错)

2.需要有层次结构,这个很重要。因为HINSTANCE就是HANDLE,HBITMAP(位图句柄),HDC(设备描述表句柄),HICON(图标句柄)等等,这些就是HANDLE。不理解的话,鸡、鸭、鹅这些都是家禽,一个道理。对,就像类继承一样,是ISA的关系。

好了越来越有眉目了。通过上述1,2我们排除了类对象,因为它不是一个简单是数字,它太高级在底层代码中并不适用。

于是我们选择了指针,这个好,因为我们都知道,int*也是void*,float*,char*都是void*(void*理解为一个单纯的指针,当然指向特定类型的指针ISA 指针)。

但是,如果这样,各种资源的标识就能互相转换了,很不安全。现在似乎想想可以理解了:

typedef void*HANDLE;

#define DECLARE_HANDLE(name) structname##__ { int unused; }; typedef struct name##__*name

那么HINSTANCE就是structHINSTANCE__*,HBITMAP就是struct HBITMAP__*,它们当然都是HANDLE,因为HANDLE是void*,都能转成HANDLE,且互相不可转换!

所以,不要认为句柄是指针,它是开发者利用一个技巧而实现的一个具有上述特性的“新类型”,就叫它句柄吧,它能唯一标识一个资源(别忘了我曾经说的,句柄是进程的,不多解释)。

好了,下面研究“伪句柄”和“真正的句柄”,在使用标识内核对象的句柄的时候,我们可能遇到这样的名词。

测试实例1:

//这两个宏可能并不好,但是最近要测试好多多线程的例子,这么写我能省去很多“体力”,呵呵。

#define ThreadProc(funName) DWORDWINAPI funName(LPVOID param)

#define ThreadProcEx(funName,paramName) DWORD WINAPI funName(LPVOID paramName)

void FileTimeShowSystemTime(constFILETIME *pft){

FILETIME localFileTime;

FileTimeToLocalFileTime(pft,&localFileTime);

SYSTEMTIME st;

FileTimeToSystemTime(&localFileTime,&st);

cout<<st.wHour<<":"<<st.wMinute<<":"<<st.wSecond;

}

ThreadProc(ChildThread);

ThreadProc(ParentThread){

HANDLE hParent = GetCurrentThread();

FILETIME creationTime, exitTime, kernelTime,userTime;

GetThreadTimes(hParent, &creationTime,&exitTime, &kernelTime,&userTime);

FileTimeShowSystemTime(&creationTime);

cout<<endl;

Sleep(5000);

HANDLE h = BEGINTHREADSIMPLE(ChildThread,hParent);

CloseHandle(h);

return 0;

}

ThreadProc(ChildThread){

FILETIME creationTime, exitTime, kernelTime,userTime;

GetThreadTimes((HANDLE)param, &creationTime,&exitTime, &kernelTime,&userTime);

FileTimeShowSystemTime(&creationTime);

cout<<endl;

return 0;

}

int main(int argc, char*argv[])

{

FILETIME creationTime, exitTime, kernelTime,userTime;

GetThreadTimes(GetCurrentThread(), &creationTime,&exitTime, &kernelTime,&userTime);

FileTimeShowSystemTime(&creationTime);

cout<<endl;

Sleep(5000);

HANDLE h = BEGINTHREADSIMPLE(ParentThread, NULL);

CloseHandle(h);

while(1){}

return 0;

}

程序结果:

14:50:51

14:50:56

14:51:1

很显然我们在ChildThread中没有得到ParentThread的CreateTime,这时就是伪句柄在作怪了:

注意:GetCurrentThread()、GetCurrentProcess() 所获得的句柄就是伪句柄,我们可以这么像,他们得到的不是句柄而是一个许可证,当亮出这个许可证的时候上下文环境就会认为这是一个标识着当前线程的句柄。所以无论我们把这个许可证传到哪里,得到的都是当前线程的句柄。在这个例子中就是ChildThread的句柄。

如何获得真实的句柄呢?也非常容易,见下面的例子:

//把ParentThread、ChildThread作如下修改:

ThreadProc(ParentThread){

HANDLE hParent;

DuplicateHandle(GetCurrentProcess(),GetCurrentThread(), GetCurrentProcess(), &hParent,0, FALSE, DUPLICATE_SAME_ACCESS);

FILETIME creationTime, exitTime, kernelTime,userTime;

GetThreadTimes(GetCurrentThread(), &creationTime,&exitTime, &kernelTime,&userTime);

FileTimeShowSystemTime(&creationTime);

cout<<endl;

Sleep(5000);

HANDLE h = BEGINTHREADSIMPLE(ChildThread,hParent);

CloseHandle(h);

return 0;

}

ThreadProc(ChildThread){

FILETIME creationTime, exitTime, kernelTime,userTime;

GetThreadTimes((HANDLE)param, &creationTime,&exitTime, &kernelTime,&userTime);

FileTimeShowSystemTime(&creationTime);

cout<<endl;

CloseHandle((HANDLE)param);//关闭拷贝出的真实的句柄。

return 0;

}

程序结果为:

15:25:26

15:25:31

15:25:31

符合逻辑

//当然DuplicateHandle调用起来也比较复杂可以利用一个简单的宏做一些常规调用时的简化,这样就可以方便的调用GetRealHandle(&hParent,GRH_THREADHANDLE); 当然如果需要设置句柄继承和权限的话还是需要调用DuplicateHandle传入一些相关参数。

#define GRH_PROCESSHANDLE0

#define GRH_THREADHANDLE1

#define GetRealHandle(pHandle, type)DuplicateHandle(

GetCurrentProcess(),

(type==GRH_PROCESSHANDLE)?GetCurrentProcess():((type==GRH_THREADHANDLE)?GetCurrentThread():INVALID_HANDLE_VALUE),

GetCurrentProcess(),

&hParent,

0,

FALSE,

DUPLICATE_SAME_ACCESS)

先到这里,希望对大家有帮助,By Jiachao Ren2011-7-6

附:

注意事项

   内核对象句柄,是用来标识某个内核对象的一个ID同一个对象的该ID对于每个进程是不同的(句柄是进程的),具体如何实现是Microsoft不公开的算法,以下是一个近似的,可能的算法:

  进程创建时,windows系统为进程构造了一个句柄表

  当该进程希望获得一个内核对象句柄或者创建一个内核对象从而获得该对象句柄时

  系统会将在句柄表中增加一个表项,表项的内容中存储了指向目标内核对象的指针

  同时,系统返回这个表项在句柄表中的索引作为句柄(句柄不是指针,更可能是一个Index)

  

爱华网本文地址 » http://www.413yy.cn/a/25101014/202694.html

更多阅读

大白鱼的做法 精 兴凯湖大白鱼的做法

大白鱼的做法 精——简介白鱼翘嘴红鲌,色白如玉,俗称大白鱼,是四大并有淡水鱼之一,肉嫩味香益并具有补肾益脑、开窍利尿药用价值.大白鱼是淡水经济鱼类,成群栖息于淡水上层,体形长、侧扁,口大、斜或上翘,腹面全部或后部具肉棱,背鳍具硬刺

六论大牛市已经启动------周洛华 启动香港牛市

六论大牛市已经启动2010-10-25 来源: 上海证券报周洛华上篇五论大牛市的专栏见报后,不少读者反映说没有看懂有关波动率平价原理的内容。我感觉这是我的错,因为金融学的任何一个概念,如果别人没有听懂,那只说明你没有说清楚。因此我

编程中句柄的意思是什么 句柄无效是什么意思

所谓句柄实际上是一个数据,是一个Long (整长型)的数据。 句柄是WINDOWS用来标识被应用程序所建立或使用的对象的唯一整数,WINDOWS使用各种各样的句柄标识诸如应用程序实例,窗口,控制,位图,GDI对象等等。WINDOWS句柄有点象C语言中的文件句

再读《论雷峰塔的倒掉》 论雷峰塔的倒掉赏析

风风雨雨雷峰塔 上学时,就曾学过鲁迅先生的《论雷峰塔的倒掉》,很是羡慕先生的文笔以及阅历,怎么知道那么多的故事典故?从此,我知道了杭州的西湖和镇压白娘子的雷峰塔,以及白娘子凄美的爱情故事。今天重读这篇文章,仍然心潮澎湃,不禁为雷峰

声明:《再论句柄(HANDLE) 再论大白鹅的战斗力》为网友色混是命分享!如侵犯到您的合法权益请联系我们删除