2009-08-07 117 views
0

我有一個奇怪的問題,試圖使用Delphi(Turbo Delphi 2006)程序中使用C++編寫的DLL。AccessViolation從Delphi使用C++ DLL時

當我從命令行運行Delphi程序(見下文)時,一切正常。另外,當我從Delphi環境運行而不進行調試時(CTRL + SHIFT + F9),一切都很好。然而,隨着調試(F9)運行時,它,我得到以下錯誤:

Project Z:\test.exe faulted with message: 'access violation at 0x00403fdf: read of address 0x00a14e74'. Process stopped. Use Step or Run to continue.

奇怪的是,在執行最後一次出現的錯誤「結束」。的代碼。德爾福的CPU顯示說,這是在某處「UnsetExceptionHandler」,四大行前「FinalizeUnits」,更具體,在

00403FDF 3901 cmp [ecx],eax

我在這裏損失是有點; Delphi不是我的領域(我是編寫DLL的人,現在我需要提供一個使用它的示例程序)。所以在這個問題上的任何幫助感激:)

這裏的Delphi代碼:

program libiup_integration; 
{$APPTYPE CONSOLE} 

uses 
    SysUtils, 
    WinProcs; 

type 
    T_F_GetError = function() : pchar; stdcall; 

    T_F_SetPath = function(path: pchar) : integer; stdcall; 

    T_F_GetStrat = function(date: integer;time: single;lat: single;lon: single) : single; cdecl; 

var 
    F_GetError : T_F_GetError; 
    PF_GetError : TFarProc; 
    F_SetPath : T_F_SetPath; 
    PF_SetPath : TFarProc; 
    F_GetStrat : T_F_GetStrat; 
    PF_GetStrat : TFarProc; 
    DLLHandle : THandle; 
    errormsg : pchar; 
    h5path : pchar; 
    h5err  : integer; 
    date  : integer; 
    time  : single; 
    lat  : single; 
    lon  : single; 
    strat  : single; 
    i   : integer; 

begin 
    DLLHandle := LoadLibrary('libiup.dll'); 
    if DLLHandle <> 0 then 
    begin 
     { construct the function pointers } 
     PF_GetError := GetProcAddress(DLLHandle, 'getError'); 
     PF_SetPath := GetProcAddress(DLLHandle, 'setPath'); 
     PF_GetStrat := GetProcAddress(DLLHandle, 'getStrat'); 

     { If the function pointer is valid ... } 
     if (PF_GetError <> nil) and (PF_SetPath <> nil) and (PF_GetStrat <> nil) then 
     begin 
      { Assign the function pointer to the function handle } 
      @F_GetError := PF_GetError; 
      @F_SetPath := PF_SetPath; 
      @F_GetStrat := PF_GetStrat; 

      errormsg := StrAlloc(4096); 

      h5path := StrAlloc(256); 
      StrCopy(h5path, 'z:\data\%Y%m.h5'); 
      h5err := F_SetPath(h5path); 
      if h5err < 0 then 
      begin 
       errormsg := F_GetError(); 
       WriteLn(errormsg); 
      end; 

      for i := 1 to 10 do 
      begin 
       date := 4745; 
       time := 12.34 + i/10; 
       lat := -35.321 + i*i; 
       lon := 115.67 - i*i; 

       strat := F_GetStrat(date, time, lat, lon); 
       if strat < 0. then 
       begin 
        errormsg := F_GetError(); 
        WriteLn(errormsg); 
       end; 

       WriteLn('Value returned by getStrat call no. ' + IntToStr(i) + ': ' + FloatToStr(strat)); 
      end; 

      { and finally, delete the function pointers ...} 
      PF_SetPath := nil; 
      PF_GetStrat := nil; 
      PF_GetError := nil; 
      FreeLibrary(DLLHandle); 
      WriteLn('Press ENTER to continue ...'); 
      ReadLn; 
     end 

     else 
     { The function pointer was not valid, so this means that the function was not found in the dll. } 
     begin 
      WriteLn('Function not found'); 
      RaiseLastOSError; 
     end; 
    end 

    else 
    { The LoadLibrary function did not return a valid DLL handle. } 
    begin 
     WriteLn('DLL not loaded'); 
     FreeLibrary(DLLHandle); 
     WriteLn('Press ENTER to continue ...'); 
     ReadLn; 
    end; 
end. 

dll.h

#ifndef LIBIUP_DLL_H_ 
#define LIBIUP_DLL_H_ 
#ifdef BUILD_DLL 
#define WIN32DLL_API __declspec(dllexport) 
#else 
#define WIN32DLL_API __declspec(dllimport) 
#endif 

#include "stratcalc/SimpleStratosphericColumnCalculator.h" 
#include <iostream> 
#include <string> 
#include "boost/date_time/posix_time/posix_time.hpp" 

#ifdef __cplusplus 
extern "C" {   /* Assume C declarations for C++ */ 
#endif 
    WIN32DLL_API BOOL __stdcall DllMain(HANDLE, DWORD, LPVOID); 
    WIN32DLL_API int setPath(char*); 
    WIN32DLL_API const char* getError(); 
    WIN32DLL_API float getStrat(int, float, float, float); 
    std::string errormsg; 
    SimpleStratosphericColumnCalculator* calc; 
#ifdef __cplusplus 
}      /* End of extern "C" */ 
#endif 

#endif 

dll.cpp

#ifdef BUILD_DLL 
#include "windows.h" 
#include "dll.h" 
#include <iostream> 
// different functions of this library 
= new SimpleStratosphericColumnCalculator(); 


WIN32DLL_API BOOL __stdcall DllMain(HANDLE hModule, 
         DWORD ul_reason_for_call, 
         LPVOID lpReserved 
        ) 
{ 
    switch (ul_reason_for_call) 
    { 
     case DLL_PROCESS_ATTACH: 
      calc = new SimpleStratosphericColumnCalculator(); 
      break; 
     case DLL_THREAD_ATTACH: 
      calc = new SimpleStratosphericColumnCalculator(); 
      break; 
     case DLL_THREAD_DETACH: 
      delete calc; 
      break; 
     case DLL_PROCESS_DETACH: 
      delete calc; 
      break; 
    } 

    return TRUE; 
} 


WIN32DLL_API int setPath(char* Path) 
{ 
    errormsg = ""; 
    return calc->setPath(Path); 
} 

WIN32DLL_API const char* getError() 
{ 
    std::cout << errormsg << std::endl; 
    return errormsg.c_str(); 
} 

WIN32DLL_API float getStrat(int Date, float Time, float Lat, float Lon) 
{ 
    errormsg = ""; 
    if (Lat < -90. || Lat > 90.) 
     errormsg += "Latitude value out of bounds.\n"; 
    if (Lon < 0. || Lon > 360.) 
     errormsg += "Longitude value out of bounds.\n"; 
    if (errormsg != "") 
     return -1.; 
    return (float)calc->getStrat(Date, Time, Lat, Lon); 
} 
#else 
#endif 
+0

'T_F_GetStrat = function(date ...:single; cdecl;'嘗試stdcall約定 – 2009-08-07 12:48:00

回答

2

檢查調用約定。我在一個函數中看到了2個函數的stdcall和cdecl。嘗試改變一切,以stdcall或cdecl,看看它是否工作

+0

太棒了,那就是訣竅。我真的不知道爲什麼我將setPath和getError函數定義爲stdcall ...將它們更改爲cdecl,並且所有內容都像魅力一樣。非常感謝! – 2009-08-07 21:07:00

0

我認爲無論DLL_THREAD_DETACH和DLL_PROCESS_DETACH將被調用。所以你會雙重刪除你的計算對象。

的Try ...

if (calc != NULL) 
{ 
    delete calc; 
    calc = NULL; 
} 
+0

不,我測試通過插入一些cout語句,只調用DLL_PROCESS_DETACH 加上,問題出現在我沒有刪除calc對象的時候 – 2009-08-07 12:43:39

0

我調用LoadLibrary加載DLL時,也有類似的問題。

我通過在FreeLibrary之前調用Application.ProcessMessages得到了它。

+0

hmm,聽起來像是一個很好的計劃,我想嘗試一下,但是,當我剛寫入時Delphi不會編譯我的代碼Application.ProcessMessages在FreeLibrary調用之前,我想我必須包含一些其他單元,但哪個?Google在這裏沒有幫助我... – 2009-08-07 13:03:09

+0

它在Forms單元中,但是因爲您使用的是控制檯應用程序,所以我不知道你是否可以使用它 – Re0sless 2009-08-07 13:18:40

+0

謝謝,是的,我可以在控制檯應用程序中使用Forms單元,但是 > Application.ProcessMessages; 就在 > FreeLibrary(DLLHandle); 沒有幫助。 – 2009-08-07 13:27:43