信息化 频道

<连载>Protel二次开发从入门到精通

  6. 源程序代码例子
  6.1 前言

SDK提供一些源代码例子,来对在您设计资源管理器中的文档操作进行指导,再次强调,强列地建议您,不要用开发程序方式实际地创建一个设计数据库的新的记录或维护记录,即不要编写程序来在设计数据库中维护记录,除非您绝对地确信您知道您要做什么。所有的下面展示的例子,有一个共同目标,那就是给您作示范,如何来有效地使用强大的客户端API和Protel运行时间库。

有下列一些代码例子。

·“迭代并且显示”工程示范一个设计数据库的文档实体的抽象地址。项目在“\SAMPLES\NO2\API\Client\Iterate and Show”目录中。

·“Search and Open” 工程查找一个有文档名称的实体(不是一个抽象地址,然后打开设计实体)。项目在”\SAMPLES\NO2\API\Client\SearchAndOpenDocuments”目录中。

·“Import a document” 工程示范如何输入外部文件到一个设计数据库的文档实体。项目在“\SAMPLES\NO2\API\Client\Import External File”目录中。

·“Export a document” 工程示范如何把数据库中文档实体输出为外部文件。项目在“\SAMPLES\NO2\API\Client\Export a DDB document”目录中。

·“Report Schematic sheets” 工程示范了如何快速地查找原理图图表中是否有子图表,无需采取原理图API,此例子说明了一个TDDBItem类的ChildList字段的用途。项目在“\SAMPLES\NO2\API\Client\Report Child Schematic Sheets”目录中。

在此例子中方法的实现使用下列来自CSRTL运行时间库包单元之一:

迭代程序Iterators(ClientProcs 单元)。

AssignDDB 函数(DDB_StandardIO 单元)。

DDB_ImportFile函数(DDB_Import单元)。

DDB_ExportToFile(DDB_Export单元)。

DDBItem.ChildList和Streaming 函数(DDB_Item单元)。

  6.2 迭代和显示程序例子

此代码例子把当前打开的文档所在的容器名称作为输出文本文件的名称,扩展名称为TXT,创建一个文本文件,文本文件中存放在当前打开的文档所属容器中,所有的实体文档的抽象地址。

请见SDK例子\SAMPLES\NO2\API\Client\Iterate and Show。

{................................................................................}

Procedure WriteToATextDocument(Binderhandle : TObjecthandle;StringList : TstringList);

Var

F : TextFile;//文本文档。

I : Integer;

S : TString;//抽象地址字符串。

DDBAddress : TDDBAddress;//抽象地址对象。

Begin

ClientApi_GetDocumentEntityAbsoluteAddress(BinderHandle, S);

//把实体BinderHandle的抽象地址赋予抽象地址字符串S。

DDBAddress := TDDBAddress.Create(S);

//根据抽象地址字符串S来创建一个抽象地址对象。

DDBAddress.Offset.Name := ExtractFileNameFromPath(DDBAddress.Offset.Name) + '.TXT';

//ExtractFilenameFromPath函数提取DDBAddress.Offset.Name字符串中文件名称和扩展名称。

//文本文档名称为抽象地址中偏移地址名称,但扩展名称为TXT。

ClearIOResult;

//ClearIOResult过程复位IOResult,IOResult返回最后的I/O操作执行状态。

AssignDDB(F,DDBAddress.AsParameters,'Admin');

//AssignDDB过程联合F到一个设计数据库的实体直到F被关闭为止。此过程调用常被用于当您需要产生一个文本文件时,通过在设计资源管理器中一个服务器作用输出文档。三个参数分别为文本文件、输出文件名称、用户ID号。

Rewrite(F); //写文件。

Writeln(F,'Absolute address of an entity');//向文本文件中输出内容。

Writeln(F,'-----------------------------');

For I := 0 To Stringlist.Count - 1 Do

Writeln(F,StringList.Strings[i]);

//把列表中内容输出到文本文件中。

Writeln(F);

CloseFile(F);//关闭文件。

ClientApi_RepopulateDocumentEntity(BinderHandle,False);

//ClientApi_RepopulateDocumentEntity 过程在封装对象中刷新文档实体的内容依赖于Recursive参数值,如果参数为false,当前实体被刷新,否则实体的封装对象被刷新。它在当文档被增加到一个封装对象中您需要刷新封装对象来让设计资源管理器知道有新的文档时情况下很有用。

DDBAddress.Free;//释放抽出地址对象。

End;

{................................................................................}

//主程序,在容器中查找文档实体,查找到后把其完整抽象地址加到一个列表中,然后调用一个WriteToATextDocument过程把列表中内容输出到一个文本文件。此程序是把当前实体所在的容器,即上一级文件夹下所有的文档抽象地址信息输出。当前实体不同,输出结果可能不一样。

Procedure FindEntitiesInDDB;

Var

EntityHandle : TObjectHandle;//当前窗体中实体句柄。

Iterator : TObjectHandle;//迭代程序对面。

BinderHandle : TObjectHandle;//容器句柄。

DocumentEntity : TDocumentEntity;//文本实体。

Stringlist : TStringList;//子图表列表。

Begin

EntityHandle :=

ClientApi_FindEntityByDataHandle(MessageRouter_GetState_CurrentEditorWindow);

//MessageRouter_GetState_CurrentEditorWindow函数返回当前在项层的文档的窗体句柄。当前在项层在文档的窗体句柄。

//ClientApi_FindEntityByDataHandle函数使用一个编辑器窗体句柄来返回查找返回一个实体的句柄。

If EntityHandle = 0 Then Exit; //如果无实体对象则退出。

BinderHandle := ClientApi_GetDocumentOwnerBinder(EntityHandle);

//得到当前实体对象的容器对象句柄。

Iterator := ClientApi_CreateIterator(Binderhandle,[eDocument],eAll);

//创建一个迭代程序对象,在容器Binderhandle中查找文档实体,eDocument表示文档对象。

EntityHandle := ClientApi_GetFirstEntity(Iterator);//查找第一个文档实体。

StringList := TStringList.Create;//建立列表实体对象。

DocumentEntity := TDocumentEntity.Create(0);//建立文档实体对象。

While EntityHandle <> 0 Do//查找文件对象循环。

Begin

DocumentEntity.Handle := EntityHandle;//查找到的文件句柄赋予新建的文档实体句柄。

DocumentEntity.QueryDatabase(eGetState);//客户端内部服务器数据同步外部服务器数据。

StringList.Add('一个实体的抽象地址(Absolute address of an entity) = ' + DocumentEntity.FullAddress);

//把文档的完整抽象地址加到列表中。

EntityHandle := ClientApi_GetNextEntity(Iterator);//查找下一个对象。

End;

ClientApi_DestroyIterator(Iterator);//销毁迭代程序对象。

DocumentEntity.Free;//释放文档实体对象。

WriteToATextDocument(Binderhandle,StringList);//把容器中存在的所有文档抽象地址列表中内容输出到一个文本文件。

StringList.Free;//释放列表对象。

End;

这段代码做什么?

此代码片段中重要的函数。

ClientApi_CreateIterator

ClientApi_GetFirstEntity

ClientApi_GetNextEntity

ClientApi_DestroyIterator

MessageRouter_SendCommandToModule

ClientApi_GetDocumentOwnerBinder

MessageRouter_GetState_CurrentEditorWindow

ClientApi_FindEntityByDataHandle

AssignDDB

这个例子显示如何输出查找结果到一个文本文档中。为实现输出,在DDB_StandardIO单元提供了AssignDDB函数。AssignFile把文件名称变量关联一个设计文档的抽象地址。

一个迭代程序被使用来从一个设计数据库中提取实体,对每一个提取到的实体,调用一个Querydatabase(eGetState)过程来同步数据,用DocumentEntity对象来提取实体对象的完整地址,此实体的抽象地址字符串被传递到一个StringList列表对象中。一旦所有的实体都被迭代程序对象抽取完毕,调用WriteToATextDocument过程,把当前打开文档所在的容器对象句柄Binderhandle和Stringlist列表对象作为参数传递,并输出列表中字符串内容到一个文本文件,文本文件的名称与当前打开的文档所属的容器(上级)名称相同,扩展名称为TXT。

  6.3 改进迭代和显示程序例子

在容器中查找文档实体,查找到后把其完整抽象地址加到一个列表中,然后调用一个WriteToATextDocument过程把列表中内容输出到一个文本文件。此程序是把当前实体所在的容器,即上一级文件夹下所有的文档抽象地址信息输出。当前实体不同,输出结果可能不一样。

“迭代程序和显示例子”程序存在的问题是,必须要把当前DDB文档关闭再打开一次,才能看到输出的文本文档。能否直接在设计资源管理器中打开呢?

这个程序已解决输出文本文件显示问题。实现方法是通过在当前文档往上遍历整个DDB文件,直到找到最上一级。在最上一级执行刷新。

请见SDK例子\SAMPLES\NO2\API\Iterate and Show amend。

{....................................................................................}

//在一个循环中不断刷新当前新增实体,直到得到新增实体句柄,得到后中断退出。

Function WaitForCommit(BinderHandle : TObjectHandle; Docname : TString) : TObjectHandle;

Var

I : Integer;

Begin

Result := 0;

For I := 1 to 50 Do

Begin

ClientAPI_RepopulateDocumentEntity(BinderHandle,False);

//ClientApi_RepopulateDocumentEntity 过程在封装对象中刷新文档实体的内容依赖于Recursive参数值,如果参数为false,当前实体被刷新,否则实体的封装对象被刷新。它在当文档被增加到一个封装对象中您需要刷新封装对象来让设计资源管理器知道有新的文档时情况下很有用。

Result := ClientAPI_FindChildDocumentInBinder(Binderhandle,Docname);

//ClientApi_FindChildDocumentInBinder过程在容器Binderhandle查找文档Docname,查找到返回其句柄,否则返回零。

If Result <> 0 Then Break;//如果找到,则中断循环,找到表示新增加的文档句柄已得到,可以使用了。

WaitForSingleObject(GetCurrentThread,100);

//GetCurrentThread得到当前的线程

//WaitForSingleObject等待100毫秒。

End;

End;

{....................................................................................}

Procedure WriteToATextDocument(Binderhandle : TObjecthandle;StringList : TstringList);

Var

F : TextFile;//文本文档。

I : Integer;

S : TString;//抽象地址字符串。

NewTextDocHandle : TObjectHandle;//要新建的新的实体文件句柄。

DDBItem: TDDBItem;//项目实体。

AbsoluteString : TString;

BinderEntity: TEntity; //临时容器实体对象。

BinderParentHandle : ClientTypes.TObjectHandle;//父实体对象。

EntityHandle : ClientTypes.TObjecthandle;//实体对象。

Begin

EntityHandle :=

ClientAPI_FindEntityByDataHandle(MessageRouter_GetState_CurrentEditorWindow);

//MessageRouter_GetState_CurrentEditorWindow函数返回当前在项层的文档的窗体句柄。当前在项层在文档的窗体句柄。

//ClientApi_FindEntityByDataHandle函数使用一个编辑器窗体句柄来返回查找返回一个实体的句柄。

if EntityHandle = 0 then Exit; //如果无实体对象则退出。

ClientApi_GetDocumentEntityAbsoluteAddress(BinderHandle, S);

//把当前实体所在的容器实体即BinderHandle参数所指示的实体抽象地址赋予S。

DDBItem:= TDDBItem.Create('Admin',S);//根据S创建一个项目

DDBItem.Address.Offset.Name := ExtractFileNameFromPath(DDBItem.Address.Offset.Name) + '.TXT';

//输出文件名称。

AbsoluteString := DDBItem.Address.Offset.Name;

//输出文件名称赋予抽象地址变量AbsoluteString。

DDBItem.Address.EditorKind := 'TEXT';

//编辑器类型。

DDBITem.Address.Id := cUnassignedID;

DDBITem.Address.Attributes := 0;

DDBITem.Write;

//创建文件

ClearIOResult;

//ClearIOResult过程复位IOResult,IOResult返回最后的I/O操作执行状态。

AssignDDB(F,DDBItem.Address.AsParameters,'Admin');

//AssignDDB过程联合F到一个设计数据库的实体直到F被关闭为止。此过程调用常用于当

//您需要产生一个文本文件,通过在设计资源管理器中一个服务器作用输出文档。三个参

//数分别为文本文件、输出文件名称、用户ID号。

Rewrite(F); //写文件。

Writeln(F,'一个实体的所在的上级容器中包含的所有文档的抽象地址(Absolute address of an entity)');//向文本文件中输出内容。

Writeln(F,'---------------------------------------------------------------------------------');

For I := 0 To Stringlist.Count - 1 Do

Writeln(F,StringList.Strings[i]);

//把列表中内容输出到文本文件中。

Writeln(F);

CloseFile(F);//关闭文件。

BinderParentHandle := 1;

while(BinderParentHandle <> 0) Do

Begin

BinderHandle := ClientApi_GetDocumentOwnerBinder(EntityHandle);

//得到当前实体所在的上一级容器句柄。

BinderEntity := TEntity.Create(BinderHandle);

//根据得到的上一级容器建立一个实体对象BinderEntity。

BinderEntity.QueryDatabase(eGetState);//同步数据。

BinderParentHandle := BinderEntity.ParentHandle;

//得到实体对象的父实体句柄。

EntityHandle := BinderParentHandle;//父实体句柄赋予EntityHandle。

End;

//遍历整个DDB包,直到最上一级实体,其主要目的是为了对整个DDB包进行刷新。

//遍历完成后,BinderParentHandle和EntityHandle是0,因为已到上一级了,此时BinderHandle

//中存放在是最高层实体即DDB的句柄。

NewTextDochandle := WaitForCommit(BinderHandle,AbsoluteString);//刷新实体直到获得实体句柄。

//把DDB句柄和要刷新的文档作为参数。

ClientAPI_OpenDocumentEntity(NewTextDochandle,False);

//在窗体中打开新建的实体文档。

DDBItem.Free;

BinderEntity.Free;

End;

{................................................................................}

//主程序,在容器中查找文档实体,查找到后把其完整抽象地址加到一个列表中,然后调用

//一个WriteToATextDocument过程把列表中内容输出到一个文本文件。

Procedure FindEntitiesInDDBAmend;

Var

EntityHandle : TObjectHandle;//当前窗体中实体句柄。

Iterator : TObjectHandle;//迭代程序对面。

BinderHandle : TObjectHandle;//容器句柄。

DocumentEntity : TDocumentEntity;//文本实体。

Stringlist : TStringList;//子图表列表。

Begin

EntityHandle :=

ClientApi_FindEntityByDataHandle(MessageRouter_GetState_CurrentEditorWindow);

//MessageRouter_GetState_CurrentEditorWindow函数返回当前在项层的文档的窗体句柄。当前在项层在文档的窗体句柄。

//ClientApi_FindEntityByDataHandle函数使用一个编辑器窗体句柄来返回查找返回一个实体的句柄。

If EntityHandle = 0 Then Exit; //如果无实体对象则退出。

BinderHandle := ClientApi_GetDocumentOwnerBinder(EntityHandle);

//得到当前实体对象的容器对象句柄。

Iterator := ClientApi_CreateIterator(Binderhandle,[eDocument],eAll);

//创建一个迭代程序对象,在容器Binderhandle中查找文档实体,eDocument表示文档对象。

EntityHandle := ClientApi_GetFirstEntity(Iterator);//查找第一个文档实体。

StringList := TStringList.Create;//建立列表实体对象。

DocumentEntity := TDocumentEntity.Create(0);//建立文档实体对象。

While EntityHandle <> 0 Do//查找文件对象循环。

Begin

DocumentEntity.Handle := EntityHandle;//查找到的文件句柄赋予新建的文档实体句柄。

DocumentEntity.QueryDatabase(eGetState);//客户端内部服务器数据同步外部服务器数据。

StringList.Add('一个实体的抽象地址(Absolute address of an entity) = ' + DocumentEntity.FullAddress);

//把文档的完整抽象地址加到列表中。

EntityHandle := ClientApi_GetNextEntity(Iterator);//查找下一个对象。

End;

ClientApi_DestroyIterator(Iterator);//销毁迭代程序对象。

DocumentEntity.Free;//释放文档实体对象。

WriteToATextDocument(Binderhandle,StringList);//把容器中存在的所有文档抽象地址列表中内容输出到一个文本文件。

StringList.Free;//释放列表对象。

End;

{....................................................................................}

Procedure Command_IterateAndShowAmend(Window : TServerWindow; Parameters : PChar);

Begin

FindEntitiesInDDBAmend;

End;

本程序是一个使用一个参数进程在设计资源管理器中查找并打开一个设计文档的功能强大的例子。您仅需按下列格式应用参数字符串。

DocumentName1 = ‘’ | DocumentName2 = ‘’ ...

请见SDK例子\SAMPLES\NO2\API\Client\SearchAndOpenDocuments。

{....................................................................................}

//查找并打开文件

Procedure SearchAndOpenADocument(Filename : String);

Var

EnteredFileName : TString;

DocumentEntity : TDocumentEntity;//文档实体对象。

Iterator: ClientTypes.TObjectHandle;//迭代程序对象。

AbsoluteStorageName : TString;//抽象地址字符串。

EntityHandle : ClientTypes.TObjectHandle;//查找到的实体句柄变量。

Begin

AbsoluteStorageName := '';

EnteredFileName := Uppercase(FileName);//文件名称转换为大写。

Iterator := ClientApi_CreateIterator(0,[eDocument],eAll);

//建立迭代程序对象查找所有文档。

EntityHandle := ClientApi_GetFirstEntity(Iterator);

//查找第一个文档。

While EntityHandle <> 0 Do

Begin

DocumentEntity := TDocumentEntity.Create(EntityHandle);

//根据查找到的文档句柄建立文档对象。

DocumentEntity.QueryDataBase(ClientTypes.eGetState);//同步数据。

If EnteredFileName = UpperCase(DocumentEntity.Name) Then AbsoluteStorageName :=DocumentEntity.GetAbsoluteAddress;

//如果文档实体的名称与要查找的文档参数名称一样,即说明当前查找到的文档就是要找的文档。把查找到的文档实体的抽象地址赋予AbsoluteStorageName字符串。

EntityHandle := ClientApi_GetNextEntity(Iterator);//查找下一个文档实体。

End;

ClientApi_DestroyIterator(Iterator);//销毁迭代程序对象。

If AbsoluteStorageName = '' Then Exit;

//如果AbsoluteStorageName为空,说明没有找到与查找参数相同的文档实体对象,退出。

EntityHandle := ClientApi_FindEntityByStorageName(AbsoluteStorageName,

[eDocument]);

//ClientApi_FindEntityByStorageName函数使用一个实体的抽象地址和实体种类参数返回一个实体的句柄。

ClientApi_OpenDocumentEntity(EntityHandle,False);//在窗体中打开文档实体。

End;

{....................................................................................}

Procedure Command_SearchAndOpen(Window : TServerWindow; Parameters : PChar);

Var

Value : TString;

I : Integer;

Begin

i := 1;

While Getstate_Parameter(Parameters,'DocumentName' + GetStringFromInteger(i),Value) do

//从参数中一个一个地读取参数和参数值,直到完成。

Begin

SearchAndOpenADocument(Value);

Inc(i);

End;

End;

这段代码做什么?

这段代码片段中重要的函数和类。

ClientApi_CreateIterator

ClientApi_GetFirstEntity

ClientApi_GetNextEntity

ClientApi_DestroyIterator

DocumentEntity.Querydatabase(eGetstate)

GetAbsoluteAddress

在此例子中,参数字符串的输入可以按下列格式, “DocumentName1= XXX.YYY | DocumentName2 = AAA.BBB”…, XXX.YYY和AAA.BBB是文档名称,在进程,用一个While语句来提取每一个参数。只要您喜欢,您能够输入许许多多参数,不要忘记在每一组参数之间用“|”符号来间隔。

使用一个迭代程序读取每一个设计数据库中实体,读取到每一个实体名称与从进程参数提取的文件名称相比较,如果两个名称完全匹配,则DocumentEntity对象调用过程GetAbsoluteAddress来提取此实体的完整抽象地址,停止迭代程序执行,并且把抽象地址被传递到ClientAPI_FindEntityByStorageName函数,此函数根据实体的抽象地址和实体种类参数返回实体的句柄。

如果要查找的文档没有被打开,使用ClientAPI_OpenDocumentEntity函数来在窗体中打开设计文档。

此过程继续处理,直到所有进程参数被处理完,即完成所有的查找任务。

  6.5 查找并打开一个文档改进例子

此程序是对6.4程序的改进,主要是为了可靠地解决无论程序是在原理图编辑器还是在印制板、或文件夹,每次都能准确地查找并打开要查找的文档对象。

请见SDK例子\SAMPLES\NO2\API\SearchAndOpenDocumentsAmend。

{....................................................................................}

Procedure SearchAndOpenADocument(Filename : String);

Var

EnteredFileName : TString;

DocumentEntity: TDocumentEntity;//文档实体对象。

Iterator: ClientTypes.TObjectHandle;//迭代程序对象。

AbsoluteStorageName : TString;//抽象地址字符串。

EntityHandle : ClientTypes.TObjectHandle;//查找到的实体句柄变量。

Document: TObjectHandle;

AbsolutePath : TString;//查找到的文档的抽象地址路径。

DDBItem: TDDBItem;//查找到的文档通过建立临时项目方式取得一些信息。

Params: PChar;//传递给客户端服务器命令参数。

Begin

AbsoluteStorageName := '';

EnteredFileName := Uppercase(FileName);//文件名称转换为大写。

Iterator := ClientApi_CreateIterator(0,[eDocument],eAll);

//建立迭代程序对象查找所有文档。

EntityHandle := ClientApi_GetFirstEntity(Iterator);

//查找第一个文档。

While EntityHandle <> 0 Do

Begin

DocumentEntity := TDocumentEntity.Create(EntityHandle);

//根据查找到的文档句柄建立文档对象。

DocumentEntity.QueryDataBase(ClientTypes.eGetState);//同步数据。

If EnteredFileName = UpperCase(DocumentEntity.Name) Then

AbsoluteStorageName :=DocumentEntity.GetAbsoluteAddress;

//如果文档实体的名称与要查找的文档参数名称一样,即说明当前查找到的文档就是要

//找的文档。把查找到的文档实体的抽象地址赋予AbsoluteStorageName字符串。

EntityHandle := ClientApi_GetNextEntity(Iterator);//查找下一个文档实体。

End;

ClientApi_DestroyIterator(Iterator);//销毁迭代程序对象。

If AbsoluteStorageName = '' Then Exit; //如果抽象地址为空则退出。

//下面的代码与原有程序不同,请您仔细对照学习。

DDBItem:= TDDBItem.Create('Admin',AbsoluteStorageName);

//根据查找到的文档的抽象地址创建一个项目。

If DDBItem <> Nil Then

Begin

GetMem(Params,1024);//分配内存。

StrPCopy(Params,'FileName ='+ DDBItem.Address.Root.Path +'\'+ DDBItem.Address.Root.Name);

//合成命令参数"FileName=根路径+根名称",合成后,FileName是当前DDB包的全路径名称。

MessageRouter_SendCommandToModule('Client: OpenDocument',Params,255,0);

//把参数发送到客户端服务器,打开DDB包文档。

AbsolutePath := DDBItem.Address.AsParameters;

//查找到的文档的抽象地址路径。

Document := ClientApi_FindEntityByStorageName(AbsolutePath,[eDocument]);

//ClientApi_FindEntityByStorageName函数使用一个实体的抽象地址和实体种类参数返回一个实体的句柄。

ClientApi_OpenDocumentEntity(Document,False);//在窗体中打开文档。

ClientApi_SetAsCurrentDocument(Document);//置为当前激活。

Freemem(Params,1024);//释放内存。

End;

DDBItem.Free;//释放DDB对象。

End;

{....................................................................................}

Procedure Command_SearchAndOpen(Window : TServerWindow; Parameters : PChar);

Var

Value : TString;

I : Integer;

Begin

i := 1;

While Getstate_Parameter(Parameters,'DocumentName' + GetStringFromInteger(i),Value) do

//从参数中一个一个地读取参数和参数值,直到完成。

Begin

SearchAndOpenADocument(Value);

Inc(i);

End;

End;

  6.6 输入一个文档例子

此例子创建一个简单的外部文本文件,然后把此文本文件输入到一个设计数据库中,作为一个文本实体对象。

请见SDK例子\SAMPLES\NO2\API\Client\Import External File。

{....................................................................................}

//创建一个外部的文本文件。

Function GenerateASampleTextFile : TString;

Var

F : TextFile;//文本文件

Begin

Result := 'C:\TextFil$.Txt';//文本文件名称。

AssignFile(F,Result);//把文本文件名称和文本对象关联。

Rewrite(F);//创建一个文本文件对象。

Writeln(F,'Hello world!');//向文本文件中写内容。

Writeln(F,#13);//换一行。

Writeln(F,'Goodbye world!');//写内容。

CloseFile(F);//关闭文件。

End;

{....................................................................................}

//主程序。

Procedure ImportAnExternalFile;

Var

Address : TDDBAddress;//抽象地址对象。

EntityHandle : ClientTypes.TObjecthandle;//实体对象。

BinderHandle : ClientTypes.TObjecthandle;//容器对象句柄。

S : TString;//抽象地址字符串。

Entity : TDocumentEntity;//文档实体。

NewDocName : TString;//新建文档名称变量。

DocumentName : TString;//外部文档完整路径。

Begin

DocumentName := GenerateASampleTextFile;//创建一个文件。

NewDocName := ExtractWholeFileNameFromPath(DocumentName);//提取文件完整名称,包括扩展名称。ExtractWholeFileNameFromPath函数提取DocumentName字符串中名称和扩展名称。

EntityHandle :=

ClientAPI_FindEntityByDataHandle(MessageRouter_GetState_CurrentEditorWindow);

//MessageRouter_GetState_CurrentEditorWindow函数返回当前在项层的文档的窗体句柄。当前在项层在文档的窗体句柄。

//ClientApi_FindEntityByDataHandle函数使用一个编辑器窗体句柄来返回查找返回一个实体的句柄。

If EntityHandle = 0 Then Exit; //如果无实体对象则退出。

ClientApi_GetDocumentEntityAbsoluteAddress(EntityHandle, S);

//把当前窗体中实体抽象地址赋予字符串S。

Address := TDDBAddress.Create(S);//创建一个抽象地址对象。

Address.EditorKind := 'TEXT';//文件类型是文本文件。

Address.Offset.Name := NewDocName;//文件名称为输入到设计数据库中的文本文件名。

DDB_ImportFile(DocumentName,Address,'Admin',False);

// DocumentName为外部文件句柄,Address为内部文件实体对象句柄。'Admin'是操作用户,False表示输入文档而不是作为一个外部连接,如为True则表示为连接。

//上面代码执行完成后,外部输入文档已输入到Address实体对象中,但并没有输入到设计数据库中,所以不会在资源管理器应用程序中显示。

//刷新设计资源管理器的浏览器的内容。

BinderHandle := ClientApi_GetDocumentOwnerBinder(EntityHandle);

//得到当前实体对象的容器对象句柄。

ClientApi_RepopulateDocumentEntity(BinderHandle,False);

//ClientApi_RepopulateDocumentEntity 过程在封装对象中刷新文档实体的内容依赖于Recursive参数值,如果参数为false,当前实体被刷新,否则实体的封装对象被刷新。它在当文档被增加到一个封装对象中您需要刷新封装对象来让设计资源管理器知道有新的文档时情况下很有用。

EntityHandle := ClientApi_FindChildDocumentInBinder(BinderHandle, NewDocName);

//在空器中查找NewDocName文档。

If EntityHandle <> 0 Then

Begin

Entity := TDocumentEntity.Create(EntityHandle);

//根据查找到的实体句柄创建一个实体对象。

Entity.QueryDatabase(ClientTypes.eGetState);//用内部服务器数据同步外部服务器数据。

Entity.EditorKind := 'TEXT';//编辑器类型。

Entity.QueryDatabase(ClientTypes.eSetState);//用外部服务器数据同步内部服务器数据。

Entity.Free;//释放实体。

End

else ShowInfo('新输入的文件没有发现!');

Address.Free;// 释放地址对象。

End;

这段代码做什么?

此段代码片段中重要的函数和类。

AssignFile, Writeln, CloseFile

ClientAPI_FindEntityByDataHandle

MessageRouter_GetState_CurrentEditorWindow

ClientAPI_GetDocumentEntityAbsoluteAddress

DDB_ImportFile

ClientAPI_RepopulateDocumentEntity

此例子说明如何输入一个外部文件到数据库中。例子开始于在C盘驱动器根目录下产生一个小的文本文件,当然,您需要有一个硬盘驱动器盘符如“C:\”,当前打开的设计文档的实体句柄被通过函数ClientAPI_FindEntityByDataHandle和MessageRouter_GetState_CurrentEditorWindow获得,DocumentName字符串有完整的Windows格式文件路径和文件名称,NewDocName字符串仅是整个文件名称(不含路径,即不是FullPath)。

使用TDDBAddress对象,把EditorKind和Offset.Name字段分别分配“TEXT”和NewDocName值,即新建的TDDBAddress对象的对象类型为文本,对象名称是NewDocName。然后, 使用DDB_ImportFile函数把文件输入数据库中,DocumentName和Address作为函数的参数。再下来,设计数据库内容通过ClientAPI_RepopulateDocumentEntity函数被刷新,但新输入的文件没有出现在设计资源管理器界面上,为了使用输入的文件显示在设计资源管理器界面上,您需要按下列方法来做:

ClientAPI_FindChildDocumentInBinder函数来获得输入文档的实体的句柄,容器句柄(Binderhandle)和要查找文件实体对象的句柄(NewDocName)作为参数,此实体句柄被传递到TDocumentEntity类,然后EditorKind被分配“TEXT”值。Querydatabase(eSetState)函数注册此新文本文档实体到设计资源管理器应用程序。现在您有一个切实的文档实体。

这段程序在当前实体的上一级容器中输入外部文本文件,但是程序实际上有些问题,那就是新加入的文件并没有显示,EntityHandle := ClientApi_FindChildDocumentInBinder(BinderHandle, NewDocName)执行没有找到新加的文件。所以没有显示。如何改进请参见6.7。

  6.7 改进输入一个文档例子

请见SDK例子\SAMPLES\NO2\API\Client\Import External File Amend。

{....................................................................................}

//在一个循环中不断刷新当前新输入的实体,直到得到新输入的实体句柄,得到后中断退出。

Function WaitForCommit(BinderHandle : TObjectHandle; Docname : TString) : TObjectHandle;

Var

I : Integer;

Begin

Result := 0;

For I := 1 to 50 Do

Begin

ClientAPI_RepopulateDocumentEntity(BinderHandle,False);

//ClientApi_RepopulateDocumentEntity 过程在封装对象中刷新文档实体的内容依赖于

//Recursive参数值,如果参数为false,当前实体被刷新,否则实体的封装对象被刷新。

//它在当文档被增加到一个封装对象中您需要刷新封装对象来让设计资源管理器知道有

//新的文档时情况下很有用。

Result := ClientAPI_FindChildDocumentInBinder(Binderhandle,Docname);

//ClientApi_FindChildDocumentInBinder过程在容器Binderhandle查找文档Docname,

//查找到返回其句柄,否则返回零。

If Result <> 0 Then Break;

//如果找到,则中断循环,找到表示新输入的文档句柄已得到,可以使用了。

WaitForSingleObject(GetCurrentThread,100);

//GetCurrentThread得到当前的线程

//WaitForSingleObject等待100毫秒。

End;

End;

{....................................................................................}

Function GenerateASampleTextFile : TString;

Var

F : TextFile;//文本文件

Begin

Result := 'C:\TextFil$.Txt';//文本文件名称。

AssignFile(F,Result);//把文本文件名称和文本对象关联。

Rewrite(F);//创建一个文本文件对象。

Writeln(F,'Hello world!');//向文本文件中写内容。

Writeln(F,#13);//换一行。

Writeln(F,'Goodbye world!');//写内容。

CloseFile(F);//关闭文件。

End;

{....................................................................................}

//主程序。

Procedure ImportAnExternalFile;

Var

Address : TDDBAddress;//抽象地址对象。

EntityHandle : ClientTypes.TObjecthandle;//实体对象。

BinderHandle : ClientTypes.TObjecthandle;//容器对象句柄。

S : TString;//抽象地址字符串。

NewDocName : TString;//新建文档名称变量。

DocumentName : TString;//外部文档完整路径。

NewImportTextDocHandle : TObjectHandle;//要新建的新的实体文件句柄。

Begin

DocumentName := GenerateASampleTextFile;//创建一个文件。

NewDocName := ExtractWholeFileNameFromPath(DocumentName);

//提取文件完整名称,包括扩展名称。ExtractWholeFileNameFromPath函数提取

//DocumentName字符串中名称和扩展名称。

EntityHandle :=

ClientAPI_FindEntityByDataHandle(MessageRouter_GetState_CurrentEditorWindow);

//MessageRouter_GetState_CurrentEditorWindow函数返回当前在项层的文档的窗体句柄。

//当前在项层在文档的窗体句柄。ClientApi_FindEntityByDataHandle函数使用一个编辑

//器窗体句柄来返回查找返回一个实体的句柄。

If EntityHandle = 0 Then Exit; //如果无实体对象则退出。

ClientApi_GetDocumentEntityAbsoluteAddress(EntityHandle, S);

//把当前窗体中实体抽象地址赋予字符串S。

Address := TDDBAddress.Create(S);//创建一个抽象地址对象。

Address.EditorKind := 'TEXT';//文件类型是文本文件。

Address.Offset.Name := NewDocName;//文件名称为输入到设计数据库中的文本文件名。

DDB_ImportFile(DocumentName,Address,'Admin',False);

//DocumentName为外部文件句柄,Address为内部文件实体对象句柄。'Admin'是操作用户,

//False表示输入文档而不是作为一个外部连接,如为True则表示为连接。

//上面代码执行完成后,外部输入文档已输入到Address实体对象中,但并没有输入到设计

//数据库中,所以不会在资源管理器应用程序中显示。

//刷新设计资源管理器的浏览器的内容。

BinderHandle := ClientApi_GetDocumentOwnerBinder(EntityHandle);

//得到当前实体对象的容器对象句柄。

NewImportTextDochandle := WaitForCommit(BinderHandle,NewDocName);

//刷新实体直到获得实体句柄。把上级容器句柄和要刷新的文档作为参数。

ClientAPI_OpenDocumentEntity(NewImportTextDochandle,False);

//在窗体中打开新输入的实体文档。

Address.Free;// 释放地址对象。

End;

{....................................................................................}

Procedure Command_ImportAFileInDDBAmend(Window : TServerWindow; Parameters : PChar);

Begin

ImportAnExternalFile;

End;

  6.8 输出一个设计实体例子

本例子把一个当前激活的设计文档输出到一个外部文件夹。

请见SDK例子\SAMPLES\NO2\API\Client\Export a DDB document。

{....................................................................................}

Procedure ExportADDBDocument;

Var

S : TString;

FileLocation : TString;

NewExternalFileName : TString;

EntityHandle : ClientTypes.TObjecthandle;

Source : TDDBAddress;

Begin

EntityHandle :=

ClientAPI_FindEntityByDataHandle(MessageRouter_GetState_CurrentEditorWindow);

//MessageRouter_GetState_CurrentEditorWindow函数返回当前在项层的文档的窗体句柄。当前在项层在文档的窗体句柄。

//ClientApi_FindEntityByDataHandle函数使用一个编辑器窗体句柄来返回查找返回一个实体的句柄。

if EntityHandle = 0 then Exit; //如果无实体对象则退出。

ClientApi_GetDocumentEntityAbsoluteAddress(EntityHandle, S);

//把当前窗体中实体抽象地址赋予字符串S。

Source:= TDDBAddress.Create(S);//创建要输出的源对象。

FileLocation :=(ExtractFileDrive(ConvertToNormalFilePath(Source.AsParameters)));

//ConvertToNormalFilePath函数转换一个抽象的地址到一个常规的DOS文件路径。

//ExtractFileDrive从一个完整的路径中返回文件的包含驱动器名在内的文件路径(不包括文件名称)。

NewExternalFileName :=

(ExtractFileName(ConvertToNormalFilePath(Source.AsParameters)));

//ExtractFileName从一个完整路径中返回文件名称(不包括文件路径)。

DDB_ExportToFile(Source,FileLocation + '\'+ NewExternalFileName,'Admin');

//输出文件。

Source.Free;//释放Source对象。

End;

这段代码做什么?

此段代码片段中使用的重要的函数和类如下表。

ClientAPI_FindEntityByDataHandle

MessageRouter_GetState_CurrentEditorWindow

ClientApi_GetDocumentEntityAbsoluteAddress

TDDBAddress

DDB_ExportToFile

此例子在设计资源管理器中当前打开的设计文档中提取一个实体句柄,用一个TDDBAddress类表示实体的抽象地址对象,ClientApi_GetDocumentEntityAbsoluteAddress函数提取实体的抽象地址到一个字符串,并根据此字符串根据TDDBAddress对象,然后根据TDDBAddress对象的抽象地址参数,使用ConvertToNormalFilePath把抽象地址转换为DOS下常规路径,用ExtractFileDrive把路径中除文件名称以外的内容,包括驱动器名称提取出到FileLocation,作为输出文件的路径,用ExtractFileName路径中文件名称提取出到NewExternalFileName,不包括路径。ExtractFileDrive字符串加上ExtractFileName字符串,就合成了要输出的文件完整名称,合成字符串作为DDB_ExportToFile函数的参数,DDB_ExportToFile函数接下来把此实体内容输出保存到一个外部文件中。输出一个设计文档与输入一个外部文档相比并不复杂,都是很简单的。

  6.9 报告原理图图表例子

此例子显示原理图文档的子项目。您需要一个迭代程序对象来导向查找机制,在一个设计数据中执行项目(Item)的线性的搜索。

请见SDK例子\SAMPLES\NO2\API\Client\Report Child Schematic Sheets。

{....................................................................................}

Procedure ReportSchematics;

Var

DocumentName : TString;//实体对象的抽象地址。

DocumentAddress : TDDBAddress;//抽象地址对象。

Iterator: TObjectHandle;//迭代程序对象。

DocHandle : TObjectHandle;//查找到的实体对象句柄。

DDBItem : TDDBItem;//项目对象。

SchematicChildList : TStringList; //创建存放当前原理图和所属子原理图名称的列表。

I : Integer;

SchematicsString : String;//合成原理图和下属原理图名称字符串。

Begin

DocumentAddress := TDDBAddress.Create('');//创建一个抽象地址对象。

Iterator := ClientApi_CreateIterator(0, [eDocument], eAll);

//创建一个迭代程序对象,查找所有实体文档(eDocument)。

DocHandle := ClientApi_GetFirstEntity(Iterator);//得到第一个查找到的文档对象。

While DocHandle <> 0 Do //如果已查找到对象。

Begin

ClientApi_GetDocumentEntityAbsoluteAddress(DocHandle, DocumentName);

//把查找到的实体对象的抽象地址提取出来,赋予抽象地址字符串DocumentName。

DocumentAddress.Import_FromParameters(DocumentName);

//Import_FromParameters使用抽象地址参数字符串设置一个TDDBAddress对象。

If StringsEqual(UpperCase(DocumentAddress.EditorKind), 'SCH') Then

//如果当前是原理图,编辑器的类型为SCH表示是原理图。

If DocumentAddress.HasChildItems Then //HasChildItems判断是否有子文档。

Begin

DDBItem := TDDBItem.Create('Admin',DocumentName);//创建一个项目。

DDBItem.Read;

//ReadHeader函数读入快捷方式键连接或检索子项目(在当前项目下的项目)并且返回一个TQueryError值。如果函数调用没有成功,一个“eQEBadConnection”值被返回。

SchematicChildList := TStringlist.Create;

//创建存放当前原理图和所属子原理图名称的列表。

SchematicChildList.Add(DocumentAddress.Display_Caption);

//DocumentAddress.Display_Caption如果设计数据库是一个MS Access数据库,返回值是设计数据库所在的完整路径(一个一般的MS Windows路径名称)。如果设计数据库是一个非MS Access数据库,返回值是下列格式:“DB=”+ 设计数据库根路径 + “File=”+ 设计文档偏移路径。返回字符串。

//把查找到的当前原理图对象的完整路径加到列表SchematicChildList中。

SchematicChildList.LoadFromStream(DDBItem.ChildList);

//把当前原理图的子原理图图表加到列表中。

SchematicsString := '';

For I := 0 To SchematicChildList.Count - 1 Do

SchematicsString := SchematicsString + ' ' + SchematicChildList.Strings[I];

//把当前原理图路径和其下属的所有子原理图(如果有的话)名称字符串加在一起,合成一个字符串SchematicsString。

If SchematicChildList.Count > 0 Then

ShowInfo(DocumentAddress.Offset.Name + '有下列子原理图' + #13 +

SchematicsString);

//DocumentAddress.Offset.Name表示当前查找到的原理图的名称。

//如果当前原理图有子原理图则显示合成的字符串。

SchematicChildList.Free;//释放存放当前原理图和所属子原理图名称的列表。

DDBItem.Free;//释放项目对象。

End;

DocHandle := ClientApi_GetNextEntity(Iterator);//查找下一个原理图对象。

End;

ClientApi_DestroyIterator(Iterator);//释放迭代程序对象。

DocumentAddress.Free;//释放抽象地址对象。

End;

这段代码做什么?

此段代码片段中重要的函数和类。

ClientApi_CreateIterator

ClientApi_GetFirstEntity

ClientApi_GetNextEntity

ClientApi_DestroyIterator

ClientApi_GetDocumentEntityAbsoluteAddress

Import_FromParameters

TDDBAddress

TDDBItem

ChildList

此代码设立一个在设计数据库中查找文档的迭代机制。

首先建立一个TDDBAddress,接下来建立一个迭代程序用于查找所有文档,如果在当前DDB包中查找到有原理图文档,则使用ClientApi_GetDocumentEntityAbsoluteAddress把查找到的文档实体对象的抽象地址读取出来,再通过DocumentAddress.Import_FromParameters(DocumentName)把抽象地址读到TDDBAddress对象中,接下来判断DocumentAddress是否有子原理图,如果有,根据抽象地址建立一个项目对象DDBItem,调用项目对象的read过程读取出此原理图下属子原理图信息,再则建立一个存储当前原理图和其下属子原理图名称的列表SchematicChildList,执行SchematicChildList.LoadFromStream(DDBItem.ChildList)把当前原理图对象的子原理图信息加到列表SchematicChildList中。再把列表中内容合成字符串并显示出来。

6.10 OpenTextDocumentEntity

请见SDK例子\SAMPLES\NO2\API\Client\OpenTextDocumentEntity。

{....................................................................................}

Procedure OpenAndShowTextDocument(Documentname : String);

Var

EntityHandle : TObjectHandle;//当前实体对象的句柄。

ReportHandle : TObjectHandle;//在当前实体对象所在的容器中查找到的文档对象句柄。

BinderHandle : TObjectHandle;//当前实体对象的容器的句柄。

S : TString;//抽象地址字符串变量。

newDocname : TString;//要查找的文档名称。

ReportEntity : TDocumentEntity;//文档对象实体。

Begin

EntityHandle :=

ClientAPI_FindEntityByDataHandle(MessageRouter_GetState_CurrentEditorWindow);

//MessageRouter_GetState_CurrentEditorWindow函数返回当前在项层的文档的窗体句柄。当前在项层在文档的窗体句柄。

//ClientApi_FindEntityByDataHandle函数使用一个编辑器窗体句柄来返回查找返回一个实体的句柄。

If EntityHandle = 0 Then Exit;//如果无实体对象则退出。

BinderHandle := ClientApi_GetDocumentOwnerBinder(EntityHandle);

//得到当前实体对象的容器对象句柄。

NewDocName := ExtractWholeFileNameFromPath(DocumentName);

//ExtractWholeFileNameFromPath函数提取DocumentName字符串中名称和扩展名称。

EntityHandle := ClientApi_FindChildDocumentInBinder(BinderHandle, NewDocName);

//在当前实体所在的容器中查找NewDocName文档对象。

ShowInfo('容器句柄(Binder Handle) = ' + IntToStr(BinderHandle) + '' + #13 + '实体句柄(Entity Handle) = '+ IntToStr(EntityHandle));

If EntityHandle <> 0 Then //如果查找到文档对象,则把对象打开并设置为当前对象。

Begin

ClientApi_GetDocumentEntityAbsoluteAddress(EntityHandle, S);

//把查找到的文档对象实体的抽象地址赋予字符串S。

S := ExtractWholeFileNameFromPath(S);

//ExtractWholeFileNameFromPath函数从字符串S中提取文档对象的文件名称和扩展名称。

ReportHandle := ClientApi_FindChildDocumentInBinder(BinderHandle, S);

//在当前实体所在的容器中查找文档对象S。

If ReportHandle = 0 Then Exit;//如果未找到则退出。

ReportEntity := TDocumentEntity.Create(ReportHandle);//找到后创建一个文档对象。

ReportEntity.QueryDatabase(eGetState);//用内部服务器数据同步外部服务器数据。

If ReportEntity.ObjectHandle = 0 Then

//ObjectHandle表示实体的窗体句柄,为零表示当前没有窗体打开。

ClientApi_OpenDocumentEntity(ReportHandle, False)

//在窗体中打开查找到的文档,如果参数不为False而是True,则在设计资源管理器中直接打开。

Else

Begin

ClientApi_PerformAutoZoomForDocumentEntity(ReportHandle);//查找到的文档在窗体中以整页尺寸方式显示,自动地缩放到合适大小。

ClientApi_SetAsCurrentDocument(ReportHandle); //置为当前激活。

End;

MessageRouter_SendCommandToModule('TextEdit:MoveCursorToTopOfDocument', Nil, 0,

MessageRouter_GetState_CurrentEditorWindow);

//移动光标到文档的顶层。

ReportEntity.Free;//对象实体释放。

End

Else

ShowInfo('要查找的文档不存在!’);

End;

{...................................................................................}

Procedure Command_OpenAndShowTextDocument(Window : TServerWindow; Parameters : PChar);

Var

ADocumentName : String;

Begin

If GetState_Parameter(Parameters,'DocumentName',ADocumentName) Then

OpenAndShowTextDocument(ADocumentName)

Else ShowInfo('无效的参数,参数为DocumentName=Memory.Sch这样的型式。');

//GetState_Parameter函数参数块中检索一个参数值,如果找到返回True,否则返回False。参数被传递到一个空字符为终止符和数组中。

End;

这个程序通过提取从参数传递来的要查找的文档名称,调用OpenAndShowTextDocument过程来查找文档。

OpenAndShowTextDocument过程先取得当前实体句柄,如果当前实体句柄为零,则退出。根据当前实体的句柄,ClientApi_GetDocumentOwnerBinder取得其上级容器的句柄,然后调用过程ExtractWholeFileNameFromPath(DocumentName)来取得要查找文档的文件名称和扩展名称,执行ClientApi_FindChildDocumentInBinder(BinderHandle, NewDocName)来在当前实体所属的上级容器中查找文档,如果查找到,则调用ShowInfo来显示容器句柄和查找到的文档实体的句柄。

接下来调用ClientApi_GetDocumentEntityAbsoluteAddress(EntityHandle, S)来把查找到的实体文档的抽象地址赋予字符串S,ExtractWholeFileNameFromPath(S)获取文档的名称和扩展名称,ReportHandle := ClientApi_FindChildDocumentInBinder(BinderHandle, S)在当前实体所在的容器中查找文档对象S,如果查找到,调用TDocumentEntity.Create(ReportHandle)建立文档对象,并通过QueryDatabase(eGetState)同步数据。如果ReportEntity.ObjectHandle为0,方法ClientApi_OpenDocumentEntity(ReportHandle, False)在窗体中打开文档对象,如果不为0,ClientApi_PerformAutoZoomForDocumentEntity在窗体中打开文档并缩放到整页大小显示,并通过调用方法ClientApi_SetAsCurrentDocument来把查找到的文档置为当前文档。

这个程序的查找范围是当前实体所在的上级容器,如果要查找的文档不在当前实体上级容器中,即要查找的实体和当前实体不属同一个容器,则查找不到,即使这个要查找的文档在设计数据库中。

改进方法可以参照SearchAndOpenDocumentsAmend例子。(e-works)

0
相关文章