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]]