/*------------------------------------------------------------------------------------------ Set the root directory for where things are located, which should be the directory where this file is located. ------------------------------------------------------------------------------------------*/ void SetTestDir() { if (g_strTestDir.Length()) return; // Set this only once! // Get the path to the template files. HKEY hk; if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\SIL\\FieldWorks"), 0, KEY_QUERY_VALUE, &hk) == ERROR_SUCCESS) { achar rgch[MAX_PATH]; DWORD cb = isizeof(rgch); DWORD dwT; if (::RegQueryValueEx(hk, _T("RootCodeDir"), NULL, &dwT, (BYTE *)rgch, &cb) == ERROR_SUCCESS) { Assert(dwT == REG_SZ); StrApp str(rgch); int ich = str.FindStrCI(_T("\\distfiles")); if (ich >= 0) str.Replace(ich, str.Length(), _T("")); ich = str.FindCh('\\', str.Length() - 1); if (ich >= 0) str.Replace(ich, str.Length(), _T("")); str.Append(_T("\\Src\\Cellar\\Test\\")); g_strTestDir.Assign(str); } RegCloseKey(hk); } if (!g_strTestDir.Length()) g_strTestDir.Assign("C:\\FW\\Src\\Cellar\\Test\\"); }
DEFINE_THIS_FILE #define gle (GetLastError()) #define lenof(a) (sizeof(a) / sizeof((a)[0])) #define MAXNAMELEN 1024 // max name length for found symbols #define IMGSYMLEN ( sizeof IMAGEHLP_SYMBOL ) #define TTBUFLEN 65536 // for a temp buffer /// Add the given string to Sta. If Sta is not empty, add a semi-colon first void AppendToStaWithSep(StrApp sta, const achar * pch) { if (sta.Length()) sta.Append(";"); sta.Append(pch); }
/*---------------------------------------------------------------------------------------------- Set the values for the dialog controls based on the style styi. @param vwsProj Union of the current Vernacular and Analysis encodings for the project. ----------------------------------------------------------------------------------------------*/ void FmtGenDlg::SetDialogValues(StyleInfo & styi, Vector<int> & vwsProj) { // During SetDialogValues we never need to handle loss of focus in the name control, // because if anything needed to be done about updating that, it was done during // GetDialogValues, which is always called before SetDialogValues. We need to suppress it // because during this call the current style index and the current value of the control // may not agree: the purpose of this method is to update the control from the new style. // The normal loss-of-focus code is trying to synchronize in the opposite direction, and // can cause problems, for example, when we are disabling the control. For example: // - Disabling the window causes it to lose focus if it previously had focus. // - There is a kill focus event that tries to make the contents of the box agree with // the name of the current style. // - when this method is called, the old style is still the current one, so if we // already changed the text in the box, we wind up trying to rename the old style // to the name of the 'provided' style and produce a name conflict error. try { m_vwsProj = vwsProj; StrApp strDesc; m_fSuppressLossOfFocus = true; StrApp strName = styi.m_stuName; StrApp strTemp; // Temporary string. bool fProtectedStyle = m_pafsd->IsStyleProtected(styi.m_stuName); // Name edit box. ::SetDlgItemText(m_hwnd, kctidFgEdName, strName.Chars()); // Diable the control for styles originally provided by FieldWorks. ::EnableWindow(m_hwndName, !fProtectedStyle); // Style type ltext. switch (styi.m_st) { case kstParagraph: strTemp.Load(kstidParagraph); break; case kstCharacter: strTemp.Load(kstidCharacter); break; default: Assert(false); // Should not happen. } ::SetWindowText(m_hwndType, strTemp.Chars()); // Update the "next" and "basedOn" comboboxes LoadNextStyleCombobox(styi); SetNextStyleComboboxValue(styi); LoadBasedOnStyleCombobox(styi); SetBasedOnStyleComboboxValue(styi); // ENHANCE LarryW(JohnT): When shortcut is implemented initialize the value instead. ::EnableWindow(m_hwndShortcut, false); // Disables it. // ************************************** m_vesi.Clear(); strDesc = m_pafsd->GetNameOfStyle(styi.m_hvoBasedOn); strDesc.Append(" + "); ITsTextProps * pttp = styi.m_qttp; if (pttp) { StrApp strT; StrAppBuf strb; // a temp, used for making strings with units // Add default font info bool fFirstPart = true; SmartBstr sbstr; CheckHr(pttp->GetStrPropValue(ktptFontFamily, &sbstr)); StrUni stuFont(sbstr.Chars()); AppendDescPart(strDesc, FwStyledText::FontStringMarkupToUi(false, stuFont), fFirstPart); int val, var; CheckHr(pttp->GetIntPropValues(ktptFontSize, &var, &val)); if (var != -1) { AfUtil::MakeMsrStr (val , knpt, &strb); AppendDescPart(strDesc, strb, fFirstPart); } CheckHr(pttp->GetIntPropValues(ktptBold, &var, &val)); if (val == kttvForceOn || val == kttvInvert) AppendDescPart(strDesc, kstidBold, fFirstPart); CheckHr(pttp->GetIntPropValues(ktptItalic, &var, &val)); if (val == kttvForceOn || val == kttvInvert) AppendDescPart(strDesc, kstidItalic, fFirstPart); CheckHr(pttp->GetIntPropValues(ktptSuperscript, &var, &val)); if (val == kssvSuper) AppendDescPart(strDesc, kstidFfdSuperscript, fFirstPart); else if (val == kssvSub) AppendDescPart(strDesc, kstidFfdSubscript, fFirstPart); AppendTextIs(strDesc, (COLORREF)ReadValOrNinch(pttp, ktptForeColor), (COLORREF)ReadValOrNinch(pttp, ktptBackColor), fFirstPart); AppendUnderlineInfo(strDesc, (COLORREF)ReadValOrNinch(pttp, ktptUnderColor), ReadValOrNinch(pttp, ktptUnderline), fFirstPart); AppendOffsetInfo(strDesc, ReadValOrNinch(pttp, ktptOffset), fFirstPart); // Add info about other tabs int nDir = ReadValOrNinch(pttp, ktptRightToLeft); AddIf(strDesc, nDir == 0, kstidLeftToRight, fFirstPart); AddIf(strDesc, nDir == 1, kstidRightToLeft, fFirstPart); static const Keyval rgkeyvals[] = { {ktalLeading, kstidFpAlignLead}, {ktalLeft, kstidFpAlignLeft}, {ktalCenter, kstidFpAlignCenter}, {ktalRight, kstidFpAlignRight}, {ktalTrailing, kstidFpAlignTrail}, {ktalJustify, kstidFpAlignJustify}, //TODO: support when in use. {0, 0} }; AddFromList(strDesc, ReadValOrNinch(pttp, ktptAlign), rgkeyvals, fFirstPart); int nLeadIndent = ReadValOrNinch(pttp, ktptLeadingIndent); int nTrailIndent = ReadValOrNinch(pttp, ktptTrailingIndent); int nFirstIndent = ReadValOrNinch(pttp, ktptFirstIndent); if (nLeadIndent != knNinch || nTrailIndent != knNinch || nFirstIndent != knNinch) { AppendDescPart(strDesc, kstidIndentColon, fFirstPart); AppendMeasurement(strDesc, nLeadIndent, m_nMsrSys, kstidLeadingFmt); if (nFirstIndent != knNinch) { if (nFirstIndent < 0) AppendMeasurement(strDesc, -nFirstIndent, m_nMsrSys, kstidHangingFmt); else AppendMeasurement(strDesc, nFirstIndent, m_nMsrSys, kstidFirstLineFmt); } AppendMeasurement(strDesc, nTrailIndent, m_nMsrSys, kstidTrailingFmt); } // line spacing CheckHr(pttp->GetIntPropValues(ktptLineHeight, &var, &val)); StrApp strSpacing; StrApp strFmt; if (var == ktpvMilliPoint) { if (val < 0) strFmt.Load(kstidFpLsExactFmt); else strFmt.Load(kstidFpLsAtLeastFmt); StrAppBuf strb; AfUtil::MakeMsrStr (val , knpt, &strb); strSpacing.Format(strFmt.Chars(), strb.Chars()); } else if (var == ktpvRelative) { if (val >= kdenTextPropRel * 2) strSpacing.Load(kstidFpLsDouble); else if (val >= kdenTextPropRel * 3 / 2) strSpacing.Load(kstidFpLs15Lines); else strSpacing.Load(kstidFpLsSingle); } if (strSpacing.Length() != 0) { strFmt.Load(kstidLineSpacingFmt); strT.Format(strFmt.Chars(), strSpacing.Chars()); AppendDescPart(strDesc, strT, fFirstPart); } int mpBefore = ReadValOrNinch(pttp, ktptSpaceBefore); int mpAfter = ReadValOrNinch(pttp, ktptSpaceAfter); if (mpBefore != knNinch || mpAfter != knNinch) { AppendDescPart(strDesc, kstidSpace, fFirstPart); AppendMeasurement(strDesc, mpBefore, knpt, kstidBeforeFmt); AppendMeasurement(strDesc, mpAfter, knpt, kstidAfterFmt); } int bulnum = ReadValOrNinch(pttp, ktptBulNumScheme); AddIf(strDesc, bulnum >= kvbnBulletBase && bulnum < kvbnBulletMax, kstidBulleted, fFirstPart); AddIf(strDesc, bulnum >= kvbnNumberBase && bulnum < kvbnNumberMax, kstidNumbered, fFirstPart); int mpBTop = ReadValOrNinch(pttp, ktptBorderTop); int mpBB = ReadValOrNinch(pttp, ktptBorderBottom); int mpBL = ReadValOrNinch(pttp, ktptBorderLeading); int mpBTr = ReadValOrNinch(pttp, ktptBorderTrailing); if (mpBTop != knNinch || mpBB != knNinch || mpBL != knNinch || mpBTr != knNinch) { AppendDescPart(strDesc, kstidBorderColon, fFirstPart); int clrBorder = ReadValOrNinch(pttp, ktptBorderColor); bool fFirstBorder = true; if (clrBorder != knNinch) { StrApp strClr; strClr.Load(g_ct.GetColorRid(g_ct.GetIndexFromColor(clrBorder))); strDesc.Append(strClr.Chars()); fFirstBorder = false; } AppendBorderInfo(strDesc, mpBTop, kstidTopBdrFmt, fFirstBorder); AppendBorderInfo(strDesc, mpBB, kstidBottomBdrFmt, fFirstBorder); AppendBorderInfo(strDesc, mpBL, kstidLeadingBdrFmt, fFirstBorder); AppendBorderInfo(strDesc, mpBTr, kstidTrailingBdrFmt, fFirstBorder); } // Add info about writing-system overrides of font info. Vector<int> vwsSoFar; // Get the appropropriate writing system factory. ILgWritingSystemFactoryPtr qwsf; AssertPtr(m_pafsd); m_pafsd->GetLgWritingSystemFactory(&qwsf); AssertPtr(qwsf); //- IWritingSystemPtr qws; // Each iteration of this loop processes information about one writing system. SmartBstr sbstrCharStyles; CheckHr(pttp->GetStrPropValue(kspWsStyle, &sbstrCharStyles)); if (sbstrCharStyles.Length()) { FwStyledText::DecodeFontPropsString(sbstrCharStyles, m_vesi, vwsSoFar); SmartBstr sbstrWs; StrApp strWs; int wsUser; CheckHr(qwsf->get_UserWs(&wsUser)); SmartBstr sbstrAbbr; for (int iesi = 0; iesi < m_vesi.Size(); iesi++) { WsStyleInfo & esi = m_vesi[iesi]; if (vwsSoFar[iesi] == 0) continue; // Ignore writing system set to 0. fFirstPart = true; StrApp strT; StrApp strT2; strT.Format(_T("\n")); // Use the abbreviation in the user ws if it exists. // else try for an abbreviation in each ws in m_vwsProj in turn, // else use the ICU locale name as a last resort. IWritingSystemPtr qws; CheckHr(qwsf->GetStrFromWs(vwsSoFar[iesi], &sbstrWs)); CheckHr(qwsf->get_Engine(sbstrWs, &qws)); CheckHr(qws->get_Abbr(wsUser, &sbstrAbbr)); if (sbstrAbbr.Length() == 0) { for (int iws = 0; iws < m_vwsProj.Size(); ++iws) { CheckHr(qws->get_Abbr(m_vwsProj[iws], &sbstrAbbr)); if (sbstrAbbr.Length() != 0) break; } } if (sbstrAbbr.Length() == 0) strWs.Assign(sbstrWs.Chars(), sbstrWs.Length()); else strWs.Assign(sbstrAbbr.Chars(), sbstrAbbr.Length()); strT2.Format(_T("%s: "), strWs.Chars()); if (strT2 == _T("___: ")) strT2.Load(kctidFgUnknown); strT.Append(strT2); strDesc.Append (strT); AppendDescPart(strDesc, FwStyledText::FontStringMarkupToUi(false, esi.m_stuFontFamily), fFirstPart); if (esi.m_mpSize != knNinch) { AfUtil::MakeMsrStr (esi.m_mpSize , knpt, &strb); AppendDescPart(strDesc, strb, fFirstPart); } if (esi.m_fBold == kttvForceOn || esi.m_fBold == kttvInvert) AppendDescPart(strDesc, kstidBold, fFirstPart); if (esi.m_fItalic == kttvForceOn || esi.m_fItalic == kttvInvert) AppendDescPart(strDesc, kstidItalic, fFirstPart); if (esi.m_ssv == kssvSuper) AppendDescPart(strDesc, kstidFfdSuperscript, fFirstPart); else if (esi.m_ssv == kssvSub) AppendDescPart(strDesc, kstidFfdSubscript, fFirstPart); AppendTextIs(strDesc, esi.m_clrFore, esi.m_clrBack, fFirstPart); AppendUnderlineInfo(strDesc, esi.m_clrUnder, esi.m_unt, fFirstPart); AppendOffsetInfo(strDesc, esi.m_mpOffset, fFirstPart); } // 'for' loop } } ::SetDlgItemText(m_hwnd, kctidFgDescription, strDesc.Chars()); // ************************************** } catch(...) { m_fSuppressLossOfFocus = false; throw; } m_fSuppressLossOfFocus = false; } //:> FmtGenDlg::SetDialogValues.
/*---------------------------------------------------------------------------------------------- Get the final values for the dialog controls, after the dialog has been closed. ----------------------------------------------------------------------------------------------*/ void FmtGenDlg::GetDialogValues(StyleInfo & styi, bool & fBasedOnChanged) { StrUni stuName = GetName(); StrApp strName = stuName; achar rgcha[1024]; Vector<achar> vch; achar * pszT; memcpy(rgcha, strName.Chars(), strName.Length() * isizeof(achar)); if (stuName != styi.m_stuName) { StrApp strOldName(styi.m_stuName); StrApp strNewName(stuName); if (!m_pafsd->SetName(styi, stuName)) { // Error: restore the old name. ::SetDlgItemText(m_hwnd, kctidFgEdName, strOldName.Chars()); } // Otherwise update the comboboxes for BasedOn and Next. // This allows the later code which reads from them to work correctly, // so it is worth doing even here in a read routine. // Also update the edit box to handle stripping of leading/trailing blanks. else { ::SetDlgItemText(m_hwnd, kctidFgEdName, strNewName.Chars()); UpdateComboboxes(strOldName, strNewName); } } int iitem = ::SendMessage(m_hwndBasedOn, CB_GETCURSEL, 0,0); // <0 means the item is blank (e.g., Normal is not based on anything). // But if we pass -1 to CB_GETLBTEXT, we get the text of the first item. // This can change Normal to be based on Normal, with bad consequences. // if (iitem < 0) { pszT = _T(""); } else { int cch = ::SendMessage(m_hwndBasedOn, CB_GETLBTEXTLEN, (WPARAM)iitem, 0); if (cch < 1024) { pszT = rgcha; } else { vch.Resize(cch + 1); pszT = vch.Begin(); } cch = ::SendMessage(m_hwndBasedOn, CB_GETLBTEXT, iitem, (long)pszT); if (cch < 0) pszT = _T(""); } stuName = pszT; HVO hvoBasedOn = m_pafsd->GetHvoOfStyleNamed(stuName); if (styi.m_hvoBasedOn != hvoBasedOn) { m_pafsd->SetBasedOn(styi, hvoBasedOn); // Sets m_fDirty. // Note that this is initialised to false in AfStylesDlg::UpdateTabCtrl. fBasedOnChanged = true; } iitem = ::SendMessage(m_hwndNext, CB_GETCURSEL, 0,0); if (iitem < 0) { pszT = _T(""); } else { int cch = ::SendMessage(m_hwndNext, CB_GETLBTEXTLEN, (WPARAM)iitem, 0); if (cch < 1024) { pszT = rgcha; } else { vch.Resize(cch + 1); pszT = vch.Begin(); } cch = ::SendMessage(m_hwndNext, CB_GETLBTEXT, iitem, (long)pszT); if (cch < 0) pszT = _T(""); } stuName = pszT; HVO hvoNext = m_pafsd->GetHvoOfStyleNamed(stuName); if ((styi.m_hvoNext != hvoNext) && (styi.m_st != kstCharacter)) { m_pafsd->SetNext(styi, hvoNext); // Sets m_fDirty. } } //:> FmtGenDlg::GetDialogValues.
void StackDumper::ShowStackCore( HANDLE hThread, CONTEXT& c ) { // This makes this code custom for 32-bit windows. There is a technique to find out what // machine type we are running on, but this should do us for a good while. DWORD imageType = IMAGE_FILE_MACHINE_I386; HANDLE hProcess = GetCurrentProcess(); int frameNum; // counts walked frames DWORD offsetFromSymbol; // tells us how far from the symbol we were DWORD symOptions; // symbol handler settings IMAGEHLP_SYMBOL *pSym = (IMAGEHLP_SYMBOL *) malloc( IMGSYMLEN + MAXNAMELEN ); IMAGEHLP_MODULE Module; IMAGEHLP_LINE Line; StrApp strSearchPath; // path to search for symbol tables (I think...JT) achar *tt = 0; STACKFRAME s; // in/out stackframe memset( &s, '\0', sizeof s ); tt = new achar[TTBUFLEN]; if (!tt) return; // Build symbol search path. // Add current directory if (::GetCurrentDirectory( TTBUFLEN, tt ) ) AppendToStaWithSep(strSearchPath, tt); // Add directory containing executable or DLL we are running in. if (::GetModuleFileName( 0, tt, TTBUFLEN ) ) { StrUni stuPath = tt; // convert to Unicode if necessary, allows use of wchars const OLECHAR * pchPath = stuPath.Chars(); const OLECHAR * pch; for (pch = pchPath + wcslen(pchPath) - 1; pch >= pchPath; -- pch ) { // locate the rightmost path separator if ( *pch == L'\\' || *pch == L'/' || *pch == L':' ) break; } // if we found one, p is pointing at it; if not, tt only contains // an exe name (no path), and p points before its first byte if ( pch != pchPath ) // path sep found? { if ( *pch == L':' ) // we leave colons in place ++ pch; if (strSearchPath.Length()) strSearchPath.Append(";"); strSearchPath.Append(pchPath, (pch - pchPath)); } } // environment variable _NT_SYMBOL_PATH if (::GetEnvironmentVariable( _T("_NT_SYMBOL_PATH"), tt, TTBUFLEN )) AppendToStaWithSep(strSearchPath, tt); // environment variable _NT_ALTERNATE_SYMBOL_PATH if (::GetEnvironmentVariable( _T("_NT_ALTERNATE_SYMBOL_PATH"), tt, TTBUFLEN )) AppendToStaWithSep(strSearchPath, tt); // environment variable SYSTEMROOT if (::GetEnvironmentVariable( _T("SYSTEMROOT"), tt, TTBUFLEN )) AppendToStaWithSep(strSearchPath, tt); // Why oh why does SymInitialize() want a writeable string? Surely it doesn't modify it... // The doc clearly says it is an [in] parameter. // Also, there is not a wide character version of this function! StrAnsi staT(strSearchPath); if ( !::SymInitialize( hProcess, const_cast<char *>(staT.Chars()), false ) ) goto LCleanup; // SymGetOptions() symOptions = SymGetOptions(); symOptions |= SYMOPT_LOAD_LINES; symOptions &= ~SYMOPT_UNDNAME; SymSetOptions( symOptions ); // SymSetOptions() // Enumerate modules and tell imagehlp.dll about them. // On NT, this is not necessary, but it won't hurt. EnumAndLoadModuleSymbols( hProcess, GetCurrentProcessId() ); // init STACKFRAME for first call // Notes: AddrModeFlat is just an assumption. I hate VDM debugging. // Notes: will have to be #ifdef-ed for Alphas; MIPSes are dead anyway, // and good riddance. s.AddrPC.Offset = c.Eip; s.AddrPC.Mode = AddrModeFlat; s.AddrFrame.Offset = c.Ebp; s.AddrFrame.Mode = AddrModeFlat; memset( pSym, '\0', IMGSYMLEN + MAXNAMELEN ); pSym->SizeOfStruct = IMGSYMLEN; pSym->MaxNameLength = MAXNAMELEN; memset( &Line, '\0', sizeof Line ); Line.SizeOfStruct = sizeof Line; memset( &Module, '\0', sizeof Module ); Module.SizeOfStruct = sizeof Module; offsetFromSymbol = 0; if (!m_pstaDump) { try { m_pstaDump = NewObj StrAnsiBufHuge; } catch (...) { goto LCleanup; } } // If the stack dump gets too big, we remove some entries from near the // middle, and insert a marker. This counts the characters up to the // end of the marker. int ichEndLowHalf; ichEndLowHalf = 0; m_pstaDump->FormatAppend( "\r\n--# FV EIP----- RetAddr- FramePtr StackPtr Symbol\r\n" ); // EberhardB: a stack of 1.000 frames should be enough in most cases; limiting it // prevents a mysterious infinite(?) loop on our build machine. for ( frameNum = 0; frameNum < 1000; ++ frameNum ) { // get next stack frame (StackWalk(), SymFunctionTableAccess(), SymGetModuleBase()) // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can // assume that either you are done, or that the stack is so hosed that the next // deeper frame could not be found. if ( ! StackWalk( imageType, hProcess, hThread, &s, &c, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL ) ) break; // display its contents m_pstaDump->FormatAppend( "%3d %c%c %08x %08x %08x %08x ", frameNum, s.Far? 'F': '.', s.Virtual? 'V': '.', s.AddrPC.Offset, s.AddrReturn.Offset, s.AddrFrame.Offset, s.AddrStack.Offset ); if ( s.AddrPC.Offset == 0 ) { m_pstaDump->Append( "(-nosymbols- PC == 0)\r\n" ); } else { // we seem to have a valid PC char undName[MAXNAMELEN]; // undecorated name //char undFullName[MAXNAMELEN]; // undecorated name with all shenanigans // show procedure info (SymGetSymFromAddr()) if ( ! SymGetSymFromAddr( hProcess, s.AddrPC.Offset, &offsetFromSymbol, pSym ) ) { if ( gle != 487 ) m_pstaDump->FormatAppend( "SymGetSymFromAddr(): gle = %u\r\n", gle ); } else { UnDecorateSymbolName( pSym->Name, undName, MAXNAMELEN, UNDNAME_NAME_ONLY ); //UnDecorateSymbolName( pSym->Name, undFullName, MAXNAMELEN, UNDNAME_COMPLETE ); m_pstaDump->Append( undName ); //if ( offsetFromSymbol != 0 ) // m_pstaDump->FormatAppend( " %+d bytes", offsetFromSymbol ); //m_pstaDump->FormatAppend( "\r\n Sig: %s\r\n", pSym->Name ); //m_pstaDump->FormatAppend( "\r\n Decl: %s\r\n", undFullName ); } // show line number info, NT5.0-method (SymGetLineFromAddr()). If we can't get this function, // or it doesn't work, leave out line number info. if (! g_pfnSymGetLineFromAddr) { StrApp staModName("IMAGEHLP.DLL"); g_pfnSymGetLineFromAddr = (PFNSYMGETLINEFROMADDR) GetProcAddress( GetModuleHandle(staModName.Chars()), "SymGetLineFromAddr"); } if (! g_pfnSymGetLineFromAddr || ! g_pfnSymGetLineFromAddr( hProcess, s.AddrPC.Offset, &offsetFromSymbol, &Line ) ) { if ( g_pfnSymGetLineFromAddr && gle != 487 ) // apparently a magic number indicating not in symbol file. m_pstaDump->FormatAppend( "SymGetLineFromAddr(): gle = %u\r\n", gle ); else m_pstaDump->FormatAppend( " (no line # avail)\r\n"); } else { m_pstaDump->FormatAppend( " %s(%u)\r\n", Line.FileName, Line.LineNumber ); } #ifdef JT_20010626_WantModuleInfo // If we want this info adapt the printf and _snprintf in the following. // show module info (SymGetModuleInfo()) if ( ! SymGetModuleInfo( hProcess, s.AddrPC.Offset, &Module ) ) { m_pstaDump->FormatAppend( "SymGetModuleInfo): gle = %u\r\n", gle ); } else { // got module info OK m_pstaDump->FormatAppend( " Mod: %s[%s], base: 0x%x\r\n Sym: type: ", Module.ModuleName, Module.ImageName, Module.BaseOfImage ); switch ( Module.SymType ) { case SymNone: m_pstaDump->FormatAppend( "-nosymbols-"); break; case SymCoff: m_pstaDump->FormatAppend( "COFF"); break; case SymCv: m_pstaDump->FormatAppend( "CV"); break; case SymPdb: m_pstaDump->FormatAppend( "PDB"); break; case SymExport: m_pstaDump->FormatAppend( "-exported-"); break; case SymDeferred: m_pstaDump->FormatAppend( "-deferred-"); break; case SymSym: m_pstaDump->FormatAppend( "SYM"); break; default: m_pstaDump->FormatAppend( "symtype=%d", (long) Module.SymType); break; } m_pstaDump->FormatAppend( ", file: %s\r\n", Module.LoadedImageName); } // got module info OK #endif // JT_20010626_WantModuleInfo // We don't want to return more than about 10K of info (enough for an email). // This also serves to make sure there's enough room in the buffer for more. // The idea is that we'd like to keep both the top and bottom of the stack. // So we delete frames from the middle until we have less than 10K. if (m_pstaDump->Length() > MAXDUMPLEN) { if (!ichEndLowHalf) { static char * pszGap = "\r\n\r\n\r\n******************Frames skipped here***************\r\n\r\n\r\n"; int cchGap = strlen(pszGap); ichEndLowHalf = FindStartOfFrame(MAXDUMPLEN / 2); // Overwrite some of what's there with the gap marker. The incomplete // frame will be part of what gets deleted. m_pstaDump->Replace(ichEndLowHalf, ichEndLowHalf + cchGap, pszGap, cchGap); ichEndLowHalf += cchGap; } int cchLeave = m_pstaDump->Length(); int ichKeep = ichEndLowHalf; while (cchLeave > MAXDUMPLEN) { int ichKeepT = FindStartOfFrame(ichKeep + 1); cchLeave -= ichKeepT - ichKeep; ichKeep = ichKeepT; } m_pstaDump->Replace(ichEndLowHalf, ichKeep, (char *)NULL, 0); } } // we seem to have a valid PC // no return address means no deeper stackframe if ( s.AddrReturn.Offset == 0 ) { // avoid misunderstandings in the printf() following the loop SetLastError( 0 ); break; } } // for ( frameNum ) if ( gle != 0 ) printf( "\r\nStackWalk(): gle = %u\r\n", gle ); LCleanup: ResumeThread( hThread ); // de-init symbol handler etc. SymCleanup( hProcess ); free( pSym ); delete [] tt; #ifdef DEBUG ::OutputDebugStringA(m_pstaDump->Chars()); #endif }