My major focus is now on D. It is a nice language with great features. Template, Mixins, Array-Slicing, functional programming and more OOP. I am involved in a D-project, which is intended to redesign an old system (written in C) using D.
My teammates give me a lot of advices on design principles. One thing just inspired me. so I revised my old article "Potential memory leaks by initializing a record".
The main point: the default way of initializing a record looks more like an abuse of FillChar. I suggest declare a const record (eg. EmptyRecord) instead of using FillChar.
Thursday, April 23, 2009
Potential memory leaks by initializing a record (revised)
Posted by
stanleyxu (2nd)
/ALL RIGHTS RESERVED/ at
8:25 PM
0
comments
Tags: delphi
Thursday, October 23, 2008
LIKE is not case insensitive?
I was stuck by understanding the following SQL query:
SELECT name
FROM my_table
WHERE name LIKE '%Jack%'
There is nothing special. It just tries to pick up all "names" of "my_table", those values contain the word "Jack" (case sensitive). However, "jack" is also in the result. I cannot believe my eyes.
I googled "LIKE case insensitive" and got the answer:
The problem is caused by the collation of the database. The default collation of my database is "latin1_swedish_ci". The trailing "_ci" stands for case insensitive. I changed it to "utf8_bin", the problem has been solved.
Here are some useful links:
http://forums.mysql.com/read.php?20,202839,202839
http://dev.mysql.com/doc/refman/5.0/en/pattern-matching.html
http://dev.mysql.com/doc/refman/5.0/en/charset-charsets.html
Posted by
stanleyxu (2nd)
/ALL RIGHTS RESERVED/ at
6:15 PM
1 comments
Tags: tips
Wednesday, September 10, 2008
require_once()
If you used require_once(), you may have known one big issue of it: "If you give a relative path to the file you want to require, PHP will use the working directory as root, not the directory where this file is located." Your code won't have any problem, except the file to be required, requires some other files as well and unfortunately they are not in a same directory.
There are several solutions on the Internet.
- Put all PHP files into one folder. This works for tiny projects, but a flat folder structure is really ugly.
- Use a PHP framework, like Zend, CodeIgniter, CakePHP. They provide a certain function like $this->load() to find the correct path of these files and load them.
- If your code is not based on a framework, you can simply use
"require_once(dirname(__FILE__).'/path_to_file')" instead of
"require_once('path_to_file')". However this does not work on my xampp environment. My code hangs up when executing this line. (The problem seems not to be on the slash or backslash. Really no idea)
My Solution
Write a function to calculate the relative path from file directory to working directory. If you previously use "require_once('path_to_file')", now you write"require_once(cp('path_to_file'))". It has been tested on Windows.
if (!function_exists('cp'))
{
function cp($f) // change_path
{
if (($wp = getcwd()) === ($fp = dirname(__FILE__))) { return $f; }
$wp = explode('\\', $wp);
$fp = array_merge(explode('\\', $fp), explode('/', $f));
for ($i = 0, $p = min(count($wp), count($fp)); $i < $p; $i++)
{
if ($wp[$i] === $fp[$i])
{
array_shift($wp);
array_shift($fp);
$i--; $p--;
continue;
}
break;
}
$p = ''; foreach ($wp as $k) { $p .= '../'; }
return $p.implode('/', $fp);
}
}
Posted by
stanleyxu (2nd)
/ALL RIGHTS RESERVED/ at
8:08 AM
0
comments
Tags: tips
Saturday, August 9, 2008
Quick note on UnicodeString
Jan Goyvaerts has introduced some key information about Unicode in Delphi 2009.
http://www.micro-isv.asia/2008/08/get-ready-for-delphi-2009-and-unicode/
Marco Cantu has made a performance comparison between AnsiString and UnicodeString.
http://blog.marcocantu.com/blog/tiburon_unicode_video_5.html
Conclusion
According to the information, so much I have collected in the past a few months, I summarized them as the following points:- Simple projects can be upgraded to Delphi 2009 without any modifications. Projects with heavy string operations or file operations could be compiled as well. But they should be tested completely before release.
- UnicodeString is based on the same concept as AnsiString. So it is very fast and efficient, although it is a little bit slower than AnsiString.
- In compare with WideString much less memory will be allocated for UnicodeString. If it is not necessary, you had better switch WideStrings to UnicodeStrings for a performance boost.
UPDATE 1: Here and here are detailed performance tests
Posted by
stanleyxu (2nd)
/ALL RIGHTS RESERVED/ at
10:36 AM
0
comments
Tags: delphi
Tuesday, May 27, 2008
Do not give the OK button a keyboard accelerator
Raymond Chen, a well-known developer on the Windows Shell team at Microsoft, mentioned a principle about dialog design in his blog: Do not give the OK button a keyboard accelerator [1].
But it is funny, that even their own products do not follow this principle strictly. A remarkable example is the "Restart Prompt Dialog of Automatic Updates" in WindowsXP. Both buttons "Restart Now" and "Restart Later" have a keyboard accelerator. If this dialog pops up, while I am pressing ALT+N, the current Windows session will be terminated immediately. And there is no Postpone button either. This button appears in Windows Vista, but there is no option "Do not prompt me again, I will restart my computer later.". If I do not intend to restart my computer very soon, I have to press "Postpone" in every 4 hours. It is really annoying! Not only the unfriendly design, but also infinite critical Windows updates. The only one option for me is to turn off "Automatic Updates".
According to the great design principles [2]: I suggest remove those keyboard accelerators and add a 10-second-delay before restarting Windows, so that user can cancel this action. This is called user experience!
References
Posted by
stanleyxu (2nd)
/ALL RIGHTS RESERVED/ at
8:45 PM
1 comments
Tags: user experience
Monday, May 26, 2008
Form disappeared
After I started working on dual monitors, I have found another interesting issue:
- Create a new application with a main form and a sub-form.
- Set the property Position of the sub-form to poMainFormCenter
- Create a button "Show Sub-Form" on main form.
- Move more than 50% area of the main form out of the main screen.
- Click the button, we created.
Solution
This time you have to modify Forms.pas- Copy Forms.pas to your project folder,
- find and replace with the following code,
- and then recompile your project again.
{$IFDEF FIXUP_FORM_POPUP_POSITION}
function GetPrimaryMonitor: TMonitor;
var
I: Integer;
begin
for I := 0 to Screen.MonitorCount - 1 do
begin
Result := Screen.Monitors[I];
if Result.Primary then
Exit;
end;
Result := Screen.Monitors[0];
end;
procedure CenterFormToPrimaryMonitorCenter(var X, Y: Integer;
AForm: TCustomForm);
var
R: TRect;
begin
R := GetPrimaryMonitor.WorkareaRect;
X := R.Left + (R.Right - R.Left - AForm.Width) div 2;
Y := R.Top + (R.Bottom - R.Top - AForm.Height) div 2;
end;
procedure SnapFormToMonitorEdgeOnDemand(var X, Y: Integer;
AForm: TCustomForm);
var
DistanceLeft, DistanceRight: Integer;
CenterMon: TMonitor;
R: TRect;
begin
CenterMon := Screen.MonitorFromPoint(
Point(X + AForm.Width div 2, Screen.DesktopHeight div 2));
R := CenterMon.WorkareaRect;
// Adjust X-pos
DistanceLeft := X - R.Left;
DistanceRight := R.Right - (X + AForm.Width);
if (DistanceLeft < 0) and (DistanceRight < 0) then
begin
if DistanceLeft >= DistanceRight then
X := R.Left // Snap to left edge
else X := R.Right - AForm.Width; // Snap to right edge
end
else if (DistanceLeft < 0) or (DistanceRight < 0) then
begin
if DistanceLeft < 0 then
X := R.Left // Snap to left edge
else X := R.Right - AForm.Width; // Snap to right edge
end;
// Adjust Y-pos
if Y < R.Top then
Y := R.Top
else if Y > R.Bottom - AForm.Height then
Y := R.Bottom - AForm.Height;
end;
{$ENDIF}
procedure TCustomForm.CMShowingChanged(var Message: TMessage);
// ...
if (FPosition = poScreenCenter) or
((FPosition = poMainFormCenter) and (FormStyle = fsMDIChild)) then
begin
if FormStyle = fsMDIChild then
begin
X := (Application.MainForm.ClientWidth - Width) div 2;
Y := (Application.MainForm.ClientHeight - Height) div 2;
end else
begin
{$IFDEF FIXUP_FORM_POPUP_POSITION}
CenterFormToPrimaryMonitorCenter(X, Y, Self);
{$ELSE}
X := (Screen.Width - Width) div 2;
Y := (Screen.Height - Height) div 2;
{$ENDIF}
end;
{$IFDEF FIXUP_FORM_POPUP_POSITION}
SnapFormToMonitorEdgeOnDemand(X, Y, Self);
SetBounds(X, Y, Width, Height);
//SetWindowToMonitor() will cause unexpected popup position change!
{$ELSE}
if X < Screen.DesktopLeft then
X := Screen.DesktopLeft;
if Y < Screen.DesktopTop then
Y := Screen.DesktopTop;
SetBounds(X, Y, Width, Height);
if Visible then SetWindowToMonitor;
{$ENDIF}
end
else if FPosition in [poMainFormCenter, poOwnerFormCenter] then
begin
CenterForm := Application.MainForm;
if (FPosition = poOwnerFormCenter) and (Owner is TCustomForm) then
CenterForm := TCustomForm(Owner);
if Assigned(CenterForm) then
begin
X := ((CenterForm.Width - Width) div 2) + CenterForm.Left;
Y := ((CenterForm.Height - Height) div 2) + CenterForm.Top;
end else
begin
{$IFDEF FIXUP_FORM_POPUP_POSITION}
CenterFormToPrimaryMonitorCenter(X, Y, Self);
{$ELSE}
X := (Screen.Width - Width) div 2;
Y := (Screen.Height - Height) div 2;
{$ENDIF}
end;
{$IFDEF FIXUP_FORM_POPUP_POSITION}
SnapFormToMonitorEdgeOnDemand(X, Y, Self);
SetBounds(X, Y, Width, Height);
//SetWindowToMonitor() will cause unexpected popup position change!
{$ELSE}
if X < Screen.DesktopLeft then
X := Screen.DesktopLeft;
if Y < Screen.DesktopTop then
Y := Screen.DesktopTop;
SetBounds(X, Y, Width, Height);
if Visible then SetWindowToMonitor;
{$ENDIF}
end
else if FPosition = poDesktopCenter then
// ...
end;Conclusion
This issue is nothing. The motivation of this article [2] is to suggest you figure out the differences among DesktopRect, BoundsRect and WorkAreaRect. They are almost the same on one monitor environment. But they are totally different on dual monitors, especially when TaskBar is not at its default position.References
Posted by
stanleyxu (2nd)
/ALL RIGHTS RESERVED/ at
6:04 AM
0
comments
Tags: delphi, vcl patches
Sunday, April 27, 2008
A not cool thing of TCoolBar
There is a demo project "coolstuf" in Delphi folder. It demonstrates how to build your own web browser with Delphi. Unfortunately it shows you how to re-procedure an issue of TCoolBar as well. "Just drag the (third) Links toolbar to top and then to bottom, repeat it for several times, you will see an extra area (roughly 40px) at bottom of TCoolBar." I call this as a "TCoolBar Bands' Position Problem". If you do not get it, please look at the snapshot.
If you have read other posts in my blog, you might know, that I am very uncomfortable with such UI problems. So I did some investigation: This issue take place, when one or more bands have a fixed size. (TCoolBand.FixedSize is True) I suppose, that the height of this (fixed-size) band was not updated, when TCoolBar's height was changed. Actually, this is not the only one issue of REBAR controls. For instance: No chevron support, no whole dropdown button support, flickering problem, etc. (I will talk about them later in another post)
Solution
I have reported this issue to QualityCentral [1]. Not like other patches I have made, this time, the solution is not clean enough.You have to:
- Copy ComCtrls.pas to your project folder,
- find and replace with the following code,
- and then recompile your project again.
procedure TCoolBar.CNNotify(var Message: TWMNotify);
//PATCH-BEGIN
var
I, FID: Integer;
RBBI: TReBarBandInfo;
//PATCH-END
begin
if (Message.NMHdr^.code = RBN_HEIGHTCHANGE) then
if IsAutoSized and (ComponentState * [csLoading, csDestroying] = [])
then begin
//PATCH-BEGIN
for I := 0 to Bands.Count - 1 do
if Bands[I].FixedSize then
begin
FillChar(RBBI, SizeOfReBarBandInfo, 0);
RBBI.cbSize := SizeOfReBarBandInfo;
RBBI.fMask := RBBIM_STYLE;
FID := Bands[I].FID;
Perform(RB_GETBANDINFO, FID and IDMask, Integer(@RBBI));
Perform(RB_SETBANDINFO, FID and IDMask, Integer(@RBBI));
end;
//PATCH-END
ReadBands;
BeginUpdate;
try
if AutoSize then AdjustSize;
finally
EndUpdate;
end;
end
else if IsBackgroundDirty then
Invalidate;
end;
Conclusion
As I mentioned before, REBAR controls (TCoolBar, TCoolBand, TToolBar and TToolButton) have not been implemented correctly as they should be. I did some experiments and made couple of patches. This article [2] is only the part one. There will be part two, part three...To note that some patches must modify interface declaration and implementation both. Unfortunately Delphi cannot re-compile those modified units, when their interface declaration has been changed. The only one solution, so far as I known, is to create a copy of the whole REBAR control set and modify the new set. I will be appreciated, if someone can suggest any better ways.
References
Posted by
stanleyxu (2nd)
/ALL RIGHTS RESERVED/ at
10:59 AM
0
comments
Tags: delphi, vcl patches

