0

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        ..
}}
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
qakmak
  • 1,287
  • 9
  • 31
  • 62
  • 1
    SSCCE please. http://sscce.org/ – Roddy Jan 16 '14 at 10:20
  • Hi @Roddy What place your're not understand? – qakmak Jan 16 '14 at 10:27
  • Why would you write `if b<> nil`? `b` is your variable of type `b`. It cannot be `nil` since it is not a pointer. – David Heffernan Jan 16 '14 at 10:48
  • @David Heffernan, Sorry some fried reply and teld me that way, but now he delete his reply...... – qakmak Jan 16 '14 at 10:51
  • @qakmak the code you've shown has no problem, so the code you *haven't* shown must be broken. where's the code that calls `get_param`? Show a Short, Self-contained, Correct, Compilable Example. – Roddy Jan 16 '14 at 10:52
  • @Roddy In fact we don't really need to see the other side. The code as presented is enough. if `a := b` leads to AV then clearly the other code is broken. The asker asks what to do to fix the code in the Q and the answer is simply to do nothing. The code in the Q is not broken and should not be fixed. – David Heffernan Jan 16 '14 at 10:55
  • Also, where is `b` declared? – Disillusioned Jan 16 '14 at 10:56
  • @CraigYoung It doesn't matter! – David Heffernan Jan 16 '14 at 10:58
  • @qakmak I think you already have the basic answer. Your two sides don't match. We can stop here. Or if you want help with the mis-match then you need to show the real C# code. – David Heffernan Jan 16 '14 at 11:04
  • @David Heffernan, ok. thanks – qakmak Jan 16 '14 at 11:07
  • 1
    @DavidHeffernan Of course it matters, if `b` is a member of the `Test` class, then calling the method on an invalid instance is guaranteed to raise an AV on that very line. – Disillusioned Jan 16 '14 at 11:07
  • @CraigYoung I have been working under the assumption that the instance is fine. Judging from the updates, it would appear that all bets are off! – David Heffernan Jan 16 '14 at 11:09
  • 1
    I wonder who 1st spotted that, me or Craig :-) – Arioch 'The Jan 16 '14 at 11:11
  • Sorry guys.... that's all my fault. and thanks your helping again. – qakmak Jan 16 '14 at 11:13
  • @DavidHeffernan In my experience _an invalid instance_ is one of the most common triggers for an AV. So I don't make that sort of assumption. – Disillusioned Jan 16 '14 at 11:14
  • "and the directshow filter" - aren't DirectX objects, including DirectShow filters, COM servers/objects ? IF that holds, a new can of worms is opened and we would have to see how a COM Server of type `Test` is implemented. And how it is passed to the host application. – Arioch 'The Jan 16 '14 at 11:14
  • @CraigYoung Maybe for standalone code, but for COM interop? – David Heffernan Jan 16 '14 at 11:15
  • @Arioch 'The , I just rename it to Test. Sorry let you confused, because before I just want some way can handle the exception gonna happening. – qakmak Jan 16 '14 at 11:17
  • Is B a global variable ? or property/field of TEST class object instance ? – Arioch 'The Jan 16 '14 at 11:18
  • @Arioch 'The: I just see public b: Boolean; in Test Class. and actually I don't know how use delphi , So I don't know it is global or what. but that method actually happening in Test.Lock; I just remove it. Actually method is : Test.Lock try //there is the code finally Test.Unlock – qakmak Jan 16 '14 at 11:23
  • 1
    @DavidHeffernan You're making an assumption (I'll grant not an unreasonable assumption given the clues). But still an assumption because nowhere has OP stated he's using COM. Even so, COM is not immune to abuses that could result in methods being called on invalid instances. – Disillusioned Jan 16 '14 at 11:29
  • @qakmak then you should see if you got a valid self pointer, i added an example into my answer. Also i think you should start with debugging using native language working with COM DirectShow. Using .Net you just add a lot of complex unobvious wrappers into the mix, so would be much harder to see what actually happened behind the hood. – Arioch 'The Jan 16 '14 at 11:36
  • @qakmak " I just see public b: Boolean; in Test Class" that is VERY important to understand the nature of AV. Update you answer ans show the declaration of your TEST class including everything related to COM and interfaces and including B " but that method actually happening" so B is not a variable but a method - a function, that sources you just omitted ????? – Arioch 'The Jan 16 '14 at 11:39
  • @Arioch'The, the class line count is more than 3000+, I can't put all.....because I don't know directshow programming, so I don't know C# how access it...... – qakmak Jan 16 '14 at 11:48
  • @qakmak you can start with declaration of the class before 1st field/method, and the declaration of b within class and the declaration of get_Param – Arioch 'The Jan 16 '14 at 11:49
  • There are lots of tutorials about writing COM servers in Delphi and about using COM interfaces in C# - but you have to determine what is done bad. Either you did not make a correct server, or you did not made a correct client. Then you would be able to make a new question regarding either Delphi or C# and putting all the needed details upfront – Arioch 'The Jan 16 '14 at 11:51
  • And please, really do show in your q. the declaration of class, and get_param and b. It is really critical info. Why do we need to beg you for it? – Arioch 'The Jan 16 '14 at 13:25
  • @Arioch 'The: you can just go away If you still Angry because I'm not set you answer to best answer. – qakmak Jan 16 '14 at 13:41
  • @qakmak my being angry is you simplistic explanation, since you don't want to think that i may be right. Look that no one else had stopped me. Trust me, if i would just talk nonsense, i would be stopped hour ago. But i am not. Because i spell correct things. If my English is too bad to please your ears does not mean the information i do ask is not important. I understand that that idea pleases you. But it is wrong. – Arioch 'The Jan 16 '14 at 13:44
  • @qakmak Arioch is trying to help. – David Heffernan Jan 16 '14 at 16:28
  • There is no `get_Param` in `IDCDSPFilterInterface`. – David Heffernan Jan 16 '14 at 16:36
  • David Heffernan@: Yes, I told you I rename it, original name is EnableDelay. – qakmak Jan 16 '14 at 17:15

3 Answers3

2

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

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Arioch 'The
  • 15,799
  • 35
  • 62
  • `HRESULT` return type is a giant clue. This is COM. – David Heffernan Jan 16 '14 at 11:13
  • @DavidHeffernan HResult type is used in many DLLs, not only COM. Also, if we see a heavy bug like AV, then that means assumptions do not hold. specially a rather strong assumption like a COM Server and Object were correctly declared, correctly initialized and correctly passed. – Arioch 'The Jan 16 '14 at 11:20
  • @Arioch'The Deny it if you like. The evidence is very clear. What do you think `[PreserveSig]` is all about? – David Heffernan Jan 16 '14 at 11:23
  • @DavidHeffernan there was no Update 3 when i was typing my answer – Arioch 'The Jan 16 '14 at 11:38
  • Why when I'm try use var ptr: ^BOOL'; it tell me a lot error...on delphi – qakmak Jan 16 '14 at 11:43
  • @qakmak "it tell me a lot error" that ZERO of information, i cannot read the error with your eyes, nor can i read the sources HOW you try to use it. Concealing diagnostic messages and the sources changed is the most obvious and harming anti-fixing action, sorry. http://www.catb.org/~esr/faqs/smart-questions.html#beprecise – Arioch 'The Jan 16 '14 at 11:53
  • @Arioch 'The: don't angry, I don't know delphi. when I'm write it in try. there is a red color under the var, and then I move the mouse to the place, there is display a tooltip: excepted finally but received var. I never see error like that....so I can only tell you error..... – qakmak Jan 16 '14 at 12:00
  • @qakmak There's a misplaced apostrophe. `^BOOL';` should be `^BOOL;`. – Disillusioned Jan 16 '14 at 12:00
  • @qakmak read the link plz. It is not about knowing something, it is about common logic and sharing what you are the only person on Earth who knows. And what is very needed – Arioch 'The Jan 16 '14 at 12:05
  • @Craig Young, thanks, I'm also find I must put the var to the first line of the function. – qakmak Jan 16 '14 at 12:06
  • @qakmak actually before the 1st line of the function, when "line" is usually meant "vcommand" or "statement" or "line of CODE". Above i gave you wikipedia link for pascal language, please do read it too. There are ABC that you should know at your fingertips before even trying to change/debug delphi code – Arioch 'The Jan 16 '14 at 12:07
  • @Arioch 'The, very sorry, because I can't speak English very well. So......sorry for everything..... – qakmak Jan 16 '14 at 12:09
  • `var ptr: ^BOOL` won't help. You simply need to be clear about what the interop interface is. At the moment I see no clarity. – David Heffernan Jan 16 '14 at 12:11
  • @qakmak whatever your languahge is i think you should read both the links, at wikipedia and at SmartQuestions. And also you would maybe find the translations of both to your native language. Otherwise you would have to find a native-language Delphi usergroup. Again, it is not about knowing Delphi, it is not about knowing English, it is about helping us helping you. It is about process. Please do read those links. Save a lot of time for yourself and for us. – Arioch 'The Jan 16 '14 at 12:12
  • @DavidHeffernan 99,9% that it won't. But i think topicstarter at the moment "searches for whatches under the light" before starting to search them in the darkness where he really lost it. He still hopes that simple solutions would help. You would hardly reason him to switch to real and complex solutions before he would iterate into all non-efficient but cheap (no learning curve) options. It might be even just an MT problem and i am sure we would not be able to teach the topicstarter about MT programming ever. – Arioch 'The Jan 16 '14 at 12:15
  • @Arioch 'The, thanks again. but you need to know, I always trying use some simple words let you and other friends know what I mean, if that is let you uncomfortable, please leave this question. but you must to know there is not any one all use your Specify vocabulary. and maybe some people wont use her way to let other people understand. you can't let all people saying all words what you need. I think people still can know what I mean. by the way I'll see the link what you suggest, but I hope you can stop talking about my asking way. I come here want to help me and other people too.don't warry – qakmak Jan 16 '14 at 12:21
  • @qakmak 1st of all, no one ever talked about you "using simple words". The talk was about using that `b <> nil` - the check that you spend your time on and that would not give you ANY results with 99,9% probability. However 0,1% remains. 2nd there are many ways to ask for help. But the critical thing is giving people trying to help you the critically important information no one but you can see. So please do read those links. I am just saying you things, other would be too polite to tell you (and since my English is also bad i am telling in rather expressive than subtle and polite ways) – Arioch 'The Jan 16 '14 at 12:27
  • Ok. I'll see it. but if Some people has much knowledge, will very easy changed to a conceited. I hope you can avoid for a lifetime. – qakmak Jan 16 '14 at 12:37
  • @qakmak i hope too. However in this case the knowledgeable person is you. You and only you can read ( == know) the error. And you and only you can see ( == know) your source. – Arioch 'The Jan 16 '14 at 13:24
  • @Arioch 'The, I think we need to stop told other thing. by the way :nil = ptr and nil <> ptr both return true, So I think maybe your solution can't handle current problem....but still thank you anyway. – qakmak Jan 16 '14 at 15:42
  • My solution (actually step in investigation) is to make a list of created objects and to check if the Self value is correct (was ever created). And to do it in multihread-safe way, if DirectShow and your C# program might go multithreading. What `@b = nil` would not help me (and others) told you, i just helped you to do it since you asked to do. – Arioch 'The Jan 16 '14 at 16:20
1

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.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • If you showed a bit more of the C# side, and a more complete Delphi listing, then I think I'd be able to clear up the mismatch pretty rapidly. `[PreserveSig]` looks incompatible with your `HRESULT` return type. – David Heffernan Jan 16 '14 at 11:14
  • Hi @David Heffernan, I don't find any problem with C# code. I look other sample, looks like all interface write like that, So I still need some way to know exception will be come...... – qakmak Jan 16 '14 at 11:44
  • It would be good to see the C# code. At the moment we have some metadata. Can you show the C# – David Heffernan Jan 16 '14 at 11:49
1

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;
Disillusioned
  • 14,635
  • 3
  • 43
  • 77