Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/157.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ x64的简单windows回调thunks_C++_Callback_X86 64_Thunk - Fatal编程技术网

C++ x64的简单windows回调thunks

C++ x64的简单windows回调thunks,c++,callback,x86-64,thunk,C++,Callback,X86 64,Thunk,你们中的许多人都熟悉ATL thunks,例如用于创建窗口的ATL thunks。使该调用生效的类CStdCallThunk以该调用为目标。在本质上,它将全局回调转换成C++对象的成员函数。 这种类型的thunk不适用于需要第一个参数完整的。对于32位windows,我在库的一部分CAuxThunk找到了一个整洁的解决方案。不幸的是,这不适用于本机64位可执行文件 我想知道是否有任何x64程序集专家可以将这个CAuxThunk修补到64位windows上,或者想出任何等效的thunk,将this

你们中的许多人都熟悉ATL thunks,例如用于创建窗口的ATL thunks。使该调用生效的类CStdCallThunk以该调用为目标。在本质上,它将全局回调转换成C++对象的成员函数。 这种类型的thunk不适用于需要第一个参数完整的。对于32位windows,我在库的一部分CAuxThunk找到了一个整洁的解决方案。不幸的是,这不适用于本机64位可执行文件

我想知道是否有任何x64程序集专家可以将这个CAuxThunk修补到64位windows上,或者想出任何等效的thunk,将this u stdcall回调变成一个成员函数

LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
谢谢,

nikos

因为在64位模式下,所有类型(stdcall、cdecl和thiscall)的低级约定都是相同的,所以不需要汇编代码来实现这一点。只需创建一个调用适当成员函数的静态函数。您需要找出要使用的
指针,例如通过将
lparam
中的
hwnd
与对象关联。如果您只有一个回调,那么这当然没有问题。比如:

LRESULT CALLBACK static CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    Window w = GetWindowByHwnd(((CWPSTRUCT*)lParam)->hwnd);
    return w->CallWndProc(nCode, wParam, lParam);
}

因为在64位模式下,所有类型(stdcall、cdecl和thiscall)的低级约定都是相同的,所以不需要汇编代码来实现这一点。只需创建一个调用适当成员函数的静态函数。您需要找出要使用的
指针,例如通过将
lparam
中的
hwnd
与对象关联。如果您只有一个回调,那么这当然没有问题。比如:

LRESULT CALLBACK static CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    Window w = GetWindowByHwnd(((CWPSTRUCT*)lParam)->hwnd);
    return w->CallWndProc(nCode, wParam, lParam);
}
更新见下文

请看一下SetWindowLongPtr

这允许您将指针与窗口相关联。鉴于WindowProc看起来像这样

LRESULT回调WindowProc(
_在HWND HWND,
_在uuint uMsg,
_在WPARAM WPARAM,
_In_lparamlparam
);

您可以将hwnd参数与GetWindowLongPtr一起使用,以检索回调中的this指针

更新

看看

这似乎就是您要查找的内容,请参见下文

请看一下SetWindowLongPtr

这允许您将指针与窗口相关联。鉴于WindowProc看起来像这样

LRESULT回调WindowProc(
_在HWND HWND,
_在uuint uMsg,
_在WPARAM WPARAM,
_In_lparamlparam
);

您可以将hwnd参数与GetWindowLongPtr一起使用,以检索回调中的this指针

更新

看看


这似乎就是您要寻找的

我描述了一种生成所需thunk代码的通用方法。让我们为你的案子重做一遍,只是为了好玩

假设您的类定义为:

struct YourClass {
    LRESULT YourMemberFunc(int nCode, WPARAM wParam, LPARAM lParam);
};
<>基本上,你在C++中用占位符写你的thunk,用于实际地址:

LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam) {
    YourClass *x = reinterpret_cast<YourClass*>(0x1122112211221122);
    __int64 im = 0x3344334433443344;
    LRESULT (YourClass::*m)(int,WPARAM,LPARAM) = *reinterpret_cast<LRESULT (YourClass::**)(int,WPARAM,LPARAM)>(&im);
    return (x->*m)(nCode, wParam, lParam);
}
在发行版中编译并查看生成的程序集(在Visual Studio中,在调试期间查看程序集窗口并启用“显示代码字节”):

这将是您的thunk,在运行时,
44 33 44 44 33
替换为指向您的成员的指针(
&YourClass::yourmberfunc
),而
22 11 22 11
替换为指向实际对象实例的指针

对thunk中发生的事情的解释:

在x64调用约定(Windows下只有一个)中,前四个参数按从左到右的顺序传递到
rcx、rdx、r8、r9
寄存器中。所以当我们的恶棍被叫到的时候

rcx = nCode, rdx = wParam, r8 = lParam
对于成员函数,有一个隐式的第一个参数保存着
这个
指针,因此当输入
yourmberfunc
时,我们必须

rcx = this, rdx = nCode, r8 = wParam, r9 = lParam
编译器生成的代码正是这样做的:它移动
r8->r9,rdx->r8,ecx->edx
,然后将占位符
this=112211221221122
分配给
rcx
。现在它已经设置了参数,并且可以继续间接跳转到函数本身
rax
用于保存返回值,因此不必跨函数调用保留它。这就是为什么这里使用它来临时保存目标地址,这为尾部调用优化提供了机会(调用/返回对替换为单跳转)

为什么我们要打间接电话?因为否则我们会得到一个相对的跳跃。但是我们不能使用硬编码的相对跳转,因为thunk将被复制到内存中的不同地址!因此,我们求助于在运行时设置绝对地址,并执行间接跳转


HTH

我描述了一种生成所需thunk代码的通用方法。让我们为你的案子重做一遍,只是为了好玩

假设您的类定义为:

struct YourClass {
    LRESULT YourMemberFunc(int nCode, WPARAM wParam, LPARAM lParam);
};
<>基本上,你在C++中用占位符写你的thunk,用于实际地址:

LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam) {
    YourClass *x = reinterpret_cast<YourClass*>(0x1122112211221122);
    __int64 im = 0x3344334433443344;
    LRESULT (YourClass::*m)(int,WPARAM,LPARAM) = *reinterpret_cast<LRESULT (YourClass::**)(int,WPARAM,LPARAM)>(&im);
    return (x->*m)(nCode, wParam, lParam);
}
在发行版中编译并查看生成的程序集(在Visual Studio中,在调试期间查看程序集窗口并启用“显示代码字节”):

这将是您的thunk,在运行时,
44 33 44 44 33
替换为指向您的成员的指针(
&YourClass::yourmberfunc
),而
22 11 22 11
替换为指向实际对象实例的指针

对thunk中发生的事情的解释:

在x64调用约定(Windows下只有一个)中,前四个参数按从左到右的顺序传递到
rcx、rdx、r8、r9
寄存器中。所以当我们的恶棍被叫到的时候

rcx = nCode, rdx = wParam, r8 = lParam
对于成员函数,有一个隐式的第一个参数保存着
这个
指针,因此当输入
yourmberfunc
时,我们必须

rcx = this, rdx = nCode, r8 = wParam, r9 = lParam
编译器生成的代码正是这样做的:它移位
r8->r9,rdx->