delphi
Proper Timing with GetTickCount()
Often programmers are faced with implementing timers for short-period operations, anywhere from the sub-second to a few hours. These sort of timers are typically used in timeout operations, like idle connection timeouts, stale cache timeouts, and fade timers, but are also used in basic discrete physics calculations, input debounce timers, and timeslice allocations. In these applications I like using GetTickCount().
More information on why I like it and why to choose it over other timing options follow after the break.
(more…)
How TaskDialogIndirect() can turn Cancel into Yes
User Interface designers are rather sadistic. In the year 3000, when suicide booths will be commonplace, a User Interface designer will be the sort of fellow who places the “Stab Me to Death” button adjacent to the “Enjoy a Lovely Cup of Tea” button on the Slurp ‘N Spear vending machine down at the local Automat. If you’re interested in getting repeat business, you’ll probably want to confirm that the consumer would rather purchase a gut full of twisting metal instead of a mouthful of dried leaves in water.
Consider the following code analog to this situation, where the Delete button looks too much like, or is placed to close to the Save button in a toolbar. As a defensive programmer you safeguard the delete function with a confirmation:
if MessageDlg('This action is not undoable.'#13 + 'Are you sure you want to delete all your work?', mtConfirmation, [mbYes,mbNo], 0) = mrNo then exit; DoDeleteAllYourWork();
This works fine and the early bailout situation is preferable in my book when the code of DoDeleteAllYourWork() actually follows inline. The code is written, compiled, shipped and you forget all about it until a few years later someone calls up spitting venom because they pressed Escape and your app deleted their work. What has occurred is a subtle issue created by Delphi switching from their own MessageDlg to Vista’s powerful TaskDialogIndirect() API when you enable runtime themes in your project options.
(more…)
Determining ThreadingModel in a Delphi Application
I has occurred to me that someone might need to determine their COM threading model from inside their application. This could be useful for some ASSERT() code or perhaps as part of a unit test. From my last blog post, you’ll recall that this information is stored in an opaque structure located in each thread’s Thread Environment Block (TEB). Actually quite simple to do, with original credit going to John Robbins’ Bugslayer Column from the old MSJ magazine.
{ uses ActiveX; Ported from John Robbins - Microsoft Systems Journal Bugslayer Column - October '99 http://www.microsoft.com/msj/1099/bugslayer/bugslayer1099.aspx } function DebugCoGetThreadingModel : integer; const OLE_APT_MASK = $0080; OLE_FREE_MASK = $0140; var dwOLETLS: Cardinal; dwFlags: Cardinal; begin asm // Get TEB mov eax, FS:[018h] mov eax, [eax+0f80h] mov dwOLETLS, eax end; { Not initialized } if dwOLETLS = 0 then begin Result := -1; exit; end; dwFlags := PCardinal((dwOLETLS + $0C))^; if ((dwFlags and OLE_APT_MASK) = OLE_APT_MASK) then Result := COINIT_APARTMENTTHREADED else if ((dwFlags and OLE_FREE_MASK) = OLE_FREE_MASK) then Result := COINIT_MULTITHREADED { Unknown } else Result := -2; end;
And some sample usage code
case DebugCoGetThreadingModel of -2: Label1.Caption := 'Unknown'; -1: Label1.Caption := 'Not initialized'; COINIT_APARTMENTTHREADED: Label1.Caption := 'COINIT_APARTMENTTHREADED'; COINIT_MULTITHREADED: Label1.Caption := 'COINIT_MULTITHREADED'; end;
John also has an excellent blog of his own which is which is a fantastic low-level technical resource. Speaking of old magazines, I just discovered the Bug of the Month ad that has appeared in Dr Dobbs for nearly the past 20 years has an online archive. Head over to Gimpel Software if you’re up for some C-based brain exercises.
Debugging a Delphi Lockup with Windbg
While the Delphi debugger is quite good, there are some instances when it isn’t quite good enough.
- Your application is crashing remotely The worst place for an application to fail is when there is no debugger available. Usually these problems can be corrected via the “Works Fine Here” solution. Unfortunately most bug-tracking systems lack this option to close tickets.
- Lack of symbol information The best trace you can get in the debugger shows a thread balls deep into Windows API calls for no apparent reason. Some resolution can be gained from the DLL export addresses but without proper symbol information this isn’t enough detail.
The solution to both these scenarios is to use Microsoft’s free debugger WinDbg, available as part of the Debugging Tools for Windows package. You’ll need the version for the host platform where the trace will occur. This means get the 64-bit if you’re debugging on Win64 even if your app is 32-bit. You’ll also need the map2dbg utility, originally by Lucian Wischik.
(more…)