描述
环境: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二次开发环境配置步骤
描述
环境: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二次开发环境配置步骤
描述
环境: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二次开发环境配置步骤
描述
环境: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”);
问题根因
不熟悉普通用户权限二次开发的配置。
描述
环境:VM4.2 + VS2013及以上
现象:二次开发过程中,通常会遇到启动后直接报错VM.Core.xxxx类型初始值设定引发异常,或者启动后控件是黑色,或者模块相关报错,或者启动后加载方案报错,或者获取不到流程列表,或者流程和结果为空等等。
解答
启动时报错一般时环境问题,启动后的相关报错有可能是环境问题。二次开发,首先要确保代码无误,再从其他角度排查问题。
描述
环境: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注册表路径
描述
环境:VM4.0+VS2013及以上
现象:二次开发时,格式化配置界面乱码或无法打开脚本,变量计算,全局脚本配置界面。
解答
2.解决办法
找寻13.0.0.0版本的Json库拷贝到二次开发的exe的同级目录下,使得VM和第三方库所需要的json都自动引用这个版本的Json库。
问题根因
不熟悉如何解决格式化模块乱码
描述
环境: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二开过程中,发生样式库冲突的解决方法。
描述
环境:VM4.0+VS2013及以上
现象:VMSDK开发时,如何打印用户日志?
解答
1.配置日志xml,命名为log4Net.config,放在exe的同级目录下。
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, "");
问题根因
不熟悉生成用户日志
描述
环境: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二次开发环境配置