www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - win64 DLL stdout printing after main process completes

reply cc <cc nevernet.com> writes:
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:

```d
// 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");
}
```

```d
// mydll.di
module mydll;
export int MyDLL_Test();
```

```d
// 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?
Apr 19
next sibling parent reply frame <frame86 live.com> writes:
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 ```
Apr 19
parent cc <cc nevernet.com> writes:
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.
Apr 19
prev sibling next sibling parent reply Mike Parker <aldacron gmail.com> writes:
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.
Apr 19
parent reply cc <cc nevernet.com> writes:
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?
Apr 19
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
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.
Apr 19
parent reply cc <cc nevernet.com> writes:
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).
Apr 25
parent reply frame <frame86 live.com> writes:
On Sunday, 25 April 2021 at 15:01:25 UTC, cc wrote:

 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).
I cannot reproduce this on Windows 10. It would be just interesting to know your compiler version and OS and if you have installed any Visual Studio tools or Visual C runtimes, thanks.
Apr 26
parent reply cc <cc nevernet.com> writes:
On Monday, 26 April 2021 at 13:44:19 UTC, frame wrote:
 On Sunday, 25 April 2021 at 15:01:25 UTC, cc wrote:

 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).
I cannot reproduce this on Windows 10. It would be just interesting to know your compiler version and OS and if you have installed any Visual Studio tools or Visual C runtimes, thanks.
Win10 64-bit DMD32 D Compiler v2.096.0-dirty Sublime Text 3.1.1 Build 3176 Visual Studio 2019 is installed, as well as... quite a few runtimes, multiple for Visual C++ 2005, 2008, 2010, 2012, 2013, 2015-2019. The buffering also happens under cygwin shells (I'm not building with cygwin, I just like using their bash shell). If I run a D program through the basic cmd.exe, it runs with no stdout buffering. However any other situation (shell, sublime build+output capture, etc) buffering somehow gets enabled, unless I explicitly disable it in code or wrap the write* functions with stdout.flush() wrappers. This has happened for me for many versions of the dmd compiler stretching back years, building both 32-bit and 64-bit executables.
Apr 26
next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 26 April 2021 at 14:44:53 UTC, cc wrote:
 I run a D program through the basic cmd.exe, it runs with no 
 stdout buffering.
You'll find the same thing with C programs, since it is actually the C standard library that does this buffering rather than D. If it is writing to a character device (the only one I've ever seen in practice is the Windows console, directly, not through a pipe meaning this doesn't occur for terminal replacements or IDEs or similar), it line buffers. Otherwise, it block buffers.
Apr 26
prev sibling next sibling parent frame <frame86 live.com> writes:
On Monday, 26 April 2021 at 14:44:53 UTC, cc wrote:

 Visual Studio 2019 is installed, as well as... quite a few 
 runtimes, multiple for  Visual C++ 2005, 2008, 2010, 2012, 
 2013, 2015-2019.
like me
 If I run a D program through the basic cmd.exe, it runs with no 
 stdout buffering.
Does it also buffer if you run the .exe directly via explorer too? I have no issues with v2.096.0. Must be really a specific problem with your runtimes or Windows (I stopped updating at version 1903 :P)
Apr 26
prev sibling parent Mike Parker <aldacron gmail.com> writes:
On Monday, 26 April 2021 at 14:44:53 UTC, cc wrote:

 The buffering also happens under cygwin shells (I'm not 
 building with cygwin, I just like using their bash shell).  If 
 I run a D program through the basic cmd.exe, it runs with no 
 stdout buffering.  However any other situation (shell, sublime 
 build+output capture, etc) buffering somehow gets enabled, 
 unless I explicitly disable it in code or wrap the write* 
 functions with stdout.flush() wrappers.  This has happened for 
 me for many versions of the dmd compiler stretching back years, 
 building both 32-bit and 64-bit executables.
So that's the difference, then. I ran my test through cmd.exe. Have you tried running a similar C setup through those other shells?
Apr 26
prev sibling next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
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.
Apr 19
prev sibling next sibling parent Mike Parker <aldacron gmail.com> writes:
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: ```c // 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; } ``` ```c // 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.
Apr 20
prev sibling parent Marcone <marcone email.com> writes:
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:

 ```d
 // 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");
 }
 ```

 ```d
 // mydll.di
 module mydll;
 export int MyDLL_Test();
 ```

 ```d
 // 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.");
Apr 20