Jump to page: 1 2
Thread overview
win64 DLL stdout printing after main process completes
Apr 19, 2021
cc
Apr 19, 2021
frame
Apr 19, 2021
cc
Apr 19, 2021
Mike Parker
Apr 19, 2021
cc
Apr 19, 2021
Adam D. Ruppe
Apr 25, 2021
cc
Apr 26, 2021
frame
Apr 26, 2021
cc
Apr 26, 2021
Adam D. Ruppe
Apr 26, 2021
frame
Apr 27, 2021
Mike Parker
Apr 19, 2021
Adam D. Ruppe
Apr 20, 2021
Mike Parker
Apr 20, 2021
Marcone
April 19, 2021

I'm not sure if this is something unique to D or not, but I've having a minor issue where stdout output from a DLL (either via printf or phobos std.stdio write) is not displayed until after the main process has completed. I'm making a project based around the example at https://wiki.dlang.org/Win32_DLLs_in_D which I've heard is a little out of date but I've gotten it working nonetheless. I have the following project files:

// mydll.d
module mydll;
import core.runtime;
import core.stdc.stdio;
import core.stdc.stdlib;
import core.sys.windows.windows;
extern(Windows) BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) {
	switch (ulReason) {
		case DLL_PROCESS_ATTACH:
		printf("[dll] DLL_PROCESS_ATTACH\n");
		Runtime.initialize();
		break;
		case DLL_PROCESS_DETACH:
		printf("[dll] DLL_PROCESS_DETACH\n");
		Runtime.terminate();
		break;
		case DLL_THREAD_ATTACH:
		printf("[dll] DLL_THREAD_ATTACH\n");
		return false;
		case DLL_THREAD_DETACH:
		printf("[dll] DLL_THREAD_DETACH\n");
		return false;
		default:
	}
	return true;
}
export int MyDLL_Test() {
	printf("[dll] MyDLL_Test\n");
	return 5;
}
static this() {
	printf("[dll] static this for mydll\n");
}
static ~this() {
	printf("[dll] static ~this for mydll\n");
}
// mydll.di
module mydll;
export int MyDLL_Test();
// main.d
import mydll;
pragma(lib, "mydll.lib");
import core.sys.windows.windows;
void main() {
	printf("[Main] Start\n");
	scope(exit) printf("[Main] END\n");
	int x = MyDLL_Test();
	printf("[Main] x: %d\n", x);
	printf("[Main] Finished\n");
}

DLL compilation command line: dmd -m64 -ofmydll.dll -L/DLL mydll.d mydll.def
Main command line: rdmd -m64 main.d

And upon running, the output I receive is:

[Main] Start
[Main] x: 5
[Main] Finished
[Main] END
[dll] DLL_PROCESS_ATTACH
[dll] static this for mydll
[dll] MyDLL_Test
[dll] DLL_PROCESS_DETACH
[dll] static ~this for mydll

I would expect the first three lines of dll output to precede the "[Main] x:" line at least. Is there something I'm doing wrong? Do I need to somehow pass a reference to the main stdio to the DLL's D runtime similar to how the GC can be shared?

April 19, 2021

On Monday, 19 April 2021 at 14:55:03 UTC, cc wrote:

>

I would expect the first three lines of dll output to precede the "[Main] x:" line at least. Is there something I'm doing wrong? Do I need to somehow pass a reference to the main stdio to the DLL's D runtime similar to how the GC can be shared?

Which compiler version are you using?
This is my output:

[dll] DLL_PROCESS_ATTACH
[dll] static this for mydll
[Main] Start
[dll] MyDLL_Test
[Main] x: 5
[Main] Finished
[Main] END
[dll] DLL_PROCESS_DETACH
[dll] static ~this for mydll

You miss a core.stdc.stdio import in main().
I also omit the def-File, maybe you have an error in it? It shouldn't be necessary to include. It just did:

dmd -m64 -ofmydll.dll -L/DLL mydll.d
April 19, 2021

On Monday, 19 April 2021 at 14:55:03 UTC, cc wrote:

>

And upon running, the output I receive is:

[Main] Start
[Main] x: 5
[Main] Finished
[Main] END
[dll] DLL_PROCESS_ATTACH
[dll] static this for mydll
[dll] MyDLL_Test
[dll] DLL_PROCESS_DETACH
[dll] static ~this for mydll

I would expect the first three lines of dll output to precede the "[Main] x:" line at least. Is there something I'm doing wrong? Do I need to somehow pass a reference to the main stdio to the DLL's D runtime similar to how the GC can be shared?

It's probably just due to buffering. Insert a fflush(stdout) after the calls to printf in your DLL and see what happens.

April 19, 2021

On Monday, 19 April 2021 at 16:00:25 UTC, frame wrote:

>

You miss a core.stdc.stdio import in main().
I also omit the def-File, maybe you have an error in it? It shouldn't be necessary to include. It just did:

dmd -m64 -ofmydll.dll -L/DLL mydll.d

Sorry, here's the def file, taken from the wiki example.

LIBRARY "mydll.dll"
EXETYPE NT
SUBSYSTEM WINDOWS
CODE SHARED EXECUTE
DATA WRITE

Incidentally I get some warnings regarding it when I compile:

mydll.def(2) : warning LNK4017: EXETYPE statement not supported for the target platform; ignored
mydll.def(3) : warning LNK4017: SUBSYSTEM statement not supported for the target platform; ignored
mydll.def(4) : warning LNK4017: CODE statement not supported for the target platform; ignored
mydll.def(5) : warning LNK4017: DATA statement not supported for the target platform; ignored

Are all those lines were intended for win32 dlls and whatever the x64 equivalents are are different?
Also, the example at the D wiki URL had a -L/IMPLIB in the command line but I get LINK : fatal error LNK1146: no argument specified with option '/IMPLIB' with that so I removed it.

April 19, 2021

On Monday, 19 April 2021 at 16:04:28 UTC, Mike Parker wrote:

>

On Monday, 19 April 2021 at 14:55:03 UTC, cc wrote:

>

And upon running, the output I receive is:

[Main] Start
[Main] x: 5
[Main] Finished
[Main] END
[dll] DLL_PROCESS_ATTACH
[dll] static this for mydll
[dll] MyDLL_Test
[dll] DLL_PROCESS_DETACH
[dll] static ~this for mydll

I would expect the first three lines of dll output to precede the "[Main] x:" line at least. Is there something I'm doing wrong? Do I need to somehow pass a reference to the main stdio to the DLL's D runtime similar to how the GC can be shared?

It's probably just due to buffering. Insert a fflush(stdout) after the calls to printf in your DLL and see what happens.

This seems to work if I flush after every printf or write in both main and the dll. I was under the impression they were supposed to share the same IO buffers though, is this not the case?

April 19, 2021

On Monday, 19 April 2021 at 18:05:46 UTC, cc wrote:

>

This seems to work if I flush after every printf or write in both main and the dll. I was under the impression they were supposed to share the same IO buffers though, is this not the case?

Very little in D dlls right now are shared, so there's duplicate buffers and functions in the dll do not necessarily affect the exe's copies. It basically works in most cases but this can cause some quirks and bugs in some situations.

April 19, 2021

On Monday, 19 April 2021 at 14:55:03 UTC, cc wrote:

>

https://wiki.dlang.org/Win32_DLLs_in_D

I'm starting to think half that page should just be deleted... the version up top with the druntime dll_process_attach etc versions should really be used in all cases.

And that gets even simpler too, use

import core.sys.windows.dll;
mixin SimpleDllMain;

and you get that boilerplate for free.

April 20, 2021

On Monday, 19 April 2021 at 14:55:03 UTC, cc wrote:

>

I would expect the first three lines of dll output to precede the "[Main] x:" line at least. Is there something I'm doing wrong? Do I need to somehow pass a reference to the main stdio to the DLL's D runtime similar to how the GC can be shared?

I just compiled and executed your code locally here's the output I saw without using any flushing:

[dll] DLL_PROCESS_ATTACH
[dll] static this for mydll
[Main] Start
[dll] MyDLL_Test
[Main] x: 5
[Main] Finished
[Main] END
[dll] DLL_PROCESS_DETACH
[dll] static ~this for mydll

My command lines:

dmd -m64 -L/DLL mydll.d
dmd -m64 main.d

I dropped the -of because that's redundant. The .def file isn't needed, but I did compile with one based on the example you linked. It gave me warnings about all of the directives being ignored because they're unsupported on the target platform (I also had to change MyDLL_Test to extern(C), since I didn't use the D mangled name in the .def file) but the output was the same as above.

I did have a problem, though, when I replaced printf with writeln/writefln, in that I got no output at all. I don't have time to dig deeper at the moment.

Anway, I wonder what the difference is between our systems that we get different output. I'm on Windows 10, dmd 2.096.0, VS 2019.

I suggest you also try compiling a comparable C example to see if what the output looks like:

// dllmain.c
#define WINDOWS_LEAN_AND_MEAN
#include <windows.h>

BOOL DllMain(HINSTANCE hinst, ULONG reason, LPVOID reserved)
{
    switch(reason)
    {
        case DLL_PROCESS_ATTACH:
            printf("[dll] DLL_PROCESS_ATTACH\n");
            break;

        case DLL_PROCESS_DETACH:
            printf("[dll] DLL_PROCESS_DETACH\n");
            break;

        case DLL_THREAD_ATTACH:
            printf("[dll] DLL_THREAD_ATTACH\n");
            return 0;

        case DLL_THREAD_DETACH:
            printf("[dll] DLL_THREAD_DETACH\n");
            return 0;

        default: break;
    }

    return 1;
}

__declspec(dllexport) int __cdecl MyDLL_Test(void)
{
    printf("[dll] MyDLL_Test\n");
	return 5;
}
// main.c
#include <stdio.h>

#pragma comment(lib, "dllmain.lib")

extern __declspec(dllimport) int __cdecl MyDLL_Test(void);

int main(int argc, char** argv)
{
    printf("[Main] Start\n");
    int x = MyDLL_Test();
    printf("[Main] x: %d\n", x);
    printf("[Main] Finished\n", x);
    printf("[Main] END\n");
}

In the x64 Native Tools Command Prompt for VS 2019:

cl /LD dllmain.c
cl main.c

See if this produces the output you expect or if it looks the same as your D output.

April 20, 2021

On Monday, 19 April 2021 at 14:55:03 UTC, cc wrote:

>

I'm not sure if this is something unique to D or not, but I've having a minor issue where stdout output from a DLL (either via printf or phobos std.stdio write) is not displayed until after the main process has completed. I'm making a project based around the example at https://wiki.dlang.org/Win32_DLLs_in_D which I've heard is a little out of date but I've gotten it working nonetheless. I have the following project files:

// mydll.d
module mydll;
import core.runtime;
import core.stdc.stdio;
import core.stdc.stdlib;
import core.sys.windows.windows;
extern(Windows) BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) {
	switch (ulReason) {
		case DLL_PROCESS_ATTACH:
		printf("[dll] DLL_PROCESS_ATTACH\n");
		Runtime.initialize();
		break;
		case DLL_PROCESS_DETACH:
		printf("[dll] DLL_PROCESS_DETACH\n");
		Runtime.terminate();
		break;
		case DLL_THREAD_ATTACH:
		printf("[dll] DLL_THREAD_ATTACH\n");
		return false;
		case DLL_THREAD_DETACH:
		printf("[dll] DLL_THREAD_DETACH\n");
		return false;
		default:
	}
	return true;
}
export int MyDLL_Test() {
	printf("[dll] MyDLL_Test\n");
	return 5;
}
static this() {
	printf("[dll] static this for mydll\n");
}
static ~this() {
	printf("[dll] static ~this for mydll\n");
}
// mydll.di
module mydll;
export int MyDLL_Test();
// main.d
import mydll;
pragma(lib, "mydll.lib");
import core.sys.windows.windows;
void main() {
	printf("[Main] Start\n");
	scope(exit) printf("[Main] END\n");
	int x = MyDLL_Test();
	printf("[Main] x: %d\n", x);
	printf("[Main] Finished\n");
}

DLL compilation command line: dmd -m64 -ofmydll.dll -L/DLL mydll.d mydll.def
Main command line: rdmd -m64 main.d

And upon running, the output I receive is:

[Main] Start
[Main] x: 5
[Main] Finished
[Main] END
[dll] DLL_PROCESS_ATTACH
[dll] static this for mydll
[dll] MyDLL_Test
[dll] DLL_PROCESS_DETACH
[dll] static ~this for mydll

I would expect the first three lines of dll output to precede the "[Main] x:" line at least. Is there something I'm doing wrong? Do I need to somehow pass a reference to the main stdio to the DLL's D runtime similar to how the GC can be shared?

Hi, I use this function:

// Function echo()
void echo(T)(T text) nothrow {try {spawnShell("echo%s %s".format(text.to!string.strip() != "" ? "" : ".", text.to!string.replace(">","^>").replace("&","^&").replace("\n"," &&echo."))); } catch(Throwable){} }

echo("This is not will wait the end to print.");

April 25, 2021

On Monday, 19 April 2021 at 18:32:15 UTC, Adam D. Ruppe wrote:

>

On Monday, 19 April 2021 at 18:05:46 UTC, cc wrote:

>

This seems to work if I flush after every printf or write in both main and the dll. I was under the impression they were supposed to share the same IO buffers though, is this not the case?

Very little in D dlls right now are shared, so there's duplicate buffers and functions in the dll do not necessarily affect the exe's copies. It basically works in most cases but this can cause some quirks and bugs in some situations.

That makes sense, thanks.

Adding a note in case anyone stumbles across this with a similar problem:
Adding stdout.setvbuf(0, _IONBF); to both the main and DLL will cause D to autoflush after every write call without requiring a manual flush (which seems to happen quite often when running under anything other than a basic Windows command prompt).

« First   ‹ Prev
1 2