C#,Winform,VM联合开发,VM上位机案例全讲解。

up主我自己已经时隔快半年没有发过文章了。主要是前段时间在某国企整车厂实习,然后同时了也是在找工作。因为up主是个本科,而且学校很垃圾,而且还是机械转行干计算机的,路程非常的坎坷,还好前段时间签约了,国内某头部智能装备公司。秋招很难,但是结局还是好的,恰好我实习研究了很多天的VM的案例,主要是考核要求有个仿写VM上位机的内容。这段学习过程让我受益匪浅,我也在这里记录我学习的过程,与大家共同分享。如有错误的地方还请大家多多包涵和指出。
照往常一样,先上代码和案例,然后可以调整我的另一篇博客进行参考我仿写的上位机。

在这里插入图片描述
这张图是VM的样例参考图,其中包含了我们后面会用到的很多关于上位机的主要内容,一个就是图像显示,内容表的打印,单步执行,加载方案和句柄等等内容。后面我会对VM的案例代码进行一个注释性的讲解,比较的详细,大家在使用的使用可以直接参考复制粘贴即可。但是呢,还是推荐大家作为初学者,了解上位机如何开发的一个好渠道(要是我当初在学校能学到该多好)。
下面附上我带部分注释的案例代码
总体来说案例不会很难,核心要义在于如何调用回调函数和仿写获取模块的结果。
由于我发现我的篇幅实在太长了,所以我会另外在写一篇博客来记录我仿写的VM的上位机。中关于仿写VM模块回调的方法我也会在另起一篇博客。
大家可以在后面直接查看我的博客文章即可。0
大家在学习VM的案例的时候主要需要把握的重点有:流程的ID号,如何仿写模块的回调,单步运行函数,和绘制图像(但是绘制图像时根据VM自己的绘制图像接口进行调用,尚在研究状态)。
我已经把重点内容直接注释到函数对应的模块中了。

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using iMVS_6000PlatformSDKCS;
using FrontedUI;

namespace iMVS_6000PlatformSDKDemo_CS
{
    public partial class PlatformSDKForm : Form
    {
        // 全局变量定义
        public IntPtr m_handle            = IntPtr.Zero;                                   // SDK4Server句柄
        List<string>  arrayParamVal       = new List<string>();                            // 参数列表对应值
        private delegateOutputCallBack PlatformInfoCallBack;                               // 回调函数委托  
        public uint   m_nContinStatus     = 9999;                                          // 连续运行状态值
        public uint   m_nStopStatus       = 9999;                                          // 停止运行状态值
        public uint   m_nWorkStatus       = 9999;                                          // 流程工作状态值
        public uint   m_nModuHbID         = 9999;                                          // 模块心跳异常状态值
        public uint   m_nServerHbStatus   = 9999;                                          // 服务心跳异常状态值
        public uint   m_nClientHbStatus   = 9999;                                          // 界面心跳异常状态值
        public uint   m_nDongleStatus     = 9999;                                          // 加密狗异常状态值
        public uint   m_nShowCallbackFlag = 0;                                             // 显示回调内容标志位
        public uint   m_nFrontedFlag      = 0;                                             // 嵌入前端运行界面标志位
        //流程显示ID初始化值,这个在我们后续的用法中可以多多留意这个变量
        //在VM的项目流程中,一个项目包含多个流程,每个流程在VM中都会有一个预先的编号
        //例如我在VM里面写流程的时候会显示流程0流程1这样子
        //走到上位机中,由于VM特有的程序,所以流程ID会变成10000和10001.对应的是流程0和流程1
        //因为在上位机中,我们不会像案例一样去用下拉选项的形式去选取流程,而是直接访问流程ID号的形式
        //这样子我们可以调用流程ID号去使用流程。有时候你的项目可能会包含多个流程的时候就可以使用了
        public int    m_nShowProcessID    = 0;                                             // 显示用流程ID
        public uint   m_nProgressFlag     = 0;                                             // 显示加载或保存进度标志位

        public bool   m_isBegin;    //流程开始标记

        public enum ParamTypeEnum
        {
            IntType = 1,
            FloatType,
            StringType,
            ImageType,
            ChunkType
        }

        //圆
        float radius = float.NaN;
        float centerx = float.NaN;
        float centery = float.NaN;

        //图像
        ImageData imageData = new ImageData();
        byte[] imagebytes;

        //轮廓点
        float[] EdgePointX;
        float[] EdgePointY;


        //匹配框
        float[] MatchBoxCenterX;
        float[] MatchBoxCenterY;
        float[] MatchBoxWidth;
        float[] MatchBoxHeight;
        float[] MatchBoxAngle;

        //匹配点
        float[] MatchPointX;
        float[] MatchPointY;

        //匹配轮廓信息
        ImvsSdkPFDefine.IMVS_PATMATCH_POINT_INFO[] outLinePointInfo;

        public PictureBox curPictureBox { get; set; }

        public PlatformSDKForm()
        {
            InitializeComponent();
            curPictureBox = pictureBoxImg;
        }

        private void PlatformSDKForm_Load(object sender, EventArgs e)
        {
            // 导入数据类型
            comboBoxImportDataType.Items.Add("Template");
            comboBoxImportDataType.Items.Add("Font");
            comboBoxImportDataType.Items.Add("Calibration");
            comboBoxImportDataType.Items.Add("DLModel");
            comboBoxImportDataType.Items.Add("Image");
			comboBoxImportDataType.Items.Add("MarkInsp");
            comboBoxImportDataType.Items.Add("EdgeFlaw");
            comboBoxImportDataType.SelectedIndex = 0;

            // 进度条设置
            progressBarSaveAndLoad.Value   = 0;
            progressBarSaveAndLoad.Maximum = 100;

            // 显示隐藏
            comboBoxShowAndHide.Items.Add("隐藏");
            comboBoxShowAndHide.Items.Add("显示");
            comboBoxShowAndHide.SelectedIndex = 1;

            // 消除ListBox在回调中使用产生警告
            ListBox.CheckForIllegalCrossThreadCalls = false;

            // 显示版本号
            //string strVersion = ImvsPlatformSDK_API.IMVS_PF_GetBuildVersion_CS();
            //labelVersion.Text = strVersion;
            labelVersion.Text = "版本号";
        }
        //以上的内容都是初始化变量
        /****************************************************************************
         * @fn           退出程序
         ****************************************************************************/
        private void PlatformSDKForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            int nRet = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;//将nret置为溢出值
            new Thread(new ThreadStart(delegate              // 开辟线程关闭, 防止主线程连续运行时阻塞
            {
                if (IntPtr.Zero != m_handle)
                {
                    nRet = ImvsPlatformSDK_API.IMVS_PF_CloseVisionMaster_CS(m_handle);
                    Thread.Sleep(100);
                }
                if (IntPtr.Zero != m_handle)
                {
                    nRet = ImvsPlatformSDK_API.IMVS_PF_DestroyHandle_CS(m_handle);
                    m_handle = IntPtr.Zero;
                }

                e.Cancel = false;
                Environment.Exit(0);
            })) { IsBackground = true }.Start();

            e.Cancel = true;
        }

        /****************************************************************************
         * @fn           获取字符串中的数据
         ****************************************************************************/
        public static uint GetNumberUint(string strInput)
        {
            //一下内容是一个整体,我们在开发上位机的时候,如果我们不能用ID来代表的话
            //我们可以使用这个字符串的数据提取到数字转换为decimal类型
            //这个就是用在我们获取流程ID的上面的数字,用来获取到流程ID,就是我上面说的ID号
            uint nRes = 0;
            if (strInput != null && strInput != string.Empty)
            {
                string strNum = strInput;
                int nIndex = strInput.IndexOf("(");
                if (nIndex > 0)
                {
                    strNum = strInput.Substring(0, nIndex);
                }

                // 正则表达式剔除非数字字符(不包含小数点.)
                strNum = Regex.Replace(strNum, @"[^\d.\d]", "");

                // 如果是数字,则转换为decimal类型
                if (Regex.IsMatch(strNum, @"^[+-]?\d*[.]?\d*$"))
                {
                    nRes = uint.Parse(strNum);
                }
            }
            return nRes;
        }

        /****************************************************************************
         * @fn           选择算法平台路径
         ****************************************************************************/
        private void buttonChoseVMPath_Click(object sender, EventArgs e)
        {
            //实现打开文件夹,然后将路径加载到textBoxVMPath.Text变量中去
            //如果我们自己开发上位机,就可以访问项目文件夹,做一个相对路径的访问。
            OpenFileDialog openVMDialog = new OpenFileDialog();
            openVMDialog.Filter = "可执行文件|*.exe*";
            DialogResult openVMRes = openVMDialog.ShowDialog();
            if (DialogResult.OK == openVMRes)
            {
                textBoxVMPath.Text = openVMDialog.FileName;
            }
        }

        /****************************************************************************
         * @fn           显示/隐藏回调信息
         ****************************************************************************/
        private void buttonShowCallBackRes_Click(object sender, EventArgs e)
        {
            //这部分是为了在窗口上打印回调函数的信息
            //一般来说没什么用处,在开发的初级阶段会用到
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("回调未开始!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            if (0 == m_nShowCallbackFlag)
            {
                m_nShowCallbackFlag = 1;
                string strButtonName = this.buttonShowCallBackRes.Text;
                this.buttonShowCallBackRes.Text = ((strButtonName == "显示回调结果") ? "停止显示回调结果" : "显示回调结果");
            }
            else if (1 == m_nShowCallbackFlag)
            {
                m_nShowCallbackFlag = 0;
                string strButtonName = this.buttonShowCallBackRes.Text;
                this.buttonShowCallBackRes.Text = ((strButtonName == "显示回调结果") ? "停止显示回调结果" : "显示回调结果");
            }
        }

        /****************************************************************************
         * @fn           显示/隐藏回调信息实现函数
         ****************************************************************************/
        private void callbackInfo_Show()
        {
            //在窗口的listbox上面打印信息,用于在调试的时候显示,你的模块有没有被调用
            string strMsg = null;

            if (9999 != m_nContinStatus)
            {
                strMsg = "Continue execute status: " + Convert.ToString(m_nContinStatus);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            }
            if (9999 != m_nStopStatus)
            {
                strMsg = "Stop execute status: " + Convert.ToString(m_nStopStatus);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            }
            if (9999 != m_nWorkStatus)
            {
                strMsg = "Work status: " + Convert.ToString(m_nWorkStatus);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            }
            if (9999 != m_nModuHbID)
            {
                strMsg = "Module HB status: " + Convert.ToString(m_nModuHbID);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            }
            if (9999 != m_nServerHbStatus)
            {
                strMsg = "Server HB status: " + Convert.ToString(m_nServerHbStatus);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            }
            if (9999 != m_nClientHbStatus)
            {
                strMsg = "Client HB status: " + Convert.ToString(m_nClientHbStatus);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            }
            if (9999 != m_nDongleStatus)
            {
                strMsg = "Dongle status: " + Convert.ToString(m_nDongleStatus);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            }
        }
        
        /****************************************************************************
         * @fn           回调结果数据
         ****************************************************************************/
        public void delegateOutputCallBackFunc(IntPtr pInputStruct, IntPtr pUser)
        {
            //这个函数会经常的被调用,他调用是通过对识别到流程的ID号码进行匹配调用的
            //m_nShowProcessID,这个是我们要了解到的流程ID号的变量,当变量与resModuInfo.nProcessID相等时,就会开始回调结果数据进行运行
            //我们在开发VM的上位机的时候也可以通过同样的方式进行调用
            //同时我们在回调结果数据的信息的时候,也会根据我们是不是在当前的流程ID号下面进行对图像的绘制
            //回调信息转换
            ImvsSdkPFDefine.IMVS_PF_OUTPUT_PLATFORM_INFO struInfo = (ImvsSdkPFDefine.IMVS_PF_OUTPUT_PLATFORM_INFO)Marshal.PtrToStructure(pInputStruct, typeof(ImvsSdkPFDefine.IMVS_PF_OUTPUT_PLATFORM_INFO));
            switch (struInfo.nInfoType)
            {

                // 回调模块结果信息
                case (uint)ImvsSdkPFDefine.IMVS_CTRLC_OUTPUT_PlATFORM_INFO_TYPE.IMVS_ENUM_CTRLC_OUTPUT_PLATFORM_INFO_MODULE_RESULT:
                    {
                        // ImvsSdkPFDefine.IMVS_PF_MODULE_RESULT_INFO_LIST resultInfo = (ImvsSdkPFDefine.IMVS_PF_MODULE_RESULT_INFO_LIST)Marshal.PtrToStructure(struInfo.pData, typeof(ImvsSdkPFDefine.IMVS_PF_MODULE_RESULT_INFO_LIST));
                        // if (m_nShowProcessID == resultInfo.nProcessID)
                        // {
                        //     UpdateDataResutExOutput(resultInfo);
                        // }

                        ImvsSdkPFDefine.IMVS_PF_MODU_RES_INFO resModuInfo = (ImvsSdkPFDefine.IMVS_PF_MODU_RES_INFO)Marshal.PtrToStructure(struInfo.pData, typeof(ImvsSdkPFDefine.IMVS_PF_MODU_RES_INFO));
                        if ((m_nShowProcessID == resModuInfo.nProcessID) && (0 == m_nProgressFlag))
                        {
                            UpdateDataModuResutOutput(resModuInfo);
                        }

                        break;
                    }

                // 回调流程工作状态信息
                case (uint)ImvsSdkPFDefine.IMVS_CTRLC_OUTPUT_PlATFORM_INFO_TYPE.IMVS_ENUM_CTRLC_OUTPUT_PLATFORM_INFO_WORK_STATE:
                    {
                        ImvsSdkPFDefine.IMVS_PF_MODULE_WORK_STAUS stWorkStatus = (ImvsSdkPFDefine.IMVS_PF_MODULE_WORK_STAUS)Marshal.PtrToStructure(struInfo.pData, typeof(ImvsSdkPFDefine.IMVS_PF_MODULE_WORK_STAUS));
                        m_nWorkStatus = stWorkStatus.nWorkStatus;

                        if ((m_nShowProcessID == stWorkStatus.nProcessID) && (0 == m_nProgressFlag))
                        {
                            SetTitleBarStatus(stWorkStatus);
                        }

                        break;
                    }

                default:
                    {
                        break;
                    }
            }

            if ((m_nShowCallbackFlag == 1) && (0 == m_nProgressFlag))
            {
                callbackInfo_Show();
            }
        }

        /****************************************************************************
         * @fn           接收回调结果数据
         ****************************************************************************/
        internal void UpdateDataResutExOutput(ImvsSdkPFDefine.IMVS_PF_MODULE_RESULT_INFO_LIST struResultInfo)
        {
            //我们在回调结束后,我们就可以在这里仿写一部分我们需要输出的数据
            //在我们运行的时候,系统会自动进入函数进行获取,
            //这部分我们主要还是用于对绘制图像的标准点进行绘制,绘制前需要回去的函数我们就会这里获取到
            if (curPictureBox != null)
            {
                for (int i = 0; i < struResultInfo.nResultNum; i++)
                {
                    switch (struResultInfo.pstModuResInfo[i].nParamType)
                    {
                        case (int)ParamTypeEnum.IntType:
                            switch (struResultInfo.pstModuResInfo[i].strParamName)
                            {
                                case "width":
                                    if (struResultInfo.pstModuResInfo[i].nValueNum > 0)
                                    {
                                        imageData.Width = struResultInfo.pstModuResInfo[i].pIntValue[0];
                                    }
                                    break;
                                case "height":
                                    if (struResultInfo.pstModuResInfo[i].nValueNum > 0)
                                    {
                                        imageData.Height = struResultInfo.pstModuResInfo[i].pIntValue[0];
                                    }
                                    break;
                            }
                            break;
                        case (int)ParamTypeEnum.FloatType:
                            switch (struResultInfo.pstModuResInfo[i].strParamName)
                            {
                                case "radius":
                                    if (struResultInfo.pstModuResInfo[i].nValueNum > 0)
                                    {
                                        radius = struResultInfo.pstModuResInfo[i].pFloatValue[0];
                                    }
                                    break;
                                case "centerx":
                                    if (struResultInfo.pstModuResInfo[i].nValueNum > 0)
                                    {
                                        centerx = struResultInfo.pstModuResInfo[i].pFloatValue[0];
                                    }
                                    break;
                                case "centery":
                                    if (struResultInfo.pstModuResInfo[i].nValueNum > 0)
                                    {
                                        centery = struResultInfo.pstModuResInfo[i].pFloatValue[0];
                                    }
                                    break;
                                case "MatchOutlineX":
                                    if (struResultInfo.pstModuResInfo[i].nValueNum > 0)
                                    {
                                        EdgePointX = new float[struResultInfo.pstModuResInfo[i].nValueNum];
                                        Array.Copy(struResultInfo.pstModuResInfo[i].pFloatValue, EdgePointX, struResultInfo.pstModuResInfo[i].nValueNum);
                                    }
                                    break;
                                case "MatchOutlineY":
                                    if (struResultInfo.pstModuResInfo[i].nValueNum > 0)
                                    {
                                        EdgePointY = new float[struResultInfo.pstModuResInfo[i].nValueNum];
                                        Array.Copy(struResultInfo.pstModuResInfo[i].pFloatValue, EdgePointY, struResultInfo.pstModuResInfo[i].nValueNum);
                                    }
                                    break;
                                case "MatchBoxCenterX":
                                    if (struResultInfo.pstModuResInfo[i].nValueNum > 0)
                                    {
                                        MatchBoxCenterX = new float[struResultInfo.pstModuResInfo[i].nValueNum];
                                        Array.Copy(struResultInfo.pstModuResInfo[i].pFloatValue, MatchBoxCenterX, struResultInfo.pstModuResInfo[i].nValueNum);
                                    }
                                    break;
                                case "MatchBoxCenterY":
                                    if (struResultInfo.pstModuResInfo[i].nValueNum > 0)
                                    {
                                        MatchBoxCenterY = new float[struResultInfo.pstModuResInfo[i].nValueNum];
                                        Array.Copy(struResultInfo.pstModuResInfo[i].pFloatValue, MatchBoxCenterY, struResultInfo.pstModuResInfo[i].nValueNum);
                                    }
                                    break;
                                case "MatchBoxWidth":
                                    if (struResultInfo.pstModuResInfo[i].nValueNum > 0)
                                    {
                                        MatchBoxWidth = new float[struResultInfo.pstModuResInfo[i].nValueNum];
                                        Array.Copy(struResultInfo.pstModuResInfo[i].pFloatValue, MatchBoxWidth, struResultInfo.pstModuResInfo[i].nValueNum);
                                    }
                                    break;
                                case "MatchBoxHeight":
                                    if (struResultInfo.pstModuResInfo[i].nValueNum > 0)
                                    {
                                        MatchBoxHeight = new float[struResultInfo.pstModuResInfo[i].nValueNum];
                                        Array.Copy(struResultInfo.pstModuResInfo[i].pFloatValue, MatchBoxHeight, struResultInfo.pstModuResInfo[i].nValueNum);
                                    }
                                    break;
                                case "MatchBoxAngle":
                                    if (struResultInfo.pstModuResInfo[i].nValueNum > 0)
                                    {
                                        MatchBoxAngle = new float[struResultInfo.pstModuResInfo[i].nValueNum];
                                        Array.Copy(struResultInfo.pstModuResInfo[i].pFloatValue, MatchBoxAngle, struResultInfo.pstModuResInfo[i].nValueNum);
                                    }
                                    break;
                                case "MatchPointX":
                                    if (struResultInfo.pstModuResInfo[i].nValueNum > 0)
                                    {
                                        MatchPointX = new float[struResultInfo.pstModuResInfo[i].nValueNum];
                                        Array.Copy(struResultInfo.pstModuResInfo[i].pFloatValue, MatchPointX, struResultInfo.pstModuResInfo[i].nValueNum);
                                    }
                                    break;
                                case "MatchPointY":
                                    if (struResultInfo.pstModuResInfo[i].nValueNum > 0)
                                    {
                                        MatchPointY = new float[struResultInfo.pstModuResInfo[i].nValueNum];
                                        Array.Copy(struResultInfo.pstModuResInfo[i].pFloatValue, MatchPointY, struResultInfo.pstModuResInfo[i].nValueNum);
                                    }
                                    break;
                            }
                            break;
                        case (int)ParamTypeEnum.StringType:
                            break;
                        case (int)ParamTypeEnum.ImageType:
                            if (0 == String.Compare(struResultInfo.pstModuResInfo[i].strParamName, "image"))
                            {
                                if (struResultInfo.pstModuResInfo[i].nValueNum > 0)
                                {
                                    imagebytes = IntPtr2Bytes(struResultInfo.pstModuResInfo[i].pstImageValue[0].pData, (int)struResultInfo.pstModuResInfo[i].pstImageValue[0].nLen);
                                }
                            }
                            break;
                        case (int)ParamTypeEnum.ChunkType:
                            if (0 == String.Compare(struResultInfo.pstModuResInfo[i].strParamName, "MatchOutline"))
                            {
                                if (struResultInfo.pstModuResInfo[i].nValueNum > 0)
                                {
                                    // 匹配轮廓信息
                                    byte[] pointsBytes = IntPtr2Bytes(struResultInfo.pstModuResInfo[i].pstChunkValue[0].pData, (int)struResultInfo.pstModuResInfo[i].pstChunkValue[0].nLen);
                                    const int singlePointInfoLen = 16;
                                    int pointNum = pointsBytes.Length / singlePointInfoLen;
                                    IntPtr structPtr = Marshal.AllocHGlobal(singlePointInfoLen);
                                    int curPointIndex = 0;
                                    for (int j = 0; j < pointsBytes.Length; j += singlePointInfoLen)
                                    {
                                        Marshal.Copy(pointsBytes, j, structPtr, 16);
                                        outLinePointInfo[curPointIndex] = (ImvsSdkPFDefine.IMVS_PATMATCH_POINT_INFO)Marshal.PtrToStructure(structPtr, typeof(ImvsSdkPFDefine.IMVS_PATMATCH_POINT_INFO));
                                        curPointIndex++;
                                    }
                                    Marshal.FreeHGlobal(structPtr);
                                }
                            }
                            break;

                        default: break;
                    }
                }
            }
        }

        /****************************************************************************
         * @fn           接收回调结果数据(模块结果)
         ****************************************************************************/
        internal void UpdateDataModuResutOutput(ImvsSdkPFDefine.IMVS_PF_MODU_RES_INFO struResultInfo)
        {
            //接受回调结果的数据,是针对模块的进行回调的
            //视觉的核心内容就是做图像处理并输出数据,一般我们会输出坐标,是否NG,图像形状代号,颜色代号等
            //我们需要的出数据的时候,就需要从接受到回调函数的结果模块来进行输出。
            //例如我们在VM中写好的流程,我们在调用流程的时候,可以对流程中的模块进行仿写
            //像我们可以对VM的圆查找进行输出坐标数据,那么我们可以通过仿写下面的内容进行数据的调用
            //具体在外面会写一个如何通过VM的帮助文档仿写一个模块的调用
            if (curPictureBox != null)
            {
                if (null == struResultInfo.pData)
                {
                    return;
                }

                switch (struResultInfo.strModuleName)
                {
                    case ImvsSdkPFDefine.MODU_NAME_LOCALIMAGEVIEW:
                        ImvsSdkPFDefine.IMVS_PF_LOCALIMAGEVIEW_MODU_INFO stLocalImgInfo = (ImvsSdkPFDefine.IMVS_PF_LOCALIMAGEVIEW_MODU_INFO)Marshal.PtrToStructure(struResultInfo.pData, typeof(ImvsSdkPFDefine.IMVS_PF_LOCALIMAGEVIEW_MODU_INFO));
                        imageData.Width = stLocalImgInfo.stImgInfo.iWidth;
                        imageData.Height = stLocalImgInfo.stImgInfo.iHeight;
                        imagebytes = IntPtr2Bytes(stLocalImgInfo.stImgInfo.pImgData, stLocalImgInfo.stImgInfo.iImgDataLen);
                        break;
                    case ImvsSdkPFDefine.MODU_NAME_CAMERAMODULE:
                        ImvsSdkPFDefine.IMVS_PF_CAMERAMODULE_INFO stCameraImgInfo = (ImvsSdkPFDefine.IMVS_PF_CAMERAMODULE_INFO)Marshal.PtrToStructure(struResultInfo.pData, typeof(ImvsSdkPFDefine.IMVS_PF_CAMERAMODULE_INFO));
                        imageData.Width = stCameraImgInfo.stImgInfo.iWidth;
                        imageData.Height = stCameraImgInfo.stImgInfo.iHeight;
                        imagebytes = IntPtr2Bytes(stCameraImgInfo.stImgInfo.pImgData, stCameraImgInfo.stImgInfo.iImgDataLen);
                        break;
                        //圆查找的内容
                    case ImvsSdkPFDefine.MODU_NAME_CIRCLEFINDMODU:
                        ImvsSdkPFDefine.IMVS_PF_CIRCLEFIND_MODU_INFO stCirFindInfo = (ImvsSdkPFDefine.IMVS_PF_CIRCLEFIND_MODU_INFO)Marshal.PtrToStructure(struResultInfo.pData, typeof(ImvsSdkPFDefine.IMVS_PF_CIRCLEFIND_MODU_INFO));
                        radius = stCirFindInfo.fRadius;
                        centerx = stCirFindInfo.stCirPt.fPtX;
                        centery = stCirFindInfo.stCirPt.fPtY;
                        break;
                    case ImvsSdkPFDefine.MODU_NAME_FASTFEATUREMATCHMODU:
                        ImvsSdkPFDefine.IMVS_PF_FASTFEATUREMATCH_MODU_INFO stFeatMatchInfo = (ImvsSdkPFDefine.IMVS_PF_FASTFEATUREMATCH_MODU_INFO)Marshal.PtrToStructure(struResultInfo.pData, typeof(ImvsSdkPFDefine.IMVS_PF_FASTFEATUREMATCH_MODU_INFO));

                        if (stFeatMatchInfo.iMatchNum > 0)
                        {
                            EdgePointX = new float[stFeatMatchInfo.iMatchNum];
                            EdgePointY = new float[stFeatMatchInfo.iMatchNum];
                            MatchBoxCenterX = new float[stFeatMatchInfo.iMatchNum];
                            MatchBoxCenterY = new float[stFeatMatchInfo.iMatchNum];
                            MatchBoxWidth = new float[stFeatMatchInfo.iMatchNum];
                            MatchBoxHeight = new float[stFeatMatchInfo.iMatchNum];
                            MatchBoxAngle = new float[stFeatMatchInfo.iMatchNum];
                            MatchPointX = new float[stFeatMatchInfo.iMatchNum];
                            MatchPointY = new float[stFeatMatchInfo.iMatchNum];

                            for (int i = 0; i < stFeatMatchInfo.iMatchNum; i++)
                            {
                                EdgePointX[i] = stFeatMatchInfo.pstMatchBaseInfo[i].stMatchPt.stMatchPt.fPtX;
                                EdgePointY[i] = stFeatMatchInfo.pstMatchBaseInfo[i].stMatchPt.stMatchPt.fPtY;
                                MatchBoxCenterX[i] = stFeatMatchInfo.pstMatchBaseInfo[i].stMatchBox.stCenterPt.fPtX;
                                MatchBoxCenterY[i] = stFeatMatchInfo.pstMatchBaseInfo[i].stMatchBox.stCenterPt.fPtY;
                                MatchBoxWidth[i] = stFeatMatchInfo.pstMatchBaseInfo[i].stMatchBox.fWidth;
                                MatchBoxHeight[i] = stFeatMatchInfo.pstMatchBaseInfo[i].stMatchBox.fHeight;
                                MatchBoxAngle[i] = stFeatMatchInfo.pstMatchBaseInfo[i].stMatchBox.fAngle;
                                MatchPointX[i] = stFeatMatchInfo.pstMatchBaseInfo[i].stMatchBox.stCenterPt.fPtX;
                                MatchPointY[i] = stFeatMatchInfo.pstMatchBaseInfo[i].stMatchBox.stCenterPt.fPtY;
                            }
                        }       

                        if (stFeatMatchInfo.stMatchConInfo.iPtNum > 0)
                        {
                            outLinePointInfo = new ImvsSdkPFDefine.IMVS_PATMATCH_POINT_INFO[stFeatMatchInfo.stMatchConInfo.iPtNum];
                            outLinePointInfo = stFeatMatchInfo.stMatchConInfo.pstPatMatchPt;
                        }                       
                        break;
                    case ImvsSdkPFDefine.MODU_NAME_HPFEATUREMATCHMODU:
                        ImvsSdkPFDefine.IMVS_PF_HPFEATUREMATCH_MODU_INFO stHpFeatMatchInfo = (ImvsSdkPFDefine.IMVS_PF_HPFEATUREMATCH_MODU_INFO)Marshal.PtrToStructure(struResultInfo.pData, typeof(ImvsSdkPFDefine.IMVS_PF_HPFEATUREMATCH_MODU_INFO));
                        if (stHpFeatMatchInfo.iMatchNum > 0)
                        {
                            EdgePointX = new float[stHpFeatMatchInfo.iMatchNum];
                            EdgePointY = new float[stHpFeatMatchInfo.iMatchNum];
                            MatchBoxCenterX = new float[stHpFeatMatchInfo.iMatchNum];
                            MatchBoxCenterY = new float[stHpFeatMatchInfo.iMatchNum];
                            MatchBoxWidth = new float[stHpFeatMatchInfo.iMatchNum];
                            MatchBoxHeight = new float[stHpFeatMatchInfo.iMatchNum];
                            MatchBoxAngle = new float[stHpFeatMatchInfo.iMatchNum];
                            MatchPointX = new float[stHpFeatMatchInfo.iMatchNum];
                            MatchPointY = new float[stHpFeatMatchInfo.iMatchNum];
                            for (int i = 0; i < stHpFeatMatchInfo.iMatchNum; i++)
                            {
                                EdgePointX[i] = stHpFeatMatchInfo.pstMatchBaseInfo[i].stMatchPt.stMatchPt.fPtX;
                                EdgePointY[i] = stHpFeatMatchInfo.pstMatchBaseInfo[i].stMatchPt.stMatchPt.fPtY;
                                MatchBoxCenterX[i] = stHpFeatMatchInfo.pstMatchBaseInfo[i].stMatchBox.stCenterPt.fPtX;
                                MatchBoxCenterY[i] = stHpFeatMatchInfo.pstMatchBaseInfo[i].stMatchBox.stCenterPt.fPtY;
                                MatchBoxWidth[i] = stHpFeatMatchInfo.pstMatchBaseInfo[i].stMatchBox.fWidth;
                                MatchBoxHeight[i] = stHpFeatMatchInfo.pstMatchBaseInfo[i].stMatchBox.fHeight;
                                MatchBoxAngle[i] = stHpFeatMatchInfo.pstMatchBaseInfo[i].stMatchBox.fAngle;
                                MatchPointX[i] = stHpFeatMatchInfo.pstMatchBaseInfo[i].stMatchBox.stCenterPt.fPtX;
                                MatchPointY[i] = stHpFeatMatchInfo.pstMatchBaseInfo[i].stMatchBox.stCenterPt.fPtY;
                            }
                        }

                        if (stHpFeatMatchInfo.stMatchConInfo.iPtNum > 0)
                        {
                            outLinePointInfo = new ImvsSdkPFDefine.IMVS_PATMATCH_POINT_INFO[stHpFeatMatchInfo.stMatchConInfo.iPtNum];
                            outLinePointInfo = stHpFeatMatchInfo.stMatchConInfo.pstPatMatchPt;
                        }                        
                        break;

                    default: break;
                }
            }
        }

        /****************************************************************************
         * @fn           绘制结果图像及特征
         ****************************************************************************/
        internal void SetTitleBarStatus(iMVS_6000PlatformSDKCS.ImvsSdkPFDefine.IMVS_PF_MODULE_WORK_STAUS statusInfo)
        {
            //流程开始标志 1:开始 0:结束 
            if (0 != statusInfo.nWorkStatus)
            {
                m_isBegin = true;
                InitResultData();
            }
            else if (m_isBegin)
            {
                m_isBegin = false;

                //图像
                if (imageData.Width != 0 && imageData.Height != 0 && imagebytes != null)
                {
                    uint ImageLenth = (uint)(imageData.Width * imageData.Height);
                    if (ImageLenth != imagebytes.Length)
                    {
                        return;
                    }
                    imageData.ImageBuffer = imagebytes;

                    //获取图像数据
                    if (imageData.ImageBuffer != null)
                    {
                        var bmp = imageData.ImageDataToBitmap().GetArgb32BitMap();
                        using (var g = bmp.CreateGraphic())
                        {
                            //画圆
                            if (!float.IsNaN(radius) && !float.IsNaN(centerx) && !float.IsNaN(centery))
                            {
                                g.DrawCircle(Color.GreenYellow, 3, new PointF(centerx, centery), radius);
                                g.DrawPoint(Color.GreenYellow, new PointF(centerx, centery));
                            }

                            //画轮廓点
                            if (EdgePointX != null && EdgePointY != null && EdgePointX.Length == EdgePointY.Length)
                            {
                                for (int i = 0; i < EdgePointX.Length; i++)
                                {
                                    g.DrawPoint(Color.GreenYellow, new PointF(EdgePointX[i], EdgePointY[i]));
                                }
                            }

                            //画匹配框
                            if (MatchBoxCenterX != null && MatchBoxCenterY != null && MatchBoxWidth != null && MatchBoxHeight != null && MatchBoxAngle != null &&
                                MatchBoxCenterX.Length == MatchBoxCenterY.Length && MatchBoxCenterX.Length == MatchBoxWidth.Length && MatchBoxCenterX.Length == MatchBoxHeight.Length && MatchBoxCenterX.Length == MatchBoxAngle.Length)
                            {
                                for (int i = 0; i < MatchBoxCenterX.Length; i++)
                                {
                                    g.DrawRect(Color.GreenYellow, 3, new PointF(MatchBoxCenterX[i], MatchBoxCenterY[i]), MatchBoxWidth[i], MatchBoxHeight[i], MatchBoxAngle[i]);
                                    g.DrawPoint(Color.GreenYellow, new PointF(MatchBoxCenterX[i], MatchBoxCenterY[i]));
                                }
                            }

                            //画匹配点
                            if (MatchPointX != null && MatchPointY != null && MatchPointX.Length == MatchPointY.Length)
                            {
                                for (int i = 0; i < MatchPointX.Length; i++)
                                {
                                    g.DrawPoint(Color.Red, new PointF(MatchPointX[i], MatchPointY[i]));
                                }
                            }

                            //画匹配轮廓点
                            if (outLinePointInfo != null)
                            {
                                for (int k = 0; k < outLinePointInfo.Length; k++)
                                {
                                    g.DrawPoint(Color.GreenYellow, new PointF(outLinePointInfo[k].fMatchOutlineX, outLinePointInfo[k].fMatchOutlineY));
                                }
                            }

                            curPictureBox.Invoke(new Action(() =>
                            {
                                curPictureBox.Image = bmp;
                            }));
                        }
                    }
                }
            }
        }

        /****************************************************************************
       * @fn           初始化结果数据
       ****************************************************************************/
        private void InitResultData()
        {
            radius = float.NaN;
            centerx = float.NaN;
            centery = float.NaN;

            //图像
            imageData = new ImageData();
            imagebytes = null;

            //轮廓点
            EdgePointX = null;
            EdgePointY = null;

            MatchBoxCenterX = null;
            MatchBoxCenterY = null;

            //匹配框
            MatchBoxCenterX = null;
            MatchBoxCenterY = null;
            MatchBoxWidth = null;
            MatchBoxHeight = null;
            MatchBoxAngle = null;

            //匹配点
            MatchPointX = null;
            MatchPointY = null;

            //匹配轮廓信息
            outLinePointInfo = null;
        }

        /****************************************************************************
         * @fn           开启算法平台
         ****************************************************************************/
        private void buttonOpenVM_Click(object sender, EventArgs e)
        {
            uint   nWaitTime = 30000;
            string strMsg    = null;//定义字符串用来输出到listbox,先定义为空值
            //判断是否存在句柄已加载的情况。
            //在我们调试的时候,会多次启动VM进行调试,在调试过程中由于我们没有结束句柄进程
            //所以加入判断条件去判断句柄是否异常状态
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }
            //开启VM。
            //nWaitTime设置加载时间,防止VM加载失败
            string strPlatformPath = textBoxVMPath.Text;//加载VM的路径
            //将句柄写入iRet中用于判断IRet的值来判断是否开启VM
            int iRet = ImvsPlatformSDK_API.IMVS_PF_StartVisionMaster_CS(m_handle, strPlatformPath, nWaitTime);
            if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
            {
                strMsg = "IMVS_PF_StartVisionMaster_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                return;
            }
            strMsg = "IMVS_PF_StartVisionMaster_CS Success.";
            listBoxMsg.Items.Add(strMsg);
            listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;

            // 图像显示部分获取所有流程列表
            //在图像显示哪里有个下拉槽,对应的是那个区域的函数
            Thread.Sleep(800);
            comboBoxShowPicProcessID.Items.Clear();
            ImvsSdkPFDefine.IMVS_PF_PROCESS_INFO_LIST stProcInfoList = new ImvsSdkPFDefine.IMVS_PF_PROCESS_INFO_LIST();
            stProcInfoList.astProcessInfo = new ImvsSdkPFDefine.IMVS_PF_PROCESS_INFO[ImvsSdkPFDefine.IMVS_PF_MAX_PROCESS_NUM];
            iRet = ImvsPlatformSDK_API.IMVS_PF_GetAllProcessList_CS(m_handle, ref stProcInfoList);
            if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
            {
                strMsg = "IMVS_PF_GetAllProcessList_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                return;
            }
            //选取流程ID作为要执行的流程
            int iLop = 0;
            string strShowMsg = null;
            for (iLop = 0; iLop < stProcInfoList.nNum; iLop++)
            {
                strShowMsg = Convert.ToString(stProcInfoList.astProcessInfo[iLop].nProcessID) + " (" + stProcInfoList.astProcessInfo[iLop].strProcessName + ")";
                comboBoxShowPicProcessID.Items.Add(strShowMsg);
            }
            comboBoxShowPicProcessID.SelectedIndex = 0;
        }

        /****************************************************************************
         * @fn           关闭算法平台
         ****************************************************************************/
        private void buttonCloseVM_Click(object sender, EventArgs e)
        {
            new Thread(new ThreadStart(delegate              // 开辟线程关闭, 防止主线程连续运行时阻塞
            {
                string strMsg = null;
                if (IntPtr.Zero == m_handle)
                {
                    MessageBoxButtons msgType = MessageBoxButtons.OK;
                    DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                    if (diagMsg == DialogResult.OK)
                    {
                        return;
                    }
                }

                int iRet = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
                if (1 == m_nFrontedFlag)
                {
                    iRet = ImvsPlatformSDK_API.IMVS_PF_UnAttachFrontedWnd_CS(m_handle, pictureBoxImg.Handle);
                    if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
                    {
                        strMsg = "IMVS_PF_UnAttachFrontedWnd_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                        listBoxMsg.Items.Add(strMsg);
                        listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                    }

                    m_nFrontedFlag = 0;
                    buttonLoadFrontInterface.Text = "载入前端界面";
                }

                iRet = ImvsPlatformSDK_API.IMVS_PF_CloseVisionMaster_CS(m_handle);
                if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
                {
                    strMsg = "IMVS_PF_CloseVisionMaster_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                    listBoxMsg.Items.Add(strMsg);
                    listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                    return;
                }
                strMsg = "IMVS_PF_CloseVisionMaster_CS Success.";
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;

                // 清空流程信息列表
                comboBoxShowPicProcessID.Items.Clear();

                // 清空图像
                curPictureBox.Image = null;
                curPictureBox.Refresh();
            })) { IsBackground = true }.Start();
        }

        /****************************************************************************
         * @fn           显示/隐藏算法平台
         ****************************************************************************/
        private void buttonShowHideVM_Click(object sender, EventArgs e)
        {
            string strMsg = null;
            int iRet = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            uint nCurSel = uint.Parse(comboBoxShowAndHide.SelectedIndex.ToString());
            iRet = ImvsPlatformSDK_API.IMVS_PF_ShowVisionMaster_CS(m_handle, nCurSel);
            if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
            {
                strMsg = "IMVS_PF_ShowVisionMaster_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                return;
            }

            strMsg = "IMVS_PF_ShowVisionMaster_CS Success";
            listBoxMsg.Items.Add(strMsg);
            listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
        }

        /****************************************************************************
         * @fn           下拉显示当前所有模块信息列表
         ****************************************************************************/
        private void comboGetShowModuleID_ComboDropDown(object sender, EventArgs e)
        {
            //当前函数的作用就是通过访问遍历到的流程中的模块
            //将所得出的遍历的模块进行输出到一个下拉框里面
            //由于该程序并没有对下拉的模块选择进行过多的处理,
            //所以这个下拉模块没有用
            //但是可以通过这个函数仿写访问模块
            string strMsg = null;
            int iRet = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            comboBoxShowModuleID.Items.Clear();//清空下拉框
            comboBoxShowModuleID.Text = null;//讲下拉框初始化为空值
            ImvsSdkPFDefine.IMVS_PF_MODULE_INFO_LIST stModuInfoList = new ImvsSdkPFDefine.IMVS_PF_MODULE_INFO_LIST();
            stModuInfoList.astModuleInfo = new ImvsSdkPFDefine.IMVS_PF_MODULE_INFO[ImvsSdkPFDefine.IMVS_PF_MAX_MODULE_NUM];
            //由于默认下拉框的初始值为空值所以会直接执行if的语句
            if (null == comboBoxShowProcessID.SelectedItem)
            {
                iRet = ImvsPlatformSDK_API.IMVS_PF_GetAllModuleList_CS(m_handle, ref stModuInfoList);
                if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
                {
                    strMsg = "IMVS_PF_GetAllModuleList_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                    listBoxMsg.Items.Add(strMsg);
                    listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                    return;
                }
            }
            //当我们有选择下拉框的时候,我们可以通过访问到模块的信息,传入函数中,并执行
            //strSelProcessID获取模块字符串信息
            //nProcID获取模块中的数字,剔除文字
            else
            {
                string strSelProcessID = comboBoxShowProcessID.SelectedItem.ToString();
                uint nProcID = GetNumberUint(strSelProcessID);
                iRet = ImvsPlatformSDK_API.IMVS_PF_GetModulesByProcessId_CS(m_handle, nProcID, ref stModuInfoList);
                if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
                {
                    strMsg = "IMVS_PF_GetModulesByProcessId_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                    listBoxMsg.Items.Add(strMsg);
                    listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                    return;
                }
            }
            //遍历模块信息,将模块信息存储到下拉框里面
            int iLop = 0;
            string strShowMsg = null;
            for (iLop = 0; iLop < stModuInfoList.nNum; iLop++)
            {
                strShowMsg = Convert.ToString(stModuInfoList.astModuleInfo[iLop].nModuleID) + " (" + stModuInfoList.astModuleInfo[iLop].strDisplayName + ")";
                comboBoxShowModuleID.Items.Add(strShowMsg);
            }
            comboBoxShowModuleID.SelectedIndex = 0;

            strMsg = "IMVS_PF_GetAllModuleList_CS Success";
            listBoxMsg.Items.Add(strMsg);
            listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
        }

        /****************************************************************************
         * @fn           显示指定模块输出结果界面
         ****************************************************************************/
        private void buttonShowOneModule_Click(object sender, EventArgs e)
        {
            string strMsg    = null;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            if (null == comboBoxShowModuleID.SelectedItem)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("请先选择模块ID!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }
            //同样获取到模块的名字
            string strSelModuleID = comboBoxShowModuleID.SelectedItem.ToString();
            //获取模块ID
            uint nModuleID = GetNumberUint(strSelModuleID);
            int iRet = ImvsPlatformSDK_API.IMVS_PF_ShowModuleInterface_CS(m_handle, nModuleID);
            if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
            {
                strMsg = "IMVS_PF_ShowModuleInterface_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                return;
            }
            strMsg = "IMVS_PF_ShowModuleInterface_CS Success";
            listBoxMsg.Items.Add(strMsg);
            listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
        }

        /****************************************************************************
         * @fn           限制参数值编辑框输入类型为数字
         ****************************************************************************/
        private void textBoxParamValue_KeyPress(object sender, KeyPressEventArgs e)
        {
            string strParamVal = textBoxParamValue.Text;
            e.Handled = ((e.KeyChar < '0') || (e.KeyChar > '9'));  // 允许输入数字
            if (e.KeyChar == (char)8)                              // 允许输入回退键
            {
                e.Handled = false;
            }
            if (e.KeyChar == (char)46)
            {
                if (strParamVal == "")                             // 第一个不允许输入小数点
                {
                    e.Handled = true;
                    return;
                }
                else
                {                                                  // 小数点不允许出现2次
                    foreach (char ch in strParamVal)
                    {
                        if (char.IsPunctuation(ch))
                        {
                            e.Handled = true;
                            return;
                        }
                    }
                    e.Handled = false;
                }
            }
        }

        /****************************************************************************
         * @fn           设置模块参数值
         ****************************************************************************/
        private void buttonSetParam_Click(object sender, EventArgs e)
        {
            string strMsg = null;
            int    iRet   = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            if (null == comboBoxShowModuleID.SelectedItem)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("请先选择模块ID!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            string strSelModuleID = comboBoxShowModuleID.SelectedItem.ToString();
            uint   nModuID        = GetNumberUint(strSelModuleID);

            if (null == comboBoxParamList.SelectedItem)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("请先获取模块参数列表!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            iRet = ImvsPlatformSDK_API.IMVS_PF_SetParamValue_CS(m_handle, nModuID, comboBoxParamList.SelectedItem.ToString(), textBoxParamValue.Text);
            if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
            {
                strMsg = "IMVS_PF_SetParamValue_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                return;
            }

            strMsg = "IMVS_PF_SetParamValue_CS Success";
            listBoxMsg.Items.Add(strMsg);
            listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
        }

        /****************************************************************************
         * @fn           获取模块参数值
         ****************************************************************************/
        private void buttonGetParam_Click(object sender, EventArgs e)
        {
            string strMsg = null;
            int iRet = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            if (null == comboBoxShowModuleID.SelectedItem)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("请先选择模块ID!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }


            string strSelModuleID = comboBoxShowModuleID.SelectedItem.ToString();
            uint   nModuID        = GetNumberUint(strSelModuleID);

            if (null == comboBoxParamList.SelectedItem)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("请先获取模块参数列表!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            String strParamValue = "";
            String strParamName  = comboBoxParamList.SelectedItem.ToString();
            uint nStrValueSize   = 1024;
            iRet = ImvsPlatformSDK_API.IMVS_PF_GetParamValue_CS(m_handle, nModuID, strParamName, nStrValueSize, ref strParamValue);
            if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
            {
                strMsg = "IMVS_PF_GetParamValue_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                return;
            }
            strMsg = "IMVS_PF_GetParamValue_CS Success";
            listBoxMsg.Items.Add(strMsg);
            listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            if (!(string.IsNullOrEmpty(strParamValue)))
            {
                textBoxParamValue.Text = strParamValue.ToString();
            }
            else
            {
                textBoxParamValue.Clear();
            }
        }

        /****************************************************************************
         * @fn           获取模块参数列表
         ****************************************************************************/
        private void buttonGetParamList_Click(object sender, EventArgs e)
        {
            string strMsg = null;
            int iRet = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            if (null == comboBoxShowModuleID.SelectedItem)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("请先选择模块ID!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            ImvsSdkPFDefine.IMVS_PF_MODULE_PARAM_LIST stModuleParamList = new ImvsSdkPFDefine.IMVS_PF_MODULE_PARAM_LIST();
            stModuleParamList.stModuleParamList = new ImvsSdkPFDefine.IMVS_PF_MODULE_PARAM[ImvsSdkPFDefine.IMVS_PF_MAX_MODULE_PARAM_NUM];

            string strSelModuleID = comboBoxShowModuleID.SelectedItem.ToString();
            uint   nModuID = GetNumberUint(strSelModuleID);
            iRet = ImvsPlatformSDK_API.IMVS_PF_GetParamList_CS(m_handle, nModuID, ref stModuleParamList);
            if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
            {
                strMsg = "IMVS_PF_GetParamList_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                return;
            }

            arrayParamVal.Clear();
            comboBoxParamList.Items.Clear();
            int iLop = 0;
            for (iLop = 0; iLop < stModuleParamList.nParamNum; iLop++)
            {
                comboBoxParamList.Items.Add(stModuleParamList.stModuleParamList[iLop].strParamName);
                arrayParamVal.Add(stModuleParamList.stModuleParamList[iLop].strParamValue);
            }
            comboBoxParamList.SelectedIndex = 0;

            strMsg = "Param number = " + stModuleParamList.nParamNum.ToString();
            listBoxMsg.Items.Add(strMsg);
            listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            strMsg = "IMVS_PF_GetParamList_CS Success";
            listBoxMsg.Items.Add(strMsg);
            listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
        }

        /****************************************************************************
         * @fn           获取下拉列表参数名对应参数值
         ****************************************************************************/
        private void comboGetParamListVal_SelChange(object sender, EventArgs e)
        {
            string strMsg = null;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            int nIndex = comboBoxParamList.SelectedIndex;
            if (nIndex > arrayParamVal.Count)
            {
                strMsg = "Not Execute IMVS_PF_GetParamList_CS.";
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                return;
            }
            textBoxParamValue.Text = arrayParamVal[nIndex];
        }

        /****************************************************************************
         * @fn           选择导入文件路径
         ****************************************************************************/
        private void buttonChoseFilePath_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            DialogResult   openFileRes    = openFileDialog.ShowDialog();
            if (DialogResult.OK == openFileRes)
            {
                textBoxImportFilePath.Text = openFileDialog.FileName;
            }
        }

        /****************************************************************************
         * @fn           向指定模块导入数据
         ****************************************************************************/
        private void buttonImportData_Click(object sender, EventArgs e)
        {
            string strMsg = null;
            int iRet = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            string strImportFilePath = textBoxImportFilePath.Text;
            if ((System.Text.Encoding.Default.GetBytes(strImportFilePath).Length + 1) > ImvsSdkPFDefine.IMVS_PF_MAX_PATH_LENGTH)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("路径长度过长!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            if (null == comboBoxShowModuleID.SelectedItem)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("请先选择模块ID!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            ImvsSdkPFDefine.IMVS_PF_IMPORT_MODULE_DATA_INPUT stImportData = new ImvsSdkPFDefine.IMVS_PF_IMPORT_MODULE_DATA_INPUT();
            stImportData.stImportModuData = new ImvsSdkPFDefine.IMVS_PF_IMPORT_MODULE_DATA[ImvsSdkPFDefine.IMVS_PF_MAX_IMPORT_NUM];
            stImportData.nDataNum  = 1;
            stImportData.nDataType = uint.Parse(comboBoxImportDataType.SelectedIndex.ToString()) + 1;
            string strSelModuleID  = comboBoxShowModuleID.SelectedItem.ToString();
            uint   nModuleID       = GetNumberUint(strSelModuleID);
            stImportData.nModuleID = nModuleID;
            stImportData.stImportModuData[0].pData = Marshal.StringToHGlobalAnsi(strImportFilePath);
            int iDataLen = System.Text.Encoding.Default.GetBytes(strImportFilePath).Length;
            stImportData.stImportModuData[0].nDataLen = (uint)iDataLen;

            iRet = ImvsPlatformSDK_API.IMVS_PF_ImportModuleData_CS(m_handle, stImportData);
            if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
            {
                strMsg = "IMVS_PF_ImportModuleData_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                return;
            }

            strMsg = "IMVS_PF_ImportModuleData_CS success.";
            listBoxMsg.Items.Add(strMsg);
            listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
        }


        /****************************************************************************
         * @fn           执行一次
         ****************************************************************************/
        private void buttonExecuteOnce_Click(object sender, EventArgs e)
        {
            //运行程序
            //也是我们做常用的运行方式,我们可以通过信号的形式直接运行到这个函数

            //将打印的字符串置为空值
            string strMsg = null;
            //讲句柄量置为空值
            int iRet = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }
            //获取流程ID显示
            if (null == comboBoxShowProcessID.SelectedItem)
            {
                iRet = ImvsPlatformSDK_API.IMVS_PF_ExecuteOnce_CS(m_handle, null);
                if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
                {
                    strMsg = "IMVS_PF_ExecuteOnce_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                    listBoxMsg.Items.Add(strMsg);
                    listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                    return;
                }

                strMsg = "IMVS_PF_ExecuteOnce_CS Success";
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            }
            else
            {
                string strSelProcessID = comboBoxShowProcessID.SelectedItem.ToString();
                uint nProcID = GetNumberUint(strSelProcessID);
                iRet = ImvsPlatformSDK_API.IMVS_PF_ExecuteOnce_V30_CS(m_handle, nProcID, null);
                if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
                {
                    strMsg = "IMVS_PF_ExecuteOnce_V30_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                    listBoxMsg.Items.Add(strMsg);
                    listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                    return;
                }

                strMsg = "IMVS_PF_ExecuteOnce_V30_CS Success";
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            }
        }

        /****************************************************************************
         * @fn           停止执行
         ****************************************************************************/
        private void buttonStopExecute_Click(object sender, EventArgs e)
        {
            string strMsg = null;
            int iRet = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            uint nWaitTime = 5000;
            if (null == comboBoxShowProcessID.SelectedItem)
            {
                iRet = ImvsPlatformSDK_API.IMVS_PF_StopExecute_CS(m_handle, nWaitTime);
                if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
                {
                    strMsg = "IMVS_PF_StopExecute_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                    listBoxMsg.Items.Add(strMsg);
                    listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                    return;
                }

                strMsg = "IMVS_PF_StopExecute_CS Success";
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            }
            else
            {
                string strSelProcessID = comboBoxShowProcessID.SelectedItem.ToString();
                uint nProcID = GetNumberUint(strSelProcessID);
                iRet = ImvsPlatformSDK_API.IMVS_PF_StopExecute_V30_CS(m_handle, nProcID, nWaitTime);
                if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
                {
                    strMsg = "IMVS_PF_StopExecute_V30_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                    listBoxMsg.Items.Add(strMsg);
                    listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                    return;
                }

                strMsg = "IMVS_PF_StopExecute_V30_CS Success";
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            }
        }

        /****************************************************************************
         * @fn           限制时间间隔对话框输入类型为数字
         ****************************************************************************/
        private void textBoxTimeInterval_KeyPress(object sender, KeyPressEventArgs e)
        {
            string strParamVal = textBoxTimeInterval.Text;
            e.Handled = ((e.KeyChar < '0') || (e.KeyChar > '9'));  // 允许输入数字
            if (e.KeyChar == (char)8)                              // 允许输入回退键
            {
                e.Handled = false;
            }
            if (e.KeyChar == (char)46)
            {
                if (strParamVal == "")                             // 第一个不允许输入小数点
                {
                    e.Handled = true;
                    return;
                }
                else
                {                                                  // 小数点不允许出现2次
                    foreach (char ch in strParamVal)
                    {
                        if (char.IsPunctuation(ch))
                        {
                            e.Handled = true;
                            return;
                        }
                    }
                    e.Handled = false;
                }
            }
        }

        /****************************************************************************
         * @fn           设置连续执行时间间隔
         ****************************************************************************/
        private void buttonSetTimeInterval_Click(object sender, EventArgs e)
        {
            string strMsg = null;
            int iRet = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            string strTimeInteval = textBoxTimeInterval.Text;
            if (string.IsNullOrEmpty(strTimeInteval))
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("请输入时间间隔!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            uint nTimeInterval = 0;
            nTimeInterval = uint.Parse(strTimeInteval);
            if (null == comboBoxShowProcessID.SelectedItem)
            {
                iRet = ImvsPlatformSDK_API.IMVS_PF_SetContinousExecuteInterval_CS(m_handle, nTimeInterval);
                if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
                {
                    strMsg = "IMVS_PF_SetContinousExecuteInterval_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                    listBoxMsg.Items.Add(strMsg);
                    listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                    return;
                }

                strMsg = "IMVS_PF_SetContinousExecuteInterval_CS Success";
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            }
            else
            {
                string strSelProcessID = comboBoxShowProcessID.SelectedItem.ToString();
                uint nProcID = GetNumberUint(strSelProcessID);
                iRet = ImvsPlatformSDK_API.IMVS_PF_SetContinousExecuteInterval_V30_CS(m_handle, nProcID, nTimeInterval);
                if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
                {
                    strMsg = "IMVS_PF_SetContinousExecuteInterval_V30_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                    listBoxMsg.Items.Add(strMsg);
                    listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                    return;
                }

                strMsg = "IMVS_PF_SetContinousExecuteInterval_V30_CS Success";
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            }
        }

        /****************************************************************************
         * @fn           连续执行
         ****************************************************************************/
        private void buttonContinuExecute_Click(object sender, EventArgs e)
        {
            string strMsg = null;
            int iRet = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            if (null == comboBoxShowProcessID.SelectedItem)
            {
                iRet = ImvsPlatformSDK_API.IMVS_PF_ContinousExecute_CS(m_handle);
                if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
                {
                    strMsg = "IMVS_PF_ContinousExecute_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                    listBoxMsg.Items.Add(strMsg);
                    listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                    return;
                }
                strMsg = "IMVS_PF_ContinousExecute_CS Success";
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            }
            else
            {
                string strSelProcessID = comboBoxShowProcessID.SelectedItem.ToString();
                uint nProcID = GetNumberUint(strSelProcessID);
                iRet = ImvsPlatformSDK_API.IMVS_PF_ContinousExecute_V30_CS(m_handle, nProcID);
                if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
                {
                    strMsg = "IMVS_PF_ContinousExecute_V30_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                    listBoxMsg.Items.Add(strMsg);
                    listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                    return;
                }
                strMsg = "IMVS_PF_ContinousExecute_V30_CS Success";
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            }
        }

        /****************************************************************************
         * @fn           选择方案路径
         ****************************************************************************/
        private void buttonChooseSoluPath_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = "VM方案文件|*.sol*";
            DialogResult openFileRes = openFileDialog.ShowDialog();
            if (DialogResult.OK == openFileRes)
            {
                textBoxSolutionPath.Text = openFileDialog.FileName;
            }
        }

        /****************************************************************************
         * @fn           检查方案密码
         ****************************************************************************/
        private void buttonCheckPassWord_Click(object sender, EventArgs e)
        {
            string strMsg = null;
            int    iRet   = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            uint nHasPassword = 0;
            string strSolutionPath = textBoxSolutionPath.Text;
            iRet = ImvsPlatformSDK_API.IMVS_PF_CheckPassword_CS(m_handle, strSolutionPath, ref nHasPassword);
            if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
            {
                strMsg = "IMVS_PF_CheckPassword_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                return;
            }
            if (nHasPassword == ImvsSdkPFDefine.IMVS_PF_STATUS_HAS_PASSWORD)
            {
                strMsg = "IMVS_PF_CheckPassword_CS success. Status: Solution has password.";
            }
            else if (nHasPassword == ImvsSdkPFDefine.IMVS_PF_STATUS_HAS_NO_PASSWORD)
            {
                strMsg = "IMVS_PF_CheckPassword_CS success. Status: Solution has no password.";
            }
            else
            {
                strMsg = "IMVS_PF_CheckPassword_CS failed.";
            }
            listBoxMsg.Items.Add(strMsg);
            listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
        }

        /****************************************************************************
         * @fn           保存方案
         ****************************************************************************/
        private void buttonSaveSolution_Click(object sender, EventArgs e)
        {
            string strMsg = null;
            progressBarSaveAndLoad.Value = 0;
            uint nProcess = 0;
            labelProgress.Text = nProcess.ToString();
            labelProgress.Refresh();

            int iRet = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            ImvsSdkPFDefine.IMVS_PF_SAVE_SOLUTION_INPUT stInputSave = new ImvsSdkPFDefine.IMVS_PF_SAVE_SOLUTION_INPUT();
            string strSolutionPath = textBoxSolutionPath.Text;
            string strPassword = textBoxPassword.Text;

            if ((System.Text.Encoding.Default.GetBytes(strSolutionPath).Length + 1) > ImvsSdkPFDefine.IMVS_PF_MAX_PATH_LENGTH)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("路径长度过长!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }  
            }
            if ((System.Text.Encoding.Default.GetBytes(strPassword).Length + 1) > ImvsSdkPFDefine.IMVS_PF_PASSWORD_LENGTH)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("密码长度过长!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            stInputSave.strPath = strSolutionPath;
            stInputSave.strPassWord = strPassword;

            iRet = ImvsPlatformSDK_API.IMVS_PF_SaveSolution_CS(m_handle, stInputSave);
            if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
            {
                strMsg = "IMVS_PF_SaveSolution_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                return;
            }
            strMsg = "IMVS_PF_SaveSolution_CS success";
            listBoxMsg.Items.Add(strMsg);
            listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;

            DateTime dtStart = DateTime.Now;
            uint nProgress = 0;
            m_nProgressFlag = 1;    // 显示保存方案进度标志位置位
            for (; nProgress < 100;)
            {
                iRet = ImvsPlatformSDK_API.IMVS_PF_GetSaveProgress_CS(m_handle, ref nProgress);

                labelProgress.Text = nProgress.ToString();
                labelProgress.Refresh();
                progressBarSaveAndLoad.Value = Convert.ToInt32(nProgress);

                if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
                {
                    strMsg = "IMVS_PF_GetSaveProgress_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                    listBoxMsg.Items.Add(strMsg);
                    listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                    return;
                }

                Thread.Sleep(100);

                TimeSpan spanNow = new TimeSpan();
                spanNow = DateTime.Now - dtStart;
                if (spanNow.Seconds > 50)    // 50s后退出循环, 防止死循环
                {
                    break;
                }
            }

            m_nProgressFlag = 0;    // 显示保存方案进度标志位复位
        }

        /****************************************************************************
         * @fn           加载方案
         ****************************************************************************/
        private void buttonLoadSolution_Click(object sender, EventArgs e)
        {
            string strMsg = null;
            progressBarSaveAndLoad.Value = 0;
            uint nProcess = 0;
            labelProgress.Text = nProcess.ToString();
            labelProgress.Refresh();
            //检查句柄是否正确
            int iRet = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }
            //标志位
            if (1 == m_nFrontedFlag)
            {
                iRet = ImvsPlatformSDK_API.IMVS_PF_UnAttachFrontedWnd_CS(m_handle, pictureBoxImg.Handle);
                if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
                {
                    strMsg = "IMVS_PF_UnAttachFrontedWnd_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                    listBoxMsg.Items.Add(strMsg);
                    listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                }

                m_nFrontedFlag = 0;
                buttonLoadFrontInterface.Text = "载入前端界面";
            }

            string strPassword = textBoxPassword.Text;
            string strSolutionPath = textBoxSolutionPath.Text;
            iRet = ImvsPlatformSDK_API.IMVS_PF_LoadSolution_CS(m_handle, strSolutionPath, strPassword);
            if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
            {
                strMsg = "IMVS_PF_LoadSolution_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                return;
            }
            strMsg = "IMVS_PF_LoadSolution_CS success";
            listBoxMsg.Items.Add(strMsg);
            listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;

            //对进度条进行循环加载
            DateTime dtStart = DateTime.Now;
            uint nProgress = 0;
            m_nProgressFlag = 1;    // 显示加载方案进度标志位置位
            for (; nProgress < 100;)
            {
                iRet = ImvsPlatformSDK_API.IMVS_PF_GetLoadProgress_CS(m_handle, ref nProgress);

                labelProgress.Text = nProgress.ToString();
                labelProgress.Refresh();
                progressBarSaveAndLoad.Value = Convert.ToInt32(nProgress);

                if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
                {
                    strMsg = "IMVS_PF_GetLoadProgress_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                    listBoxMsg.Items.Add(strMsg);
                    listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                    return;
                }

                Thread.Sleep(300);

                TimeSpan spanNow = new TimeSpan();
                spanNow = DateTime.Now - dtStart;
                if (spanNow.Seconds > 50)    // 50s后退出循环, 防止死循环
                {
                    break;
                }
            }
            m_nProgressFlag = 0;    // 显示加载方案进度标志位复位

            // 获取流程列表
            comboBoxShowPicProcessID.Items.Clear();
            ImvsSdkPFDefine.IMVS_PF_PROCESS_INFO_LIST stProcInfoList = new ImvsSdkPFDefine.IMVS_PF_PROCESS_INFO_LIST();
            stProcInfoList.astProcessInfo = new ImvsSdkPFDefine.IMVS_PF_PROCESS_INFO[ImvsSdkPFDefine.IMVS_PF_MAX_PROCESS_NUM];
            iRet = ImvsPlatformSDK_API.IMVS_PF_GetAllProcessList_CS(m_handle, ref stProcInfoList);
            if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
            {
                strMsg = "IMVS_PF_GetAllProcessList_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                return;
            }

            int iLop = 0;
            string strShowMsg = null;
            for (iLop = 0; iLop < stProcInfoList.nNum; iLop++)
            {
                strShowMsg = Convert.ToString(stProcInfoList.astProcessInfo[iLop].nProcessID) + " (" + stProcInfoList.astProcessInfo[iLop].strProcessName + ")";
                comboBoxShowPicProcessID.Items.Add(strShowMsg);
            }
            comboBoxShowPicProcessID.SelectedIndex = 0;
        }

        /****************************************************************************
         * @fn           关闭方案
         ****************************************************************************/
        private void buttonCloseSolution_Click(object sender, EventArgs e)
        {
            string strMsg = null;
            int    iRet   = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            if (1 == m_nFrontedFlag)
            {
                iRet = ImvsPlatformSDK_API.IMVS_PF_UnAttachFrontedWnd_CS(m_handle, pictureBoxImg.Handle);
                if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
                {
                    strMsg = "IMVS_PF_UnAttachFrontedWnd_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                    listBoxMsg.Items.Add(strMsg);
                    listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                }

                m_nFrontedFlag = 0;
                buttonLoadFrontInterface.Text = "载入前端界面";
            }

            iRet = ImvsPlatformSDK_API.IMVS_PF_CloseSolution_CS(m_handle);
            if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
            {
                strMsg = "IMVS_PF_CloseSolution_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                return;
            }

            // 清空PictureBox控件中的内容
            pictureBoxImg.Image = null;
            pictureBoxImg.Refresh();

            strMsg = "IMVS_PF_CloseSolution_CS Success";
            listBoxMsg.Items.Add(strMsg);
            listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;

            // 清空显示流程列表
            if (ImvsSdkPFDefine.IMVS_EC_OK == iRet)
            {
                comboBoxShowPicProcessID.Items.Clear();
            }
        }

        /****************************************************************************
         * @fn           清空消息
         ****************************************************************************/
        private void buttonDeleteMsg_Click(object sender, EventArgs e)
        {
            listBoxMsg.Items.Clear();
        }

        /****************************************************************************
         * @fn           获取加密狗权限
         ****************************************************************************/
        private void buttonGetDongleAuth_Click(object sender, EventArgs e)
        {
            string strMsg = null;
            int iRet = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            iRet = ImvsPlatformSDK_API.IMVS_PF_GetDongleAuthority_CS(m_handle);
            string hexDongleStatu = String.Format("{0:X}", iRet);
            strMsg = "IMVS_PF_GetDongleAuthority_CS Dongle Authority Status:" + hexDongleStatu;
            listBoxMsg.Items.Add(strMsg);
            listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
        }

        /****************************************************************************
         * @fn           载入前端运行界面
         ****************************************************************************/
        private void buttonLoadFrontInterface_Click(object sender, EventArgs e)
        {
            string strMsg = null;
            int iRet = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            if (0 == m_nFrontedFlag)
            {
                iRet = ImvsPlatformSDK_API.IMVS_PF_AttachFrontedWnd_CS(m_handle, pictureBoxImg.Handle);
                if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
                {
                    strMsg = "IMVS_PF_AttachFrontedWnd_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                    listBoxMsg.Items.Add(strMsg);
                    listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                    return;
                }

                m_nFrontedFlag = 1;
                buttonLoadFrontInterface.Text = "卸载前端界面";

                strMsg = "IMVS_PF_AttachFrontedWnd_CS Success";
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            }
            else if (1 == m_nFrontedFlag)
            {
                iRet = ImvsPlatformSDK_API.IMVS_PF_UnAttachFrontedWnd_CS(m_handle, pictureBoxImg.Handle);
                if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
                {
                    strMsg = "IMVS_PF_UnAttachFrontedWnd_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                    listBoxMsg.Items.Add(strMsg);
                    listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                    return;
                }

                m_nFrontedFlag = 0;
                buttonLoadFrontInterface.Text = "载入前端界面";

                strMsg = "IMVS_PF_UnAttachFrontedWnd_CS Success";
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            }     
        }

        /****************************************************************************
         * @fn           下拉显示当前所有流程信息列表
         ****************************************************************************/
        private void comboGetShowProcessID_ComboDropDown(object sender, EventArgs e)
        {
            string strMsg = null;
            int iRet = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            comboBoxShowProcessID.Items.Clear();
            comboBoxShowProcessID.Text = null;
            ImvsSdkPFDefine.IMVS_PF_PROCESS_INFO_LIST stProcInfoList = new ImvsSdkPFDefine.IMVS_PF_PROCESS_INFO_LIST();
            stProcInfoList.astProcessInfo = new ImvsSdkPFDefine.IMVS_PF_PROCESS_INFO[ImvsSdkPFDefine.IMVS_PF_MAX_PROCESS_NUM];
            iRet = ImvsPlatformSDK_API.IMVS_PF_GetAllProcessList_CS(m_handle, ref stProcInfoList);
            if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
            {
                strMsg = "IMVS_PF_GetAllProcessList_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                return;
            }

            int iLop = 0;
            string strShowMsg = null;
            for (iLop = 0; iLop < stProcInfoList.nNum; iLop++)
            {
                strShowMsg = Convert.ToString(stProcInfoList.astProcessInfo[iLop].nProcessID) + " (" + stProcInfoList.astProcessInfo[iLop].strProcessName + ")";
                comboBoxShowProcessID.Items.Add(strShowMsg);
            }
            comboBoxShowProcessID.SelectedIndex = 0;

            strMsg = "IMVS_PF_GetAllProcessList_CS Success";
            listBoxMsg.Items.Add(strMsg);
            listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
        }

        /****************************************************************************
         * @fn           下拉获取流程ID用于显示
         ****************************************************************************/
        private void comboBoxShowPicProcessID_ComboDropDown(object sender, EventArgs e)
        {
            string strMsg = null;
            int iRet = ImvsSdkPFDefine.IMVS_EC_UNKNOWN;
            if (IntPtr.Zero == m_handle)
            {
                MessageBoxButtons msgType = MessageBoxButtons.OK;
                DialogResult diagMsg = MessageBox.Show("句柄异常, 请重启软件!", "提示", msgType);
                if (diagMsg == DialogResult.OK)
                {
                    return;
                }
            }

            comboBoxShowPicProcessID.Items.Clear();
            ImvsSdkPFDefine.IMVS_PF_PROCESS_INFO_LIST stProcInfoList = new ImvsSdkPFDefine.IMVS_PF_PROCESS_INFO_LIST();
            stProcInfoList.astProcessInfo = new ImvsSdkPFDefine.IMVS_PF_PROCESS_INFO[ImvsSdkPFDefine.IMVS_PF_MAX_PROCESS_NUM];
            iRet = ImvsPlatformSDK_API.IMVS_PF_GetAllProcessList_CS(m_handle, ref stProcInfoList);
            if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
            {
                strMsg = "IMVS_PF_GetAllProcessList_CS Failed. Error Code: " + Convert.ToString(iRet, 16);
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                return;
            }

            int iLop = 0;
            string strShowMsg = null;
            for (iLop = 0; iLop < stProcInfoList.nNum; iLop++)
            {
                strShowMsg = Convert.ToString(stProcInfoList.astProcessInfo[iLop].nProcessID) + " (" + stProcInfoList.astProcessInfo[iLop].strProcessName + ")";
                comboBoxShowPicProcessID.Items.Add(strShowMsg);
            }
            comboBoxShowPicProcessID.SelectedIndex = 0;
        }

        /****************************************************************************
         * @fn           下拉获取流程ID用于显示
         ****************************************************************************/
        private void comboBoxShowPicProcessID_Selchange(object sender, EventArgs e)
        {
            string strSelProcessID = comboBoxShowPicProcessID.SelectedItem.ToString();
            m_nShowProcessID = (int)(GetNumberUint(strSelProcessID));
        }

        /****************************************************************************
         * @fn           IntPtr转Bytes
         ****************************************************************************/
        public static byte[] IntPtr2Bytes(IntPtr ptr, int size)
        {
            byte[] bytes = null;
            if ((size > 0) && (null != ptr))
            {
                bytes = new byte[size];
                Marshal.Copy(ptr, bytes, 0, size);
            }
            return bytes;
        }

        private void buttonChooseServerPath_Click(object sender, EventArgs e)
        {
            OpenFileDialog openVMDialog = new OpenFileDialog();
            openVMDialog.Filter = "可执行文件|*.exe*";
            DialogResult openVMRes = openVMDialog.ShowDialog();
            if (DialogResult.OK == openVMRes)
            {
                textBoxServerPath.Text = openVMDialog.FileName;
            }
        }

        private void buttonCreateHandle_Click(object sender, EventArgs e)
        {
            string strMsg = null;

            string strServerPath = textBoxServerPath.Text;
            // 创建句柄
            if (IntPtr.Zero != m_handle)
            {
                ImvsPlatformSDK_API.IMVS_PF_DestroyHandle_CS(m_handle);
                m_handle = IntPtr.Zero;
            }
            if (IntPtr.Zero == m_handle)
            {
                m_handle = ImvsPlatformSDK_API.IMVS_PF_CreateHandle_CS(strServerPath);
                if (m_handle == IntPtr.Zero)
                {
                    strMsg = "IMVS_PF_CreateHandle_CS Failed.";
                    listBoxMsg.Items.Add(strMsg);
                    listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                    return;
                }

                strMsg = "IMVS_PF_CreateHandle_CS Success.";
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
            }

            // 注册回调
            IntPtr pUser = new IntPtr();
            pUser = this.Handle;
            PlatformInfoCallBack = new delegateOutputCallBack(delegateOutputCallBackFunc);
            int iRet = ImvsPlatformSDK_API.IMVS_PF_RegisterResultCallBack_V30_CS(m_handle, PlatformInfoCallBack, pUser);
            if (ImvsSdkPFDefine.IMVS_EC_OK != iRet)
            {
                strMsg = "IMVS_PF_RegisterResultCallBack_V30_CS Failed";
                listBoxMsg.Items.Add(strMsg);
                listBoxMsg.TopIndex = listBoxMsg.Items.Count - 1;
                return;
            }
        }

        private void textBoxTimeInterval_TextChanged(object sender, EventArgs e)
        {

        }

        private void groupBoxTimeInterval_Enter(object sender, EventArgs e)
        {

        }
    }
}

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C# Winform上位机是一种基于Windows桌面应用程序的上位机开发方式,可以通过串口通信等方式与下位机进行数据交互。以下是一个简单的C# Winform上位机的例子: 1.在Visual Studio中创建一个Windows Forms应用程序项目。 2.在窗体上添加一个ComboBox控件和一个Button控件。 3.在代码中引用System.IO.Ports命名空间,使用SerialPort类实现串口通信。 4.在Button的Click事件中编写代码,获取可用串口列表并在ComboBox中显示。 5.在ComboBox的SelectedIndexChanged事件中编写代码,获取选中的串口名称并打开串口。 6.在串口接收事件中编写代码,处理下位机发送的数据。 以下是一个简单的C# Winform上位机的代码示例: ```csharp using System; using System.IO.Ports; using System.Windows.Forms; namespace WinformSerialPort { public partial class Form1 : Form { private SerialPort serialPort; public Form1() { InitializeComponent(); serialPort = new SerialPort(); serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived); } private void Form1_Load(object sender, EventArgs e) { string[] ports = SerialPort.GetPortNames(); if (ports.Length != 0) { comboBox1.Items.AddRange(ports); comboBox1.SelectedIndex = 0; } else { MessageBox.Show("请插入串口设备!!"); } } private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) { if (serialPort.IsOpen) { serialPort.Close(); } serialPort.PortName = comboBox1.SelectedItem.ToString(); serialPort.BaudRate = Convert.ToInt32(comboBox2.SelectedItem.ToString()); serialPort.Open(); } private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) { string data = serialPort.ReadExisting(); // 处理接收到的数据 } } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值