基于C#开发PLC上位机(三)—MX软件中.dll库调用尝试

       

目录

一.失败案例:

二.成功案例:

 结论


        使用控件有很多限制,总有些人不喜欢使用winform,习惯用别的工具开发界面。本文在探索一个通用的工程,添加.dll文件实现在任意C#工程中即可调用三菱提供的官方函数。

一.失败案例:

        示例工程中,在工程文件下bin目录查看引用的.dll文件,我们初步猜测项目必须引用的库为前两个。

         接下来开始实验,我们新建一个控制台应用程序,不同于示例中,控制台项目中没有任何界面或者控件。

在引用中添加上述两个库,即:

添加命名控件,随便写两行代码,验证一下相关函数是否可用,我这里使用的是Open函数。

 

       

        很遗憾,它在报错,这个报错的大概意思是指有个基类需要在程序集System.Windows.Forms中才能使用,现在缺少此程序集。

还是在刚才的引用中,找到这个程序集并选中,可以发现报错已经消失:

         

        接着运行此代码,很遗憾,还在报错,该报错的大概意思就是ActiveX控件只能在单线程使用,而控制台程序是在多线程下运行的:

         百度解决方案,当前线程不在单线程单元中,因此无法实例化 ActiveX 控件解决办法 - winzheng - 博客园 (cnblogs.com),按照此种方法尝试:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AxActProgTypeLib;
using AxActUtlTypeLib;
using ActUtlTypeLib;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
              Thread newThread = new Thread(new ThreadStart(ThreadMethod));
              //ApartmentState Property is obsolete;
             // newThread.SetApartmentState(ApartmentState.MTA);

              // The following line is ignored since
              // ApartmentState can only be set once.
              newThread.SetApartmentState(ApartmentState.STA);
              Console.WriteLine("ThreadState: {0}, ApartmentState: {1}",
                  newThread.ThreadState, newThread.ApartmentState);
              newThread.Start();
              // Wait for newThread to start and go to sleep.
              Thread.Sleep(300);
              try
              {
                  // This causes an exception since newThread is sleeping.
                  newThread.SetApartmentState(ApartmentState.STA);
              }
              catch (ThreadStateException stateException)
              {
                  Console.WriteLine("\n{0} caught:\n" +
                      "Thread is not in the Unstarted or Running state.",
                      stateException.GetType().Name);
                  Console.WriteLine("ThreadState: {0}, ApartmentState: {1}",
                      newThread.ThreadState, newThread.GetApartmentState());
              }


        }
        static void ThreadMethod()
        {
           // Thread.Sleep(1000);
            AxActUtlType axActUtlType1 = new AxActUtlType();
            axActUtlType1.ActLogicalStationNumber = 1;
            //Set the value of 'Password'.
            //The Open method is executed.
            int iReturnCode = axActUtlType1.Open();
            Console.WriteLine(iReturnCode);
        }
    }
}

        依然在报错:

         于是博主参照示例工程的引用项目,将没有的程序集都添加了进来:

        最终还在报和上述一样的错误,可以看出这个AxHost只能在winform下运行,此次尝试失败。

二.成功案例:

        接下来我们转变思路,经过我们上文中的做法,已经可以确定该控件必须在winform环境下运行,所以接下来可以尝试一下在控制台程序中内嵌一个窗体,类似Windows系统中内嵌一个Linux虚拟机。

        新建一个工程,在“解决方案-引用”中添加以下三个库:

        有些库的复制本地属性是False,意思就是直接添加不会被导入本地文件夹,在引用中添加后还需要手动将该文件复制进入工程文件中的bin文件,上述三个库并不需要,但是后续可能有的会需要,提前说明避免踩坑。           

        同样的,记得添加命名空间:

         下边粘贴代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using AxActUtlTypeLib;
using System.Threading;
namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread newThread = new Thread(new ThreadStart(ThreadMethod));
            //ApartmentState Property is obsolete;
            // newThread.SetApartmentState(ApartmentState.MTA);

            // The following line is ignored since
            // ApartmentState can only be set once.
            newThread.SetApartmentState(ApartmentState.STA);
            Console.WriteLine("ThreadState: {0}, ApartmentState: {1}",
                newThread.ThreadState, newThread.ApartmentState);
            newThread.Start();
            // Wait for newThread to start and go to sleep.
            Thread.Sleep(300);
            try
            {
                // This causes an exception since newThread is sleeping.
                newThread.SetApartmentState(ApartmentState.STA);
            }
            catch (ThreadStateException stateException)
            {
                Console.WriteLine("\n{0} caught:\n" +
                    "Thread is not in the Unstarted or Running state.",
                    stateException.GetType().Name);
                Console.WriteLine("ThreadState: {0}, ApartmentState: {1}",
                    newThread.ThreadState, newThread.GetApartmentState());
            }
            void ThreadMethod()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                MainOperation formTest = new MainOperation();
                int iReturnCode;
                iReturnCode = formTest.test();
                Console.WriteLine(iReturnCode);
                Application.Run(formTest);
    
            }

        }
    }
    public partial class MainOperation : Form
    {
        public MainOperation()
        {

        }
        public int  test()
        {
            AxActUtlTypeLib.AxActUtlType axActUtlType1 = new         
            AxActUtlTypeLib.AxActUtlType();
            this.Controls.Add(axActUtlType1);
            axActUtlType1.ActLogicalStationNumber = 1;
            int iReturnCode = axActUtlType1.Open();
            return iReturnCode;
        }
    }
}

        这个代码就是在单线程运行的基础上,建立一个Form,控件实际还是在form中运行,博主在尝试时曾提示过运行环境错误,故将管理器配置为X86,若无相关报错则无需理会:

运行结果如下:

        

        相同的问题,既然已经在form环境中运行控件了为什么还会报错?不知道大家记不记得前边文章中使用控件前需要勾选工具箱中组件,而这里我们是用的是控制台,根本没有选择组件这一说,就相当于我们使用的自定义组件没有注册:

         百度解决方案:引发类型为“System.Windows.Forms.AxHost+InvalidActiveXStateException”的异常 解决办法 - Marksion - 博客园 (cnblogs.com)

        再次尝试,我们事先已经配置并启动Communication Setup Utility,启动Simulator 3,再次启动:

        返回值为0,证明已经成功,下边粘贴修改后的Test函数代码:

        public int  test()
        {
            AxActUtlTypeLib.AxActUtlType axActUtlType1 = new 
            AxActUtlTypeLib.AxActUtlType();
           ((System.ComponentModel.ISupportInitialize)(axActUtlType1)).BeginInit();
            this.Controls.Add(axActUtlType1);
           ((System.ComponentModel.ISupportInitialize)(axActUtlType1)).EndInit();
            axActUtlType1.ActLogicalStationNumber = 1;
            int iReturnCode = axActUtlType1.Open();
            return iReturnCode;
        }

 结论

         本质上还是在Winform环境下调用的.dll,因为我们并没有看到三菱.dll库的底层,所以最终尝试的结果还是证明在winform控制台下调用库才能稳定运行。。

        

        


版权声明:本文为qq_34191294原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。