立體字屏保

电脑桌面单击右键选"属性" 然后在弹出的框上选"屏幕保护程序" 然后在"屏幕 保护程序(S)"选择"三维文字" 然后再在弹出的框内自定义文字一栏填写自己想设为屏保的字,确定--应用就行了

posted @ 2006-06-21 11:14 青蛙學堂 阅读(455) | 评论 (0)编辑 收藏

Eclipse环境的下载和安装

Eclipse 环境的下载和安装

1 、安装 jdk

首先要创建一个 java 的工作环境,在 sun 的网站上下载 j2se ,安装到自己的系统中,我下载的是 1.4 版本,安装目录为“ D:\j2sdk1.4.2_04 ”。

下载地址: http://java.sun.com/j2se/1.4.2/download.html

设置环境参数

右键“我的电脑”-“属性”-“高级”-“环境变量”

增加:

java_home D:\j2sdk1.4.2_04\

Classpath d:\j2sdk1.4.2_04\;d:\j2sdk1.4.2_04\lib\tools.jar;d:\j2sdk1.4.2_04\lib\dt.jar;d:\j2sdk1.4.2_04\bin

Path d:\j2sdk1.4.2_04\bin\

环境就设置好了。

2 、下载 Eclipse 及插件

Eclipse 可以在它的主页下载:

http://www.eclipse.org/downloads/index.php

 

我们除了下载 Eclipse Platform SDK 3.0.1 外,还要下载 Eclipse Tools Project 中的 EMF GEF VE ,读者可以自己下载别的工具,但是这几个是必下的。 EMF 插件为很多其它插件所使用,特别是我们经常用到 Lomboz 插件写 J2EE 时, J2EE 环境在以后介绍。 GEF 是为 Eclipse 提供一个图形编辑的框架,而 VE 则提供了图形化编程的环境。

下载可得到了几个压缩包。

3 、安装 Eclipse

将下载的 Eclipse 的压缩包解压,解压后即可使用。但是前提是之前 jdk 环境已经设置好。(见上文)

我将它解压至 e:\eclipse

 

然后双击 eclipse 图标即可运行,界面如下:

是不是很漂亮啊。

点开 window preferences ,设置如图,设置好后点 Apply ,即可。

这样就好。

我们来使用它编第一个程序。

新建一个 java 项目。

再新建一个 Class,如下

 

点击 Finish 完成。

然后添加代码:

 

然后点击 Run Run as… 2.Java Aplication ,可看到结果:

4 、安装插件

这里以 GEF 插件为例子。

GEF 的压缩包解压,可得到 features plugins 文件夹。

第一种安装方法,是将这两个文件夹的内容直接拷贝到 eclipse 安装文件夹的相关目录下,然后再删除 eclipse 安装目录下的 configuration 中的 org.eclipse.update 目录,即可。

但是这种安装方法不便于管理,安装的插件多了不便维护,所以我们通常采用第二种安装方法。

第二种安装的方法 Link 的方法。

GEF 压缩包解压在自己定义的一个目录里,我解压到 e:\plugins\gef 目录,在 gef 目录中建立一个 eclipse 目录,然后将 features plugins 目录拷贝到这个 eclipse 目录中。因为在 link 的时候, Eclipse 会寻找解压目录中的 eclipse 目录,然后在该目录中读取 features plugins 目录。如图:

然后删去 Eclipse 安装目录下的 configuration 目录,建立 links 目录,在 links 目录中建立 gef.link 文件,在文件中指出 gef 解压的目录,如图:

 

注意, gef.link 文件的文件名可以任意取,便于自己维护为好。文件中使用的是“ / ”或者“ \\ ”。

这样, gef 就安装好了。

用同样的方法可以安装 emf ve ,装好后再次启动 Eclipse ,点击 File New Others… ,看到比以前没装插件多了些东西吧。

 

新建一个 java 项目

 

再建一个 Visual Class

点击finish,可以看到:

 

是不是很棒?

posted @ 2006-06-12 08:54 青蛙學堂 阅读(347) | 评论 (0)编辑 收藏

IniFile

{
  
  [Section_Name]
  Key_Name1=Value1
  Key_Name2=Value2
  
}

uses
  IniFiles;

// Write values to a INI file

procedure TForm1.Button1Click(Sender: TObject);
var
  ini: TIniFile;
begin
  // Create INI Object and open or create file test.ini
  ini := TIniFile.Create('c:\MyIni.ini');
  try
    // Write a string value to the INI file.
    ini.WriteString('Section_Name', 'Key_Name', 'String Value');
    // Write a integer value to the INI file.
    ini.WriteInteger('Section_Name', 'Key_Name', 2002);
    // Write a boolean value to the INI file.
    ini.WriteBool('Section_Name', 'Key_Name', True);
  finally
    ini.Free;
  end;
end;


// Read values from an INI file

procedure TForm1.Button2Click(Sender: TObject);
var
  ini: TIniFile;
  res: string;
begin
  // Create INI Object and open or create file test.ini
  ini := TIniFile.Create('c:\MyIni.ini');
  try
    res := ini.ReadString('Section_Name', 'Key_Name', 'default value');
    MessageDlg('Value of Section:  ' + res, mtInformation, [mbOK], 0);
  finally
    ini.Free;
  end;
end;

// Read all sections

procedure TForm1.Button3Click(Sender: TObject);
var 
  ini: TIniFile;
begin
  ListBox1.Clear;
  ini := TIniFile.Create('MyIni.ini');
  try
    ini.ReadSections(listBox1.Items);
  finally 
    ini.Free; 
  end;
end;

// Read a section

procedure TForm1.Button4Click(Sender: TObject);
var 
  ini: TIniFile;
begin
  ini: = TIniFile.Create('WIN.INI');
  try
    ini.ReadSection('Desktop', ListBox1.Items);
  finally
    ini.Free;
  end;
end;


// Read section values

procedure TForm1.Button5Click(Sender: TObject);
var
  ini: TIniFile;
begin
  ini := TIniFile.Create('WIN.INI');
  try
    ini.ReadSectionValues('Desktop', ListBox1.Items);
  finally 
    ini.Free;  
  end;
end;

// Erase a section

procedure TForm1.Button6Click(Sender: TObject);
var 
  ini: TIniFile;
begin
  ini := TIniFile.Create('MyIni.ini');
  try
    ini.EraseSection('My_Section');
  finally
    ini.Free;
  end;
end;

*****************************************************************8

谢谢楼上各位的回答。但我想大家可能理会错我的意思了。我的意思是:
假如我有一个文件Myini.ini,内容如下:
[AAA]
Test1=Test
Test2=Test
[BBB]
Test1=Test
Test2=Test
[CCC]
...=...
...

我想得到所有的小节的名称,即AAA、BBB和CCC,改怎么做呢?

************************************************************************

这么做:
1、声明一个var ini_file:TIniFile; sectionlist:Tstringlist;
2、创建  ini_file:=TIniFile.Create('这里是文件路径');
         sectionlist:=Tstringlist.create;  //存放所有section的name
3、ini_file.ReadSections(sectionlist);
至此,sectionlist这个list里面就是你要的section name了

***************************************************************

100、如何操作INI文件?  
INI 文件在系统配置及应用程序参数保存与设置方面,具有很重要的作用,所以可视化的编程一族,如 VB、VC、VFP、Delphi 等都提供了读写 INI 文件的方法,其中Delphi中操作 INI 文件,最为简洁,这是因为Delphi3提供了一个 TInifile 类,使我们可以非常灵活的处理 INI 文件。

一、有必要了解 INI 文件的结构:
;注释
[小节名]
关键字=值
...
INI文件允许有多个小节,每个小节又允许有多个关键字,“=”后面是该关键字的值。
值的类型有三种:字符串、整型数值和布尔值。其中字符串存贮在INI文件中时没有引号,布尔真值用1表示,布尔假值用0表示。
注释以分号“;”开头。

二、定义
1、在Interface的Uses节增加IniFiles;
2、在Var变量定义部分增加一行:
myinifile:Tinifile;
然后,就可以对变量myinifile进行创建、打开、读取、写入等操作了。

三、打开INI文件
myinifile:=Tinifile.create('program.ini');
上面这一行语句将会为变量myinifile与具体的文件program.ini建立联系,然后,就可以通过变量myinifile,来读写program.ini文件中的关键字的值了。

值得注意的是,如果括号中的文件名没有指明路径的话,那么这个Program.ini文件会存储在Windows目录中

把Program.ini文件存储在应用程序当前目录中的方法是:为其指定完整的路径及文件名。下面的两条语句可以完成这个功能:
Filename:=ExtractFilePath(Paramstr (0))+'program.ini'; myinifile:=Tinifile.Create(filename);

四、读取关键字的值
针对INI文件支持的字符串、整型数值、布尔值三种数据类型,TINIfiles类提供了三种不同的对象方法来读取INI文件中关键字的值。

假设已定义变量vs、vi、vb分别为string、integer、boolean类型。
vs:=myinifile.Readstring ('小节名','关键字',缺省值);
vi:=myinifile.Readinteger ('小节名','关键字',缺省值);
vb:=myinifile.Readbool ('小节名','关键字',缺省值);
其中缺省值为该INI文件不存在该关键字时返回的缺省值。

五、写入INI文件
同样的,TInifile类也提供了三种不同的对象方法,向INI文件写入字符串、整型数及布尔类型的关键字。
myinifile.writestring('小节名','关键字',变量或字符串值);
myinifile.writeinteger('小节名','关键字',变量或整型数值);
myinifile.writebool('小节名','关键字',变量或True或False);
当这个INI文件不存在时,上面的语句还会自动创建该INI文件。

六、删除关键字
除了可用写入方法增加一个关键字,Tinifile类还提供了一个删除关键字的对象方法:
myinifile.DeleteKey('小节名','关键字');

七、小节操作
增加一个小节可用写入的方法来完成,删除一个小节可用下面的对象方法:
myinifile.EraseSection('小节名');
另外Tinifile类还提供了三种对象方法来对小节进行操作:
myinifile.readsection('小节名' TStrings变量);可将指定小节中的所有关键字名读取至一个字符串列表变量中;
myinifile.readsections(TStrings变量);可将INI文件中所有小节名读取至一个字符串列表变量中去。
myinifile.readsectionvalues('小节名',TStrings变量);可将INI文件中指定小节的所有行(包括关键字、=、值)读取至一个字符串列表变量中去。

八、释放
在适当的位置用下面的语句释放myinifile:
myinifile.distory;

九、一个实例

下面用一个简单的例子(如图),演示了建立、读取、存贮INI文件的方法。myini.ini文件中包含有“程序参数”小节,和用户名称(字符串)、是否正式用户(布尔值)和已运行时间(整型值)三个关键字。程序在窗体建立读取这些数据,并在窗体释放时写myini.ini文件。

附源程序清单

unit Unit1;
interface

uses
Windows,Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, inifiles, StdCtrls, ExtCtrls;

type
TForm1=class(TForm)
Edit1:TEdit;
CheckBox1:TCheckBox;
Edit2:TEdit;
Label1:TLabel;
Label2:TLabel;
Timer1:TTimer;
Label3:TLabel;
procedureFormCreate(Sender:TObject);
procedureFormDestroy(Sender:TObject);
procedureTimer1Timer(Sender:TObject);

private
{Privatedeclarations}
public
{Publicdeclarations}
end;

var
Form1:TForm1;

implementation
var
myinifile:TInifile;
 
{$R*.DFM}

procedureTForm1.FormCreate(Sender:TObject);
var
filename:string;
begin
filename:=ExtractFilePath(paramstr(0))+'myini.ini';
myinifile:=TInifile.Create(filename);
edit1.Text:=myinifile.readstring ('程序参数','用户名称','缺省的用户名称');
edit2.text:=inttostr(myinifile.readinteger('程序参数','已运行时间',0));
checkbox1.Checked:=myinifile.readbool ('程序参数','是否正式用户',False);
end;

procedureTForm1.FormDestroy(Sender:TObject);
begin
myinifile.writestring('程序参数','用户名称',edit1.Text);
myinifile.writeinteger('程序参数','已运行时间',strtoint(edit2.text));
myinifile.writebool('程序参数','是否正式用户',checkbox1.Checked);
myinifile.Destroy;
end;

procedureTForm1.Timer1Timer(Sender:TObject);
begin
edit2.Text:=inttostr(strtoint(edit2.text)+1);
end;
end.

**************************************************************8
看看我的笨方法:

var
  slTemp:TStringList;
  iCount:Integer;
  sList:Array of String;
  sTemp:String;
begin
  slTemp:=TStringList.Create;
  slTemp.LoadFromFile('abc.ini');
  SetLength(sList,0);
  for iCount:=0 to slTemp.Count-1 do
  begin
    if (LeftStr(slTemp.Strings[iCount]<>'[') and (RightStr(slTemp.Strings[iCont]<>']') then Continue;
    SetLength(sList,Length(sList)+1);
    sList[High(sList)]:=slTemp.Strings[iCount];
  end;
end;


**************************



posted @ 2006-06-01 16:56 青蛙學堂 阅读(1092) | 评论 (0)编辑 收藏

delphi----IniFile

     摘要: 在 Windows 中的应用程序极大多数拥有自己的初始化文件,如 PowerBuilder、Office及Cstar等。因此 初始化文件的读写是每个高级程序员必须掌握的技术。虽然初始化文件的读写也可用 Object Pascal 中的文本文件一样读写,但因初始化文件不同于一般的文本文件,它有自己固定的格式(见下面的初始化文件是 ...  阅读全文

posted @ 2006-06-01 16:47 青蛙學堂 阅读(900) | 评论 (0)编辑 收藏

Edit File -- delhpi

1.AssignFile 过程
关联一个外部文件名到一个文件变量上。

单元
System

语法
procedure AssignFile(var F; FileName: string);

描述
调用AssignFile来初始化Delphi代码中的文件变量。F是一个任何文件类型的文件变量。FileName是一个字符串类型的表达式,或者,如果扩展的语法激活的话,是PChar类型的表达式。
调用AssignFile之后,F就和外部文件关联起来直到F被关闭。所有在文件变量F上的更多的操作都会操作在名为Filename的外部文件上。
当FileName参数为空时,AssignFile会将F和标准输入或标准输出文件关联起来。如果赋予一个空名字,在调用了Reset(F)之后,F将引用标准输入文件,而在调用了Rewrite(F)之后,F将引用标准输出文件。
不要在已经打开的文件变量上使用AssignFile。
注意:为了避免范围冲突,AssignFile 代替了在早期版本的Delphi产品中可用的Assign过程。然而为了向后兼容Assign仍然是可用的。
示例
var
F: TextFile;
S: string;
begin
if OpenDialog1.Execute then { Display Open dialog box }
begin
AssignFile(F, OpenDialog1.FileName); { File selected in dialog }
Reset(F);
Readln(F, S); { Read first line of file }
Edit1.Text := S; { Put string in a TEdit control }
CloseFile(F);
end;
end;

2.ChDir 过程
改变当前目录

单元
System

语法
procedure ChDir(const S: string); overload;
procedure ChDir(P: PChar); overload;

描述
ChDir 会将当前目录改变为由S或P指定的路径。如果这个操作失败,异常EInOutError将会引发。
在Windows上,路径可以包含驱动器指示符(drive specifier),而这将导致当前的驱动盘同时改变。
注意:在Delphi中,{$I+} 使用异常来处理运行时错误。当使用{$I-}时,要使用IOResult来检查I/O错误。
示例
begin
{$I-}
{ Change to directory specified in Edit1 }
ChDir(Edit1.Text);
if IOResult <> 0 then
MessageDlg('Cannot find directory', mtWarning, [mbOk], 0);
end;

3.CloseFile 过程
终止文件变量和外部磁盘文件之间的关联

单元
System

语法
procedure CloseFile(var F);

描述
由于命名冲突,CloseFile代替了Close过程。使用CloseFile过程而不是Close来终止文件变量和外部磁盘文件之间的关联。
F是一个使用Reset,Rewrite或Append打开的任何文件类型的文件变量。和F关联的外部文件会完全地更新然后关闭并释放文件句柄便于重用。
注意:{$I+} 使用异常来处理运行时错误。当使用{$I-}时,要使用IOResult检查I/O 错误。

4.CreateDir 函数
创建一个新目录
单元
SysUtils
语法
function CreateDir(const Dir: string): Boolean;
描述
CreateDir 创建一个新目录。如果新目录成功创建,则返回值为true,或者如果出现错误则返回值为false。
示例
下面的例子会创建目录'C:\temp',如果目录不存在的话。

uses FileCtrl;

procedure TForm1.Button1Click(Sender: TObject);
begin
if not DirectoryExists('c:\temp') then
if not CreateDir('C:\temp') then
raise Exception.Create('Cannot create c:\temp');
end;

5.DeleteFile 函数
从删除一个磁盘文件
单元
SysUtils
语法
function DeleteFile(const FileName: string): Boolean;
描述
DeleteFile 删除磁盘上由 FileName 命名的文件。如果文件不能被删除或者文件不存在,函数将返回false。
示例

if FileExists(FileName) then
if MessageDlg('Do you really want to delete ' + ExtractFileName(FileName) + '?'), mtConfirmation, [mbYes, mbNo], 0, mbNo) = IDYes then
DeleteFile(FileName);

6.DirectoryExists 函数
确定指定的目录是否存在
单元
SysUtils
语法
function DirectoryExists(const Directory: string): Boolean;
描述
调用 DirectoryExists 来确定由Directory参数指定的目录是否存在。如果目录存在,函数返回true。如果目录不存在,函数返回false。
如果输入的是全称路径名(full path name),DirectoryExists 会沿着指定的路径查找目录。否则Directory参数会被认为是当前目录的相对路径。
FileCtrl 单元(仅用于Windows) 同样包含一个 DirectoryExists 函数。然而,FileCtrl 版本是不赞成的,SysUtils 版本是首选的,即使代码不需要跨平台(However, the FileCtrl version is deprecated, and the SysUtils version preferred, even if the code does not need to be cross-platform)。

7.DiskFree 函数
返回指定盘符上空闲的字节数
单元
SysUtils
语法
function DiskFree(Drive: Byte): Int64;
描述
DiskFree 返回指定驱动盘()的空闲字节数,其中 0 = 当前盘, 1 = A, 2 = B,等等。如果驱动盘数字无效,DiskFree 返回-1。
注意:DiskFree 仅在Windows上可用。
示例
var
S: string;
AmtFree: Int64;
Total: Int64;
begin
AmtFree := DiskFree(0);
Total := DiskSize(0);
S := IntToStr(AmtFree div Total) + 'percent of the space on drive 0 is free: ' (AmtFree div 1024) + ' Kbytes free. ';
Label1.Caption := S;
end;

8.DiskSize 函数
返回指定盘符的字节大小
单元
SysUtils
语法
function DiskSize(Drive: Byte): Int64;
描述
DiskSize 返回指定驱动盘的字节大小,其中 0 = 当前盘,1 = A, 2 = B, 等等。如果驱动盘数字无效,DiskSize返回-1。
注意:DiskSize 仅在Windows上可用。

9.文件模式常量(File mode constants)
文件模式常量用于打开和关闭磁盘文件
单元
System
语法
const fmClosed = $D7B0; // closed file
const fmInput = $D7B1; // reset file (TTextRec)
const fmOutput = $D7B2; // rewritten file (TTextRec)
const fmInOut = $D7B3; // reset or rewritten file (TFileRec)
const fmCRLF = $8 // DOS-style EoL and EoF markers (TTextRec)
const fmMask = $D7B3; // mask out fmCRLF flag (TTextRec)
描述 当打开和关闭磁盘文件时,使用文件模式常量。这些常量主要用在这样的Delphi代码中,TFileRec和TTextRec的Mode字段包含这些值中的某个值(These constants are used primarily in Delphi code, where the Mode field of TFileRec and TTextRec contain one of these values.)。

10.文件名称常量(File name constants)
文件名称常量用于以平台中立的方式表达文件名称。
单元
SysUtils
语法
const
PathDelim = {$IFDEF MSWINDOWS} '\'; {$ELSE} '/'; {$ENDIF}
DriveDelim = {$IFDEF MSWINDOWS} ':'; {$ELSE} ''; {$ENDIF}
PathSep = {$IFDEF MSWINDOWS} ';'; {$ELSE} ':'; {$ENDIF}
描述
文件名称常量指定了在Windows和Linux中不同的的定界符和分隔符(delimiter and separator)。

11.文件打开模式常量(File open mode constants)
打开打开模式常量用于控制对文件或流的访问模式。
单元
SysUtils
语法
On Windows:
const
fmCreate = $FFFF;
fmOpenRead = $0000;
fmOpenWrite = $0001;
fmOpenReadWrite = $0002;

fmShareCompat = $0000 platform;
fmShareExclusive = $0010;
fmShareDenyWrite = $0020;
fmShareDenyRead = $0030 platform;
fmShareDenyNone = $0040;

On Linux:
const
fmOpenRead = O_RDONLY;
fmOpenWrite = O_WRONLY;
fmOpenReadWrite = O_RDWR;
fmShareExclusive = $0010;
fmShareDenyWrite = $0020;
fmShareDenyNone = $0030;

描述
当文件或流被打开时,文件打开模式常量用于控制文件或流能够如何共享。
TFileStream构造函数有一个Mode参数,你能够设置为这些常量中的一个:
Constant Definition

fmCreate 如果文件存在,那么将打开用于写访问,否则会创建新文件。其他的常量都声明在 SysUtils 单元,而这个常量声明在 Classes 单元中
fmOpenRead 仅以读访问方式打开
fmOpenWrite 仅以写访问方式打开
fmOpenReadWrite 以读写访问方式打开
fmShareCompat 和FCB打开的方法兼容。不要在跨平台应用程序中使用这个模式
fmShareExclusive 读写访问被拒绝
fmShareDenyWrite 写访问被拒绝
fmShareDenyRead 读访问被拒绝。不要在跨平台应用程序中使用这个模式
fmShareDenyNone 允许其他代码进行完全的访问

12.FileAccessRights 变量
当应用程序被调用时指向特殊的命令行参数。
单元
System
语法
var FileAccessRights: Integer platform;
描述
在 Windows 中,FileAccessRights 变量被忽略。
在 Linux 中,每个文件都有一组许可位(permission bits)控制着对文件的访问。当创建新文件时,FileAccessRights 指定了一组默认的许可标记来使用。当你没有显式指定要使用的许可位时,FileCreate 方法使用 FileAccessRights 来设置它创建的文件的访问权力。
13.FileAge 函数
返回文件的OS时间戳(Returns the OS timestamp of a file.)
单元
SysUtils
语法
function FileAge(const FileName: string): Integer;
描述
调用 FileAge 来获得由 FileNameto 指定的文件的 OS 时间戳。返回值可以使用 FileDateToDateTime函数转换为TDateTime对象。如果文件不存在返回值为 -1。
在Linux中,-1 是一个有效的时间戳。可使用 FileExists 核实文件不存在。
示例
下面的代码将一个文件的属性读入一组变量中,并在文件属性对话框中设置检查框以表现当前的属性,然后执行对话框。如果用户改变并接受对话框的设置,代码将设置文件属性以匹配改变的设置:
procedure TFMForm.Properties1Click(Sender: TObject);
var
Attributes, NewAttributes: Word;
begin
with FileAttrForm do
begin
FileDirName.Caption := FileList.Items[FileList.ItemIndex];
{ set box caption }
PathName.Caption := FileList.Directory;
{ show directory name }
ChangeDate.Caption :=
DateTimeToStr(FileDateToDateTime(FileAge(FileList.FileName)));
Attributes := FileGetAttr(FileDirName.Caption);
{ read file attributes }
ReadOnly.Checked := (Attributes and SysUtils.faReadOnly) = faReadOnly;
Archive.Checked := (Attributes and faArchive) = faArchive;
System.Checked := (Attributes and faSysFile) = faSysFile;
Hidden.Checked := (Attributes and faHidden) = faHidden;
if ShowModal <> id_Cancel then { execute dialog box }
begin
NewAttributes := Attributes;
{ start with original attributes }
if ReadOnly.Checked then
NewAttributes := NewAttributes or SysUtils.faReadOnly
else
NewAttributes := NewAttributes and not SysUtils.faReadOnly;
if Archive.Checked then
NewAttributes := NewAttributes or faArchive
else
NewAttributes := NewAttributes and not faArchive;
if System.Checked then
NewAttributes := NewAttributes or faSysFile
else
NewAttributes := NewAttributes and not faSysFile;
if Hidden.Checked then
NewAttributes := NewAttributes or faHidden
else
NewAttributes := NewAttributes and not faHidden;
if NewAttributes <> Attributes then { if anything changed... }
FileSetAttr(FileDirName.Caption, NewAttributes);
{ ...write the new values }
end;
end;
end;

14.FileClose 过程
关闭指定的文件
单元
SysUtils
语法
procedure FileClose(Handle: Integer);
描述
FileClose 关闭给定文件句柄的文件。句柄在文件使用FileOpen或FileCreate打开时获得。
当和Delphi语言的文件变量一起使用时,应使用 CloseFile 过程代替。
示例
下面的例子使用了一个按钮,一个字符串栅格和一个保存对话框在窗体上。单击按钮后,用户将被提示输入文件名。当用户单OK后,字符串栅格的内容将被写到指定的文件中。附加的信息同样被写到文件中,以便文件能够使用FileRead函数容易地读取。
procedure TForm1.Button1Click(Sender: TObject);
var
BackupName: string;
FileHandle: Integer;
StringLen: Integer;
X: Integer;
Y: Integer;
begin
if SaveDialog1.Execute then
begin
if FileExists(SaveDialog1.FileName) then
begin
BackupName := ExtractFileName(SaveDialog1.FileName);
BackupName := ChangeFileExt(BackupName, '.BAK');
if not RenameFile(SaveDialog1.FileName, BackupName) then
raise Exception.Create('Unable to create backup file.');
end;
FileHandle := FileCreate(SaveDialog1.FileName);
{ Write out the number of rows and columns in the grid. }
FileWrite(FileHandle,
StringGrid1.ColCount, SizeOf(StringGrid1.ColCount));
FileWrite(FileHandle,
StringGrid1.RowCount, SizeOf(StringGrid1.RowCount));
for X := 0 to StringGrid1.ColCount - 1 do
begin
for Y := 0 to StringGrid1.RowCount - 1 do
begin
{ Write out the length of each string, followed by the string itself. }
StringLen := Length(StringGrid1.Cells[X,Y]);
FileWrite(FileHandle, StringLen, SizeOf(StringLen));
FileWrite(FileHandle,
StringGrid1.Cells[X,Y], Length(StringGrid1.Cells[X,Y]);
end;
end;
FileClose(FileHandle);
end;
end;

15.FileCreate 函数
创建一个新文件
单元
SysUtils
语法
function FileCreate(const FileName: string): Integer; overload;
function FileCreate(const FileName: string; Rights: Integer): Integer; overload;
描述
FileCreate 用指定的名称创建新文件。如果返回值是正数,说明函数成功而且值是新文件的句柄。返回值是-1说明有错误发生。
在 Windows中,FileAccessRights 变量和 Rights 参数被忽略。

posted @ 2006-06-01 11:58 青蛙學堂 阅读(271) | 评论 (0)编辑 收藏

DELPHI中使用DLL

第一章 为什么要使用动态链接库(DLL) top
提起DLL您一定不会陌生,在Windows中有着大量的以DLL为后缀的文件,它们是保证Windows正常运行和维护升级的重要保证。(举个例子,笔者的Win95 System目录下尽有500多个DLL文件。)其实,DLL是一种特殊的可执行文件。说它特殊主要是因为一般它都不能直接运行,需要宿主程序比如*.EXE程序或其他DLL的动态调用才能够使用。简单的说,在通常情况下DLL是经过编译的函数和过程的集合。
使用DLL技术主要有以下几个原因:

一、减小可执行文件大小。
DLL技术的产生有很大一部分原因是为了减小可执行文件的大小。当操作系统进入Windows时代后,其大小已经达到几十兆乃至几百兆。试想如果还是使用DOS时代的单执行文件体系的话一个可执行文件的大小可能将达到数十兆,这是大家都不能接受的。解决的方法就是采用动态链接技术将一个大的可执行文件分割成许多小的可执行程序。

二、实现资源共享。
这里指的资源共享包括很多方面,最多的是内存共享、代码共享等等。早期的程序员经常碰到这样的事情,在不同的编程任务中编写同样的代码。这种方法显然浪费了很多时间,为了解决这个问题人们编写了各种各样的库。但由于编程语言和环境的不同这些库一般都不能通用,而且用户在运行程序时还需要这些库才行,极不方便。DLL的出现就像制定了一个标准一样,使这些库有了统一的规范。这样一来,用不同编程语言的程序员可以方便的使用用别的编程语言编写的DLL。另外,DLL还有一个突出的特点就是在内存中只装载一次,这一点可以节省有限的内存,而且可以同时为多个进程服务。

三、便于维护和升级。
细心的朋友可能发现有一些DLL文件是有版本说明的。(查看DLL文件的属性可以看到,但不是每一个DLL文件都有)这是为了便于维护和升级。举个例子吧,早期的Win95中有一个BUG那就是在闰年不能正确显示2月29日这一天。后来,Microsoft发布了一个补丁程序纠正了这个BUG。值得一提的是,我们并没有重装Win95,而是用新版本的DLL代替了旧版本的DLL。(具体是哪一个DLL文件笔者一时想不起来了。)另一个常见的例子是驱动程序的升级。例如,著名的DirectX就多次升级,现在已经发展到了6.0版了。更妙的是,当我们试图安装较低版本的DLL时,系统会给我们提示,避免人为的操作错误。例如我们升级某硬件的驱动程序时,经常碰到Windows提示我们当前安装的驱动程序比原来的驱动程序旧。

四、比较安全。
这里说的安全也包括很多方面。比如,DLL文件遭受病毒的侵害机率要比普通的EXE文件低很多。另外,由于是动态链接的,这给一些从事破坏工作的“高手”们多少带来了一些反汇编的困难。

第二章 在Delphi中编写DLL top

注意:在这里笔者假定读者使用的是Delphi 3或Delphi 4开场白说了那么多,总该言归正传了。编写DLL其实也不是一件十分困难的事,只是要注意一些事项就够了。为便于说明,我们先举一个例子。

library Delphi;

uses
SysUtils,
Classes;

function TestDll(i:integer):integer;stdcall;
begin
Result:=i;
end;

exports
TestDll;

begin
end.

上面的例子是不是很简单?熟悉Delphi的朋友可以看出以上代码和一般的Delphi程序的编写基本是相同的,只是在TestDll函数后多了一个stdcall参数并且用exports语句声明了TestDll函数。只要编译上面的代码,就可以得到一个名为Delphi.dll的动态链接库。现在,让我们来看看有哪些需要注意的地方。 一、在DLL中编写的函数或过程都必须加上stdcall调用参数。在Delphi 1或Delphi 2环境下该调用参数是far。从Delphi 3以后将这个参数变为了stdcall,目的是为了使用标准的Win32参数传递技术来代替优化的register参数。忘记使用stdcall参数是常见的错误,这个错误不会影响DLL的编译和生成,但当调用这个DLL时会发生很严重的错误,导致操作系统的死锁。原因是register参数是Delphi的默认参数。

二、所写的函数和过程应该用exports语句声明为外部函数。
正如大家看到的,TestDll函数被声明为一个外部函数。这样做可以使该函数在外部就能看到,具体方法是单激鼠标右键用“快速查看(Quick View)”功能查看该DLL文件。(如果没有“快速查看”选项可以从Windows CD上安装。)TestDll函数会出现在Export Table栏中。另一个很充分的理由是,如果不这样声明,我们编写的函数将不能被调用,这是大家都不愿看到的。

三、当使用了长字符串类型的参数、变量时要引用ShareMem。
Delphi中的string类型很强大,我们知道普通的字符串长度最大为256个字符,但Delphi中string类型在默认情况下长度可以达到2G。(对,您没有看错,确实是两兆。)这时,如果您坚持要使用string类型的参数、变量甚至是记录信息时,就要引用ShareMem单元,而且必须是第一个引用的。既在uses语句后是第一个引用的单元。如下例:
uses
ShareMem,
SysUtils,
Classes;
还有一点,在您的工程文件(*.dpr)中而不是单元文件(*.pas)中也要做同样的工作,这一点Delphi自带的帮助文件没有说清楚,造成了很多误会。不这样做的话,您很有可能付出死机的代价。避免使用string类型的方法是将string类型的参数、变量等声明为Pchar或ShortString(如:s:string[10])类型。同样的问题会出现在当您使用了动态数组时,解决的方法同上所述。

第三章 在Delphi中静态调用DLL top

调用一个DLL比写一个DLL要容易一些。首先给大家介绍的是静态调用方法,稍后将介绍动态调用方法,并就两种方法做一个比较。同样的,我们先举一个静态调用的例子。

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.

上面的例子中我们在窗体上放置了一个编辑框(Edit)和一个按钮(Button),并且书写了很少的代码来测试我们刚刚编写的Delphi.dll。大家可以看到我们唯一做的工作是将TestDll函数的说明部分放在了implementation中,并且用external语句指定了Delphi.dll的位置。(本例中调用程序和Delphi.dll在同一个目录中。)让人兴奋的是,我们自己编写的TestDll函数很快被Delphi认出来了。您可做这样一个实验:输入“TestDll(”,很快Delphi就会用fly-by提示条提示您应该输入的参数是什么,就像我们使用Delphi中定义的其他函数一样简单。注意事项有以
下一些:

一、调用参数用stdcall。
和前面提到的一样,当引用DLL中的函数和过程时也要使用stdcall参数,原因和前面提到的一样。

二、用external语句指定被调用的DLL文件的路径和名称。
正如大家看到的,我们在external语句中指定了所要调用的DLL文件的名称。没有写路径是因为该DLL文件和调用它的主程序在同一目录下。如果该DLL文件在C:\,则我们可将上面的引用语句写为external ’C:\Delphi.dll’。注意文件的后缀.dll必须写上。

三、不能从DLL中调用全局变量。
如果我们在DLL中声明了某种全局变量,如:var s:byte 。这样在DLL中s这个全局变量是可以正常使用的,但s不能被调用程序使用,既s不能作为全局变量传递给调用程序。不过在调用程序中声明的变量可以作为参数传递给DLL。

四、被调用的DLL必须存在。
这一点很重要,使用静态调用方法时要求所调用的DLL文件以及要调用的函数或过程等等必须存在。如果不存在或指定的路径和文件名不正确的话,运行主程序时系统会提示“启动程序时出错”或“找不到*.dll文件”等运行错误。

第四章 在Delphi中动态调用DLL top

动态调用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;

大家已经看到了,这种动态调用技术很复杂,但只要修改参数,如修改LoadLibrary(’Cpp.dll’)中的DLL名称为’Delphi.dll’就可动态更改所调用的DLL。

一、定义所要调用的函数或过程的类型。
在上面的代码中我们定义了一个TIntFunc类型,这是对应我们将要调用的函数TestC的。在其他调用情况下也要做同样的定义工作。并且也要加上stdcall调用参数。

二、释放所调用的DLL。
我们用LoadLibrary动态的调用了一个DLL,但要记住必须在使用完后手动地用FreeLibrary将该DLL释放掉,否则该DLL将一直占用内存直到您退出Windows或关机为止。

现在我们来评价一下两种调用DLL的方法的优缺点。静态方法实现简单,易于掌握并且一般来说稍微快一点,也更加安全可靠一些;但是静态方法不能灵活地在运行时装卸所需的DLL,而是在主程序开始运行时就装载指定的DLL直到程序结束时才释放该DLL,另外只有基于编译器和链接器的系统(如Delphi)才可以使用该方法。动态方法较好地解决了静态方法中存在的不足,可以方便地访问DLL中的函数和过程,甚至一些老版本DLL中新添加的函数或过程;但动态方法难以完全掌握,使用时因为不同的函数或过程要定义很多很复杂的类型和调用方法。对于初学者,笔者建议您使用静态方法,待熟练后再使用动态调用方法。

第五章 使用DLL的实用技巧 top

一、编写技巧。
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目录下或者Windows\system目录下。这样做可以在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编程都有很多益处。

Delphi中如何调用DLL
马上想得到的使用说明有以下几点:

1. 所需动态连结的 DLL 须置放在与执行档同一目录或Windows System 目录2. 确认 DLL export 出来的函式的原型, 以目前的情况而言, 通常只拿得到 C语言的函数原型,这时要注意 C 与 object Pascal 相对应的型别, 如果需要, 在interface 一节定义所需的资料类别

3. 在 implementation 节中宣告欲使用的函式, 语法大致如下:

procedure ProcName(Argu...); far; external ’DLL档名’;

index n;

function FuncName(Argr...): DataType; far;

external ’DLL档名’; index n;

宣告时, index n 如果不写, 便是参考资料中所谓 import by name 的方式, 此时, 由於需要从 DLL 的 name table 中找出这个函式, 因此, 连结执行速度比import by ordinal稍慢一些, 此外, 还有一种 by new name, 由於我没用过, 您可以查一参考资料, 大意是可以 import 後改用另一个程式命名呼叫这个函式

4. 然後, 呼叫与使用就与一般的Delphi 没有两样5. 上述是直接写到呼叫DLL函式的程式单元中, 此外,也可以将DLL的呼叫宣告集中到一个程式单元(Import unit), Delphi 内附的 WinTypes, WinProcs是一个例子,

您可以参考一下,同时观察一下 C 与 Pascal 互相对应的资料型态6. 除了上述的 static import 的方式, 另外有一种 dynamic import 的写法,先宣告一个程序类型(procedural-type),程式执行时, 以LoadLibrary() API Load进来後, 再以 GetProcAddress() API 取得函式的位址的方式来连结呼叫, 在ObjectPascal Language Guide P.132-133 有一个例子, 您可以参考看看

如果要举个例子, 以下是从我以前的程式节录出来的片断:

(* for CWindows 3.1 *)

unit Ime31;

interface

uses

SysUtils, WinTypes, WinProcs, Dialogs;

type

(* 必要的资料型态宣告 *)

tDateNTime = record

wYear, wMonth, wDay: word;

wHour, wMin, wSec: word;

end;

TImePro = record

hWndIme: HWnd; { IME handle }

dtInstDate: tDateNTime; { Date and time of installation }

wVersion: word; { the version of IME }

szDescription: array[0..49] of byte; { Description of IME module}

szName: array[0..79] of byte; { Module name of the IME }

szOptions: array[0..29] of byte; { options of IME at startup}

fEnable: boolean; { IME status; True=activated,False=deactivated }

end;

pTImePro = ^TImePro;

function SetIme(const sImeFileName: string): boolean; far;

implementation

(* begin 呼叫 winnls.dll export 函数的宣告 *)

function ImpSetIme(hWndIme: HWND; lpImePro: pTImePro): boolean;far; external ’winnls.dll’;

(* end 呼叫 winnls.dll export 函数的宣告 *)

(* -------------------------------------------------- *)

(* SetIme(const sImeFileName: string): boolean;

(* ======

(* 切换到某一特定的输入法

(*

(* 传入引数:

(* sImeFileName: 输入法 IME 档名, 例: phon.ime;

(* 空字串: 英数输入法

(*

(* 传回值:

(* True: 切换成功

(* False: 失败

(* -------------------------------------------------- *)

function SetIme(const sImeFileName: string): boolean;

var

pImePro: pTImePro;

begin

Result := False;

if MaxAvail < SizeOf(TImePro) then

begin

MessageDlg(’记忆体不足’, mtWarning, [mbOk], 0);

Exit;

end

else

begin

New(pImePro);

try

if sImeFileName = ’’ then (* 空字串, 还原到英数输入法 *)

pImePro^.szName[0] := 0

else

StrPCopy(@pImePro^.szName, sImeFileName);

Result := ImpSetIme(0, pImePro); (* 呼叫 ImpSetIme *)

finally

Dispose(pImePro);

end; { of try }

end;

end; { of SetIme }

end.

posted @ 2006-05-31 16:04 青蛙學堂 阅读(2247) | 评论 (0)编辑 收藏

Delphi--(DLL)

动态链接库是一个能够被应用程序和其它的DLL调用的过程和函数的集合体,它里面包含的是公共代码或资源。由于DLL代码使用了内存共享技术,在某些地方windows也给了DLL一些更高的权限,因而DLL中可以实现一些一般程序所不能实现的功能,如实现windows的HOOK、ISAPI等。

  同时,DLL还为不同语言间代码共享提供了一条方便的途径。因而DLL在编程时应用较为广泛,本文将介绍如何在 Delphi 中建立和使用DLL。

  一.DLL 库内存共享机制

  从使用效果看,DLL和unit 很像,它们都可以被别的工程模块所调用,但二者在内部的实现机制上确存在着差别。如果一个程序模块中用uses语句引用了某个unit,编译程序在编译该模块时,便会连同unit一起编译,并把编译后的可执行代码链接到本程序模块中,这就是一个程序模块能够调用所引用unit中过程和函数的原因。

  当同一个unit被多个工程所引用时,则每个工程中都含有该unit的可执行代码,当含有该unit的多个工程同时执行时,unit的可执行代码会随不同工程而多次被调入内存,造成内存资源的浪费。DLL则不同,它即使被某个工程调用,编译后仍是独立的。

  也就是说编译后,一个DLL库形成一个单独的可执行文件,而不与任何其它的可执行文件连接在一起,因而DLL库并不从属于某个特定的工程,当多个工程调用同一个DLL库时只有第一个工程把DLL库调入内存,其余工程并不重复调入同一个DLL库到内存,而是到同一个共享内存区读取。并且,DLL的执行代码是在程序运行期间动态调入的,而不是如unit在程序运行时就与整个工程一起调入内存。这样便可消除unit带来的相同代码多处占用内存的弊病。

  二 Delphi中DLL库的建立

 在Delphi环境中,编写一个DLL同编写一个一般的应用程序并没有太大的区别。事实上作为DLL主体的DLL函数的编写,除了在内存、资源的管理上有所不同外,并不需要其它特别的手段。

    一般工程文件的格式为:
  program  工程标题; 
  uses    子句; 
  程序体
  而DLLs工程文件的格式为:
  library 工程标题; 
  uses 子句; 
  exprots 子句; 
  绦蛱?
 它们主要的区别有两点:

  1.一般工程文件的头标用program关键字,而DLL工程文件头标用library 关键字。不同的关键字通知编译器生成不同的可执行文件。用program关键字生成的是.exe文件,而用library关键字生成的是.dll文件;

  2.假如DLL要输出供其它应用程序使用的函数或过程,则必须将这些函数或过程列在exports子句中。而这些函数或过程本身必须用export编译指令进行编译。  在Delphi主菜单file 中选new...项,在弹出的窗口中双击DLL图标,便会自动给出DLL源模块框架,如下:

  Library project1;
  {...注释...}
  uses
  SysUtils, Classes;
  begin
  end. 

  接下来便可在USES和begin之间加入想在该DLL中实现的过程和函数的定义,并用export和exprots保字把它们引出,以便别的模块引用,在begin和end之间加入初始化代码,初始化代码是用来对DLL变量初始化的。应注意,即便无初始化代码begin与end也不可省略,如下例:

  library minmax;
  function Min(X, Y: Integer): Integer; export;
  begin
  if X < Y then Min := X else Min := Y;
  end;
  function Max(X, Y: Integer): Integer; export;
  begin
  if X > Y then Max := X else Max := Y;
  end;
  exports
  Min index 1,
  Max index 2;
  begin
  end. 

  经编译后,并以minmax.DLL存盘后,一个DLL库文件便形成了。 
三 DLL库的访问

  访问DLL库有两种方式,一种是静态引用,另一种是动态引用。

  用静态引用这种方法装入DLL要做两件事情:为DLL 库创建一个输入单元,以及用USES把输入单元连接到要使用DLL 函数的程序模块中。为DLL库创建的输入单元与普通的单元的区别仅在于:在它的接口处声明的过程、函数,并不在它的实现部分给出真正的实现代码,而是用external关键字把过程、函数的实现细节委托给外部DLL模块。

  external命令的使用语法如下:

  procedure /function 过程/函数名;external DLL模块名;

  下面给出为上面创建的minmax.DLL库写的输入单元源文件testdll .pas,从中可看出输入单元与一般单元的一些差别,代码如下所示:
  unit testdll;
  interface
  uses
  function Min (X, Y: Integer): Integer;
  function Max (X, Y: Integer): Integer; 
  implementation 
  function Min; external ‘minmax.DLL’;
  function Max; external ‘minmax.DLL’;
  end. 

  一个应用程序若想调用minmax.DLL中的函数,只须在其uses语句中加入testdll 单元即可。

 动态装入DLL,要用到Windows的三个API函数。Loadlibrary、Freelibrary和GetprocAddress 。  loadlibrary函数用来装入DLL库,其调用格式如下:

  function loadlobrary (DLLfileName:Pchar): THandle:

  当不再需要一个DLL库时,应调用FreeLibrary函数将其释放,以空出宝贵的内存资源,其调用格式如下:

  procedure FreeLibrary (Libmodule:THandle)

  Libmodule 为由LoadLibrary调用得到的DLL库句柄。在用loadlobrary 函数装入某个DLL库和调用FreeLibrary释放该DLL库之间的程序段中, 可以使用该DLL库中的过程和函数,具体使用方法是:用GetprocAddress函数把DLL库中函数的地址传递给程序中某个函数变量,再用该变量实现DLL函数的调用。GetprocAddress函数声名如下
function GetprocAddress (Libmodule:THandle:procname:pchar):TFarProc: 
  如下例所示:
  type
  TTimeRec = record
  Second: Integer;
  Minute: Integer;
  Hour: Integer;
  end;
  TGetTime = procedure(var Time: TTimeRec);
  THandle = Integer;
  var
  Time: TTimeRec;
  Handle: THandle;
  GetTime: TGetTime;
  ...
  begin
  Handle := LoadLibrary('DATETIME.DLL');
  if Handle <> 0 then
  begin
  @GetTime := GetProcAddress(Handle, 'GetTime');
  if @GetTime <> nil then
  begin
  GetTime(Time);
  with Time do
  WriteLn('The time is ', Hour, ':', Minute, ':', Second);
  end;
  FreeLibrary(Handle);
  end;
  end;

  在调用动态链接库时应注意, 所需动态链接库须与应用程序在同一目录或Windows System 目录下。

  动态链接库是 Windows下程序组织的一种重要方式,使用动态链接库可以极大地保护用户在不同开发工具、不同时期所做的工作,提高编程效率。

posted @ 2006-05-31 15:44 青蛙學堂 阅读(205) | 评论 (0)编辑 收藏

Excel

启动 Excel
Dim objExcel As Excel.Application
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = True'设置EXCEL对象可见(或不可见)


创建有一个工作表的工作簿
Dim objWorkBook As Excel.WorkBook
objExcel.SheetsInNewWorkbook = 1
Set objWorkbook = objExcel.Workbooks.Add


打开已经存在的 EXCEL 工件簿文件
Set objWorkbook=objExcel.Workbooks.Open("文件名")


设置活动工作表
Dim objSheet As Excel.Worksheet
Set objSheet = objExcel.Worksheets("表名")

给单元格(row,col)赋值
objSheet.Cells(row, col) =值


给合并的单元格赋值,如(A3:A9)
objSheet.Range("A3:A9") =值


运行 EXCEL 宏
objWorkbook.RunAutoMacros ("宏名")

插入一行
objSheet.Rows("1:1").Insert Shift:=xlDown


保存 EXCEL 文件
objWorkbook.Save
另存为
objWorkbook.SaveAs("文件名")


关闭工作簿
objWorkbook.Close (True)


结束 EXCEL 对象
objExcel.Quit
如果要求在退出应用程序后EXCEL不提示用户是否保存已修改的
文件,则可使用如下语句:
objExcel.DisplayAlerts = False
objExcel.Quit
objExcel.DisplayAlerts = True



释放 objExcel 对象
Set objExcel = Nothing


注意: 在工程中运用 Excel 对象模型,必须引用 Excel Object Library
工程--> 引用 加入 Excel Object Library
在 VB 中操作 EXCEL 对象,如为可见,在操作中手式关闭 EXCEL
,而 VB 程序无法知道,如果此时使用 EXCEL 对象,则VB程序会产
生错误。形成 VB 程序无法完全控制 EXCEL 的状况,使得 VB 与
EXCEL 脱节。在编程时应注意加以防止出现出现这种情况。

posted @ 2006-05-31 15:24 青蛙學堂 阅读(262) | 评论 (0)编辑 收藏

DLL木马程序

相信经常玩木马的朋友们都会知道一些木马的特性,也会有自己最喜爱的木马,不过,很多朋友依然不知道近年兴起的“DLL木马”为何物。什么是“DLL木马”呢?它与一般的木马有什么不同?

  一、从DLL技术说起

  要了解DLL木马,就必须知道这个“DLL”是什么意思,所以,让我们追溯到几年前,DOS系统大行其道的日子里。在那时候,写程序是一件繁琐的事情,因为每个程序的代码都是独立的,有时候为了实现一个功能,就要为此写很多代码,后来随着编程技术发展,程序员们把很多常用的代码集合(通用代码)放进一个独立的文件里,并把这个文件称为“库”(Library),在写程序的时候,把这个库文件加入编译器,就能使用这个库包含的所有功能而不必自己再去写一大堆代码,这个技术被称为“静态链接”(Static Link)。静态链接技术让劳累的程序员松了口气,一切似乎都很美好。可是事实证明,美好的事物不会存在太久,因为静态链接就像一个粗鲁的推销员,不管你想不想要宣传单,他都全部塞到你的手上来。写一个程序只想用到一个库文件包含的某个图形效果,就因为这个,你不得不把这个库文件携带的所有的图形效果都加入程序,留着它们当花瓶摆设,这倒没什么重要,可是这些花瓶却把道路都阻塞了——静态链接技术让最终的程序成了大块头,因为编译器把整个库文件也算进去了。

 时代在发展,静态链接技术由于天生的弊端,不能满足程序员的愿望,人们开始寻找一种更好的方法来解决代码重复的难题。后来,Windows系统出现了,时代的分水岭终于出现。Windows系统使用一种新的链接技术,这种被称为“动态链接”(Dynamic Link)的新技术同样也是使用库文件,微软称它们为“动态链接库”——Dynamic Link Library,DLL的名字就是这样来的。动态链接本身和静态链接没什么区别,也是把通用代码写进一些独立文件里,但是在编译方面,微软绕了个圈子,并没有采取把库文件加进程序的方法,而是把库文件做成已经编译好的程序文件,给它们开个交换数据的接口,程序员写程序的时候,一旦要使用某个库文件的一个功能函数,系统就把这个库文件调入内存,连接上这个程序占有的任务进程,然后执行程序要用的功能函数,并把结果返回给程序显示出来,在我们看来,就像是程序自己带有的功能一样。完成需要的功能后,这个DLL停止运行,整个调用过程结束。微软让这些库文件能被多个程序调用,实现了比较完美的共享,程序员无论要写什么程序,只要在代码里加入对相关DLL的调用声明就能使用它的全部功能。最重要的是,DLL绝对不会让你多拿一个花瓶,你要什么它就给你什么,你不要的东西它才不会给你。这样,写出来的程序就不能再携带一大堆垃圾了——绝对不会让你把吃剩的东西带回家,否则罚款,这是自助餐。

  DLL技术的诞生,使编写程序变成一件简单的事情,Windows为我们提供了几千个函数接口,足以满足大多数程序员的需要。而且,Windows系统自身就是由几千个DLL文件组成,这些DLL相互扶持,组成了强大的Windows系统。如果Windows使用静态链接技术,它的体积会有多大?我不敢想。

 二、应用程序接口API

  上面我们对DLL技术做了个大概分析,在里面我提到了“接口”,这又是什么呢?因为DLL不能像静态库文件那样塞进程序里,所以,如何让程序知道实现功能的代码和文件成了问题,微软就为DLL技术做了标准规范,让一个DLL文件像奶酪一样开了许多小洞,每个洞口都注明里面存放的功能的名字,程序只要根据标准规范找到相关洞口就可以取得它要的美味了,这个洞口就是“应用程序接口”(Application Programming Interface),每个DLL带的接口都不相同,尽最大可能的减少了代码的重复。用Steven的一句话:API就是一个工具箱,你根据需要取出螺丝刀、扳手,用完后再把它们放回原处。在Windows里,最基本的3个DLL文件是kernel32.dll、user32.dll、gdi32.dll。它们共同构成了基本的系统框架

 三、DLL与木马

  DLL是编译好的代码,与一般程序没什么大差别,只是它不能独立运行,需要程序调用。那么,DLL与木马能扯上什么关系呢?如果你学过编程并且写过DLL,就会发现,其实DLL的代码和其他程序几乎没什么两样,仅仅是接口和启动模式不同,只要改动一下代码入口,DLL就变成一个独立的程序了。当然,DLL文件是没有程序逻辑的,这里并不是说DLL=EXE,不过,依然可以把DLL看做缺少了main入口的EXE,DLL带的各个功能函数可以看作一个程序的几个函数模块。DLL木马就是把一个实现了木马功能的代码,加上一些特殊代码写成DLL文件,导出相关的API,在别人看来,这只是一个普通的DLL,但是这个DLL却携带了完整的木马功能,这就是DLL木马的概念。也许有人会问,既然同样的代码就可以实现木马功能,那么直接做程序就可以,为什么还要多此一举写成DLL呢?这是为了隐藏,因为DLL运行时是直接挂在调用它的程序的进程里的,并不会另外产生进程,所以相对于传统EXE木马来说,它很难被查到。

  四、DLL的运行

  虽然DLL不能自己运行,可是Windows在加载DLL的时候,需要一个入口函数,就如同EXE的main一样,否则系统无法引用DLL。所以根据编写规范,Windows必须查找并执行DLL里的一个函数DllMain作为加载DLL的依据,这个函数不作为API导出,而是内部函数。DllMain函数使DLL得以保留在内存里,有的DLL里面没有DllMain函数,可是依然能使用,这是因为Windows在找不到DllMain的时候,会从其它运行库中找一个不做任何操作的缺省DllMain函数启动这个DLL使它能被载入,并不是说DLL可以放弃DllMain函数。

 五、DLL木马技术分析

  到了这里,您也许会想,既然DLL木马有那么多好处,以后写木马都采用DLL方式不就好了吗?话虽然是这么说没错,但是DLL木马并不是一些人想象的那么容易写的。要写一个能用的DLL木马,你需要了解更多知识。

  1. 木马的主体

  千万别把木马模块写得真的像个API库一样,这不是开发WINAPI。DLL木马可以导出几个辅助函数,但是必须有一个过程负责主要执行代码,否则这个DLL只能是一堆零碎API函数,别提工作了。

  如果涉及一些通用代码,可以在DLL里写一些内部函数,供自己的代码使用,而不是把所有代码都开放成接口,这样它自己本身都难调用了,更不可能发挥作用。

  DLL木马的标准执行入口为DllMain,所以必须在DllMain里写好DLL木马运行的代码,或者指向DLL木马的执行模块。

2. 动态嵌入技术

  Windows中,每个进程都有自己的私有内存空间,别的进程是不允许对这个私人领地进行操作的,但是,实际上我们仍然可以利用种种方法进入并操作进程的私有内存,这就是动态嵌入,它是将自己的代码嵌入正在运行的进程中的技术。动态嵌入有很多种,最常见的是钩子、API以及远程线程技术,现在的大多数DLL木马都采用远程线程技术把自己挂在一个正常系统进程中。其实动态嵌入并不少见,罗技的MouseWare驱动就挂着每一个系统进程-_-

  远程线程技术就是通过在另一个进程中创建远程线程(RemoteThread)的方法进入那个进程的内存地址空间。在DLL木马的范畴里,这个技术也叫做“注入”,当载体在那个被注入的进程里创建了远程线程并命令它加载DLL时,木马就挂上去执行了,没有新进程产生,要想让木马停止惟有让挂接这个木马DLL的进程退出运行。但是,很多时候我们只能束手无策——它和Explorer.exe挂在一起了,你确定要关闭Windows吗?

  3. 木马的启动

  有人也许会迫不及待的说,直接把这个DLL加入系统启动项目不就可以了。答案是NO,前面说过,DLL不能独立运行,所以无法在启动项目里直接启动它。要想让木马跑起来,就需要一个EXE使用动态嵌入技术让DLL搭上其他正常进程的车,让被嵌入的进程调用这个DLL的DllMain函数,激发木马运行,最后启动木马的EXE结束运行,木马启动完毕。

  启动DLL木马的EXE是个重要角色,它被称为Loader,如果没有Loader,DLL木马就是破烂一堆,因此,一个算得上成熟的DLL木马会想办法保护它的Loader不会那么容易被毁灭。记得狼狈为奸的故事吗?DLL木马就是爬在狼Loader上的狈。

  Loader可以是多种多样的,Windows的rundll32.exe也被一些DLL木马用来做了Loader,这种木马一般不带动态嵌入技术,它直接挂着rundll32进程运行,用rundll32的方法(rundll32.exe [DLL名],[函数] [参数])像调用API一样去引用这个DLL的启动函数激发木马模块开始执行,即使你杀了rundll32,木马本体还是在的,一个最常见的例子就是3721中文实名,虽然它不是木马。

  注册表的AppInit_DLLs键也被一些木马用来启动自己,如求职信病毒。利用注册表启动,就是让系统执行DllMain来达到启动木马的目的。因为它是kernel调入的,对这个DLL的稳定性有很大要求,稍有错误就会导致系统崩溃,所以很少看到这种木马。

  有一些更复杂点的DLL木马通过svchost.exe启动,这种DLL木马必须写成NT-Service,入口函数是ServiceMain,一般很少见,但是这种木马的隐蔽性也不错,而且Loader有保障。

  4. 其它

  到这里大家也应该对DLL木马有个了解了,是不是很想写一个?别急,不知道大家想过没有,既然DLL木马这么好,为什么到现在能找到的DLL木马寥寥无几?现在让我来泼冷水,最重要的原因只有一个:由于DLL木马挂着系统进程运行,如果它本身写得不好,例如没有防止运行错误的代码或者没有严格规范用户的输入,DLL就会出错崩溃。别紧张,一般的EXE也是这样完蛋的,但是DLL崩溃会导致它挂着的程序跟着遭殃,别忘记它挂接的是系统进程哦,结局就是……惨不忍睹。所以写一个能公布的DLL木马,在排错检查方面做的工作要比一般的EXE木马多,写得多了自己都烦躁……

  六、DLL木马的发现和查杀

  经常看看启动项有没有多出莫名其妙的项目,这是Loader的所在,只要杀了狼,狈就不能再狂了。而DLL木马本体比较难发现,需要你有一定编程知识和分析能力,在Loader里查找DLL名称,或者从进程里看多挂接了什么陌生的DLL,可是对新手来说……总之就是比较难啊比较难,所以,最简单的方法:杀毒软件和防火墙(不是万能药,切忌长期服用)。

posted @ 2006-05-31 11:29 青蛙學堂 阅读(141) | 评论 (0)编辑 收藏

Delphi编程发送E-mail

接发E-mail是许多“网虫”必修的功课,E-mail工具软件也很多,国外
的有Microsoft的OutlookExpress、TheBat等,国内则有FoxMail这样的精品。
其实,利用可视化编程工具Delphi4.0也能够制作出自己的E-mail软件。
Delphi4.0有关E-mail的组件有两个:NmPOP3和NmSTMP,它们都位于Internet
选项卡上,其中,NmPOP3组件封装并实现POP3协议,用来从InternetPOP3服务
器上读取电子邮件;NmSTMP封装并实现STMP协议,可用来向Internet的STMP服
务器发送电子邮件。限于篇幅,我们不能两者都介绍,这里只用NmSTMP编写一
个发送E-mail的程序,至于NmPOP3,以后有机会再谈,或者在看完本文后你有
兴趣,也可以借助于Delphi的帮助文档尝试用NmPOP3编程。
我们先来看一下程序运行界面。图1是程序主窗体,上面有一个字符串网格
(StringGrid)和三个按钮,它们的容器是仅有一个标签的PageControl。单击
“Clear”钮清除网格内容,单击“Send”钮发送E-mail,单击“NewMail”
钮弹出图2所示的对话框,此对话框用来设置STMP服务器名称、发件人地址、收
件人地址、发件人名称和邮件主题,其中前三项必须填写,“SelectFile”按
钮用来打开Open对话框,以便选取要发送的附件。
NmSTMP的属性和方法不多,关键的属性是Host(STMP服务器名称)和PostMessage
(包含邮件信息),正确设置了Host属性和PostMessage属性后,就可以用Connect
方法(连接服务器)和SendMail方法发送E-mail了。
编写代码之前先要改变StringGrid1的一些缺省属性:ColCount属性为6,
FixedCols属性为0,RowCount属性为2,另外,将PageControl1的Align属性置
为alClient。
以下是Unit1(主窗体)代码清单:
unitUnit1;
interface
uses
Windows,Messages,SysUtils,Classes,Graphics,Controls,Forms,
Dialogs,Grids,ComCtrls,StdCtrls,Psock,NMsmtp;
type
TForm1=class(TForm)
PageControl1:TPageControl;
TabSheet1:TTabSheet;
StatusBar1:TStatusBar;
StringGrid1:TStringGrid;
Button1:TButton;
Button2:TButton;
Button3:TButton;
NMSMTP1:TNMSMTP;
procedureFormCreate(Sender:TObject);
procedureButton1Click(Sender:TObject);
procedureButton2Click(Sender:TObject);
procedureButton3Click(Sender:TObject);
procedureNMSMTP1Failure(Sender:TObject);
procedureNMSMTP1SendStart(Sender:TObject);
procedureNMSMTP1Success(Sender:TObject);
private
{Privatedeclarations}
public
{Publicdeclarations}
end;
var
Form1:TForm1;
implementation
usesUnit2;
{$R*.DFM}
procedureTForm1.FormCreate(Sender:TObject);
begin
PageControl1.Pages[0].Caption:=‘SendMail’;
self.Caption:=‘MyMailer’;
self.BorderIcons:=[biSystemMenu,biMinimize];
self.BorderStyle:=bsSingle;
Application.Icon:=self.Icon;
Application.Title:=self.Caption;
withStringGrid1do
begin
Cells[0,0]:=‘Host’;
Cells[1,0]:=‘ToAddress’;
Cells[2,0]:=‘FromAddress’;
Cells[3,0]:=‘YourName’;
Cells[4,0]:=‘Subject’;
Cells[5,0]:=‘File’;
end;
Button2.Enabled:=False;
Button3.Enabled:=False;
end;
procedureTForm1.Button1Click(Sender:TObject);
begin
Form2.Show;
end;
procedureTForm1.Button2Click(Sender:TObject);
var
i:Integer;
begin
fori:=1toStringGrid1.RowCount-2do
withNmsmtp1do
begin
Host:=StringGrid1.Cells[0,i];
PostMessage.ToAddress.Add(StringGrid1.Cells[1,i]);
PostMessage.FromAddress:=StringGrid1.Cells[2,i];
PostMessage.FromName:=StringGrid1.Cells[3,i];
PostMessage.Subject:=StringGrid1.Cells[4,i];
PostMessage.Attachments.Add(StringGrid1.Cells[5,i]);
Connect;
Sendmail;
DisConnect;
end;
Button2.Enabled:=False;
Button3.Click;
end;
procedureTForm1.Button3Click(Sender:TObject);
var
i:Integer;
begin
withStringGrid1do
begin
fori:=1toRowCount-2do
begin
Cells[0,i]:=‘’;
Cells[1,i]:=‘’;
Cells[2,i]:=‘’;
Cells[3,i]:=‘’;
Cells[4,i]:=‘’;
Cells[5,i]:=‘’;
end;
RowCount:=2;
end;
Button2.Enabled:=False;
Button3.Enabled:=False;
end;
procedureTForm1.NMSMTP1Failure(Sender:TObject);
begin
StatusBar1.SimpleText:=‘Mailsendfailure!’;
end;
procedureTForm1.NMSMTP1SendStart(Sender:TObject);
begin
StatusBar1.SimpleText:=‘NowSending...’;
end;
procedureTForm1.NMSMTP1Success(Sender:TObject);
begin
StatusBar1.SimpleText:=‘SendSuccess!’;
end;
end.
Button1是“NewMail”按钮,Button2是“Send”按钮,Button3是“Clear”按钮。
以下是Unit2代码清单:
unitUnit2;
interface
uses
Windows,Messages,SysUtils,Classes,Graphics,Controls,Forms,
Dialogs,StdCtrls;
type
TForm2=class(TForm)
OpenDialog1:TOpenDialog;
GroupBox1:TGroupBox;
GroupBox2:TGroupBox;
Edit1:TEdit;
Edit2:TEdit;
Edit3:TEdit;
Edit4:TEdit;
Edit5:TEdit;
Button1:TButton;
Button2:TButton;
Button3:TButton;
Label1:TLabel;
Label2:TLabel;
Label3:TLabel;
Label4:TLabel;
Label5:TLabel;
Label6:TLabel;
procedureButton1Click(Sender:TObject);
procedureButton2Click(Sender:TObject);
procedureButton3Click(Sender:TObject);
procedureFormActivate(Sender:TObject);
procedureFormCreate(Sender:TObject);
private
{Privatedeclarations}
public
{Publicdeclarations}
end;
var
Form2:TForm2;
implementation
usesUnit1;
{$R*.DFM}
procedureTForm2.FormCreate(Sender:TObject);
begin
self.Caption:=‘NewMail’;
self.BorderStyle:=bsDialog;
end;
procedureTForm2.FormActivate(Sender:TObject);
begin
Edit1.Text:=‘’;
Edit2.Text:=‘’;
Edit3.Text:=‘’;
Edit4.Text:=‘’;
Edit5.Text:=‘’;
Label1.Caption:=‘NoFile’;
end;
procedureTForm2.Button1Click(Sender:TObject);
begin
ifOpenDialog1.Executethen
Label1.Caption:=Opendialog1.Filename;
end;
procedureTForm2.Button2Click(Sender:TObject);
var
i:Integer;
begin
if(Edit1.Text<>‘’)and(Edit2.Text<>‘’)and(Edit5.Text<>‘’)
and(Label1.Caption<>‘NoFile’)then
begin
withForm1.StringGrid1do
begin
RowCount:=RowCount+1;
i:=RowCount-2;
Cells[0,i]:=Edit1.Text;
Cells[1,i]:=Edit2.Text;
Cells[2,i]:=Edit5.Text;
Cells[3,i]:=Edit3.Text;
Cells[4,i]:=Edit4.Text;
Cells[5,i]:=Label1.Caption;
end;
Form1.Button2.Enabled:=True;
Form1.Button3.Enabled:=True;
end;
self.Hide;
end;
procedureTForm2.Button3Click(Sender:TObject);
begin
self.Hide;
end;
end.
Edit1、Edit2、Edit3、Edit4、Edit5编辑框分别用于填写服务器名称、收件
人地址、发件人名称、邮件主题和发件人地址。
现在一个E-mail发送程序就完成了。你可以试一试,自已给自已发几封邮件,
用FoxMail之类的软件是否能收到信。顺便说一句,本文就是用这个自编程序发到
编辑部的。

 

posted @ 2006-05-24 09:13 青蛙學堂 阅读(366) | 评论 (0)编辑 收藏

仅列出标题
共43页: First 25 26 27 28 29 30 31 32 33 Last 
<2006年2月>
2930311234
567891011
12131415161718
19202122232425
2627281234
567891011

导航

统计

常用链接

留言簿(8)

随笔分类

随笔档案

收藏夹

青蛙学堂

最新评论

阅读排行榜

评论排行榜