How to prevention when assignment a out param happening "Access Violation Exception"?

StackOverflow https://stackoverflow.com/questions/21158874

  •  28-09-2022
  •  | 
  •  

Frage

There is method:

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

Now the exception happening on a := b; , happening Access violation Exception. Ofcourse I can try and catch it. but I don't want to do that.... So Is there any way can determine use some way and skip the assignment. like:

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

Maybe it's very easy, but because I don't know use delphi, So hope your guys can help me. thanks.

Update1:

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

Update2:

I'm try to use :

if b<> nil then Enabled := b;

but I can't build it , it will display: E2008 Incompatible types

Update3:

I'm trying to debug it, and when I'm debug, on the Local variables panel display:

a Inaccessible value

I'm use .NET called it. there is metadata:

bool get_Param{ [param: In, MarshalAs(UnmanagedType.Bool)] [PreserveSig] set; }

actually I'm not use .NET access it. I'm use .NET access a DirectShow filter, and the directshow filter is current method(write by delphi)

Update4:

this is partial C# code

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

Lösung 2

There is a gross mismatch across the two sides of your interop boundary. Your Delphi function does not match the C# declaration.

The solution is not to test for parameter validity. Your Delphi code, given the declaration of the function in the question, is correct. The solution is to make both sides of the interop boundary match. I cannot tell you more than that until you show both sides of the interop boundary.

Andere Tipps

I'm try to use :

 if b<> nil then Enabled := b;

but I can't build it , it will display: E2008 Incompatible types

Pointer variables are ABC of Pascal. http://en.wikipedia.org/wiki/Pascal_(programming_language)#Pointer_types

So the proper way to write that check would be

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;

That is the basic question to you explicit questions.

Now, in reality that check does not help. It would only protect your from nil/NULL pointers, but that is not what probably happens. What happens is probably a random garbage pointer instead of nil. Due to error in the calling code.

Again, you can check that via var ptr: Pointer {untyped}; ptr := @Self; if ptr = nil then ... or just if nil <> Self or just if Assigned(Self) - but that would only protect you from NIL pointers, not from RANDOM GARBAGE pointers.

More so, i think that actual garbage is not in pointer to the variable a, but to the pointer to Self and b being a member of TEST classm, thus the real statement is a := Self.b;.

Since you use stdcall i think you're trying to make a DLL for using from an EXE made in a in non-Delphi language. Most probably you either made a wrong definition for function in that client app code. Actually, you just can make a proper declaration is you Test is a class. You only can make a proper if get_Param is a method of RECORD Test or perhaps if it is STATIC CLASS method of Test class. So the proper way to write your function would be like following

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;

Read Delphi documentation what you can get/put to/from DLL functions. Integers, floats, pointers, IInterface. You cannot pass into DLL complex and behaving objects like stings, dynamic arrays, object instances. And since you cannot pass an object instance, you cannot pass a Self variable and you cannot call a method.

One very expensive way to catch it would be like

{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; 

If your DLL can be used by multi-threaded application you should also wrap the marked calls into http://docwiki.embarcadero.com/Libraries/XE2/en/System.SyncObjs.TCriticalSection

Since I can't see where you've decalred b, I'm going to assume it's a member of Test.

So one strong possibility is that you have an invalid instance of Test, and you get an Access Violation trying to read b in order to assign it to a. As an example the following use of get_Param would raise an exception.

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

The point is that you need a valid instance of Test in order to use it. E.g.

var
  LTest: Test;
  LA: Boolean;
begin
  LTest := Test.Create;
  try
    LTest.get_Param(LA);
  finally
    LTest.Free;
  end;
end;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top