2

如何在 C# 中使用 COM 对象的生命周期

我将创建 OPC 服务器对象,它将用于 threading.timer 这个定时器将在一段时间后每隔几秒调用一次 opcserver 对象,它将释放自己的异常作为“ COM 对象已从其底层 RCW 无法使用..”

这是代码

public partial class OPC_server : DevExpress.XtraEditors.XtraForm
{
    private System.Threading.Timer timer1;
    private System.Threading.Timer timer2;
    parameter param = new parameter();//another class
    private static readonly object myLockHolder = new object();
    private static readonly object myLockHolder1 = new object();
    public static OpcServer[] _opcServer;

    private void OPC_server_Load(object sender, EventArgs e)
    {
        getconnectedOPC();
    }

    public void getconnectedOPC()
    {
        ds = opcconn.GetOPCServerInfo();
        int i=0;
        DataTable dtOPC=new DataTable();
        if (ds.Tables[0].Rows.Count != 0 || ds.Tables[0] != null)
        {
            dtOPC = ds.Tables[0].Copy();
            _opcServer = new OpcServer[dtOPC.Rows.Count];
            TimeSpan delayTime = new TimeSpan(0, 0, 1);
            TimeSpan intervalTime = new TimeSpan(0, 0, 0, 0, 450);
            foreach (DataRow row in dtOPC.Rows)
            {
                if (i <= dtOPC.Rows.Count)
                {
                    //connetion(row);
                    getconnect(i, row, dtOPC.Rows.Count);
                    i++;
                }

            }
            connetion(dtOPC.Rows.Count);
        }
    }

    //connecting the server 
    public void getconnect(int conn, DataRow r,int rows)
    {

        DataSet ds2=new DataSet();
        DataTable dt2 = new DataTable();
        try
        {

            string machinename = Convert.ToString(r["OPCIPAddress"]);
            string servername = Convert.ToString(r["OPCName"]);

            _opcServer[conn] = new OpcServer();
            int i = _opcServer[conn].Connect(machinename, servername);
            if (i == 0)
            {
                opcconn.update("true", servername);
                writelog(servername, "connected");
            }

            else
            {
                opcconn.update("false", servername);
                writelog(servername, "disconnected");
            }
        }
        catch (OPCException e)
        {
            servername = Convert.ToString(r["OPCName"]);
            opcconn.update("false", servername);
            writelog(servername, e.Message.ToString());
        }
        catch (ApplicationException e)
        {
            servername = Convert.ToString(r["OPCName"]);
            opcconn.update("false", servername);
            writelog(servername, "No instance server");
        }  
   }


    public void OPCthread(DataRow r2,int timerinfo)
    {
    if (timerinfo == 0)
    {
       int rer = Convert.ToInt32(r2["refreshRate"]);//at least 1 second
       TimeSpan dueTime = new TimeSpan(0, 0,0,0,rer);
      TimeSpan interval = new TimeSpan(0, 0, 0 ,0 ,rer);
       timer1 = new System.Threading.Timer(register, r2, dueTime,interval);
            }
    else if (timerinfo == 1)
    {

        TimeSpan dueTime;
        TimeSpan interval;
        int rer1 = Convert.ToInt32(r2["refreshRate"]);
        dueTime = new TimeSpan(0, 0, 0, 0, rer1);
        interval = new TimeSpan(0, 0, 0, 0, rer1);
        timer2 = new System.Threading.Timer(register1, r2, dueTime, interval);
    }
}

public void register(object row1)
{
    try
    {
        lock (myLockHolder)
        {
            int cnt = 0, cnt1 = 0;
            ItemValue[] rVals;
            OPCItemDef[] item;
            OpcServer srv = new OpcServer();
            string[] array;
            //SrvStatus status1;
            DataSet paramds = new DataSet();
            DataTable paramdt = new DataTable();
            DataRow dt = (System.Data.DataRow)row1;
            int serverID = Convert.ToInt32(dt["OPCServerID"]);
           paramds = param.getparameter(Convert.ToInt32(dt["groupID"]));

            if (Convert.ToBoolean(dt["setactive"]) == true)
            {
          if (paramds != null && paramds.Tables[0].Rows.Count != 0)
                {
                    paramdt = paramds.Tables[0].Copy();
                    int tq = 0;
                    item = new OPCItemDef[paramdt.Rows.Count];
                    int clienthandle = 1;
                    foreach (DataRow r in paramdt.Rows)
                    {
                        if (tq < item.Length)
                        {
              item[tq] = new OPCItemDef(Convert.ToString(r["param_ID"]), Convert.ToBoolean(r["active"]), clienthandle, VarEnum.VT_EMPTY);
                            ++clienthandle;
                            tq++;
                        }

                    }
                    array = new string[item.Length];
                    cnt1 = 0;
                    while (cnt1 < array.Length)
                    {
                        array[cnt1] = item[cnt1].ItemID;
                        cnt1++;
                    }
          rVals = _opcServer[serverID - 1].Read(array, Convert.ToInt32(dt["refreshRate"]));
              param.update(rVals, Convert.ToInt32(dt["groupID"]));
                }
            }
        }

    }

    catch (ThreadAbortException) { }
    finally {  }
}

public void register1(object row2)
{
    try
    {
        lock (myLockHolder1)
        {
            int cnt = 0, cnt11 = 0;
            ItemValue[] rVals1;
            OPCItemDef[] item1;
            OpcServer srv1 = new OpcServer();
            string[] array1;
            DataSet paramds1 = new DataSet();
            DataTable paramdt1 = new DataTable();
            DataRow dt1 = (System.Data.DataRow)row2;
            int serverID1 = Convert.ToInt32(dt1["OPCServerID"]);
            //  Boolean gstatus = grpclass.getstatus(Convert.ToInt32(dt["groupID"]));
            paramds1 = param.getparameter2(Convert.ToInt32(dt1["groupID"]));
            if (Convert.ToBoolean(dt1["setactive"]) == true)
            {
                if (paramds1 != null)
                {
                    paramdt1 = paramds1.Tables[0].Copy();
                    int tq1 = 0;
                    item1 = new OPCItemDef[paramdt1.Rows.Count];
                    int clienthandle1 = 1;
                    foreach (DataRow r in paramdt1.Rows)
                    {
                        if (tq1 < item1.Length)
                        {
                            item1[tq1] = new OPCItemDef(Convert.ToString(r["param_ID"]), Convert.ToBoolean(r["active"]), clienthandle1, VarEnum.VT_EMPTY);
                            clienthandle1++;
                            tq1++;
                        }

                    }
                    array1 = new string[item1.Length];
                    cnt11 = 0;
                    while (cnt11 < array1.Length)
                    {
                        array1[cnt11] = item1[cnt11].ItemID;
                        cnt11++;
                    }
       rvals = _opcServer[serverID1 - 1].Read(array1, Convert.ToInt32(dt1["refreshRate"]));
                    param.update1(rVals1, Convert.ToInt32(dt1["groupID"]));
                }

            }
        }
    }
    catch { }
    finally { }
}

请告诉我正确的解决方案

4

1 回答 1

0

当您使用 OPC 时,您使用的是 COM。由于您还使用 GUI,因此您很可能将单线程单元 (STA) 用于您的ApartmentState. 在这种情况下,您应该确保所有 OPC 调用都发生在首先实例化 OPC 对象的线程上。由于 COM 对象是在 STA 线程上创建的,因此它将尝试将所有调用编组回该线程。

要完成这项工作,您需要使用单独Thread的而不是 aSystem.Threading.Timer来执行 OPC 调用,以便它们始终在同一个线程上。回调每次都会在System.Threading.Timer不同的线程(来自线程池)上执行(非确定性)。如果服务器没有响应,您将获得更好的性能,使其远离 UI 线程,您将缺少 UI。此外,如果需要,服务器可以选择关闭连接。您将收到一个 OPC Shutdown 事件,该事件将告诉您服务器希望您断开连接。

于 2011-05-19T03:54:04.373 回答