📄 zmisc3.htm
字号:
<!-- This document was created with HomeSite v2.0 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<TITLE>UDDF - Misc</TITLE>
<META NAME="Description" CONTENT="Miscellaneous section of the Delphi Developers FAQ" >
<META NAME="KeyWords" CONTENT="" >
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<CENTER>
<IMG SRC="../images/uddf.jpg"> </CENTER>
<HR SIZE="6" color="#00FF00">
<CENTER><FONT SIZE="7" FACE="Arial Black" COLOR="RED">Miscellaneous Part 3</FONT></CENTER>
<P><H1><A NAME="zmisc30">Avoiding using stale pointers</P></A></H1>
<P><I>"David S. Becker" <dsb@plaza.ds.adp.com></I></P>
I've written a very simple unit, and devised some simple methods, to help
prevent the usage of stale pointers. My biggest recommendation is to add
an 'initialization' section to ALL UNITS WHICH CONTAIN POINTER OR OBJECT
VARIABLES and set all the pointers (object variables are really pointers
too) to nil. This will ensure that the pointers are all nilified before
they are ever used. Then, simply reset pointers to nil after freeing them.
My unit contains a Nilify() function for setting pointers to nil, as well
as special versions of Free, Dispose, and FreeMem (called NilXXX) which
test for nil before freeing memory, and resets the pointer to nil once it
has been freed. I've also included a special version of Assigned(), called
IsNil(), which takes a const parameter instead of a var parameter, which
means you can use it on properties, etc. <P>
This unit, of course, does nothing to the VCL, so you can still get stale
pointers back from the VCL... But strict adherence to the functions in
this unit should help ensure YOU don't make a mistake. The only condition
on its use/distribution is that you forward any changes or suggestions you
might have to me. Use it and program in good health! <P>
<HR><PRE>unit Pointers;
{
Author: David S. Becker (dsb@plaza.ds.adp.com)
Date: 1/27/97
Copyright: None
Distribution Rights: Free, unlimited use, provided you forward any and all
changes or suggestions you have to me.
This unit was created to aid in the managment of pointers and objects. Since
the compiler does not initialize pointers or objects to nil, and does not set
them to nil when freed, it is possible to accidentally reference stale
pointers. For this reason, I recommend you add an 'initialization' section to
all units and call Nilify() on all pointers/objects in that unit. This
will ensure that all pointers/objects start off as nil. Furthermore, you
should use the NilFree (for objects), NilDispose (for pointers created with
New), and NilFreeMem (for pointers created with GetMem) instead of their
standard counterparts. These procedures are safe to call on nil pointer/
objects, as they check for nil before performing any action. After freeing
the memory allocated to the pointer/object, they reset the pointer to nil. If
you are strict in your use of these procedures, your risk of accessing stale
pointer is greatly reduced. (Of course, you can still get stale pointers from
the VCL as it obviously doesn't use these functions.)
}
{==============================================================================}
interface
{------------------------------------------------------------------------------}
{ Checks a pointer against nil }
{ NOTE: This function differs from Assigned() in that Assigned() requires a }
{ variable, whereas IsNil() does not. }
function IsNil(const p: Pointer): Boolean;
{ Sets a pointer to nil }
procedure Nilify(var p);
{ Frees a non-nil object, then sets it to nil }
procedure NilFree(o: TObject);
{ Frees a non-nil pointer created by New, then sets it to nil }
procedure NilDispose(var p: Pointer);
{ Frees a non-nil pointer, then sets it to nil }
procedure NilFreeMem(var p: Pointer; size: Word);
{==============================================================================}
implementation
{------------------------------------------------------------------------------}
function IsNil(const p: Pointer): Boolean;
begin
Result := (p = nil);
end;
{------------------------------------------------------------------------------}
procedure Nilify(var p);
begin
Pointer(p) := nil;
end;
{------------------------------------------------------------------------------}
procedure NilFree(o: TObject);
begin
if not IsNil(o) then begin
o.Free;
Nilify(o);
end;
end;
{------------------------------------------------------------------------------}
procedure NilDispose(var p: Pointer);
begin
if not IsNil(p) then begin
Dispose(p);
Nilify(p);
end;
end;
{------------------------------------------------------------------------------}
procedure NilFreeMem(var p: Pointer; size: Word);
begin
if not IsNil(p) then begin
FreeMem(p,size);
Nilify(p);
end;
end;
end.
</PRE><HR>
<P><H1><A NAME="zmisc31">Multi Language Applications</P></A></H1>
<P><I>Eddie Shipman <eshipman@inetport.com></I></P>
For anyone needing to do multi-language apps and don't want to
write a lot of code checking what language the program is
running, see below. I compiled a stringtable resource into my exe and
this is how I used it for multi-language dialogs. <P>
Instead of using the Runtime directives to check what language, I used a
runtime
variable to set the index for the messages into the stringtable and then
load the
messages from there depending upon the language.
You could also create different stringtables for each language and then
compiling
them in by using the compile directives. <P>
Here is some example code, give it a try: <P>
<HR><PRE>unit French1;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls, IniFiles;
type
TForm1 = class(TForm)
Button1: TButton;
procedure FormActivate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
StringIndex : Integer;
implementation
{$R *.DFM}
{$R MULTLANG.RES}
{ Here is the way the resource file for this project looks:
1, "Attention"
2, "No Condition definition selected!"
3, "Always"
4, "Cannot delete the 'always' condition."
5, "Confirmation"
6, "Delete the condition?"
7, "Yes"
8, "No"
9, "Attention"
10, "Pas de condition Selectionn閑"
11, "Toulours"
12, "Ne peux effacer la condition 'Toujours'"
13, "Confirmation"
14, "Effacer cette condition?"
15, "&Oui"
16, "&Non"
}
procedure TForm1.FormActivate(Sender: TObject);
var
{inifile : TIniFile; Optional}
ProgramLanguage : String;
begin
{ Here, I just set it to French }
ProgramLanguage := 'fra';
{ You can optionally get the language from Win.INI:}
{inifile := TInifile.Create('WIN.INI');
ProgramLanguage := inifile.ReadString('intl', 'sLanguage', 'enu');
inifile.Free;}
{ Forgive me if I leave out any languages, Tthese are th only ones
in my setup.inf for my copy of Windows.
dan = Danish
nld = Dutch
enu = English (American)
eng = English (International)
fin = Finnish
fra = French
frc = French Canadian
deu = German
isl = Icelandic
ita = Italian
nor = Norwegian
ptg = Portuguese
esp = Spanish
esn = Spanish (Modern)
sve = Swedish
}
if ProgramLanguage = 'enu' then
begin
StringIndex := 0;
end
else
if ProgramLanguage = 'fra' then
begin
StringIndex := 8;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
i,j,k : integer;
DialogForm : tform;
begin
Application.NormalizeTopMosts;
{no Condition Selected!}
DialogForm := CreateMessageDialog(LoadStr(StringIndex+2),mtWarning,[mbOK]);
{Attention}
DialogForm.caption := LoadStr(StringIndex + 1);
DialogForm.showmodal;
Application.RestoreTopMosts;
{Cannot Delete the 'always' condition}
DialogForm := CreateMessageDialog(LoadStr(StringIndex+4),mtWarning,[mbOK]);
{Always}
DialogForm.caption := LoadStr(StringIndex + 3);
DialogForm.showmodal;
Application.RestoreTopMosts;
{Delete the condition?}
DialogForm := CreateMessageDialog(LoadStr(StringIndex+6),mtInformation, [mbYes, mbNo]);
{confirmation}
DialogForm.caption := LoadStr(StringIndex + 5);
for j := 0 to DialogForm.controlCount-1 do
begin
if DialogForm.controls[j] is tButton then
with tButton(DialogForm.controls[j]) do
begin
if caption = '&Yes' then caption := LoadStr(StringIndex+7);
if caption = '&No' then caption := LoadStr(StringIndex+8);
end;
end;
DialogForm.showmodal;
end;
end.
</PRE><HR>
<P><H1><A NAME="zmisc32">Associated Executable</P></A></H1>
<P><I>Michael Ax <ax@HREF.COM></I></P>
<HR><PRE>unit UcShell;
{ Author: Michael Ax http://www.axsystems.com/
Copyright (c) 1995..1997 Michael Ax. All Rights Reserved.
This source code is part of TPack from HREF Tools Corp.
Obtain purchasing and additional information by sending an email to
software@href.com (any subject, any message)...
or visit us on the web at http://www.href.com/software/
}
interface
uses Classes, SysUtils, Windows, ShellApi, Forms;
{---------------------------------------------------------------}
function WinExecutableName(const AssociatedFile:string):String;
procedure WinShellOpen(const AssociatedFile:string);
procedure WinShellPrint(const AssociatedFile:string);
procedure WinShellExecute(const Operation,AssociatedFile:string);
{---------------------------------------------------------------}
implementation
Const
cStrBufSize= 80;
{---------------------------------------------------------------}
function WinExecutableName(const AssociatedFile:string):String;
//HINSTANCE FindExecutable(
// LPCTSTR lpFile, // pointer to string for filename
// LPCTSTR lpDirectory, // pointer to string for default directory
// LPTSTR lpResult // pointer to buffer for string for executable file
on return
// );
begin
SetLength(result,cStrBufSize); //ucshell
FindExecutable(pchar(AssociatedFile),'',pchar(result));
SetLength(result,strlen(pchar(result)));
end;
//
procedure WinShellExecute(const Operation,AssociatedFile:string);
var
a1:string;
begin
a1:=Operation;
if a1='' then
a1:='open';
ShellExecute(
application.handle //hWnd: HWND
,pchar(a1) //Operation: PChar
,pchar(AssociatedFile) //FileName: PChar
,'' //Parameters: PChar
,'' //Directory: PChar
,SW_SHOWNORMAL //ShowCmd: Integer
);
// GetLastErrorString(0); //ucdialog
end;
procedure WinShellPrint(const AssociatedFile:string);
begin
WinShellExecute('print',AssociatedFile);
end;
procedure WinShellOpen(const AssociatedFile:string);
begin
WinShellExecute('open',AssociatedFile);
end;
{-----------------------------------------------------------------}
end.
</PRE><HR>
<P><H1><A NAME="zmisc33">MAPI and MS Exchange</P></A></H1>
<P><I>Keith Anderson <keith@PURESCIENCE.COM></I></P>
Use the following to login:
<HR><PRE> MapiLogon(application.handle,nil,nil,mapi_use_default,0,@mapihandle)</PRE><HR>
Then use the following to send your message:
<HR><PRE> MapiSendMail(mapihandle, 0,MapiMessage,0, 0);</PRE><HR>
Make sure the SUBJECT, RECIP and NOTTEXT fields are complete in the
MapiMessage structure or the message won't be sent. <P>
Also make sure Exchange is running using the GetWindowHandle API function,
and if it's not, use ShellExecute (or whatever) to launch it first.
<P><H1><A NAME="zmisc34">Constucting Object Variables</P></A></H1>
<P><I>From: richardp@calweb.com (Coyote)</I></P>
In the past few days there have been more than a few questions on this
group indicating a lack of understanding about object instantiation. I'm
guessing that these have been beginners, but in one case the questioner
was taking a class on Delphi. I'd hope that an instructor would at least
*try* to explain the subject. <P>
Anyway, for all of you having pointer errors, exceptions, and GPFs, take
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -