令人难以置信的是,您可以在上面的文章中阅读多少误导性信息......
甚至在 microsoft msdn 文档中也声称 IsBadPtr 被禁止。哦,好吧 - 我更喜欢工作应用程序而不是崩溃。即使长期工作可能无法正常工作(只要最终用户可以继续使用应用程序)。
通过谷歌搜索,我没有找到任何有用的 windows 示例 - 找到了 32 位应用程序的解决方案,
http://www.codeproject.com/script/Content/ViewAssociatedFile.aspx?rzp=%2FKB%2Fsystem%2Fdetect-driver%2F%2FDetectDriverSrc.zip&zep=DetectDriverSrc%2FDetectDriver%2Fsrc%2FdrvCppLib%2Frtti.cpp&obid=58895&obtid=2&ovid=2
但我还需要支持 64 位应用程序,所以这个解决方案不适合我。
但我已经收获了 wine 的源代码,并设法编写了同样适用于 64 位应用程序的类似代码 - 在此处附加代码:
#include <typeinfo.h>
typedef void (*v_table_ptr)();
typedef struct _cpp_object
{
v_table_ptr* vtable;
} cpp_object;
#ifndef _WIN64
typedef struct _rtti_object_locator
{
unsigned int signature;
int base_class_offset;
unsigned int flags;
const type_info *type_descriptor;
//const rtti_object_hierarchy *type_hierarchy;
} rtti_object_locator;
#else
typedef struct
{
unsigned int signature;
int base_class_offset;
unsigned int flags;
unsigned int type_descriptor;
unsigned int type_hierarchy;
unsigned int object_locator;
} rtti_object_locator;
#endif
/* Get type info from an object (internal) */
static const rtti_object_locator* RTTI_GetObjectLocator(void* inptr)
{
cpp_object* cppobj = (cpp_object*) inptr;
const rtti_object_locator* obj_locator = 0;
if (!IsBadReadPtr(cppobj, sizeof(void*)) &&
!IsBadReadPtr(cppobj->vtable - 1, sizeof(void*)) &&
!IsBadReadPtr((void*)cppobj->vtable[-1], sizeof(rtti_object_locator)))
{
obj_locator = (rtti_object_locator*) cppobj->vtable[-1];
}
return obj_locator;
}
下面的代码可以检测指针是否有效,你可能需要添加一些NULL检查:
CTest* t = new CTest();
//t = (CTest*) 0;
//t = (CTest*) 0x12345678;
const rtti_object_locator* ptr = RTTI_GetObjectLocator(t);
#ifdef _WIN64
char *base = ptr->signature == 0 ? (char*)RtlPcToFileHeader((void*)ptr, (void**)&base) : (char*)ptr - ptr->object_locator;
const type_info *td = (const type_info*)(base + ptr->type_descriptor);
#else
const type_info *td = ptr->type_descriptor;
#endif
const char* n =td->name();
这从指针获取类名 - 我认为它应该足以满足您的需求。
我仍然担心的一件事是指针检查的性能 - 在上面的代码片段中,已经进行了 3-4 个 API 调用 - 对于时间关键的应用程序来说可能是多余的。
如果有人可以测量指针检查的开销,例如与 C#/托管 c++ 调用相比,那就太好了。