为什么使用可变参数调用 DLL 会检索到错误的结果,并使用额外未使用的参数解决问题 exe.cppdll.cpp文字版更新 2更新 1

问题描述

平台:x64;配置:调试;无法在 x86 下重现。

编译器:用于 EXE 和 DLL 的 msvc。

嗨,我最近在开发 DLL 时遇到了一个问题。当我的示例程序尝试使用可变参数调用 DLL 导出函数时,我发现当我尝试按照我想要的方式调用它时,它检索到的值与我传入的值不同。在一次随机尝试中,我添加一个 unused 参数,并惊讶地发现它在执行此操作后检索到了正确的值。

虽然我认为我的目标可以通过将最后一个命名参数 shapeType 作为可变参数部分的第一个参数来实现,但我仍然想知道为什么会发生这种情况。

我已将代码简化如下(省略了包含)并记录了我在图像的地址视图中找到的内容。图中的红线表示args(va_list,实际上是编译时宏定义的char*)指向的地址。我已经上移了几行,以便也可以看到其他论点。由于此代码中的重现问题不需要有意义的 HWND 值,因此我只是在那里放了一个随机数。如果您需要包括项目文件在内的整套源文件,请与我联系。

如果你能帮助我,那就太好了,提前致谢。

exe.cpp

#define UNUSED 1
#if UNUSED
typedef int(__cdecl* ADDLINE)(HWND hWnd,int shapeType,int unused,int fillType,float boldness,float a,float r,float g,float b,float x1,float y1,float x2,float y2);
#else
typedef int(__cdecl* ADDLINE)(HWND hWnd,float y2);
#endif 
int main() {
    HINSTANCE hinstLib;
    hinstLib = LoadLibrary(L"dll.dll");
    ADDLINE addLine = (ADDLINE)GetProcAddress(hinstLib,"addShape");
#if UNUSED
    addLine((HWND)0x00000000000b11bc,16,2,1,10.0f,127.0f,255.0f,0.0f,500.0f,500.0f);
#else
    addLine((HWND)0x00000000000b11bc,500.0f);
#endif
    return 0;
}

dll.cpp

#define UNUSED 1
extern "C" __declspec(dllexport) int addShape(HWND hWnd,...) {
    va_list args;
    va_start(args,shapeType);
#if UNUSED
    va_arg(args,int); //unused
#endif
    va_arg(args,int); //first int
    std::cout<< va_arg(args,float); //first float
    va_end(args);
    return 0;
}

Memory View Comparison

文字

0x00000062C7B6F7C0 bc 11 0b 00 00 00 00 00
0x00000062C7B6F7C8 10 00 00 00 ff 7f 00 00
0x00000062C7B6F7D0 01 00 00 00 00 00 00 00
0x00000062C7B6F7D8 00 00 00 00 00 00 00 00
0x00000062C7B6F7E0 00 00 fe 42 cc cc cc cc
0x00000062C7B6F7E8 00 00 7f 43 cc cc cc cc
UNUSED=0 (without unused),output=0


0x000000FFC20FF600 bc 11 0b 00 00 00 00 00
0x000000FFC20FF608 10 00 00 00 ff 7f 00 00
0x000000FFC20FF610 02 00 00 00 00 00 00 00
0x000000FFC20FF618 01 00 00 00 00 00 00 00
0x000000FFC20FF620 00 00 20 41 cc cc cc cc
0x000000FFC20FF628 00 00 fe 42 cc cc cc cc
UNUSED=1 (with unused),output=10

IEEE-754 Floating Point: 0x41200000==10.0

更新 2

dll.cpp
extern "C" __declspec(dllexport) int addShape(HWND hWnd,shapeType);
    va_arg(args,float); //first float
    va_end(args);
    return 0;
}
执行程序
extern "C" typedef int(__cdecl* ADDLINE)(HWND hWnd,...);
int main() {
    HINSTANCE hinstLib;
    hinstLib = LoadLibrary(L"dll.dll");
    ADDLINE addLine = (ADDLINE)GetProcAddress(hinstLib,"addShape");
    addLine((HWND)0x00000000000b11bc,500.0f);
    return 0;
}

更新 1

我在评论中尝试了一些建议,但我不确定我是否做得正确。把文件exe.cpp改成下面这个文件后,除了UNUSED=1还是不行。 注意:dll.cpp 中的 UNUSED 如果 1 中的 1 将设置为 exe.cpp,否则将设置为 0

#define UNUSED 0
extern "C"{
#if UNUSED==1
typedef int(__cdecl* ADDLINE)(HWND hWnd,float y2);
#elif UNUSED==2
typedef int(__cdecl* ADDLINE)(HWND hWnd,...);
#else
typedef int(__cdecl* ADDLINE)(HWND hWnd,float y2);
#endif 
}
int main() {
    HINSTANCE hinstLib;
    hinstLib = LoadLibrary(L"dll.dll");
    ADDLINE addLine = (ADDLINE)GetProcAddress(hinstLib,"addShape");
#if UNUSED==1
    addLine((HWND)0x00000000000b11bc,500.0f);
#endif
    return 0;
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)