|
For a system-wide hotkey you can use RegisterHotKey[^]. > The problem with computers is that they do what you tell them to do and not what you want them to do. <
> Sometimes you just have to hate coding to do it well. <
|
|
|
|
|
I have a problem in my program that I don't know how to even begin to track down. Please help!
It's an MFC program compiled in Visual Studio 2008 for WinXP and above (WinVer=0x0501). It runs fine for everyone who has tested it except one person who is running WinXP SP3. He's tried it on two different computers running WinXP SP3 and it crashes on both. I'm pretty sure he's the only one with SP3. I have XP SP2 here and it runs fine.
It crashes at the Windows entry point - the call to _tWinMain in crt0.c (which I know through the crash.dmp file he sent me):
mainret = _tWinMain( (HINSTANCE)&__ImageBase,<br />
NULL,<br />
lpszCommandLine,<br />
StartupInfo.dwFlags & STARTF_USESHOWWINDOW<br />
? StartupInfo.wShowWindow<br />
: SW_SHOWDEFAULT<br />
);<br />
<br />
<br />
The error message says: "Unhandled exception at 0x0041505e (myprog.exe) in CRASH.DMP: 0xC0000005: Access violation reading location 0x00000004."
I don't know how to even begin to track down a problem like this, especially when it appears to be platform-specific. Could someone give me some guidance on how to go about this?
Thanks!!!!
|
|
|
|
|
Hi,
I sympathise! The best way I can think of, is to get a separate machine with XpSp3 on it, and single step through it with a debugger. (you can also make your own system dual boot.) All you need is 'Bare Bones', with the Compiler, and your Files.
The bug appears to be in the Startup code. See if it does the same with a trivial MFC program. Also, after the Debug Version is Fixed (On your SP2 Machine!!) Test if the Retail version behaves, on BOTH SP2 and SP3 machines.
Things to look out for: It appears that either '__ImageBase' or 'lpszCommandLine' ended up being 0x04. You probably end up single stepping from 'wmainCRTStartup'.
Success,
Bram van Kampen
|
|
|
|
|
Bram van Kampen wrote: The best way I can think of, is to get a separate machine with XpSp3 on it, and single step through it with a debugger. (you can also make your own system dual boot.) All you need is 'Bare Bones', with the Compiler, and your Files.
I'd like to do that, but I'm running out of computers to put test code on. I used to have two XP notebooks, but one of them is dying - it makes a very loud grinding noise - and none of my machines has the hard disk space for dual booting.
Do you know at what point in an MFC program the _tWinMain function is called? If I could know how much of my code is executed - at what point in my program the deadly call is made - it would be a huge help. I'm just not that adept with the more exotic aspects of the debugger so I don't know how to figure this out.
|
|
|
|
|
Hi,
permutations wrote: I'd like to do that, but I'm running out of computers to put test code on.
well, That's somewhat essential if you support code spanning different O'S'. I have a dedicated Desktop machine with several harddisks, which I can boot up on anything from Xp Standard to Win7. The machine cost me less than £100 in a carboot sale. It 'Runs' vista, but just about. (a Lot happier with Win7). It is not ideal as a recommended environment for a customer, but it does exactly do the things I want to trap, i.e. incompatibilities.
permutations wrote: Do you know at what point in an MFC program the _tWinMain function is called?
Just start debugging by pressing F10. The program will break at _tWinMain. Then in your Stack window, go to the Calling Routine, and scroll to the top where you find _WinMainCRTStartUp(). Set a breakpoint there, and start again. That code will call set up the libraries and call the constructors.
Bram van Kampen
|
|
|
|
|
I broke down and did it. I don't have a lot of computers, but I do have a lot of spare hard drives, it turns out. I forgot about that.
I still cannot reproduce the bug, even under XP SP3. Also, two more beta testers turned up with XP SP3 and they can't, either. I think it's something this other guy is running. I asked him to try disabling his startup programs. It may be a bug in something else he's running that's writing beyond the boundaries of its own memory.
Also, I have VC++ 6 installed now on the XP SP3 system, and I'm going to rebuild the project there with line numbers in the map file. That will tell me exactly the line that is causing the problem.
|
|
|
|
|
Hi
permutations wrote: I broke down and did it
It's not that serious I hope...
permutations wrote: I still cannot reproduce the bug, even under XP SP3. Also, two more beta testers turned up with XP SP3 and they can't, either
Bugs like that can be tricky to find. An added problem is that seems to occur before WinMain starts. Things like Dumpfiles probably won't work! Things to look out for are your global variables. Are they all propperly initialised! If not, your program may work most of the time because the variable has a value that is by coincidence acceptable (or at least does not cause a crash). Change Something, (anything at all), and Oops! Crash!.
permutations wrote: two more beta testers turned up with XP SP3 and they can't, either
That seems to be a good omen!
Success,
Bram van Kampen
|
|
|
|
|
couple of things to look for:
1. initialization of global variables (especially classes which do non-trivial things in their ctors).
2. are you loading any DLLs? are they doing anything non-trivial in their WinMain's ?
also, i ran into a similar problem when i apparently got a bit too aggressive with pre-compiled headers. i had moved everything i could think of into the PCH, and for some reason, this caused the ctor of a global std::list variable to explode on startup. i never could track down exactly why it was happening, so i simply turned off PCH for that configuration and it worked fine.
|
|
|
|
|
Chris Losinger wrote: 2. are you loading any DLLs? are they doing anything non-trivial in their WinMain's ?
Yes, there is a very significant DLL. Here's a little bit more about what I'm doing. I wrote a DOS program back in 1991 that got some good reviews and sold pretty well. I wanted to rerelease this for both Windows and the Web, but without completely rewriting the thing. So I separated out all the DOS interface stuff, and created what I call the "engine", which I can then access from any interface.
Using precompiler directives, I can compile the engine as a DLL (called from my MFC interface), a CGI (compiled for Linux on the server) and accessed through HTML, or a standalone console app with no interface (I hardcode the values for testing).
In my InitInstance procedure, I find the user's My Documents directory, make a subdirectory beneath that for the files the app creates, then call a function in the DLL called BuildFileNames(). This basically takes some standard filenames and prepends the path that I found in InitInstance. I have stepped through this whole thing with the debugger and it is working correctly.
When I return from that, I initialize some global variables that I export in the DLL, open a database file (or create an empty one, if it does not exist), add the database file to the MRU list, and then display the app's main window.
The app uses a modeless dialog for the main window. I wrote a class called ModelessMain, which was easier than trying to circumvent the doc/view architecture.
One of my difficulties in tracking down the problem is that I don't know at what point it's crashing, from the perspective of my own code. The crash is in the _tWinMain() procedure, and I don't know at what point that is called. Isn't it called before InitInstance() even executes? And if so, how can my own code be causing this crash?
My difficulty here is my lack of understanding of how my MFC program is eventually calling the function that fails - the stack of calls from my program to eventually the failure point. That's why I don't even know where to look in my own code.
I really appreciate any help you can give me because I'm dead in the water at this point. I simply don't have the first clue how to proceed. I read something somewhere about looking at the stack of calls to figure this out, but I don't know how to do these advanced debugging techniques.
|
|
|
|
|
permutations wrote: The crash is in the _tWinMain() procedure, and I don't know at what point that is called. Isn't it called before InitInstance() even executes?
tWinMain calls AfxWinMain (in fact, that's all it does, in the MFC source that comes with VS08 ), and AfxWinMain eventually ends up calling your app's InitInstance.
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine, int nCmdShow)
#pragma warning(suppress: 4985)
{
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
so, i doubt the problem is in tWinMain itself. the problem has to be farther down the line.
if you can't reproduce the problem on your own machine, you can try something like a map file[^]. or, there's always good old log files[^].
|
|
|
|
|
Chris Losinger wrote: tWinMain calls AfxWinMain (in fact, that's all it does, in the MFC source that comes with VS08 ), and AfxWinMain eventually ends up calling your app's InitInstance.
This is another one of my points of confusion. In the crash.dmp file the beta tester sent me, the crash pops up inside the source file crt0c. The call looks similar to the one you quote, but not exactly. When I step into my app, I see what you quoted here. It's from appmodule.cpp. I tried to trace this through but it never got to this mysterious crt0.c call, which is slightly different. I also cannot figure out why the program would be calling _tWinMain TWICE in different modules.
Furthermore, if _tWinMain is called BEFORE my InitInstance function, then how could anything in my InitInstance function be the cause of the crash?
Chris Losinger wrote: so, i doubt the problem is in tWinMain itself. the problem has to be farther down the line.
I don't understand. How can code farther down the line, that hasn't executed yet, be the cause of the crash? There are fundamental things I don't understand about how MFC/Windows work that hamper my ability know where to look.
Chris Losinger wrote: if you can't reproduce the problem on your own machine, you can try something like a map file[^]. or, there's always good old log files[^].
Very interesting article about what to do with a map file, thanks. I've been creating a map file with exports, but had no idea what to do with it.
|
|
|
|
|
permutations wrote: How can code farther down the line, that hasn't executed yet, be the cause of the crash?
just a guess, but the tWinMain call might be the last-known function. that is, the crash blew most of the call stack away leaving tWinMain on top. that happens from time to time, even when running inside a debugger - a stray pointer kills your app and the debugger says it died inside AfxInitInstance (or whatever) - that's not the actual last function, it's just what the rubble looks like, after everything fell over.
just a guess, though.
permutations wrote: I also cannot figure out why the program would be calling _tWinMain TWICE in different modules.
i suspect a DLL could call tWinMain as part of its own startup.
|
|
|
|
|
Chris Losinger wrote: just a guess, but the tWinMain call might be the last-known function. that is, the crash blew most of the call stack away leaving tWinMain on top. that happens from time to time, even when running inside a debugger - a stray pointer kills your app and the debugger says it died inside AfxInitInstance (or whatever) - that's not the actual last function, it's just what the rubble looks like, after everything fell over.
Very interesting! I suspect you are right. I didn't think of that.
Chris Losinger wrote: i suspect a DLL could call tWinMain as part of its own startup.
Also interesting, and I think you may be right there, too.
I'd better get going on installing XP SP3 and a compiler somewhere so I can reproduce the bug here. So tedious. Maybe I'll watch TV while I do that.
|
|
|
|
|
permutations wrote: the crash pops up inside the source file crt0c
I believe that this is the start up code. This is where your app really gets started up by windows. It calls tWinMain, and, yes, it is before AfxWinMain and InitInstance. You are starting debugging at a point after this code has called your/mfc's code. You never see it get there because the programs already left that code before you start looking. Try setting a breakpoint in that code before starting your debug run.
While the start up code is before tWinMain, AfxWinMain, and InitInstance, it does call the constructors for any global classes that have to be instantiated. It probably initializes dlls as well. I'd suggest you go back to Chris Losinger's post which I believe was right on target:
Chris Losinger wrote: couple of things to look for:
1. initialization of global variables (especially classes which do non-trivial things in their ctors).
2. are you loading any DLLs? are they doing anything non-trivial in their DllMain's (edited by Avi) ?
Also, if you are dynamically linking with the MFC or C runtime libray dll's, have you triple checked dll versions on the client machine. Some versions of these have multiple revisions with identical names out in the wild. I have worked on a project that had problems that appear to have been due to this.Please do not read this signature.
|
|
|
|
|
You are assuming I'm able to reproduce the fault on my own system. Sadly, no. It is only this one particular beta tester who is experiencing the crash. The program runs fine on all my own computers (three different versions of Windows), and on every other person's computer who has ever run it.
The only thing I have to go on is the crash dump this particular beta tester sends me each time I send him a new build.
I think I have to bite the bullet and install the operating system he's using on one of my own systems. I can't see how I can possibly find this any other way, given that /MAPINFO:LINES is no longer supported by the linker in Visual Studio 2008.
I'll shut down my XP SP2 computer, pull out the hard drive and put in another hard drive I have that I don't mind blowing away, and install XP SP3 and VC++ 6 (which blessedly supports /MAPINFO:LINES. I just pray that I am able to reproduce the bug this way. I can't think what else it could be besides the unique platform he's using. I don't think any of my other beta testers are running XP SP3.
|
|
|
|
|
Good luck. I think that you are right about reproducing the error so that you can identify it. Will the VC 6 debugger be compatible with your VS 2008 executable? Please do not read this signature.
|
|
|
|
|
It was originally written with VC++ 6 so it should work fine.
However I am freaking out because I can't find the VC++ 6 disk, and it's not on the MSDN site for some reason. They have VC++ 4.2 and then Visual Studio 2005. I don't know why they don't have VC++ 6. Does it go by some other name? I can't remember.
EDIT:
OMG it's gone - I can't believe it. I feel like going to the storage place to look through my old MSDN disks for it, but it's night and raining. I can't believe this.
http://blogs.msdn.com/publicsector/archive/2005/12/07/501169.aspxmodified on Friday, March 12, 2010 9:18 PM
|
|
|
|
|
Got it - PHEW!! That's a relief.
Saved again by my packrat instinct. I had it in storage.
Now to set up the hard drive...
|
|
|
|
|
Chris Losinger wrote: if you can't reproduce the problem on your own machine, you can try something like a map file[^]. or, there's always good old log files[^].
I was so excited when I read this article and saw there was a way to identify the exact line number where the crash occurred - until I learned that Microsoft has removed the /MAPINFO:LINES option starting in Visual Studio 2005. <<sob>> How could they do that?
At least now I know for sure the error is in InitInstance(). I just don't know WHERE in InitInstance().
|
|
|
|
|
permutations wrote: At least now I know for sure the error is in InitInstance(). I just don't know WHERE in InitInstance().
time to add a log file. (or, a bunch of AfxMessageBox calls).
|
|
|
|
|
Chris Losinger wrote: also, i ran into a similar problem when i apparently got a bit too aggressive with pre-compiled headers. i had moved everything i could think of into the PCH, and for some reason, this caused the ctor of a global std::list variable to explode on startup. i never could track down exactly why it was happening, so i simply turned off PCH for that configuration and it worked fine.
Forgot to mention... I'm not using PCH. I'd already turned this off.
|
|
|
|
|
Okay, my level of mystification is ever so slightly reduced thanks to a very excellent article here:
MFC under the hood[^]
I still don't know why the crash dump points at crt01.c, but apparently _tWinMain is actually called by AfxWinMain, and... (drum roll)... this function is calling my app's InitInstance() method, which is where the read access error is occurring.
I can't use the map file to tell exactly what line is causing the fault because Microsoft bizarrely removed the MAPINFO:LINES option from the linker starting with Visual Studio 2005. (I'm running Visual Studio 2008.) I can estimate the range of lines in which it's occurring by looking at function addresses in the map file. It's somewhere between the start of the InitInstance() method and my first call to StringCchCopy() - if I'm reading the map file correctly.
It's starting to look like I'll never find this unless I install XP3 and a compiler somewhere, and recreate the error so I can use the debugger to find it. Maybe I'll install it on my tablet - the one that makes a horrible grinding noise. (This appears to be the fan and not the hard drive, since replacing the hard drive didn't help.)
Actually, come to think of it, I have an extra hard drive for that computer because of the grinding noise. I can install XP SP3 clean there, install VC++ 6 (which blessedly can show line numbers in the map file) and find the error that way. It's kind of a pain, but I don't see what other choice I have.
Oh wait! Better yet. I have an extra hard drive for an notebook that is running properly. I bought a bigger one. I can use the smaller one to install the test system. I will do that.
|
|
|
|
|
I've got XP SP3 installed and I can't reproduce the crash. The program runs fine. I also found someone else with XP SP3 and it didn't crash for him, either.
There is apparently something unique about how this one beta tester sets up his systems (the crash happens on both his computers), but I have no idea what.
On the plus side, I'm installing VC++ 6 on the XP SP3 system and that has an option for map line numbers. I'll move the project over to that computer and rebuild. Then when I get the crash report back I'll know exactly what line is causing the problem.
|
|
|
|
|
Actually, I think I did finally reproduce the crash, though in a slightly different form.
Using VC++ 6 on XP SP3, when I do a full rebuild, I get a link error at the very end: "fatal error LNK 1561: entry point must be defined". If I then do an incremental build it links fine and I'm able to run the program.
But this link error sounds suspiciously like the error my beta tester gets. When he runs the program, it fails on the program entry call to _tWinMain, and it's a read error. It's probably trying to read the program entry point and finding a null pointer.
I think that if I'm able to solve my link problem, I'll also solve the beta tester's crash problem. It's probably one of two things: either I set up my DLL incorrectly and that is causing confusion about entry points (I can't even remember how I did this - I'm going over it all again), or (more likely) I have a buffer overrun in one of the very first variables I set up in the program that is wiping out the program entry point. Buffer overruns are always such a joy to hunt for (not).
|
|
|
|
|
I'm stuck. I'm only getting this link error in Release mode. In Debug mode it's fine. And I've gone over everything carefully and can see no problems. I've also included error checking everywhere.
|
|
|
|
|