2009-08-07 6 views
0

J'ai un problème étrange en essayant d'utiliser une DLL écrite en C++ à partir d'un programme Delphi (Turbo Delphi 2006).AccessViolation lors de l'utilisation de la DLL C++ de Delphi

Lorsque j'exécute le programme Delphi (voir ci-dessous) à partir de la ligne de commande, tout fonctionne correctement. En outre, lorsque je l'exécute à partir de l'environnement Delphi sans débogage (CTRL + MAJ + F9), tout va bien. Cependant, lors de l'exécution, il avec débogage (F9), je reçois l'erreur suivante:

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

La chose étrange est que l'erreur se produit sur l'exécution de la dernière « fin ». du code. L'affichage du processeur de Delphi dit ceci est quelque part dans « UnsetExceptionHandler », quatre lignes avant « FinalizeUnits », pour être plus précis, à

00403FDF 3901 cmp [ecx],eax

Je suis un peu à une perte ici; Delphi n'est pas mon domaine (j'étais celui qui écrivait la DLL, et maintenant je dois fournir un exemple de programme l'utilisant). Ainsi, toute aide à ce sujet est très apprécié :)

Voici le code 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 = fonction (date ...: single; cdecl;' essayez la convention stdcall –

Répondre

2

Vérifiez les conventions d'appel. Je vois stdcall dans 2 fonctions et cdecl dans une fonction. Essayez de tout changer en stdcall ou cdecl et voyez si cela fonctionne

+0

super, ça a fait l'affaire. Je ne sais pas vraiment pourquoi j'ai défini les fonctions setPath et getError comme stdcall ... les ai changées en cdecl et tout fonctionne comme un charme. Merci beaucoup! –

0

Je pense que les deux DLL_THREAD_DETACH et DLL_PROCESS_DETACH seront appelés. Vous allez donc supprimer deux fois votre objet calc.

Essayez ...

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

non, je l'ai testé en insérant quelques instructions cout .. seulement DLL_PROCESS_DETACH est appelée plus, le problème était aussi là quand je n'ai pas supprimé l'objet calc –

0

J'ai eu un problème similaire lors du chargement de DLL avec LoadLibrary.

Je l'ai arrondi en appelant Application.ProcessMessages avant FreeLibrary.

+0

hmm, cela me semble être un bon plan, et je voudrais essayer ceci, mais Delphi ne compilera pas mon code quand j'écrirai Application.ProcessMessages avant l'appel FreeLibrary Je suppose que je dois inclure une autre unité, mais laquelle? Google ne m'a pas aidé ici ... –

+0

Son dans l'unité de formulaires, mais comme vous utilisez une application de console je ne sais pas savoir si vous pouvez l'utiliser – Re0sless

+0

merci, oui je peux utiliser l'unité de formulaires dans l'application de la console, mais > Application.ProcessMessages; juste avant le > FreeLibrary (DLLHandle); n'a pas aidé. –

Questions connexes