如何在发出“访问违规例外”的情况下进行预防?

时间:2014-01-16 10:13:55

标签: delphi delphi-2007

有方法:

function Test.get_Param(out a : BOOL): HRESULT; stdcall;
begin
  a := b;
  Result := T_Result;
end;

现在a := b;发生异常,发生访问冲突异常。 当然,我可以尝试抓住它。但我不想那样做...... 那么有什么方法可以确定使用某种方式并跳过任务。像:

if (! now I know it will happening that Exception){
    a := b; // so I can skip 
}
Result := T_Result;

也许这很容易,但因为我不知道使用delphi,所以希望你的家伙可以帮助我。感谢。

UPDATE1:

b: Boolean;//Some friend need to know what is the b param type.

UPDATE2:

我尝试使用:

if b<> nil then Enabled := b;

但我无法构建它,它将显示:E2008不兼容的类型

UPDATE3:

我正在尝试调试它,当我调试时,在Local variables面板上显示:

  

a Inaccessible值

我使用.NET称之为。有元数据:

bool get_Param{ [param: In, MarshalAs(UnmanagedType.Bool)] [PreserveSig] set; }
实际上我并没有使用.NET访问它。我使用.NET访问DirectShow过滤器,directshow过滤器是当前方法(由delphi编写)

UPDATE4:

这是部分C#代码

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), SuppressUnmanagedCodeSecurity, Guid("hidden")]
public interface IDCDSPFilterInterface{
    bool get_Param{ [param: In, MarshalAs(UnmanagedType.Bool)] [PreserveSig] set; } 
    ..            hidden other        ..
}}

3 个答案:

答案 0 :(得分:2)

  

我尝试使用:

 if b<> nil then Enabled := b;
  

但我无法构建它,它将显示:E2008不兼容的类型

指针变量是Pascal的ABC。 http://en.wikipedia.org/wiki/Pascal_(programming_language)#Pointer_types

所以编写该检查的正确方法是

function Test.get_Param(out a : BOOL): HRESULT; stdcall;
var ptr: ^BOOL; 
begin
  ptr := @a;
  if nil = ptr then ....

  a := b;
  Result := T_Result;
end;

这是你明确问题的基本问题。

现在,实际上检查无济于事。它只会保护你的nil / NULL指针,但这不是可能发生的事情。发生的事情可能是随机垃圾指针而不是nil。由于调用代码中的错误。

同样,您可以通过var ptr: Pointer {untyped}; ptr := @Self; if ptr = nil then ...if nil <> Self或仅if Assigned(Self)检查 - 但这只能保护您免受NIL指针的攻击,而不是来自RANDOM GARBAGE指针。

更多的是,我认为实际的垃圾不是指向变量a的指针,而是指向Selfb的指针是TEST类的成员,因此真实声明是a := Self.b;

由于您使用stdcall我认为您正在尝试使用非Delphi语言中的EXE创建DLL。很可能你在该客户端应用程序代码中对函数做了错误的定义。实际上,如果Test是一个类,你就可以做出正确的声明。如果get_Param是RECORD Test的方法,或者如果它是Test类的STATIC CLASS方法,则只能使其正确。因此,编写函数的正确方法如下

function Test.get_Param(out a : BOOL): HRESULT; 
begin
  a := b;
  Result := T_Result;
end;

function DLL_get_Param(const TestObject: pointer; out a : BOOL): HRESULT; stdcall;
var MyTest: Test;
begin
  pointer(MyTest) := TestObject;

  Result := MyTest.DLL_get_Param(a);
end;

export DLL_get_Param;

阅读Delphi文档,您可以获取/放入DLL函数。 IntegersfloatspointersIInterface。您无法传递DLL复合体并执行诸如stings,动态数组,对象实例之类的对象。由于您无法传递对象实例,因此无法传递Self变量,也无法调用方法。

抓住它的一种非常昂贵的方式就像

{global} var TestInstances: TList;
type 
  TEST = class...

    procedure AfterConstructon; override;
    procedure BeforeConstructon; override;

....


procedure Test.AfterConstructon; 
begin
  inherited;
  TestInstances.Add(Self); // single-thread assumption here
end;

procedure Test.BeforeConstructon; 
begin
  TestInstances.Remove(Self); // single-thread assumption here
  inherited;
end;

function Test.get_Param(out a : BOOL): HRESULT; stdcall;
begin
  if not ( TestInstances.IndexOf(Self) >= 0  {found!} )  // single-thread assumption here
     then ... WTF ???
  ...

....

initialization     
  TestInstances := TList.Create;
finalization 
  TestInstances.Free;
end; 

如果您的DLL可以被多线程应用程序使用,您还应该将标记的调用包装到http://docwiki.embarcadero.com/Libraries/XE2/en/System.SyncObjs.TCriticalSection

答案 1 :(得分:1)

互操作边界的两侧存在严重不匹配。您的Delphi函数与C#声明不匹配。

解决方案不是测试参数有效性。鉴于问题中的函数声明,您的Delphi代码是正确的。解决方案是使互操作边界的两侧匹配。在你展示互操作边界的两边之前,我不能告诉你更多。

答案 2 :(得分:1)

由于我无法看到你已经去死的地方b,我将假设它是Test的成员。

因此,有一个很大的可能性是您有Test的无效实例,并且您发现访问冲突试图阅读b以便将其分配给a。例如,以下使用get_Param会引发异常。

var
  LTest: Test;
  LA: Boolean;
begin
  LTest := nil;
  LTest.get_Param(LA);
end;

关键是你需要一个有效的Test实例才能使用它。 E.g。

var
  LTest: Test;
  LA: Boolean;
begin
  LTest := Test.Create;
  try
    LTest.get_Param(LA);
  finally
    LTest.Free;
  end;
end;