我想从头开始实现自己的OPC DA客户端(版本2.02,2.05a,3.00),但不使用任何第三方。另外,我想利用OPCEnum.exe服务获取已安装的OPC服务器列表。是否有任何类型的文档详细解释了实施OPC客户端的过程?
答案 0 :(得分:4)
我有一个c#实现,但实际上很难适应它。我将尝试总结所需的步骤。
大多数情况下,您需要从Opcfoundation.org免费下载OPC Core Components Redistributable软件包中的OpcRcw.Comn.dll和OpcRcw.Da.dll。安装后,文件位于C:\ Windows \ assembly \ GAC_MSIL中。在项目中创建一个引用。
关于编码,这是你应该做的(你想要实现三个对象,服务器,组和项目):
让我们从服务器开始:
Type typeofOPCserver = Type.GetTypeFromProgID(serverName, computerName, true);
m_opcServer = (IOPCServer)Activator.CreateInstance(typeofOPCserver);
m_opcCommon = (IOPCCommon)m_opcServer;
IConnectionPointContainer icpc = (IConnectionPointContainer)m_opcServer;
Guid sinkGUID = typeof(IOPCShutdown).GUID;
icpc.FindConnectionPoint(ref sinkGUID, out m_OPCCP);
m_OPCCP.Advise(this, out m_cookie_CP);
我已经在这里划了很多检查以适应它,把它当作样本...... 然后,您需要在服务器上添加组的方法:
// Parameter as following:
// [in] active, so do OnDataChange callback
// [in] Request this Update Rate from Server
// [in] Client Handle, not necessary in this sample
// [in] No time interval to system UTC time
// [in] No Deadband, so all data changes are reported
// [in] Server uses english language to for text values
// [out] Server handle to identify this group in later calls
// [out] The answer from Server to the requested Update Rate
// [in] requested interface type of the group object
// [out] pointer to the requested interface
m_opcServer.AddGroup(m_groupName, Convert.ToInt32(m_isActive), m_reqUpdateRate, m_clientHandle, pTimeBias, pDeadband, m_LocaleID, out m_serverHandle, out m_revUpdateRate, ref iid, out objGroup);
// Get our reference from the created group
m_OPCGroupStateMgt = (IOPCGroupStateMgt)objGroup;
最后你需要创建项目:
m_OPCItem = (IOPCItemMgt)m_OPCGroupStateMgt;
m_OPCItem.AddItems(itemList.Length, GetAllItemDefs(itemList), out ppResults, out ppErrors);
其中itemlist是OPCITEMDEF []的数组。我使用来自我的结构的GetAllItemDefs来构建上述内容。
private static OPCITEMDEF[] GetAllItemDefs(params OpcItem[] opcItemList)
{
OPCITEMDEF[] opcItemDefs = new OPCITEMDEF[opcItemList.Length];
for (int i = 0; i < opcItemList.Length; i++)
{
OpcItem opcItem = opcItemList[i];
opcItemDefs[i].szAccessPath = "";
opcItemDefs[i].bActive = Convert.ToInt32(opcItem.IsActive);
opcItemDefs[i].vtRequestedDataType = Convert.ToInt16(opcItem.ItemType, CultureInfo.InvariantCulture);
opcItemDefs[i].dwBlobSize = 0;
opcItemDefs[i].pBlob = IntPtr.Zero;
opcItemDefs[i].hClient = opcItem.ClientHandle;
opcItemDefs[i].szItemID = opcItem.Id;
}
return opcItemDefs;
}
最后,关于枚举服务器,我使用这两个函数:
/// <summary>
/// Enumerates hosts that may be accessed for server discovery.
/// </summary>
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
public string[] EnumerateHosts()
{
IntPtr pInfo;
int entriesRead = 0;
int totalEntries = 0;
int result = NetServerEnum(
IntPtr.Zero,
LEVEL_SERVER_INFO_100,
out pInfo,
MAX_PREFERRED_LENGTH,
out entriesRead,
out totalEntries,
SV_TYPE_WORKSTATION | SV_TYPE_SERVER,
IntPtr.Zero,
IntPtr.Zero);
if (result != 0)
throw new ApplicationException("NetApi Error = " + String.Format("0x{0,0:X}", result));
string[] computers = new string[entriesRead];
IntPtr pos = pInfo;
for (int ii = 0; ii < entriesRead; ii++)
{
SERVER_INFO_100 info = (SERVER_INFO_100)Marshal.PtrToStructure(pos, typeof(SERVER_INFO_100));
computers[ii] = info.sv100_name;
pos = (IntPtr)(pos.ToInt32() + Marshal.SizeOf(typeof(SERVER_INFO_100)));
}
NetApiBufferFree(pInfo);
return computers;
}
/// <summary>
/// Returns a list of servers that support the specified specification on the specified host.
/// </summary>
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
public string[] GetAvailableServers(Specification specification)
{
lock (this)
{
// connect to the server.
ArrayList servers = new ArrayList();
MULTI_QI[] results = new MULTI_QI[1];
GCHandle hIID = GCHandle.Alloc(IID_IUnknown, GCHandleType.Pinned);
results[0].iid = hIID.AddrOfPinnedObject();
results[0].pItf = null;
results[0].hr = 0;
try
{
// create an instance.
Guid srvid = CLSID;
CoCreateInstanceEx(srvid, null, CLSCTX.CLSCTX_LOCAL_SERVER, IntPtr.Zero, 1, results);
m_server = (IOPCServerList2)results[0].pItf;
// convert the interface version to a guid.
Guid catid = new Guid(specification.ID);
// get list of servers in the specified specification.
IOPCEnumGUID enumerator = null;
m_server.EnumClassesOfCategories(1, new Guid[] { catid }, 0, null, out enumerator);
// read clsids.
Guid[] clsids = ReadClasses(enumerator);
// release enumerator
if (enumerator != null && enumerator.GetType().IsCOMObject)
Marshal.ReleaseComObject(enumerator);
// fetch class descriptions.
foreach (Guid clsid in clsids)
{
try
{
string url = CreateUrl(specification, clsid);
servers.Add(url);
}
catch (Exception) { }
}
}
catch
{
}
finally
{
if (hIID.IsAllocated) hIID.Free();
if (m_server != null && m_server.GetType().IsCOMObject)
Marshal.ReleaseComObject(m_server);
}
return (string[])servers.ToArray(typeof(string));
}
}
我知道我已经划了很多但也许它仍然可以帮助你;) 如果您认为我已经清楚了,请将答案标记为正确;) 亲切的问候, d。