2013-07-24 2 views
0

Я хотел бы реализовать собственный клиент OPC DA (версии 2.02, 2.05a, 3.00) с нуля, но без использования сторонних разработчиков. Также я хотел бы воспользоваться службой OPCEnum.exe, чтобы получить список установленных OPC-серверов. Есть ли какой-либо документ, который объясняет подробный и шаг за шагом процесс внедрения OPC-клиента?Внедрение клиента OPC DA с нуля

+1

с сайта opcfoundation.org вы можете получить спецификацию, тогда вам нужно знать COM для реализации интерфейсов. Я не видел никакого учебника для этого, и большинство примеров программ полагаются на некоторый набор, поскольку COM может быть болью для работы. –

+0

Спасибо, но проблема в том, что не все спецификации являются бесплатными, я имею в виду, что я зарегистрирован, но я не являюсь участником, так что, если, например, я хочу получить спецификацию OPC DA 2,05 или 3,00, я не могу. Для членов не существует только спецификация 2.02. – user1624552

+0

хорошо, что вы не дали много информации в своем вопросе, поэтому ее трудно ответить, например. было бы хорошо, если бы вы упомянули, какую версию OPCDA вы намереваетесь. –

ответ

4

У меня есть реализация C#, но на самом деле это сложно поместить здесь. Я попытаюсь суммировать необходимые шаги.

В основном вам необходимо иметь OpcRcw.Comn.dll и OpcRcw.Da.dll из распространяемых пакетов OPC Core Components, которые можно бесплатно удалить с Opcfoundation.org. После установки файлы находятся в папке 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.

+2

У вас есть полная реализация, опубликованная в любом месте в Интернете, например github? –

+1

Было бы неплохо, если бы вы могли поделиться полным исходным кодом. – Pankaj