【问题标题】:AccessViolation when using C++ DLL from Delphi使用 Delphi 的 C++ DLL 时的访问冲突
【发布时间】:2009-08-07 12:27:50
【问题描述】:

我在尝试使用 Delphi (Turbo Delphi 2006) 程序中用 C++ 编写的 DLL 时遇到了一个奇怪的问题。

当我从命令行运行 Delphi 程序(见下文)时,一切正常。此外,当我从 Delphi 环境中运行它而不进行调试 (CTRL+SHIFT+F9) 时,一切都很好。但是,在 使用 调试 (F9) 运行它时,我收到以下错误:

Project Z:\test.exe 出现错误 消息:'访问冲突在 0x00403fdf: 读取地址 0x00a14e74'。进程停止。使用步骤 或运行以继续。

奇怪的是错误发生在执行最后一个“结束”时。的代码。 Delphi 的 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

【问题讨论】:

  • T_F_GetStrat = function(date ... : single; cdecl; 尝试标准调用约定

标签: c++ delphi dll access-violation


【解决方案1】:

检查调用约定。我在 2 个函数中看到 stdcall,在一个函数中看到 cdecl。尝试将所有内容更改为 stdcall 或 cdecl 看看是否有效

【讨论】:

  • 太棒了,成功了。我真的不知道为什么我将 setPath 和 getError 函数定义为 stdcall ...将它们更改为 cdecl 并且一切都像一个魅力。非常感谢!
【解决方案2】:

我认为 DLL_THREAD_DETACH 和 DLL_PROCESS_DETACH 都会被调用。所以你会双重删除你的 calc 对象。

试试……

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

【讨论】:

  • 不,我通过插入一些 cout 语句进行了测试。仅调用 DLL_PROCESS_DETACH。另外,当我没有删除 calc 对象时,问题也存在。
【解决方案3】:

我在使用 LoadLibrary 加载 Dll 时遇到了类似的问题。

我通过在 FreeLibrary 之前调用 Application.ProcessMessages 解决了这个问题。

【讨论】:

  • 嗯,听起来不错,我想试试这个。但是,当我在 FreeLibrary 调用之前编写 Application.ProcessMessages 时,Delphi 不会编译我的代码。我想我必须包括一些其他单位,但哪个?谷歌在这里没有帮助我......
  • 它在表单单元中,但由于您使用的是控制台应用程序,我不知道您是否可以使用它。
  • 谢谢,是的,我可以在控制台应用程序中使用表单单元。但是 > Application.ProcessMessages;就在 > FreeLibrary(DLLHandle) 之前;没有帮助。
猜你喜欢
  • 1970-01-01
  • 2010-11-19
  • 1970-01-01
  • 1970-01-01
  • 2011-05-28
  • 1970-01-01
  • 2014-03-19
  • 1970-01-01
  • 2010-10-09
相关资源
最近更新 更多