Hi,
I'm modifying large bridge playing program written in C++ using MS Visual C++ 6.0 and am having a problem with the program. When I run it in Auto Test mode: it deals, bids and plays hands and posts the results to a dialog window, after 181 hands the GUI in the dialog window stops being updated and if I move the dialog window I get an error message: "Easybridge has encountered a problem ...". The error report lists ModName: ntdll.dll, offset: 0120e.
If I let the dialog box be displayed for several minutes when it has reached 181 hands, its display is NOT updated and nothing happens until I touch it or open another window on top of it. The program appears to have been running while the display was frozen at 181 hands because when I open Wordpad, the display jumps to show more hands played.
On Entering Debug I see one entry for the EasyBridge program in the call stack. The statement at the line shown in the call stack is: if (!AfxGetApp()->PumpMessage())
Also on the stack there is a failed Assert in MFC42D.DLL SelectObject() at line 558 where m_hDC is = NULL
The PumpMessage() statement is in the loop where the program deals, bids and plays the name. The full loop's code follows:
Code:
do
{
#ifdef _DEBUG
msOld.Checkpoint(); // NCR-AT debug
#endif
// play continuously
// deal a new hand
m_strStatus = "Dealing...";
UpdateData(FALSE);
pDOC->DealHands();
numHands++;
// and get bids
m_strStatus = "Bidding...";
UpdateData(FALSE);
do
{
// get the computer's bids
int nPos = pDOC->GetCurrentPlayerPosition();
int nBid = pDOC->GetCurrentPlayer()->Bid();
nCode = pDOC->EnterBid(nPos, nBid);
if ((nCode == -99) || (nCode == 1))
{
// passed out, or 3 passes, and bidding is complete
break;
}
else if (nCode == -1)
{
AfxMessageBox("Error in Bidding Dialog!");
bBreak = TRUE;
break;
}
} while (!bBreak);
// bidding is complete; see if we reached a contract
if (nCode == -99)
continue; // passed out, so redeal
// start timeing
long lStartTime = timeGetTime();
// now play out the hand -- play on full auto
theApp.SetValue(tnCardPlayMode, CEasyBApp::PLAY_FULL_AUTO_EXPRESS);
pDOC->SetValue(tbExpressPlayMode, TRUE);
pDOC->InvokeNextPlayer();
// pump the mesage loop while the hand is being played out
m_strStatus = "Playing hand...";
UpdateData(FALSE);
if(numHands == 180) { // NCR-AT stop just before abend
if (AfxMessageBox("The Practice abends at about game 181. Do you wish to continue?",
MB_ICONQUESTION | MB_YESNO) == IDNO)
break;
} // NCR-AT end
MSG msg;
int cnt = 0; // NCR-AT debug
while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (!AfxGetApp()->PumpMessage())
{
::PostQuitMessage(0);
return;
}
cnt++; // NCR-AT
}
totalCnt += cnt; // NCR
TRACE("numHands=%d cnt=%d totalCnt=%d\n", numHands, cnt, totalCnt); // NCR
// reset flags
pDOC->SetValue(tbExpressPlayMode, FALSE);
// end timer
lNumHands++;
long lEndTime = timeGetTime();
lfTotalTime += (lEndTime - lStartTime);
strAvgTime.Format(_T("%.1f secs"), lfTotalTime / (lNumHands*1000));
//
CStatic* pText = (CStatic*) GetDlgItem(IDC_AVG_TIME);
pText->SetWindowText(strAvgTime);
pText->UpdateWindow();
//
CStatic* pLabel = (CStatic*) GetDlgItem(IDC_LABEL_AVGTIME);
if (!pLabel->IsWindowVisible())
{
pLabel->ShowWindow(SW_SHOW);
pLabel->UpdateWindow();
}
//
if (m_bStopFlag)
break;
// save results and update the display
Update();
#ifdef _DEBUG
// NCR-AT dump every so often
if(numHands % 100 == 1)
{
msNew.Checkpoint();
msDif.Difference( msOld, msNew );
msDif.DumpStatistics();
if(numHands < 20)
msOld.DumpAllObjectsSince(); // only want a couple
}
#endif
} while (!bBreak);
How do I find out what my program is doing to the Windows environment that is causing the problem and fix it?
If you can run the code under the debugger, once the program crashes, look at the call stack to determine what part of your program caused the failure in the MFC dll.
If you can't run under a debugger, the put in some assert and trace statements. Add asserts to all returned pointer values. Use TRACE statements and a program like DbgView to find out where you are in the program.
Thanks for the response.
When the problem happens, I enter a debugger and look at the call stack. I included info about the call stack in my first post. I'll try it from the debugger to see if the call stack is different.
Another observation: If I open the program and before starting AutoPlay, I C+A+D to start the task manager and leave the taskmanager running on top of the program's window, when I then start the AutoPlay part of the program, the program runs as before (updates the dialog window stats up to hand 181) and then continues running!!! It updates the stats every so often, say every 10 to 50 hands and continues running. It got to over 1000 hands before I got tired of waiting and ended it. Also sometime while its running, the whole of the monitor screen is painted the same color as the dialog window background (light tan) and only the controls that are being updated in the dialog window and in the task manager show. The window's border and controls do not show.
I'm curious about the "m_hDC is = NULL" ASSERT. Is this from your OnPaint handler? If so, could you post your OnPaint code? I think this might be the cause of the painting problem and may be the root cause. If the program is doing painting outside of OnPaint, this could cause issues as well.
One thing I wonder about is why the display always freezes after displaying the stats for 181 hands. Would that mean that somewhere in Windows code there is a buffer with 181 entries and the 182nd entry causes the problem?
if(numHands == 180) { // NCR-AT stop just before abend
if (AfxMessageBox("The Practice abends at about game 181. Do you wish to continue?",
MB_ICONQUESTION | MB_YESNO) == IDNO)
break;
} // NCR-AT end
Arjay,
Any other suggestions on why the display stops updating at 181 hands?
hoxsiew,
That's my code to prevent the program reaching the error point. It allows me to exit the loop at 180 hand played ie. before the error happens.
hoxsiew,
That's my code to prevent the program reaching the error point. It allows me to exit the loop at 180 hand played ie. before the error happens.
Oh, OK. I thought it suspicious that it matched your magic number, but I see that it is by design after the fact.
It's difficult trying to debug your program from afar. If you want to zip it up and post it, I'd be happy to take a look (assuming it's VS2005 or VS2008). I suspect something in your painting routine is leaking.
Windows still has a lot of resources that have a limitation.
Amount of GDI handles, windows etc. An error like this where everything appears to be running smoothly and suddenly you get 'weird' errors and graphic glitches usually indicate an issue somewhere with resources not getting cleaned up properly.
Open task manager, open the 'Processes' tab. Make sure the Handles, USER objects and GDI objects columns are visible (add them via the menu: View, Select Columns).
Run your program and see if any of those 3 numbers is continuously increasing as you play through the hands.
Also keep a check on memory usage. It could be a memory leak and at 181 hands you run out of allocatable memory.
To run the test, you need to use the debug version
First, why do you need to use the debug version?
Second, Microsoft's License says that it is not legal to distribute debug versions of your program. If you create a standalione EXE or DLL, it must use or depend on the release versions of the MFC and runtime libraries, not debug versions.
Regards,
Paul McKenzie
Last edited by Paul McKenzie; January 17th, 2010 at 11:30 AM.
To run the test, you need to use the debug version and use the Game|Auto Test menu item
Sorry, I can't seem to get anywhere with this. My caveat was that I only have VS2005 and VS2008 and this code appears to be VC6 code. There appears to be several files listed in the project that are missing, notably the View, which was the one I was most interested in seeing (where the paint routines should be).
May I suggest you change your source code so that you aren't coding using the broken VC 6.0 syntax, especially the loops. Most people are using Visual Studio 2005 and above, and the code below causes syntax errors.
Code:
for (int i = 0; i < whatever; ++i)
{
// whatever
}
for (i = 0; i < whatever2; ++i )
{
}
The VC 6.0 compiler is broken. The line in red is not legal C++, since the scope of the "i" variable ends with the first for() loop. You have a lot of places in your code where stuff like this is done.
Change this so that the declaration of "i: is outside the loop:
Code:
int i;
for (i = 0; i < whatever; ++i)
{
// whatever
}
for (i = 0; i < whatever2; ++i )
{
}
Bookmarks