Re: Elegant way to use dynamic bindings

2018-03-08 Thread Dennis via Digitalmars-d-learn

On Friday, 9 February 2018 at 20:19:33 UTC, Dennis wrote:
I'd still like to find a nice way to generate the boilerplate 
code for dynamic loading, if I come up with something I'll post 
it here.


So I ended up using an import library for a while, but I then 
wanted to get the handle of the DLL, which I don't know how to do 
with an import library. I also didn't like the non-customizable 
Windows pop-ups that appear when the libraries can't be found so 
I finally wrote some mixin code to generate the boilerplate for 
dynamic loading:


https://gist.github.com/dkorpel/3bf108ca48cb43bdbe3cc8bf30405b4d

Now you only need to declare the functions in a Struct:
```
struct FunctionsInMyDLL {
int getVersion();
string getName();
// more functions
}
```
And the templates do the rest. :)


Re: Elegant way to use dynamic bindings

2018-02-09 Thread Dennis via Digitalmars-d-learn

On Friday, 9 February 2018 at 18:14:06 UTC, Mike Wey wrote:
You may need to pass `/s` to implib so it will add the 
underscore to the symbol in the import library. If it's 
actually needed depends on what the dll uses.


That did it, now both dynamic loading and dynamic linking work. 
:) Thanks both of you.


I'd still like to find a nice way to generate the boilerplate 
code for dynamic loading, if I come up with something I'll post 
it here.


Re: Elegant way to use dynamic bindings

2018-02-09 Thread Mike Wey via Digitalmars-d-learn

On 09-02-18 15:04, Dennis wrote:
I read the Derelict documentation a while ago, I didn't grasp all of it. 
Reading it again, I can now make sense of it though. :)


On Friday, 9 February 2018 at 12:53:44 UTC, Mike Parker wrote:
Did you link with the library you created with implib? That linker 
error suggests you didn't.


I added `pragma(lib, "mupen64plus.lib");` above the extern(C) block.
Adding `libs "mupen64plus"` to dub.sdl doesn't make a difference.

The thing that confuses me is that the import lib has symbols without 
underscore prefix (I see them when running `libunres -p 
mupen64plus.lib`), but when I change the function pointer declaration 
into a function declaration it tries to link "_CoreGetAPIVersions" and 
can't find it.


I put the .dll's in the root of the project directory by the way. Does 
that count as a "system library search path"?


You may need to pass `/s` to implib so it will add the underscore to the 
symbol in the import library. If it's actually needed depends on what 
the dll uses.


--
Mike Wey


Re: Elegant way to use dynamic bindings

2018-02-09 Thread Dennis via Digitalmars-d-learn

On Friday, 9 February 2018 at 14:51:30 UTC, Mike Parker wrote:
Where was the lib file located? Was it in the root project 
directory? How are you compiling your project? What does your 
directory tree look like?

(...)
That depends. Is that the directory where your executable is 
written? Are you launching it from inside an Visual Studio or 
from the command line? Normally, the executable's directory is 
on the system path, but when using VS the default configuration 
is to write the executables into configuration-specific 
subdirectories.


I use `dub run` from cmd or Mono-D. All .exe, .lib and .dll files 
are in the root. Source files are in the subdirectory 'source'.


I tried to reduce the problem by making a simple test folder 
containing the necessary .dll files, import library and source 
files:


freetype6.dll
libpng12.dll
libpng3.dll
main.d
main.exe
main.obj
mupen64plus-audio-sdl.dll
mupen64plus-input-sdl.dll
mupen64plus-rsp-hle.dll
mupen64plus-video-glide64mk2.dll
mupen64plus-video-rice.dll
mupen64plus.dll
mupen64plus.lib
SDL.dll
zlib1.dll

Where main.d is:
```
import std.stdio;

version(dynamiclink) {

pragma(lib, "mupen64plus.lib");
extern(C) nothrow @nogc {
int CoreGetAPIVersions(int*, int*, int*, int*);
}

int main() {
int a, b, c, d;
CoreGetAPIVersions(, , , );
writeln("Version: ", a, " - ", b, " - ", c, " - ", d);
return 0;
}
}

version(dynamicload) {

	import core.sys.windows.windows: LoadLibrary, GetProcAddress, 
GetLastError;
	extern(C) alias p_CoreGetAPIVersions = int function(int*, int*, 
int*, int*);

p_CoreGetAPIVersions CoreGetAPIVersions;

int main() {
auto handle = LoadLibrary("mupen64plus.dll");
		CoreGetAPIVersions = cast(p_CoreGetAPIVersions) 
GetProcAddress(handle, "CoreGetAPIVersions");


int a, b, c, d;
CoreGetAPIVersions(, , , );
writeln("Version: ", a, " - ", b, " - ", c, " - ", d);
return 0;
}
}
```

With `dmd main.d -version=dynamicload` it works, but with `dmd 
main.d -version=dynamiclink` it still gives this:


main.obj(main)
Error 42: Symbol Undefined _CoreGetAPIVersions
Error: linker exited with status 1


Re: Elegant way to use dynamic bindings

2018-02-09 Thread Mike Parker via Digitalmars-d-learn

On Friday, 9 February 2018 at 14:04:05 UTC, Dennis wrote:

I added `pragma(lib, "mupen64plus.lib");` above the extern(C) 
block.
Adding `libs "mupen64plus"` to dub.sdl doesn't make a 
difference.


Where was the lib file located? Was it in the root project 
directory? How are you compiling your project? What does your 
directory tree look like?




The thing that confuses me is that the import lib has symbols 
without underscore prefix (I see them when running `libunres -p 
mupen64plus.lib`), but when I change the function pointer 
declaration into a function declaration it tries to link 
"_CoreGetAPIVersions" and can't find it.


Yes, the underscore is normally prepended to cdecl functions on 
Windows. It makes no difference if your function prototypes are 
properly declared.




I put the .dll's in the root of the project directory by the 
way. Does that count as a "system library search path"?


That depends. Is that the directory where your executable is 
written? Are you launching it from inside an Visual Studio or 
from the command line? Normally, the executable's directory is on 
the system path, but when using VS the default configuration is 
to write the executables into configuration-specific 
subdirectories.


Re: Elegant way to use dynamic bindings

2018-02-09 Thread Dennis via Digitalmars-d-learn
I read the Derelict documentation a while ago, I didn't grasp all 
of it. Reading it again, I can now make sense of it though. :)


On Friday, 9 February 2018 at 12:53:44 UTC, Mike Parker wrote:
Did you link with the library you created with implib? That 
linker error suggests you didn't.


I added `pragma(lib, "mupen64plus.lib");` above the extern(C) 
block.

Adding `libs "mupen64plus"` to dub.sdl doesn't make a difference.

The thing that confuses me is that the import lib has symbols 
without underscore prefix (I see them when running `libunres -p 
mupen64plus.lib`), but when I change the function pointer 
declaration into a function declaration it tries to link 
"_CoreGetAPIVersions" and can't find it.


I put the .dll's in the root of the project directory by the way. 
Does that count as a "system library search path"?


Re: Elegant way to use dynamic bindings

2018-02-09 Thread Mike Parker via Digitalmars-d-learn

On Friday, 9 February 2018 at 12:15:04 UTC, Dennis wrote:



I presume the .dll isn't loaded properly (if at all), but I 
can't find a load function in the .lib and don't know how to 
debug this. So I guess I'll just do it manually since that 
works, but does anyone have some tips to make .dll bindings 
elegantly?


I suggest you read this first:

http://derelictorg.github.io/bindings/

It explains the difference between dynamic bindings and static 
bindings. The important thing to understand is that both types 
can be used with DLLs, but only static bindings can be use with 
static libraries.


Dynamic bindings have no link time dependency on the DLL and the 
DLL must be loaded manually. Static bindings have a link time 
dependency and can be linked with either a static library, an 
import library (on Windows -- what you get when you run implib or 
compile a DLL yourself), or directly with a shared object (.so) 
on non-Windows systems (and probably .dylib/Frameworks on Mac).


Dynamic bindings use function pointer because that's the only way 
to do manuall loading. For static bindings, you use normal 
function declarations and the OS will load the DLL automatically 
when the app starts up (dynamic loading) if you've linked to an 
import library or .so, and, of course, will load nothing if 
you've linked to a static library.


Some Derelict packages, like DerelictSDL2 and DerelictGLFW3, 
support both dynamic and static binding. For the former, the 
function pointer declarations and the loader are all in [1]. For 
the latter, there is no loader and the declarations are all in 
[2].


[1] 
https://github.com/DerelictOrg/DerelictGLFW3/blob/master/source/derelict/glfw3/dynload.d


[2] 
https://github.com/DerelictOrg/DerelictGLFW3/blob/master/source/derelict/glfw3/statfun.d


So if you don't need to load manually and don't mind the 
link-time dependency on the C library, then you can use normal 
function declarations in your binding:


extern(C) @nogc nothrow {
void foo();
}



Re: Elegant way to use dynamic bindings

2018-02-09 Thread Mike Parker via Digitalmars-d-learn

On Friday, 9 February 2018 at 12:15:04 UTC, Dennis wrote:

I found the IMPLIB tool 
(http://www.digitalmars.com//ctg/implib.html) and made a .lib 
for the .dll and at first I got:


Error 42: Symbol Undefined _CoreGetAPIVersions
Error: linker exited with status 1



Forgot to address this in the previous post.

Did you link with the library you created with implib? That 
linker error suggests you didn't.