• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Delphi精要

原作者: [db:作者] 来自: [db:来源] 收藏 邀请
最近到图书馆里借了一本Delphi好书-《*Delphi精要*》。说实在的,国内的
Delphi书有95%是垃圾,   大都是网上的技巧,代码堆积起来的,通常一本书30分
钟就可以搞定。但是这本技术书写得有点武侠  
版的味道,而且都是作者切身的经验体会,可以和我先前看过的 台@@湾 的牛人陈宽达
的《Delphi深度历险》  
相提并论。好书当然要做笔记了,以下就是俺的看书笔记。  

1.集合  
定义  
TOneSet= set of (A,B,C);//全集  
声明  
partSet=[A,B];  
运算  
+:  
partSet=partSet+[B];//等价于:Include(partSet,B);  
-:  
partSet=partSet-[B];//等价于:Exclude(partSet,B);  

2.指针  
除了pchar类型的指针变量,其他类型的指针变量是不允许进行加减运算的  
@I等价于addr(I)  

3.编译时函数:  
编译时函数可以在声明中调用如下:  
var  
  R1:Word=Trunc(12.6);  
编译时函数列表:  
ord()  
chr()  
Trunc()  
Round()  
High()  
Low()  
SizeOf()  

4.DLL  
  1)在DLL中编写的函数或过程都必须加上stdcall调用参数.  
    
library Delphi;   
uses   
SysUtils,   
Classes;   
function TestDll(i:integer):integer;stdcall;   
begin   
    Result:=i;   
end;   
exports   
   TestDll;   
begin   
end.   
  2)当使用了长字符串类型的参数、变量时要引用ShareMem。    
    Delphi中的string类型很强大,我们知道普通的字符串长度最大为256个字
符,但Delphi中string类型在默认情况下长度可以达到2G。(对,您没有看错,确
实是两兆。)这时,如果您坚持要使用string类型的参数、变量甚至是记录信息
时,就要引用ShareMem单元,而且必须是第一个引用的。既在uses语句后是第一个
引用的单元。如下例:   
uses   
ShareMem,   
SysUtils,   
Classes;    
    还有一点,在您的工程文件(*.dpr)中而不只是单元文件(*.pas)中也要做
同样的工作,这一点Delphi自带的帮助文件没有说清楚,造成了很多误会。不这样
做的话,您很有可能付出死机的代价。避免使用string类型的方法是将string类型
的参数、变量等声明为Pchar或ShortString(如:s:string[10])类型。同样的问
题会出现在当您使用了动态数组时,解决的方法同上所述。  
  3)静态调用例子:  
unit Unit1;   
interface   
uses   
Windows, Messages, SysUtils, Classes, Graphics,   
Controls, Forms, Dialogs, StdCtrls;   
type   
   TForm1 = class(TForm)   
   Edit1: TEdit;   
   Button1: TButton;   
procedure Button1Click(Sender: TObject);   
private   
...{ Private declarations }   
public   
...{ Public declarations }   
end;
   
var   
    Form1: TForm1;   
implementation   
...{$R *.DFM}   
//本行以下代码为我们真正动手写的代码   
function TestDll(i:integer):integer;stdcall;   
external ’Delphi.dll’;   
procedure TForm1.Button1Click(Sender: TObject);   
begin   
    Edit1.Text:=IntToStr(TestDll(1));   
end;   
end.   
4)动态调用:  
这一点很重要,使用静态调用方法时要求所调用的DLL文件以及要调用的函数或过
程等等必须存在。如果不存在或指定的路径和文件名不正确的话,运行主程序时系
统会提示“启动程序时出错”或“找不到*.dll文件”等运行错误。   
                      
    动态调用DLL相对复杂很多,但非常灵活。为了全面的说明该问题,这次我们
举一个调用由C++编写的DLL的例子。首先在C++中编译下面的DLL源程序。   
#include   
extern ”C” _declspec(dllexport)   
int WINAPI TestC(int i)   
...{   
    return i;   
}    
    编译后生成一个DLL文件,在这里我们称该文件为Cpp.dll,该DLL中只有一个
返回整数类型的函数TestC。为了方便说明,我们仍然引用上面的调用程序,只是
将原来的Button1Click过程中的语句用下面的代码替换掉了。   
procedure TForm1.Button1Click(Sender: TObject);   
type   
TIntFunc=function(i:integer):integer;stdcall;   
var   
    Th:Thandle;   
    Tf:TIntFunc;   
    Tp:TFarProc;   
begin   
    Th:=LoadLibrary(’Cpp.dll’); ...{装载DLL}   
    if Th>0 then   
    try   
       Tp:=GetProcAddress(Th,PChar(’TestC’));   
       if Tp<>nil   
       then  
       begin   
           Tf:=TIntFunc(Tp);   
           Edit1.Text:=IntToStr(Tf(1)); ...{调用TestC函数}   
       end   
      else   
          ShowMessage(’TestC函数没有找到’);   
   finally   
     FreeLibrary(Th); ...{释放DLL}   
   end   
else   
   ShowMessage(’Cpp.dll没有找到’);   
end;   
5)  
一、编写技巧。    
    1 、为了保证DLL的正确性,可先编写成普通的应用程序的一部分,调试无误
后再从主程序中分离出来,编译成DLL。    
    2 、为了保证DLL的通用性,应该在自己编写的DLL中杜绝出现可视化控件的名
称,如:Edit1.Text中的Edit1名称;或者自定义非Windows定义的类型,如某种记
录。    
    3 、为便于调试,每个函数和过程应该尽可能短小精悍,并配合具体详细的注
释。    
    4 、应多利用try-finally来处理可能出现的错误和异常,注意这时要引用
SysUtils单元。    
    5 、尽可能少引用单元以减小DLL的大小,特别是不要引用可视化单元,如
Dialogs单元。例如一般情况下,我们可以不引用Classes单元,这样可使编译后的
DLL减小大约16Kb。   
二、调用技巧。    
    1 、在用静态方法时,可以给被调用的函数或过程更名。在前面提到的C++编
写的DLL例子中,如果去掉extern ”C”语句,C++会编译出一些奇怪的函数名,原来
的TestC函数会被命名为@TestC$s等等可笑的怪名字,这是由于C++采用了C++
 name mangling技术。这个函数名在Delphi中是非法的,我们可以这样解决这个问
题:   
改写引用函数为   
function TestC(i:integer):integer;stdcall;   
external ’Cpp.dll’;name ’@TestC$s’;   
其中name的作用就是重命名。    
    2 、可把我们编写的DLL放到Windows目录下或者Windowssystem目录下。这样
做可以在external语句中或LoadLibrary语句中不写路径而只写DLL的名称。但这样
做有些不妥,这两个目录下有大量重要的系统DLL,如果您编的DLL与它们重名的话
其后果简直不堪设想,况且您的编程技术还不至于达到将自己编写的DLL放到系统
目录中的地步吧!   
三、调试技巧。    
    1 、我们知道DLL在编写时是不能运行和单步调试的。有一个办法可以,那就
是在Run|parameters菜单中设置一个宿主程序。在Local页的Host Application栏
中添上宿主程序的名字就可进行单步调试、断点观察和运行了。    
    2 、添加DLL的版本信息。开场白中提到了版本信息对于DLL是很重要的,如果
包含了版本信息,DLL的大小会增加2Kb。增加这么一点空间是值得的。很不幸我们
如果直接使用Project|options菜单中Version选项是不行的,这一点Delphi的帮助
文件中没有提到,经笔者研究发现,只要加一行代码就可以了。如下例:   
library Delphi;   
uses   
SysUtils,   
Classes;   
...{$R *.RES}   
//注意,上面这行代码必须加在这个位置   
function TestDll(i:integer):integer;stdcall;   
begin   
    Result:=i;   
end;   
exports   
   TestDll;   
begin   
end.    
    3 、为了避免与别的DLL重名,在给自己编写的DLL起名字的时候最好采用字符
数字和下划线混合的方式。如:jl_try16.dll。    
    4 、如果您原来在Delphi 1或Delphi 2中已经编译了某些DLL的话,您原来编
译的DLL是16位的。只要将源代码在新的Delphi 3或Delphi 4环境下重新编译,就
可以得到32位的DLL了。   
[后记]:除了上面介绍的DLL最常用的使用方法外,DLL还可以用于做资源的载体。
例如,在Windows中更改图标就是使用的DLL中的资源。另外,熟练掌握了DLL的设
计技术,对使用更为高级的OLE、COM以及ActiveX编程都有很多益处。 

 ======================================================== 
14:36 2005-11-30  

1.操作有序变量的函数:  
Ord()  
Pred()  
Succ()  
High()  
Low()  

2.Boolean类型  
Boolean//一个字节  
...{以下四个是用以兼容操作系统的}  
ByteBool//一个字节  
WordBool//两个字节  
LongBool//四个字节  

3.枚举和子界  
TColors=(Red,Blue=5,Green,Yellow,Orange,Purple);  
TMyColors=Green..Purple;  

4.Real  
声明变量时用Double和Single,在用做参数传递时用Extended.  

5.过程类型和方法类型  
Type  
...{过程类型:}  
TMyFunction = function(参数列表):返回类型;  
TMyProcedure = procedure()(参数列表);  
...{方法类型:}  
TNotifyEvent= procedure(Sender:TObject) of object;  

6.Variant类型  
Variant类型有三个状态:Unassigned,Null,非Null  

7.类型别名  
type DWORD =LongWord;//任何时刻DWORD和LongWord都是相容的  
type   
  HWND = type LongWord;//用于var和out参数等要求严格类型匹配的地方时,被
认为不兼容  

========================================================  
21:23 2005-12-8  

1.变体记录  
type  
  TMessage= 
  packed record//Using packed slows data access and, in the case of a character          array, affects type compatibility (for more information,   

    msg:Cardinal;  
    case Integer of  
  0:(  
    WParam:Longint;  
    LParam:Longint;  
    Result:LongInt;  
  );  
  1:(  
   WParamLo:word;  
   WParamHi:word;  
   LParamLo:word;  
   LParamHi:word;  
   ResultLo:word;  
   ResultHi:word;  
  );  
end;  
以上是vcl消息定义  
typedef struct ...{  
    HWND hwnd;  
    UINT message;  
    WPARAM wParam;  
    LPARAM lParam;  
    DWORD time;  
    POINT pt;  
} MSG, *PMSG;  
系统消息结构定义  

2.vcl中两种消息派遣   
      
    vcl消息机制的整个流程如下:  
Windows->Delphi Application->(TWinControl)MainWndProc->WndProc->Dispatch->Handler   
(1)Application->dispatchMessage(const lpMsg:TMsg)根据参数lpMsg的接受者句
柄字段,将消息正文发给该句柄对应的窗口控件在windows中注册的窗口过程:
Twincontrol.MainWndProc.所以到这里,消息就传递给Twincontrol了。这是在
Windows中派遣,是底层Api函数的调用。   
 (2)TObject.Dispatch(var Message);  
  Dispatch首先在本类中查找相应的消息方法,如果没有找到,那么逐级上溯父
类,祖先类,直到找到对应的消息方法。  
  procedure Tobject.Dispatch(var Message)  
  begin  
      搜索Handler;  
      如果没有找到就调用DefaultHandler(var Message);  
  end;  

========================================================  
 19:40 2005-12-9  

1.发送消息的多种方法  

1).给指定窗口发送消息  
 给窗口发送消息:  
  function SendMessage(hWnd:HWND;Msg:UINT;wParam:WParam;lParam:LParam):LRESULT;stdcall;  

 //That is, SendMessage does not return until the target control has handled the message, even if it //is in another thread.  

  function DispatchMesage(const lpMsg:TMsg):Longint;stdcall;  
------------------------------------------------------------------------------  

  function PostMessage(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LParam):Bool;stdcall;  


2) 给应用程序发送消息:  
  function SendAppMessage(Msg:Cardinal;wParam,lParam:Longint);  

3) 给线程发送消息  
  function PostThreadMessage(idThread:DWORD;Msg:UINT;wParam:WPARAM;lParam:LPARAM):BOOL;stdcall;  

  获取idThread可用Api函数得:  
  function GetWindowThreadProcessId(hWnd:HWND;lpdwProcessId:Pointer=nil):DWORD;stdcall;overload;  

  function GetWindowThreadProcessId(hWnd:HWND;var dwProcessId:DWORD):DWORD;stdcall;overload;   
    今天郁闷啊,去玩魔兽输了两盘,好没面子,以后不玩了,魔兽bye了!虽然
你很完美,但是与你无缘了,但是我盼望着在未来的某一天我可以开发一款像你这
样的游戏!加油,加油,继续加油!  

========================================================  
2005-12-12  

1.字符串资源  
resourcestring  
  AuthorName = ’Marco Cantù’;  
  BookName = ’Essential Pascal’;  
procedure TForm1.Button1Click(Sender: TObject);  
begin  
    ShowMessage (BookName + #13 + AuthorName);  
end;  
以上代码中的两个字符串将分两行输出显示,因为字符串被分行符 #13 隔开。  
有趣的是,当你用资源编辑器打开执行文件时,你会在程序资源中看到你所定义的
字符串。这意味着字符串并没有进入编译代码,而是保存在执行文件 (EXE文件) 
的一个单独区域。  
注意:简而言之,采用资源的好处一方面可让Windows 来完成有效的内存处理,另
一方面不用更改源代码就可实现程序的本地化 (把字符串翻译成不同的语言)。   

2.位操作  
type TIntBitPos=0..31;  

//取得一个Integer中的某位  
function GetBitOfInt(I:integer;BitPos:TIntBitPos):Boolean;  
begin  
  result:=(I shr BitPos) and $1=1;  
end;  
//替换一个Integer的某位  
procedure ReplaceBitOfInt(var I:integer;BitPos:TIntBitPos;NewValue:Boolean);  

var  
  newV:Integer;  
begin  
  if GetBitOfInt(I,BitPos)<>NewValue then  
  begin  
    if BitPos=0 then  
       NewV:=1;  
    else  
       NewV:=2 shl (BitPos-1);  
    if NewValue then  
       Inc(I,NewV)  
    else  
       Dec(I,NewV);    
  end;  
end;  

========================================================  
 11:27 2005-12-13  

1.自定义系统唯一消息  
UINT RegisterWindowMessage(LPCTSTR lpString);  
DWORD GetWindowThreadProcessId(HWND hWnd,  
    LPDWORD lpdwProcessId  
);  

例子:  
接收端  
AppReceive  
var  
  Id:dword;  
begin  
  mainform.newOneMessage(var Msg:TMsg;var Handled:Boolean);  
  begin  
    if Msg.message=Id then  
    begin  
       showMessage(’应用程序收到消息’);  
       handled:=true;  
    end;  
  end;  
  mainform.formcreate();  
  begin  
     caption:=’接受者’;  
     ID:=RegisterWindowMessage(PChar(’OneOfAppMessage’));  
  end;  
   
  mainform.WndProc(var Message:TMessage) override;  
  begin  
    inherited;  
    with Message do if Msg=Id then  
    begin  
       showMessage(’主窗体收到消息’);  
       result:=0;  
    end;  
  end;  
end;  
发送端  
AppSend  
var  
  Id:dword;  
begin  
  mainform.formcreate();  
  begin  
     caption:=’发送者’;  
     ID:=RegisterWindowMessage(Pchar(’OneOfAppMessage’));  
  end;  
   
  mainform.button1Click(sender.Tobject);  
  begin  
     H:=FindWindow(nil,pchar(’接受者’));  
     if H<>0 then  
     begin  
        sendMessage(H,ID,0,0);  
        PostThreadMessage(GetWindowThreadProcessId(H),ID,0,0);  
    end;  
  end;  
end; 
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/pottos/archive/2007/03/13/1528397.aspx

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Delphi 操作Word(统计字数) - ╰★张志峰★╮发布时间:2022-07-18
下一篇:
DelphiByte数组与IntString之间的相互转换发布时间:2022-07-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap