• 从VSPD虚拟COM口安装包解出独立的驱动安装包(虚拟串口开发和EXE程序反解压)


    最近在开发项目进行测试时,每次都要架设实体机器,很不方便,于是就想着可不可以写一个虚拟的机器,便于测试。我们项目与机器的通信方式是基于COM口的,于是要做虚拟机器,首先要解决的问题是创建虚拟的COM口。

    网上搜索一番,主要有VSPM和VSPD,前者是在WIN7前使用稳定,后者在WIN7中使用稳定。我的电脑是WIN7_64的,所以选用了VSPD7。于是下了个VSPD7.1的安装包,安装完成后,利用软件界面就可以创建相应的虚拟COM口了。具体如何使用,可以参看这篇文章《虚拟串口VSPD的使用方法》。记住一点,VSPD的COM通信是成对的,一个用于接收数据,一个用于发送数据。

    有了虚拟COM口后,就是写一个DEMO进行测试。具体可以参看这篇文件章《win7系统下用vspd软件进行串口编程实例》。

    当虚拟COM口可以实现通讯之后,就想着我们的程序是依赖于这个VSPD安装包的,那如果我们是否可以不依赖呢?有两种方案:

    方案一:自己写一个虚拟COM的驱动,然后里面实现。有兴趣的可以参看该文《开发虚拟串口驱动程序》。

    方案二:VSPD安装包是一个安装程序,为了实现虚拟COM,必然会有相应的驱动。如果我们能够找到这个驱动并安装,之后用相应的接口来调用,或是可行。

    方案一想了,但自认还没有这个能耐,于是果断放弃,退而选方案二。那么方案二要实现,首先要解决的问题是接口的调用,因为驱动程序即使不能做到自己安装,但还是可以通过VSPD安装包的安装来解决,那么VSPD中有没有提供这样的接口呢?

    查看VSPD的用户手册(User Manual),里面果然有相应的接口(在Using serial port driver in your program下的Functions中),于是有C#写了相应的调用,下面是代码。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    //Add
    using System.Runtime.InteropServices;
    
    namespace Anser.U2Simulator.Model
    {
        public class VSPD
        {        
            //[DllImport("VSPDCTL.dll", EntryPoint = "CreatePair", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
            //public static extern bool CreatePair(byte[] comName1, byte[] comName2);  
    
            /// <summary>
            /// CreatePair creates a pair of virtual serial ports with given names. 
            /// It accepts two null-terminated strings determining which ports should be created as input. 
            /// For example, "COM5" and "COM6". 
            /// </summary>
            /// <param name="comName1">A null-terminated string that defines the name of the first port in a pair</param>
            /// <param name="comName2">A null-terminated string that defines the name of the second port in a pair</param>
            /// <returns>CreatePair returns TRUE if virtual serial pair was created successfully and FALSE otherwise</returns>
            [DllImport("vspdctl.dll")]
            public static extern bool CreatePair(string comName1, string comName2);
    
            /// <summary>
            /// DeletePair deletes a pair of virtual serial ports with a given name. 
            /// As input it takes name of any virtual serial port in a pair.
            /// For example, if you want to remove pair named "COM5"-"COM6", 
            /// you can pass either "COM5" or "COM6" as argument to DeletePair function.
            /// </summary>
            /// <param name="comName">  A null-terminated string that defines one of the two port names in a pair you want to delete </param>
            /// <returns>DeletePair returns TRUE if virtual serial pair was successfully deleted and FALSE otherwise</returns>
            [DllImport("vspdctl.dll")]
            public static extern bool DeletePair(string comName);
    
            /// <summary>
            /// DeleteAll deletes all virtual serial ports currently present in a system. It accepts no arguments at input. 
            /// </summary>
            /// <returns>DeleteAll returns TRUE if all virtual serial pairs were successfully deleted and FALSE otherwise</returns>
            [DllImport("vspdctl.dll")]
            public static extern bool DeleteAll();
    
            [DllImport("vspdctl.dll")]
            public static extern bool SetStrictBaudrateName(string comName, bool isStrictBaudrate);
    
            [DllImport("vspdctl.dll")]
            public static extern bool SetStrictBaudrateHandle(IntPtr handle, bool isStrictBaudrate);
    
            /// <summary>
            /// SetStrictBaudrate enables/disables full baudrate emulation, 
            /// needs the name of one of the paired virtual ports and boolean parameter
            /// that defines if strict baudrate emulation should be enabled or not.
            /// </summary>
            /// <param name="comName">A null-terminated string that defines one of the two port names in a pair </param>
            /// <param name="isStrictBaudrate">A boolean variable which should be TRUE 
            /// if you want to enable strict baudrate emulation and FALSE if you want to disable it</param>
            /// <returns>SetStrictBaudrate returns TRUE if strict baudrate emulation was successfully enabled and FALSE otherwise</returns>
            [DllImport("vspdctl.dll")]
            public static extern bool SetStrictBaudrate(string comName, bool isStrictBaudrate);
    
            /// <summary>
            /// SetBreak enables/disables line break emulation in virtual serial ports. 
            /// </summary>
            /// <param name="comName">A null-terminated string that defines one of the two port names in a pair</param>
            /// <param name="isBreak"> A boolean variable should be TRUE if you want to emulate connection break and FALSE if you want to re-establish it </param>
            /// <returns>SetBreak returns TRUE if line break emulation was successfully enabled and FALSE otherwise.</returns>
            [DllImport("vspdctl.dll")]
            public static extern bool SetBreak(string comName, bool isBreak);
    
            /// <summary>
            /// QueryBus: QueryBus sends request to get complete information from the virtual serial bus installed by VSPD. 
            /// </summary>
            /// <param name="inBufferPtr">A pointer to VSBUS_QUERY or VSBUS_QUERY_EX structures. 
            /// If you want to get information about all current virtual serial ports 
            /// then use VSBUS_QUERY structure 
            /// and if you want to get extended information 
            /// about single virtual serial pair then use VSBUS_QUERY_EX structure.</param>
            /// <param name="inBufferSize"></param>
            /// <param name="outBufferPtr"></param>
            /// <param name="outBufferSize">A pointer to either PORT_INFORMATION or PORT_INFORMATION_EX structures list. 
            /// If you have used VSBUS_QUERY than you should get PORT_INFORMATION list 
            /// and if you used VSBUS_QUERY_EX then you should get PORT_INFORMATION_EX.</param>
            /// <returns></returns>
            [DllImport("vspdctl.dll")]
            public static extern bool QueryBus(IntPtr inBufferPtr, long inBufferSize, IntPtr outBufferPtr, long outBufferSize);
    
            /// <summary>
            /// SetWiring sets custom signal lines wiring (pinout). 
            /// </summary>
            /// <param name="comName">A null-terminated string that defines one of the two port names in a pair </param>
            /// <param name="bufferPtr">A pointer to VSERIAL_WIRING structure </param>
            /// <param name="bufferSize">Size of Buffer parameter in bytes </param>
            /// <returns>SetWiring returns TRUE if signal lines wiring was created successfully and FALSE otherwise</returns>
            [DllImport("vspdctl.dll")]
            public static extern bool SetWiring(string comName, IntPtr bufferPtr, long bufferSize);
    
            /// <summary>
            /// SetAccessList restricts access to created virtual serial ports for various applications. 
            /// </summary>
            /// <param name="comName"> A null-terminated string that defines one of the two port names in a pair </param>
            /// <param name="bufferPtr">A pointer to PROGRAM_ACCESS array </param>
            /// <param name="bufferSize">Size of Buffer parameter in bytes </param>
            /// <returns>SetAccessList returns TRUE if port access list was created successfully and FALSE otherwise</returns>
            [DllImport("vspdctl.dll")]
            public static extern bool SetAccessList(string comName, IntPtr bufferPtr, long bufferSize);
    
            //[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi,Pack=1)]
            public struct _VSBUS_QUERY
            {
                /// <summary>
                /// VSBUS_QUERY structure size
                /// </summary>
                ulong Size;
    
                /// <summary>
                /// Has QUERYTYPE_PORTS = 1 value. Can be extended in the future. 
                /// </summary>
                ulong QueryType;
            };
    
            private const int MAX_PORTNAME_LEN = 6;
            public struct _VSBUS_QUERY_EX
            {
                /// <summary>
                /// VSBUS_QUERY_EX structure size
                /// </summary>
                ulong Size;
    
                /// <summary>
                /// 1:query all virtual ports.
                /// 2:query particular virtual pair
                /// 3:query particular virtual pair; name of the application, which created the port, is returned.
                /// </summary>
                ulong QueryType;
    
                /// <summary>
                /// Unicode name of any port in the pair you want to delete. 
                /// For instance, if "COM6-COM7" virtual serial ports pair was created, 
                /// then to remove it, PortName's value should be COM6 or COM7. 
                /// </summary>
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PORTNAME_LEN)]
                string PortName;
            }
    
        }
    }
    
    代码中用到的结构只写了一部分,如果需要用到更多的结构的,可以参看VSPD的使用手册,然后自行改造。

    在这些接口中我要用的只是创建和册除虚拟COM口,所以只要用到CreatePair、DeletePair和DeleteAll,下面是对这三个接口调用的示例代码。

    VSPD.CreatePair("COM101", "COM201");
    VSPD.DeletePair("COM101");
    VSPD.DeleteAll();
    使用COM101和COM201,是为了更方便从名字上看出他们是一对的。

    有了这些之后,那么自己增删虚拟COM口已经可以实现了。那么还剩下另一个问题,就是能不能从VSPD的安装包中解出相应的驱动程序。

    经过一番试验后,找到了一种方法,具体步骤如下

    1.使用常用的解压缩工具尝试解压vspd.exe,见图1

    图1


    2.查看清单文件,找到该EXE打包所用的工具,见图2

    在vspd/.rsrc/MANIFEST下用UE打开文件1,然后查看打包用的工具是Inno.Setup.
    图2

    3.查找Inno打包的EXE的反解压工具。

    经网上搜索后,找到了innounp.exe。

    4.使用innounp.exe反解压vspd.exe。见图3.

    图3

    5.查看安装脚本install_script.iss

    打开安装脚本后,会看到Files下的Source指向了一系列的文件,而驱动程序是以sys为后缀的,所以我们关心的是sys的文件和其所在的文件夹,我们可以看到sys所在的文件夹里面有evsbc7.inf、evsbc7.sys、evserial7.cat、evserial7.inf、evserial7.sys、vsbsetup.exe这些文件。
    其中两个文件特别要注意,一个是evserial7.inf,一个是vsbsetup.exe。inf是一种安装文件,右击点击该文件可以看到有安装的字样,有的系统可以安装(如XP),有的系统不一定能安装(如win7_64)。另一个exe文件,是执行文件,但不确定是不是驱动程序的安装执行文件。

    6.测试安装脚本

    尝试执行evsbc7.inf安装后,有时可以成功,有时不能成功,看来这个文件不太可靠,具体要视系统而定。那我们尝试使用vsbsetup.exe安装(最好是用CMD来执行安装,这样可以看到异常和安装结果),安装时会需要几秒至几十秒不等(CMD安装时,会等一段时间,但安装完成后不会有其他提示),安装完成后,用前面的demo创建虚拟com口,在电脑的设备管理器中的可以看到com口的数量增加了。这么说这个exe执行文件就是安装驱动的程序。
    至此,驱动程序已经从vspd.exe中解出来了,不过还需要注意一点,就是版本与系统的对应。
    NT5对应XP_32
    NT5x64对应XP_64
    NT6对应WIN7_32
    NT6x64对应WIN7_64

    7.自行打包

    有了驱动程序的安装脚本,那么要合并到自己的程序中,只是打包的问题了,这个有很多打包工具可以实现。
    如果使用VS打包,在制作安装包的同时,再做一个类库,该类库中添加一个安装程序类Installer1.cs,然后在该类中可以在安装过程中执行相应的动作。
    http://blog.csdn.net/xingxing513234072/article/details/20387813


  • 相关阅读:
    工厂方法模式
    命名空间的规划
    Download Manager
    Intent(二)
    Intent (一)
    Fragment (一)
    修改环境变量需不需要重启电脑
    Spring mvc和SSH如何取舍?
    ORA-01795: 列表中的最大表达式数为1000的解决方法详解
    apache与tomcate的区别
  • 原文地址:https://www.cnblogs.com/sparkleDai/p/7605062.html
Copyright © 2020-2023  润新知