2009-08-07 7 views
0

Ich habe ein seltsames Problem, eine DLL in C++ geschrieben von einem Delphi (Turbo Delphi 2006) Programm zu verwenden.AccessViolation bei der Verwendung von C++ DLL aus Delphi

Wenn ich das Delphi-Programm (siehe unten) über die Befehlszeile ausführen, funktioniert alles einwandfrei. Wenn ich es aus der Delphi-Umgebung ohne Debugging (STRG + UMSCHALT + F9) ausführe, ist alles in Ordnung. Wenn es jedoch mit Debugging (F9) ausgeführt wird, erhalte ich folgende Fehlermeldung:

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

Das Seltsame ist, dass der Fehler bei der Ausführung das letzte tritt am Ende. " des Codes. Delphi CPU-Display sagt, das ist irgendwo in ‚UnsetExceptionHandler‘, vier Zeilen vor ‚FinalizeUnits‘, um genauer zu sein, bei

00403FDF 3901 cmp [ecx],eax

Ich bin etwas ratlos hier; Delphi ist nicht meine Domäne (ich war diejenige, die die DLL geschrieben hat, und jetzt muss ich ein Beispielprogramm bereitstellen, das sie verwendet). So dass jede Hilfe zu diesem Thema wird sehr geschätzt :)

Hier ist der Delphi-Code:

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 = Funktion (Datum ...: single; cdecl;' versuchen stdcall Konvention –

Antwort

2

Überprüfen Sie die Aufrufkonventionen. Ich sehe Stdcall in 2 Funktionen und Cdecl in einer Funktion. Versuchen Sie, alles zu stdcall oder cdecl zu ändern und zu sehen, ob es funktioniert

+0

großartig, das hat den Trick gemacht. Ich weiß nicht wirklich, warum ich die Funktionen setPath und getError als stdcall definiert habe ... habe sie in cdecl geändert und alles funktioniert wie ein Zauber. Danke vielmals! –

0

ich beide denken DLL_THREAD_DETACH und DLL_PROCESS_DETACH werden aufgerufen. Sie werden Ihr calc-Objekt also doppelt löschen.

Try ...

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

nein, ich habe das getestet, indem einige Cout-Anweisungen. Nur DLL_PROCESS_DETACH wird aufgerufen plus, das Problem war auch da, als ich das calc-Objekt nicht gelöscht habe –

0

Ich hatte ein ähnliches Problem, wenn Dlls mit Loadlibrary geladen werden.

Ich habe es durch den Aufruf von Application.ProcessMessages vor FreeLibrary.

+0

hmm, klingt wie ein guter Plan, und ich würde das gerne ausprobieren, aber Delphi wird meinen Code nicht kompilieren, wenn ich nur schreibe Application.ProcessMessages vor dem FreeLibrary-Aufruf Ich denke, ich muss ein anderes Gerät hinzufügen, aber welches Google hat mir hier nicht geholfen ... –

+0

Es ist in der Forms-Einheit, aber wie Sie eine Konsole-App verwenden, tut ich nicht wissen, ob Sie es verwenden können .. – Re0sless

+0

danke, ja ich kann Forms Einheit in der Konsole App verwenden. Aber > Application.ProcessMessages; direkt vor dem > FreeLibrary (DLLHandle); hat nicht geholfen. –

Verwandte Themen