== Debugging a Delphi Application == == Using Memory Profiler == === Project Setup === # Project > Options > Compiler #* Code Generation: #** Optimization #** Stack Frames #* Debugging: #** Debug Information # Project > Options > Linker #* Include TD32 debug info #* Map File: Detailed # Build project (Project > Build All Projects). === AQTime === # Run AQTime and include project executable to debug (File > Open > choose the .exe file). # Select profiler to execute: Options > Profile Options (or from drop-down in toolbar). Use VCL > VCL Class Profiler. # Run executable with profiler (Project > Run). # Test and push the executable to try to break it. Once you are done with tests, simply quit the application. # Review memory leaks report in AQTime (it takes a few seconds to update after the tested application has exited). == Using Built-in Debugging Tools == === Using FastMM === # Download [[http://fastmm.sourceforge.net|FastMM (Fast Memory Manager)]], and [[http://jedqc.blogspot.com/2007/07/new-fastmm4-options-interface.html|FastMM Options Interface GUI]] # Open project in Delphi. # Install FastMM in your project and source code (see instructions distributed with FastMM package). # Set ''FullDebugMode'' in Project > Options > Directories/Conditionals > Conditional defines. # Build project (Project > Build All Projects). # Execute project as usual. A dialog will popup if there are any critical errors or memory leaks during run time. Example, in ''MyProject.dpr'': program MyProject; {$DEFINE FullDebugMode} // for software that needs debug reporting using FastMM4 uses FastMM4 {memory manager replacement (and mem leak detector)}, Forms, Windows, sysUtils, messages, Dialogs, Classes; begin OutputDebugString(pchar('DBGVIEWCLEAR')); // clear DebugView window (get from www.sysinternals.com) // register with FastMM4 some known memory leaks RegisterExpectedMemoryLeak(28 {21-28}, 1); // TCriticalSection x 1 RegisterExpectedMemoryLeak(44 {37-44}, 1); // TShellFolder x 1 RegisterExpectedMemoryLeak(60 {45-60}, 1); // TStringList x 1 FastMM4.ReportMemoryLeaksOnShutdown := DebugHook <> 0; // report leaks only when using debugger . . . project code here . . . end. In ''FastMM4Options.inc'', enable the following define statements: {$define UseOutputDebugString} {$define LogErrorsToFile} {$define LogMemoryLeakDetailToFile} {$define ClearLogFileOnStartup} {$define EnableMemoryLeakReporting} {$define HideExpectedLeaksRegisteredByPointer} {$define RequireDebuggerPresenceForLeakReporting} {$define RequireDebugInfoForLeakReporting} ==== References ==== * New Memory Manage in BDS 2006: http://dn.codegear.com/articles/33416 * JED's GUI: http://jedqc.blogspot.com/2007/07/new-fastmm4-options-interface.html === Using EventLog or DebugView === Create some debugging routines in ''DebugTools.pas'' (Pascal unit): //------------------------------------------------------------------------------ // Unit Name: DebugTools // Author: Siegwart Mayr // Date: 17-May-2006 // Purpose: Library with debugging routines. //------------------------------------------------------------------------------ unit DebugTools; interface Uses Windows, Forms; //------------------------------------------- // types //------------------------------------------- Type TOutlineNodeType = (ntEmpty, ntNode, ntLeaf); //------------------------------------------- // function prototypes //------------------------------------------- procedure DebugMsg(str: string; OutlineLevel: integer=0; NodeType: TOutlineNodeType=ntNode); procedure DebugStr(str: string); //------------------------------------------- // resource strings //------------------------------------------- ResourceString rsOutlineBullet = '+'; rsOutlineLeaf = '-'; rsOutlineEmpty = '|'; implementation //------------------------------------------------------------------------------ // description: Send the specified string to the Windows debugger environment, // so that it can be viewed with DbgViewer (http://www.sysinternals.com) // parameters : str: string, OutlineLevel: integer, NoteType: TOutlineNodeType // return : None //------------------------------------------------------------------------------ procedure DebugMsg(str: string; OutlineLevel: integer=0; NodeType: TOutlineNodeType=ntNode); {$ifdef FullDebugMode} var LevelSpacer: string; NodeSymbol: string; {$endif} begin {$ifdef FullDebugMode} case NodeType of ntEmpty: NodeSymbol := rsOutlineEmpty; ntNode: NodeSymbol := rsOutlineBullet + rsOutlineBullet; ntLeaf: NodeSymbol := rsOutlineBullet + rsOutlineLeaf; else NodeSymbol := rsOutlineBullet; end; case OutlineLevel of 1: begin LevelSpacer := StringOfChar(' ', 1) + NodeSymbol; end; 2: begin LevelSpacer := StringOfChar(' ', 2) + NodeSymbol; end; 3: begin LevelSpacer := StringOfChar(' ', 3) + NodeSymbol; end; else LevelSpacer := ''; end; OutputDebugString(pchar(LevelSpacer + ' ' + str)); {$endif} end; //------------------------------------------------------------------------------ // description: Simple debugging routine. // parameters : str: string // return : None //------------------------------------------------------------------------------ procedure DebugStr(str: string); begin //{$ifdef FullDebugMode} OutputDebugString(pchar(str)); //{$endif} end; end. # Include ''DebugTools'' in the ''Uses'' clause in the Delphi source code. # Insert ''DebugStr('My debug message here...')'' statements in the source code whenever something needs debugging. # Use one of these utilities to view debug messages as application is being executed: #* When application is run from Delphi's IDE: use Delphi's built-in Event Log (View > Debug Windows > Event Log (Ctrl-Alt-V)). #* When application is run by itself: use ''DbgView.exe'' utility (from http://www.sysinternals.com). Leave utility running while application is run as well.