C++ 如何获取指向用于挂接的COM方法的指针?

C++ 如何获取指向用于挂接的COM方法的指针?,c++,winapi,assembly,activex,member-function-pointers,C++,Winapi,Assembly,Activex,Member Function Pointers,我知道这似乎是一个回答过度的问题,但这一个是不同的。 我有一个ActiveX对象,它导出了一些方法。我需要在它的一个方法上设置一个钩子,即Func1,我知道如何使用VirtualProtect(),等等。如果我打开ollydbg并深入ActiveX DLL,我会看到需要设置钩子的Func1的确切地址 使用Visual Studio 2008,我使用的是预编译器指令: #import "myactx.dll" no_namespace, named_guids, raw_interfaces_on

我知道这似乎是一个回答过度的问题,但这一个是不同的。 我有一个ActiveX对象,它导出了一些方法。我需要在它的一个方法上设置一个钩子,即
Func1
,我知道如何使用
VirtualProtect()
,等等。如果我打开ollydbg并深入ActiveX DLL,我会看到需要设置钩子的
Func1
的确切地址

使用Visual Studio 2008,我使用的是预编译器指令:

#import "myactx.dll" no_namespace, named_guids, raw_interfaces_only
在我的代码中,我试图做到这一点:

LPVOID ptr = &IMyActx::Func1;
编译时返回一个错误:

错误C2440:“正在初始化”:无法从“HRESULT(\uu stdcall IMyActx::*)(BSTR,BSTR)”转换为“LPVOID”

我研究并发现,我不能将指向类的指针方法强制转换为指向函数的指针,因为隐式的
这个
参数

但是,我不打算调用此函数。我只想知道它在内存中的地址,这样我就可以把它传递给我的挂钩例程(它需要一个
LPVOID
指针)

在我看来,这似乎是不可思议的,我可以调用一个函数,但不能在内存中获取它的原始地址。它让我想插入一些x86汇编代码,只是为了得到我想要的指针

非常感谢您的建议,谢谢阅读

编辑。。。 现在想想<代码>LPVOID ptr=&IMyActx::Func1不应该工作,因为
IMyActx
是一个纯虚拟类!无论如何,在实例化一个对象并尝试获取指向
Func1
的原始指针之前,我尝试了一些组合,但到目前为止没有任何效果。我在ollydbg中看到,对
Func1
的调用生成为:

mov edx, [eax];
call dword ptr ds:[edx + 0x1C];
因此,我可以假设我需要在
vptr+0x1C
字节处读取
DWORD
,瞧

如果我没有记错的话,组件对象模型保证它将始终是
Func1
ptr,在
[vptr+0x1C]
给定相同的接口ID时,它将永远处于
[vptr+0x1C]
位置。对吧?

我可能会这样做,用一些伪代码:

#define FUNC1_ENTRY   0x1C / sizeof(LPBYTE)

CoCreateInstance(CLSID_MyActx, 0, CLSCTX_ALL, IID_IMyActxObj, (LPVOID*) &pObj);

LPVOID pToHook = (*pObj)[FUNC1_ENTRY];

如果我理解正确,您希望将指向类方法的指针转换为函数指针

这实际上是不可能的

简单的例子:

class A {
    public:
    void func()
    {
        this->var = 0;
    }
    int var;
};

A myObj;
A::func* ptr2 = &(myObj::func); // works
void* ptr = &(myObj::func); // doesn't: what would "this" in line 5 point to?
您甚至不能使用
重新解释\u cast


我也有过这个问题。然后我只需要创建一个函数,将输入值映射到指向对象的指针。也许您可以创建一个包装器函数,在该函数中,您可以通过使用指向该方法的指针来调用该方法。

COM对象的方法实际上是普通函数。这就是使C客户端以C++而不是C++编写的。
我建议为C客户机生成头文件,这样可以很容易地检索函数地址。但是,您首先需要一个要挂接的类的实例。

指向方法的指针和指向函数的指针是不可转换的,因为该标准(故意)不保证方法指针可以存储在void*中。虽然一个简单的函数指针可以存储在一个空的*.Martin reinterpret\u cast中,但编译时返回:
code
error C2440:“reinterpret\u cast”:无法从“HRESULT”(\uu stdcall IMyActx::*)(BSTR,BSTR)转换'到'LPVOID'1>没有可以进行此转换的上下文
code
抱歉,这是一时冲动,尽管我重新确认的是错误的。我把它拿出来,因为它不应该工作。(注意,方法指针可能比普通指针大。因此无法将其转换为void*)。问题不仅在于指针大小,还在于ptm性质。如果它指向一个抽象类的虚拟方法,并且仅当您提供此;)时才调用分派,该怎么办?指向成员的指针根本不是“真正的”内存指针……您在update中描述的解决方案应该可以工作,但看起来相当危险:)几年前,我使用迂回来钩住activex对象。我刚刚使用了ANSI C版本的activex接口(你知道,midl在一个文件中生成两个版本,一个用于C,一个用于C++)。当使用
\uu stdcall
调用约定时,情况会发生变化,因为它适用于所有COM对象方法。使用stdcall的类成员函数是一个普通函数,第一个参数是
this
。(对于使用默认调用约定的成员函数,情况并非如此。)现在,即使成员函数是普通的
\uu stdcall
函数,指向成员函数的指针仍然与函数指针不同,这是正确的。事实上,我不认为有一种简单的语法可以获得一个普通的函数指针,可以读取vtable,也可以通过函数的名称获取函数的地址。COM对象的方法实际上不是普通函数。如果将对象作为C++类实现,则不会有任何“正则”C函数。使用C-client头文件,您不只是获取存根方法的地址吗?不过,这对于OP来说已经足够了。@Andre:它们是使用stdcall调用约定的普通C函数。COM对象只是指向普通C函数指针结构的指针。这就是用非C++语言编写COM服务器的原因。存根仅用于跨进程封送。VisualC++在虚拟代码成员声明为代码>的时候,生成一个与COM ABI相匹配的VTAT是一个愉快的巧合(当然,这是由Visual C++团队有意实现的)。所有COM都是用纯C定义的。