CnPack Forum » 技术板块灌水区 » DELPHI编写OPC(一):用 Automation(自动化)编写OPC客户端


2007-11-5 17:08 skyjacker
DELPHI编写OPC(一):用 Automation(自动化)编写OPC客户端

DELPHI[font=宋体]编写[/font]OPC([font=宋体]一[/font])[font=宋体]:在[/font] Delphi [font=宋体]下用[/font] Automation[font=宋体](自动化)编写[/font]OPC [font=宋体]客户端[/font]

{* |<PRE>
======================================================================
* [font=宋体]版权声明:[/font]Copyright ? SkyJacker. [font=宋体]未经原作者同意,禁止任何形式的编辑、转载[/font]
*                   [color=black]WITHOUT AUTHORAGREEMENT, FORBIDDEN TRANSSHIPMENT[/color].
* [font=宋体]声明版权的两点原因:[/font]
* 1[font=宋体]、我在网上看到一篇很不错的文章,作者说如果需要源代码可以跟他联系,可是我搜不[/font]
* [font=宋体]到作者是谁。因为原作者太多了。[/font]
* 2[font=宋体]、同样是一片好文章,结果被某些网站分成了[/font]N[font=宋体]份,夹杂着一些大型花边广告图像。通[/font]
* [font=宋体]过广告赚钱我很理解也很佩服,但是你们不应该把原文删得乱七八糟。[/font]
================================================================================
* [font=宋体]软件名称:[/font]DELPHI[font=宋体]编写[/font]OPC
* [font=宋体]单元名称:在[/font] Delphi [font=宋体]下用[/font] Automation[font=宋体](自动化)编写[/font]OPC [font=宋体]客户端[/font]
* [font=宋体]单元作者:[/font]SkyJacker(Msn&Email: HeMiaoYu@gmail.com)
* [font=宋体]备[/font]    [font=宋体]注:[/font]
* [font=宋体]开发平台:[/font]Win2003 + Delphi 6.0 UP2
* [font=宋体]兼容测试:无[/font]
* [font=宋体]本[/font][font=宋体]地[/font] [font=宋体]化:该单元中的字符串不符合本地化处理方式[/font]
* [font=宋体]单元标识:[/font]
* [font=宋体]发布目的:互相交流学习,共同完善《[/font]DELPHI [font=宋体]编写[/font] OPC[font=宋体]》系列。“这不是一个人的战斗!”[/font]
* [font=宋体]发布地址:[/font][url=http://bbs.cnpack.org/]http://bbs.cnpack.org[/url] [font=宋体]我在这儿等着您的指导[/font]
* [font=宋体]修改记录:[/font]2007.11.03
*                [font=宋体]创建单元[/font]
================================================================================
|</PRE>}

一、[font=宋体]什么是[/font]OPC
[font=宋体]OPC[/font][font=宋体]([/font][font=宋体]OLE for Process Control[/font][font=宋体],用于过程控制的OLE[/font][font=宋体])是 [/font][font=宋体]Microsoft COM/DCOM [/font][font=宋体]技术在工控领域的应用。[/font]
[font=宋体]OPC[/font][font=宋体]提供一套统一的标准,采用 C/S 模式,硬件厂商或其外包公司完成具有统一OPC接口标准的Server程序,软件厂商只需按照OPC标准编写Client程序访问Server程序,即可实现与硬件设备的通信。[/font]

[font=宋体]二、[/font]OPCAutomation [font=宋体]安装步骤:[/font]
1)[font=宋体]、使用[/font]regsvr32 [font=宋体]注册[/font] OPCDAAuto.dll
2)[font=宋体]、在[/font] Delphi [font=宋体]中导入类型库[/font]OPC Automation 2.0[font=宋体]。如图[/font]Figure 1-1[font=宋体]:[/font]

[img=389,475]http://file:///C:/DOCUME%7E1/ADMINI%7E1/LOCALS%7E1/Temp/msohtml1/01/clip_image002.jpg[/img]

[font=宋体]方法一:人工创建[/font] OPCAutomation[font=宋体]类[/font]

(1)[font=宋体]、声明[/font] OPC [font=宋体]特有的类与接口[/font]

       OPCItems[font=宋体]在[/font] Automation [font=宋体]中没有实现的类,因此直接声明其接口。[/font]
    {Private declarations }
   FOPCServer: TOPCServer;
   FOPCGroup: TOPCGroup;
   FOPCItems: OPCItems; // interface
   FOPCItem: OPCItem; // interface

   // OPC [font=宋体]常用操作函数[/font]
   function OPCServerConnect(AServerProgID: WideString): Boolean;
   {* [font=宋体]连接[/font] OPC Server}
   function OPCGroupConnect(AGroupName: OleVariant): Boolean;
   {* [font=宋体]连接[/font] OPC Group}
    procedure OPCItemCreateOne(AItemName:OleVariant);
   {* [font=宋体]创建一个[/font] OPCItem}
   function OPCItemOneStart(): Boolean;
   {* [font=宋体]为了读写[/font] Item[font=宋体],定位到[/font] OPCServer [font=宋体]的一个[/font] Item}
   procedure OPCServerDisconnect;
   {* [font=宋体]断开与[/font] OPC [font=宋体]服务器的连接[/font]}
   procedure OPCItemReadWrite;
   {* [font=宋体]读写[/font] Item [font=宋体]数据[/font]}

const
cnServerProgID = 'www.cnpack.org OpcServer 0.01'; // [font=宋体]替换成你的[/font] OPC [font=宋体]服务器[/font]
cnGroupName = 'Group1';
cnItemName = 'Voltage.PV'; // [font=宋体]读取的具体项值[/font]

var
FrmMain: TFrmMain;

implementation

{$R *.dfm}

// [font=宋体]连接[/font] OPC Server
function TFrmMain.OPCServerConnect(AServerProgID:WideString): Boolean;
begin
Result := True;
  try
   FOPCServer := TOPCServer.Create(Self);
   FOPCServer.Connect1(AServerProgID);
except
   Result := False;
end;
end;

// [font=宋体]连接[/font] OPC Group
functionTFrmMain.OPCGroupConnect(AGroupName: OleVariant): Boolean;
begin
Result := True;
  try
   FOPCGroup := TOPCGroup.Create(Self);
   FOPCGroup.ConnectTo(FOPCServer.OPCGroups.Add(AGroupName));

   FOPCGroup.IsActive := True;   
   FOPCGroup.IsSubscribed := True; // [font=宋体]事件支持[/font]
except
   Result := False;
end;
end;

// [font=宋体]创建一个[/font] OPCItem
procedureTFrmMain.OPCItemCreateOne(AItemName: OleVariant);
var
NumItems: Integer;
OVItemID: OleVariant;
OVClientHandles: OleVariant;
OVServerHandles: OleVariant;
OVErrors: OleVariant;
OleErr: string;
begin
FOPCItems := FOPCGroup.OPCItems;

NumItems := 1;

OVItemID := VarArrayCreate([1, 1], varOleStr);
OVItemID[1] := AItemName;

OVClientHandles := VarArrayCreate([1, 1], varInteger);
OVClientHandles[1] := 1;

OVServerHandles := VarArrayCreate([1, 1], varInteger);
OVServerHandles[1] := 0; // [font=宋体]初始化[/font]

OVErrors := VarArrayCreate([1, 1], varOleStr);
OVErrors := EmptyParam;

FOPCItems.AddItems(
   NumItems,
   PSafeArray(TVarData(OVItemID).VOleStr),
   PSafeArray(TVarData(OVClientHandles).VInteger),
   PSafeArray(TVarData(OVServerHandles).VInteger),
   PSafeArray(TVarData(OVErrors).VInteger),
   EmptyParam,
   EmptyParam
   );
//OleErr := OPCServer1.GetErrorString(OVErrors[1]); // [font=宋体]如果[/font] ItemID [font=宋体]无效[/font],[font=宋体]则此命令也无效[/font]
  ifOVServerHandles[1] >0 then
   FOPCItem := FOPCItems.GetOPCItem(OVServerHandles[1])
else
begin
   raise EOleError.Create('[font=宋体]失败[/font]: [font=宋体]连接[/font]' +AItemName + #13#10 + OleErr);
  end
end;

// [font=宋体]定位到一个[/font] Item
function TFrmMain.OPCItemOneStart():Boolean;
begin
Result := False;
  ifnot OPCServerConnect(cnServerProgID) then
begin
    OPCServerDisconnect;
   Exit;
end;
  ifnot OPCGroupConnect(cnGroupName) then
begin
   OPCServerDisconnect;
   Exit;
end;
  try
   OPCItemCreateOne(cnItemName);
   Result := True;
except on E: Exception do
   begin
     OPCServerDisconnect;
     ShowMessage(E.Message);
   end;
end;
end;

// [font=宋体]断开与[/font] OPC [font=宋体]服务器的连接[/font]
procedure TFrmMain.OPCServerDisconnect;
begin
  ifAssigned(FOPCServer) then
begin
   if Assigned(FOPCGroup) then
   begin
     FOPCServer.OPCGroups.RemoveAll;
     FOPCGroup.Free;
     FOPCGroup := nil;
   end;
   FOPCItems := nil;
   FOPCItem := nil;

   FOPCServer.Disconnect;
   FOPCServer.Free;
   FOPCServer := nil;
end;
end;

procedure TFrmMain.OPCItemReadWrite;
var
Value, Quality, TimeStamp: OleVariant;
begin
  ifnot Assigned(FOPCItem) then Exit;

  // [font=宋体]写[/font]
  //FOPCItem.Write(10);

  // [font=宋体]读[/font]
FOPCItem.Read(OPCDevice, Value, Quality, TimeStamp);
edtValue.Text := Value;
edtQua.Text := Quality;
edtTimeStamp.Text := TimeStamp;
end;

procedure TFrmMain.btnOPCItemStartClick(Sender:TObject);
begin
  ifOPCItemOneStart then
   btnOPCItemStart.Enabled := False;
end;

procedure TFrmMain.btnStopClick(Sender:TObject);
begin
OPCServerDisconnect;
btnStart.Enabled := True;
btnOPCItemStart.Enabled := True;
end;

procedureTFrmMain.btnReadWriteClick(Sender: TObject);
begin
OPCItemReadWrite;
end;

[font=宋体]方法一的代码确实有点繁,但是却可以加深理解。下面有个代码少的。[/font]

[font=宋体]方法二:利用[/font] ActiveX[font=宋体]面板的[/font]OPC [font=宋体]控件[/font]

[font=宋体]选择[/font] OPCServer,OPCGroup [font=宋体]控件。如图[/font]Figure 1-2[font=宋体]:[/font]
[img=152,75]http://file:///C:/DOCUME%7E1/ADMINI%7E1/LOCALS%7E1/Temp/msohtml1/01/clip_image004.jpg[/img]

// [font=宋体]使用控件连接[/font] OPC Server
procedureTFrmMain.btnCtrlStartClick(Sender: TObject);
var
NumItems: Integer;
OVItemID: OleVariant;
OVClientHandles: OleVariant;
OVServerHandles: OleVariant;
OVErrors: OleVariant;
OleErr: string;
begin
OPCServer1.Connect1(cnServerProgID);
OPCGroup1.ConnectTo(OPCServer1.OPCGroups.Add(cnGroupName));
FOPCItems := OPCGroup1.OPCItems;


NumItems := 1;

OVItemID := VarArrayCreate([1, 1], varOleStr);
OVItemID[1] := cnItemName;

OVClientHandles := VarArrayCreate([1, 1], varInteger);
OVClientHandles[1] := 1;

OVServerHandles := VarArrayCreate([1, 1], varInteger);
OVServerHandles[1] := 0; // [font=宋体]初始化[/font]

OVErrors := VarArrayCreate([1, 1], varOleStr);
OVErrors := EmptyParam; // [font=宋体]初始化[/font]

FOPCItems.AddItems(
   NumItems,
   PSafeArray(TVarData(OVItemID).VOleStr),
   PSafeArray(TVarData(OVClientHandles).VInteger),
   PSafeArray(TVarData(OVServerHandles).VInteger),
   PSafeArray(TVarData(OVErrors).VInteger),
   EmptyParam,
   EmptyParam
   );

  ifOVServerHandles[1] >0 then
   FOPCItem := FOPCItems.GetOPCItem(OVServerHandles[1])
else
begin
   raise EOleError.Create('[font=宋体]失败[/font]: [font=宋体]连接[/font]' +cnItemName + #13#10 + OleErr);
  end
end;

procedureTFrmMain.btnCtrlReadWriteClick(Sender: TObject);
begin
OPCItemReadWrite;
end;

[font=宋体]如果你是刚开始学习编写[/font] OPC Client[font=宋体],千万不要指望仅仅这篇文章就可以完成你的第一个“[/font]Hello World[font=宋体]”。而且,我知道你要的不仅仅是这点代码,其实你要的也许是[/font]OPC Server demo[font=宋体],[/font]OPC*.dll[font=宋体]。[/font]
[font=宋体]不过不要紧,[/font][url=http://www.cnpack.org/]http://www.cnpack.org[/url][font=宋体],《[/font]DELPHI[font=宋体]编写[/font]OPC[font=宋体]》,热心网友会帮助你的。[/font]
[font=宋体]我相信等《[/font]DELPHI[font=宋体]编写[/font]OPC[font=宋体]》系列快结束时,[/font] [font=宋体]“[/font]www.cnpack.org OpcServer 0.01[font=宋体]”[/font][font=宋体]会出来的,作者也许就是你。[/font]
[font=宋体]给你一些链接,让我们来记住这些值得尊敬的文章和作者吧。吃水不忘挖井人嘛。[/font]
[font=宋体](在我发布这些链接的时候,我已经点开了这些链接,并且我没有中毒或木马,[/font]Good Luck![font=宋体])[/font]

[font=宋体]三、本文参考资料:[/font]

[url=http://bbs.gongkong.com/Detail.Asp?id=98664&page=2]http://bbs.gongkong.com/Detail.Asp?id=98664&page=2[/url]
[url=http://blog.gongkong.com/Index.Asp?Id=10434]http://blog.gongkong.com/Index.Asp?Id=10434[/url]
[url=http://www.opcfoundation.org/forum/viewtopic.php?t=2042]http://www.opcfoundation.org/forum/viewtopic.php?t=2042[/url]
[url=http://www.cnblogs.com/Phoenix-Rock/archive/2007/09/05/541696.html]http://www.cnblogs.com/Phoenix-Rock/archive/2007/09/05/541696.html[/url]
[url=http://www.cnpack.org/]http://www.cnpack.org[/url] [font=宋体]本文的版权部分与代码格式摘抄于此处喔[/font]
……

四、OPC DLL 下载

2005-11-25  09:10            86,016 opchda_ps.dll
2005-11-25  09:10           102,400 opcproxy.dll
2005-11-25  09:10            69,632 opc_aeps.dll
2005-11-25  09:10            61,440 opccomn_ps.dll
2005-11-25  09:11            98,304 OPCENUM.EXE
1999-11-17  07:51           105,984 OPCDAAuto.dll

[[i] 本帖最后由 skyjacker 于 2007-11-30 15:32 编辑 [/i]]

2007-11-11 09:55 zzzl
报告楼主,前两张图显示不了

2008-10-30 23:31 hjusea
你好我想问一下OPC接口读取和接收数据的详细写法有吗?
我用你做的不能连接远程机为什么?
QQ:308564493

2008-11-6 15:49 kendling
不错的文章,支持一个。

2008-12-9 16:46 lixupeng
不太懂不过还是支持下:)

页: [1]


Powered by Discuz! Archiver 5.0.0  © 2001-2006 Comsenz Inc.