c - Win32::API 给出错误的原型(prototype)错误

标签 c perl winapi

面向

Win32::API a function was called with the wrong prototype and caused a C stack consistency EBP=18fde0 ESP=18fdd0

下面是perl和C代码

my $CheckSqlAnyWindow = new Win32::API($dllfile,
                   "CheckSqlAnyWindow", [ 'N', 'P', 'P' ], 'N');
    my $hwndSqlany = pack("L", 0);
    my ($i, $sqlanyWinId);
    START:
    for ($i = 0; $i < $numRetries; $i++) 
    {

        $rc = $CheckSqlAnyWindow->Call($procId,"$engine - Adaptive Server Anywhere - 12.0.1 (3817)", $hwndSqlany);
        if ($rc <= 0)
        {
                $Cisco::DbUtils::errstr =  Win32::FormatMessage( Win32::GetLastError());
                return 1;
        }
}

c 代码

BOOL CheckSqlAnyWindow(DWORD pid, char *winTitle, DWORD * hwnd)
{
    StartDbInfo startDbBuf;
    BOOL rc;

    startDbBuf.pid = pid;
    startDbBuf.hwnd = NULL;
    strcpy(startDbBuf.winTitle, winTitle);

    rc = EnumWindows((WNDENUMPROC) getWindowId, (LPARAM) &startDbBuf);
    memcpy((DWORD *) hwnd, (DWORD *) &startDbBuf.hwnd, sizeof(DWORD));
    return (TRUE);
}

谁能指出这里要进行的更正吗?

最佳答案

在 Windows 上,您有不同的调用约定。一个关键的区别在于函数调用后由谁清理参数和返回值占用的堆栈空间。 C 中使用的标准调用约定(通常称为 cdecl)将这项工作留给了调用者

Windows API 函数使用不同的调用约定,Microsoft 将其命名为 stdcall。在此约定中,被调用者 有责任清理堆栈。由于 perl 模块 Win32::API 旨在调用 Windows API 函数,因此这是它默认使用的调用约定。

您收到的消息支持这一点:EBP=18fde0ESP=18fdd0 彼此相距正好 16 个字节,这是函数参数加上返回值的大小值(value)。由于您的函数声明没有任何表示调用约定的属性,因此它使用 cdecl,因此它根本不执行任何堆栈清理,但 Win32::API期望它能做到。

一种解决方案是将调用约定通知 Win32::API

Win32::API->new($dllfile, "CheckSqlAnyWindow", [ 'N', 'P', 'P' ], 'N', '__cdecl');

另一个解决方案是更改您的库以使用 stdcall 约定。

BOOL __stdcall CheckSqlAnyWindow(DWORD pid, char *winTitle, DWORD * hwnd)

请注意,__stdcall 是 MSVC、GCC、clang 以及其他一些编译器所采用的符号。其他编译器可能使用不同的语法将函数声明为stdcall。由于包含 windows.h,您可以通过使用以下内容来避免整个问题:

BOOL WINAPI CheckSqlAnyWindow(DWORD pid, char *winTitle, DWORD * hwnd)

关于c - Win32::API 给出错误的原型(prototype)错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45059300/

相关文章:

c - 如何更改作为参数传递的变量的值?

perl - File::Copy 报告 NFS 写入错误错误?

winapi - 如何检查我的代码是否在 DllMain 中执行

c# - 来自 .NET 的 Windows Mobile API 调用 - 什么是 dll 以及什么是枚举值

c - 如何在进度条中显示文本?

c - 这个数组是静态的还是动态的?

我们可以将更长的字符串分配给数组吗?

c - 使用编译器警告捕获常量1的左移溢出?

perl - 如何在现有文件的中间插入一行

perl - 在 Perl 中,如何导入示例 CSV,进行基本的文本操作,然后将其保存回 CSV?