1 ///////////////////////////////////////////////////////////////////////////////
7 // Copyright (c) 2003 Michael Carruth
9 ///////////////////////////////////////////////////////////////////////////////
16 #include "StackTrace.h"
18 //////////////////////////////////////////////////////////////////////
19 // Construction/Destruction
20 //////////////////////////////////////////////////////////////////////
23 //-----------------------------------------------------------------------------
24 // CExceptionReport::CExceptionReport
28 CExceptionReport::CExceptionReport(PEXCEPTION_POINTERS ExceptionInfo
, BSTR message
)
30 m_excpInfo
= ExceptionInfo
;
32 TCHAR szModName
[_MAX_FNAME
+ 1];
33 GetModuleFileName(NULL
, szModName
, _MAX_FNAME
);
34 m_sModule
= szModName
;
35 m_sCommandLine
= GetCommandLine();
40 //-----------------------------------------------------------------------------
41 // CExceptionReport::getCrashFile
43 // Creates the dump file returning the file name
45 string
CExceptionReport::getCrashFile()
47 TCHAR buf
[MAX_PATH
] = {0};
48 _stprintf_s(buf
, MAX_PATH
, _T("%s\\%s.dmp"), _tgetenv("TEMP"), CUtility::getAppName().c_str());
51 HANDLE hFile
= CreateFile(
57 FILE_ATTRIBUTE_NORMAL
,
61 // Write the minidump to the file
65 writeDumpFile(hFile
, m_excpInfo
, reinterpret_cast<void *>(this));
75 void CExceptionReport::writeDumpFile(HANDLE hFile
, PEXCEPTION_POINTERS excpInfo
, void *data
)
77 if (excpInfo
== NULL
) {
78 // Generate exception to get proper context in dump
80 RaiseException(EXCEPTION_BREAKPOINT
, 0, 0, NULL
);
81 } __except(writeDumpFile(hFile
, GetExceptionInformation(), data
), EXCEPTION_CONTINUE_EXECUTION
) {
84 MINIDUMP_EXCEPTION_INFORMATION eInfo
;
85 eInfo
.ThreadId
= GetCurrentThreadId();
86 eInfo
.ExceptionPointers
= excpInfo
;
87 eInfo
.ClientPointers
= FALSE
;
89 MINIDUMP_CALLBACK_INFORMATION cbMiniDump
;
90 cbMiniDump
.CallbackRoutine
= CExceptionReport::miniDumpCallback
;
91 cbMiniDump
.CallbackParam
= data
;
95 GetCurrentProcessId(),
97 MiniDumpWithIndirectlyReferencedMemory
,
98 excpInfo
? &eInfo
: NULL
,
104 //-----------------------------------------------------------------------------
105 // CExceptionReport::getCrashLog
107 // Creates the XML log file returning the name
109 string
CExceptionReport::getCrashLog()
112 MSXML2::IXMLDOMDocument
*pDoc
= NULL
;
113 MSXML2::IXMLDOMNode
*root
= NULL
;
114 MSXML2::IXMLDOMNode
*node
= NULL
;
115 MSXML2::IXMLDOMNode
*newNode
= NULL
;
116 BSTR rootName
= ::SysAllocString(L
"Exception");
121 // Create an empty XML document
122 CHECKHR(CoCreateInstance(
123 MSXML2::CLSID_DOMDocument
,
125 CLSCTX_INPROC_SERVER
,
126 MSXML2::IID_IXMLDOMDocument
,
130 root
= CreateDOMNode(pDoc
, MSXML2::NODE_ELEMENT
, rootName
);
133 // Add exception record node
137 node
= CreateExceptionRecordNode(pDoc
, m_excpInfo
->ExceptionRecord
);
138 CHECKHR(root
->appendChild(node
, &newNode
));
139 // The XML Document should now own the node.
141 SAFERELEASE(newNode
);
145 // Add optional message node
147 if (m_message
!= NULL
) {
148 node
= CreateMsgNode(pDoc
, m_message
);
149 CHECKHR(root
->appendChild(node
, &newNode
));
150 // The XML Document should now own the node.
152 SAFERELEASE(newNode
);
156 // Add processor node
158 node
= CreateProcessorNode(pDoc
);
159 CHECKHR(root
->appendChild(node
, &newNode
));
160 // The XML Document should now own the node.
162 SAFERELEASE(newNode
);
167 node
= CreateOSNode(pDoc
);
168 CHECKHR(root
->appendChild(node
, &newNode
));
169 // The XML Document should now own the node.
171 SAFERELEASE(newNode
);
176 node
= CreateModulesNode(pDoc
);
177 CHECKHR(root
->appendChild(node
, &newNode
));
178 // The XML Document should now own the node.
180 SAFERELEASE(newNode
);
183 // Add stack walkback node
185 node
= CreateWalkbackNode(pDoc
, m_excpInfo
!= NULL
? m_excpInfo
->ContextRecord
: NULL
);
186 CHECKHR(root
->appendChild(node
, &newNode
));
187 // The XML Document should now own the node.
189 SAFERELEASE(newNode
);
192 // Add the root to the doc
193 CHECKHR(pDoc
->appendChild(root
, NULL
));
196 // Create dat file name and save
198 TCHAR buf
[MAX_PATH
] = {0};
199 _tprintf_s(buf
, _T("%s\\%s.xml"), getenv("TEMP"), CUtility::getAppName());
201 V_BSTR(&v
) = CUtility::AllocSysString(buf
);
203 SysFreeString(V_BSTR(&v
));
209 SAFERELEASE(newNode
);
210 SysFreeString(rootName
);
218 //-----------------------------------------------------------------------------
219 // CExceptionReport::getNumSymbolFiles
221 // Returns the number of symbols files found
223 int CExceptionReport::getNumSymbolFiles()
225 return m_symFiles
.size();
229 //-----------------------------------------------------------------------------
230 // CExceptionReport::getSymbolFile
232 // Returns the symbol file name given an index
234 string
CExceptionReport::getSymbolFile(int index
)
238 if (0 < index
&& index
< (int)m_symFiles
.size())
239 ret
= m_symFiles
[index
];
244 //-----------------------------------------------------------------------------
245 // CExceptionReport::CreateDOMNode
250 CExceptionReport::CreateDOMNode(MSXML2::IXMLDOMDocument
* pDoc
,
254 MSXML2::IXMLDOMNode
* node
;
258 V_I4(&vtype
) = (int)type
;
260 pDoc
->createNode(vtype
, bstrName
, NULL
, &node
);
264 //-----------------------------------------------------------------------------
265 // CreateExceptionSymbolAttributes
267 // Create attributes in the exception record with the symbolic info, if available
269 void CExceptionReport::CreateExceptionSymbolAttributes(DWORD_PTR
/*address*/, const char * /*ImageName*/,
270 const char *FunctionName
, DWORD_PTR functionDisp
,
271 const char *Filename
, DWORD LineNumber
, DWORD lineDisp
,
275 BSTR funcName
= ::SysAllocString(L
"FunctionName");
276 BSTR funcDispName
= ::SysAllocString(L
"FunctionDisplacement");
277 BSTR fileName
= ::SysAllocString(L
"Filename");
278 BSTR lineName
= ::SysAllocString(L
"LineNumber");
279 BSTR lineDispName
= ::SysAllocString(L
"LineDisplacement");
280 CExceptionReport
*self
= reinterpret_cast<CExceptionReport
*>(data
);
284 // don't need ImageName [module], as that is already done
285 if (FunctionName
!= NULL
) {
287 V_BSTR(&v
) = CUtility::AllocSysString(FunctionName
);
288 self
->m_exception_element
->setAttribute(funcName
, v
);
290 SysFreeString(V_BSTR(&v
));
291 TCHAR buf
[MAX_PATH
] = {0};
292 _tprintf_s(buf
, offsetFormat
, functionDisp
);
294 V_BSTR(&v
) = CUtility::AllocSysString(buf
);
295 self
->m_exception_element
->setAttribute(funcDispName
, v
);
297 SysFreeString(V_BSTR(&v
));
300 if (Filename
!= NULL
) {
302 V_BSTR(&v
) = CUtility::AllocSysString(Filename
);
303 self
->m_exception_element
->setAttribute(fileName
, v
);
305 SysFreeString(V_BSTR(&v
));
307 TCHAR buf
[MAX_PATH
] = {0};
308 _tprintf_s(buf
, _T("%d"), LineNumber
);
310 V_BSTR(&v
) = CUtility::AllocSysString(buf
);
311 self
->m_exception_element
->setAttribute(lineName
, v
);
313 SysFreeString(V_BSTR(&v
));
315 _tprintf_s(buf
, offsetFormat
, lineDisp
);
317 V_BSTR(&v
) = CUtility::AllocSysString(buf
);
318 self
->m_exception_element
->setAttribute(lineDispName
, v
);
320 SysFreeString(V_BSTR(&v
));
322 ::SysFreeString(funcName
);
323 ::SysFreeString(funcDispName
);
324 ::SysFreeString(fileName
);
325 ::SysFreeString(lineName
);
326 ::SysFreeString(lineDispName
);
329 //-----------------------------------------------------------------------------
330 // CExceptionReport::CreateExceptionRecordNode
335 CExceptionReport::CreateExceptionRecordNode(MSXML2::IXMLDOMDocument
* pDoc
,
336 EXCEPTION_RECORD
* pExceptionRecord
)
338 MSXML2::IXMLDOMNode
* pNode
= NULL
;
339 MSXML2::IXMLDOMElement
* pElement
= NULL
;
340 BSTR nodeName
= ::SysAllocString(L
"ExceptionRecord");
341 BSTR modName
= ::SysAllocString(L
"ModuleName");
342 BSTR codeName
= ::SysAllocString(L
"ExceptionCode");
343 BSTR descName
= ::SysAllocString(L
"ExceptionDescription");
344 BSTR addrName
= ::SysAllocString(L
"ExceptionAddress");
345 BSTR commandlineName
= ::SysAllocString(L
"CommandLine");
350 // Create exception record node
351 pNode
= CreateDOMNode(pDoc
, MSXML2::NODE_ELEMENT
, nodeName
);
353 // Get element interface
354 CHECKHR(pNode
->QueryInterface(MSXML2::IID_IXMLDOMElement
, (void**)&pElement
));
357 // Set module name attribute
360 V_BSTR(&v
) = CUtility::AllocSysString(m_sModule
);
361 pElement
->setAttribute(modName
, v
);
363 SysFreeString(V_BSTR(&v
));
366 // Set command line name attribute
369 V_BSTR(&v
) = CUtility::AllocSysString(m_sCommandLine
);
370 pElement
->setAttribute(commandlineName
, v
);
372 SysFreeString(V_BSTR(&v
));
375 // Set exception code
377 TCHAR buf
[MAX_PATH
] = {0};
378 _tprintf_s(buf
, _T("%#x"), pExceptionRecord
->ExceptionCode
);
381 V_BSTR(&v
) = CUtility::AllocSysString(buf
);
382 pElement
->setAttribute(codeName
, v
);
384 SysFreeString(V_BSTR(&v
));
387 // Set exception description
390 switch (pExceptionRecord
->ExceptionCode
)
392 case EXCEPTION_ACCESS_VIOLATION
:
393 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_ACCESS_VIOLATION");
395 case EXCEPTION_DATATYPE_MISALIGNMENT
:
396 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_DATATYPE_MISALIGNMENT");
398 case EXCEPTION_BREAKPOINT
:
399 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_BREAKPOINT");
401 case EXCEPTION_SINGLE_STEP
:
402 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_SINGLE_STEP");
404 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED
:
405 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_ARRAY_BOUNDS_EXCEEDED");
407 case EXCEPTION_FLT_DENORMAL_OPERAND
:
408 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_FLT_DENORMAL_OPERAND");
410 case EXCEPTION_FLT_DIVIDE_BY_ZERO
:
411 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_FLT_DIVIDE_BY_ZERO");
413 case EXCEPTION_FLT_INEXACT_RESULT
:
414 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_FLT_INEXACT_RESULT");
416 case EXCEPTION_FLT_INVALID_OPERATION
:
417 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_FLT_INVALID_OPERATION");
419 case EXCEPTION_FLT_OVERFLOW
:
420 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_FLT_OVERFLOW");
422 case EXCEPTION_FLT_STACK_CHECK
:
423 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_FLT_STACK_CHECK");
425 case EXCEPTION_FLT_UNDERFLOW
:
426 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_FLT_UNDERFLOW");
428 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
429 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_INT_DIVIDE_BY_ZERO");
431 case EXCEPTION_INT_OVERFLOW
:
432 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_INT_OVERFLOW");
434 case EXCEPTION_PRIV_INSTRUCTION
:
435 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_PRIV_INSTRUCTION");
437 case EXCEPTION_IN_PAGE_ERROR
:
438 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_IN_PAGE_ERROR");
440 case EXCEPTION_ILLEGAL_INSTRUCTION
:
441 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_ILLEGAL_INSTRUCTION");
443 case EXCEPTION_NONCONTINUABLE_EXCEPTION
:
444 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_NONCONTINUABLE_EXCEPTION");
446 case EXCEPTION_STACK_OVERFLOW
:
447 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_STACK_OVERFLOW");
449 case EXCEPTION_INVALID_DISPOSITION
:
450 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_INVALID_DISPOSITION");
452 case EXCEPTION_GUARD_PAGE
:
453 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_GUARD_PAGE");
455 case EXCEPTION_INVALID_HANDLE
:
456 V_BSTR(&v
) = ::SysAllocString(L
"EXCEPTION_INVALID_HANDLE");
459 V_BSTR(&v
) = L
"EXCEPTION_UNKNOWN";
462 pElement
->setAttribute(descName
, v
);
464 SysFreeString(V_BSTR(&v
));
467 // Set exception address
469 _tprintf_s(buf
, _T("%#x"), pExceptionRecord
->ExceptionAddress
);
472 V_BSTR(&v
) = CUtility::AllocSysString(buf
);
473 pElement
->setAttribute(addrName
, v
);
475 SysFreeString(V_BSTR(&v
));
477 // Try to include symbolic information
478 m_exception_element
= pElement
;
479 AddressToSymbol(reinterpret_cast<DWORD_PTR
>(pExceptionRecord
->ExceptionAddress
)-1,
480 CreateExceptionSymbolAttributes
,
481 reinterpret_cast<void *>(this));
483 ::SysFreeString(nodeName
);
484 ::SysFreeString(modName
);
485 ::SysFreeString(codeName
);
486 ::SysFreeString(addrName
);
487 SAFERELEASE(pElement
);
492 //-----------------------------------------------------------------------------
493 // CExceptionReport::CreateProcessorNode
498 CExceptionReport::CreateProcessorNode(MSXML2::IXMLDOMDocument
* pDoc
)
500 MSXML2::IXMLDOMNode
* pNode
= NULL
;
501 MSXML2::IXMLDOMElement
* pElement
= NULL
;
502 BSTR nodeName
= ::SysAllocString(L
"Processor");
503 BSTR archName
= ::SysAllocString(L
"Architecture");
504 BSTR levelName
= ::SysAllocString(L
"Level");
505 BSTR numberName
= ::SysAllocString(L
"NumberOfProcessors");
509 // Create exception record node
510 pNode
= CreateDOMNode(pDoc
, MSXML2::NODE_ELEMENT
, nodeName
);
512 // Get element interface
513 CHECKHR(pNode
->QueryInterface(MSXML2::IID_IXMLDOMElement
, (void**)&pElement
));
516 // Get processor info
524 switch (si
.wProcessorArchitecture
)
526 case PROCESSOR_ARCHITECTURE_INTEL
:
527 V_BSTR(&v
) = ::SysAllocString(L
"PROCESSOR_ARCHITECTURE_INTEL");
529 case PROCESSOR_ARCHITECTURE_MIPS
:
530 V_BSTR(&v
) = ::SysAllocString(L
"PROCESSOR_ARCHITECTURE_MIPS");
532 case PROCESSOR_ARCHITECTURE_ALPHA
:
533 V_BSTR(&v
) = ::SysAllocString(L
"PROCESSOR_ARCHITECTURE_ALPHA");
535 case PROCESSOR_ARCHITECTURE_PPC
:
536 V_BSTR(&v
) = ::SysAllocString(L
"PROCESSOR_ARCHITECTURE_PPC");
538 case PROCESSOR_ARCHITECTURE_SHX
:
539 V_BSTR(&v
) = ::SysAllocString(L
"PROCESSOR_ARCHITECTURE_SHX");
541 case PROCESSOR_ARCHITECTURE_ARM
:
542 V_BSTR(&v
) = ::SysAllocString(L
"PROCESSOR_ARCHITECTURE_ARM");
544 case PROCESSOR_ARCHITECTURE_IA64
:
545 V_BSTR(&v
) = ::SysAllocString(L
"PROCESSOR_ARCHITECTURE_IA64");
547 case PROCESSOR_ARCHITECTURE_ALPHA64
:
548 V_BSTR(&v
) = ::SysAllocString(L
"PROCESSOR_ARCHITECTURE_ALPHA64");
550 case PROCESSOR_ARCHITECTURE_AMD64
:
551 V_BSTR(&v
) = ::SysAllocString(L
"PROCESSOR_ARCHITECTURE_AMD64");
553 case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
:
554 V_BSTR(&v
) = ::SysAllocString(L
"PROCESSOR_ARCHITECTURE_IA32_ON_WIN64");
556 case PROCESSOR_ARCHITECTURE_UNKNOWN
:
557 V_BSTR(&v
) = ::SysAllocString(L
"PROCESSOR_ARCHITECTURE_UNKNOWN");
560 V_BSTR(&v
) = ::SysAllocString(L
"Unknown");
562 pElement
->setAttribute(archName
, v
);
564 SysFreeString(V_BSTR(&v
));
570 if (PROCESSOR_ARCHITECTURE_INTEL
== si
.wProcessorArchitecture
)
572 switch (si
.wProcessorLevel
)
575 V_BSTR(&v
) = ::SysAllocString(L
"Intel 30386");
578 V_BSTR(&v
) = ::SysAllocString(L
"Intel 80486");
581 V_BSTR(&v
) = ::SysAllocString(L
"Intel Pentium");
584 V_BSTR(&v
) = ::SysAllocString(L
"Intel Pentium Pro or Pentium II");
587 V_BSTR(&v
) = ::SysAllocString(L
"Unknown");
590 pElement
->setAttribute(levelName
, v
);
592 SysFreeString(V_BSTR(&v
));
595 // Set num of processors
598 V_I4(&v
) = si
.dwNumberOfProcessors
;
599 pElement
->setAttribute(numberName
, v
);
602 ::SysFreeString(nodeName
);
603 ::SysFreeString(archName
);
604 ::SysFreeString(levelName
);
605 ::SysFreeString(numberName
);
606 SAFERELEASE(pElement
);
611 //-----------------------------------------------------------------------------
612 // CExceptionReport::CreateOSNode
617 CExceptionReport::CreateOSNode(MSXML2::IXMLDOMDocument
* pDoc
)
619 MSXML2::IXMLDOMNode
* pNode
= NULL
;
620 MSXML2::IXMLDOMElement
* pElement
= NULL
;
621 BSTR nodeName
= ::SysAllocString(L
"OperatingSystem");
622 BSTR majorName
= ::SysAllocString(L
"MajorVersion");
623 BSTR minorName
= ::SysAllocString(L
"MinorVersion");
624 BSTR buildName
= ::SysAllocString(L
"BuildNumber");
625 BSTR csdName
= ::SysAllocString(L
"CSDVersion");
629 // Create exception record node
630 pNode
= CreateDOMNode(pDoc
, MSXML2::NODE_ELEMENT
, nodeName
);
632 // Get element interface
633 CHECKHR(pNode
->QueryInterface(MSXML2::IID_IXMLDOMElement
, (void**)&pElement
));
638 oi
.dwOSVersionInfoSize
= sizeof(oi
);
645 V_I4(&v
) = oi
.dwMajorVersion
;
646 pElement
->setAttribute(majorName
, v
);
652 V_I4(&v
) = oi
.dwMinorVersion
;
653 pElement
->setAttribute(minorName
, v
);
659 V_I4(&v
) = oi
.dwBuildNumber
;
660 pElement
->setAttribute(buildName
, v
);
666 V_BSTR(&v
) = CUtility::AllocSysString(oi
.szCSDVersion
);
667 pElement
->setAttribute(csdName
, v
);
668 ::SysFreeString(V_BSTR(&v
));
671 ::SysFreeString(nodeName
);
672 ::SysFreeString(majorName
);
673 ::SysFreeString(minorName
);
674 ::SysFreeString(buildName
);
675 ::SysFreeString(csdName
);
676 SAFERELEASE(pElement
);
681 //-----------------------------------------------------------------------------
682 // CExceptionReport::CreateModulesNode
687 CExceptionReport::CreateModulesNode(MSXML2::IXMLDOMDocument
* pDoc
)
689 MSXML2::IXMLDOMNode
* pNode
= NULL
;
690 MSXML2::IXMLDOMNode
* pNode2
= NULL
;
691 MSXML2::IXMLDOMNode
* pNewNode
= NULL
;
692 MSXML2::IXMLDOMElement
* pElement
= NULL
;
693 MSXML2::IXMLDOMElement
* pElement2
= NULL
;
694 BSTR nodeName
= ::SysAllocString(L
"Modules");
695 BSTR nodeName2
= ::SysAllocString(L
"Module");
696 BSTR fullPath
= ::SysAllocString(L
"FullPath");
697 BSTR baseAddrName
= ::SysAllocString(L
"BaseAddress");
698 BSTR sizeName
= ::SysAllocString(L
"Size");
699 BSTR timeStampName
= ::SysAllocString(L
"TimeStamp");
700 BSTR fileVerName
= ::SysAllocString(L
"FileVersion");
701 BSTR prodVerName
= ::SysAllocString(L
"ProductVersion");
707 // Create modules node
708 pNode
= CreateDOMNode(pDoc
, MSXML2::NODE_ELEMENT
, nodeName
);
711 // Add module information (freeing storage as we go)
713 MINIDUMP_MODULE_CALLBACK item
;
714 std::vector
<MINIDUMP_MODULE_CALLBACK
>::iterator iter
;
715 for (iter
= m_modules
.begin(); iter
!= m_modules
.end(); iter
++)
718 // Create module node
719 pNode2
= CreateDOMNode(pDoc
, MSXML2::NODE_ELEMENT
, nodeName2
);
721 // Get element interface
722 CHECKHR(pNode2
->QueryInterface(MSXML2::IID_IXMLDOMElement
, (void**)&pElement
));
728 V_BSTR(&v
) = SysAllocString(item
.FullPath
);
729 pElement
->setAttribute(fullPath
, v
);
731 SysFreeString(V_BSTR(&v
));
736 TCHAR buf
[MAX_PATH
] = {0};
737 _tprintf_s(buf
, addressFormat
, item
.BaseOfImage
);
739 V_BSTR(&v
) = CUtility::AllocSysString(buf
);
740 pElement
->setAttribute(baseAddrName
, v
);
742 SysFreeString(V_BSTR(&v
));
747 _tprintf_s(buf
, sizeFormat
, item
.SizeOfImage
);
749 V_BSTR(&v
) = CUtility::AllocSysString(buf
);
750 pElement
->setAttribute(sizeName
, v
);
752 SysFreeString(V_BSTR(&v
));
757 FILETIME ft
= CUtility::getLastWriteFileTime(item
.FullPath
);
760 FileTimeToSystemTime(&ft
, &st
);
762 _tprintf_s(buf
, _T("%02u/%02u/%04u %02u:%02u:%02u"),
771 V_BSTR(&v
) = CUtility::AllocSysString(buf
);
772 pElement
->setAttribute(timeStampName
, v
);
774 SysFreeString(V_BSTR(&v
));
779 _tprintf_s(buf
,"%d.%d.%d.%d",
780 HIWORD(item
.VersionInfo
.dwFileVersionMS
),
781 LOWORD(item
.VersionInfo
.dwFileVersionMS
),
782 HIWORD(item
.VersionInfo
.dwFileVersionLS
),
783 LOWORD(item
.VersionInfo
.dwFileVersionLS
));
786 V_BSTR(&v
) = CUtility::AllocSysString(buf
);
787 pElement
->setAttribute(fileVerName
, v
);
789 SysFreeString(V_BSTR(&v
));
792 // Set product version
794 _tprintf_s(buf
, "%d.%d.%d.%d",
795 HIWORD(item
.VersionInfo
.dwProductVersionMS
),
796 LOWORD(item
.VersionInfo
.dwProductVersionMS
),
797 HIWORD(item
.VersionInfo
.dwProductVersionLS
),
798 LOWORD(item
.VersionInfo
.dwProductVersionLS
));
801 V_BSTR(&v
) = CUtility::AllocSysString(buf
);
802 pElement
->setAttribute(prodVerName
, v
);
804 SysFreeString(V_BSTR(&v
));
807 // Append module to modules
809 pNode
->appendChild(pNode2
, &pNewNode
);
810 // The XML Document should now own the node.
812 SAFERELEASE(pElement2
);
813 SAFERELEASE(pNewNode
);
821 ::SysFreeString(nodeName
);
822 ::SysFreeString(nodeName2
);
823 ::SysFreeString(fullPath
);
824 ::SysFreeString(baseAddrName
);
825 ::SysFreeString(sizeName
);
826 ::SysFreeString(timeStampName
);
827 ::SysFreeString(fileVerName
);
828 ::SysFreeString(prodVerName
);
830 SAFERELEASE(pNewNode
);
831 SAFERELEASE(pElement
);
832 SAFERELEASE(pElement2
);
837 //-----------------------------------------------------------------------------
840 // Builds the application-defined message node
842 MSXML2::IXMLDOMNode
*
843 CExceptionReport::CreateMsgNode(MSXML2::IXMLDOMDocument
* pDoc
, BSTR message
)
845 MSXML2::IXMLDOMNode
* pNode
= NULL
;
846 MSXML2::IXMLDOMElement
* pElement
= NULL
;
847 BSTR nodeName
= ::SysAllocString(L
"ApplicationDescription");
849 // Create CrashDescription record node
850 pNode
= CreateDOMNode(pDoc
, MSXML2::NODE_ELEMENT
, nodeName
);
852 // Get element interface
853 CHECKHR(pNode
->QueryInterface(MSXML2::IID_IXMLDOMElement
, (void**)&pElement
));
855 pElement
->put_text(message
);
858 ::SysFreeString(nodeName
);
859 SAFERELEASE(pElement
);
864 //-----------------------------------------------------------------------------
865 // CreateWalkbackEntryNode
867 // Create a single node in the stack walback
870 CExceptionReport::CreateWalkbackEntryNode(DWORD_PTR address
, const char *ImageName
,
871 const char *FunctionName
, DWORD_PTR functionDisp
,
872 const char *Filename
, DWORD LineNumber
, DWORD lineDisp
,
875 MSXML2::IXMLDOMNode
* pNode
= NULL
;
876 MSXML2::IXMLDOMElement
* pElement
= NULL
;
877 MSXML2::IXMLDOMNode
* pNewNode
= NULL
;
879 BSTR nodeName
= ::SysAllocString(L
"Frame");
880 BSTR frameName
= ::SysAllocString(L
"FrameNumber");
881 BSTR addrName
= ::SysAllocString(L
"ReturnAddress");
882 BSTR moduleName
= ::SysAllocString(L
"ModuleName");
883 BSTR funcName
= ::SysAllocString(L
"FunctionName");
884 BSTR funcDispName
= ::SysAllocString(L
"FunctionDisplacement");
885 BSTR fileName
= ::SysAllocString(L
"Filename");
886 BSTR lineName
= ::SysAllocString(L
"LineNumber");
887 BSTR lineDispName
= ::SysAllocString(L
"LineDisplacement");
888 CExceptionReport
*self
= reinterpret_cast<CExceptionReport
*>(data
);
890 // Create frame record node
891 pNode
= self
->CreateDOMNode(self
->m_stack_doc
, MSXML2::NODE_ELEMENT
, nodeName
);
893 // Get element interface
894 CHECKHR(pNode
->QueryInterface(MSXML2::IID_IXMLDOMElement
, (void**)&pElement
));
899 self
->m_frameNumber
++;
900 TCHAR buf
[MAX_PATH
] = {0};
901 _tprintf_s(buf
, _T("%d"), self
->m_frameNumber
);
904 V_BSTR(&v
) = CUtility::AllocSysString(buf
);
905 pElement
->setAttribute(frameName
, v
);
907 SysFreeString(V_BSTR(&v
));
909 _tprintf_s(buf
, offsetFormat
, address
);
911 V_BSTR(&v
) = CUtility::AllocSysString(buf
);
912 pElement
->setAttribute(addrName
, v
);
914 SysFreeString(V_BSTR(&v
));
916 if (ImageName
!= NULL
) {
918 V_BSTR(&v
) = CUtility::AllocSysString(ImageName
);
919 pElement
->setAttribute(moduleName
, v
);
921 SysFreeString(V_BSTR(&v
));
924 if (FunctionName
!= NULL
) {
926 V_BSTR(&v
) = CUtility::AllocSysString(FunctionName
);
927 pElement
->setAttribute(funcName
, v
);
929 SysFreeString(V_BSTR(&v
));
930 _tprintf_s(buf
, offsetFormat
, functionDisp
);
932 V_BSTR(&v
) = CUtility::AllocSysString(buf
);
933 pElement
->setAttribute(funcDispName
, v
);
935 SysFreeString(V_BSTR(&v
));
938 if (Filename
!= NULL
) {
940 V_BSTR(&v
) = CUtility::AllocSysString(Filename
);
941 pElement
->setAttribute(fileName
, v
);
943 SysFreeString(V_BSTR(&v
));
945 _tprintf_s(buf
, _T("%d"), LineNumber
);
947 V_BSTR(&v
) = CUtility::AllocSysString(buf
);
948 pElement
->setAttribute(lineName
, v
);
950 SysFreeString(V_BSTR(&v
));
952 _tprintf_s(buf
, offsetFormat
, lineDisp
);
954 V_BSTR(&v
) = CUtility::AllocSysString(buf
);
955 pElement
->setAttribute(lineDispName
, v
);
957 SysFreeString(V_BSTR(&v
));
959 // add to walkback element
961 self
->m_stack_element
->appendChild(pNode
, &pNewNode
);
962 SAFERELEASE(pNewNode
);
963 // The XML Document should now own the node.
966 SAFERELEASE(pElement
);
967 ::SysFreeString(nodeName
);
968 ::SysFreeString(frameName
);
969 ::SysFreeString(addrName
);
970 ::SysFreeString(moduleName
);
971 ::SysFreeString(funcName
);
972 ::SysFreeString(funcDispName
);
973 ::SysFreeString(fileName
);
974 ::SysFreeString(lineName
);
975 ::SysFreeString(lineDispName
);
978 //-----------------------------------------------------------------------------
979 // CreateWalkbackNode
981 // Builds the stack walkback list
983 MSXML2::IXMLDOMNode
*
984 CExceptionReport::CreateWalkbackNode(MSXML2::IXMLDOMDocument
* pDoc
, CONTEXT
*pContext
)
986 MSXML2::IXMLDOMNode
* pNode
= NULL
;
988 MSXML2::IXMLDOMElement
* pElement
= NULL
;
989 BSTR nodeName
= ::SysAllocString(L
"CallStack");
991 // Create CallStack record node
992 pNode
= CreateDOMNode(pDoc
, MSXML2::NODE_ELEMENT
, nodeName
);
994 // Get element interface
995 CHECKHR(pNode
->QueryInterface(MSXML2::IID_IXMLDOMElement
, (void**)&pElement
));
998 // set static variables for use by CreateWalkbackEntryNode
999 m_stack_element
= pElement
;
1002 // If no context is supplied, skip 1 frames:
1005 DoStackTrace(pContext
== NULL
? 1 : 0, 9999, CreateWalkbackEntryNode
, pContext
, this);
1008 ::SysFreeString(nodeName
);
1009 SAFERELEASE(pElement
);
1014 //-----------------------------------------------------------------------------
1015 // CExceptionReport::miniDumpCallback
1017 // Mini dump module callback. Hit once for each module processed by
1018 // MiniDumpWriteDump. Builds a linked list of all module names which is
1019 // eventually used to create the <modules> node in the XML log file.
1022 CExceptionReport::miniDumpCallback(PVOID data
,
1023 CONST PMINIDUMP_CALLBACK_INPUT CallbackInput
,
1024 PMINIDUMP_CALLBACK_OUTPUT
)
1026 CExceptionReport
*self
= reinterpret_cast<CExceptionReport
*>(data
);
1027 if (ModuleCallback
== CallbackInput
->CallbackType
)
1029 MINIDUMP_MODULE_CALLBACK item
;
1031 item
= CallbackInput
->Module
;
1032 item
.FullPath
= _wcsdup(CallbackInput
->Module
.FullPath
);
1033 self
->m_modules
.push_back(item
);