{
To programmatically close another application,
send to the application a WM_QUIT message.
"Window caption" is the caption of the
window that you are sending the message to.
}
function KillApp(const sCapt: PChar) : boolean;
var AppHandle:THandle;
begin
AppHandle:=FindWindow(Nil, sCapt);
Result:=PostMessage(AppHandle, WM_QUIT, 0, 0);
end;
{Usage:}
if not KillApp('Window caption') then
ShowMessage('App not closed'); |
03/2000. IsTrueTypeFont
{
Given a font's name (such as Arial,
Verdana, Times New Roman, etc), function
returns a boolean value meaning
if the font is or isn't a True Type font.
}
function IsTrueTypeFont(FontName : string):boolean;
const
PITCH_MASK: byte = $0F;
var
TxMet: TTextMetric;
TempCanvas : TCanvas;
PitchTest : byte;
begin
TempCanvas:=TCanvas.Create;
TempCanvas.Handle:=CreateCompatibleDC(0);
TempCanvas.Font.Name:=FontName;
GetTextMetrics(TempCanvas.Handle, TxMet);
PitchTest:=TxMet.tmPitchAndFamily and PITCH_MASK;
Result:=(PitchTest and TMPF_TRUETYPE) <> 0;
TempCanvas.free;
end; |
02/2000. ALT+TAB, CTRL+ESC, CTRL+ALT+DEL
{
If you wish to disable those keys while your
application is running call SystemKeys:
When you call SystemKeys, if Disable is True,
the keys will be disabled, False otherwise.
}
procedure SystemKeys(Disable: Boolean);
var OldVal : LongInt;
begin
SystemParametersInfo(SPI_SCREENSAVERRUNNING,
Word(Disable), @OldVal, 0);
end; |
01/2000. Hide Title Bar
{A quick way to hide your program's title bar:}
procedure TForm1.FormCreate(Sender: TObject);
begin
SetWindowLong( Handle,
GWL_STYLE,
GetWindowLong( Handle, GWL_STYLE )
and not WS_CAPTION );
ClientHeight := Height;
end; |
Calculate a week-of-the-year index (0-51) for a given date. Week 0 is the week containing the first Sunday of the year. } function WeekNum(const TDT:TDateTime) : Word; var Y,M,D:Word; dtTmp:TDateTime; begin DecodeDate(TDT,Y,M,D); dtTmp := EnCodeDate(Y,1,1); Result := (Trunc(TDT-dtTmp)+(DayOfWeek(dtTmp)-1)) DIV 7; if Result <> 0 then Result := Result - 1; end;
Change the font in Tool Tip (Hint box)} Type TMyHintWindow = Class (THintWindow) Constructor Create (AOwner: TComponent);override; end; Constructor TMyHintWindow.Create(AOwner:TComponent); begin Inherited Create (AOwner); Canvas.Font.Name := 'Courier New'; Canvas.Font.Size := 72; end; procedure TForm1.FormCreate(Sender: TObject); begin Application.ShowHint := false; HintWindowClass := TMyHintWindow; Application.ShowHint := True; end; |
37. Date/Time and other International Settings
{
By default, Delphi gets its date/time, currency
and numeric format from Control Panel's
International settings.
We can set the constants defined in Delphi,
like DecimalSeparator, ShortDateFormat
and others like:
}
procedure SetLocale;
begin
DecimalSeparator := '.';
ThousandSeparator : = ',';
ShortDateFormat := 'mm/dd/yy';
end;
{
To a complete list of these variables, look at
Currency and date/time formatting variables
in Delphi Help
} |
36. Window Flashing
{
Flashing a window means changing the appearance
of its caption bar as if the window were changing
from inactive to active status, or vice versa.
Typically, a window is flashed to inform the user
that the window requires attention but that it
does not currently have the keyboard focus.
The FlashWindow API function flashes
the window only once.
To create a flashing window add a TTimer component
on a form, and use the following code in the
OnTimer event handler:
}
procedure TForm1.Timer1Timer(Sender: TObject);
begin
FlashWindow (Handle, True);
end; |
35. Open & Close CD-drive
{To OPEN the CD-ROM:}
mciSendString
('Set cdaudio door open wait', nil, 0, handle);
{To CLOSE the CD-ROM:}
mciSendString
('Set cdaudio door closed wait', nil, 0, handle);
{Remember to include the MMSystem
unit in your uses clause.} |
uses ShellAPI;
Function DelTree(DirName : string): Boolean;
{
Completely deletes a directory regardless
of whether the directory is filled or has
subdirectories. No confirmation is requested
so be careful. If the operation is successful
then True is returned, False otherwise
}
var
SHFileOpStruct : TSHFileOpStruct;
DirBuf : array [0..255] of char;
begin
try
Fillchar(SHFileOpStruct,Sizeof(SHFileOpStruct),0);
FillChar(DirBuf, Sizeof(DirBuf), 0 );
StrPCopy(DirBuf, DirName);
with SHFileOpStruct do begin
Wnd := 0;
pFrom := @DirBuf;
wFunc := FO_DELETE;
fFlags := FOF_ALLOWUNDO;
fFlags := fFlags or FOF_NOCONFIRMATION;
fFlags := fFlags or FOF_SILENT;
end;
Result := (SHFileOperation(SHFileOpStruct) = 0);
except
Result := False;
end;
end;
{
Usage
if DelTree('c:\TempDir') then
ShowMessage('Directory deleted!')
else
ShowMessage('Errors occured!');
} |
33. From/To the 8.3 Format To/From the Long Format
unit LFN_ALT;
interface
{
This unit provides two functions that convert
filenames from the long format to the 8.3
format, and from the 8.3 format to the long
format.
}
function AlternateToLFN(AltName:String):String;
function LFNToAlternate(LongName:String):String;
implementation
uses Windows;
function AlternateToLFN(AltName:String):String;
var
temp: TWIN32FindData;
searchHandle: THandle;
begin
searchHandle:=FindFirstFile(PChar(AltName),temp);
if searchHandle <> ERROR_INVALID_HANDLE then
result := String(temp.cFileName)
else
result := '';
Windows.FindClose(searchHandle);
end;
function LFNToAlternate(LongName:String):String;
var
temp: TWIN32FindData;
searchHandle: THandle;
begin
searchHandle:=FindFirstFile(PChar(LongName),temp);
if searchHandle <> ERROR_INVALID_HANDLE then
result := String(temp.cALternateFileName)
else
result := '';
Windows.FindClose(searchHandle);
end;
end.{unit} |
32. Get Files "Last Modified" Attribute
function FileLastModified
(const TheFile: string): string;
var
FileH : THandle;
LocalFT : TFileTime;
DosFT : DWORD;
LastAccessedTime : TDateTime;
FindData : TWin32FindData;
begin
Result := '';
FileH := FindFirstFile(PChar(TheFile), FindData);
if FileH <> INVALID_HANDLE_VALUE then begin
Windows.FindClose(Handle);
if (FindData.dwFileAttributes AND
FILE_ATTRIBUTE_DIRECTORY) = 0 then
begin
FileTimeToLocalFileTime
(FindData.ftLastWriteTime,LocalFT);
FileTimeToDosDateTime
(LocalFT,LongRec(DosFT).Hi,LongRec(DosFT).Lo);
LastAccessedTime := FileDateToDateTime(DosFT);
Result := DateTimeToStr(LastAccessedTime);
end;
end;
end;
{
Usage:
label1.Caption:=FileLastModified('c:\autoexec.bat');
} |
31. Reading a Directory's Content
procedure FindAll (const Path: String;
Attr: Integer;
List: TStrings);
var
Res: TSearchRec;
EOFound: Boolean;
begin
EOFound:= False;
if FindFirst(Path, Attr, Res) < 0 then
exit
else
while not EOFound do begin
List.Add(Res.Name);
EOFound:= FindNext(Res) <> 0;
end;
FindClose(Res);
end;
{
The following example lists all files and
subdirectories of the C:\Windows directory
into a TListBox called ListBox1:
FindAll('C:\Windows\*.*',faAnyFile,ListBox1.Items);
} |
LeftStr() takes a certain portion of
the left side of a string.
. MidStr() takes a specified number of
characters from a string.
. RightStr() takes a certain portion of
the right side of a string.
}
function RightStr
(Const Str: String; Size: Word): String;
begin
if Size > Length(Str) then Size := Length(Str);
RightStr := Copy(Str, Length(Str)-Size+1, Size)
end;
function MidStr
(Const Str: String; From, Size: Word): String;
begin
MidStr := Copy(Str, From, Size)
end;
function LeftStr
(Const Str: String; Size: Word): String;
begin
LeftStr := Copy(Str, 1, Size)
end;
{
Let's say we have a string
Dstr := 'Delphi is the BEST', then
LeftStr(Dstr, 5) := 'Delph'
MidStr(Dstr, 6, 7) := 'i is th'
RightStr(Dstr, 6) := 'e BEST'
} |
29. Reverse a String
}
28. Search And Replace
function SearchAndReplace
(sSrc, sLookFor, sReplaceWith : string) : string;
var
nPos, nLenLookFor : integer;
begin
nPos := Pos(sLookFor, sSrc);
nLenLookFor := Length(sLookFor);
while (nPos > 0) do begin
Delete(sSrc, nPos, nLenLookFor);
Insert(sReplaceWith, sSrc, nPos);
nPos := Pos(sLookFor, sSrc);
end;
Result := sSrc;
end;
{
Let's say you have a string
'testing;search;and;replace'
and you want to replace ';' with spaces.
Here's how you'd call this function
sOldString:='testing;search;and;replace';
sNewString:=SearchAndReplace(sOldString, ';', ' ')
} |
27. Convert The First Letter In Any Word To A Capital
{
Tip submitted by: Andrew Burt, [email protected]
}
procedure TForm1.Button1Click(Sender: TObject);
var
GetString : string;
GetLength : Integer;
I : Integer;
T : String;
begin
if edit1.SelLength > 0 then
GetString:= Edit1.Seltext
else GetString:= Edit1.Text;
GetLength:= Length(Edit1.Text);
if GetLength>0 then begin
for I:= 0 to GetLength do begin
if (GetString[I] = ' ') or (I=0) then begin
if GetString[I+1] in ['a'..'z'] then begin
T:=GetString[I+1];
T:=UpperCase(T);
GetString[I+1]:=T[1];
end;
end;
end;
if edit1.Sellength>0 then
Edit1.Seltext:=GetString
else Edit1.Text:=GetString;
end;
end; |
Here is an example of creating a
font that is rotated 45 degrees
}
procedure TForm1.Button1Click(Sender: TObject);
var
lf : TLogFont;
tf : TFont;
begin
with Form1.Canvas do begin
Font.Name := 'Arial';
Font.Size := 24;
tf := TFont.Create;
try
tf.Assign(Font);
GetObject(tf.Handle, sizeof(lf), @lf);
lf.lfEscapement := 450;
lf.lfOrientation := 450;
tf.Handle := CreateFontIndirect(lf);
Font.Assign(tf);
finally
tf.Free;
end;
TextOut(20, Height div 2, 'Rotated Text!');
end;
end; |
25. Checking If File Is In Use
{
IsFileInUse will return true if the file is
locked for exclusive access. It would fail if the
file doesn't exist at all.
}
function IsFileInUse(fName : string) : boolean;
var
HFileRes : HFILE;
begin
Result := false;
if not FileExists(fName) then exit;
HFileRes :=
CreateFile(pchar(fName),
GENERIC_READ or GENERIC_WRITE,
0, nil, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
Result := (HFileRes = INVALID_HANDLE_VALUE);
if not Result then
CloseHandle(HFileRes);
end; |
24. Capture Maximize/Minimize Buttons
...
public
procedure WMSysCommand
(var Msg: TWMSysCommand);
message WM_SYSCOMMAND;
...
implementation
...
procedure TForm1.WMSysCommand;
begin
if (Msg.CmdType = SC_MINIMIZE) or
(Msg.CmdType = SC_MAXIMIZE) then
MessageBeep(0);
DefaultHandler(Msg);
end; |
23. Enlarge a Form Over Screen Size
{Add a button to a form and try this:}
//Due to the default Windows handling of
//the WM_GETMINMAXINFO message,
//the max size of the form is set to
//the screen size.
...
private
procedure WMGetMinMaxInfo
(var msg: TWMGetMinMaxInfo);
message WM_GETMINMAXINFO;
...
implementation
procedure TForm1.WMGetMinMaxInfo
(var msg: TWMGetMinMaxInfo);
begin
inherited;
with msg.MinMaxInfo^.ptMaxTrackSize do begin
X := GetDeviceCaps(Canvas.Handle, HORZRES)
+ (Width - ClientWidth);
Y := GetDeviceCaps(Canvas.Handle, VERTRES)
+ (Height - ClientHeight);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
Const
Rect: TRect = (Left:0; Top:0; Right:0; Bottom:0);
begin
if Left > 0 then begin
Rect := BoundsRect;
SetBounds(
Left - ClientOrigin.X,
Top - ClientOrigin.Y,
GetDeviceCaps(Canvas.Handle, HORZRES)
+ (Width - ClientWidth),
GetDeviceCaps(Canvas.Handle, VERTRES)
+ (Height - ClientHeight)
);
end
else BoundsRect := Rect;
end; |
Here is how to keep the window from moving:
First, make the borderstyle something
like bsDialog, so that the window cant be resized.
Next, add the following declaration
to your form class:
}
procedure PosChange(var Msg: TWmWindowPosChanging);
message WM_WINDOWPOSCHANGING;
//Finally, implement the procedure like:
procedure TForm1.PosChange
(var Msg: TWmWindowPosChanging);
begin
Msg.WindowPos.x := Left;
Msg.WindowPos.y := Top;
Msg.Result := 0;
end;
{
Thats it. Easy as can be. The only problem with
this is that you cant move the form if you want
your code to. To get around this, just set up a
Boolean variable called PosLocked, set it to
True when you want to lock the forms position,
and to false when you need to move the form (when
your done, remember to set it back to true). Then
to implement the proc above, just make it
}
if PosLocked then begin
Msg.WindowPos.x := Left;
Msg.WindowPos.y := Top;
Msg.Result := 0;
end else inherited; |
21. Execute the Windows Explorer Find File Dialog Box
{
The following example demonstrates using DDE to
execute Explorer's find file dialog. The example
opens the dialog in the Directory "C:\DelphiTips".
}
uses ddeman;
procedure TForm1.Button1Click(Sender: TObject);
begin
with TDDEClientConv.Create(Self) do begin
ConnectMode := ddeManual;
ServiceApplication := 'explorer.exe';
SetLink( 'Folders', 'AppProperties');
OpenLink;
ExecuteMacro
('[FindFolder(, C:\DelphiTips)]', False);
CloseLink;
Free;
end;
end; |
20. Delete files with the ability to UNDO
{
Delete a file with the ability to undo by
sending the file to the "Recycle Bin."
Function FileDeleteRB will return True
if the operation was successful.
}
uses ShellAPI;
function FileDeleteRB(
FileName:string): boolean;
var
fos : TSHFileOpStruct;
begin
FillChar(fos, SizeOf(fos), 0);
with fos do begin
wFunc := FO_DELETE;
pFrom := PChar(FileName);
fFlags := FOF_ALLOWUNDO
or FOF_NOCONFIRMATION
or FOF_SILENT;
end;
Result := (ShFileOperation(fos)=0);
end; |
19. Add documents to the Windows Start-Documents Menu
{
If you would like to add documents to the new
"Start-Documents" menu that was added with the
creation of Windows 95/NT, use the following
function. Be sure to add ShellAPI and ShlOBJ
to your uses clause.
}
procedure AddtoDocMenu(fName : String);
begin
SHAddToRecentDocs(SHARD_PATH, PChar(fName));
end; |
18. Making a transparent form
{Add a button to a form and try this:}
procedure TForm1.FormCreate(Sender: TObject);
var
FullRgn, ClientRgn, ButtonRgn: THandle;
Margin, X, Y: Integer;
begin
Margin := (Width - ClientWidth) div 2;
FullRgn := CreateRectRgn(0, 0, Width, Height);
X := Margin;
Y := Height - ClientHeight - Margin;
ClientRgn := CreateRectRgn
(X, Y, X + ClientWidth, Y + ClientHeight);
CombineRgn(FullRgn, FullRgn, ClientRgn, RGN_DIFF);
X := X + Button1.Left;
Y := Y + Button1.Top;
ButtonRgn := CreateRectRgn
(X, Y, X + Button1.Width, Y + Button1.Height);
CombineRgn(FullRgn, FullRgn, ButtonRgn, RGN_OR);
SetWindowRgn(Handle, FullRgn, True);
end; |
When users enter data, they often need to format it
in a standard way. You can't depend on the user to
do it, so the best bet is to make your program do
the formatting itself.
For example, if the user types a name in all
lowercase letters, the program could automatically
convert the first character in the first and last
names to uppercase letters.
Add the following code to the OnKeyPress event for
the Edit1 component:
}
with Sender as TEdit do
if (SelStart = 0) or
(Text[SelStart] = ' ') then
if Key in ['a'..'z'] then
Key := UpCase(Key); |
16. Using the RunOnce Registry Key
end;
15. Select a block of code by column
//Submited by Joe Ebbeler
{
Many times you may want to select a block of code
in the Delphi editor by column rather than line.
e.g.. You just removed a loop of some kind and you
want to shift a big block of text over 2 spaces.
You can do this by pressing Ctrl + O + C then use
the arrow keys to select the number of characters
then the number of rows. Then press the delete key
or copy or cut. To go back to regular select mode
you can press Ctrl + O + L or you can click
anywhere with the mouse.
} |
The table component's ACTIVE property
must be set to FALSE.
Then, put this code on the form's create event:
}
Session.AddPassword('My secret password');
TableName.Active := True; |
13. Enable/Disable the Windows "START" button
//Enable:
EnableWindow(FindWindowEx(FindWindow
('Shell_TrayWnd', nil), 0,'Button',nil),TRUE);
//Disable:
EnableWindow(FindWindowEx(FindWindow
('Shell_TrayWnd', nil), 0,'Button',nil),FALSE); |
12. Is IDE running?
{
If you want to check whether IDE is runing or not
try this function: (Supose you want your new
shareware component to work only when IDE is
running, or something like that)
}
Function RunningInTheIDE: boolean;
Begin
Result:=FindWindow('TAppBuilder', nil) > 0;
End; |
11. Hint and Warning messages
{
It's a good idea to turn on hint and warning
messages specially when writing and compiling
your own code. Although some of these hints and
warnings can be ignored, most of them - if
nothing else - will remind you of things you
could do to improve your code.
- Go to "Project | Options"
- Change to the "Compiler" tab
- Make sure "Show hints" and "Show warnings"
check boxes are checked
} |
10. Show/Hide the TaskBar in Windows 95
//To hide the task bar use
ShowWindow(FindWindow
('Shell_TrayWnd',nil), SW_HIDE);
//To show the task bar use
ShowWindow(FindWindow
('Shell_TrayWnd',nil), SW_SHOWNA); |
Procedure IcoToBmp;
var
Icon : TIcon;
Bitmap : TBitmap;
begin
Icon := TIcon.Create;
Bitmap := TBitmap.Create;
Icon.LoadFromFile('c:\picture.ico');
Bitmap.Width := Icon.Width;
Bitmap.Height := Icon.Height;
Bitmap.Canvas.Draw(0, 0, Icon );
Bitmap.SaveToFile('c:\picture.bmp');
Icon.Free;
Bitmap.Free;
end; |
8. Prevent CTRL+DELETE in DBGrid
//How to disable deleting
//records with keyboard in DBGrid
procedure Form1.DBGrid1KeyDown
(Sender: TObject; var Key: Word; Shift:TShiftState);
begin
if (Shift = [ssCtrl]) and (Key = VK_DELETE) then
Key := 0; {ignore}
end; |
7. Extract Icon and paint on Form
{
How can I extract the associated icon and draw
it into a small area of the form (e.g. Notepad icon)?
}
procedure TForm1.Button1Click(Sender: TObject);
var
IconIndex : word;
h : hIcon;
begin
IconIndex := 0;
h:=ExtractAssociatedIcon
(hInstance,'C:\WINDOWS\NOTEPAD.EXE', IconIndex);
DrawIcon(Form1.Canvas.Handle, 10, 10, h);
end; |
6. Detecting Drive Types
//Note: you will need one button and
//one memo on your form, for this tip...
procedure TForm1.Button1Click(Sender: TObject);
var
Drive: Char;
DriveLetter: String[4];
begin
for Drive := 'A' to 'Z' do
begin
DriveLetter := Drive + ':\';
case GetDriveType(PChar(Drive + ':\')) of
DRIVE_REMOVABLE:
Memo1.Lines.Add(DriveLetter + ' Floppy Drive');
DRIVE_FIXED:
Memo1.Lines.Add(DriveLetter + ' Fixed Drive');
DRIVE_REMOTE:
Memo1.Lines.Add(DriveLetter + ' Network Drive');
DRIVE_CDROM:
Memo1.Lines.Add(DriveLetter + ' CD-ROM Drive');
DRIVE_RAMDISK:
Memo1.Lines.Add(DriveLetter + ' RAM Disk');
end;
end;
end; |
procedure ScreenShot(DestBitmap : TBitmap);
var
DC : HDC;
begin
DC := GetDC (GetDesktopWindow);
try
DestBitmap.Width := GetDeviceCaps (DC, HORZRES);
DestBitmap.Height := GetDeviceCaps (DC, VERTRES);
BitBlt(DestBitmap.Canvas.Handle,
0,
0,
DestBitmap.Width,
DestBitmap.Height,
DC,
0,
0,
SRCCOPY);
finally
ReleaseDC (GetDesktopWindow, DC);
end;
end; |
4. Remove App from TaskBar
procedure TForm1.FormCreate(Sender: TObject);
begin
ShowWindow(Application.Handle, SW_HIDE);
SetWindowLong(Application.Handle, GWL_EXSTYLE,
getWindowLong(Application.Handle, GWL_EXSTYLE) or
WS_EX_TOOLWINDOW );
ShowWindow( Application.Handle, SW_SHOW );
end; |
3. Show window contents while dragging
{
If you see the Microsoft Plus! you should notice
the "Show window contents while dragging", you
can use this option from your program by calling
the API function: SystemParametersInfo
}
//To Show window contents while dragging:
SystemParametersInfo
(SPI_SETDRAGFULLWINDOWS, 1, nil, 0);
//To disable this option call the function:
SystemParametersInfo
(SPI_SETDRAGFULLWINDOWS, 0, nil, 0); |
2. Life Cycle Of A Form
{
When determining which events of a form to define
to do what you want, it's good to know the life
cycle of a form.
}
ACTION
Create
Show
Paint
Activate
ReSize
Paint
Close query
Close
Deactivate
Hide
Destroy
EVENT
OnCreate
OnShow
OnPaint
OnActivate
OnResize
OnPaint
OnCloseQuery
OnClose
OnDeactivate
OnHide
OnDestroy |
1. Updating Cursor immediately
{
For example, if I change my cursor to a waiting
clock cursor before some time-consuming operations
is executed, why isn't my waiting clock cursor
activated immediately? It's only activated after
the event! This peace of code will update cursor
immediately.
}
begin
Try
Screen.Cursor:=crHourGlass;
MyDataForm := TMyDataForm.Create(Application);
Screen.Cursor:=crDefault;
MyDataForm.ShowModal;
MyDataForm.Free;
Finally
Screen.Cursor:=crDefault;
end;
end; |
http://www.zdjournals.com/ddj/
http://www.zdjournals.com/ddj/https://secure.zdjournals.com/ddj/cbw13m.htm
https://secure.zdjournals.com/ddj/cbw13m.htm
by Lee Inman
Does the thought of creating applications for multiple foreign markets make you cringe? Do you worry about extreme development times and endless searching and replacing? If so, read on. This article will show you how to get your application ready for the international market without months of development time. Adhering to a few simple guidelines during the application's development and having the right tools makes a world of difference.
You internationalize your applications to prepare them for the international market. It's the process that enables your application to operate in multiple locales (the user's natural environment). This means that all of the strings displayed by the application must be translated, and that forms and dialogs need to be modified to display the translated strings properly. The ideal situation is one where you actually plan to internationalize an application early in the development process. If you fail to do so, a little more work will be required.
The most obvious internationalizing step is to translate, or localize, the strings that appear in your application. Your primary goal in preparing your application is to write it so that it can be translated without altering the code. At this stage, don't worry about the strings that are defined as form and component property values--we'll handle them later. You'll need to isolate strings, such as error messages and hints, that you present to the user. In fact, all literal strings in your application should be isolated. The easiest way to do this is by declaring constants for them using the resourcestring keyword:
resourcestring MouseError = `Error using the mouse'; KeyboardError = `Error using the keyboard';
Using the resourcestring keyword to define strings has the following benefits:
The resource file that Delphi automatically creates for the above example will contain a string table similar to this:
STRINGTABLE
{
65368, "Error using the mouse"
65369, "Error using the keyboard"
}
If possible, all strings should be isolated in a single unit. Placing the strings in a single unit will make your life easier when it's time to actually create different language versions. Once all strings have been isolated and your application's forms are defined, you can begin the process of localizing your application.
If your application wasn't designed with internationalization issues in mind, don't despair. It will just take a little work to get the job done. Start by searching for all literal strings and move them to a separate unit, where you define them using the resourcestring keyword as described in the previous section.
Isolating literal strings simplifies the translation process. The next step involves the creation of one or more resource DLLs. Delphi produces executables that can detect and load language-specific DLLs that contain internationalized versions of the application's resources (text strings, graphic images, forms, etc.) automatically! All you need to do is make sure that the correct information is placed in the DLLs. There's no special code to add to your application--Delphi determines the proper resource DLL to load each time the application is executed.
Delphi 4 makes this part a snap, because it generates the resource DLL, including copies of all your forms, and builds the string resource file for you. Use the Delphi 4 Resource DLL Wizard to create a resource DLL for your program. To invoke the Resource DLL Wizard, choose File | New from the Delphi main menu to display the Object Repository. On the New tab, double-click the Resource DLL Wizard Icon. The Resource DLL Wizard requires an open, saved, and compiled project. It will create an RC file that contains the string tables from used RC files and resourcestring strings of the project, and generate a project for a resource--only DLL that contains the relevant forms.
The first step you must take when using the Resource DLL wizard is to select which forms should be included in the resource DLL. Do this by selecting one or more forms and clicking the Add button. Then, click Next to select which resource file to include. If you defined string constants with the resourcestring keyword, you should see at least one resource file with an .rc extension. When you're finished selecting resource files, click Next to advance to the final wizard screen. The final wizard screen allows you to select the country, the filename, and the storage location for the generated DLL. After entering this information, click Finish and Delphi automatically creates and loads the resource DLL project. You should create a resource DLL for each locale you want to support. Each resource DLL should have a filename extension specific to the target locale. For example, the French version of your resources will be named PGMNAME.FRA, the German version PGMNAME.DEU, and so on. If you use the Resource DLL wizard, this is handled for you. Otherwise, use the code in Listing A to obtain the locale code for the target translation. The code in Listing A places the locale names and codes in a list box on the main form. You may need to modify it slightly to suit your specific needs.
Listing A: Target local code
function LocalesCallback(Locale : PChar) :Bool; stdcall; var LCID : Integer; Size : Integer; S : string; Ext : string; begin LCID := StrToInt(`$' + Copy(Locale, 5, 4)); //get name for this locale id Size := GetLocaleInfo(LCID, LOCALE_SLANGUAGE, nil, 0); SetLength(S, Size); //includes null GetLocaleinfo(LCID, LOCALE_SLANGUAGE, PChar(S), Size); //don't include null SetLength(S, Size - 1); //get locale code (file extension) Size := GetLocaleInfo(LCID, LOCALE_SABBREVLANGNAME, nil, 0); SetLength(Ext, Size); //includes null GetLocaleinfo(LCID, LOCALE_SABBREVLANGNAME, PChar(Ext), Size); //don't include null SetLength(Ext, Size - 1); //add to list if Ext > `` then Form1.lbLocales.Items.Add(Ext + ` - ` + S); Result := Bool(1); end; procedure TForm1.GetLocalesClick(Sender :TObject); begin EnumSystemLocales(@LocalesCallback, LCID_SUPPORTED); end;
PLACE THE PARAGRAPH BELOW IN A NOTE BOX Note: With versions of Delphi prior to version 4, you'll need to take a different approach to internationalization, and one that this article doesn't attempt to cover. If you're using an older version of Delphi, you'll need to create the resource DLLs manually. Unfortunately, the earlier versions of Delphi don't offer the Resource DLL Wizard.
At this point, your resources are isolated into one or more resource DLLs that contain DFM and RC files. You can open individual forms in the IDE and translate the relevant parts. First, open the RC files and translate relevant strings. Notice that all of the Delphi-defined string constants are automatically placed in the string resource file. Next, open each form file and edit it as you would normally. You can change the size and layout for forms and components, but not property values. Finally, edit each string resource file using Delphi's StringTable editor (by opening the resource file from the Project Manager), using the Delphi code editor, or by using a text editor, such as NotePad.
The executables, DLLs, and packages that make up your application contain all the necessary resources. However, to replace those resources by localized versions, you need only to ship your application with localized resource DLLs that have the same name as your EXE, DLL, or BPL files. When your application starts up, it automatically checks the locale of the local system. If it finds any resource DLLs with the same name as the EXE, DLL, or BPL files it's using, it checks the extension on those DLLs. If the extension of the resource module matches the language and country of the system locale, your application will use the resources in that resource module instead of the resources in the executable, DLL, or package. If there isn't a resource module that matches both the language and the country, your application will try to locate a resource module that matches just the language. If there's no resource module that matches the language, your application will use the resources compiled into the executable, DLL, or package.
If you need to load resources dynamically, use the global FindResourceHInstance function to obtain the handle of the current resource module, rather than using MainInstance or simply HInstance. Doing so insures that you'll use the proper module instance for the current locale (and load the resource from the appropriate resource DLL). For example, to load a bitmap resource:
Bitmap.Handle := LoadBitmap(FindResourceHInstance (HInstance),'SOMEIMAGE');
If you want your application to use a different resource module than the one that matches the locale of the local system, you can set a locale override entry in the Windows registry. Under the HKEY_CURRENT_USER\Software\Borland\Locales key, add your application's path and filename as a string value, and set the data value to the extension of your resource DLLs. At startup, the application will look for resource DLLs with this extension before trying the system locale. Setting this registry entry allows you to test localized versions of your application without changing the locale on your system. For example, the following procedure can be used in a test program to set the registry key value that indicates the locale to use when loading your Delphi application:
procedure SetLocaleOverrides(const FileName, LocaleOverride : string); var Reg: TRegistry; begin Reg := TRegistry.Create; try if Reg.OpenKey(`Software\Borland\Locales', True) then Reg.WriteString(FileName, LocaleOverride); finally Reg.Free; end; end; ... //test resources for France SetLocaleOverrides(ParamStr(0), `FRA');
To revert to the default resources, just set the LocalOverride parameter to an empty string or delete the added registry key (the path and filename of the project).
SetLocaleOverrides(ParamStr(0), ``);
Using this process, you can ship a single application that adapts itself automatically to the locale of the system it's running on, simply by providing the appropriate resource DLLs. To add support for additional locals, all you need to do is create another resource DLL and place it in the same directory as your application. Nothing could be easier.
Windows Programming
Delphi phones home
We based this article on code and techniques developed by Bill Hannan of Sparta, New Jersey.
Many people develop and use applications that manage data-bases of contact names and information. Some commercial personal information managers (PIMs) even let you dial a phone number in your database directly from your computer. In this article, we'll show you how to use a few Windows Application Programming Interface (API) calls to accomplish the same task.
This technique uses three Windows API functions. The openComm() function initializes a connection to the Com Port, the writeComm() function sends data to the Com Port, and the closeComm() function closes the connection. We'll use the openComm() function to create a handle to a Com Port, and then we'll send our dialing commands to that port using the writeComm() function. Finally, we'll close the connection using the closeComm() function.
The code for dialing the phone via the Windows API is shown in Figure A . When you call this procedure, simply pass a phone number (as a string), and the procedure will open a connection from the Com Port to the modem and send the commands to dial the specified number. After you've finished your call, the function closes the connection to the Com Port.
Figure A - You can use the dialPhone() function to automatically dial your modem.
procedure dialPhone(const numberToDial: String;
const commPort: String);
var
theHandle: Integer;
openErrMsg: String;
myBuffer: String;
dialString: array[0..79] of char;
port: array[0..10] of char;
begin
StrPCopy(port, commPort);
theHandle := openComm(port, 50 , 50);
if theHandle < 0 then
begin
case theHandle of
-1: openErrMsg := 'Bad Comm Port ID';
-2: openErrMsg :=
'Comm Port in use by another program';
-10: openErrMsg :=
'Comm Port Hardware Problem';
else
openErrMsg :=
'Unexpected error Opening Comm Port';
end;
showMessage(openErrMsg);
end
else
if MessageDlg('Dial '+numberToDial+
' on port ' + commPort + ' now?',
mtConfirmation, [mbYes, mbNo], 0) = mrYes then
begin
myBuffer := 'ATDT' + numberToDial + ';\r';
StrPCopy(dialString, myBuffer);
writeComm(theHandle,dialString,50);
application.processMessages;
showMessage('Click OK To Disconnect Modem');
writeComm(theHandle, '+++', 5);
writeComm(theHandle, 'ATH', 5);
end;
closeComm(theHandle);
end;
The code first opens the Com Port using the openComm() function. In this case, it specifies 50 input and 50 output character buffers. Next, it tests to see that the port opened. If the port didn't open, the code tests to see what error occurred, and then it reports the error.
If the port opened successfully, the code displays a message box asking the user to confirm the dial. If the user confirms the dial request, the code sends the dial command to the opened Com Port via the writeComm() function. Finally, another dialog box is displayed so that you can disconnect the modem from the call. When the modem disconnects, the code uses the writeComm() function again to reset the modem. Finally, the code uses the closeComm() function to close the opened Com Port.
In this article, we've shown how you can use the Windows API to dial a phone number. Using a few simple calls to the API, you can open, write to, and close communications ports on your computer from within your Delphi applications.
Ever wanted to hide files inside your application ? Well, it is possible.
Inprise does actually ship an editor with delphi which is capable of compiling any file in to a resource. The name of this compiler (In delphi 4 anyway) is BRCC32.EXE and can be found in the \program files\borland\delphi4\bin directory.
I will now give an example of how to embed your files, and then how to use these files.
clouds rcdata c:\windows\clouds.bmp
You now have a file called MyRes.Res. Clouds is your ID for the resource item, rcdata tells the compiler that this is a binary file, and the last paramter is the file you want included. You may have as many lines as you like in your RC file, as long as the ID is unique.
{$R *.DFM}
You need to change this to
{$R *.DFM}
{$R MyRes.Res}
procedure TForm1.FormCreate(Sender: TObject);
var
//We need a stream to read our resource
RS : TResourceStream;
begin
//Open resource item named "Clouds"
RS := TResourceStream.Create(HInstance,'Clouds',RT_RCDATA);
try
//Load our Image from our ResourceStream
Image1.Picture.Bitmap.LoadFromStream(RS); //Load the bitmap from our stream
finally
//Free the memory used for our stream
RS.Free;
end;
end; |
procedure TForm1.FormCreate(Sender: TObject);
var
//Obviously we need our Resource Stream
RS : TResourceStream;
//Also we need a File stream to write to disk with
FS : TFileStream;
begin
//Open our resource
RS := TResourceStream.Create(HInstance,'Clouds',RT_RCDATA);
//Create our file
FS := TFileStream.Create('c:\newfile.bmp', fmCreate);
try
//Copy from Resource to Disk
FS.CopyFrom(RS,RS.Size);
finally
FS.Free;
RS.Free;
end;
end; |
Dateline: 01/26/99
We know that, generally, pressing the Tab key moves the input focus to next control and Shift-Tab to previous in the tab order of the form. When working with Windows applications, most users intuitively expect the Enter key to behave like a Tab key.
Over the past few years, I've seen a lot of third-party code for implementing better data entry processing in Delphi. In this article, I'll try to bring you the best methods I have found (with some modifications of my own).
Examples below are written with assumption that there is no default button on the form. When your form contains a button whose Default property is set to True, pressing Enter at runtime executes any code contained in the button's OnClick event handler.
Solutions
First modification
procedure TForm1.Edit1KeyPress (Sender: TObject; var Key: Char); begin If Key = #13 Then Begin If HiWord(GetKeyState(VK_SHIFT)) <> 0 then SelectNext(Sender as TWinControl,False,True) else SelectNext(Sender as TWinControl,True,True); Key := #0 end; end; |
Second modification
procedure TForm1.DBGrid1KeyPress (Sender: TObject; var Key: Char); begin If Key = #13 Then Begin If HiWord(GetKeyState(VK_SHIFT)) <> 0 then begin with (Sender as TDBGrid) do if selectedindex > 0 then selectedindex := selectedindex - 1 else begin DataSource.DataSet.Prior; selectedindex := fieldcount - 1; end; end else begin with (Sender as TDBGrid) do if selectedindex < (fieldcount - 1) then selectedindex := selectedindex + 1 else begin DataSource.DataSet.Next; selectedindex := 0; end; end; Key := #0 end; end |