您的位置:首页 > 其它

串口操作经验总结

2017-08-31 16:44 218 查看
对于串口通讯,如果时C/S版本的程序,由于是本地运行,故可以调用各种接口进行相关的操作,相对较为简单。

但对于B/S版本的程序,相对复杂一下。故总结此次操作的相关知识点,积累经验如下。

对于APS.NET程序而言,目前流行的方法就是制作ACTIVX控件封装串口类操作,作为用户控件进行客户端本地串口操作,具体制作流程有待进一步研究。但此控件只对IE浏览器适用,且需要客户端的相关授权。而GROME有自己的API相关插件。

对于JAVA程序而言,其APPLET技术与ACTIVX类似,可以使用该技术进行相关操作。

以下为制作ACTIVEX控件并集成网页端串口操作的代码,供参考。

C#制作ActiveX控件并添加到网页

1.创建ActiveX控件——按钮

2.定义一个接口,并在控件中实现

3.部署安装

4.CAB打包

5.添加到网页中进行测试

一.
创建ActiveX控件——按钮


1.新建一个Window窗体控件库项目,命名为ActiveXDemo.

 



2.在自动生成的UserControl1页面上添加一个button

 



3.点击事件里我们只弹出一个MesageBox

 

[csharp]
viewplain
copy

private void button1_Click(object sender, EventArgs e)  
{  
    MessageBox.Show("Active is working now!");  
}  

4.在右边解决方案资源管理器的ActiveXDemo项目上右键→属性→应用程序→程序集信息→使程序集COM可见(M)。再切换到“生成”标签→勾选“为COM互操作注册”。



 

 

 



 



5.打开Properties里面的AssemblyInof.cs文件,添加如下代码:

 



6.为控件创建GUID:工具→创建GUID,选5,点击复制

 



7.打开UserControl1.cs,在publicpartialclassUserControl1:UserControl上面粘贴上一步生成的GUID,并添加usingSystem.Runtime.InteropServices;

代码如下:

 

[csharp]
viewplain
copy

using System;    
using System.Collections.Generic;    
using System.ComponentModel;    
using System.Drawing;    
using System.Data;    
using System.Linq;    
using System.Text;    
using System.Threading.Tasks;    
using System.Windows.Forms;    
using System.Runtime.InteropServices;    
    
namespace ActiveXDemo    
{    
    [Guid("73D3BE6A-E3B3-46F7-AFFE-8673390DA3F6")]    
    public partial class UserControl1: UserControl    
    {    
        public UserControl1()    
        {    
            InitializeComponent();    
        }    
    
        private void button1_Click(object sender, EventArgs e)    
        {    
            MessageBox.Show("ActiveX is working now!");    
        }    
    }    
}   

二、定义一个接口,并在控件中实现

创建一个IObjectSafety接口,让ActiveX控件获取客户端的信任。

1.右键ActiveXDemo项目—>添加—>新建项→VisualC#项→接口

注意接口内容是固定的不要修改!!!也就是说你直接复制粘贴就可以用了,不要管里面的序列号,跟上面生成的GUID不是一回事。

 

[csharp]
viewplain
copy

using System;  
using System.Runtime.InteropServices;  
namespace ActiveXDemo  
{     
    [ComImport, GuidAttribute("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]  
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]  
    public interface IObjectSafety  
    {  
        [PreserveSig]  
        int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);  
  
        [PreserveSig()]  
        int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);  
    }  
}  

2.在UserControl1控件的后台代码UserControl1.cs中实现这个接口,代码如下:

 

[csharp]
viewplain
copy

using System;  
using System.Collections.Generic;  
using System.ComponentModel;  
using System.Drawing;  
using System.Data;  
using System.Linq;  
using System.Text;  
using System.Threading.Tasks;  
using System.Windows.Forms;  
using System.Runtime.InteropServices;  
  
namespace ActiveXDemo  
{  
    [Guid("73D3BE6A-E3B3-46F7-AFFE-8673390DA3F6"), ProgId("ActiveXDemo.UserControl1"), ComVisible(true)]  
    public partial class UserControl1 : UserControl, IObjectSafety  
    {  
 
        #region IObjectSafety 成员 格式固定  
  
        private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";  
        private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";  
        private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";  
        private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";  
        private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}";  
  
        private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;  
        private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;  
        private const int S_OK = 0;  
        private const int E_FAIL = unchecked((int)0x80004005);  
        private const int E_NOINTERFACE = unchecked((int)0x80004002);  
  
        private bool _fSafeForScripting = true;  
        private bool _fSafeForInitializing = true;  
  
        public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)  
        {  
            int Rslt = E_FAIL;  
  
            string strGUID = riid.ToString("B");  
            pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;  
            switch (strGUID)  
            {  
                case _IID_IDispatch:  
                case _IID_IDispatchEx:  
                    Rslt = S_OK;  
                    pdwEnabledOptions = 0;  
                    if (_fSafeForScripting == true)  
                        pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;  
                    break;  
                case _IID_IPersistStorage:  
                case _IID_IPersistStream:  
                case _IID_IPersistPropertyBag:  
                    Rslt = S_OK;  
                    pdwEnabledOptions = 0;  
                    if (_fSafeForInitializing == true)  
                        pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;  
                    break;  
                default:  
                    Rslt = E_NOINTERFACE;  
                    break;  
            }  
  
            return Rslt;  
        }  
  
        public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)  
        {  
            int Rslt = E_FAIL;  
            string strGUID = riid.ToString("B");  
            switch (strGUID)  
            {  
                case _IID_IDispatch:  
                case _IID_IDispatchEx:  
                    if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) && (_fSafeForScripting == true))  
                        Rslt = S_OK;  
                    break;  
                case _IID_IPersistStorage:  
                case _IID_IPersistStream:  
                case _IID_IPersistPropertyBag:  
                    if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) && (_fSafeForInitializing == true))  
                        Rslt = S_OK;  
                    break;  
                default:  
                    Rslt = E_NOINTERFACE;  
                    break;  
            }  
  
            return Rslt;  
        }  
 
        #endregion  
        public UserControl1()  
        {  
            InitializeComponent();  
        }  
  
        private void button1_Click(object sender, EventArgs e)  
        {  
            MessageBox.Show("ActiveX is working now!");  
  
        }  
    }  
}  

注意

[csharp]
viewplain
copy

[Guid("73D3BE6A-E3B3-46F7-AFFE-8673390DA3F6")]  

变成了

 

[csharp]
viewplain
copy

[Guid("73D3BE6A-E3B3-46F7-AFFE-8673390DA3F6"), ProgId("ActiveXDemo.UserControl1"), ComVisible(true)]  

可能发生的问题

到目前为止,ActiveXDemo项目完工了,ActiveXDemo项目右键-->生成。

这个时候,我这边出现了一个错误:

错误1无法注销程序集“D:\learnActiveX\ActiveXDemo\ActiveXDemo\bin\Debug\ActiveXDemo.dll”-拒绝访问。请确保您正在以管理员身份运行应用程序。不允许所请求的注册表访问权。ActiveXDemo

最后发现用管理员身份运行VS2012,然后打开ActiveXDemo项目,再生成,就不会报错了。

三、打包部署

1.解决方案ActiveXDemo右键-->添加新项目-->其他项目类型-->安装和部署。如果你没有安装过这个,请先安装。命名为ActiveSetup

 



2.选择applicationinformation:基本配置,自定义填写



 3.接下来先把ApplicationFiles,点击MyCompany下的第一个节点可以自己重命名

 



 4.点击AddProjectOutPuts,选择主输出点ok

 



5.ActiveSetup项目右键,生成。在ActiveSetup\Express\DVD-5\DiskImages\DISK1文件夹下有如下文件:

一个exe一个mis我们只用mis的

 

 

还要一个cabarc.exe这个我会在下载里给大家提供

  cabarc.exe:微软提供的cab打包工具

    ActiveXSetup.msi:  项目生成的部署安装文件
 
   install.inf:需要跟ActiveXSetup.msi打包在一起的文件
 
   build.bat: 打包的批处理命令
install.inf

[version]
signature="$CHICAGO$"
AdvancedINF=2.0

[SetupHooks]
hook1=hook1

[hook1]
run=msiexec.exe/i"%EXTRACT_DIR%\ActiveXSetup.msi"/qn


 build.bat 

"cabarc.exe"ntest.cabActiveXSetup.msiinstall.inf


运行一下bat就可以生成一个

cab

我们随便建一个webfrom网站

在debug下边建一下dll文件夹

把test.cab放到文件夹里

 

 

cabarc.exe:微软提供的cab打包工具地址:files.cnblogs.com/files/dongh/cab%E5%88%B6%E4%BD%9C%E5%B7%A5%E5%85%B7.rar

使用VS2010C#开发ActiveX控件(上)

最近做读卡器的B/S应用程序开发,由于读卡器厂商提供的手册都是C/S版本的,而且只有一个原始的Dll包,并没有web版的,那么就只好自己动手,丰衣足食了。
        要开发Web版的读卡程序,大体思路如下:
1.      
使用C#对原始的Dll进行封装,这里要封装两部分内容,一部分是串口通信的功能,一部分是对卡读写的功能。
2.      
开发ActiveX控件调用封装后的Dll,使用串口通信来对卡进行读写。
3.      
打包并发布ActiveX控件。
4. 使用ActiveX控件。

思路1中封装代码有2个类SerialInterfaceHelper,串口通信的帮助类,MifareOneHelper,M1卡的读写帮助类,我们放在了项目CardReader.Library中。
由于本文的重点是使用VS2010(C#)进行ActiveX控件的开发,因此思路1中的内容就不进行详述了,后面会直接给出类库可以参考。本文的实例中演示C#开发
一个ActiveX读卡器控件,实现读取卡号并显示出卡号或异常信息的功能,分成三个大的步骤来实现:开发ActiveX控件、打包并发布ActiveX控件和使用
ActiveX控件。
  开发ActiveX控件

    常见的一些ActiveX大部分是使用VB、Delphi、C++开发,使用C#开发ActiveX要解决下面三个问题:

(1)使.NET组件可以被COM调用

(2)在客户机上注册后,ActiveX控件能通过IE的安全认证

(3)已在客户机上注册时,安装包能通过IE的签名认证

开发ActiveX步骤:

1. 创建WindowsFormsControlLibrary项目CardReader.Controls,设置项目属性能够被COM调用。

右击CardReader.Controls,选择属性,设置项目的Assembly属性,如下图1所示:




图1

对MakeAssemblyCom-Visible选项划钩。

设置项目的编译选项,如图2所示:


图2

图2中对RegisterforCOMInterop选中,对COM组件进行注册。(注意,此处如果实在debug状态下修改的,那在调到release状态下还需要再设置一次。)

设置应用程序的AssemblyInfo属性,右击项目的Properties,打开AssemblyInfo文件,Assembly:AllowPartiallyTrustedCallers,注意添加引用System.Security,代码如下:
using System.Reflection;

using System.Runtime.CompilerServices;

using System.Runtime.InteropServices;

using System.Security;

// General Information about an assembly is controlled through the following 

// set of attributes. Change these attribute values to modify the information

// associated with an assembly.

[assembly: AssemblyTitle("CardReader.Controls")]

[assembly: AssemblyDescription("")]

[assembly: AssemblyConfiguration("")]

[assembly: AssemblyCompany("Microsoft")]

[assembly: AssemblyProduct("CardReader.Controls")]

[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]

[assembly: AssemblyTrademark("")]

[assembly: AssemblyCulture("")]

 

[assembly:AllowPartiallyTrustedCallers()]

// Setting ComVisible to false makes the types in this assembly not visible 

// to COM components.  If you need to access a type in this assembly from 

// COM, set the ComVisible attribute to true on that type.

[assembly: ComVisible(true)]

 

// The following GUID is for the ID of the typelib if this project is exposed to COM

[assembly: Guid("15493d85-ec9e-4c75-a237-9009a997b780")]

 

// Version information for an assembly consists of the following four values:

//

//      Major Version

//      Minor Version 

//      Build Number

//      Revision

//

// You can specify all the values or you can default the Build and Revision Numbers 

// by using the '*' as shown below:

// [assembly: AssemblyVersion("1.0.*")]

[assembly: AssemblyVersion("1.0.0.0")]

[assembly: AssemblyFileVersion("1.0.0.0")]

 
 

2. 开发读卡器用户控件,这个用户控件包含三个部分:

一个TextBox,用以显示读出的卡号

一个Button,读卡

一个Label,显示错误信息

编写读卡按钮事件的代码,完成控件开发后,为了使该用户控件作为一个ActiveX控件进行使用,还需要做以下修改:


首先,为控件类创建一个唯一的GUID,这个编号将用于B/S系统的客户端调用时使用,注意这里的GUID不能和AssemblyInf中的GUID相同,生成GUID的方法如下,

在开始-》程序中打开MicrosoftWindowsSDKTools,如下图3所示: 



 

图3
点击GUIDGenerator,生成GUID,如下图4所示:



图4
COPY生成的GUID到记事本,再拷贝GUID的字符串到控件类,代码如下所示:[Guid("E395359C-86F2-4D7B-A91A-5A64B9E3BA6C")]
public partial class ReadCardControl : UserControl
其次,为了让ActiveX控件获得客户端的信任,控件类还需要实现一个名为“IObjectSafety”的接口,要创建该接口(注意,不能修改该接口的GUID值),

IObjectSafety代码如下:

    [ComImport, Guid("1D9AD540-F2C9-4368-8697-C4AAFCCE9C55")]

    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]

    public interface IObjectSafety

    {

        [PreserveSig]

        void GetInterfacceSafyOptions(

        int riid,

        out int pdwSupportedOptions,

        out int pdwEnabledOptions);

 

        [PreserveSig]

        void SetInterfaceSafetyOptions(

        int riid,

        int dwOptionsSetMask,

        int dwEnabledOptions);

    }
注意这里要添加引用:using System.Runtime.InteropServices;

 

3. 修改控件类,使之继承IObjectSafety接口,代码清单如下:

[Guid("E395359C-86F2-4D7B-A91A-5A64B9E3BA6C")]

    public partial class ReadCardControl : UserControl,IObjectSafety

    {

        public int icdev; // 通讯设备标识符

        public Int16 st;

        public int sec;

 

        public ReadCardControl()

        {

            InitializeComponent();

        }
        #region IObjectSafety 成员

 

        public void GetInterfacceSafyOptions(int riid, out int pdwSupportedOptions, out int pdwEnabledOptions)

        {

            pdwSupportedOptions = 1;

            pdwEnabledOptions = 2;

        }

 

        public void SetInterfaceSafetyOptions(int riid, int dwOptionsSetMask, int dwEnabledOptions)

        {

            throw new NotImplementedException();

        }

 
        #endregion

}
 

  打包并发布ActiveX

        ActiveX控件开发完成后,我们要讲ActiveX控件打包和发布。ActiveX控件可以使用VS2010的安装项目进行部署,使用VS2010创建Windows
Form的安装工程就可以将ActiveX的dll进行打包。在打包时注意将ActiveX控件项目作为主输出项目,并设置其Register属性为vsdrpCOM,创建打包项目如下图5所示:



图5


创建一个Windows安装项目,并给项目添加项目输出,如下图6所示:




图6


在添加项目输出时,我们将ActiveX项目添加进来,在项目中选择ActiveX控件项目(CardReader.Controls),PrimaryOut(基本输出),如下图7所示:




图7


添加完项目输出以后,在ApplicationFolder里已经有了三个文件:CardReader.Controls.tlb、CardReader.Libary.dll、Primary
OutputFromCardReader.Controls,同时将mwrf32.dll也打进安装包里,右击添加文件,浏览到mwrf32.dll添加进来即可。注意首先要将mwrf32.dll拷贝到ActiveX控件
项目中的Bin中,添加文件时浏览到\\CardReader\CardReader.Controls\bin\Debug中的mwrf32.dll打包进去,否则会出现找不到mwrf32.dll的错误。
添加完文件后,设置PrimaryOutputFromCardReader.Controls的Register属性为vsdrpCOM。设置完成后右击安装工程SetupCardReader,
修改其属性,如下图8所示:

 


图8


        在上图中可以设置输出的文件名,这个文件名就是打包后安装文件.MSI的文件名。设置包文件、压缩方式,CABsize,这三项均选择默认值即可。

最后设置安装URL,这里的安装URL是用来发布或者测试ActiveX的URL地址的。上图中我们将在89端口下进行测试,因此URL设置为:

http://localhost:89/CardReader

这样打包文件就生成了,我们可以打开\\CardReader\SetupCardReader\Debug看到生成了2个文件,一个是setup.exe,一个是SetupCardReader.msi,
这里的Setup.exe就是我们在使用ActiveX时的codebase文件。
打包成exe文件以后,我们可以进一步对安装文件进行打包成.cab文件,安装隐藏了msi
安装界面,类似于cabarc打包ocx
的效果
(点击install
之后其他的都后台做了),本文中暂不讨论,感兴趣的读者可以使用CABSDK中的工具CABARC.EXE(下载地址
http://support.microsoft.com/kb/310618)来进行。
  使用ActiveX

打包完成后,我们就可以在应用程序中使用打包好的ActiveX控件了,创建一个web项目(CardReader.Web),在测试页面的HTML代码中添加对ActiveX控件

的引用,修改default.aspx的代码如下:

    <object id="cardReader1" classid="clsid:E395359C-86F2-4D7B-A91A-5A64B9E3BA6C" 

        width="500"

        height="100" 

        codebase="CardReader/SetupCardReader/Debug/Setup.exe">

    </object>
注意这里的clsid:E395359C-86F2-4D7B-A91A-5A64B9E3BA6C的值是我们在开发ActiveX控件时的GUID。

运行的效果图下图9所示:




图9


        图9中,我们演示了不调用串口通信和读卡程序下的效果,至于要调用串口通信和读卡程序,我将在另一篇帖子里进行详细说明。

        至此,使用VS2010开发ActiveX控件的大部分功能已经完成了,在VS2010环境中使用C#开发ActiveX控件,技术并不太困难,但是要求客户端需要安装.NET
Framework。鉴于ActiveX控件一般都是实现一些简单单一的功能,所以建议使用.NETFramework2.0/.NETFramework4.0下开发,

本实例中我们使用了.NETFramework4.0。

使用VS2010C#开发ActiveX控件(下),完整代码下载

 在使用VS2010C#开发ActiveX控件(上)中,

http://www.cnblogs.com/yungboy/archive/2011/01/10/1932433.html

我们介绍了开发、打包、发布、使用ActiveX控件的全过程。在演示程序中,我们没有调用串口通信和读卡器Dll程序,由于我们读卡器的原始Dll

是使用其它语言进行开发的,对C#来说,是非托管代码,因此我们还需要在代码级别进行非托管代码的安全性设置。

 
 其实如果我们不进行设置,只是修改了代码,运行程序以后,其出错界面如下图1所示:



图1
抛出异常如下:
**************ExceptionText**************
System.MethodAccessException:Attemptbysecuritytransparentmethod'Rare.Card.Libary.Controls.
ReadCardControl.btnRead_Click(System.Object,System.EventArgs)'tocallnativecodethroughmethod'Rare.Card.Libary.MifareOneHelper.rf_read(Int32,Int32,Byte[])'failed. Methodsmustbesecuritycriticalor

securitysafe-criticaltocallnativecode.
 
通过查阅MSDN,对异常的解释如下:
在Microsoft.NETFramework4
中,公共语言运行时(CLR)
安全模型发生了不少变化。其中一项变化,即采用Level2透明性
(与Silverlight
的安全模型非常相似)很可能影响AllowPartiallyTrustedCallers(APTCA)
库的作者。透明性属性有三种:SecurityTransparent、SecuritySafeCritical
和SecurityCritical。
 
SecurityTransparent:标记为SecurityTransparent
的代码从安全性角度而言是可靠的。它不能完成任何危险操作,例如声明权限、
执行无法验证的代码或调用本机代码。它也不能直接调用SecurityCritical
代码。
如上文所述,出于安全的考虑,所有部分受信任代码都强制为SecurityTransparent。这也是APTCA
库的默认透明性。
SecurityCritical:与SecurityTransparent
不同,SecurityCritical
代码能够执行任何所需操作。它能够执行声明、
调用本机代码和其他操作。它能够调用其他方法,且不受透明性标记的限制。
只有完全受信任代码才能为SecurityCritical。事实上,(非APTCA)完全受信任代码默认情况下属于SecurityCritical,
从而保护其免受透明的部分受信任调用方的调用。
SecuritySafeCritical:SecuritySafeCritical
代码起着桥梁的作用,它允许透明代码调用关键方法。SecuritySafeCritical
代码与SecurityCritical
代码的权限相同,但它可由SecurityTransparent
代码调用。因此,SecuritySafeCritical代码必须以安全方式公开基础SecurityCritical
方法(以避免一些部分受信任的恶意代码尝试通过SecuritySafeCritical
层攻击这些方法),这一点极为重要。
与SecurityCritical
代码一样,SecuritySafeCritical
代码必须完全受信任。
具体可以参考:
http://msdn.microsoft.com/zh-cn/magazine/ee336023.aspx
 
根据MSDN的解释,问题出在了封装原始Dll的C#类库CardReader.Library上,我们可以在代码级别设置透明性属性可以解决问题。
具体解决办法如下:
1.      
设置ActiveX控件读卡代码的透明属性为:SecuritySafeCritical,设置以后的代码清单如下:
      [SecuritySafeCritical]

        /// <summary>

        /// 读卡

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void btnRead_Click(object sender, EventArgs e)

        {

            int i = 0;

            byte[] data = new byte[16];

            byte[] buff = new byte[32];

 

            for (i = 0; i < 16; i++)

                data[i] = 0;

            for (i = 0; i < 32; i++)

                buff[i] = 0;

 

            st = MifareOneHelper.rf_read(icdev, sec * 4 + 1, data);

            if (st == 0)

            {

                SerialInterfaceHelper.hex_a(data, buff, 16);

                txtCardID.Text = System.Text.Encoding.ASCII.GetString(buff);

                lblMsg.Text = "读取卡号成功!";

            }

            else

                lblMsg.Text = "读取卡号失败!";

 

            //test method

            //if (string.IsNullOrEmpty(txtCardID.Text))

            //{

            //    lblMsg.Text = "读取数据失败!";

            //}

            //else

            //{

            //    lblMsg.Text = string.Format("读取数据:{0}!", txtCardID.Text);

            //}

        }

注意要添加引用:using System.Security;

在这里注掉了测试代码,使用了串口通信和读卡代码。
2. 设置封装原始读卡器Dll的透明属性。
设置M1读卡器帮助类MifareOneHelper的透明属性为:[SecurityCritical],同时设置调用的方法MifareOneHelper.rf_read的
透明属性为[SecurityCritical]。
   设置串口通信帮助类SerialInterfaceHelper的透明属性为:[SecurityCritical],同时设置调用的方法SerialInterfaceHelper.hex_a的
透明属性为[SecurityCritical]。
 
完整代码已提供,还有2个地方需要注意的是,客户端如果安装ActiveX失败,则把运行ActiveX的地址加入到信任站点里,
信任站点的安全级别降低到最低或者设置信任站点关于ActiveX的选项。
/Files/yungboy/CardReader.7z
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: