C++ 对类方法的正确约定调用

C++ 对类方法的正确约定调用,c++,windows,visual-studio,visual-c++,calling-convention,C++,Windows,Visual Studio,Visual C++,Calling Convention,我无法使用\u此调用给我以下错误: 错误C4234:使用了非标准扩展名:“\u thiscall”关键字保留供将来使用 我正在从dll调用一个类函数: typedef void(*SETDIRPROC)(void*,D3DXVECTOR3&); void ZMyCharacter_SetDirection_Rev( void ) { if( pZMyCharacter == 0 ) { printf( "cannot set direction now

我无法使用
\u此调用
给我以下错误:
错误C4234:使用了非标准扩展名:“\u thiscall”关键字保留供将来使用

我正在从dll调用一个类函数:

typedef void(*SETDIRPROC)(void*,D3DXVECTOR3&);

void ZMyCharacter_SetDirection_Rev( void )
{
    if( pZMyCharacter == 0 )
    {
        printf( "cannot set direction now\n" );
        return;
    }
    SETDIRPROC SetDir_Proc = (SETDIRPROC)0x004A2AF0;
    D3DXVECTOR3 pos = D3DXVECTOR3(4.0f,2.0f,1.0f);
    SetDir_Proc( pZMyCharacter, pos );
}
pZMyCharacter
是一个
void*
指针,指向实际应用程序上的实际
类ZMyCharacter
。它可以工作,但我得到调试错误(可以忽略)警告,调用约定不同。确实如此,因为默认情况下,
SETDIRPROC
\uu cdecl
,我无法将其更改为
\uu thiscall

typedef void(uu thiscall*SETDIRPROC)(void*,D3DXVECTOR3&)//错误C4234


我该如何处理这个问题呢?

我想应该是这样的:

typedef void(__thiscall &ZMyCharacter::*SETDIRPROC)(D3DXVECTOR3&);
SETDIRPROC SetDir_Proc = (SETDIRPROC)0x004A2AF0;
static_cast<ZMyCharacter*>(pZMyCharacter)->SetDir_Proc( pos );
typedef void(uu thiscall&ZMyCharacter::*SETDIRPROC)(D3DXVECTOR3&);
SETDIRPROC SetDir_Proc=(SETDIRPROC)0x004A2AF0;
静态转换(pZMyCharacter)->SetDir\u进程(pos);

\uu此调用
用于成员函数指针,而不是您声明的自由函数。上面的内容应该更接近编译器需要的内容——成员函数类型强制转换和调用。

我认为应该如下所示:

typedef void(__thiscall &ZMyCharacter::*SETDIRPROC)(D3DXVECTOR3&);
SETDIRPROC SetDir_Proc = (SETDIRPROC)0x004A2AF0;
static_cast<ZMyCharacter*>(pZMyCharacter)->SetDir_Proc( pos );
typedef void(uu thiscall&ZMyCharacter::*SETDIRPROC)(D3DXVECTOR3&);
SETDIRPROC SetDir_Proc=(SETDIRPROC)0x004A2AF0;
静态转换(pZMyCharacter)->SetDir\u进程(pos);

\uu此调用
用于成员函数指针,而不是您声明的自由函数。上面的内容应该更接近编译器需要的内容——成员函数类型强制转换和调用。

这是未经测试的,但应该给您一个开始。请注意,它依赖于MSVC实现细节,因此它不是标准的,在其他编译器中不起作用:

#pragma warning(push)
#pragma warning(disable: 4608)
template < typename Src, typename Dest >
Dest force_cast( Src src )
{
union _convertor { Dest d; Src s; _convertor() : d(0), s(0) {} } convertor;
convertor.s = src;
return convertor.d;
}
#pragma warning(pop)

void func(ZMyCharacter* pZMyCharacter)
{
typedef void (ZMyCharacter::*F_SetDirection)(D3DXVECTOR3&);
F_SetDirection pfSetDirection = force_cast< FARPROC, F_SetDirection >(0x004A2AF0);
D3DXVECTOR3 pos = D3DXVECTOR3(4.0f,2.0f,1.0f);
(pZMyCharacter->*pfSetDirection)(pos);
}
#pragma警告(推送)
#杂注警告(禁用:4608)
模板
卸载力(Src)
{
联合_转换器{Dest d;Src s;_转换器():d(0),s(0){}转换器;
convertor.s=src;
返回转换器d;
}
#布拉格警告(pop)
void func(ZMyCharacter*pZMyCharacter)
{
typedef void(ZMyCharacter::*F_SetDirection)(D3DXVECTOR3&);
F_设置方向pfSetDirection=强制铸造(0x004A2AF0);
D3DXVECTOR3位置=D3DXVECTOR3(4.0f、2.0f、1.0f);
(pZMyCharacter->*pfSetDirection)(位置);
}

这是未经测试的,但应该给您一个开始。请注意,它依赖于MSVC实现细节,因此它不是标准的,在其他编译器中不起作用:

#pragma warning(push)
#pragma warning(disable: 4608)
template < typename Src, typename Dest >
Dest force_cast( Src src )
{
union _convertor { Dest d; Src s; _convertor() : d(0), s(0) {} } convertor;
convertor.s = src;
return convertor.d;
}
#pragma warning(pop)

void func(ZMyCharacter* pZMyCharacter)
{
typedef void (ZMyCharacter::*F_SetDirection)(D3DXVECTOR3&);
F_SetDirection pfSetDirection = force_cast< FARPROC, F_SetDirection >(0x004A2AF0);
D3DXVECTOR3 pos = D3DXVECTOR3(4.0f,2.0f,1.0f);
(pZMyCharacter->*pfSetDirection)(pos);
}
#pragma警告(推送)
#杂注警告(禁用:4608)
模板
卸载力(Src)
{
联合_转换器{Dest d;Src s;_转换器():d(0),s(0){}转换器;
convertor.s=src;
返回转换器d;
}
#布拉格警告(pop)
void func(ZMyCharacter*pZMyCharacter)
{
typedef void(ZMyCharacter::*F_SetDirection)(D3DXVECTOR3&);
F_设置方向pfSetDirection=强制铸造(0x004A2AF0);
D3DXVECTOR3位置=D3DXVECTOR3(4.0f、2.0f、1.0f);
(pZMyCharacter->*pfSetDirection)(位置);
}

我将带你走上黑暗恐怖的道路,来到行为不明的国度

这里的问题是,您需要调用指向成员函数的指针,而实际上没有指向成员函数的指针。你可以使用一点乌兰巴托的黑暗魔法来完成这项任务。这个黑魔法可以让你将一个简单的整数值转换成一个指向成员函数的完全可用的指针。为此,我们可以创建一个
联合体

// Magical beans. Replace with your own beans if you have them.
struct ZMyCharacter {};

// Here be dark magic!
union FunctionAddress
{
    typedef void (ZMyCharacter::*MEMBER_FUNC)(D3DXVECTOR3);

    FunctionAddress(uintptr_t addr) : address(reinterpret_cast<void*>(addr)) {}

    MEMBER_FUNC function;
private:
    void* address;
};
要使用它,您需要对
ZMyCharacter\u SetDirection\u Rev
进行几处更改,以直接调用成员函数,而不是将其作为指向另一个函数的指针传递(基于您前面的问题,我假设是某个内联程序集)

请记住,如果函数是虚拟的,那么您就是在回避虚拟函数分派。如果是这种情况,你应该为它打破多态性的情况做好准备。如果希望完全支持虚拟函数的分派,则需要对虚拟表的布局进行完全反向工程。为此,你可以做一些更简单的事情,不用使用太多的黑魔法

// reverse engineered virutal function layour/ordering
struct ZMyCharacter
{
    virtual void func1();
    virtual void func2();
    virtual void func3();
    virtual void target_function(D3DXVECTOR3&);
    virtual void func4();
};

void ZMyCharacter_SetDirection_Rev( void )
{
    if( pZMyCharacter == NULL )
    {
        printf( "cannot set direction now\n" );
        return;
    }
    D3DXVECTOR3 pos = D3DXVECTOR3(4.0f,2.0f,1.0f);
    pZMyCharacter->target_function( pos );
}
我意识到这对您当前的代码库有一些改变。您应该能够将代码或概念集成到您要完成的任务中



我提到的未定义行为与访问工会的非活动成员有关。通常这被认为是不好的。

我将带你走上黑暗而可怕的道路,来到行为不明的国度

这里的问题是,您需要调用指向成员函数的指针,而实际上没有指向成员函数的指针。你可以使用一点乌兰巴托的黑暗魔法来完成这项任务。这个黑魔法可以让你将一个简单的整数值转换成一个指向成员函数的完全可用的指针。为此,我们可以创建一个
联合体

// Magical beans. Replace with your own beans if you have them.
struct ZMyCharacter {};

// Here be dark magic!
union FunctionAddress
{
    typedef void (ZMyCharacter::*MEMBER_FUNC)(D3DXVECTOR3);

    FunctionAddress(uintptr_t addr) : address(reinterpret_cast<void*>(addr)) {}

    MEMBER_FUNC function;
private:
    void* address;
};
要使用它,您需要对
ZMyCharacter\u SetDirection\u Rev
进行几处更改,以直接调用成员函数,而不是将其作为指向另一个函数的指针传递(基于您前面的问题,我假设是某个内联程序集)

请记住,如果函数是虚拟的,那么您就是在回避虚拟函数分派。如果是这种情况,你应该为它打破多态性的情况做好准备。如果希望完全支持虚拟函数的分派,则需要对虚拟表的布局进行完全反向工程。为此,你可以做一些更简单的事情,不用使用太多的黑魔法

// reverse engineered virutal function layour/ordering
struct ZMyCharacter
{
    virtual void func1();
    virtual void func2();
    virtual void func3();
    virtual void target_function(D3DXVECTOR3&);
    virtual void func4();
};

void ZMyCharacter_SetDirection_Rev( void )
{
    if( pZMyCharacter == NULL )
    {
        printf( "cannot set direction now\n" );
        return;
    }
    D3DXVECTOR3 pos = D3DXVECTOR3(4.0f,2.0f,1.0f);
    pZMyCharacter->target_function( pos );
}
我意识到这对您当前的代码库有一些改变。您应该能够将代码或概念集成到您要完成的任务中


我提到的未定义行为与访问工会的非活动成员有关。通常这被认为是不好的。

这一点(obsc