September 28, 2005
Joel Lucsy wrote:
> David Gileadi <david et solutionstream com> wrote:
> 
>> I'm getting an access violation when calling into a D DLL from C#.
>>
>> A bit of background:  I'm writing a chess AI in D for a school project.  It has
>> to interface with a C# application, in VS 2005 Beta 2.  The C# application
>> dynamically loads a C# DLL, which is a thin wrapper for my D DLL.  This wrapper
>> uses C#'s interop services to load my D DLL and make calls to it.  The call I'm
>> making which is crashing is (in the C# code):
>>
>> [DllImport("chess.dll")]
>> private static extern ChessMove getNextMove(ChessMove opponentsMove);
>>
>> On the D side, the method looks like:
>>
>> export extern(C) ChessMove getNextMove(ChessMove opponentsMove){..}
> 
> 
> I suspect the calling convention between C# and D doesn't match. By default, C# assumes _stdcall. But I see you've declared the D side as extern(C).
> You can try specifing on the C# side
> [DllImport("chess.dll",CallingConvention=CallingConvention.Cdecl)]
> Or you could modify the D syntax, but I'm unfamiliar with how that works in D.
> Hope that helps.
> 

export extern(Windows) will export stdcall in D, I believe.

However, if the problem was that C# was expecting stdcall and D was providing cdecl, I don't see why the length of time the function runs for would make a difference -- surely it would crash regardless as soon as the C# code tried to use the stack after the function returned?
September 28, 2005
David Gileadi <david et solutionstream com> escribió:
> In article <dhevd4$kr0$1@digitaldaemon.com>, =?UTF-8?B?VGhvbWFzIEvDvGhuZQ==?=
> says...
> 
>>What happen if you replace getNextMove with a dummy D function that
>>simply a) waits 5 seconds or b) loops (without any alarm/timer) for 5
>>seconds?
>>
>>Thomas
> 
> 
> Wow.  I wouldn't have expected it, but testing your dummy function theory a)
> using the code
> 
> Thread.getThis().wait(5000);
> 
> and then returning a dummy ChessMove causes the access violation.  So it seems
> that for whatever reason, the layer between the two sides can't handle the long
> call.  Maybe it's C# trying to protect itself.  In any case, I can probably set
> up some workaround using callbacks or some such.  Thanks for the help,
> 
> -Dave
> 
> 

It could be specific to Microsoft's implementation, because I tried something like that using Mono and I didn't get any AVs. What I used as the function body was a while(true) {}. I couldn't use the Thread version because the program just exited. I couldn't also use printf (to debug or whatever) because of the same reason. Have you been able to do that?

I'm sorry I can't be more helpful, I just thought I'd let you know it seems to work using Mono.

-- 
Carlos Santander Bernal
September 28, 2005
In article <dhf7k5$t1s$1@digitaldaemon.com>, Carlos Santander says...
>
>It could be specific to Microsoft's implementation, because I tried something like that using Mono and I didn't get any AVs. What I used as the function body was a while(true) {}. I couldn't use the Thread version because the program just exited. I couldn't also use printf (to debug or whatever) because of the same reason. Have you been able to do that?

Microsoft's .NET implementation has a fairly aggressive GC, so I suppose it's possible that the GC is running in a different thread and moving stuff around while the call is in progress.  Where is this struct stored?


Sean


September 28, 2005
In article <dhf7k5$t1s$1@digitaldaemon.com>, Carlos Santander says...
>
>David Gileadi <david et solutionstream com> escribió:
>> In article <dhevd4$kr0$1@digitaldaemon.com>, =?UTF-8?B?VGhvbWFzIEvDvGhuZQ==?= says...
>> 
>>>What happen if you replace getNextMove with a dummy D function that
>>>simply a) waits 5 seconds or b) loops (without any alarm/timer) for 5
>>>seconds?
>>>
>>>Thomas
>> 
>> 
>> Wow.  I wouldn't have expected it, but testing your dummy function theory a) using the code
>> 
>> Thread.getThis().wait(5000);
>> 
>> and then returning a dummy ChessMove causes the access violation.  So it seems that for whatever reason, the layer between the two sides can't handle the long call.  Maybe it's C# trying to protect itself.  In any case, I can probably set up some workaround using callbacks or some such.  Thanks for the help,
>> 
>> -Dave
>> 
>> 
>
>It could be specific to Microsoft's implementation, because I tried something like that using Mono and I didn't get any AVs. What I used as the function body was a while(true) {}. I couldn't use the Thread version because the program just exited. I couldn't also use printf (to debug or whatever) because of the same reason. Have you been able to do that?
>
>I'm sorry I can't be more helpful, I just thought I'd let you know it seems to work using Mono.
>
>-- 
>Carlos Santander Bernal

I do have printf in my code, and it didn't cause my program to exit (although it didn't do anything useful).  I haven't tried Threads.  I'll probably have to try them, though, if I'm going to implement callbacks, which I'll probably have to do if this problem persists.  I'll post an update after I try it as to whether it works.


September 28, 2005
Sean Kelly escribió:
> In article <dhf7k5$t1s$1@digitaldaemon.com>, Carlos Santander says...
> 
>>It could be specific to Microsoft's implementation, because I tried something like that using Mono and I didn't get any AVs. What I used as the function body was a while(true) {}. I couldn't use the Thread version because the program just exited. I couldn't also use printf (to debug or whatever) because of the same reason. Have you been able to do that?
> 
> 
> Microsoft's .NET implementation has a fairly aggressive GC, so I suppose it's
> possible that the GC is running in a different thread and moving stuff around
> while the call is in progress.  Where is this struct stored?
> 
> 
> Sean
> 
> 

In my case, I first passed a reference to a struct (a class, in fact) from the exe to the dll, so it was in .Net. Then, I passed a struct to the dll and then returned another to the exe. In both cases, it worked.

-- 
Carlos Santander Bernal
September 28, 2005
David Gileadi <david et solutionstream com> escribió:
> 
> I do have printf in my code, and it didn't cause my program to exit (although it
> didn't do anything useful).  I haven't tried Threads.  I'll probably have to try
> them, though, if I'm going to implement callbacks, which I'll probably have to
> do if this problem persists.  I'll post an update after I try it as to whether
> it works.
> 
> 

I don't understand that. Didn't you say you used "Thread.getThis().wait(5000);"? That's what I was talking about, which didn't work for me.

Regarding printf, could you post a minimal D DLL using printf? I really couldn't get that to work. Now that I think about it, I think it caused an AV, but I'm not sure.

-- 
Carlos Santander Bernal
September 28, 2005
yah i suspected C# was just timing out. this sounds a lot like how some of the old OLE stuff behaves. I dont think microsoft plays well with others and generally takes brute force methods to keep things to their liking. perhaps you can break the process into smaller steps or stages and just run them one at a time.


David Gileadi <david et solutionstream com> wrote:
> In article <dhevd4$kr0$1@digitaldaemon.com>, =?UTF-8?B?VGhvbWFzIEvDvGhuZQ==?=
> says...
> 
>>-----BEGIN PGP SIGNED MESSAGE-----
>>Hash: SHA1
>>
>>David Gileadi <david et solutionstream com> schrieb:
>>
>>
>>>Well, my hope (and belief from the D docs) was that D structs are also C binary
>>>compatible, as they are in C#, with some tweaking.  ChessMove is a fairly simple
>>>struct, with 3 enums and 5 ints.  I tested passing it from C# as an argument,
>>>accessing its members and passing back another, and verified that the values
>>>were passed correctly both ways.  None of this resulted in an access violation.
>>>It's only when my code runs for a while, presumably also using more memory, that
>>>I get the access violation.
>>>
>>>So in short, I'd hoped for C binary compatibility, and it's seemed to work as
>>>far as that goes.  My worry is that somehow a garbage collector is trying to
>>>overstep its bounds, or some other strange thing is afoot.
>>
>>Do you check in D that the to-be-returned struct exists at the expected
>>location and is "sane" before actually returning it?
>>
>>What happen if you replace getNextMove with a dummy D function that
>>simply a) waits 5 seconds or b) loops (without any alarm/timer) for 5
>>seconds?
>>
>>Thomas
>>-----BEGIN PGP SIGNATURE-----
>>
>>iD8DBQFDOwGY3w+/yD4P9tIRAlBGAKCILfmpCv5pT2vH8b+du16zLMWSFwCfVkDK
>>Zov+Be5KRcjWofVyL5V4IRw=
>>=jrEC
>>-----END PGP SIGNATURE-----
> 
> 
> Wow.  I wouldn't have expected it, but testing your dummy function theory a)
> using the code
> 
> Thread.getThis().wait(5000);
> 
> and then returning a dummy ChessMove causes the access violation.  So it seems
> that for whatever reason, the layer between the two sides can't handle the long
> call.  Maybe it's C# trying to protect itself.  In any case, I can probably set
> up some workaround using callbacks or some such.  Thanks for the help,
> 
> -Dave
> 
> 
September 29, 2005
David Gileadi <david et solutionstream com> schrieb:

> In article <dhevd4$kr0$1@digitaldaemon.com>, =?UTF-8?B?VGhvbWFzIEvDvGhuZQ==?= says...
> 
>> David Gileadi <david et solutionstream com> schrieb:

[snip]

>> What happen if you replace getNextMove with a dummy D function that
>> simply a) waits 5 seconds or b) loops (without any alarm/timer) for 5
>> seconds?
>> 
>> Thomas

> Wow.  I wouldn't have expected it, but testing your dummy function theory a) using the code
>
> Thread.getThis().wait(5000);
>
> and then returning a dummy ChessMove causes the access violation.  So it seems that for whatever reason, the layer between the two sides can't handle the long call.  Maybe it's C# trying to protect itself.  In any case, I can probably set up some workaround using callbacks or some such.  Thanks for the help,

Are you sure that it is the long call and not the timer itself causing a broken collaboration between C# and D?

Thomas
September 29, 2005
David Gileadi <david et solutionstream com> wrote:
> In article <dheit4$95b$1@digitaldaemon.com>, James Dunne says...
> 
>>David Gileadi <david et solutionstream com> wrote:
>>
>>>I'm getting an access violation when calling into a D DLL from C#.
>>>
>>>A bit of background:  I'm writing a chess AI in D for a school project.  It has
>>>to interface with a C# application, in VS 2005 Beta 2.  The C# application
>>>dynamically loads a C# DLL, which is a thin wrapper for my D DLL.  This wrapper
>>>uses C#'s interop services to load my D DLL and make calls to it.  The call I'm
>>>making which is crashing is (in the C# code):
>>>
>>>[DllImport("chess.dll")]
>>>private static extern ChessMove getNextMove(ChessMove opponentsMove);
>>>
>>>On the D side, the method looks like:
>>>
>>>export extern(C) ChessMove getNextMove(ChessMove opponentsMove){..}
>>>
>>>ChessMove is a struct defined in C# and D, which I've carefully verified to have
>>>the same size and member offsets.
>>>
>>>getNextMove() does a best-move search as deep as it can, time-limited to 5
>>>seconds, after which it returns.  The odd thing is, if I limit it to only run a
>>>couple of levels deep of search, it returns fine--no access violation.  However,
>>>if I search to the full 5-second time limit, I get an AccessViolationException
>>>in C#.
>>>
>>>I've tested the code separately in a plain D program, and it runs fine, no
>>>errors, for the full 5 seconds per move.  It's only when I call it through C#
>>>that it causes the error.
>>>
>>>I suspected the garbage collector, so I tried calling disable() as soon as I
>>>enter getNextMove(), and never calling enable(), just to test.  However, the
>>>access violation still occurs.
>>>
>>>I've searched in this group and on the Internet for reasons this might be
>>>happening, and haven't found any answers.  Just wanted to see if you folks had
>>>any ideas.  I'd hate to have to port to C# ;)
>>>
>>>
>>
>>I don't think you're going to get anywhere attempting to make C# and D binary compatible.  They are completely different animals.  It's like trying to force a square peg into a round hole.
>>
>>What you should do is take an intermediate step.  Since the only thing that is probably guaranteed to be portable between the two languages is a function calling convention, you might have to create "constructor" functions in both your C# and D code which take members from your ChessMove class as parameters and create the respective class in each language.  I'm not quite sure how to handle object references using this method, but I think you get the general idea.  This is basically a boiled down version of RPC (remote procedure call), except yours is local, so I'd say LPC =P.
>>
>>Perhaps it is necessary for someone to write an interop library for D. Pardon my ignorance of existing D projects which already achieve this. Mango comes to mind as a candidate for this sort of thing being done already.  Anyone have such a library?  Speak up! =)
>>
>>BTW, if you'd like me to elaborate more on this concept and do some testing, don't hesitate to ask.
> 
> 
> Thanks for your reply.
> 
> Well, my hope (and belief from the D docs) was that D structs are also C binary
> compatible, as they are in C#, with some tweaking.  ChessMove is a fairly simple
> struct, with 3 enums and 5 ints.  I tested passing it from C# as an argument,
> accessing its members and passing back another, and verified that the values
> were passed correctly both ways.  None of this resulted in an access violation.
> It's only when my code runs for a while, presumably also using more memory, that
> I get the access violation.
> 
> So in short, I'd hoped for C binary compatibility, and it's seemed to work as
> far as that goes.  My worry is that somehow a garbage collector is trying to
> overstep its bounds, or some other strange thing is afoot.
> 
> 

Perhaps they are binary compatible, and perhaps they're not.  I would do a few things:

1) Check the member alignment of your structs.
2) Make sure you're using C#'s unsafe statement modifier to call D's code.
3) Simply provide a dummy D getChessMove() function and test the call over and over to make sure the stack isn't being destroyed
4) If all else fails, pass the object as a set of by-reference parameters to the D function and forget about structs.
September 29, 2005
In article <dhg07c$1fqq$2@digitaldaemon.com>, =?UTF-8?B?VGhvbWFzIEvDvGhuZQ==?= says...
>
>-----BEGIN PGP SIGNED MESSAGE-----
>Hash: SHA1
>
>David Gileadi <david et solutionstream com> schrieb:
>
>> In article <dhevd4$kr0$1@digitaldaemon.com>, =?UTF-8?B?VGhvbWFzIEvDvGhuZQ==?= says...
>> 
>>> David Gileadi <david et solutionstream com> schrieb:
>
>[snip]
>
>>> What happen if you replace getNextMove with a dummy D function that
>>> simply a) waits 5 seconds or b) loops (without any alarm/timer) for 5
>>> seconds?
>>> 
>>> Thomas
>
>> Wow.  I wouldn't have expected it, but testing your dummy function theory a) using the code
>>
>> Thread.getThis().wait(5000);
>>
>> and then returning a dummy ChessMove causes the access violation.  So it seems that for whatever reason, the layer between the two sides can't handle the long call.  Maybe it's C# trying to protect itself.  In any case, I can probably set up some workaround using callbacks or some such.  Thanks for the help,
>
>Are you sure that it is the long call and not the timer itself causing a broken collaboration between C# and D?
>
>Thomas
>-----BEGIN PGP SIGNATURE-----
>
>iD8DBQFDO4S93w+/yD4P9tIRAr0dAKCWPVQcYOuFMCGov+sWkJtzYi1L4wCfYeJV
>mDmcc/4v/ADG4sqvxfimh+I=
>=RmLI
>-----END PGP SIGNATURE-----

No, and in fact after testing dummy function theory b) and not getting an access violation, I figure that the Thread use itself is causing the trouble.  I imagine that the garbage collection thread runs after I allocate enough memory, which is why I get the access violation only after a period of time. Conjecture, but it's my best guess right now.

In any case, I'm getting pretty convinced that I should port this project to C#, to save myself further headache.  It's only a school project, after all.

Thanks everyone for all your suggestions and support.  I'll be sure to get back on the D train for other projects :)

P.S.  Is the garbage collector implemented entirely in D?  I did a (very) quick
look through the GC code in Phobos and discovered that the call to disable()
seems to simply increment the GCX struct's disabled member.  However, from what
I could tell, the disabled memeber is never read (except in an assert), so it
seems that calling disable() would have no effect.  Am I way off-base here?