www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - DLLs and headaches

reply "Unknown W. Brackets" <unknown simplemachines.org> writes:
This is kinda complicated, hopefully someone will still read it and try it.

DLLs typically don't have access to the host process.  Sometimes, when 
creating plugins, such access may be desirable.  The typical solution is 
to have the host and plugins both load a secondary DLL.

I've tried to replicate this with D.  I have a stub program, a "primary" 
dll, and a "plugin" dll.

Although the solution in itself does work, I'm having a lot of problems 
and they seem related to D.  But, maybe I'm just doing it all wrong?

If I import std.stdio in a DLL, it won't compile.  Period.  Otherwise, 
the primary DLL never finishes - it just dies when it frees the plugin 
library.

There are a bunch of files, unfortunately.  Listing below:

--- test.d ---
import std.c.stdio;
import primary;

extern (C)
void* gc_getProxy();

// Just a stub to load the primary code.
int main()
{
	printf("Entering main().\n");

	primary_init(gc_getProxy());
	int ret = primary_main();
	primary_terminate();

	printf("Exiting main().\n");
	return ret;
}
---------

--- plugin.d ---
import core.runtime;
import std.c.stdio;
import std.c.windows.windows;

import primary;

extern (Windows)
BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
{
	switch (ulReason)
	{
	case DLL_PROCESS_ATTACH:
		printf("DLL_PROCESS_ATTACH -> plugin\n");
		Runtime.initialize();
		break;

	case DLL_PROCESS_DETACH:
		printf("DLL_PROCESS_DETACH -> plugin\n");
		Runtime.terminate();
		break;

	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
		return false;
	}

	return true;
}

// This is just here to load a plugin and export anything.
export void dummy()
{
}
---------

--- plugin.def ---
LIBRARY         plugin
DESCRIPTION     'Plugin Example'
EXETYPE         NT
CODE            PRELOAD DISCARDABLE
DATA            PRELOAD SINGLE
---------

--- primary.d ---
import std.c.windows.windows;
import core.runtime;
import std.c.stdio;

// SKIP_RUNTIME uses Windows instead of Runtime.*, makes no difference.

// FAIL2 shows that it won't even compile with std.stdio.
version (FAIL2)
	import std.stdio;

extern (Windows)
BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
{
	switch (ulReason)
	{
	case DLL_PROCESS_ATTACH:
		printf("DLL_PROCESS_ATTACH -> primary\n");
		Runtime.initialize();
		break;

	case DLL_PROCESS_DETACH:
		printf("DLL_PROCESS_DETACH -> primary\n");
		Runtime.terminate();
		break;

	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
		return false;
	}

	return true;
}

extern (C)
{
     void gc_setProxy(void* p);
     void gc_clrProxy();
}

export void primary_init(void* gc)
{
	printf("primary_init()\n");
	gc_setProxy(gc);
}

export void primary_terminate()
{
	printf("primary_terminate()\n");
	gc_clrProxy();
}

export int primary_main()
{
	HMODULE h;
	FARPROC fp;
	bool unloaded;

	printf("Start Dynamic Link...\n");

	version (SKIP_RUNTIME)
		h = LoadLibraryA("plugin.dll");
	else
		h = cast(HMODULE) Runtime.loadLibrary("plugin.dll");
	if (h is null)
	{
		printf("error loading plugin.dll\n");
		return 1;
	}

     version (FAIL2)
	    writefln("hi");

	version (SKIP_RUNTIME)
		unloaded = FreeLibrary(h) != 0;
	else
		unloaded = Runtime.unloadLibrary(h);

	if (!unloaded)
	{   printf("error freeing plugin.dll\n");
		return 1;
	}

	printf("End...\n");

	return 0;
}
---------

--- primary.def ---
LIBRARY         primary
DESCRIPTION     'Primary Program'
EXETYPE         NT
CODE            PRELOAD DISCARDABLE
DATA            PRELOAD SINGLE
---------

--- compilation ---
echo === Compile the primary DLL.
dmd primary.d primary.def -g -L/map
implib /noi /system primary.lib primary.dll

echo === Compile the example plugin.
dmd plugin.d plugin.def primary.lib -g -L/map

echo === Compile the stub.
dmd test.d primary.lib -g
---------

Anyone know anything?

-[Unknown]
May 04 2009
parent reply Don <nospam nospam.com> writes:
Unknown W. Brackets wrote:
 This is kinda complicated, hopefully someone will still read it and try it.
 
 DLLs typically don't have access to the host process.  Sometimes, when 
 creating plugins, such access may be desirable.  The typical solution is 
 to have the host and plugins both load a secondary DLL.
 
 I've tried to replicate this with D.  I have a stub program, a "primary" 
 dll, and a "plugin" dll.
 
 Although the solution in itself does work, I'm having a lot of problems 
 and they seem related to D.  But, maybe I'm just doing it all wrong?
 
 If I import std.stdio in a DLL, it won't compile.  Period.  Otherwise, 
 the primary DLL never finishes - it just dies when it frees the plugin 
 library.
Is this D1 or D2? If D2 -- I haven't been able to get D2 DLLs to work at all. They just crash during the initialization (something to do with initialising the thread-locals, I think, but I haven't been able to track it down completely).
May 04 2009
next sibling parent "Unknown W. Brackets" <unknown simplemachines.org> writes:
D2; but actually, it kinda works.  It crashes on freeing the library, 
but it loads fine.

If I use std.stdio, link says that primary.__ModuleInfo is missing, but 
that just means it crashes during compile/link.

That said, I'm very dissapointed that Runtime doesn't support Posix yet. 
  Means I'll have to roll it myself anyway.

-[Unknown]


Don wrote:
 Unknown W. Brackets wrote:
 This is kinda complicated, hopefully someone will still read it and 
 try it.

 DLLs typically don't have access to the host process.  Sometimes, when 
 creating plugins, such access may be desirable.  The typical solution 
 is to have the host and plugins both load a secondary DLL.

 I've tried to replicate this with D.  I have a stub program, a 
 "primary" dll, and a "plugin" dll.

 Although the solution in itself does work, I'm having a lot of 
 problems and they seem related to D.  But, maybe I'm just doing it all 
 wrong?

 If I import std.stdio in a DLL, it won't compile.  Period.  Otherwise, 
 the primary DLL never finishes - it just dies when it frees the plugin 
 library.
Is this D1 or D2? If D2 -- I haven't been able to get D2 DLLs to work at all. They just crash during the initialization (something to do with initialising the thread-locals, I think, but I haven't been able to track it down completely).
May 04 2009
prev sibling parent reply Richard Webb <numpsyuk hotmail.com> writes:
Don Wrote:

 If D2 -- I haven't been able to get D2 DLLs to work at all. They just 
 crash during the initialization (something to do with initialising the 
 thread-locals, I think, but I haven't been able to track it down 
 completely).
Hi, I've recently been having a go at writing a COM object in D, and have run into this when trying it in D2. Debugging through it, i get a crash on the void* pstart = cast(void*) &_tlsstart; on line 1192 of thread.d, due to a null pointer access. This sounds like the issue described at http://www.nynaeve.net/?p=187 ? Is this a known problem with D2 ?
Sep 17 2009
parent Don <nospam nospam.com> writes:
Richard Webb wrote:
 Don Wrote:
 
 If D2 -- I haven't been able to get D2 DLLs to work at all. They just 
 crash during the initialization (something to do with initialising the 
 thread-locals, I think, but I haven't been able to track it down 
 completely).
Hi, I've recently been having a go at writing a COM object in D, and have run into this when trying it in D2. Debugging through it, i get a crash on the void* pstart = cast(void*) &_tlsstart; on line 1192 of thread.d, due to a null pointer access.
Yes, that's the exact same place where it crashed for me.
 This sounds like the issue described at http://www.nynaeve.net/?p=187 ?
Indeed it does. Thanks for the link, that's tremendously helpful.
 Is this a known problem with D2 ?
It wasn't, but it is now. Walter has created bugzilla 3342.
Sep 25 2009