2017-07-12 34 views
0

面對的Win32 API ::給出錯誤原型錯誤

的Win32 API ::一個函數被調用與錯誤原型並引起了C堆棧一致性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); 
} 

任何人都可以指出要在這裏完成的更正嗎?

+1

嘗試'WINAPI'或'__stdcall'在當在C代碼中沒有指定的調用約定在你的C函數 –

回答

5

在Windows上,您有不同的調用約定。一個關鍵的區別是誰在調用函數後清理參數佔用的堆棧空間並返回值。 C中使用的標準調用約定(通常稱爲cdecl)將此工作留給調用者

Windows API函數使用不同的調用約定,由Microsoft命名爲stdcall。在這個約定中,被調用者有責任清理堆棧。由於perl模塊Win32::API旨在調用Windows API函數,因此這是默認情況下使用的調用約定。

您收到的消息支持此消息:EBP=18fde0ESP=18fdd0相距16個字節,這就是函數參數的大小和返回值。因爲你的函數聲明沒有任何表示調用約定的屬性,所以它使用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,鐺,可能是一些其他的編譯器,以及採用的符號。其他編譯器可能使用不同的語法來聲明函數爲stdcall。您可以通過以下避免整個問題,因爲你有windows.h

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

的定義,編譯器的默認約定被使用,通常是*'cdecl',但可能是別的,取決於用戶的編譯器設置。所以你不能總是假設'cdecl',除非你永遠不會改變默認值。 –

+0

@ikegami感謝編輯,我不熟悉'Win32 :: API',所以不知道它也支持'cdecl'。 –

+0

@FelixPalmen謝謝。 _cdecl工作。但即使當我使用_cdecl時,我也會得到相同的錯誤。我們不能使用WINAPI,因爲這是windows dll.Below是代碼 'my $ CreateProcess = new Win32 :: API(「kernel32。d'「,」CreateProcess「, ['P','P','P','P','N','N','P','P','P','P'], 'N'); $ rc = $ CreateProcess-> Call($ dbengineCodeFile,$ cmdLine,0,0, NORMAL_PRIORITY_CLASS,0,「。」,$ startInfo,$ procInfo);' 對此有何建議? – Prateek