首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从头开始实现OPC DA客户端

从头开始实现OPC DA客户端
EN

Stack Overflow用户
提问于 2013-07-24 23:06:30
回答 1查看 3.3K关注 0票数 2

我想从头开始实现我自己的OPC DA客户端( 2.02、2.05a、3.00版),但不使用任何第三方。此外,我还想使用OPCEnum.exe服务来获取已安装的OPC服务器的列表。是否有任何类型的文档详细地、循序渐进地解释实现OPC客户端的过程?

EN

回答 1

Stack Overflow用户

发布于 2013-08-27 18:09:54

我有一个c#实现,但实际上很难在这里适应它。我将尝试总结一下所需的步骤。

大多数情况下,您需要从Opcfoundation.org免费下载OPC Core Components Redistributable package中的OpcRcw.Comn.dll和OpcRcw.Da.dll。安装后,这些文件将位于C:\Windows\assembly\GAC_MSIL中。在项目中创建引用。

关于编码,这是你应该做的(有三个你想实现的对象,Server,Group和Item):

让我们从服务器开始:

代码语言:javascript
复制
 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);

我做了很多检查以适应这里的情况,拿来当样品...然后,您需要在服务器上使用一个方法来添加组:

代码语言:javascript
复制
 // 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;

最后,您需要创建项目:

代码语言:javascript
复制
 m_OPCItem = (IOPCItemMgt)m_OPCGroupStateMgt;
 m_OPCItem.AddItems(itemList.Length, GetAllItemDefs(itemList), out ppResults, out ppErrors);

其中itemlist是一个OPCITEMDEF[]数组。我使用GetAllItemDefs从我的一个结构中构建了上面的代码。

代码语言:javascript
复制
    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;
    }

最后,关于枚举服务器,我使用以下两个函数:

代码语言:javascript
复制
   /// <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。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17837952

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档