Using .lib and .dll in D applications
moe via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Tue Jun 21 16:59:54 PDT 2016
I had some time to try it out and I finally got it to work. I
have only tried in windows so far but there was a pitfall in
windows. Your dll need a DllMain entry to compile. This was the
only thing that was missing from your information. The rest
worked perfectly. This may be obvious to most around here, but I
did not know before. So, I thought it might make sense to show my
working solution in case someone else stumbles upon the same
problem.
I wanted the app and the plugin to be independent projects form
one another. So they both need a shared project containing the
interface for the plugin. That makes the 3 projects shown below.
I can than after compiling the app simply copy the plugin dll
into a plugins folder and the app will find it on demand. So that
I could later add more plugins if desired. Obviously in that case
I would have to get a list of available plugins by reading the
filenames in the plugins directory instead of a hard coded path
in the app. I tried to reduce it to the bare minimum with a
working solution. Even with the DllMain entry (which is necessary
for windows) it turns out to be surprisingly compact.
There are 3 distinct projects. I have the following directories
(omitting some generated by dub):
- PluginTest
-- PluginContract // all files for the shared plugin interface
(separate project)
---- source
------ iplugin.d // the interface for the plugin
---- dub.json // the project file for the shared plugin interface
-- TestApp // all files for the app (separate project)
---- packages
------ DerelictUtil-master // contains the project for derelict
---- source
------ app.d // the app
---- dub.json // the project file for the app
-- TestPlugin // all files for the plugin (separate project)
---- source
------ someplugin.d // the plugin
---- dub.json // the project file for the plugin
Here are the files:
Shared plugin interface (Project 1)
===================================
Note, these are necessary for the linker to find the files:
"targetType": "library"
"targetPath": "lib"
PluginTest/PluginContract/dub.json
----------------------------------
{
"name": "plugincontract",
"authors": ["root"],
"description": "A minimal D application.",
"copyright": "Copyright © 2016, root",
"license": "proprietary",
"platforms": ["windows"],
"versions": ["DesktopApp"],
"targetType": "library",
"configurations": [
{
"name": "debug",
"targetPath": "lib",
"buildOptions": ["debugMode", "debugInfo"],
},
{
"name": "release",
"targetPath": "lib",
"buildOptions": ["releaseMode", "optimize", "inline"],
}
]
}
PluginTest/PluginContract/source/iplugin.d
------------------------------------------
module iplugin;
interface IPlugin
{
void Talk(string msg);
}
TestApp (Project 2)
===================
PluginTest/TestApp/dub.json
---------------------------
{
"name": "testapp",
"authors": ["root"],
"description": "A minimal D application.",
"copyright": "Copyright © 2016, root",
"license": "proprietary",
"platforms": ["windows"],
"versions": ["DesktopApp"],
"targetType": "executable",
"dependencies": {
"derelict-util": {"path": "packages/DerelictUtil-master"},
"plugincontract": {"path": "../PluginContract"}
},
"configurations": [
{
"name": "debug",
"targetPath": "bin/debug",
"buildOptions": ["debugMode", "debugInfo"],
},
{
"name": "release",
"targetPath": "bin/release",
"buildOptions": ["releaseMode", "optimize", "inline"],
}
]
}
PluginTest/TestApp/source/app.d
-------------------------------
import std.stdio;
import derelict.util.sharedlib;
import iplugin;
alias GetPluginImpl = extern(C) nothrow IPlugin function();
GetPluginImpl getPlugin;
void main()
{
SharedLib lib;
lib.load(["plugins/testplugin.dll"]);
getPlugin = cast(GetPluginImpl)lib.loadSymbol("getPlugin");
auto plugin = getPlugin();
plugin.Talk("Hello World.");
writeln("End of app.");
}
TestPlugin (Project 3)
======================
PluginTest/TestPlugin/dub.json
------------------------------
{
"name": "testplugin",
"authors": ["root"],
"description": "A minimal D application.",
"copyright": "Copyright © 2016, root",
"license": "proprietary",
"platforms": ["windows"],
"versions": ["DesktopApp"],
"targetType": "dynamicLibrary",
"importPaths": ["../PluginContract"],
"dependencies": {
"plugincontract": {"path": "../PluginContract"}
},
"configurations": [
{
"name": "debug",
"targetPath": "bin/debug",
"buildOptions": ["debugMode", "debugInfo"],
},
{
"name": "release",
"targetPath": "bin/release",
"buildOptions": ["releaseMode", "optimize", "inline"],
}
]
}
PluginTest/TestPlugin/source/SomePlugin.d
-----------------------------------------
module someplugin;
import std.stdio;
import iplugin;
export extern(C) nothrow IPlugin getPlugin()
{
import core.memory : GC;
auto plugin = new SomePlugin();
// Make sure the GC doesn't collect the instance
GC.addRoot(cast(void*)plugin);
return plugin;
}
class SomePlugin : IPlugin
{
// this() {}
void Talk(string msg)
{
writefln("SomePlugin: %s", msg);
}
}
//shared static this() { printf("plugin shared static this\n"); }
//shared static ~this() { printf("plugin shared static ~this\n");
}
version(Windows)
extern(Windows) bool DllMain(void* hInstance, uint ulReason,
void*)
{
import std.c.windows.windows;
import core.sys.windows.dll;
switch (ulReason)
{
default: assert(0);
case DLL_PROCESS_ATTACH:
dll_process_attach( hInstance, true );
break;
case DLL_PROCESS_DETACH:
dll_process_detach( hInstance, true );
break;
case DLL_THREAD_ATTACH:
dll_thread_attach( true, true );
break;
case DLL_THREAD_DETACH:
dll_thread_detach( true, true );
break;
}
return true;
}
Hope it helps someone. And again thanks for the help!
More information about the Digitalmars-d-learn
mailing list