面向
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=18fde0
和 ESP=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/