添加虚拟变量会清除错误

时间:2015-02-27 16:14:54

标签: delphi dll

下面是一个调用dll并返回值的最小代码段。它工作正常。

dll(rtlsdr.dll)来自Software Defined Radio字段,控制一个小型USB加密狗。

代码工作正常,但只有我有虚拟变量' var junk:Integer'在函数getCenterFrequency中。如果我将其删除或发表评论,我会收到内存故障:

  

地址0012FEAE的访问冲突。读取地址00000000

如果我直接访问加密狗,而不是通过调用该函数,它可以正常工作。

如果我从Delphi UI或直接运行EXE,我会得到相同的结果。

我已经安装了EurekaLog,但它没有捕获异常。

什么可能导致这种奇怪的行为? Delphi XE2最新版本,Windows 7。

unit uTest;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs;

const
  rtldll = 'rtlsdr.dll';

type
  TfrmTest = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    function getCenterFrequency: longword;
  public
    { Public declarations }
    _dev: Pointer;
  end;

var
  frmTest: TfrmTest;
  _dev: Pointer;

implementation

{$R *.dfm}

function rtlsdr_open(rtlsdr_dev_t: Pointer; index: UINT32): Integer;    stdcall; external rtldll;

function rtlsdr_get_center_freq(rtlsdr_dev_t: Pointer): Integer; stdcall;   external rtldll;

function TfrmTest.getCenterFrequency: longword;
//var
//junk: Integer;
begin
  Result := rtlsdr_get_center_freq(_dev);
end;

procedure TfrmTest.FormCreate(Sender: TObject);
var
  CF1, CF2: longword;
begin
  _dev := 0;
  if rtlsdr_open(@_dev, 0) <> 0 then
    ShowMessage('error');

  CF1 := rtlsdr_get_center_freq(_dev);
  CF2 := getCenterFrequency;
end;

end.

2 个答案:

答案 0 :(得分:3)

RTLSDR函数使用cdecl调用约定,而不是stdcall调用约定。另外,我建议您更改Pointer指针以匹配DLL实际使用的rtlsdr_dev_t类型。

type
  rtlsdr_dev_t = record
  end;
  prtlsdr_dev_t = ^rtlsdr_dev_t;

function rtlsdr_open(out dev: prtlsdr_dev_t; index: UInt32): Integer; cdecl; external rtldll;

function rtlsdr_close(dev: prtlsdr_dev_t): Integer; cdecl; external rtldll;

function rtlsdr_get_center_freq(dev: prtlsdr_dev_t): UInt32; cdecl; external rtldll;

然后你可以这样做:

var
  _dev: prtlsdr_dev_t = nil;

function TfrmTest.getCenterFrequency: Uint32;
begin
  Result := rtlsdr_get_center_freq(_dev);
end;

procedure TfrmTest.FormCreate(Sender: TObject);
var
  CF1, CF2: UInt32;
begin
  _dev := nil;
  if rtlsdr_open(_dev, 0) <> 0 then
  begin
    ShowMessage('error');
    Exit;
  end;
  CF1 := rtlsdr_get_center_freq(_dev);
  CF2 := getCenterFrequency;
  rtlsdr_close(_dev);
  _dev := nil;
end;

答案 1 :(得分:2)

据我所知,这个库导出了cdecl个函数。您已导入stdcall。仅这一点就足以导致您报告的行为。