分享好友 编程语言首页 频道列表

Delphi TStream 详细介绍

delphi文章/教程  2023-02-09 10:280

Delphi TStream 详细介绍


Stream对象,又称流式对象,是TStream、THandleStream、TFileStream、TMemoryStream、TResourceStream和TBlobStream等的统称。它们分别代表了在各种媒介上存储数据的能力,它们将各种数据类型(包括对象和部件)

在内存、外存和数据库字段中的管理操作抽象为对象方法,并且充分利用了面向对象技术的优点,应用程序可以相当容易地在各种Stream对象中拷贝数据。

  下面介绍各种对象的数据和方法及使用方法。

TStream对象

  TStream对象是能在各种媒介中存储二进制数据的对象的抽象对象。从TStream
对象继承的对象用于在内存、Windows资源文件、磁盘文件和数据库字段等媒介中存储数据。
 
Stream中定义了两个属性:Size和Position。它们分别以字节为单位表示的流的大小和当前指针位置。TStream中定义的方法用于在各种流中读、写和相互拷贝二进制数据。因为所有的Stream对象都是从TStream中继承来的,所以在TStream中定义的域和方法都能被Stream对象调用和访

问。此外,又由于面向对象技术的动态联编功能,TStream为各种流的应用提供了统一的接口,简化了流的使用;不同Stream对象是抽象了对不同存储媒介的数据上的操作,因此,TStream的需方法为在不同媒介间的数据拷贝提供了最简捷的手段。

TStream的属性和方法

  1.
Position属性 
声明:property Position: Longint;
  Position属性指明流中读写的当前偏移量。

  2. Size属性
  声明:property Size: Longint;

Size属性指明了以字节为单位的流的的大小,它是只读的。
  3. CopyFrom方法
  声明:function
CopyFrom(Source: TStream; Count: Longint): Longint;

CopyFrom从Source所指定的流中拷贝Count个字节到当前流中, 并将指针从当前位置移动Count个字节数,函数返回值是实际拷贝的字节数。

  4. Read方法
  声明:function Read(var Buffer; Count: Longint): Longint;
virtual; abstract;

Read方法从当前流中的当前位置起将Count个字节的内容复制到Buffer中,并把当前指针向后移动Count个字节数,函数返回值是实际读的字节数。如果返回值小于Count,这意味着读操作在读满所需字节数前指针已经到达了流的尾部。

  Read方法是抽象方法。每个后继Stream对象都要根据自己特有的有关特定存储媒介的读操作覆盖该方法。而且流的所有其它的读数据的方法(如:ReadBuffer,ReadComponent等)在完成实际的读操作时都调用了Read方法。面向对象的动态联编的优点就体现在这儿。因为后继Stream对

象只需覆盖Read方法,而其它读操作(如ReadBuffer、ReadComponent等)都不需要重新定义,而且TStream还提供了统一的接口。

  5. ReadBuffer方法
  声明:procedure ReadBuffer(var Buffer; Count: Longint);

  ReadBuffer方法从流中将Count个字节复制到Buffer 中,
并将流的当前指针向后移动Count个字节。如读操作超过流的尾部,ReadBuffer方法引起EReadError异常事件。
  6.
ReadComponent方法
  声明:function ReadComponent(Instance: TComponent):
TComponent;

ReadComponent方法从当前流中读取由Instance所指定的部件,函数返回所读的部件。ReadComponent在读Instance及其拥有的所有对象时创建了一个Reader对象并调用它的ReadRootComponent方法。

  如果Instance为nil,ReadComponent的方法基于流中描述的部件类型信息创建部件,并返回新创建的部件。
  7.
ReadComponentRes方法
  声明:function ReadComponentRes(Instance: TComponent):
TComponent;

ReadComponentRes方法从流中读取Instance指定的部件,但是流的当前位置必须是由WriteComponentRes方法所写入的部件的位置。

  ReadComponentRes

首先调用ReadResHeader方法从流中读取资源头,然后调用ReadComponent方法读取Instance。如果流的当前位置不包含一个资源头。ReadResHeader将引发一个EInvalidImage异常事件。在Classes库单元中也包含一个名为ReadComponentRes的函数,该函数执行相同的操作,只不过它基于应

用程序包含的资源建立自己的流。
  8. ReadResHeader方法
  声明:procedure ReadResHeader;

ReadResHeader方法从流的当前位置读取Windows资源文件头,并将流的当前位置指针移到该文件头的尾部。如果流不包含一个有效的资源文件头,ReadResHeader将引发一个EInvalidImage异常事件。

  流的ReadComponentRes方法在从资源文件中读取部件之前,会自动调用ReadResHeader方法,因此,通常程序员通常不需要自己调用它。

  9. Seek方法
  声明:function Seek(Offset: Longint; Origin: Word): Longint;
virtual; abstract;

Seek方法将流的当前指针移动Offset个字节,字节移动的起点由Origin指定。如果Offset是负数,Seek方法将从所描述的起点往流的头部移动。下表中列出了Origin的不同取值和它们的含义:

函数Seek的参数的取值

 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  常量       值      Seek的起点 Offset的取值

─────────────────────────────────
 SoFromBeginning 0  流的开头 正 数

 SoFromCurrent 1 流的当前位置 正数或负数
 SoFromEnd 2 流的结尾 负 数

 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  10. Write方法

  在Delphi对象式管理的对象中有两类对象的方法都有称为Write的:Stream对象和Filer对象。Stream对象的Write方法将数据写进流中。Filer对象通过相关的流传递数据,在后文中会介绍这类方法。

  Stream对象的Write方法声明如下:

function Write(const Buffer; Count: Longint):
Longint; virtual; abstract;


Write方法将Buffer中的Count个字节写入流中,并将当前位置指针向流的尾部移动Count个字节,函数返回写入的字节数。
 
TStream的Write方法是抽象的,每个继承的Stream对象都要通过覆盖该方法来提供向特定存储媒介(内存、磁盘文件等)写数据的特定方法。流的其它所有写数据的方法(如WriteBuffer、WriteComponent)都调用Write担当实际的写操作。

  11. WriteBuffer方法
  声明:procedure WriteBuffer(const Buffer; Count:
Longint);

  WriteBuffer的功能与Write相似。WriteBuffer方法调用Write来执行实际的写操作,如果流没能写所有字节,WriteBuffer会触发一个EWriteError异常事件。

  12. WriteComponent方法

  在Stream对象和Filer对象都有被称为WriteComponent的方法。Stream对象的WriteComponent方法将Instance所指定的部件和它所包含的所有部件都写入流中;Writer对象的WriteComponent将指定部件的属性值写入Writer对象的流中。

  Stream对象的WriteComponent方法声明是这样的:
procedure WriteComponent(Instance:
Tcomponent);


  WriteComponent创建一个Writer对象,并调用Writer的WriteRootComponent方法将Instance及其拥有的对象写入流。

  13. WriteComponentRes方法
  声明:WriteComponentRes(const ResName: String;
Instance: TComponent);
  WriteComponentRes方法首先往流中写入标准Windows
资源文件头,然后将Instance指定的部件写入流中。要读由WriteComponentRes写入的部件,必须调用ReadComponentRes方法。

  WriteComponentRes使用ResName传入的字符串作为资源文件头的资源名,然后调用WriteComponent方法将Instance和它拥有的部件写入流。

  14. WriteDescendant方法
  声明:procedure WriteDescendant(Instance
Ancestor: TComponent);

  Stream对象的WriteDescendant方法创建一个Writer对象,然后调入该对象的WriteDescendant方法将Instance部件写入流中。Instance可以是从Ancestor部件继承的窗体,也可以是在从祖先窗体中继承的窗体中相应于祖先窗体中Ancestor部件的部件。

  15. WriteDescendantRes方法
  声明:procedure WriteDescendantRes(const
ResName: String;
Instance, Ancestor: TComponent);

  WriteDescendantRes方法将Windows资源文件头写入流,并使用ResName作用资源名,然后调用WriteDescendant方法,将Instance写入流。

TStream的实现原理

  TStream对象是Stream对象的基础类,这是Stream对象的基础。为了能在不同媒介上的存储数据对象,后继的Stream对象主要是在Read和Write方法上做了改进,。因此,了解TStream是掌握Stream对象管理的核心。Borland公司虽然提供了Stream对象的接口说明文档,但对于其实现和应

用方法却没有提及,笔者是从Borland Delphi 2.0 Client/Server Suite 提供的源代码和部分例子程序中掌握了流式对象技术。

  下面就从TStream的属性和方法的实现开始。
  1. TStream属性的实现

  前面介绍过,TStream具有Position和Size两个属性,作为抽象数据类型,它抽象了在各种存储媒介中读写数据所需要经常访问的域。那么它们是怎样实现的呢?

  在自定义部件编写这一章中介绍过部件属性定义中的读写控制。Position和Size也作了读写控制。定义如下:

property
Position: Longint read GetPosition write SetPosition;
property Size: Longint
read GetSize;

  由上可知,Position是可读写属性,而Size是只读的。

  Position属性的实现就体现在GetPosition和SetPosition。当在程序运行过程中,任何读取Position的值和给Position赋值的操作都会自动触发私有方法GetPosition和SetPosition。两个方法的声明如下:

function
TStream.GetPosition: Longint;
begin
Result := Seek(0, 1);

end;

procedure TStream.SetPosition(Pos: Longint);
begin

Seek(Pos, 0);
end;

在设置位置时,Delphi编译机制会自动将Position传为Pos。

  前面介绍过Seek的使用方法,第一参数是移动偏移量,第二个参数是移动的起点,返回值是移动后的指针位置。

  Size属性的实现只有读控制,完全屏蔽了写操作。读控制方法GetSize实现如下:

function TStream.GetSize:
Longint;
var
Pos: Longint;
begin
Pos := Seek(0, 1);
Result
:= Seek(0, 2);
Seek(Pos, 0);
end;

2. TStream方法的实现
  ⑴
CopyFrom方法

  CopyFrom是Stream对象中很有用的方法,它用于在不同存储媒介中拷贝数据。例如,内存与外部文件之间、内存与数据库字段之间等。它简化了许多内存分配、文件打开和读写等的细节,将所有拷贝操作都统一到Stream对象上。

  前面曾介绍:CopyFrom方法带Source和Count两个参数并返回长整型。该方法将Count个字节的内容从Source拷贝到当前流中,如果Count值为0则拷贝所有数据。

function
TStream.CopyFrom(Source: TStream; Count: Longint): Longint;
const

MaxBufSize = $F000;
var
BufSize, N: Integer;
Buffer: PChar;

begin
if Count = 0 then
begin
Source.Position := 0;
Count :=
Source.Size;
end;
Result := Count;
if Count > MaxBufSize then
BufSize := MaxBufSize else BufSize := Count;
GetMem(Buffer, BufSize);

try
while Count <> 0 do
begin
if Count > BufSize then

N := BufSize
else
N := Count;
Source.ReadBuffer(Buffer^, N);

WriteBuffer(Buffer^, N);
Dec(Count, N);
end;
finally

FreeMem(Buffer, BufSize);
end;
end;

  ⑵
ReadBuffer方法和WriteBuffer方法

  ReadBuffer方法和WriteBuffer方法简单地调用虚拟函数Read、Write来读写流中数据,它比Read和Write增加了读写数据出错时的异常处理。

procedure
TStream.ReadBuffer(var Buffer; Count: Longint);
begin
if (Count <>
0) and (Read(Buffer, Count) <> Count) then
raise
EReadError.CreateRes(SReadError);
end;

procedure
TStream.WriteBuffer(const Buffer; Count: Longint);
begin
if (Count
<> 0) and (Write(Buffer, Count) <> Count) then
raise
EWriteError.CreateRes(SWriteError);
end;

  ⑶
ReadComponent、ReadResHeader和ReadComponentRes方法

  ReadComponent方法从当前流中读取部件。在实现上ReadComponent方法创建了一个TStream对象,并用TReader的ReadRootComponent方法读部件。在Delphi对象式管理中,Stream对象和Filer对象结合很紧密。Stream对象的许多方法的实现需要Filer对象的支持,而Filer对象的构造函数

直接就以Stream对象为参数。在ReadComponent方法的实现中就可清楚地看到这一点:

function
TStream.ReadComponent(Instance: TComponent): TComponent;
var
Reader:
TReader;
begin
Reader := TReader.Create(Self, 4096);
try
Result
:= Reader.ReadRootComponent(Instance);
finally
Reader.Free;
end;

end;

ReadResHeader方法用于读取Windows资源文件的文件头,由ReadComponentRes方法在读取Windows资源文件中的部件时调用,通常程序员不需自己调用。如果读取的不是资源文件ReadResH
:= FSize + Offset;
end;
Result := FPosition;

end;

  Offse代表移动的偏移量。Origin代表移动的起点,值为0表示从文件头开始,值为1表示从当前位置开始,值为2表示从文件尾往前,这时OffSet一般为负数。Seek的实现没有越界的判断。

  3. SaveToStream和SaveToFile方法

  SaveToStream方法是将MemoryStream对象中的内容写入Stream所指定的流。其实现如下:

procedure
TCustomMemoryStream.SaveToStream(Stream: TStream);
begin
if FSize
<> 0 then Stream.WriteBuffer(FMemory^, FSize);

end;

  SaveToStream方法调用了Stream的WriteBuffer方法,直接将FMemory中的内容按FSize字节长度写入流中。

  SaveToFile方法是与SaveToStream方法相关的。SaveToFile方法首先创建了一个FileStream对象,然后把该文件Stream对象作为SaveToStream的参数,由SaveToStream
方法执行写操作,其实现如下:

procedure TCustomMemoryStream.SaveToFile(const FileName:
string);
var
Stream: TStream;
begin
Stream :=
TFileStream.Create(FileName, fmCreate);
try
SaveToStream(Stream);

finally
Stream.Free;
end;
end;

  在Delphi
的许多对象的SaveToStream
和SaveToFile、LoadFromStream和LoadFromFile方法的实现都有类似的嵌套结构。

TMemoryStream对象

 

TMemoryStream对象是一个管理动态内存中的数据的Stream对象,它是从TCustomMemoryStream中继承下来的,除了从TCustomMemoryStream中继承的属性和方法外,它还增加和覆盖了一些用于从磁盘文件和其它注台读数据的方法。它还提供了写入、消除内存内容的动态内存管理方法。下面

介绍它的这些属性和方法。

TMemoryStream的属性和方法

  1. Capacity属性

  声明:property Copacity: Longint;

Capacity属性决定了分配给内存流的内存池的大小。这与Size属性有些不同。Size属性是描述流中数据的大小。在程序中可以将Capacity
的值设置的比数据所需最大内存大一些,这样可以避免频繁地重新分配。
  2. Realloc方法
  声明:function
Realloc(var NewCapacity: Longint): Pointer; virtual;

Realloc方法,以8K为单位分配动态内存,内存的大小由NewCapacity指定,函数返回指向所分配内存的指针。
  3.
SetSize方法

  SetSize方法消除内存流中包含的数据,并将内存流中内存池的大小设为Size字节。如果Size为零,是SetSize方法将释放已有的内存池,并将Memory属性置为nil;否则,SetSize方法将内存池大小调整为Size。

4. Clear方法
  声明:procedure Clear;

Clear方法释放内存中的内存池,并将Memory属性置为nil。在调用Clear方法后,Size和Position属性都为0。
  5.
LoadFromStream方法
  声明:procedure LoadFromStream(Stream: TStream);

LoadFromStream方法将Stream指定的流中的全部内容复制到MemoryStream中,复制过程将取代已有内容,使MemoryStream成为Stream的一份拷贝。

  6. LoadFromFile方法
  声明:procedure LoadFromFile(count FileName: String);

LoadFromFile方法将FileName指定文件的所有内容复制到MemoryStream中,并取代已有内容。调用LoadFromFile方法后,MemoryStream将成为文件内容在内存中的完整拷贝。

TMemoryStream对象的实现原理

  TMemoryStream从TCustomMemoryStream对象直接继承,因此可以享用TCustomMemoryStream的属性和方法。前面讲过,TCustomMemoryStream是用于内存中数据操作的抽象对象,它为MemoryStream对象的实现提供了框架,框架中的内容还要由具体MemoryStream对象去填充。TMemoryStrea

m对象就是按动态内存管理的需要填充框架中的具体内容。下面介绍TMemoryStream对象的实? FBuffer :=
AllocMem(FDataSet.RecordSize);
FRecord := FBuffer;
if not
FDataSet.GetCurrentRecord(FBuffer) then Exit;
OpenMode := dbiReadOnly;

end else
begin
if not (FDataSet.State in [dsEdit, dsInsert]) then
DBError(SNotEditing);
OpenMode := dbiReadWrite;
end;

Check(DbiOpenBlob(FDataSet.Handle, FRecord, FFieldNo, OpenMode));
end;

FOpened := True;
if Mode = bmWrite then Truncate;

end;

 该方法首先是用传入的Field参数给FField,FDataSet,FRecord和FFieldNo赋值。方法中用AllocMem按当前记录大小分配内存,并将指针赋给FBuffer,用DataSet部件的GetCurrentRecord方法,将记录的值赋给FBuffer,但不包括BLOB数据。

  方法中用到的DbiOpenBlob函数是BDE的API函数,该函数用于打开数据库中的BLOB字段。

  最后如果方法传入的Mode参数值为bmWrite,就调用Truncate将当前位置指针以后的
数据删除。

  分析这段源程序不难知道:
  ● 读写BLOB字段,不允许BLOB字段所在DataSet部件有Filter,否则产生异常事件
  ●
要读写BLOB字段,必须将DataSet设为编辑或插入状态
  ● 如果BLOB字段中的数据作了修改,则在创建BLOB
流时,不再重新调用DBiOpenBlob函数,而只是简单地将FOpened置为True,这样可以用多个BLOB
流对同一个BLOB字段读写

  Destroy方法释放BLOB字段和为FBuffer分配的缓冲区,其实现如下:

destructor
TBlobStream.Destroy;
begin
if FOpened then
begin
if FModified
then FField.FModified := True;
if not FField.FModified then

DbiFreeBlob(FDataSet.Handle, FRecord, FFieldNo);
end;
if FBuffer
<> nil then FreeMem(FBuffer, FDataSet.RecordSize);
if FModified then

try
FField.DataChanged;
except

Application.HandleException(Self);
end;

end;

  如果BLOB流中的数据作了修改,就将FField的FModified置为True;如果FField的Modified为False就释放BLOB字段,如果FBuffer不为空,则释放临时内存。最后根据FModified的值来决定是否启动FField的事件处理过程DataChanged。

  不难看出,如果BLOB字段作了修改就不释放BLOB字段,并且对BLOB
字段的修改只有到Destroy时才提交,这是因为读写BLOB字段时都避开了FField,而直接调用BDE API函数。这一点是在应用BDE
API编程中很重要,即一定要修改相应数据库部件的状态。
  2. Read和Write方法的实现
  Read和Write方法都调用BDE
API函数完成数据库BLOB字段的读写,其实现如下:
  
function TBlobStream.Read(var Buffer;
Count: Longint): Longint;
var
Status: DBIResult;
begin
Result :=
0;
if FOpened then
begin
Status := DbiGetBlob(FDataSet.Handle,
FRecord, FFieldNo, FPosition,
Count, @Buffer, Result);
case Status of

DBIERR_NONE, DBIERR_ENDOFBLOB:
begin
if FField.FTransliterate then

NativeToAnsiBuf(FDataSet.Locale, @Buffer, @Buffer, Result);

Inc(FPosition, Result);
end;
DBIERR_INVALIDBLOBOFFSET:

{Nothing};
else
DbiError(Status);
end;
end;

end;

  Read方法使用了BDE

API的DbiGetBlob函数从FDataSet中读取数据,在本函数中,各参数的含义是这样的:FDataSet.Handle代表DataSet的BDE句柄,FReacord表示BLOB字段所在记录,FFieldNo表示BLOB字段号,FPosition表示要读的的数据的起始位置,Count表示要读的字节数,Buffer是读出数据所占的内存,

Result是实际读出的字节数。该BDE函数返回函数调用的错误状态信息。

  Read方法还调用了NativeToAnsiBuf进行字符集的转换。

function TBlobStream.Write(const
Buffer; Count: Longint): Longint;
var
Temp: Pointer;
begin

Result := 0;
if FOpened then
begin
if FField.FTransliterate then

begin
GetMem(Temp, Count);
try
AnsiToNativeBuf(FDataSet.Locale,
@Buffer, Temp, Count);
Check(DbiPutBlob(FDataSet.Handle, FRecord, FFieldNo,
FPosition,
Count, Temp));
finally
FreeMem(Temp, Count);
end;

end else
Check(DbiPutBlob(FDataSet.Handle, FRecord, FFieldNo, FPosition,

Count, @Buffer));
Inc(FPosition, Count);
Result := Count;

FModified := True;
end;
end;

Write方法调用了BDE
API的DbiPutBlob函数实现往数据库BLOB字段存储数据。

该函数的各参数含义如下:

调用函数DbiPutBlob的各传入参数的含义

 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
   参数名           含义

──────────────────────────────
  FDataSetHandle 写入的数据库的BDE句柄
 
FRecord 写入数据的BLOB字段所在的记录
FFieldNo BLOB字段号
  FPosition 写入的起始位置
 
Count 写入的数据的字节数
  Buffer 所写入的数据占有的内存地址
 
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

标志,该标志意味着后面存储有一连串的项目。Reader对象,在读这一连串项目时先调用ReadListBegin方法读取该标志位,然后用EndOfList判断是否列表结束,并用循环语句读取项目。在调用WriteListBegin方法的后面必须调用WriteListEnd方法写列表结束标志,相应的在Reader对象中

有ReadListEnd方法读取该结束标志。
  5. WriteListEnd方法
  声明:procedure
WriteListEnd;
WriteListEnd方法在流中,写入项目列表结束标志,它是与WriteListBegin相匹配的方法。
  6.
WriteBoolean方法
  声明:procedure WriteBoolean(Value: Boolean);

WriteBoolean方法将Value传入的布尔值写入流中。
  7. WriteChar方法
  声明:procedure
WriteChar(Value: char);
WriteChar方法将Value中的字符写入流中。
  8. WriteFloat方法

  声明:procedure WriteFloat(Value: Extended);

WriteFloat方法将Value传入的浮点数写入流中。
  9. WriteInteger方法
  声明:procedure
WriteInteger(Value: Longint);
WriteInteger方法将Value中的整数写入流中。
  10.
WriteString方法
  声明:procedure WriteString(const Value: string);

WriteString方法将Value中的字符串写入流中。
  11. WriteIdent方法
  声明:procedure
WriteIdent(const Ident: string);
WriteIdent方法将Ident传入的标识符写入流中。
  12.
WriteSignature方法
  声明:procedure WriteSignature;
WriteSignature方法将Delphi
Filer对象标签写入流中。WriteRootComponent方法在将部件写入流之前先调用WriteSignature方法写入Filer标签。Reader对象在读部件之前调用ReadSignature方法读取该标签以指导读操作。

  13. WritComponent方法
  声明:procedure WriteComponent(Component:
TComponent);

WriteComponent方法调用参数Component的WriteState方法将部件写入流中。在调用WriteState之前,WriteComponent还将Component的ComponetnState属性置为csWriting。当WriteState返回时再清除csWriting.

14. WriteRootComponent方法
  声明:procedure WriteRootComponent(Root:
TComponent);

WriteRootComponent方法将Writer对象Root属性设为参数Root带的值,然后调用WriteSignature方法往流中写入Filer对象标签,最后调用WriteComponent方法在流中存储Root部件。

查看更多关于【delphi文章/教程】的文章

展开全文
相关推荐
反对 0
举报 0
评论 0
图文资讯
热门推荐
优选好物
更多热点专题
更多推荐文章
Delphi中的消息处理机制 delphi 方法
每一个VCL都有一内在的消息处理机制,其基本点就是构件类接收到某些消息并把它们发送给适当的处理方法,如果没有特定的处理方法,则调用缺省的消息处理句柄。    其中mainwndproc是定义在Twincontrol类中的一个静态方法,不能被重载(Override)。它不直接处

0评论2023-02-09482

Delphi CompilerVersion Constant / Compiler Conditional Defines
http://delphi.wikia.com/wiki/CompilerVersion_Constant The CompilerVersion constant identifies the internal version number of the Delphi compiler.It is defined in the System unit and may be referenced either in code just as any other consta

0评论2023-02-09888

Delphi revelations #1 – kbmMW Smart client on NextGen (Android) – Scope problems kbmmw中向服务器端传递
Delphi 启示 #1 – kbmMW Smart client on NextGen (Android) – 作用域问题以更高级的方式使用kbmMW smart client,在Android设备上,我遇到了问题。通过继承TInvokeableVariantType,kbmMW smart client可以使用Delphi支持的特殊类型的自定义Variant,从而可

0评论2023-02-09360

Delphi 调用DLL外部函数时的指针参数
某项目需要调用设备厂家提供的DLL的函数,厂家给了一个VB的例子,有个参数是ByRef pBuffer As Single。于是在Delphi中用buffer:array of single代替:function func(buffer:array of single;count:integer):integer;far;stdcall;external 'func.dll';调用后bu

0评论2023-02-09964

《zw版·Halcon-delphi系列原创教程》 Halcon分类函数012,polygon,多边形
《zw版·Halcon-delphi系列原创教程》 Halcon分类函数012,polygon,多边形为方便阅读,在不影响说明的前提下,笔者对函数进行了简化::: 用符号“**”,替换:“procedure”:: 用大写字母“X”,替换:“IHUntypedObjectX”:: 省略了字符:“const”、“OleVa

0评论2023-02-09662

最简单的delphi启动画面(转)
首先做一窗体,然后将BorderStyle的属性设为bsnone,放image控件,align设为alclient 然后将主程序的修改为 uses Windows, Forms, Unit1 in 'Unit1.pas' {Form1}, Unit2 in 'Unit2.pas' {Form2}; {$ R *.res} begin Application.Initialize; Form2:=TForm2.Cre

0评论2023-02-09349

Delphi备忘三:TCollection的使用,用Stream保存
 代码unit ufrmGetFunctionDefine;interfaceuses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,TypInfo,  Dialogs,ufrmStockBaseCalc, StdCtrls, ComCtrls,uQEFuncManager,uWnDataSet,uDataService;type  T

0评论2023-02-09409

Delphi Dcp 和BPL的解释
dcp = delphi compiled package,是 package 编译时跟 bpl 一起产生出来的,记录着 package 中公开的 class、procedure、function、variable、const.... 等等的名称和相对位址。package英文翻译过来就是“包”。如果 某个控件包 A 引用了 控件包 B,当 控件包

0评论2023-02-09393

Delphi面向对象学习随笔六:接口 delphi基础
作者:巴哈姆特(转载请注明出处并保持完整) 在对象化中,类的继承是一个非常强大的机制;而更加强大的继承机制应该是来自从一个接口的继承。    本篇我们将讨论接口的特点。    首先,接口的定义方式与类相似。不同的是:类代表了一种实体,而接口代

0评论2023-02-09803

Delphi 的字符及字符串[2] - Char、AnsiChar、WideChar、PChar、PAnsiChar、PWideChar
//单字符 Char、AnsiChar (在目前版本(2007)中, 它们是一回事, 只有 1 字节大小)var  c: Char; {Char 类型的取值范围是: #0..#255, 用十六进制表示是: #$0..#$FF}begin  {用十进制方式赋值:}  c := #65;  ShowMessage(c); {A}  {用十六进制方式赋值:} 

0评论2023-02-09353

Delphi XE2读取内存偏移数据代码
刚学习的时候直接读取基值是很简单的,但是类型[[[00a41ff0+1c]+34]+490]这样的偏移数值应该如何读取呢?下面给大家分享下Delphi 的代码:varGameH:HWND; {定义窗口句柄}GamePid:DWORD;{定义窗口进程ID}ReadByte:SIZE_T;{实际读取字节}Gamehprocess: THandle;

0评论2023-02-09681

《zw版·Halcon-delphi系列原创教程》 Halcon分类函数007, match,图像匹配
《zw版·Halcon-delphi系列原创教程》 Halcon分类函数007, match,图像匹配为方便阅读,在不影响说明的前提下,笔者对函数进行了简化::: 用符号“**”,替换:“procedure”:: 用大写字母“X”,替换:“IHUntypedObjectX”:: 省略了字符:“const”、“OleV

0评论2023-02-09495

Delphi 数据类型的说明
简单类型包括实数类型(Real) 和有序类型(Ordinal),有序类型又包括整数类型,字符类型,布尔类型,枚举类型和子界类型等。数据类型                       范围                                 

0评论2023-02-09615

问题-[Delphi]MainFrame.pas(4340): E2036 Variable required
问题现象:写了一个TObjectList的Sort方法,但是写成ObjectList.Sort(@SortBridgeEDOReportQtys); 再F9时提示“E2036 Variable required”。 问题原因:[DCC错误] MainFrame.pas(4340):要求E2036变解决方法:ObjectList.Sort(@SortBridgeEDOReportQtys);

0评论2023-02-09927

Delphi发送邮件...
///首先在控件栏定位到:Indy Clients加入控件IdSMTP///再定位到:Indy Misc加入控件IdMessage ///发送邮件函数procedure TForm1.SendMail(YYuser: string;YYpass:string); begin try IdSMTP1.AuthenticationType:=atLogin; //设置登陆类型 IdSMTP1.Username:=

0评论2023-02-09383

更多推荐