www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Using stdin/out in a windows application bugs only when compiled to

reply realhet <real_het hotmail.com> writes:
Hi,

The following narrow test program works fine when compiled with 
DMD to 32bit target:

import std.stdio, core.sys.windows.windows, core.runtime;
extern(Windows) int WinMain(HINSTANCE hInstance, HINSTANCE 
hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
{
	Runtime.initialize;
	writeln("Hello");
	stdout.flush; //exception
         readln; //exception
	return 0;
}

It shows the console window and waits for user input at readln.

If I try to compile this to 64bit target or with LDC (both 32 and 
64) it gets privileged instruction exception at stdout.flush. If 
I comment out flush then it fails at readln.

Is there a way to fix this? I don't wanna lose the console window 
even on 64bit.

Thanks!
Jun 07 2018
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 6/7/18 3:19 PM, realhet wrote:
 Hi,
 
 The following narrow test program works fine when compiled with DMD to 
 32bit target:
 
 import std.stdio, core.sys.windows.windows, core.runtime;
 extern(Windows) int WinMain(HINSTANCE hInstance, HINSTANCE 
 hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
 {
      Runtime.initialize;
      writeln("Hello");
      stdout.flush; //exception
          readln; //exception
      return 0;
 }
 
 It shows the console window and waits for user input at readln.
 
 If I try to compile this to 64bit target or with LDC (both 32 and 64) it 
 gets privileged instruction exception at stdout.flush. If I comment out 
 flush then it fails at readln.
 
 Is there a way to fix this? I don't wanna lose the console window even 
 on 64bit.
 
 Thanks!
 
Are you just compiling the 32-bit dmd version with default flags? If so, it's likely an issue with MSVC runtime library not being properly set up. DMD 32 bit by default uses DMC runtime. To verify, use the switch -m32mscoff to do 32-bit result but link against MSVC library. I know this isn't really an answer, but it at least narrows it down. Been a while since I did windows development, but it sounds like you are trying to print to or read from a console that isn't open. A windows program that has gui-only flag doesn't by default allocate a console. Most likely dmc just does it for you. -Steve
Jun 07 2018
parent reply realhet <real_het hotmail.com> writes:
On Thursday, 7 June 2018 at 19:42:05 UTC, Steven Schveighoffer 
wrote:
 Are you just compiling the 32-bit dmd version with default 
 flags?
Yes, no flags at all and it defaults to a 32bit target. I can use the console and able to make windows, and able to setup an opengl window too. The console (stdin/stdout/SetConsoleAttribute) stuff crashes only when I compile to 64bit with DMD or to 32/64 with LDC.
 If so, it's likely an issue with MSVC runtime library not being 
 properly set up. DMD 32 bit by default uses DMC runtime.
I just tried to put up msvcrt2017 runtime but doesnt solved the issue.
 To verify, use the switch -m32mscoff to do 32-bit result but 
 link against MSVC library.
Compiling this way is impossible: It can't link even basic stuff like GetDC().
 I know this isn't really an answer, but it at least narrows it
down. Been a while since I did windows development, but it sounds like you are trying to print to or read from a console that isn't open. A windows program that has gui-only flag doesn't by default allocate a console. Most likely dmc just does it for you.
To be honest I don't use gui-only flag as I don't even know about where to put it :D (.def file maybe, but I don't). I use core.Runtime.initialize only. That is enough in 32bit but not in 64bit. My goal is to have a fully functional exe that contains every necessary things inside it. So far this is given when I use DMD and compile to win32. The error I'm getting is not a 'friendly' exception. It is a privileged instruction crash. And it caused only by adding the -m64 option, not changing anything else. The linking is done by DMD itself also. (If I link with msvcenv.bat && MSLink.exe, it produces also the same fail.)
Jun 07 2018
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 6/7/18 7:16 PM, realhet wrote:
 On Thursday, 7 June 2018 at 19:42:05 UTC, Steven Schveighoffer wrote:
 Are you just compiling the 32-bit dmd version with default flags?
Yes, no flags at all and it defaults to a 32bit target. I can use the console and able to make windows, and able to setup an opengl window too. The console (stdin/stdout/SetConsoleAttribute) stuff crashes only when I compile to 64bit with DMD or to 32/64 with LDC.
So that is definitely dmc initializing the console window in that context.
 
 If so, it's likely an issue with MSVC runtime library not being 
 properly set up. DMD 32 bit by default uses DMC runtime.
I just tried to put up msvcrt2017 runtime but doesnt solved the issue.
Sorry, I'm not familiar with Windows enough to help.
 
 To verify, use the switch -m32mscoff to do 32-bit result but link 
 against MSVC library.
Compiling this way is impossible: It can't link even basic stuff like GetDC().
Also lost with this one.
 
 I know this isn't really an answer, but it at least narrows it
down. Been a while since I did windows development, but it sounds like you are trying to print to or read from a console that isn't open. A windows program that has gui-only flag doesn't by default allocate a console. Most likely dmc just does it for you.
To be honest I don't use gui-only flag as I don't even know about where to put it :D (.def file maybe, but I don't). I use core.Runtime.initialize only. That is enough in 32bit but not in 64bit.
I don't know what happens nowadays. I literally haven't tried to build non-console Windows applications since like 2008 or so? I thought it was a linker flag, but I'm not sure.
 My goal is to have a fully functional exe that contains every necessary 
 things inside it. So far this is given when I use DMD and compile to win32.
 The error I'm getting is not a 'friendly' exception. It is a privileged 
 instruction crash.
Well, you are telling the linker, when you create your WinMain function that you are handling all the runtime setup yourself, and you are not using a console. So somehow you have to initialize the console. Alternatively, you can define extern(C) main function, and handle the D initialization from there. Is there a reason you want the D runtime but don't want to have D initialize it for you?
 And it caused only by adding the -m64 option, not changing anything 
 else. The linking is done by DMD itself also. (If I link with 
 msvcenv.bat && MSLink.exe, it produces also the same fail.)
Just to be clear, it's not the 32-bit vs 64-bit, it has to do with which C runtime you are using. -Steve
Jun 07 2018
parent realhet <real_het hotmail.com> writes:
On Thursday, 7 June 2018 at 23:25:45 UTC, Steven Schveighoffer 
wrote:
...
The WinMain exported function works alone well and on 32bit it also does the console. On 64 I also tried AllocConsole, but fail. I get the Console handle with GetConsoleHandle, it sends back a nonzero value. But as I play with it, now I can broke it even when I only use main() as export. This bat file runs(dmd and visual-d installed to default c:\d path) (It only affects LDC & win64) ---------------------------------------------------- echo void main(){ import std.stdio; writeln(123); } > test.d ldmd2 -vcolumns -c -op -allinst -w -m64 -release -O -inline -boundscheck=off test.d call msvcenv amd64 cd c:\d link /LIBPATH:C:\d\ldc2\lib64 /OUT:test.exe /MACHINE:X64 /MAP legacy_stdio_definitions.lib test.obj druntime-ldc.lib phobos2-ldc.lib msvcrt.lib test.exe ---------------------------------------------------- And when I want to run the same exe from outside with totalcommander, it brings up an "application was unable to start: 0xc00000fb exception in a small window o.O. UPDATE: The exe only starts when "msvcenv.bat amd64" was called before. That enironment setter bat file is needed for the exe as well o.O I really thank you for trying to help me. Maybe that other different runtime you mentioned is using environment variables to be able to start up. Tomorrow I will test it.
Jun 07 2018
prev sibling next sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Thursday, 7 June 2018 at 19:19:55 UTC, realhet wrote:
 Hi,

 The following narrow test program works fine when compiled with 
 DMD to 32bit target:

 import std.stdio, core.sys.windows.windows, core.runtime;
 extern(Windows) int WinMain(HINSTANCE hInstance, HINSTANCE 
 hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
 {
 	Runtime.initialize;
 	writeln("Hello");
 	stdout.flush; //exception
         readln; //exception
 	return 0;
 }

 It shows the console window and waits for user input at readln.

 If I try to compile this to 64bit target or with LDC (both 32 
 and 64) it gets privileged instruction exception at 
 stdout.flush. If I comment out flush then it fails at readln.
I get no exceptions with this code, but if I run if I compile with no flags, it prints hello and waits for input. With -m32mscoff or -m64, there's no output. If I run from Windows Explorer, the no-flag version pops up a console, prints and waits, while the -m32mscoff and do nothing. As Steven mentioned earlier, this is a runtime issue. The standard I/O streams are not available in the MSVC runtime by default when compiling as a GUI application. You don't have to enable any flags to get that -- it's automatic when WinMain is present. The DititalMars runtime, which is what you get with the default compile, apparently does initialize the standard I/O streams and makes sure the console pops up when you write to it.
 Is there a way to fix this? I don't wanna lose the console 
 window even on 64bit.
If you want to keep WinMain and still have the console stuff available from the start with the MSVC runtime, you can get it with this: dmd -m64 -L/SUBSYSTEM:console -L/ENTRY:WinMainCRTStartup foo.d With this (for -m32mscoff as well), the above code runs the same as it does with the DigitalMars runtime.
Jun 07 2018
parent realhet <real_het hotmail.com> writes:
On Friday, 8 June 2018 at 02:44:13 UTC, Mike Parker wrote:
...you can get it with this:

 dmd -m64 -L/SUBSYSTEM:console -L/ENTRY:WinMainCRTStartup foo.d
Thank You! It works with LDC -m64 as well. And now that I repaired my VCRedist2015 the bat file test (my second code example) is working too.
Jun 08 2018
prev sibling parent reply Mike Franklin <slavo5150 yahoo.com> writes:
On Thursday, 7 June 2018 at 19:19:55 UTC, realhet wrote:
 Hi,

 The following narrow test program works fine when compiled with 
 DMD to 32bit target:

 import std.stdio, core.sys.windows.windows, core.runtime;
 extern(Windows) int WinMain(HINSTANCE hInstance, HINSTANCE 
 hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
 {
 	Runtime.initialize;
 	writeln("Hello");
 	stdout.flush; //exception
         readln; //exception
 	return 0;
 }

 It shows the console window and waits for user input at readln.

 If I try to compile this to 64bit target or with LDC (both 32 
 and 64) it gets privileged instruction exception at 
 stdout.flush. If I comment out flush then it fails at readln.

 Is there a way to fix this? I don't wanna lose the console 
 window even on 64bit.

 Thanks!
You might be running into this issue: https://issues.dlang.org/show_bug.cgi?id=6880 I recall similar issues with a project I was working on, but I don't remember all the details now. Anyway, I ended up with this in the end. https://github.com/JinShil/Dsus2/blob/b08c66c6a6efb46134c409aac9f1c600d62f99fa/Dsus2/main.d#L300-L331 Mike
Jun 07 2018
parent realhet <real_het hotmail.com> writes:
On Friday, 8 June 2018 at 03:08:21 UTC, Mike Franklin wrote:
 I recall similar issues with a project I was working on, but I 
 don't remember all the details now.  Anyway, I ended up with 
 this in the end.
Using main() instead of WinMain() did the trick too. Also it's simpler, so I choose this way. But it was also important to learn about the SUBSYSTEM and ENTRY linker options. Thank you all very much!
Jun 08 2018