Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29487 Discussions

Message loop exits unexpectantly in Windows Vista

cartman4
Beginner
1,426 Views
Hello,

In porting my app to Windows Vista I've encountered a problem where the message loop in the following code exits even before the window is displayed. The same code works fine in Windows XP. The value of mesg%MESSAGE at the return is WM_QUIT, but Spy++ doesn't show a WM_QUIT being received by the window. Any idea what I'm doing wrong?

subroutine displayBltSplashScreen

use ftsGlobals
use globals
use user32

implicit none

include 'common.inc'
include 'mainHeader.inc'

type (T_MSG) mesg

integer hbkgBrush, iopt, iopt1, i, j, dx, dy, hwndDlg

logical retlog

character(SIZEOFAPPNAME) lpszSplash
character(SIZEOFAPPNAME) lpszAppName
character*10 button1Label, button2Label

type (T_WNDCLASSEX) wcSplash2

lpszSplash = "splash"C
lpszAppName =""C

hbkgBrush = COLOR_BACKGROUND

iopt = 0
iopt1 = WS_POPUP

haventDoneSplash = .false.

!tail number selection window
wcSplash2%cbSize = sizeof(wcSplash2)
wcSplash2%lpszClassName = loc(lpszSplash)
wcSplash2%lpfnWndProc = LOC(splashProc)
wcSplash2%style = IOR(CS_VREDRAW , CS_HREDRAW)
wcSplash2%hInstance = ghInstance
!wcSplash2%hCursor = LoadCursor( NULL, IDC_ARROW )
wcSplash2%hIcon = NULL
wcSplash2%hIconSm = NULL
wcSplash2%hCursor = NULL
wcSplash2%hbrBackground = hbkgBrush
wcSplash2%lpszMenuName = NULL
wcSplash2%cbClsExtra = 0
wcSplash2%cbWndExtra = 0
i = registerClassEx(wcSplash2)

hwndDlg = CreateWindowEx ( iopt, lpszSplash, &
lpszAppName, &
iopt1, &
100, &
100, &
600, &
400, &
NULL, &
NULL, &
ghInstance, &
NULL &
)

ghwndSplash = hwndDlg

retlog = ShowWindow( hwndDlg, SW_SHOW )

do while( GetMessage (mesg, NULL, 0, 0) )

retlog = TranslateMessage( mesg )
i = DispatchMessage( mesg )

end do

return
end

0 Kudos
9 Replies
jimdempseyatthecove
Honored Contributor III
1,426 Views

Insert diagnostic code to verify the value of hwndDlgit is a valid handle. Note, Vista may have added an additional return value that is not a valid handle that is also not NULL nor one of the NT/XP error codes.

It also is advised to check the return of ShowWindow.

Your do while loop assumes everything is set for calling GetMessage

Jim Dempsey

0 Kudos
anthonyrichards
New Contributor III
1,426 Views

Try

hwndDlg = CreateWindowEx (WS_EX_TOPMOST, lpszSplash, &
lpszAppName, &
IOR(WS_POPUPWINDOW, WS_CAPTION),&
100, &
100, &
400,&
600,&
NULL, &
NULL, &
ghINSTANCE, &
NULL )

and

retlog = ShowWindow( hwndDlg, SW_SHOWNORMAL )

You should also add an interface block for splashproc e.g.

interface
integer function splashproc ( hWnd, mesg, wParam, lParam )
!DEC$ IF DEFINED(_X86_)
!DEC$ ATTRIBUTES STDCALL, ALIAS : '_splashproc@16' :: splashproc
!DEC$ ELSE
!DEC$ ATTRIBUTES STDCALL, ALIAS : 'splashproc' :: splashproc
!DEC$ ENDIF
integer(4) hwnd,mesg,wparam,lparam
end function
end interface

0 Kudos
cartman4
Beginner
1,426 Views
Thanks for the reply Jim!

The hwndDlg value looks like a valid window handle (#0002045A). ShowWindow returns a nonzero value (#00000018).
0 Kudos
cartman4
Beginner
1,426 Views
I think I found the problem. The windows procedure for a previous window was erroneously calling PostQuitMessage after it's message loop has already exited, and the resulting WM_QUIT was making it's way to the current message loop. I don't know why the problem only manifested itself in Vista though.

Anyway thanks for the input Jim and Anthony!
0 Kudos
anthonyrichards
New Contributor III
1,426 Views

I think you can also get funny things happening with your 'while(GetMessage...) construction. Better I think is the following construction for your message loop:

do while( GetMessage (mesg, hwndDlg, 0, 0) .GT.0)

retlog = TranslateMessage( mesg )
i = DispatchMessage( mesg )

end do

Remember that Getmessage can return -1 as well as 0 and 1.

If you call this routine more than once, you should also check whether the window class has already been registered before you use registerclassEx (or unregister it before exiting the routine), and only use createwindowExafter you have testedthat registerclassex has returned a non-zero value.

0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,426 Views
Pardon my bluntness Tony, but your post was full of bad advice.

First, one should use NULL hwnd for GetMessage in a message loop for any practical application. That ensures that the correct target window will be eventually reached. Quote: "Value NULL: GetMessage retrieves messages for any window that belongs to the calling thread and thread messages posted to the calling thread via PostThreadMessage".

Second, the style:
do while( GetMessage (mesg, hwndDlg, 0, 0) .GT. 0)
is not good. GetMessage will return -1 in case of an error (e.g. bad hwnd); you likely don't want to exit your application if perchance you coded a wrong SendMessage call somewhere -- rather, you'd like the message ignored. Instead, one should use .NE. 0: GetMessage does not return a LOGICAL but an INTEGER(BOOL). Unfortunately, Ifort by default lets you get away with such free integer/logical mixing, where one can easily shoot oneself in the foot under the right circumstances.

Third, frankly, I don't get the purpose of check on RegisterClassEx return value; it cannot possibly fail. If it does fail, that means a) that you won't get the window at all and b) that you have a bug in your code that you should fix. While I'm all for defensive programming, this is taking it too far.
0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,426 Views
Cartman4:
I think I found the problem. The windows procedure for a previous window was erroneously calling PostQuitMessage after it's message loop has already exited, and the resulting WM_QUIT was making it's way to the current message loop. I don't know why the problem only manifested itself in Vista though.


See this interesting explanation and discussion afterwards (note that it dates from 2005):

http://blogs.msdn.com/oldnewthing/archive/2005/11/04/489028.aspx

According to that, multiple WM_QUIT messages (used to) "coalesce", i.e. system just merged them into one (because a "real" message has never existed in the first place). However, the behavior was not documented, therefore Vista developers were free to change it by changing the system internals -- purposefully or accidentally. You seem to be hit by that.
0 Kudos
anthonyrichards
New Contributor III
1,426 Views
I don't mind criticism, Jugoslav and would bow to yourwindows knowledge. However, my advice was posted given the information by the posterthathis window was not appearing (hence my and Jack'ssuggestion to check the Registerwindow return value - surely bug finding requires such 'defensive' programmimg?) and also that it appeared to be a splash window - hence why look at messages for all the thread's windows if you are bug-hunting?
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,426 Views

Jugoslave and Anthony

When I used to program device drivers on Windows NT in C we used the technique of using a macro named ASSERT(expression, "message") and place that into the code following function calls that would ordinarily never fail in a fully debugged application. The macro is expanded in the Debug version but not in the Release version. In Fortran you can use the Fortran Pre-Processor (FPP) to provide the same functionality

#ifdef _DEBUG
#define ASSERT(e, msg) IF(.NOT. (e)) CALL doASSERT(msg)
#else
#define ASSERT(e, msg)
#endif

Something like the above is often very useful during the initial phases of developing an applicaiton.

Jim Dempsey

0 Kudos
Reply