www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Access Violation calling a D DLL from a C# DLL

reply David Gileadi <david et solutionstream com> <David_member pathlink.com> writes:
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# ;)
Sep 27 2005
next sibling parent reply James Dunne <james.jdunne gmail.com> writes:
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.
Sep 28 2005
next sibling parent reply Sean Kelly <sean f4.ca> writes:
In article <dheit4$95b$1 digitaldaemon.com>, James Dunne says...
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! =)

Someone was working on a way to compile D to IDL code, and things had gotten pretty far last I heard. But I'll be darned if I can remember who it was :p Sean
Sep 28 2005
parent James Dunne <james.jdunne gmail.com> writes:
Sean Kelly wrote:
 In article <dheit4$95b$1 digitaldaemon.com>, James Dunne says...
 
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! =)

Someone was working on a way to compile D to IDL code, and things had gotten pretty far last I heard. But I'll be darned if I can remember who it was :p Sean

I'm not sure if compiling D code to MSIL is the best solution here, but we'd have to ask the OP what his reasons are for segregating the application between C# and D.
Sep 28 2005
prev sibling parent reply David Gileadi <david et solutionstream com> <David_member pathlink.com> writes:
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.
Sep 28 2005
next sibling parent reply =?UTF-8?B?VGhvbWFzIEvDvGhuZQ==?= <thomas-dloop kuehne.cn> writes:
-----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-----
Sep 28 2005
parent reply David Gileadi <david et solutionstream com> <David_member pathlink.com> writes:
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
Sep 28 2005
next sibling parent reply Carlos Santander <csantander619 gmail.com> writes:
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
Sep 28 2005
next sibling parent reply Sean Kelly <sean f4.ca> writes:
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
Sep 28 2005
parent Carlos Santander <csantander619 gmail.com> writes:
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
Sep 28 2005
prev sibling parent reply David Gileadi <david et solutionstream com> <David_member pathlink.com> writes:
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.
Sep 28 2005
parent Carlos Santander <csantander619 gmail.com> writes:
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
Sep 28 2005
prev sibling next sibling parent JT <jtd514 ameritech.net> writes:
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

Sep 28 2005
prev sibling parent reply =?UTF-8?B?VGhvbWFzIEvDvGhuZQ==?= <thomas-dloop kuehne.cn> writes:
-----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-----
Sep 28 2005
parent reply David Gileadi <david et solutionstream com> <David_member pathlink.com> writes:
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?
Sep 29 2005
parent David Gileadi <david et solutionstream com> <David_member pathlink.com> writes:
I suppose I shouldn't have made the below a P.S. in another topic, since that
probably got it ignored.  Again, I only did a quick look, but just wanted to see
if this is really an issue or just my ignorance.

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?

-Dave
Sep 30 2005
prev sibling next sibling parent reply pragma <pragma_member pathlink.com> writes:
In article <dhes7r$i5q$1 digitaldaemon.com>, David Gileadi <david et
solutionstream com> says...
 [snip]

It's only when my code runs for a while, presumably also using more memory, that
I get the access violation.

You mentioned that you're disabling the GC in the D-dll, is this still the case? If so, then this is almost certainly the problem. While disabling the GC side-steps any issues you may have with premature collections from D's GC, you now have to adjust how you code your app. In a nutshell: virtually anything that would cause a leak in a C program now applies to your D code, so you need to use 'delete' where appropriate to control memory usage if you're not already. There are also some D idoms that will consume additional memory without your consent, and are beyond discrete control via 'delete'. Array concatenations, and other various uses of "Copy on Write" are the front-line offenders here. Also, there may be portions of Phobos (and any other external D libs for that matter) that may not be "non-GC friendly" and assume a fully (or at least periodically) garbage collected environment. You may need to pair back your dependencies to avoid any problems. Otherwise, just stick with providing structs and other scalars/primitives through your dll's interface, keep the GC on, and you should be okay. - EricAnderton at yahoo
Sep 28 2005
parent David Gileadi <david et solutionstream com> <David_member pathlink.com> writes:
In article <dhf29r$nmg$1 digitaldaemon.com>, pragma says...
In article <dhes7r$i5q$1 digitaldaemon.com>, David Gileadi <david et
solutionstream com> says...
 [snip]

It's only when my code runs for a while, presumably also using more memory, that
I get the access violation.

You mentioned that you're disabling the GC in the D-dll, is this still the case? If so, then this is almost certainly the problem. While disabling the GC side-steps any issues you may have with premature collections from D's GC, you now have to adjust how you code your app. In a nutshell: virtually anything that would cause a leak in a C program now applies to your D code, so you need to use 'delete' where appropriate to control memory usage if you're not already. There are also some D idoms that will consume additional memory without your consent, and are beyond discrete control via 'delete'. Array concatenations, and other various uses of "Copy on Write" are the front-line offenders here. Also, there may be portions of Phobos (and any other external D libs for that matter) that may not be "non-GC friendly" and assume a fully (or at least periodically) garbage collected environment. You may need to pair back your dependencies to avoid any problems. Otherwise, just stick with providing structs and other scalars/primitives through your dll's interface, keep the GC on, and you should be okay. - EricAnderton at yahoo

No, I wasn't brave enough to permanently disable the GC, just tried it to see if it was the culprit (it didn't help the problem). I quickly removed the disable call. GC in my opinion is one of the benefits of D. I appreciate your advice in any case.
Sep 28 2005
prev sibling parent James Dunne <james.jdunne gmail.com> writes:
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.
Sep 29 2005
prev sibling parent reply Joel Lucsy <jjlucsy usol.com> writes:
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. -- Joel Lucsy "The dinosaurs became extinct because they didn't have a space program." -- Larry Niven
Sep 28 2005
parent Niall FitzGibbon <billdoor gmail.com> writes:
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?
Sep 28 2005