How to see complete call stack on debug a dialog box

When I set a breakpoint within dialog box code and stop there, the call stack is shown as something like:

CEditArchiveDataDlg::OnInitDialog() line 1079
AfxDlgProc(HWND__ * 0x00000e54, unsigned int 0x00000110, unsigned int 0x00000d60, unsigned int 0x00000d60) line 35 + 14 bytes
KERNEL32! bff7363b()
KERNEL32! bff942e7()

and I can't see where in my main app the DoModal() is actually called from. Nor can I go back and look at variables that should be visible to me in the routine that is invoking the dialog box.

It's possible I need the system symbols to help the debugger unwind thru the callstack but the only reference I can find to loading the system symbols is for a Windows NT system and I am using Windows 98!

Is there any way that I can persuade the debugger to give me a complete call stack back to my WinApp code (theApp)?

This is the call stack from a breakpoint in the constructor of the CDialog derived object that is going to start the above dialog box with a DoModal() (I've chopped off long lines):

CEditArchiveDataDlg::CEditArchiveDataDlg(CRaceArchive * 0x0045a778 {CRaceArchive}, CWnd * 0x00000000 {CWnd hWnd=???}) line 1038
CRaceArchive::EditArchiveData() line 363 + 17 bytes
CRaceApp::OnEditEditArchiveData() line 263
_AfxDispatchCmdMsg(CCmdTarget * 0x0045a6b0 class CRaceApp  theApp, unsigned int 0x0000800e, int 0x00000000, void (void)* 0x00401bae CRaceApp::OnEditEditArchiveData(void), void * ...
CCmdTarget::OnCmdMsg(unsigned int 0x0000800e, int 0x00000000...
CFrameWnd::OnCmdMsg(unsigned int 0x0000800e, int 0x00000000, ...
CMDIFrameWnd::OnCmdMsg(unsigned int 0x0000800e, int 0x00000...
CWnd::OnCommand(unsigned int 0x0000800e, long 0x00000000) ...
CFrameWnd::OnCommand(unsigned int 0x0000800e, ...
CMDIFrameWnd::OnCommand(unsigned int 0x0000800e, ...
CWnd::OnWndMsg(unsigned int 0x00000111, unsigned int ...
CWnd::WindowProc(unsigned int 0x00000111, unsigned int...
AfxCallWndProc(CWnd * 0x007c1650 {CMainFrame hWnd=0x000009dc}, HWND__ * 0x000009dc, unsigned int 0x00000111,...
AfxWndProc(HWND__ * 0x000009dc, unsigned int...
AfxWndProcBase(HWND__ * 0x000009dc, unsigned ...
KERNEL32! bff7363b()
KERNEL32! bff942e7()
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

>>and I can't see where in my main app the DoModal() is
>>actually called from

No, the call stack is correct - this is obviously happening inside a thread, and it's the complete call stack of the thread you placed your breakpoint in. If you install the system symbols, you'll see that one of the 'KERNEL*' symbols is 'BaseThreadStart()'

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
BTW: Otherwise your call stack would be corrupted and the program would crash. The debugger basically does sth. like this:

    CONTEXT             ctx;
    STACKFRAME          sf;

    PIMAGEHLP_SYMBOL    pimgSym;
    DWORD               dwDisplacement;

    pimgSym =   ( PIMAGEHLP_SYMBOL) malloc (    sizeof  (   IMAGEHLP_SYMBOL)    +   256);

    pimgSym->SizeOfStruct   =   sizeof  (   IMAGEHLP_SYMBOL)    +   256;
    pimgSym->MaxNameLength  =   256;

    SuspendThread   (>hThread);

    ZeroMemory  (   &ctx,   sizeof  (   CONTEXT));
    ZeroMemory  (   &sf,    sizeof  (   STACKFRAME));


    if  (   !GetThreadContext   (   hThread,    &ctx))
            return  (   0);

    printf  (   "\nStack trace:\n");

    sf.AddrPC.Offset    =   ctx.Eip;
    sf.AddrPC.Mode      =   AddrModeFlat;
    sf.AddrStack.Offset =   ctx.Esp;
    sf.AddrStack.Mode   =   AddrModeFlat;
    sf.AddrFrame.Offset =   ctx.Ebp;
    sf.AddrFrame.Mode   =   AddrModeFlat;

    while   (   TRUE)
                if  (   !StackWalk  (   IMAGE_FILE_MACHINE_I386,
                    )   break;

                if  (   0   ==  sf.AddrFrame.Offset) // Basic sanity check to make sure
                        break;                       // the frame is OK.  Bail if not.

                printf  (   "TID: %u H:0x%x %08X  %08X  ",  

                if  (   !SymGetSymFromAddr  (   hProcess,
                        char    acModule    [   MAX_PATH]   =   "\0";

                        DWORD   dwSection   =   0;
                        DWORD   dwOffset    =   0;

                        nErr    =   GetLastError    ();
                        GetLogicalAddress   (  (PVOID) sf.AddrPC.Offset,

                        printf  (   "%04X:%08X %s\n",
                else    printf  (   "%hs+%X\n", pimgSym->Name, dwDisplacement);
emitchellAuthor Commented:
Can I install the system symbols on a Windows 98 machine? If so could you point me to the doc that tells me how.

Since the dialog box is opened with its own thread, can I persuade the debugger to go look at the call stack of the other thread?

What I'd really like to do is to check on the variables in my base app when I find that there is a problem inside the dialog box. Is this possible?

Cloud Class® Course: Microsoft Office 2010

This course will introduce you to the interfaces and features of Microsoft Office 2010 Word, Excel, PowerPoint, Outlook, and Access. You will learn about the features that are shared between all products in the Office suite, as well as the new features that are product specific.

>>Can I install the system symbols on
>>a Windows 98 machine?

Hmm, yes, but I have to say that I'm a bit lost - yes, you can, but as we're using NT as our development platform, I should read some 'readmes' ;-)

>>Since the dialog box is opened
>>with its own thread, can I persuade
>>the debugger to go look at the call
>>stack of the other thread?  

Yes, there's an option to switch to other threads too (being at home, I have no VC++ installed to give you the correct hint where exactly to set this option)

>>What I'd really like to do is to
>>check on the variables in my base >>app when I find that there is a
>>problem inside the dialog box. Is
>>this possible?

Yes, of course, you should make sure to set a brekpoint in the execution path you want to follow - the easiest method is to hard-code an __asm{ int 3};' aka 'DebugBreak()' in your code to force the debugger to load...
emitchellAuthor Commented:
I'm not sure what the system symbols gets me except I assume that it will translate the KERNEL32 addresses to something more meaningful! I found the following in the MSDN help:

How to Set Up Windows NT Debug Symbols
ID: Q148659

but there doesn't seem to be anything for Windows 98. I'm going to try this on my NT machine at work tomorrow just to see what the symbols buys me!

> Yes, there's an option to switch to other threads too (being at
> home, Ihave no VC++ installed to give you the correct hint
> where exactly toset this option)

I found the Threads... menu item under the Debug menu but when I use this when I am at the breakpoint in the dialog box, it just shows a single thread.  This is the entry in the threads dialog:

Thread ID    Suspend   Priority   Location
*fff7bb71     0            8           CEditArchiveDataDlg::OnInitDialog

which seems to indicate that it is the thread where I am stopped.  However there is no indication of any other thread which is presumably stopped in the DoModal() of the main app.

>>What I'd really like to do is to
>>check on the variables in my base
>>app when I find that there is a
>>problem inside the dialog box. Is
>>this possible?

> Yes, of course, you should make sure to set a brekpoint in the > execution path you want to follow - the easiest method is to
> hard-code an __asm{int 3};' aka 'DebugBreak()' in your code
> to force the debugger to load...

Remember my problem is not how to get control.  I've set the breakpoint in the OnInitDialog() of the dialog box so the debugger has stopped the process at this point and is active. If I could switch the debugger to the other thread, that would let me LOOK at variables in the main app. At present I am blind. I have to go back, set a breakpoint at the DoModal() and look when the debugger stops there. Look around and make a note of what the variables are set to and then give the debugger a "go" when it will stop inside the dialog box and and I can then follow the action there.  If I forget to look at an important variable, I go back and do it all over again. Most systems I've worked on with a debugger (Unix, VAX/VMS), one just goes up the call stack to the appropriate routine and all the symbols are available for examination. Of course I've never come upon multiple threads before either!

                          Here are your options, emitchell
emitchellAuthor Commented:
I just read the MSDN doc on debugging threads and there they say that the Threads... item in the Debug menu shows the number of active threads in the process.  Since I only show one thread, it can't be a case of the DoModal() starting a separate thread.  With one thread  there shouldn't be anything in the way of a full unwind to the start of the process!

>>With one thread  there shouldn't be anything in the way
>>of a full unwind to the start of the process!

You're right, but there's still one other thing: Context and the Window procedure. The window procedure is called from the system context (and not your app), so it's still the complete call stack (try a simple Win32 app a set a breakpoint in the window proc...)
emitchellAuthor Commented:
Now I have tried this on my NT machine at the office which appears to give a complete call stack (copied at the end) and with all the symbols! Now I can go to the DoModal() routine by clicking on this line, just as one is supposed to do.

It appears that my problem is with Windows 98.   Does anyone know of a way around this?

EditArchiveDataDlg::OnInitDialog() line 46
AfxDlgProc(HWND__ * 0x001405ea, unsigned int 0x00000110...
USER32! DefDlgProcWorker@20 + 111 bytes
USER32! DefDlgProcA@16 + 37 bytes
USER32! CallWindowProcAorW@24 + 41 bytes
USER32! CallWindowProcA@20 + 25 bytes
CWnd::DefWindowProcA(unsigned int 0x00000110, unsigned ...
CWnd::Default() line 249
CDialog::HandleInitDialog(unsigned int 0x001f05e6, unsi...
CWnd::OnWndMsg(unsigned int 0x00000110, unsigned int 0x...
CWnd::WindowProc(unsigned int 0x00000110, unsigned int ...
AfxCallWndProc(CWnd * 0x0012fc04 {CEditArchiveDataDlg h...
AfxWndProc(HWND__ * 0x001405ea, unsigned int 0x00000110...
AfxWndProcBase(HWND__ * 0x001405ea, unsigned int 0x0000...
USER32! SendMessageWorker@20 + 154 bytes
USER32! InternalCreateDialog@28 + 1462 bytes
USER32! CreateDialogIndirectParamAorW@24 + 54 bytes
USER32! CreateDialogIndirectParamA@20 + 25 bytes
CWnd::CreateDlgIndirect(const DLGTEMPLATE * 0x0041aa68,...
CDialog::DoModal() line 528 + 32 bytes
CCallStakDoc::OnNewDocument() line 47 + 8 bytes
CMultiDocTemplate::OpenDocumentFile(const char * 0x0000...
CDocManager::OnFileNew() line 829
CWinApp::OnFileNew() line 29
_AfxDispatchCmdMsg(CCmdTarget * 0x004178c0 class CCallS...
CWinApp::OnFileNew, void * 0x00000000, unsigned int 0x0...
AFX_CMDHANDLERINFO * 0x00000000) line 88
CCmdTarget::OnCmdMsg(unsigned int 0x0000e100, int 0x000...
CWinApp::ProcessShellCommand(CCommandLineInfo & {CComma...
CCallStakApp::InitInstance() line 93 + 12 bytes
AfxWinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00...
WinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000...
WinMainCRTStartup() line 330 + 54 bytes
KERNEL32! BaseProcessStart@4 + 64 by

It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.