【VM服务管家】VM4.2平台SDK_6.1 环境配置类

news2024/9/29 17:34:36

目录

  • 2.1.1 环境配置:基于Csharp二次开发环境配置方法
  • 2.1.2 环境配置:基于MFC二次开发环境配置方法
  • 2.1.3 环境配置:基于Qt二次开发环境配置方法
  • 2.1.4 用户权限:普通以EXE方式启动Server的方法
  • 2.1.5 环境配置:程序启动后报错的通用方法
  • 2.1.6 VM路径:通过注册表获取VM安装路径的方法
  • 2.1.7 第三方库:格式化模块参数配置界面乱码的解决方法
  • 2.1.8 第三方库:控件与三方样式库冲突问题解决方法
  • 2.1.9 用户日志:用户日志打印的方法
  • 2.1.10 环境配置:基于LabView二次开发环境配置方法

2.1.1 环境配置:基于Csharp二次开发环境配置方法

描述
环境:VM4.2 + VS2013及以上,注意,只要VS2013有.NET Framework4.6.1,就可以使用VS2013进行VM SDK开发。
现象:基于C#如何进行VM二次开发环境配置?
解答
WinForm、WPF开发平台,两者二次开发环境配置步骤基本一致。
第一步:新建项目。使用VS新建一个窗体应用程序,以WinForm为例,框架选择.NET Framework4.6.1,接着打开项目属性页面,取消勾选【首选32位】,然后重新编译项目。最后,关闭项目。
在这里插入图片描述
在这里插入图片描述

第二步:添加引用。使用导入工具来添加引用,工具路径VisionMaster4.2.0\Development\V4.x\ComControls\Tool\ImportRef.exe。操作步骤:选择项目所在的路径,勾选需要引用的模块,也可以全部引用。点击确定按钮,待进度条100%后,打开项目,可以发现项目的引用中出现VM二次开发相关的dll。
在这里插入图片描述
在这里插入图片描述

第三步:添加控件。在WinForm窗体程序中,打开工具箱,鼠标右击【所有Windows窗体】,点击【选择项】,弹出.NET Framework组件窗口,浏览VM4.2的安装路径文件夹:VisionMaster4.2.0\Development\V4.x\ComControls\Assembly,选择VMControls.Winform.Release.dll,添加后工具箱出现VM二次开发控件。
在这里插入图片描述

控件分别为:
VmFrontend 前端运行界面控件
VmGlobalTool 全局模块控件
VmMainView 主界面控件
VmParams 参数配置控件
VmParamsConfigWithRender 参数配置带渲染控件
VmProcedure 流程配置控件
VmRenderControl 渲染控件
VmSingleModuleSet 独立Group控件
用户可将控件拖拽到窗体中使用。
如上所述为WinForm窗体应用程序添加控件的方法,下面介绍WPF添加控件的方法。
在WPF窗体应用程序->工具箱中点击【选择项】,弹出WPF组件窗口,接着浏览VM4.2的安装路径文件夹:VisionMaster4.2.0\Development\V4.x\ComControls\Assembly,选择VMControls.WPF.Release.dll。拖拉控件至窗口中,xaml中代码自动生成。
在这里插入图片描述

添加完依赖库引用和控件后,启动程序,效果如下图所示。
用户可在流程配置控件中新建流程,搭建和调试视觉方案。同时,用户可在程序中引用平台库(using VM.Core和using VM.PlatformSDKCS)和模块库(查阅VisionMaster4.2.0\Development\V4.x\Documentations中的开发手册查看模块库名称)来实现业务代码开发。
在这里插入图片描述

问题根因
不熟悉基于C#的VM二次开发环境配置步骤

2.1.2 环境配置:基于MFC二次开发环境配置方法

描述
环境:VM4.2 + VS2013及以上
现象:基于MFC如何进行VM二次开发环境配置?
解答
第一步:新建项目。以MFC+ VS2013为例。应用程序类型选择:基于对话框。
在这里插入图片描述

第二步:配置VC++目录。打开项目属性页,平台选择x64。依次配置头文件目录、库文件目录和附加依赖项。
其中,头文件目录需要配置模块头文件。库目录选择win64\C。附加依赖项选择iMVS-6000PlatformSDK.lib。
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

第三步:添加控件头文件和源文件。将控件头文件、源文件拷贝到工程目录下(本例为VS2013创建的程序,控件文件路径VisionMaster4.2.0\Development\V4.x\ComControls\Includes\VS2013,VS2017创建的程序则选择VS2017文件夹),拷贝之后再添加头文件和源文件。
在这里插入图片描述

第四步:添加VM 封装的ActiveX控件,这些控件在VM安装时已经注册,可以直接选择。
在这里插入图片描述

第五步:在程序中包含头文件,并进行控件的绑定与初始化。
在这里插入图片描述

定义控件变量:

private:
	CVmMainViewControlInterface m_MainViewctr;

控件变量绑定界面:

void CVMMFCApplication1Dlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_VMUSERCONTROL1, m_MainViewctr);
}

通过控件变量给控件初始化:

BOOL CVMMFCApplication1Dlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
	// 将“关于...”菜单项添加到系统菜单中。
             …
	// TODO: 在此添加额外的初始化代码
	try
	{
		m_MainViewctr.GetObjectPointer();
	}
	catch (CVmException e)
	{}
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

至此,完成环境配置。启动程序,效果如下图所示。
用户可在主界面控件中新建流程,搭建和调试视觉方案。用户可在程序中引用平台库和模块库(查阅VisionMaster4.2.0\Development\V4.x\Documentations中的开发手册查看模块库名称)来实现业务代码开发。
在这里插入图片描述

问题根因
不熟悉基于MFC的VM二次开发环境配置步骤

2.1.3 环境配置:基于Qt二次开发环境配置方法

描述
环境:VM4.2 + Qt5.14
现象:基于Qt如何进行VM二次开发环境配置?
解答
第一步:新建项目。打开QTCreate,编译器推荐选择MSVC2017 64bit。
在这里插入图片描述
在这里插入图片描述

第二步:配置外部库。打开后缀为.pro的文件,在代码区域鼠标右击,选择【添加库】,选择【外部库】,选择VM安装路径下的相关库文件和包含路径, 效果如下图所示。
在这里插入图片描述

为了控件能正常显示,在此代码区域头部添加一句QT +=axcontainer。
第三步:添加控件头文件和源文件。将控件头文件、源文件拷贝到工程目录下(本例为VS2013创建的程序,控件文件路径VisionMaster4.2.0\Development\V4.x\ComControls\Includes\QT),拷贝之后再添加头文件和源文件。
在这里插入图片描述

第四步:添加VM 封装的ActiveX控件,这些控件在VM安装时已经注册,可以直接选择。
在这里插入图片描述

第五步:在程序中包含头文件,并进行控件的初始化。
在这里插入图片描述
在这里插入图片描述

至此,完成环境配置。启动程序,效果如下图所示。 注意加载方案时,在控件上显示方案,则需要在控件初始化前,调用CreateSolutionInstance();
在这里插入图片描述

用户可在主界面控件中新建流程,搭建和调试视觉方案。用户可在程序中引用平台库和模块库(查阅VisionMaster4.2.0\Development\V4.x\Documentations中的开发手册查看模块库名称)来实现业务代码开发。
问题根因
不熟悉基于Qt的VM二次开发环境配置步骤

2.1.4 用户权限:普通以EXE方式启动Server的方法

描述
环境:VM4.2 +VS2013及以上
现象:当客户二次开发程序,需要以Windows普通用户权限调用Vm做视觉处理,需要将Server以EXE方式启动。
解答
1)C#二次开发:修改二次开发程序的xxx.exe.config配置文件,在“AppSettings”里面增加以下两条信息。下图以圆查找demo程序为例。注意“ServerPath”是该电脑上Server的绝对路径,要填正确。
在这里插入图片描述在这里插入图片描述

2)C++二次开发:在所有VM二次开发接口前(如程序的入口处)调用IVmSolution.h文件中的SetServerPath接口,设置服务的绝对路径。
举例:SetServerPath(“C:\Program Files\VisionMaster4.0.0\Applications\Server\VisionMasterServer.exe”);
问题根因
不熟悉普通用户权限二次开发的配置。

2.1.5 环境配置:程序启动后报错的通用方法

描述
环境:VM4.2 + VS2013及以上
现象:二次开发过程中,通常会遇到启动后直接报错VM.Core.xxxx类型初始值设定引发异常,或者启动后控件是黑色,或者模块相关报错,或者启动后加载方案报错,或者获取不到流程列表,或者流程和结果为空等等。
在这里插入图片描述

解答
启动时报错一般时环境问题,启动后的相关报错有可能是环境问题。二次开发,首先要确保代码无误,再从其他角度排查问题。

  1. 确保方案未损坏:VM能正常打开,且能打开方案;
  2. 确保环境配置步骤正确:是否插好加密狗;是否以管理员身份运行VS再打开项目;项目框架是否是4.6.1(4.7或4.8,win10之外其它未作测试可能存在问题),项目属性的32位是否取消勾选;程序启动前关闭VM软件;
  3. 确保dll路径正确:VM4.2SDK开发不需拷贝操作,所以项目exe生成路径无VMSDK的dll;但打完补丁,最好运行下unGAC.bat和GAC.bat;补充:VM4.0SDK开发在打完补丁后,重新拷贝一次;
  4. 确保版本适配:多版本时,方案和程序的升级是否适配当前VM版本和接口函数。
    通用手段:
  5. 在界面拖个显示方案的控件,比如主界面控件(VmMainViewConfigControl),观察方案加载、运行及结果获取;
  6. 使用trycatch捕获异常码,并在手册中查找异常码对应的内容;
    C#
    try{ }catch(VmException ex)
    {MessageBox.Show(Convert.ToString(ex.errorCode, 16));}
    catch(Exception ex)
    {MessageBox.Show(ex.Message.ToString());}
  7. 确保自带的Demo能正常运行,或者在相同的操作下能正常运行;
  8. 程序中使用判空操作;关闭时释放VM资源;断点调试;线程同步异步的概念掌握。
  9. 偶发问题、内存泄漏或崩溃问题,复现问题后,用工具打包日志给研发。
    问题根因
    不熟悉二次开发程序启动后报错排查方法。

2.1.6 VM路径:通过注册表获取VM安装路径的方法

描述
环境:VM4.0及以上 +VS2013及以上
现象:如何后台自动获取VM的安装路径。
解答

C#
//从注册表读取VM安装路径
public string GetVisionMasterInstallPath()
{
    try
    {
        RegistryKey Key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
        RegistryKey myreg = Key.OpenSubKey(@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\VisionMaster_" + "4.2.0", RegistryKeyPermissionCheck.Default,System.Security.AccessControl.RegistryRights.FullControl);
        string VisionMasterInstallPath = myreg.GetValue("DisplayIcon").ToString();
        Key.Close();
        myreg.Close();
        return VisionMasterInstallPath.Replace("Applications\\VisionMaster.exe", ""); ;
    }
    catch (System.Exception ex)
    {
        throw ex;
    }
}     

问题根因
不熟悉如何获取VM注册表路径

2.1.7 第三方库:格式化模块参数配置界面乱码的解决方法

描述
环境:VM4.0+VS2013及以上
现象:二次开发时,格式化配置界面乱码或无法打开脚本,变量计算,全局脚本配置界面。
解答

  1. 查看App.config配置文件,在配置文件中可以看到针对Json库做了版本重定向,统一使用13.0.0.0的版本,这里导致VM中使用Json库时尝试去寻找13.0.0.0导致失败报错。通常是因为VM二次开发时,使用了第三方库(例如HslCommunication.dll),导入了这种配置。VM版本界面默认使用的Json库版本是11.0.0.0。
    在这里插入图片描述

2.解决办法
找寻13.0.0.0版本的Json库拷贝到二次开发的exe的同级目录下,使得VM和第三方库所需要的json都自动引用这个版本的Json库。
问题根因
不熟悉如何解决格式化模块乱码

2.1.8 第三方库:控件与三方样式库冲突问题解决方法

描述
环境:VM4.0及以上 + VS2013及以上
现象:当使用VM进行二次开发时,VM提供的VmMainViewConfigControl控件或VmParamsConfigControl控件与自身引用的第三方MaterialDesign样式库产生冲突,导致VM控件中字体显示异常。
在这里插入图片描述

针对该控件冲突问题,猜测是由于VM的控件中未对其中的TextBox的Fontsize属性进行设置,导致针对整个程序或用户自定义控件引用MaterialDesign样式库时,样式库中的样式覆盖VM控件中相应样式,造成字体显示异常。
解答
针对该问题有以下几种解决方案:
VM修改相关控件的样式以避免冲突。
修改MaterialDesign样式库中相关样式以避免冲突。
修改MaterialDesign样式库的引用方式。
方法1:VM修改相关控件的样式以避免冲突。但是,由于这是三方库与VM控件样式设置不同导致的冲突问题,而不同的三方库可能会引发不同位置的冲突问题,因此该做法无法解决开发者的根本问题。
方法2:对MaterialDesign样式库中的相关样式进行修改以避免与VM控件产生冲突,该方法可以由用户自行修改相应冲突的代码,且不需要更改现有程序,如果能实现,确实不失为一种很好的解决办法。由于MaterialDesign样式库为第三方库,所以使用反编译工具,对该样式库进行反编译,之后找到对应冲突处的代码。找到该样式库下的资源文件夹,找到TextBoxBase样式设置。
在这里插入图片描述

在找到相关的源代码位置后,发现在反编译出来的样式库当中无法对资源文件样式进行修改,所以当前方案行不通。
方法3:改变对MaterialDesign样式库的引用方式,在发现该问题之后,首先想到的其实是更改程序对三方库的引用方式,改变对整个程序引用该三方库,仅在需要使用该样式的自定义用户控件中对该样式库进行引用。然而这样做需要对VM控件及其他控件做隔离处理,对程序改动太大,所以并不实用。
最终解决办法:由于在方法2中已经对MaterialDesign库完成了反编译,且找到了对应的源代码,最终考虑在自定义用户控件中对TextBox的相关样式进行重新定义,覆盖掉MaterialDesign库中引发冲突的部分,最终使该问题成功得到解决。
代码片段:
在这里插入图片描述

这里提供了一种在不对程序进行太大改动的情形下,控件库样式冲突的解决思路。控件库冲突是一种比较常见的问题,在其他客户进行VM SDK开发过程中也同样遇到过类似的问题,使用该方法均可以快速进行问题的定位及解决。
问题根因
不熟悉VM二开过程中,发生样式库冲突的解决方法。

2.1.9 用户日志:用户日志打印的方法

描述
环境:VM4.0+VS2013及以上
现象:VMSDK开发时,如何打印用户日志?
解答
1.配置日志xml,命名为log4Net.config,放在exe的同级目录下。

<?xml version="1.0" encoding="utf-8" ?>

<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>
  
  <log4net>
    <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">	  
      <!--日志路径-->
      <param name= "File" type="log4net.Util.PatternString" value= ".\user\user.log"/>
      <!--是否是向文件中追加日志-->
      <param name= "AppendToFile" value= "true"/>
	    <!--编码-->
	    <param name="Encoding" value="utf-8" />
      <!--log保留天数-->
      <param name= "MaxSizeRollBackups" value= "5"/>
      <!--日志文件名是否是固定不变的-->
      <param name= "StaticLogFileName" value= "false"/>
      <!--日志文件名格式为:2008-08-31.log-->
      <param name= "DatePattern" value= "yyyy-MM-dd&quot;.log&quot;"/>
      <!--日志根据日期滚动-->
      <param name= "RollingStyle" value= "Size"/>
	    <param name="MaximumFileSize" value="10MB"/>
	  	<!--多进程同时写入时加锁-->
	    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <layout type="log4net.Layout.PatternLayout">
        <!-- <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n %loggername" /> -->
		    <!--<conversionPattern value="Time:%date ThreadID:[%thread] Level:%-5level MSG:%message%newlineNUM:%-5L FILE:%F%newline" />-->
		    <conversionPattern value="%date{yyyy-MM-dd HH:mm:ss.fff} %-5level [%thread] [%class::%method@%L] %message%newline%newline" />
      </layout>
	    <filter type="log4net.Filter.LoggerMatchFilter">
        <loggerToMatch value="UserLog" /><!--过滤器-->
      </filter>
      <filter type="log4net.Filter.DenyAllFilter" />
    </appender>

	
    <root>
      <!--(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低) -->
      <level value="info" />
	    <appender-ref ref="RollingLogFileAppender"/> 
	    <appender-ref ref="UserRollingLogFileAppender"/> 
    </root>
  </log4net>
</configuration>

2.生成用户日志类别,读取log4Net.config文件。

using log4net;
using log4net.Appender;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace VMTestB3
{
    public class LogHelper
    {
        public static readonly ILog objLog = null;
        static LogHelper()
        {
            try
            {
                string stmp = Assembly.GetExecutingAssembly().Location;
                stmp = stmp.Substring(0, stmp.LastIndexOf('\\') + 1);
                string path = stmp + "log4Net.config";
                log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(path));
                objLog = log4net.LogManager.GetLogger("UserLog");
            }
            catch (Exception ex)
            {
                //程序异常
            }
        }     
        public void Info(object message)
        {
            objLog?.Info(message);
            //objLog?.Error(message);
        }
    }
}

3.在主函数中进行调用,打印日志到项目生成路径\ user\user.log

LogHelper loguser=new LogHelper();
loguser.Info("加载方案.............................................");
VmSolution.Load(textBoxSolPath.Text, "");

问题根因
不熟悉生成用户日志

2.1.10 环境配置:基于LabView二次开发环境配置方法

描述
环境:VM4.2 +labview2015
现象:基于LabView如何进行VM二次开发环境配置?
解答
1预备知识
在 LabVIEW 中调用第三方库函数,有这么几种方式,如下:
1.1调用库函数方式
在 LabVIEW 的程序面板中,右键选择“互连接口”,接着选择“库与可执行程序”,如下图所示:
在这里插入图片描述

接着选择调用库函数节点,接着右键菜单中选择“配置”,在随后弹出的对话框中, 选择库函数 DLL 所在路径, 选择对应的 DLL , 这里以调用海康渲染库MVRenderPlus.dll 为例,如下图所示:
在这里插入图片描述

选择对应的函数名,配置对应的函数的参数和返回值即可。到这一步就结束了,这种方式的调用适合调用 C/C++编写的独立的动态库,我们 VM 之前的版本,例如VM3.4 用这种方式调用就足够了,只需要选择 imvs6000-PlatformSDK.dll,然后选择对应的 API 函数,比如 LoadSolution 这样的 API,配置好正确的输入参数和返回值就行了。不过这种方式有一个缺憾,就是调用者必须事先对要调用的 SDK 接口有一个比较全面的了解,必须掌握 LabVIEW 编程语言之外的语言,比如掌握了一定的 C 语言编程基础,拿到DLL 文件配套的头文件(.h 文件),对照着头文件配置输入参数和返回值。
1.2使用 ActiveX 容器方式调用
这种方式对遵循 COM 标准编写出来的动态库是很方便的,COM 是微软开发的一套跨语言的二进制调用标准,基于 COM 编写的动态库,不管这个动态库是用什么语言开发的(C++,VB,VB.net,C#, Delphi),都能被其他语言调用(如 Java,Python等),甚至可以在网页上运行。ActiveX 容器的调用如下图所示:
在这里插入图片描述

以调用 VM SDK 中的 VmMainView 控件为例,在 LabVIEW 的 ActiveX 选板中选择“ 打开自动化” ,然 后 再 随 后 弹 出 的 对 话 框 中 , 浏览 , 然后选择VmMainViewControlWinform Version 1.0 ,如下如所示:
在这里插入图片描述

通过选择 VmMainViewControlInterface,来创建控件的引用实例,接着在选板中选择“ 调用节点” , 将引用指向刚才创建的实例, 选择调用方法, 例如调用“GetObjectPointer”, 如下图所示:
在这里插入图片描述

1.3使用.net容器的方式调用
在 Lab VIEW 中通过.net 容器调用第三方库是最简单的方式(当然前提是第三库有.Net 封装),幸运的是,海康机器人的算法平台 SDK 刚好有.net 的封装,使用.net 的封装库,调用者不需要管理内存(绝大多数情况下不需要关心内存的申请和释放),更加激动人心的是,Lab VIEW 开发者调用 VM SDK,是不需要事先了解 SDK 内部 的工作原理,不需要深入理解它的框架,就可以快速开发属于自己的视觉应用。LabVIEW 的.net 容器调用方式如下所示:
在这里插入图片描述

在构造器节点中创建 VMSolution 的实例,接着调用属性节点来操作 VM 的一些常用方法,如加载方案,加载流程,运行方案,运行流程,获取模块结果等等。同时, 由于VM SDK 将方案中的所有模块结果和运行状态都和渲染控件做了数据绑定,也就是模块结果数据发生改变,会立刻在渲染控件上得到呈现,是典型的数据和界面代码分离的一种架构,这种模式对 LabVIEW 开发者很友好,因为 LabVIEW 开发者将不需要调用低级的绘图和像素操作 API(甚至都不需要关注渲染是怎么实现的) 就能将结果呈现给客户。
2遇到的困境
如上所述,使用.net 容器调用VM SDK 是我们推荐的方式,但在具体是操作环节,还是有很多开发者要载跟斗,这里将 LabVIEW 调用 VM4.2(VM4.0 也是差不多的)SDK 遇到的问题描述一下。
困境 1:选择 GAC 列表中的 VM 控件库无反应。
首先,很多开发者是在前面板中,添加了一个.net 容器,然后选择插入.net 控件,如下图所示:
在这里插入图片描述

接着选择 VM SDK 的.net 封装控件,例如 VMControls.Winform.Release.dll,然后展开VMControls.Winform.Release, 选择 VmMainViewConfigControl 控件,如下如图所示:
在这里插入图片描述

选择后按下确定按钮,按下了之后,发现毫无反应,前面板的.net 容器没有任何反应, 无法开展下一步了,很多开发者进行到这一步基本上要打退堂鼓了,毫无头绪啊。
困境 2:尝试加载程序集发生错误。
好,我们继续挣扎一下,我们知道在 VM 的安装目录下,倒是有 VM 控件的DLL,是不是我们不应该选择 GAC(全局程序集缓存)列表中的 VMControls.Winform.Release.dll, 而应该选择 VM 安装目录:
C:\Program Files\VisionMaster4.2.0\Development\V4.x\ComControls\Libraries\win64 下的dll 库呢?我们尝试加载上面目录下的 VMMainViewControlWinform,却又遇到下面的问题,尝试加载程序集时发生错误。
在这里插入图片描述

3解决的办法
首先,好消息是使用.net 容器调用 VM SDK 这条路是行得通的,我们要解决的是,如何正确的加载 VM.Controls.Winform.Release 这个动态库。
上面提到的困境1是因为 LabVIEW 在加载 GAC 中的VM.Controls.Winform.Release.dll 后,接着加载控件 dll,在初始化控件的时候,发生了异常,这个异常被 SDK 捕捉到, 但并未抛出,相当于在 VM SDK 内部是知道发生了异常的,但是没有通知到 LabVIEW, 所以 LabVIEW 无法正确的完成对这个控件的初始化操做的时候,无法向用户传达出这种异常,表现为.net 容器外观未发生任何变化,没有响应。
由于 VM 控件的初始化需要依赖的 DLL 不仅仅是 VM.Controls.Winform.Release,还依赖 VMControls.Interface.dll,VMControls.RenderInterface.dll, VMControls.WPF.dll 等等,因此正确的初始化控件,需要手动做得工作更多。
为了能正确的初始化 VM 控件,我们可以对 VM 控件做一层浅封装,所谓浅封装,就是将 VM 控件做成用户自定义控件的方式,在 LabVIEW 中加载用户自定义控件,这种方式就可以不用 LabVIEW 来自动初始化控件(LabVIEW 会在控件拖动到前面板时自动初始化)。
操作步骤:
第 1 步:将 VM 控件封装成 UserControl。新建一个 C#的用户自定义控件工程,如下图所示,选择 Windows 桌面项目,接着选择 Windows 窗体控件库,需要注意的是, 框架必须选择.NET Framework4.6.1 以上。
在这里插入图片描述

第 2 步:在VS 工具箱中添加 VM 控件到用户窗体上。如下图所示,在 VS 工具箱中,找到VmMainViewConfigControl 控件(选择其他控件也可以,这里只是举例说明 VmMainView 控件如何浅封装,其他控件的封装方法和这个方式是完全一样的)
在这里插入图片描述

将控件拖动到窗体后,有一个需要注意的点,为了保证控件能够主动适应调用它的宿主 窗口和在 LabVIEW 中可以通过拖动鼠标改变大小,应该将控件的 Dock 属性设置为“Fill”, 如下图所示:
在这里插入图片描述

第 3 步:编译工程生成 dll。
在这一步我们只需要编译工程,不需要写一行代码,是的,不要怀疑,就是不需要编写一行代码,按下 CTRL+SHIFT+B 组合键直接编译即可。不过在进行编译之前,我们最好对 UserControl1 做一下重命名,不然生成的控件名称叫做 UserControl1,没有很好指示性,重命名要用右键,不要直接改名。具体做法是:在代码编辑器中对 UserControl1 这个单词按下鼠标右键,在弹出菜单中找到重命名,重命名成你想要的名字。
编译完成后,会在工程所在的 Debug 目录下生成用户控件dll, 默认情况下,VisualStudio会把所有引用到的 dll 都会复制到这个 Debug 目录下,这样,你的工程 Debug 目录下将会产生一堆 dll 文件,所以为了让生成目录看起来干净整洁一些,我们可以对所有引用到的 dll 的引用属性“复制到本地”的属性值设置为“False”(当然,你可以不设置,保持默认的”True”,只是生成的目录下会多出一堆 DLL) 如下图所示:
在这里插入图片描述

这样,在你的工程 Debug 目录下只会产生一个 dll,就是以工程名命名的控件 dll,例如下图所示:
在这里插入图片描述

其中 pdb 文件,是调试信息文件,用来单步调试代码,跟踪断点用的,用户是用不上的,这个在客户机上可以不需要。直接将 VmMainViewControl 拷贝到用户的 LabVIEW 程序所在目录即可。
好了经过上面 3 步,我们再次回到 LabVIEW 中,以.net 容器方式调用 VM 控件,就不会出现上文提到到困境 1 出现的问题。在 LabVIEW 的前面板中,右键菜单“.NET 与ActiveX”菜单项下的子菜单“.NET 容器”,添加一个.NET 容器,然后执行:插入.NET 控件。在随后弹出的窗口中,选择刚才编译好的 VmMainViewControl.dll ,如下图所示:
在这里插入图片描述

选择 UserControl1,按下确定按钮,在前面板中按一下运行按钮,接着激动人心的一面出现了,如下图所示:
在这里插入图片描述

4 VM SDK 非界面控件的封装
界面控件调用问题只是解决了一部分问题,VM SDK 中涉及到的非界面的控制,例如, 加载方案,控制流程运行等等操作,就需要直接调用 VM SDK 的一些 API 函数了,前文我们提到了可以使用调用库函数方式来调用三方库,这种方式对于 VM3.x 版本是完全没问题的,因为整个 VM SDK 从头到尾就依赖一个 imvs6000-platform.dll ,但是到了VM4.x VM 的 SDK 接口已经是完全的面向对象了,VM SDK 已经抽象为 IVMSolution, IVMModule, IVMProcedure 等等一系列的抽象接口,对 VM 的控制被分散在几十个不同模块之中,不再是一个个全局的静态函数, 因此还是需要将 VM SDK 常用方法提取出来, 封装成 C#调用接口。
不过好消息是,我们将 VM SDK 封装,NET 调用接口,仍然是浅封装,因为 VM SDK 本身就有已经开发好的 C#封装接口,我们只需要做浅封装,仅仅是为了让 LabVIEW 能方便的找到依赖。
操作步骤
第 1 步:创建类库工程
新建一个C#的类库工程,类库取个名字叫 VMOperator(名字随便取)如下图所示:
在这里插入图片描述

第 2 步:添加引用
只需要添加两个dll 的引用,一个是 VM.Core, 一个是VM.PlatformSDKCS,并将它们的引用属性“复制到本地”设置为 False, 如下图所示:
在这里插入图片描述

第 3 步:编写类库
这一步是有点代码量的,如果完全不懂 C#编程的,只会 LabVIEW 的编程的同学您还是绕道走吧,找一个会 C#编程的,让其封装一下供你调用。不过这个类库的编写非常的简单,只是简单的将接口再包装一下,有点像将酒厂的原浆倒进自己的瓶子里,就可以号称这个酒是您自己的酿造的(自己不说,旁人还真以为你有酿酒的本事似的)。
这一层的 SDK 封装,我们新建一个VMOperator 类,如下所示:

C#
using System;
using System.Collections.Generic; using System.Linq;
using System.Text;
using System.Threading.Tasks; using VM.Core;
using  VM.PlatformSDKCS; using GlobalVariableModuleCs; 
namespace HIKVMOperator
{
	public class VMOperator
	{
	}
}

接着就是对这个类添加一些和VM 相关的方法来丰富它。所有的方法,我们遵循一个共同的模板,如下,伪代码可以表示为:

int foobar(param1,param2,…)
{
	try
	{
		int ret = vm_sdk_api(param1,pram2,…); return 0;
	}
	catch(VmException ex)
	{
		return ex.ErrorCode;
	}
}

之所以这样写,是为了让调用者在调用的时候知道错误发生的原因,有助于排查问题。按照这种模板,我们将 VM 的常用操作封装如下:
加载方案方法

public static int LoadSolution(string solPath,string password)
{
	try
	{
		VmSolution.Load(solPath, password); return 0;
	}
	catch(VmException ex)
	{
		return ex.errorCode;
	}
}

运行流程方法

public static int RunProcedure(string procedureName)
{
	try
	{
		VmProcedure vmProcedure = VmSolution.Instance[procedureName] as VmProcedure;
		vmProcedure.Run(); 
		return 0;
	}
	catch (VmException ex)
	{
		return ex.errorCode;
	}
}

获取流程配置的输出值

public static int GetProcedureResult(string procedureName,string resultName,ref int resultCount,ref object[] resultVal)
{
	try
	{
		VmProcedure vmProcedure = VmSolution.Instance[procedureName] as VmProcedure;
		if (resultVal.Length > 0)
		{
			if(resultVal[0].GetType()==typeof(float))
			{
				FloatDataArray floatDataArray = vmProcedure.ModuResult.GetOutputFloat(resultName); 
				resultCount = floatDataArray.nValueNum;
				for(int i=0;i< resultCount; i++)
				{
					resultVal[i] = floatDataArray.pFloatVal[i];
				}
			}
			if (resultVal[0].GetType() == typeof(int))
			{
				IntDataArray intDataArray = vmProcedure.ModuResult.GetOutputInt(resultName); resultCount = intDataArray.nValueNum;
				for (int i = 0; i < resultCount; i++)
				{
					resultVal[i] = intDataArray.pIntVal[i];
				}
			}
			if (resultVal[0].GetType() == typeof(string))
			{
				StringDataArray strDataArray = vmProcedure.ModuResult.GetOutputString(resultName); resultCount = strDataArray.nValueNum;
				for (int i = 0; i < resultCount; i++)
				{
					resultVal[i] = strDataArray.astStringVal[i];
				}
			}
		}
		else
		{
			return int.MinValue;
		}
		return 0;
	}
	catch (VmException ex)
	{
	return ex.errorCode;
	}
}

VMOperator的资源释放方法

public static int DestroyInstance()
{
	try
	{
		VmSolution.Instance.Dispose(); 
		return 0;
	}
	catch (VmException ex)
	{
	return ex.errorCode;
	}
}

这里就不贴出全部的封装的接口代码了,总体上还是非常的简单搬运,并不存在复杂的编程逻辑。封装好 VmOperator 类库后,我们就可以使用.NET 容器调用 VmOperator 来实现对VM SDK 的调用了。
第 4 步:在 LabVIEW 中调用封装好的VMOperator 类库
在 LabVIEW 的后置面板中,右键菜单选择“.NET 和 ActiveX”,接着选择“.NET”,拖出一个构造器节点,如下图所示:
在这里插入图片描述

选择我们刚才封装好的 VMOperator 类库。
接着再添加一个调用节点,选择方法,在方法列表中选择想要调用的方法,例如调用加载方案接口,如下图所示:
在这里插入图片描述

5举个例子
经过上面铺垫,对 LabVIEW 调用 VM SDK 遇到的阻碍我们就已经完全攻破了,接着我们举一个实际的例子来演示如何 LabVIEW 中调用 VM SDK,也使这份文档能真正帮助到 LabVIEW 开发者,而不是夸夸其谈,言之无物。
我们要实现一个这样的简单需求
(1)在 LabVIEW 前面板放置一个路径选择按钮,选择方案路径,放置一个方案加载按钮,放置一个方案运行一次按钮,放置一个停止按钮,放置一个 VM MainView 控件,放置一个VM RenderControl 控件
(2)按下路径选择按钮传入路径,按下加载按钮加载选择的方案文件,按下运行按钮运行方案中的流程 1 一次。
(3)方案中的流程 1 运行一次,VM Render 控件渲染流程 1 的运行结果。
(4)VM MainView 控件用来调试流程
根据以上需求,我们在 LabVIEW 的前面板放置几个按钮和相关VM 控件,如下图所示:
在这里插入图片描述

在 LabVIEW 的后置面板,也就是程序编辑区,编写程序框图,我们用顺序结构,顺序结构包含两帧,前一帧在 While 循环中运行程序主干,结束帧用来释放 VmOperator 资源(敲重点:这个非常非常重要!!!,不然你的 LabVIEW 程序分分钟死给你看)。
所以程序框图如下:
加载方案按钮和运行一次按钮用了事件结构,下图是加载方案按钮按下事件响应:
在这里插入图片描述

运行一次按钮的事件响应如下如所示:
在这里插入图片描述

再次强调: 程序的结束帧一定要释放 VMOperator, 也就是调用 VMOperator 的DistoryInstance 方法,如果不释放 VMOperator, LabVIEW 程序会崩溃,同时也会在LabVIEW 程序目录下生成 VM 的 dump 文件。
程序的运行效果,如下图所示:
在这里插入图片描述

6更进一步
既然通过调用封装后的 VMOperator 类库结合 VM 的界面控件就可以在 LabVIEW 中畅行无阻,为什么我们不将 VMOperator 和VM 的界面控件整合在一起作为一个用户控件放在 LabVIEW 中呢?为什么不呢?实在是没有理由让两者分开了,VMOperator 和 VM 界面控件本该就是一个整体, 而不是按照这种割裂开来的方式用, 所以我们将VMOperator 和 VM 界面控件封装成一个用户控件。
操作步骤:
第 1 步:创建窗体控件库工程
新建一个 C#的窗体控件工程,如下图所示:
在这里插入图片描述

第 2 步:设计界面
我们在控件界面上放置一个 VM RenderControl 和几个按钮控件,分别用来加载方案, 运行方案,流程调试按钮(通过按下此按钮进入 VM MainView 界面),模块调试按钮
(通过按下此按钮进入 VM ParamConfigWithRender 界面),然后放置一个流程列表和模块列表,用来显示所有流程和所有模块,加一个流程结果输出显示 List,会枚举出所有配置过的流程输出结果项。基本上这一个控件就包含了百分之 90 以上的 VM 调试场景,足以应付常规应用了。如下图所示:
在这里插入图片描述

第 3 步:代码编写
这部分就是 VMOperator 类库的各种方法的调用,以及界面控件的使用,代码逻辑极其简单,这一步对于熟悉 C#编程和 VM 二次开发的视觉开发者来说,应该说半天时间足以编写完成。这里我就不把全部的代码在这里展示了。
第 4 步:编译生成用户控件 DLL
这一步没啥好说的,编写好代码,按下 CTRL+SHIFT+B 组合键即可,会在工程目录下生成 UserControl1.dll (当然UserControl1 这个名称你可以在工程代码中重构)
第 5 步:在 LabVIEW 中调用
在 LabVIEW 中调用我们使用.NET 容器的方式调用,LabVIEW 的调用代码如下:
在这里插入图片描述

看看,这个程序如此的简洁,这才是正确的使用姿势。好,我们来看看它的运行效果

再看看在这里插入图片描述
程序调试界面
在这里插入图片描述

7总结
通过上面的每一步的解释说明,可以归纳总结以下几个结论
(1)在 LabVIEW 中调用 VM4.x 版本的 SDK 是完全可以做得到的,在 LabVIEW 中使用面向对象的编程方式开发VM 应用是很方便的。
(2)直接使用 VM SDK 提供的 DLL 和控件 DLL,LabVIEW 加载程序集会出错,是因为GAC 并没有把 LabVIEW 需要的基础程序集也加进去,我们可以通过对 VM SDK 做一层简单的浅层封装,用自定义控件和用户自定义库的方式让 LabVIEW 加载可以避免这个问题。
(3)LabVIEW 中调用 VM SDK 时,程序结束时一定要记得释放 VmSoluition 这个全局对象,否则会是使 VM 崩溃从而导致 LabVIEW 这个宿主也跟着崩溃。
(4)在 VS 中将所有VM 控件和 VM 操作 API 封装成一个整体的库,然后在 LabVIEW 中调用,会显著降低 LabVIEW 使用VM SDK 的难度。
(5)图形化编程是 LabVIEW 的突出特点,也是 VM 的突出优点,也是有别于其他机器视觉算法平台之处,LabVIEW 和 VM 混合编程是很好的一种视觉应用开发模式。
问题根因
不熟悉基于Labview二次开发环境配置

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/485998.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于类别级正则化的无监督域自适应眼底图像分割

文章目录 Unsupervised Domain Adaptive Fundus Image Segmentation with Category-Level Regularization摘要方法Inter-domain Category RegularizationSource Domain Category RegularizationTarget Domain Category Regularization总损失 Unsupervised Domain Adaptive Fund…

总结目前敏捷开发框架(持续更新....)

文章目录 0 敏捷开发1 类型分类1.1. Scrum1. 2.极限编程&#xff08;XP&#xff09;1. 3. 快速应用程序开发 (RAD)1. 4. 动态系统开发方法&#xff08;DSDM&#xff09;1.5.统一流程&#xff08;UP&#xff09;1. 6. 精益方法1. 7. 看板1. 8.FDD&#xff08;功能驱动开发&#…

2023年最新版【接口自动化测试,web自动化测试,app自动化测试】全套自动化测试面试题

前言&#xff1a; 自动化测试是软件测试中的一个重要领域&#xff0c;它可以帮助企业提高软件开发质量、缩短测试周期和降低测试成本。随着信息技术的不断发展&#xff0c;自动化测试也在不断地创新和发展。本篇文章收集了2023年最新版的接口自动化测试、Web自动化测试和App自…

通俗理解CNN感受野的计算方法

x o u t x i n − k s 1 x_{out} \frac{x_{in} - k}{s} 1 xout​sxin​−k​1 如果不考虑padding&#xff0c;卷积输出的feature map的计算公式如上&#xff0c;那么 x i n ( x o u t − 1 ) ∗ s k x_{in} (x_{out} - 1) * s k xin​(xout​−1)∗sk。因此计算模型的感…

springbooot使用google验证码

springbooot使用google验证码 1、使用场景2、springboot使用google验证码1、引入依赖2、编写配置类3、编写控制层4、前端实现 1、使用场景 由于需要做一个前后端分离的项目&#xff0c;想着使用google验证码&#xff0c;由于年龄大了&#xff0c;这些知识啊&#xff0c;用完就…

防伪标志使用的全息薄膜,竟可合成大自然的“结构色”

大自然为生物赋予了各种各样的色彩&#xff0c;除了常见的赤橙黄绿青蓝紫外&#xff0c;还有反光效果很好的金属色等等。有趣的是&#xff0c;一些生物身上的颜色也能像金属那样闪闪发光&#xff0c;在不同光线下颜色甚至还会有变化。实际上&#xff0c;大自然很多色彩由色素产…

全注解下的SpringIoc 续6-多环境配置

我们都知道&#xff0c;在企业开发过程中&#xff0c;一个项目往往都会有开发、测试、仿真、生产等环境配置&#xff0c;除了使用配置中心&#xff08;比如Apollo等&#xff09;之外&#xff0c;Spring Boot也提供了不同环境之间切换的机制&#xff0c;下面让我们来一起看看。 …

Docker安全最佳实践

目录 1、探测容器开放端口和服务漏洞 2、宿主机、网络、镜像、DockerApi安全 3、更新Docker、日志、事件 4、Docker安全测试 5、Docker安全最佳实践 1、探测容器开放端口和服务漏洞 使用Nmap扫描Docker容器中的开放端口 使用docker ps命令获取正在运行的容器ID或名称。在…

密码学作业——置换密码部分

part1: encrypt加密函数_代码补充&#xff1a; /*请在此处添加*/cout<<Substition[plain[i]]; part2:Decrypt解密函数_代码补充: /*请在此处添加代码*/ cout<<ReverseTable[cipher[i]];part3:设置 转换表Substition[]部分: // 将i对应的置换表元素设为s1中对应…

prometheus实战之三:告警规则

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 本篇概览 本文是《prometheus实战》系列的第三篇&#xff0c;一起来学习prometheus的告警功能&#xff0c;如下图所示&#xff0c;整个告警功能分为规则和通…

Python使用AI animegan2-pytorch制作属于你的漫画头像/风景图片

Python使用AI animegan2-pytorch制作属于你的漫画头像 1. 效果图2. 原理3. 源码参考 git clone https://github.com/bryandlee/animegan2-pytorch cd ./animegan2-pytorch python test.py --photo_path images/photo_test.jpg --save_path images/animegan2_result.png1. 效果图…

全球首个机器人辅助试管婴儿降生

近日&#xff0c;两名通过机器人辅助受精手术成功诞生的女婴成为全球瞩目的焦点。这是全球首批由机器人成功辅助受精的婴儿案例&#xff0c;预示着未来生育技术的发展趋势。 以往&#xff0c;试管婴儿受精过程中将精子注入卵子内的环节都是由人工完成。胚胎技术人员需要在显微镜…

最简单的循环

☃️个人主页&#xff1a;fighting小泽 &#x1f338;作者简介&#xff1a;目前正在学习C语言和数据结构 &#x1f33c;博客专栏&#xff1a;C语言学习 &#x1f3f5;️欢迎关注&#xff1a;评论&#x1f44a;&#x1f3fb;点赞&#x1f44d;&#x1f3fb;留言&#x1f4aa;&am…

6. Docker——详说镜像

本章讲解知识点 Docker 镜像 Union File System&#xff08;联合文件系统&#xff09;技术 回说 Docker 镜像分层 Docker 镜像分层原理 1. Docker 镜像 镜像是一种轻量级、可执行的独立软件包&#xff0c;用来打包软件运行环境和基于运行环境开发的软件&#xff0c;它包含…

一文了解 Zebec Labs 投资的 Coral Finance,空投计划或在不久推出

在前不久&#xff0c;Zebec Labs 宣布对链上衍生品协议 Coral Finance 进行150万美元的投资&#xff0c;以帮助该协议完成早期启动并&#xff0c;并在后续持续的为其提供孵化支持。Coral Finance 将在不久部署在 Nautilus Chain 主网上。据了解&#xff0c;Coral Finance 是 Na…

【VM服务管家】VM4.2平台SDK_6.2 模块操作类

目录 2.2.1 流程操作&#xff1a;通过流程或Group设置输入输出图像的方法2.2.2 模块操作&#xff1a;设置输入图像、参数和ROI2.2.3 N点标定&#xff1a;清空标定点、生成标定文件2.2.4 分支字符&#xff1a;控制调试模式开关的方法2.2.5 条件检测&#xff1a;条件检测模块设置…

【GAMES101】02 Review Of Linear Algebra

1.点乘&#xff1a; 向量点乘 → 一个数值 点乘在图形学中的应用&#xff1a; 找到两个方向之间的夹角。找到一个向量投影到另一个向量上是什么样的。计算两个向量的方向&#xff08;是接近还是远离&#xff09;判定高光范围&#xff0c;从1&#xff08;重合&#xff…

【VM服务管家】VM4.2平台SDK_6.5 全局类

目录 2.5.1 全局相机&#xff1a;获取全局相机列表和设置相机参数的方法 2.5.1 全局相机&#xff1a;获取全局相机列表和设置相机参数的方法 描述 环境&#xff1a;VM4.2 VS2013及以上 问题&#xff1a;问题1&#xff1a;如何获取方案中所有的全局相机的连接状态&#xff0c;…

c++基础-分支语句

目录 if语句 if-else switch语句 if语句 在C中&#xff0c;if语句是一种分支结构&#xff0c;它允许程序根据条件执行不同的操作。可以使用if语句来检查一个条件是否为真&#xff0c;如果为真就执行一个语句块&#xff0c;否则执行另一个语句块。 if语句的语法如下&#xff…

自媒体平台图文创作建议和技巧

自媒体博主在自媒体平台进行图文创作时&#xff0c;需要注意哪些方面才能创造出更好的内容获得更多的关注呢&#xff1f;今天跟大家分享自媒体创作中的一些图文创作建议和技巧。 一、确定目标受众 首先需要明确自己要传达的信息和目标受众。要考虑读者的兴趣、需求和阅读习惯&…