GetProcAddress函数是一个API windows 函数,得到函数地址,地址是一个无类型的指针。在此例子中,_PcbAPI_QueryPrimitive是一个无类型的指针。第二个字符串“PcbAPI_QueryPrimitive”在SetProcAddress方法中是过程的名称。这步骤涉及了PCBClass单元中函数调用,说明如下:
TPCBObject = Class
BitField: TBitField;
BitField2 : Byte;
Index : Word;
Layer : TLayer;
Moveable: Boolean;
Net : TObjectHandle;
Component : TObjectHandle;
Constructor Create(AHandle: TObjectHandle);
Function QueryDatabase(Mode : TQueryMode) : Integer;Virtual;
Procedure GetState_BoundingRectangle(Var Lx, Ly, Hx, Hy : TCoord); Virtual;
FunctionImport_FromUser : Boolean; Virtual;
Procedure GraphicallyInvalidate;
...
End;
TPCBObject.QueryDatabase(Mode : TQueryMode)函数抽取或分配有关此对象的信息。
Function TPCBObject.QueryDatabase(Mode : TqueryMode) : TShortInt;
Begin
PcbApi_GetObjectBitField2(Mode,ObjectHandle,BitField2);
Result := PcbApi_QueryPrimitive(Mode, ObjectHandle, BitField,
Index, Layer, Net, Component, Moveable);
End;
用QueryDatabase函数,用函数PcbApi_QueryPrimitive,一个调用被安排到PCBProcs单元,内存分配和类型转换在PCBProcs单元内部完成。
函数类型声明:
TPcbApi_QueryPrimitive=
Function(Mode : TQueryMode;
ObjectHandle : TObjectHandle;
VarBitField : TBitField;
VarIndex: TWord;
VarLayer: TLayer;
VarNet: TObjectHandle;
VarComponent: TObjectHandle;
VarMoveable : TBoolean) : TshortInt;
函数指针类型定义
_PcbApi_QueryPrimitive : TFarProc;
对函数指针的内存分配被完成,并且指针的地址被设置到它的在ADVPCB.DLL中的实现(implementation)处。
Procedure SetAllPCBProcAddresses;
Procedure SetProcAddress(Var P : TFarProc; ProcName : Pchar);
Begin
If PcbLibrary = 0 Then P := Nil
Else P := GetProcAddress(PCBLibrary,ProcName);
//取PCBLibrary句柄中ProcName函数的地址到指针P。
End;
Begin
PCBLibrary := GetModuleHandle('AdvPcb.dll');//取得AdvPcb.dll句柄。
SetProcAddress(_PcbApi_QueryPrimitive, 'PcbApi_QueryPrimitive');
//取得AdvPcb.dll中输出的函数PcbApi_QueryPrimitive的地址到指针变量_PcbApi_QueryPrimitive中。
End;
函数的主体
Function PcbApi_QueryPrimitive
(Mode: TQueryMode;
ObjectHandle: TObjectHandle;
Var BitField: TBitField;
Var Index : TWord;
Var Layer : TLayer;
Var Net : TObjectHandle;
Var Component : TObjectHandle;
Var Moveable: TBoolean) : TShortInt;
Begin
Result := 0;
//如果nil检查指针
If _PcbApi_QueryPrimitive = Nil then Exit;
//如果在DLL输出的函数中没有找到PcbApi_QueryPrimitive函数,即_PcbApi_QueryPrimitive为空,则退出。
//找到后进行指针类型转换,即把指针所指向的内存地址中内存转换为函数
Result:= TPcbApi_QueryPrimitive(_PcbApi_QueryPrimitive)
(Mode, ObjectHandle, BitField, Index, Layer,
Net, Component, Moveable);
End;
3.4 数据完整性
从PCB数据库中抽取数据(就是复制相同的一组数据)需要注意“数据完整性”,请参见图4-11和4-12,数据完整性在数据库中数据和外部服务器的外部数据之间保持数据同步。
|
序号 |
PCB服务器 |
外部的服务器 |
状态 |
|
1 |
|
初始的状态 原理图服务器和外部服务器有相同的数据。 |
|
|
2 |
第二状态 在原理图服务器中数据集已修改,但数据完整性没有保护。 |
||
|
3 |
第三状态 外部服务器调用GetState模块,强制新数据集应用到外部服务器。同步数据任务空间。 |
||
|
4 |
末状态 数据完整性已保护,也就是说,在原理图服务器和外部服务器之间数据集有相同的值。 |
||
|
图4-11 PCB GetState模块 |
|||
图4-11说明内部数据库中数据发生改变,外部服务器中数据与内部服务器中数据不一致,外部服务器调用GetState模块来使用内部数据库中数据强制刷新外部服务器中数据,从而使内外部服务器中数据同步。
|
序号 |
PCB服务器 |
外部的服务器 |
状态 |
|
1 |
|
初始的状态 原理图服务器和外部服务器有相同的数据。 |
|
|
2 |
第二状态 外部数据集已经修改,但是数据完整性没有保护。 |
||
|
3 |
第三状态 外部服务器调用SetState模板,强制新的数据集被应用到原理图服务器。同步数据任务空间。 |
||
|
4 |
末状态 数据完整性已保护,也就是说,在原理图服务器和外部服务器之间数据集有相同的值。 |
||
|
图4-12 PCB SetState模块 |
|||
当外部服务器中数据发生改变后,内部服务器中数据和外部服务器中数据不一致,此时外部服务器调用SetState模块来强制用外部服务器中数据刷新内部数据库数据,从而使内外部服务器数据同步。
图4-11中,当您从PCB编辑器的数据库中抽取数据到您的外部的服务器,这样就有两个相同的数据集,一旦您在PCB编辑器修改内部数据库中的数据集,那么现在就有了两个不同表现的数据集,因而,您应调用一个带有GetState模块的QueryDatabase方法,来进行外部服务器数据更新,更新后两个数据库数据集相同。
图4-12,当您从PCB编辑器的数据库中抽取数据到您的外部服务器,这样就有两个相等的数据集,一旦您在外部数据库中修改了数据集,那么现在就有了两个不同表现的数据集,因而,您应调用一个带有SetState模块的QueryDatabase方法来强制PCB编辑器进行内部数据的更新,更新后两个数据库数据集相同。
当两个或更多数据集表现相同的信息时,其有相同的值,需要保护数据完整性。例如,如果您抽取一条线到PCB外,并在外部服务器中使用,这样这条线对象将有两个表现,一个在PCB数据库内,一个在外部服务器。
QueryDatabase进程的实际实现,是那个印制板对象必须通过使用当前印制板文档的句柄来创建,接下来,在印制板中,PCB对象就能被增加,删除或修改。
3.5 创建一个新的PCB对象
使用PCB API来创建PCB对象,需要按一列一些简单的步骤进行,以确保PCB编辑器数据库系统将能成功注册这些对象。下面是一个简单的例子,说明了如何创建一个新的PCB对象的步骤,例子代码显示出,在任何PCB对象被创建、销毁或修改前,创建一个新的印制板对象最高的任务,如果这里没有印制板对象,内置在PCB编辑器的数据库系统将不会被更新,因而,PCB文档将不受到影响,此例子显示出对象句柄是很重要的。
代码片段功能是放一个过孔对象(Via object,是一个PCB编辑器的设计对象)到PCB文档上。
请见SDK例子\SAMPLES\NO4\API\PCB\Create a via object。
{....................................................................................}
Procedure CreateAViaObject;
Var
BoardHandle : TobjectHandle; //印制板句柄。
ViaHandle : TobjectHandle; //过孔对象句柄。
PCBBoard: TPCBBoard; //印制板对象。
Via : TPCBVia; //过孔对象。
Begin
SetAllPCBProcAddresses;
//SetAllPCBProcAddresses过程初始化并且设置所有PCB编辑器调用。即取得所有AdvPcb.dll中输出的函数和过程的地址指针。
BoardHandle := PcbApi_GetCurrentBoardHandle;
//PcbApi_GetCurrentBoardHandle函数返回当前在设计资源管理器中的PCB文档的句柄,如果印制板没有找到则返回值是空(nil)。
PCBBoard := TPCBBoard.Create(BoardHandle);//创建一个印制板对象。
PCBBoard.QueryDatabase(eGetState);//同步内部服务器数据库和外部服务器数据库
ViaHandle := PcbApi_CreateObject(eViaObject);
//PcbApi_CreateObject函数使用给定的对象种类参数创建一个PCB对象,此函数返回新建的PCB对象的对象句柄。
Via := TPCBVia.Create(ViaHandle);//新建一过孔对象。
Via.QueryDatabase(eGetState);//用内部数据同步外部数据。
Via.x1:= MilsToCoord(1000);
Via.y1:= MilsToCoord(1000);
Via.Size:= MilsToCoord(50);
Via.HoleSize:= MilsToCoord(20);
Via.LowLayer:= eTopLayer;
Via.HighLayer := eBottomLayer;
//以上代码给新建的过孔对象赋值。
Via.QueryDatabase(eSetState);//用外部服务器数据强制刷新内部服务器数据。
PCBBoard.AddObject(Via.ObjectHandle);//把过孔对象增加到印制板上。
PCBBoard.Free;
Via.Free;
//以上代码清理现场。
End;
此段代码使用了下列重要的函数或过程。
|
PcbApi_GetCurrentBoardHandle |
PcbApi_CreateObject |
|
QueryDatabase |
AddObject |
这段代码做什么?
在上面代码中,先创建TPCBBoard对象,并且通过PcbApi_GetCurrentBoardHandle函数得到印制板对象的句柄,接着来创建一个新的过孔对象(Via),您需要使用带有对象ID号如eViaObject的PcbApi_CreateObject函数,您接着需要应用一个QueryDatabase(eGetState)方法来初始化此Via对象,再下一步是分配新的数据值到新建的Via对象的每一个字段,不管怎样,仅注册Via对象到PCB编辑器数据库是不够的。
为了使PCB编辑器的数据库系统知道这个新的Via对象,我们需要来增加新Via对象到印制板对象中,通过使用印制板对象的AddObject方法,AddObject方法的参数是新建Via对象的句柄,一旦AddObject方法被调用,现在,新建的Via对象在PCB编辑器工作空间已是有效对象,当您完成这些工作时,不在忘记释放PCB对象和印制板对象。
新的PCB对象被分配了唯一的对象句柄,此对象句柄是通过带有传入对象种类参数的PcbApi_CreateObject API函数来创建的,对象句柄提供了身份验证方法,并且在PCB编辑器数据库中注册新的和已存在的PCB对象,使用这些对象的句柄,您能维护存储在数据库中的PCB对象的属性。(e-works)
