Thread overview
Can't find windows' CreateThread function / concurrency.spawn crashes host application
Jan 01, 2016
alkololl
Jan 01, 2016
alkololl
Jan 01, 2016
Adam D. Ruppe
Jan 02, 2016
alkololl
Jan 02, 2016
Adam D. Ruppe
Jan 02, 2016
alkololl
Jan 02, 2016
Rainer Schuetze
Jan 02, 2016
alkololl
Jan 04, 2016
Rainer Schuetze
January 01, 2016
Hey there and a happy new year,

I wrote a C++ Dll which gets injecrted into another process. Now I want to port that Dll to D. In my C++ Dll I used a while loop which captures all keystrokes via GetAsyncKeyState and waited for F7 to be pressed and lastly unloads the dll via FreeLibraryAndExitThread.
This while loop needs to be run out of an dedicated thread.
I've found that std.c.windows.windows doesn't include a definition for Windows API's CreateThread method and the usage of concurrency.spawn crashes my host application (in which the Dll gets injected to).

How am I supposed to create a thread in the host application? Or are there other ways to capture the F7 keystroke?
January 01, 2016
Here is my code:

// File dllmain.d
module dllmain;

import core.runtime;
import std.c.stdlib;
import std.string;
import std.c.windows.windows;

import honmod;


private HINSTANCE g_hInst;


extern (Windows) BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
{
	g_hInst = hInstance;
	
	switch (ulReason) {
		case DLL_PROCESS_ATTACH:
			Runtime.initialize();
			break;
			
		case DLL_PROCESS_DETACH:
			Runtime.terminate();
			break;
			
		default:
	}
	
	return true;
}


static this()
{
	honmod.initialize(g_hInst);
	MessageBoxA(null, "Dll Injection successful", "", MB_OK);
}


static ~this()
{
	MessageBoxA(null, "Dll ejected", "", MB_OK);
}




// File honmod
module honmod;

import std.concurrency;
import std.c.windows.windows;
import core.thread;


private HINSTANCE _hModule;



// The quit thread waits until F7 gets pressed and then frees the module
private void quitThread()
{
	while (true) {
		// KeyDown
		if (GetAsyncKeyState(VK_F7) & 0x0001) {
			break;
		}
		
		Sleep(1);
	}
	
	FreeLibraryAndExitThread(_hModule, 0);
}


void initialize(HINSTANCE hModule)
{
	_hModule = hModule;
	
	// Spawn the quit thread
	new Thread(&quitThread).start();
}
January 01, 2016
On Friday, 1 January 2016 at 22:02:46 UTC, alkololl wrote:
> I've found that std.c.windows.windows doesn't include a

std.c.windows is basically useless. The new version should have it in core.sys.windows.windows though I'm not sure if it has actually been released yet.

If it isn't in there on your version, you can also just define teh function yourself somewhere and use it. Add to your module:

extern(Windows)
HANDLE CreateThread(
   LPSECURITY_ATTRIBUTES  lpThreadAttributes,
   SIZE_T                 dwStackSize,
   LPTHREAD_START_ROUTINE lpStartAddress,
   LPVOID                 lpParameter,
   DWORD                  dwCreationFlags,
   LPDWORD                lpThreadId
);

and then call it. If a type isn't defined you can replace it with void* usually.
January 02, 2016
On Friday, 1 January 2016 at 22:45:20 UTC, Adam D. Ruppe wrote:
> On Friday, 1 January 2016 at 22:02:46 UTC, alkololl wrote:
>> I've found that std.c.windows.windows doesn't include a
>
> std.c.windows is basically useless. The new version should have it in core.sys.windows.windows though I'm not sure if it has actually been released yet.
>
> If it isn't in there on your version, you can also just define teh function yourself somewhere and use it. Add to your module:
>
> extern(Windows)
> HANDLE CreateThread(
>    LPSECURITY_ATTRIBUTES  lpThreadAttributes,
>    SIZE_T                 dwStackSize,
>    LPTHREAD_START_ROUTINE lpStartAddress,
>    LPVOID                 lpParameter,
>    DWORD                  dwCreationFlags,
>    LPDWORD                lpThreadId
> );
>
> and then call it. If a type isn't defined you can replace it with void* usually.

Thanks, I replaced LPSECURITY_ATTRIBUTES and LPTHREAD_START_ROUTINE with void* and it works now. Anyhow the method FreeLibraryAndExitThread, which worked perfectly in the C++ Dll, doesn't unload the D Dll properly (the call has no effect at all). Why is that?
January 02, 2016
On Saturday, 2 January 2016 at 00:32:20 UTC, alkololl wrote:
>  Why is that?

I'm not sure, but in the switch you posted, you didn't handle the DLL_THREAD_ATTACH and DLL_THREAD_DETACH cases, the runtime might be incrementing the refcount there.

Check this out:
http://wiki.dlang.org/Win32_DLLs_in_D

January 02, 2016
On Saturday, 2 January 2016 at 01:44:46 UTC, Adam D. Ruppe wrote:
> On Saturday, 2 January 2016 at 00:32:20 UTC, alkololl wrote:
>>  Why is that?
>
> I'm not sure, but in the switch you posted, you didn't handle the DLL_THREAD_ATTACH and DLL_THREAD_DETACH cases, the runtime might be incrementing the refcount there.
>
> Check this out:
> http://wiki.dlang.org/Win32_DLLs_in_D

Thanks for your reply. I replaced my switch statement with the one behind the link you left but the result (no result) stays the same. The Dll doesn't get unloaded. Not until I close the host application.
January 02, 2016

On 02.01.2016 16:34, alkololl wrote:
> On Saturday, 2 January 2016 at 01:44:46 UTC, Adam D. Ruppe wrote:
>> On Saturday, 2 January 2016 at 00:32:20 UTC, alkololl wrote:
>>>  Why is that?
>>
>> I'm not sure, but in the switch you posted, you didn't handle the
>> DLL_THREAD_ATTACH and DLL_THREAD_DETACH cases, the runtime might be
>> incrementing the refcount there.
>>
>> Check this out:
>> http://wiki.dlang.org/Win32_DLLs_in_D
>
> Thanks for your reply. I replaced my switch statement with the one
> behind the link you left but the result (no result) stays the same. The
> Dll doesn't get unloaded. Not until I close the host application.

D needs "implicite thread local storage" to implement thread local variables, but Windows XP and earlier versions do not support this for DLLs dynamically loaded through LoadLibrary. The D runtime implements the part necessary for loading, but does not support unloading. As a consequence it sets the DLL to never unload.

If you are actually running XP, you can check https://github.com/denis-sh/hooking. IIRC Denis Shelomovskij implemented the missing parts.
January 02, 2016
On Saturday, 2 January 2016 at 16:42:46 UTC, Rainer Schuetze wrote:

> On 02.01.2016 16:34, alkololl wrote:
>> On Saturday, 2 January 2016 at 01:44:46 UTC, Adam D. Ruppe wrote:
>>> [...]
>>
>> Thanks for your reply. I replaced my switch statement with the one
>> behind the link you left but the result (no result) stays the same. The
>> Dll doesn't get unloaded. Not until I close the host application.
>
> D needs "implicite thread local storage" to implement thread local variables, but Windows XP and earlier versions do not support this for DLLs dynamically loaded through LoadLibrary. The D runtime implements the part necessary for loading, but does not support unloading. As a consequence it sets the DLL to never unload.
>
> If you are actually running XP, you can check https://github.com/denis-sh/hooking. IIRC Denis Shelomovskij implemented the missing parts.

What? I'm actually running Windows 7. For me it's inevitable to not unload the D Dll dynamically. Isn't there some kind of workaround or a sneaky hack to solve this?
January 04, 2016

On 02.01.2016 18:41, alkololl wrote:
> On Saturday, 2 January 2016 at 16:42:46 UTC, Rainer Schuetze wrote:
>
>> On 02.01.2016 16:34, alkololl wrote:
>>> On Saturday, 2 January 2016 at 01:44:46 UTC, Adam D. Ruppe wrote:
>>>> [...]
>>>
>>> Thanks for your reply. I replaced my switch statement with the one
>>> behind the link you left but the result (no result) stays the same. The
>>> Dll doesn't get unloaded. Not until I close the host application.
>>
>> D needs "implicite thread local storage" to implement thread local
>> variables, but Windows XP and earlier versions do not support this for
>> DLLs dynamically loaded through LoadLibrary. The D runtime implements
>> the part necessary for loading, but does not support unloading. As a
>> consequence it sets the DLL to never unload.
>>
>> If you are actually running XP, you can check
>> https://github.com/denis-sh/hooking. IIRC Denis Shelomovskij
>> implemented the missing parts.
>
> What? I'm actually running Windows 7. For me it's inevitable to not
> unload the D Dll dynamically. Isn't there some kind of workaround or a
> sneaky hack to solve this?

If you run Windows 7, I guess the runtime patch is not the issue here.

Have you tried to load the DLL explicitely (without injecting it)? Does it unload correctly in this case? If not, it should ease debugging the problem.