www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why is the Win32 boilerplate the way it is?

reply "Jeremy Sorensen" <jeremy.a.sorensen gmail.com> writes:
I found an example of boilerplate code for Win32 programming in D 
here:
http://wiki.dlang.org/D_for_Win32

I have some questions.
1. It appears that the call to myWinMain from WinMain is to 
ensure that any exception or error is caught. At first glance it 
looks like this is to ensure that runtime.terminate() gets 
called, but in fact it doesn't, the catch block doesn't do it and 
there is no scope(exit).  Is this a problem? (And what would 
happen if you didn't catch the exception?)
2. Why does the boilerplate return 0 on success and failure? (If 
the return code is irrelevant, why the comment that says "failed" 
next to the return code?)
3. I can't imagine a technical reason why the myWinMain signature 
has to match the WinMain signature. Wouldn't it be better to omit 
the hPrevInstance since it isn't used? (Or are we preserving 
backwards compatibility with Win16?).

If there is a resource somewhere that explains all this I would 
happy to consult it but I couldn't find anything.

Thanks.
Jun 28 2014
parent reply Jacob Carlborg <doob me.com> writes:
On 2014-06-29 06:47, Jeremy Sorensen wrote:
 I found an example of boilerplate code for Win32 programming in D here:
 http://wiki.dlang.org/D_for_Win32

 I have some questions.
 1. It appears that the call to myWinMain from WinMain is to ensure that
 any exception or error is caught. At first glance it looks like this is
 to ensure that runtime.terminate() gets called, but in fact it doesn't,
 the catch block doesn't do it and there is no scope(exit).  Is this a
 problem? (And what would happen if you didn't catch the exception?)
 2. Why does the boilerplate return 0 on success and failure? (If the
 return code is irrelevant, why the comment that says "failed" next to
 the return code?)
 3. I can't imagine a technical reason why the myWinMain signature has to
 match the WinMain signature. Wouldn't it be better to omit the
 hPrevInstance since it isn't used? (Or are we preserving backwards
 compatibility with Win16?).

 If there is a resource somewhere that explains all this I would happy to
 consult it but I couldn't find anything.
You don't need to use WinMain. You can use a plain D main function and add the "-L/SUBSYSTEM:WINDOWS:4.0" link flag to suppress the console. There are API's to get access to the arguments passed to WinMain, if necessary. -- /Jacob Carlborg
Jun 29 2014
next sibling parent reply "Jeremy Sorensen" <jeremy.a.sorensen gmail.com> writes:
On Sunday, 29 June 2014 at 07:51:50 UTC, Jacob Carlborg wrote:
 You don't need to use WinMain. You can use a plain D main 
 function and add the "-L/SUBSYSTEM:WINDOWS:4.0" link flag to 
 suppress the console. There are API's to get access to the 
 arguments passed to WinMain, if necessary.
OK so I just tried this and found some amazing things. By using main instead of WinMain the std runtime is automatically loaded, and uncaught exceptions are not swallowed up like in WinMain, so you don't need the try-catch anymore! This makes life much better. The only question I have is what happens when you use SUBSYSTEM:WINDOWS:4.0 (Which I understand means XP or higher) and the program runs on something older? Will you get an error message or just silent failure?
Jun 29 2014
next sibling parent "Trass3r" <un known.com> writes:
 The only question I have is what happens when you use 
 SUBSYSTEM:WINDOWS:4.0 (Which I understand means XP or higher) 
 and the program runs on something older?
<WinXP is dead :)
Jun 29 2014
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2014-06-29 17:06, Jeremy Sorensen wrote:

 The only question I
 have is what happens when you use SUBSYSTEM:WINDOWS:4.0 (Which I
 understand means XP or higher) and the program runs on something older?
 Will you get an error message or just silent failure?
Actually, I don't know. You could try some different value. If you search on Google I'm sure you'll find something. -- /Jacob Carlborg
Jun 29 2014
parent "Jeremy Sorensen" <jeremy.a.sorensen gmail.com> writes:
On Sunday, 29 June 2014 at 18:16:05 UTC, Jacob Carlborg wrote:
 On 2014-06-29 17:06, Jeremy Sorensen wrote:

 The only question I
 have is what happens when you use SUBSYSTEM:WINDOWS:4.0 (Which 
 I
 understand means XP or higher) and the program runs on 
 something older?
 Will you get an error message or just silent failure?
Actually, I don't know. You could try some different value. If you search on Google I'm sure you'll find something.
Good suggestion, it took me a bit to figure out how to convince Visual-D to do it, but I got it. I am using windows 8.1, so I had to use an as-yet fictitious number but when I did Windows told me it couldn't run the program, which is just perfect behavior.
Jun 29 2014
prev sibling parent "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Sunday, 29 June 2014 at 15:06:25 UTC, Jeremy Sorensen wrote:
 The only question I have is what happens when you use 
 SUBSYSTEM:WINDOWS:4.0 (Which I understand means XP or higher) 
 and the program runs on something older?
Windows XP is version 5.1. 4.0 was Windows NT 4 (which I believe was the NT-family Windows version preceding Windows 2000).
Jul 02 2014
prev sibling parent reply "Jeremy Sorensen" <jeremy.a.sorensen gmail.com> writes:
On Sunday, 29 June 2014 at 07:51:50 UTC, Jacob Carlborg wrote:

 You don't need to use WinMain. You can use a plain D main 
 function and add the "-L/SUBSYSTEM:WINDOWS:4.0" link flag to 
 suppress the console. There are API's to get access to the 
 arguments passed to WinMain, if necessary.
Thanks for your help on this, I couldn't find a way to get the nCmdShow argument, is it safe to assume SW_SHOWNORMAL for starting a new application? So the situation so far is this: 1. You don't need hPrevInstance 2. You can get hInstance via GetModuleHandle(null) (I think that is the best way) 3. [awesome] use main(string[] args) to get your command line arguments exactly like you are used to (except no program name, I tested this) 4. You don't have to worry about the runtime, it is handled automatically 5. You don't have to catch at the top level and put up a message box, this is also done automatically Assuming the nCmdShow thing isn't a problem I see no reason why the wiki should tell people to use WinMain at all.
Jun 29 2014
parent reply "Jason King" <jhking airmail.net> writes:
On Monday, 30 June 2014 at 05:30:23 UTC, Jeremy Sorensen wrote:
 Assuming the nCmdShow thing isn't a problem I see no reason why 
 the wiki should tell people to use WinMain at all.
If MSDN is to be believed VOID WINAPI GetStartupInfo( _Out_ LPSTARTUPINFO lpStartupInfo ); will get you nCmdShow and lots of other goodies.
Jun 30 2014
parent reply "Jeremy Sorensen" <jeremy.a.sorensen gmail.com> writes:
 If MSDN is to be believed
 VOID WINAPI GetStartupInfo(
   _Out_  LPSTARTUPINFO lpStartupInfo
 );
 will get you nCmdShow and lots of other goodies.
I keep getting "Error: undefined identifier GetStartupInfo" (or GetStartupInfoA, or GetStartupInfoW). According to MSDN it should be available from <Windows.h>, which according to the D documentation means "import core.sys.windows.windwos" should make it available. I still don't know the right way to pass a pointer to it, but I don't think that is causing this error. Any ideas? Thanks.
Jun 30 2014
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Monday, 30 June 2014 at 15:14:24 UTC, Jeremy Sorensen wrote:
 documentation means "import core.sys.windows.windwos"
The Windows headers that come with D are pathetically minimal. You'll need to grab a more complete win32 header OR copy/paste the individual prototypes off MSDN and use them that way. So add this to your D file after importing core.sys.windows.windows: extern(Windows) void GetStartupInfoA(STARTUPINFO*); // the pathetic druntime Windows headers define TCHAR as ascii, so we'll use the A version And try compiling it. If it complains that STARTUPINFO is undefined too, copy its prototype in: struct STARTUPINFO { DWORD cb; LPTSTR lpReserved; LPTSTR lpDesktop; LPTSTR lpTitle; DWORD dwX; DWORD dwY; DWORD dwXSize; DWORD dwYSize; DWORD dwXCountChars; DWORD dwYCountChars; DWORD dwFillAttribute; DWORD dwFlags; WORD wShowWindow; WORD cbReserved2; LPBYTE lpReserved2; HANDLE hStdInput; HANDLE hStdOutput; HANDLE hStdError; } And that should make it work.
Jun 30 2014
next sibling parent reply "Jason King" <jhking airmail.net> writes:
On Monday, 30 June 2014 at 15:19:39 UTC, Adam D. Ruppe wrote:
 On Monday, 30 June 2014 at 15:14:24 UTC, Jeremy Sorensen wrote:
 documentation means "import core.sys.windows.windwos"
The Windows headers that come with D are pathetically minimal. You'll need to grab a more complete win32 header OR copy/paste the individual prototypes off MSDN and use them that way.
This is a more complete set of windows api headers https://github.com/AndrejMitrovic/WindowsAPI
Jun 30 2014
parent "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Monday, 30 June 2014 at 15:58:50 UTC, Jason King wrote:
 On Monday, 30 June 2014 at 15:19:39 UTC, Adam D. Ruppe wrote:
 On Monday, 30 June 2014 at 15:14:24 UTC, Jeremy Sorensen wrote:
 documentation means "import core.sys.windows.windwos"
The Windows headers that come with D are pathetically minimal. You'll need to grab a more complete win32 header OR copy/paste the individual prototypes off MSDN and use them that way.
This is a more complete set of windows api headers https://github.com/AndrejMitrovic/WindowsAPI
I have a mirror which updates automatically, and is usable as a git submodule: https://github.com/CS-svnmirror/dsource-bindings-win32
Jul 02 2014
prev sibling parent "Jeremy Sorensen" <jeremy.a.sorensen gmail.com> writes:
On Monday, 30 June 2014 at 15:19:39 UTC, Adam D. Ruppe wrote:
 The Windows headers that come with D are pathetically minimal. 
 You'll need to grab a more complete win32 header OR copy/paste 
 the individual prototypes off MSDN and use them that way.

 So add this to your D file after importing 
 core.sys.windows.windows:

 extern(Windows)
 void GetStartupInfoA(STARTUPINFO*); // the pathetic druntime 
 Windows headers define TCHAR as ascii, so we'll use the A 
 version


 And try compiling it. If it complains that STARTUPINFO is 
 undefined too, copy its prototype in:

 struct STARTUPINFO {
   DWORD  cb;
   LPTSTR lpReserved;
   LPTSTR lpDesktop;
   LPTSTR lpTitle;
   DWORD  dwX;
   DWORD  dwY;
   DWORD  dwXSize;
   DWORD  dwYSize;
   DWORD  dwXCountChars;
   DWORD  dwYCountChars;
   DWORD  dwFillAttribute;
   DWORD  dwFlags;
   WORD   wShowWindow;
   WORD   cbReserved2;
   LPBYTE lpReserved2;
   HANDLE hStdInput;
   HANDLE hStdOutput;
   HANDLE hStdError;
 }


 And that should make it work.
Yup that worked
Jun 30 2014