digitalmars.D.learn - access violation With dll?
- Taylor Hillegeist (42/42) Jul 16 2015 Beleive it or not the code below does work. However I get an
- Adam D. Ruppe (16/20) Jul 16 2015 Those signatures don't actually match, your call is overwriting
- jklp (17/60) Jul 16 2015 Your proto is wrong. Your forgot the FFI convention (__cdecl =
- jklp (10/28) Jul 16 2015 Also i guess that the dll returns a null terminated string so the
- Taylor Hillegeist (3/35) Jul 16 2015 Hey that was very useful. Thank you both! Also if you have any
- Adam D. Ruppe (6/8) Jul 16 2015 my book goes into it briefly *shameless plug*
- Adam D. Ruppe (6/15) Jul 16 2015 That's not needed with printf, since it works with null
- Adam D. Ruppe (33/40) Jul 16 2015 Just to go a little deeper into what is happening here, we'll
Beleive it or not the code below does work. However I get an
access violation after every run? any Ideas why?
+++++++++++++++++++++++++Code to Run DLL
function+++++++++++++++++++++++++++
import core.runtime;
import std.stdio;
import core.memory;
import std.c.windows.windows;
int main()
{
HMODULE h;
FARPROC fp;
printf("Start Dynamic Link...\n");
h = cast(HMODULE) Runtime.loadLibrary("SharedLib.dll");
void function(ref char[], int) Testf
= cast(void function(ref char[], int))
GetProcAddress(h, "Test"); //Function Says HELLO WORLD
char[] STUFF;
STUFF.length = 5000;
Testf( STUFF , STUFF.length);
printf("%s\n", (&STUFF)); //PRINTS HELLO WORLD
Runtime.unloadLibrary(h);
printf("End...\n");
return 0;
}
++++++++++++++++++++++++++++++END CODE+++++++++++++++++++++++++++
the function header has this line:
void __cdecl Test(char MyOutput[], int32_t len);
and i get this Error:
object.Error (0): Access Violation
----------------
0x77206568
0x646C726F
0x00405A2C in int object.ModuleInfo.opApply(scope int
delegate(object.ModuleInfo*))
0x0040222C in main
0x00414949 in mainCRTStartup
0x7678337A in BaseThreadInitThunk
0x770592E2 in RtlInitializeExceptionChain
0x770592B5 in RtlInitializeExceptionChain
To be honest I was surprised this worked, since i am fairly
unfamiliar to linking to dlls.
Jul 16 2015
On Thursday, 16 July 2015 at 17:04:09 UTC, Taylor Hillegeist wrote:void function(ref char[], int) Testf = cast(void function(ref char[], int)) GetProcAddress(h, "Test"); //Function Says HELLO WORLDvoid __cdecl Test(char MyOutput[], int32_t len);Those signatures don't actually match, your call is overwriting the stack with the string data, which means main cannot return properly; all that stuff has been smashed to bits. The proper D signature of that C function is: extern(C) void function(char*, int); You really shouldn't try to use D arrays or `ref` when interacting with C functions, C doesn't understand those D features. (You can make it work but it needs cooperation in both functions.) Instead, stick to the basic types C supports like ints and pointers. If you fix that, your code should work. I'd say go ahead and alias the type for easier use extern(C) alias dll_func_type = void function(char*, int); auto Testf = cast(dll_func_type) GetProcAddress(...);
Jul 16 2015
On Thursday, 16 July 2015 at 17:04:09 UTC, Taylor Hillegeist
wrote:
Beleive it or not the code below does work. However I get an
access violation after every run? any Ideas why?
+++++++++++++++++++++++++Code to Run DLL
function+++++++++++++++++++++++++++
import core.runtime;
import std.stdio;
import core.memory;
import std.c.windows.windows;
int main()
{
HMODULE h;
FARPROC fp;
printf("Start Dynamic Link...\n");
h = cast(HMODULE) Runtime.loadLibrary("SharedLib.dll");
void function(ref char[], int) Testf
= cast(void function(ref char[], int))
GetProcAddress(h, "Test"); //Function Says HELLO WORLD
char[] STUFF;
STUFF.length = 5000;
Testf( STUFF , STUFF.length);
printf("%s\n", (&STUFF)); //PRINTS HELLO WORLD
Runtime.unloadLibrary(h);
printf("End...\n");
return 0;
}
++++++++++++++++++++++++++++++END
CODE+++++++++++++++++++++++++++
the function header has this line:
void __cdecl Test(char MyOutput[], int32_t len);
and i get this Error:
object.Error (0): Access Violation
----------------
0x77206568
0x646C726F
0x00405A2C in int object.ModuleInfo.opApply(scope int
delegate(object.ModuleInfo*))
0x0040222C in main
0x00414949 in mainCRTStartup
0x7678337A in BaseThreadInitThunk
0x770592E2 in RtlInitializeExceptionChain
0x770592B5 in RtlInitializeExceptionChain
To be honest I was surprised this worked, since i am fairly
unfamiliar to linking to dlls.
Your proto is wrong. Your forgot the FFI convention (__cdecl =
extern(C)).
Try this instead:
---
extern(C)
alias Proto = void function(char*, int);
Proto func = cast(Proto) GetProcAddress(h, "Test");
if (func)
{
char[] STUFF;
STUFF.length = 5000;
func (STUFF.ptr , STUFF.length);
// prints etc...
}
----
Jul 16 2015
On Thursday, 16 July 2015 at 17:22:50 UTC, jklp wrote:On Thursday, 16 July 2015 at 17:04:09 UTC, Taylor Hillegeist wrote:Also i guess that the dll returns a null terminated string so the result has to be read like this: --- import std.string; printf("%s\n", fromStringz(STUFF.ptr)); --- Otherwise you'll get a random output after the 'HELLO WORLD'. (wait maybe the console will automatically cut... ?)[...]Your proto is wrong. Your forgot the FFI convention (__cdecl = extern(C)). Try this instead: --- extern(C) alias Proto = void function(char*, int); Proto func = cast(Proto) GetProcAddress(h, "Test"); if (func) { char[] STUFF; STUFF.length = 5000; func (STUFF.ptr , STUFF.length); // prints etc... } ----
Jul 16 2015
On Thursday, 16 July 2015 at 17:28:52 UTC, jklp wrote:On Thursday, 16 July 2015 at 17:22:50 UTC, jklp wrote:Hey that was very useful. Thank you both! Also if you have any good resources regarding this topic I would be interested.On Thursday, 16 July 2015 at 17:04:09 UTC, Taylor Hillegeist wrote:Also i guess that the dll returns a null terminated string so the result has to be read like this: --- import std.string; printf("%s\n", fromStringz(STUFF.ptr)); --- Otherwise you'll get a random output after the 'HELLO WORLD'. (wait maybe the console will automatically cut... ?)[...]Your proto is wrong. Your forgot the FFI convention (__cdecl = extern(C)). Try this instead: --- extern(C) alias Proto = void function(char*, int); Proto func = cast(Proto) GetProcAddress(h, "Test"); if (func) { char[] STUFF; STUFF.length = 5000; func (STUFF.ptr , STUFF.length); // prints etc... } ----
Jul 16 2015
On Thursday, 16 July 2015 at 19:25:42 UTC, Taylor Hillegeist wrote:Also if you have any good resources regarding this topic I would be interested.my book goes into it briefly *shameless plug* https://www.packtpub.com/application-development/d-cookbook The interfacing with C page on the dlang.org helps too: http://dlang.org/interfaceToC
Jul 16 2015
On Thursday, 16 July 2015 at 17:28:52 UTC, jklp wrote:Also i guess that the dll returns a null terminated string so the result has to be read like this: --- import std.string; printf("%s\n", fromStringz(STUFF.ptr)); ---That's not needed with printf, since it works with null terminated strings natively (it is itself a C function). Good advice for using writef though, or you can also just `to!string(cstr)` to get one.Otherwise you'll get a random output after the 'HELLO WORLD'. (wait maybe the console will automatically cut... ?)the console won't, it'll generally spew trash.
Jul 16 2015
On Thursday, 16 July 2015 at 17:04:09 UTC, Taylor Hillegeist
wrote:
void function(ref char[], int) Testf
= cast(void function(ref char[], int))
GetProcAddress(h, "Test"); //Function Says HELLO WORLD
char[] STUFF;
STUFF.length = 5000;
Testf( STUFF , STUFF.length);
printf("%s\n", (&STUFF)); //PRINTS HELLO WORLD
Just to go a little deeper into what is happening here, we'll
convert the D features into C features and understand what it
sees.
A D array, `char[]`, is seen in C as: `struct char_array { size_t
length; char* ptr; }`. A D `ref` is seen in C as a pointer.
So, your function there, in C, would look like:
void function(struct char_array *arr, int);
Which isn't what you were hoping for... so what happened when you
called it was the C side got:
Testf((char*) &STUFF, 5000);
Which runs... but what is &STUFF? It is one of those char_array
structs sitting on the stack! Which is only 8 bytes long.
So when the C function wrote out HELLO WORLD\0, your D array got
smashed with:
length = (size_t) 'LLEH';
ptr = (char*) 'ROW ';
And the 'LD\0' went right out of bounds and wrote over whatever
else was on the stack next (which is probably the HMODULE so when
you called FreeLibrary, it tried to free junk and caused the
access violation, but I'm not sure, you could load up a debugger
and try to find out, but the main point is that it overwrote
memory that it wasn't supposed to!).
The printf, however, ran because you made the same mistake twice
- passing &STUFF to it, while wrong, just passed the data your
last call clobbered.... coincidentally being valid enough to
print out.
Then the extern(C) vs extern(D) thing can come into play, but
here you just lucked out.
So yeah to avoid this in the future, be sure all those things
match the way C sees them - ref and arrays are generally wrong
there, use plain pointers instead.
Jul 16 2015









"Adam D. Ruppe" <destructionator gmail.com> 