News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Modeless dialog: can't get it to work

Started by NoCforMe, April 18, 2017, 02:36:03 PM

Previous topic - Next topic

NoCforMe

Read up on the subject, did everything that was required, still no work; obviously, I'm missing something.

I'm trying to put up a small progress dialog modelessly. Dialog contains exactly 2 controls, a progress bar and a button (cancel). Works fine as a modal dialog, using DialogBoxIndirectParam(). (It's a memory-template dialog.)

But when I change it to a modeless dialog, using CreateDialogIndirectParam(), it never appears. The code just seems to bomb right through the call and proceed normally from there.

Here's what I've done:
o Changed the message loop to catch dialog messages:
msgloop:
INVOKE GetMessage, ADDR msg, NULL, 0, 0
OR EAX, EAX ;EAX = 0 = exit
JZ exit99

; Handle modeless dialog messages here:
CMP ProgressDialogHandle, NULL
JE @F
INVOKE IsDialogMessage, ProgressDialogHandle, ADDR msg
OR EAX, EAX
JNZ msgloop ;TRUE means dialog msg. was processed.

@@: INVOKE TranslateMessage, ADDR msg
INVOKE DispatchMessage, ADDR msg
JMP msgloop

exit99:


o Used DestroyWindow() instead of EndDialog() in the dialog procedure. (Doesn't matter because this code is never reached anyhow.)

The dialog header has the WS_VISIBLE style. This seems to cover everything, according to what I've read online (both MSDN and forums) and in Petzold.

What am I missing here?

BTW, I captured all the messages going to the dialog proc; here's what I saw:

WM_SETFONT
WM_NOTIFYFORMAT
WM_QUERYUISTATE
WM_CHANGEUISTATE
WM_INITDIALOG
WM_WINDOWPOSCHANGING
WM_WINDOWPOSCHANGING
WM_ACTIVATEAPP
WM_NCACTIVATE
WM_ACTIVATE
WM_IME_SETCONTEXT
WM_SETFOCUS
WM_WINDOWPOSCHANGED
WM_NCCALCSIZE
WM_MOVE
WM_SIZE
WM_KILLFOCUS
WM_IME_SETCONTEXT
WM_USER
WM_CHANGEUISTATE
WM_SHOWWINDOW
WM_WINDOWPOSCHANGING
WM_NCPAINT
WM_ERASEBKGND
WM_WINDOWPOSCHANGED
WM_NCCALCSIZE
WM_NCPAINT
WM_ERASEBKGND
WM_PAINT
WM_ERASEBKGND
WM_PRINTCLIENT
WM_CTLCOLORBTN
WM_NOTIFY
WM_NOTIFY

TIA
Assembly language programming should be fun. That's why I do it.

jj2007

Quote from: NoCforMe on April 18, 2017, 02:36:03 PMWhat am I missing here?

I don't have the faintest idea. But I can tell you what I am missing here:
1. Windows error messages (GetLastError)
2. Full code

fearless

You can use CreateDialogParam, something like:

DoDlgProgress PROC hWin:DWORD, dwSomeParamValue:DWORD

    Invoke CreateDialogParam, hInstance, IDD_DLGPROGRESS, hWin, Addr DlgProgressProc, dwSomeParamValue
    ; dwSomeParamValue passed as lParam parameter in the WM_INITDIALOG message, if not required just use NULL
    mov ProgressDialogHandle, eax ; save handle created to dialog

    .WHILE TRUE
        invoke GetMessage,addr msg,NULL,0,0
        .BREAK .if !eax
        Invoke IsDialogMessage, ProgressDialogHandle, addr msg
        .IF eax == 0
            invoke TranslateMessage,addr msg
            invoke DispatchMessage,addr msg
        .ENDIF
    .ENDW
    mov eax,msg.wParam
   
    ret
DoDlgProgress ENDP

DlgProgressProc PROC hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

    mov eax, uMsg
    .IF eax == WM_INITDIALOG
        ; get lParam for value passed to function if required for use somewhere
       
        ; show window or not, depending on whats required.
        Invoke ShowWindow, hWin, SW_SHOWNORMAL
       
        ...


or just add the IsDialogMessage part to main processing loop

Use EndDialog in the dialog proc.
In WM_INITDIALOG id get the handles to the progressbar control and any other buttons used and save them to global handles. Then do any processing in a separate thread so you can update progress bar, enable/disable any buttons and update any static text required with the handles to the ui items - that way the main message loop will continue and you wont get a freeze on the dialog ui whilst its processing something.

NoCforMe

Wellll, I feel quite the idiot here. Turns out there was one wee small error I was making. I omitted to say that the modeless dialog was being created in a separate thread, which I'd forgotten about. Of course, since CreateDialogIndirectParam() returns immediately (unlike DialogBoxIndirect Param() ), the thread ended and the dialog box went kablooey. (I discovered this by putting up a MessageBox, which showed the modeless dialog humming along nicely until I closed the message box, at which point the dialog disappeared.)

Good thing too, JJ, since I was about to post a boatload of code here. Saved you all that trouble!

Quote from: fearless on April 19, 2017, 04:55:19 AM
Use EndDialog in the dialog proc.

Ackshooly, that's wrong. Everyone, including MSDN and Petzold, says to use DestroyWindow() instead of EndDialog() for a modeless dialog.
Assembly language programming should be fun. That's why I do it.

jj2007

Quote from: NoCforMe on April 20, 2017, 12:45:40 PMGood thing too, JJ, since I was about to post a boatload of code here. Saved you all that trouble!

Putting on my tin foil hat and do a telediagnosis of your code and thoughts, that is trouble.
Running your code in Olly and see where it fails and why, that is easy.

hutch--

You need to know just a little bit about what the history of dialogs is about. Primarily they are designed as accessories to a running application created with CreateWindowEx() which already has a message processing loop for the current process. With this as the base you can run either a modal or modeless dialog and either will run correctly if its coded properly. It is when you make a dialog as the main interface that you get problems with a modeless dialog as there is no main message loop. When you use a dialog as an interface you make the parent dialog a modal as the OS provides the message loop.

You can use a modeless dialog as the main interface but then you have to create a message loop that works with it.