|
Ok,
On my way! But if I didn't have a machine I could reproduce this error on, how would I go about deciphering the drwatson stuff? I understand assembler enough to work with it, but I'm not sure how to go backwards from the drwatson to trace it to my application.
I'll report back after I try the pdb and debugger route
thanks!
Dan Willis
|
|
|
|
|
As you probably guessed Dr. Watson dumps stack, assembly, and memory dump for each thread in your program. Stack is meaningless unless you have PDB symbol file.
In you example "OrdinalXXXX" and "!<nosymbols>" could be real function name.
0012FCD0 6C371ED5 00000007 00000000 00982548 00982548 !<nosymbols>
0012FD50 6C371CEA 00000219 00000007 0040B268 0012FD6C !Ordinal5163
0012FD70 6C371C73 00000219 00000007 00000000 0040E4EC !Ordinal6374
0012FDD0 6C371BFB 00000000 001203B6 00000219 00000007 !Ordinal1109
0012FDEC 6C371BBA 001203B6 00000219 00000007 00000000 !Ordinal1578
0012FE18 77E148DC 001203B6 00000219 00000007 00000000 !Ordinal1579
0012FE38 77E14AA7 6C371B81 001203B6 00000219 00000007 user32!PtInRect
0012FEC4 77E266FD 0040E4EC 00000001 6C3711CE 0040E4EC user32!TranslateMessageEx
0040E4EC 00000219 00000007 00000000 1DDEB5AD 000001C0 user32!DispatchMessageA
From what I can guess one thread in your example just received WP_PAINT (or some UI windows message) and stumbled on 0 pointer or something, another was dealing with stack allocation. But again I could be wrong. This looks like typical crash from MS Office (probably Excel).
P.S. build pdb with detailed information.
|
|
|
|
|
Would you believe I don't have the MS SDK? All I have is VC++ Pro. I can't find a stand alone debugger. Sheesh!
I'm looking on the microsoft site. Got any ideas where I can find it? UGH
I also started to sift through the drwatson file.
If I could find this:
FAULT ->00407cad 83780402 cmp dword ptr [eax+0x4],0x2 ds:00b8d5d6=????????
Then I'd be able to trace it back to the place in the application which it is dying. I'm assuming the 00407cad is the location in memory the call is at, and I know what the call is I'm looking at.
but what is the 83780402 number? and what is the ds:00b8d5d6=????? Is that the other place in memory that the cmp is checking against?
Again, thanks. I'm just trying to learn more. Still have alot to learn I see. lol
Dan Willis
|
|
|
|
|
http://www.microsoft.com/ddk/debugging/default.asp
|
|
|
|
|
Thanks!
Off to the races again!
Dan Willis
|
|
|
|
|
There's a much easier way to debug this problem that doesnt (normally) require anything to be done to your clients machine. Use the .MAP file generated by the compiler.
Look in the .MAP file for the next lowest function offset from the FAULT entry offset in the Dr. Watson log file. That will show you what function the fault is happening in. If you didn't have the .MAP file enabled when you built what's running on your customer's machine, you can enable it now and build it as long as everything else is the same.
-pete
|
|
|
|
|
What do you mean by
pete mcquain wrote:
the next lowest function offset from the FAULT entry offset in the Dr. Watson log file.
Do you mean this:
00407ca8 8bec mov ebp,esp
00407caa 8b450c mov eax,[ebp+0xc] ss:00cbd2a6=????????
FAULT ->00407cad 83780402 cmp dword ptr [eax+0x4],0x2 ds:00b8d5d6=????????
-->>>> 00407cb1 751d jnz 004172d0
00407cb3 f6401001 test byte ptr [eax+0x10],0x1 ds:00b8d5d6=??
00407cb7 7417 jz 004107d0
00407cb9 8b400c mov eax,[eax+0xc] ds:00b8d5d6=????????
the one with the -->>>> ??
The drwatson log is in my first post. What should I be looking for? I don't see anything in the .map that has the 00407cad in it. Or am I looking in the wrong place
Dan Willis
|
|
|
|
|
What DrWatson tried to tell you was that while executing machine instructions from the address 00407cad to 00407cb0 (hexadecimal numbers!), where the bytes '83 78 04 02' (being the assembler instructions cmp dword ptr [eax+0x4],0x2 ds:00b8d5d6 ) had been located, a fault occured.
Now, you need to look into the .MAP file of your program (has to be from the same build as the dying one!) and find the function that contains the instructions at 00407cad to 00407cb0 .
This is the function with the highest start address (listed in the .MAP-file) that is also below your FAULT-adress (00407cad, from DrWatson).
Here the Error had occured.
Now you have a place to start looking for the error - up until here has been the easy part
Hope this helps
My opinions may have changed, but not the fact that I am right.
|
|
|
|
|
Yeah, what he said
-pete
|
|
|
|
|
You were right, That WAS the easy part.
Thanks. At least deciphering is a little clearer. But sheesh! trying to track down why is a whole 'nother issue!
Seems I'm chasing a phantom. Sometimes it dies, other times it will stay running for hours At least I know where to look and it has to do with clearing out memory, so I'm on my way, but sheesh, it keeps changing on me
well, back to the testing ground. I'll see what I can come up with using this new found knowledge
Dan Willis
|
|
|
|
|
OK, I found where it is consistantly dying, but I'm not sure why. Here's the function it is dying in:
void CFileView::OnGetDispInfo(NMHDR* pNMHDR, LRESULT* pResult)
{
CString string;
LV_DISPINFO* pDispInfo = (LV_DISPINFO*) pNMHDR;
if (pDispInfo->item.mask & LVIF_TEXT) {
ITEMINFO* pItem = (ITEMINFO*) pDispInfo->item.lParam;
switch (pDispInfo->item.iSubItem) {
case 0: // File name
::lstrcpy (pDispInfo->item.pszText, pItem->strFileName);
break;
case 1: // File size
string.Format (_T ("%u"), pItem->nFileSizeLow);
::lstrcpy (pDispInfo->item.pszText, string);
break;
case 2: // Date and time
CTime time (pItem->ftLastWriteTime);
BOOL pm = FALSE;
int nHour = time.GetHour ();
if (nHour == 0)
nHour = 12;
else if (nHour == 12)
pm = TRUE;
else if (nHour > 12) {
nHour -= 12;
pm = TRUE;
}
string.Format (_T ("%d/%0.2d/%0.2d (%d:%0.2d%c)"),
time.GetMonth (), time.GetDay (), time.GetYear () % 100,
nHour, time.GetMinute (), pm ? _T ('p') : _T ('a'));
::lstrcpy (pDispInfo->item.pszText, string);
break;
}
}
*pResult = 0;
}
Does anyone see anything wrong it? I'm still pluggin away, but this is the root of my problem I believe. All paths merge in this function. Any comments are greatly appreciated guys Thanks!
Dan Willis
|
|
|
|
|
Are you sure pDispInfo->item.pszText is always initialized and it has sufficient size? Same goes for pItem->strFileName.
|
|
|
|
|
no I'm not sure. I didn't realize I needed to be concerned with here. mmmm..... What should I do to initialize it in this case..
I think you're on to something here.
But I thought if I created a pointer to the LV_DISPINFO and then made that pointer point to the pNMHDR that being passed in, I wouldn't have to initialize the pDispInfo->.... since all I'm doing to making the pointer point to the pNMHDR being passed in. Am I right in this assumption?
Dan Willis
|
|
|
|
|
Do not get it. Run it by me again . Could you publish the structure here?
|
|
|
|
|
Ok Here's the LV_DISPINFO structure and the LVITEM structure that's embedded in it
typedef struct tagLVDISPINFO {
NMHDR hdr;
LVITEM item;
} NMLVDISPINFO, FAR *LPNMLVDISPINFO;
typedef struct _LVITEM {
UINT mask;
int iItem;
int iSubItem;
UINT state;
UINT stateMask;
LPTSTR pszText;
int cchTextMax;
int iImage;
LPARAM lParam;
#if (_WIN32_IE >= 0x0300)
int iIndent;
#endif
} LVITEM, FAR *LPLVITEM;
Ok, looking at the code I posted before referencing this data structure:
LV_DISPINFO* pDispInfo = (LV_DISPINFO*) pNMHDR;
if (pDispInfo->item.mask & LVIF_TEXT) {
ITEMINFO* pItem = (ITEMINFO*) pDispInfo->item.lParam;
switch (pDispInfo->item.iSubItem) {
case 0: // File name
::lstrcpy (pDispInfo->item.pszText, pItem->strFileName);
break;
case 1: // File size
string.Format (_T ("%u"), pItem->nFileSizeLow);
::lstrcpy (pDispInfo->item.pszText, string);
break;
case 2: // Date and time
CTime time (pItem->ftLastWriteTime);
BOOL pm = FALSE;
int nHour = time.GetHour ();
if (nHour == 0)
nHour = 12;
else if (nHour == 12)
pm = TRUE;
else if (nHour > 12) {
nHour -= 12;
pm = TRUE;
}
string.Format (_T ("%d/%0.2d/%0.2d (%d:%0.2d%c)"),
time.GetMonth (), time.GetDay (), time.GetYear () % 100,
nHour, time.GetMinute (), pm ? _T ('p') : _T ('a'));
::lstrcpy (pDispInfo->item.pszText, string);
break;
}
}
*pResult = 0;
I thought I would have enough space in the pDispInfo->item.pszText to put what ever string I needed to in there. I guess what you are saying is that I need to
initialize my structure to ensure the proper size.
Dan Willis
|
|
|
|
|
I think AlexO hit the nail in the head.
According to the docs for LVITEM, pszText is an LPTSTR, which means that it's just a pointer. It's not a character buffer, like your program is treating it. When you copy onto it, you're overwriting whatever memory it's pointing to at the moment, which may be harmless in some cases but not in others.
I'm not sure what your function is used for, but it looks like its intent is to change the text of the list view items. I don't understand why you're doing it this way instead of using SetItemText but whatever.
At any rate, the quick solution to this problem is to stop copying into the pointer and just assign it to a buffer that does not go away. The easiest way to do that is to make your string declaration static:
static CString string;
Then instead of ::lstrcpy (pDispInfo->item.pszText, string), you can do something like this:
pDispInfo->item.pszText = (LPTSTR)(LPCTSTR)string;
This will point it to the string's buffer, which will not go away since it will be static.
That's the quick and dirty solution, without knowing much else.
Regards,
Alvaro
All you need in this life is ignorance and confidence, and then success is sure. -- Mark Twain
|
|
|
|
|
that and ITEMINFO. What is ITEMINFO? I could not find in the standard headers.
|
|
|
|
|
typedef struct {
int iImage;
int iSelectedImage;
int iIndent;
LPTSTR pszText;
} ITEMINFO, *PITEMINFO;
Searched MSDN and found it on an example illustrating the use of ComboBoxEx controls. My guess is that ITEMINFO is his own structure which also happens to have the same name.
Regards,
Alvaro
All you need in this life is ignorance and confidence, and then success is sure. -- Mark Twain
|
|
|
|
|
oh,
Sorry guys, I was on a bug hunt (still).
I totally forgot about the ITEMINFO struct. Here is my ITEMINFO Structure:
typedef struct tagITEMINFO {
CString strFileName;
DWORD nFileSizeLow;
FILETIME ftLastWriteTime;
} ITEMINFO;
The reason I am modifying the displayed file information is that I'm really displaying a single "file" for a group of files, and this required me to associate a different filename/filesize/filedate with the item in the item list.
I suppose there was a different way to do it but this was all that came to mind the first time it was written.
I tried the
pDispInfo->item.pszText = (LPTSTR) (LPCTSTR) string;
and declaring the string as static but I'm still having the same issues. Good ole' Dr. Watson. Same exact spot though. I wish I could figure out how to find the exact line from the Dr. Watson. Then I'd be able to narrow it down even more. Although I suspect you guys are right, it has something to do with the buffer size for the text string.
Dan Willis
|
|
|
|
|
Ok now we are getting somewhere . Show how you instantiate your ITEMINFO and how you assign it to lParam
|
|
|
|
|
Here's where I initialize the ITEMINFO. I do this for every item in the list that is to be shown in my ListView.
//
// Allocate a new ITEMINFO structure and initialize it with information
// about the item.
//
ITEMINFO* pItem;
try {
pItem = new ITEMINFO;
}
catch (CMemoryException* e) {
e->Delete ();
return FALSE;
}
pItem->strFileName = fileName;
pItem->nFileSizeLow = fileSize / 1024; // in KB
pItem->ftLastWriteTime = fileAccessTime;
//
// Add the item to the list view.
//
LV_ITEM lvi;
lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
lvi.iItem = nIndex;
lvi.iSubItem = 0;
lvi.iImage = 0;
lvi.pszText = LPSTR_TEXTCALLBACK;
lvi.lParam = (LPARAM) pItem;
if (GetListCtrl ().InsertItem (&lvi) == -1)
return FALSE;
// now add the file data text
GetListCtrl().SetItemText(nIndex,3,(LPCSTR) fileDataType);
Dan Willis
|
|
|
|
|
I think I may have found my problem. Gimme a couple of minutes
Dan Willis
|
|
|
|
|
How can I get the temp directory? (The one you get from set in the command prompt)
Dylan
|
|
|
|
|
|
Don't know whether you need a second solution, but here it is:
You can also find the environment variables in the registry, f.i. for the current user under the key HKCU/Environment. It's all env variables defined there, not only TEMP.
|
|
|
|