问题
I have a weird problem trying to use a DLL written in C++ from a Delphi (Turbo Delphi 2006) program.
When I run the Delphi program (see below) from the command line, everything works fine. Also, when I run it from the Delphi environment without debugging (CTRL+SHIFT+F9), everything is fine. However, when running it with debugging (F9), I get the following error:
Project Z:\test.exe faulted with message: 'access violation at 0x00403fdf: read of address 0x00a14e74'. Process stopped. Use Step or Run to continue.
The weird thing is that the error occurs on executing the last 'end.' of the code. Delphi's CPU display says this is somewhere in 'UnsetExceptionHandler', four lines before 'FinalizeUnits', to be more specific, at
00403FDF 3901 cmp [ecx],eax
I'm somewhat at a loss here; Delphi is not my domain (I was the one writing the DLL, and now I need to provide an example program using it). So any help on this issue is greatly appreciated :)
Here's the 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
回答1:
Check the calling conventions. I see stdcall in 2 functions and cdecl in one function. Try to change everything to stdcall or cdecl and see if it works
回答2:
I think both DLL_THREAD_DETACH and DLL_PROCESS_DETACH will be called. So you'll be double deleting your calc object.
Try...
if ( calc != NULL )
{
delete calc;
calc = NULL;
}
回答3:
I had a similar problem when loading Dlls with LoadLibrary.
I got round it by calling Application.ProcessMessages before FreeLibrary.
来源:https://stackoverflow.com/questions/1244441/accessviolation-when-using-c-dll-from-delphi