delphi tips & techniques brian long ([email protected]) master consultant falafel software
TRANSCRIPT
Before We Begin
Hours: 8:00 – 12:00
Break Time: 10:00 – 10:30
Please ask questions as we go along
Let’s keep this informal
The IDEToolbars
The Editor
The Form Designers
The Object Inspector
Miscellaneous
Enhancing from within
Undocumented registry entries
ToolbarsSave mouse-clicks with the File | Open
toolbutton’s drop down menu
Less need to switch to the Project Manager with the Run | Run tool button’s drop down button
Avoid unneeded debugging with Run | No Debug
Restore corrupted toolbars
Move toolbars between systems
The EditorCode Insight et al
Code Folding
Refactoring
Help Insight
Error Insight
Editor bookmarks
Keyboard macros
Case switching
Buffer list
Block marking
Block indent / unindent
Block operations
Bracket matching
Various selection / deletion operations
Incremental search
Drag & drop
The EditorAn overwhelming number of keyboard shortcuts availableIn Delphi 7 help under “shortcuts”In Delphi 8/“Diamondback” help via Reference | Keyboard
MappingsMany based on the ancient WordStar word processor
keyboard shortcutsMany were present in Turbo Pascal & Borland PascalCtrl+Q+? is a Quick operationCtrl+K+? is a blocK operationCtrl+O+? is an Other operationMore recent additions just fill in any available gaps
The EditorCode Insight – Code Completion
– Manually invoked by Ctrl+Space– Supports being alpha-sorted– Supports being resized– Supports automatically adding units into the uses
clause:HKCU\...\7.0\Code Insight\ExtraUnits(feature removed in Delphi 8, replaced in Delphi “Diamondback” with new option:Refactor | Find Unit)
The EditorCode Insight – Code Parameters
– Manually invoked with Ctrl+Shift+Space
Code Insight – Code Templates
– Manually invoked with Ctrl+J– Stored in the text file delphi32.dci / bds.dci
The EditorCode browsing
– Ctrl+click on an identifier– context menu, Find declaration– Navigation buttons: Alt+← & Alt+→
Module navigation– Ctrl+Shift+↓ or Ctrl+Shift+↑
Class completion– Ctrl+Shift+C– Good property implementation
The EditorCode Folding
– Ctrl+Shift+K+G Fold interface and implementation– Ctrl+Shift+K+E Fold | Nearest– Ctrl+Shift+K+N Fold | Namespace (Unit)– Ctrl+Shift+K+C Fold | Types– Ctrl+Shift+K+M Fold | Methods– Ctrl+Shift+K+R Fold | Regions– Ctrl+Shift+K+P Fold | Nested Methods– Ctrl+Shift+K+U Unfold | Nearest– Ctrl+Shift+K+A Unfold | All– Ctrl+Shift+K+O Toggle code folding
The EditorRefactoring
– Ctrl+Shift+V Declare Variable– Ctrl+Shift+D Declare Field– Ctrl+Shift+M Extract Method– Ctrl+Shift+L Extract Resource String– Ctrl+Shift+A Find Unit– Ctrl+Shift+E Rename– Ctrl+Shift+J Sync Edit
The EditorHelp Insight
– Enabled by default– Ctrl+Shift+H– Works with Code Completion window
Error Insight
– Enabled by default
– Symbol existence verification
The EditorBookmarks
– Toggle: Ctrl+Shift+n or Ctrl+K+n– Go to: Ctrl+n or Ctrl+Q+n (n = 0, 1, 2, ..., 9)
– Not persisted in project desktops
– Alternative is to use disabled breakpoints, which are persisted
– Use the Breakpoints window to navigate (View | Debug Windows | Breakpoints)
The EditorKeyboard macros:
– Start/stop recording: Ctrl+Shift+R– Playback: Ctrl+Shift+P– Limited to editor keystrokes only– Macro toolbar (added officially in Delphi 8,
unofficially in Delphi 7)
The EditorCase-switching:
– Upper case: Ctrl+K+N– Lower case: Ctrl+K+O– Toggle case: Ctrl+O+U
Buffer list:– Ctrl+B– Implemented in Win32 DclSmpEdit70.dpk
ToolsAPI package demo
The EditorBlock marking
– Shift+navigation keys• Non-inclusive: Ctrl+O+K (default)• Inclusive: Ctrl+O+I• Line: Ctrl+O+L• Column: Ctrl+O+C
– Alt+Shift+navigation keys or Alt+mouse• Column block marking
The Editor
Block operations
– Toggle comment: Ctrl+/– Write to text file: Ctrl+K+W– Read from text file: Ctrl+K+R– Print: Ctrl+K+P
The EditorBracket matching (almost obsolete in Delphi 8+)
– Alt+[– Alt+]– Ctrl+Q+[– Ctrl+Q+]– Matches {,} and (,)– Does not match begin,end
The EditorSelecting the current word
– Ctrl+K+T
Deleting to the next word– Ctrl+T
Deleting to the end of the line– Ctrl+Shift+Y, Ctrl+Q+Y
Deleting the current line– Ctrl+Y
The EditorSelecting the current line
– Ctrl+K+L
Selecting lines– Home, Shift+↑ or Shift+↓
Incremental search– Ctrl+Shift+S (or Ctrl+E in Classic)
The EditorDrag & drop
– Dragging text moves it– Ctrl+dragging text copies it
– Same functionality as Microsoft Word
– Preserves clipboard content
The Form DesignersSelecting a component’s parent
– EscapeSelecting the form
– VCL: Select a component, then Shift+click it– WinForms: Click form caption bar
Lassoing on a container– VCL: Ctrl+drag mouse– WinForms: drag the mouse
The Form DesignersMoving & sizing components:
VCL designer WinForms designer
Move by one grid unit
Ctrl+Shift+cursor keys or drag component
Cursor keys or drag component
Move by one pixel Ctrl+cursor keys or Alt+drag component
Ctrl+cursor keys
Resize by one grid unit
Drag grab handle Shift+cursor keys or drag grab handle
Resize by one pixel Shift+cursor keys or Alt+drag grab handle
Ctrl+Shift+cursor keys
The Object InspectorProperty editor keyboard access
– Ctrl+Enter
Incremental property search– Tab
Instance list– Ctrl+↓
Following linked components (VCL-only)– Ctrl+double-click
MiscellaneousDrag & drop RAD now works (kinda)!MPD keyboard shortcuts
– Ctrl+Tab and Shift+Ctrl+TabIDE memory consumption
– IDE command line switches –hm and -hvPreventing docking
– Hold down Ctrl– Use the environment option
Enhancing from withinImplement a Win32 package
In Register procedure use e.g.:– Application– Application.MainForm– Application.FindComponent
Modify aspects of IDE as you choose
Tidy up in the finalization section
Use ToolsAPI for official route
Undocumented registryAll relative to HKCU\Software\Borland\
Removing Ctrl+Alt shortcutsDelphi\7.0\Editor\Options\NoCtrlAltKeys="1“Tools | Options | Editor Options | Key Mappings | Use Ctrl+Alt
keys
Delphi 7 Macro toolbar (as in later versions)Delphi\7.0\Extras\ShowRecordMacro="1"
Delphi for .NET Reflection IL DisassemblyBDS\3.0\Globals\ShowILDisassembly="1"
Designer Insight (WinForms)BDS\3.0\DesignerInsight\Visible="1"
The languageIterations
Logical assignments
Logical array indices
Typed constants
Sets & cases
Accessing protected members
Accessing private members
Characters
Concise object creation
The language
Iterations - extension to for loop syntax
var I: Integer;
S: String;
...
for I := 0 to Pred(ListBox1.Items.Count) do
begin
S := ListBox1.Items[I];
MessageBox.Show(S)
end
The language
Iterations - extension to for loop syntax
var
S: String;
...
for S in ListBox1.Items do
MessageBox.Show(S)
The language
Iterations - extension to for loop syntax
var S: String;
...
for S in ListBox1.Items do
MessageBox.Show(S)
Works with arrays (inc. multi-dimensional), strings, sets, and anything that implements IEnumerable
The language
if X then
Y := True
else
Y := False
if X then
Y := False
else
Y := True
↓ ↓
Y := X Y := not X
Logical assignments
The languageLogical array indices
– Arrays need not be indexed by numbers– A typical array is specified using a subrange, e.g.:
MyArray[ 1..10 ] of Byte;
– Subranges can be made from any ordinal type, e.g.:
MyArray[ Boolean ] of String;
The languageTyped constants
– Very useful for initialising constant arrays & records
– Currently defaults to actually being constant
– Toggling the option allows them to be used like C static variables:•{$WRITEABLECONST ON}•{$J+}
The languageTyped constantsprocedure TForm1.UpdateUI;begin if Length( Trim( edtTextEntry.Text ) ) = 0 then Bar.SimpleText := 'No text to add' else Bar.SimpleText := 'You can add the text'end;
↓procedure TForm1.UpdateUI;const Desc: array[ Boolean ] of String = ( 'No text to add', 'You can add the text' );begin Bar.SimpleText := Desc[ Length( Trim( edtTextEntry.Text ) ) <> 0 ];end;
The languageSets & cases
– Conditionals easily become cumbersome (develop a surfeit of brackets)
– Conditionals that compare a variable against a number of values can be simplified using sets or case statements
– If the values have an ordinal value less than 256 a set can be used
– Otherwise you can employ a case statement
The languageSets & casesprocedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift:
TShiftState);begin if (Key = VK_UP) or (Key = VK_DOWN) or (Key = VK_LEFT) or (Key = VK_RIGHT) then begin Bar.SimpleText := 'Cursor key'; Key := 0; end else if (Key = VK_PRIOR) or (Key = VK_NEXT) then begin Bar.SimpleText := 'Page movement key'; Key := 0; end else Bar.SimpleText := 'Miscellaneous key'end;
The languageSets & casesprocedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift:
TShiftState);begin if Key in [ VK_LEFT..VK_DOWN ] then begin Bar.SimpleText := 'Cursor key'; Key := 0; end else if Key in [ VK_PRIOR, VK_NEXT ] then begin Bar.SimpleText := 'Page movement key'; Key := 0; end else Bar.SimpleText := 'Miscellaneous key'end;
The languageSets & casesprocedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift:
TShiftState);begin case Key of VK_LEFT..VK_DOWN: begin Bar.SimpleText := 'Cursor key'; Key := 0; end; VK_PRIOR, VK_NEXT: begin Bar.SimpleText := 'Page movement key'; Key := 0; end else Bar.SimpleText := 'Miscellaneous key' endend;
The languageConcise object creation (who needs a variable?)procedure TForm1.Button1Click(Sender: TObject);const RegPath = 'Software\Microsoft\Windows\CurrentVersion\Explorer\
Advanced'; RegEntry = 'HideFileExt';begin with TRegistry.Create do try if OpenKey( RegPath, False ) then WriteInteger( RegEntry, 0 ) finally Free endend;
The languageAccessing protected members
– Delphi’s definition of protected is not the same as in C++
– It’s more like C++’s protected with friend classes– Rather like C#’s protected internal– Akin to .NET CLR’s family or asembly– Protected members are accessible to:
• any derived classes• any code in the target class’s unit
The languageAccessing protected members
– A common trick is to implement so called “access” classes or “hack” classes to gain access to protected members
– An access class is a shallow descendant defined in the unit where access is required:type TWCAccess = class( TWinControl );
– Used several times in the VCL source– Search VCL / VCL for .NET source for:
Access = class(T
The languageAccessing protected members
– Another trick uses “interposer” classes
– These are defined in the unit requiring access
– Distinguishing feature is the name is the same as the original, thereby removing the need for a typecast:type
TDBGrid =
class( DBGrids.TDBGrid );
The languageAccessing private members
– No easy answer to this except hacking– Relies on you knowing:
• how many data fields precede the target private data field• Which class the field was added in• how many bytes they take up
– Add to this the ancestor class’s instance size– You now have the offset from the start of the
instance data
The languageAccessing private membersfunction GetPrivateField(Obj: TObject; Cls: TClass;
DataOffset: Cardinal): Pointer;var ParentInstanceSize: Cardinal;begin //Get parent instance data size //and add on the VMT pointer ParentInstanceSize := Cls.ClassParent.InstanceSize + 4; Result := Pointer( Cardinal( Obj ) +
ParentInstanceSize + DataOffset )end;
var FocusedCtl: TWinControl;... FocusedCtl := TWinControl( GetPrivateField( Self, TCustomForm, 4 )^ );
The language
Characters
– Characters don’t need concatenation– They can be effectively embedded in the
string as long as there is no white space
Caption := 'Copyright '#169' 2004, Me';
The RTLPlatform checking
Calling Win32 APIs
Tracking memory usage
Memory manager statistics
Memory manager debug routines
Replacing/chaining the memory manager
The RTLPlatform checking through SysUtils
– Win32Platform•VER_PLATFORM_WIN32_WINDOWS•VER_PLATFORM_WIN32_NT
– Win32MajorVersion– Win32MinorVersion– Win32BuildNumber– Win32CSDVersion
• Corrective Service Disk (Service Pack)– CheckWin32Version
The RTL
Operating System Win32Platform Win32MajorVersion Win32Minor-Version
Win32CSD-Version[1]
Windows 95 VER_PLATFORM_WIN32_WINDOWS 4 0
Windows 95 OSR2 VER_PLATFORM_WIN32_WINDOWS 4 0 'B' or 'C'
Windows 98 VER_PLATFORM_WIN32_WINDOWS 4 10
Windows 98 SE VER_PLATFORM_WIN32_WINDOWS 4 10 'A'
Windows Me VER_PLATFORM_WIN32_WINDOWS 4 90
Windows NT VER_PLATFORM_WIN32_NT <= 4 Service pack
Windows 2000 VER_PLATFORM_WIN32_NT 5 0 Service pack
Windows XP VER_PLATFORM_WIN32_NT 5 1 Service pack
Windows Server 2003 VER_PLATFORM_WIN32_NT 5 2 Service pack
Platform checking
The RTLPlatform checking through .NET FCL
– Environment.OSVersion.Platform• PlatformID.Win32Windows• PlatformID.Win32NT• PlatformID.Win32CE
– Environment.OSVersion.Version.Major– Environment.OSVersion.Version.Minor– Environment.OSVersion.Version.Build– Environment.OSVersion.Version.Revision
The RTL Calling Win32 APIs
– GetLastError– RaiseLastWin32Error– RaiseLastOSError– SysErrorMessage– Win32Check– EWin32Error– EOSError
The RTL Tracking memory usage
– AllocMemCount– AllocMemSize
Win32 Memory manager statistics– GetHeapStatus– THeapStatus
The RTLWin32 Memory manager debug routines
– GetHeapBlocks– FindObjects– Recompiling the RTL
Win32 Replacing the memory manager
– Chasing AVs
– Tracking memory
The debuggerTracing
The CPU window
Run without debugging
Re-executing code
Debugging DLLs
Watching special values
The debuggerTracing
– Debug messages
– The Event Log
– SysInternals DebugView
– Hooking Automation (Win32)•VarDispProc• hooking named parameters
The debuggerTracing
– Reimplemented assertions (Win32)•AssertErrorProc
– Advanced breakpoints
– Evaluating functions in watches
The debuggerThe CPU window
– Navigating around• Keys• Context menus• Following addresses to code and data• Changing memory
The debuggerThe CPU window (Win32)
– Object internals
TBar Variable
TBar VMTTBar Instance
VMT Ptr
IFoo Variable
IYada Variable
IFoo MT
IYada MT
TBar.Meth1
TBar.Meth2
TBar.Meth1Code
TBar.Meth2Code
IFoo+TBar.Meth1 Stub
IFoo+TBar.Meth2 Stub
IFoo.Meth1
IFoo.Meth2
IFoo+TBar MT
IYada+TBar MT
The debuggerThe CPU window (Win32)
– Object internalsTFoo Variable
TFoo.VMeth1
TFoo.VMeth2
DMT Ptr
TFoo VMT
…
…
VMT Ptr
TFoo Instance
TFoo.VMeth1Code
TFoo.VMeth2Code
TFoo.DMeth1
TFoo.DMeth2
DMT Count
TFoo.DMeth1 id
TFoo.DMeth2 id
…
…
TFoo.DMeth1Code
TFoo.DMeth1Code
The debuggerThe CPU window (Win32)
– VMT prefix fields
– Locating an object’s class name• Follow the VMT trail•vmtClassName
– How big is a memory block?• Prefix fields• The $7FFFFFFC mask
The debuggerRe-executing code – reset EIP
Debugging DLLs
– Host application
– Remote debug symbols required to debug COM DLLs
Watching special values– TDateTime values
WindowsThe Windows key
+e Explorer +f Find files– Ctrl++f Find computer +l Lock workstation (XP+) +m Minimize all– Shift++m Undo minimize all +d Bring desktop to front +r Run... +F1 Windows help +Break System properties +u Microsoft Narrator
WindowsTask Manager keystroke: Ctrl+Shift+Esc
Can drag from Explorer to Command prompt window and Run... dialog
Can add NotePad etc. to Send To by adding a shortcut in %USERPROFILE%\SendTo
WindowsEntering ANSI/ASCII symbols on numeric keypad:
– Alt + 4 digit number = ANSI character– Alt + 3 digit number = ASCII character
Retrieving lost windows– Alt+Space drops down the system menu– M triggers Move menu– Cursor keys move the window around– Mouse makes window snap to pointer
Accessibility options
.NETSDK Command prompt
Profiling
– CLR Profiler
– Brew your own
Debugging outside the IDE
– cordbg
– GUI Debugger
– Windbg & SOS
Thank You
1002
Delphi Tips & Techniques
Please fill out the speaker evaluation
You can contact me further at [email protected]