这是今天做一个邮件发送模块把一个类包装成Win32 API形式调用时想到的。简单的实现了一下句柄的概念,对于理解内核对象和句柄的概念有一定帮助,看起来还颇像那么回事,呵呵。不过这里的“句柄表”是借助了TLS实现的。
值得一提的是,这个小例子也实现了引用计数的概念,就像线程一样,刚创建时,线程对象的句柄计数是2,因此要CloseHandle一次。下次需要句柄需要重新OpenThread。这里的对象句柄的引用计数也是2,因此刚创建的句柄关掉后,对象不会被删除。当计数递减到1时就删除这个对象。下面是例子的源码:
#include <Windows.h>
#include <stdio.h>
#include <list>
using namespace std;
#pragma warning(disable:4996)
class TEST
{
public:
TEST(LPCSTR lpName)
{
refCount = 2;
x = 0;
strcpy(name, lpName);
printf(“X value is %d \n”, x);
}
~TEST()
{
printf(“Destructor \n”);
}
void EditX(DWORD value)
{
x = value;
}
public:
DWORD refCount;
char name[10];
DWORD x;
};
list<TEST *> Obj;
HANDLE WINAPI Create(LPCSTR lpName)
{
DWORD index = TlsAlloc();
if (index == TLS_OUT_OF_INDEXES)
{
return NULL;
}
TEST *p = new TEST(lpName);
Obj.push_back(p);
if (!TlsSetValue(index, p))
{
return NULL;
}
return (HANDLE)index;
}
HANDLE WINAPI Open(LPCSTR lpName)
{
for (list<TEST *>::iterator it = Obj.begin(), end = Obj.end(); it != end; ++it)
{
if (0 == strcmp((*it)->name, lpName))
{
DWORD index = TlsAlloc();
if (index == TLS_OUT_OF_INDEXES)
{
return NULL;
}
if (!TlsSetValue(index, *it))
{
return NULL;
}
(*it)->refCount++;
return (HANDLE)index;
}
}
return NULL;
}
BOOL WINAPI Close(HANDLE h)
{
TEST *p = (TEST *)TlsGetValue((DWORD)h);
if (--(p->refCount) == 0)
{
for (list<TEST *>::iterator it = Obj.begin(), end = Obj.end(); it != end; /*nothing*/)
{
if (0 == strcmp((*it)->name, p->name))
{
Obj.erase(it++);
}
else
{
++it;
}
}
delete p;
}
TlsFree((DWORD)h);
return TRUE;
}
BOOL WINAPI Edit(HANDLE h, DWORD value)
{
TEST *p = (TEST *)TlsGetValue((DWORD)h);
if (p == NULL)
{
return FALSE;
}
p->EditX(value);
printf(“X value is %d \n”, p->x);
return TRUE;
}
int main()
{
HANDLE h = Create(“Gooleer”);
if (h != NULL)
{
Edit(h, 1);
Close(h);
}
Edit(h, 2);
h = Open(“Gooleer”);
if (h != NULL)
{
Edit(h, 3);
Close(h);
}
return 0;
}