1

我不能使用__thiscall给我以下错误:
error C4234: nonstandard extension used : '__thiscall' keyword reserved for future use

我正在从 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 );
}

pZMyCharactervoid*指向class ZMyCharacter真实应用程序上的真实的指针。它有效,但我收到调试错误(可以忽略)警告调用约定不同。确实是,因为SETDIRPROC默认__cdecl情况下,我无法将其更改为__thiscall.

typedef void(__thiscall *SETDIRPROC)(void*,D3DXVECTOR3&);//错误C4234

我该如何解决这个问题?

4

4 回答 4

2

我认为它应该是这样的:

typedef void(__thiscall &ZMyCharacter::*SETDIRPROC)(D3DXVECTOR3&);
SETDIRPROC SetDir_Proc = (SETDIRPROC)0x004A2AF0;
static_cast<ZMyCharacter*>(pZMyCharacter)->SetDir_Proc( pos );

__thiscall旨在用于成员函数指针,而不是像您声明的自由函数。以上应该更接近编译器所需要的——一个成员函数类型转换和调用。

于 2013-06-23T02:00:02.713 回答
2

我将带你走上黑暗而可怕的道路,前往行为不明的土地……

这里的问题是您需要调用指向成员函数的指针,而实际上没有指向成员函数的指针。你可以使用一些来自 UB 的黑魔法来完成这个任务。这个黑魔法可以让你将一个简单的整数值转换为一个完全可用的指向成员函数的指针。为此,我们可以创建一个union...

// 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;
};

这种神奇的union方法将允许您通过其构造函数从一个简单的整数值设置指向成员函数的指针......

FunctionAddress pZMyFunction(0x004A2AF0);

要使用它,您需要进行一些更改以ZMyCharacter_SetDirection_Rev直接调用成员函数,而不是将其作为指向另一个函数的指针传递(基于您之前的问题,我假设它是一些内联汇编)...

void ZMyCharacter_SetDirection_Rev( void )
{
    if( pZMyCharacter == NULL )
    {
        printf( "cannot set direction now\n" );
        return;
    }
    D3DXVECTOR3 pos = D3DXVECTOR3(4.0f,2.0f,1.0f);

    // directly call using pointer to member function
    (pZMyCharacter->*pZMyFunction.function)( pos );
}

请记住,如果该函数是虚拟的,则您正在回避虚拟函数调度。如果是这种情况,您应该为它破坏多态性的情况做好准备。如果您想完全支持虚拟功能的分派,您将需要对虚拟表的布局进行完全逆向工程。为此,您可以做一些不使用太多黑暗魔法的更简单的事情。

// 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 );
}

我意识到这会改变您当前代码库的一些内容。您应该能够将代码或概念集成到您要完成的工作中。


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

于 2013-06-23T03:01:46.410 回答
1

这是未经测试的,但应该给你一个开始。请注意,它依赖于 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);
}
于 2013-06-23T03:00:37.313 回答
1

完全不推荐这里的这个小(晦涩)片段但您可以想象,它可以工作:

class ZMyCharacterHook
{
public:
    virtual void SetDir(D3DXVECTOR3&);
};

typedef void (*SETDIRPROC)(D3DXVECTOR3&);
typedef void (ZMyCharacterHook::*SETDIR_METHOD)(D3DXVECTOR3&);

SETDIRPROC SetDir_Proc = (SETDIRPROC)0x004A2AF0;

D3DXVECTOR3 pos = D3DXVECTOR3(4.0f, 2.0f, 1.0f);
((ZMyCharacterHook *)pZMyCharacter->*(SETDIR_METHOD &)SetDir_Proc)(pos);

它不能以任何方式维护,并且只有在您真的想冒险时才应该使用,因为它具有未定义的行为(查看参考转换解决方法)。

如果您想更加离散,但仍然反对任何可维护性和可移植性,您可以使用 x86 MSVC 内联汇编来显式设置ecx(在使用时保存this指针thiscall),然后通过其地址调用“简单”函数:

__asm
{
    pusha                    // save all registers
    mov  ecx, pZMyCharacter  // "this" pointer
    lea  eax, pos            // eax = &pos (parameter passed by reference)
    push eax                 // parameters pushed onto the stack
    mov  eax, 0x004A2AF0
    call eax                 // the function call itself
    popa                     // restore registers, no messed up code from here on
}
于 2013-06-23T04:16:06.120 回答