精华内容
下载资源
问答
  • winform调用activex
    2019-01-08 08:07:58

    使用反射动态调用ActiveX控件

    袁永福 2018-3-2

    ■■■■问题描述:

    目前的基于.NET平台的软件研发中仍然存在大量的对COM及ActiveX控件的调用。使用C#调用ActiveX控件时一般是使用vs.net工具的添加COM引用时自动生成的互操作性程序集。这种方法操作简单,能保证一定的性能。但会产生额外的程序文件,不利于应用软件的简洁部署。而且当开发环境和运行环境使用的ActiveX控件的版本不一致[袁永福原创]时还容易出错。

    笔者长期从事基于.NET平台的通用产品类软件研发。[袁永福原创]产品类软件要求部署简洁,为此笔者都会将多个工程编译生成的多个.NET程序集文件合并成一个.NET程序集文件来做到简洁部署。

    实践中发现自动生成的互操作性程序集无法合并。另外产品类软件应该能适应各种复杂的开发和生产环境,甚至ActiveX控件的CLSID 都有可能变化。

    例如,对于COM类库“HebcaFormSealLib”,VS.NET会自动生成程序集文件“AxInterop.HebcaFormSealLib.dll”、“Interop.HebcaFormSealLib.dll”。这些程序集文件无法进行程序集合并,而且对于32位或64位的工程项目类型敏感,容易导致错误。

    ■■■■技术改进:

    因此笔者不采用这种自动生成的互操作性程序集。转而采用自定义的反射来调用ActiveX控件。

    后期绑定ActiveX 控件主要知识点为System.Windows.Forms.AxHost类型和Type.InvokeMember方法。

    AxHost类型是从System.Windows.Forms.Control类型[袁永福原创]派生出来的,专门用于承载ActiveX控件。它是一个抽象类,有一个受保护的构造函数,函数参数是一个guid格式的ActiveX控件的CLSID字符串。还有一个GetOcx内部方法用于创建ActiveX控件的对象实例,它是一个COM对象引用。

    创建了这个COM对象引用后就可以调用Type.InvokerMember方法来动态的调用指定名称的方法和属性。

    ■■■■范例:

    笔者最近在使用某电子签名的ActiveX控件来实现文档签名的功能。笔者写出以下接口代码

    [System.Runtime.InteropServices.ComVisible(false)]
    public class DCHebeiCAControl : System.Windows.Forms.AxHost
    {
        public DCHebeiCAControl()
            : base("{e4ee564c-0845-4404-91ee-0c206113333f}")
        { }
    
        public object _ocx = null;
        protected override void AttachInterfaces()
        {
            this._ocx = base.GetOcx();
        }
        private void CheckOCX()
        {
            if (this._ocx == null)
            {
                throw new System.NullReferenceException("_ocx");
            }
        }
        public VersionType GetBaseVersionType()
        {
            this.CheckOCX();
            VersionType result = (VersionType)this._ocx.GetType().InvokeMember(
                "GetBaseVersionType",
                BindingFlags.InvokeMethod,
                null,
                this._ocx,
                new object[] { });
            return result;
        }
    
        public string GetCert(string sealSN)
        {
            this.CheckOCX();
            string result = (string)this._ocx.GetType().InvokeMember(
                "GetCert",
                BindingFlags.InvokeMethod,
                null,
                this._ocx,
                new object[] { sealSN });
            return result;
        }
    
        public string GetClientDetailVersionInfo()
        {
            this.CheckOCX();
            string result = (string)this._ocx.GetType().InvokeMember(
                "GetClientDetailVersionInfo",
                BindingFlags.InvokeMethod,
                null,
                this._ocx,
                new object[] { });
            return result;
        }
    
        public int GetClientVersion()
        {
            this.CheckOCX();
            int result = (int)this._ocx.GetType().InvokeMember(
                "GetClientVersion",
                BindingFlags.InvokeMethod,
                null,
                this._ocx,
                new object[] { });
            return result;
        }
    
        public string GetClientVersionInfo()
        {
            this.CheckOCX();
            string result = (string)this._ocx.GetType().InvokeMember(
                "GetClientVersionInfo",
                BindingFlags.InvokeMethod,
                null,
                this._ocx,
                new object[] { });
            return result;
        }
    
        public object GetConfig(string argName)
        {
            this.CheckOCX();
            object result = (object)this._ocx.GetType().InvokeMember(
                "GetConfig",
                BindingFlags.InvokeMethod,
                null,
                this._ocx,
                new object[] { argName });
            return result;
        }
        // ----------- 封装其他接口 -----------------------------
    }//classDCHebeiCAControl
    

     

    上述代码中各个功能函数内部代码结构简单[袁永福原创],之间有很大的相似性,因此完全可以编写一个代码生成器来自动生成上述代码。

    完成自定义的控件后,笔者再创建一个WinForm 窗体,在其Load事件中创建控件并添加到窗体上,其代码如下

    private DCHebeiCAControl _Control = null;
    
    private void frmTest_Load(object sender, EventArgs e)
    {
        this._Control = new DCHebeiCAControl();
        this._Control.Size = new Size(200, 200);
        this._Control.Location = new Point(0, 0);
        this.Controls.Add(this._Control);
    }
    

     

    这样无需使用自动生成的COM接口程序集即可调用ActiveX控件,大幅提高程序的通用性,而且对于32位和64位的项目类型不敏感。方便部署和更新。

    不过这样由于采用后期绑定而带来一定的性能[袁永福原创]问题,因此对于性能敏感而又频繁调用ActiveX控件的场景下需要谨慎采用这种模式。

     

    ■■■■小结:

    在.net开发中调用旧的ActiveX控件是很多开发场景中不得不做的事情。在本文中,笔者介绍了在C#中调用ActiveX控件的标准模式,并提出了一种[袁永福原创]改良模式来提高程序的通用性。为操作ActiveX控件的.NET程序开发提供了一种新的技术手段。

    更多相关内容
  • winform C#调用Unity3d的Activex
  • 本文实例讲述了在C#中实现多线程中调用winform窗体控件的方法,对于C#程序设计的学习有着很好的借鉴参考价值。具体方法如下: 首先,由于Windows窗体控件本质上不是线程安全的。因此如果有两个或多个线程适度操作某...
  • ■■■■前言 ...使用C#调用ActiveX控件时一般是使用vs.net工具自动生成的互操作性程序集。这种方法操作简单,能保证一定的性能。...本文就提出使用反射技术动态调用ActiveX控件的方式来解决这些问题。 ...

    ■■■■前言

    目前的基于.NET平台的软件研发中仍然存在大量的对COMActiveX控件的调用。使用C#调用ActiveX控件时一般是使用vs.net工具自动生成的互操作性程序集。这种方法操作简单,能保证一定的性能。但会产生额外的程序文件,不利于应用软件的简洁部署,还容易产生和ActiveX控件版本相关的错误。本文就提出使用反射技术动态调用ActiveX控件的方式来解决这些问题。

     

    ■■■■问题描述:

    目前的基于.NET平台的软件研发中仍然存在大量的对COMActiveX控件的调用。使用C#调用ActiveX控件时一般是使用vs.net工具的添加COM引用时自动生成的互操作性程序集。这种方法操作简单,能保证一定的性能。但会产生额外的程序文件,不利于应用软件的简洁部署。而且当开发环境和运行环境使用的ActiveX控件的版本不一致[袁永福原创]时还容易出错。

    笔者长期从事基于.NET平台的通用产品类软件研发。[袁永福原创]产品类软件要求部署简洁,为此笔者都会将多个工程编译生成的多个.NET程序集文件合并成一个.NET程序集文件来做到简洁部署。

    实践中发现自动生成的互操作性程序集无法合并。另外产品类软件应该能适应各种复杂的开发和生产环境,甚至ActiveX控件的CLSID 都有可能变化。

    例如,对于COM类库“HebcaFormSealLib”,VS.NET会自动生成程序集文件“AxInterop.HebcaFormSealLib.dll”、“Interop.HebcaFormSealLib.dll”。这些程序集文件无法进行程序集合并,而且对于32位或64位的工程项目类型敏感,容易导致错误。

    ■■■■技术改进:

    因此笔者不采用这种自动生成的互操作性程序集。转而采用自定义的反射来调用ActiveX控件。

    后期绑定ActiveX 控件主要知识点为System.Windows.Forms.AxHost类型和Type.InvokeMember方法。

    AxHost类型是从System.Windows.Forms.Control类型[袁永福原创]派生出来的,专门用于承载ActiveX控件。它是一个抽象类,有一个受保护的构造函数,函数参数是一个guid格式的ActiveX控件的CLSID字符串。还有一个GetOcx内部方法用于创建ActiveX控件的对象实例,它是一个COM对象引用。

    创建了这个COM对象引用后就可以调用Type.InvokerMember方法来动态的调用指定名称的方法和属性。

    ■■■■范例:

    笔者最近在使用某电子签名的ActiveX控件来实现文档签名的功能。笔者写出以下接口代码

     
    [System.Runtime.InteropServices.ComVisible(false)]
    public class DCHebeiCAControl System.Windows.Forms.AxHost
    {
         public DCHebeiCAControl()
            base("{e4ee564c-0845-4404-91ee-0c206113333f}")
         }
         public object _ocx null;
         protected override void AttachInterfaces()
         {
            this._ocx base.GetOcx();
         }
         private void CheckOCX()
         {
            if (this._ocx == null)
            {
                throw new System.NullReferenceException("_ocx");
            }
         }
         public VersionType GetBaseVersionType()
         {
            this.CheckOCX();
            VersionType result (VersionType)this._ocx.GetType().InvokeMember(
                "GetBaseVersionType",
                BindingFlags.InvokeMethod,
                null,
                this._ocx,
                new object[});
            return result;
         }
         public string GetCert(string sealSN)
         {
            this.CheckOCX();
            string result (string)this._ocx.GetType().InvokeMember(
                "GetCert",
                BindingFlags.InvokeMethod,
                null,
                this._ocx,
                new object[sealSN });
            return result;
         }
         public string GetClientDetailVersionInfo()
         {
            this.CheckOCX();
            string result (string)this._ocx.GetType().InvokeMember(
                "GetClientDetailVersionInfo",
                BindingFlags.InvokeMethod,
                null,
                this._ocx,
                new object[});
            return result;
         }
         public int GetClientVersion()
         {
            this.CheckOCX();
            int result (int)this._ocx.GetType().InvokeMember(
                "GetClientVersion",
                BindingFlags.InvokeMethod,
                null,
                this._ocx,
                new object[});
            return result;
         }
         public string GetClientVersionInfo()
         {
            this.CheckOCX();
            string result (string)this._ocx.GetType().InvokeMember(
                "GetClientVersionInfo",
                BindingFlags.InvokeMethod,
                null,
                this._ocx,
                new object[});
            return result;
         }
         public object GetConfig(string argName)
         {
            this.CheckOCX();
            object result (object)this._ocx.GetType().InvokeMember(
                "GetConfig",
                BindingFlags.InvokeMethod,
                null,
                this._ocx,
                new object[argName });
            return result;
         }
         // ----------- 口 -----------------------------
    }//classDCHebeiCAControl
     

     

    上述代码中各个功能函数内部代码结构简单[袁永福原创],之间有很大的相似性,因此完全可以编写一个代码生成器来自动生成上述代码。

    完成自定义的控件后,笔者再创建一个WinForm 窗体,在其Load事件中创建控件并添加到窗体上,其代码如下

    这样无需使用自动生成的COM接口程序集即可调用ActiveX控件,大幅提高程序 

    private DCHebeiCAControl _Control null;
    private void frmTest_Load(object senderEventArgs e)
    {
         this._Control new DCHebeiCAControl();
         this._Control.Size new Size(200200);
         this._Control.Location new Point(00);
         this.Controls.Add(this._Control);
    }
     

    的通用性,而且对于32位和64位的项目类型不敏感。方便部署和更新。

    不过这样由于采用后期绑定而带来一定的性能[袁永福原创]问题,因此对于性能敏感而又频繁调用ActiveX控件的场景下需要谨慎采用这种模式。

     

    ■■■■小结:

    .net开发中调用旧的ActiveX控件是很多开发场景中不得不做的事情。在本文中,笔者介绍了在C#中调用ActiveX控件的标准模式,并提出了一种[袁永福原创]改良模式来提高程序的通用性。为操作ActiveX控件的.NET程序开发提供了一种新的技术手段。

    转载于:https://www.cnblogs.com/xdesigner/p/8513392.html

    展开全文
  • 有一个ActiveX控件,在静态的html页面中用<...我把ActiveX的dll用AxImp.exe封装成了WinForm控件,能够显示出来,但是不能运行。然后我想把html用WebBrowser加载,仍然是能够显示但不能运行。请问有什么办法可以解决?
  • 1、WinForm引用Adobe PDF Reader 工作中写WinForm程序经常会引用第三方的组件,包括引用Com组件,做了一个桌面程序需要展示PDF,看了些其它的开源组件对PDF的兼容性都不是很好,有些看着PDF是正常的但是复制出来的...

    1、WinForm引用Adobe PDF Reader  

    工作中写WinForm程序经常会引用第三方的组件,包括引用Com组件,做了一个桌面程序需要展示PDF,看了些其它的开源组件对PDF的兼容性都不是很好,有些看着PDF是正常的但是复制出来的字有很多乱码。然后就直接引用了adboe pdf reader来显示,测试了不同pdf兼容性算是不错的。那如何引用呢? 

    • 在工具栏选择项

    • 添加Com组件

    找到Adobe PDF Reader勾选,然后点击确定之后组件就被添加到工具箱里面了。

    • 使用Com组件

    新建一个窗体或者用户控件,将刚才添加的Adobe PDF Reader 组件拖入到窗体中就可以像winform控件一样操作该控件了。

    在该窗体类中生成了一个AxAcroPDFLib.AxAcroPDF的控件,进入该控件类可以看到控件类对外提供的方法,包括用于加载显示pdf的 LoadFile 方法,gotoFirstPage 等翻页的方法。
     

    而该控件有一个父类AxHost类,进入Axhost类有一个摘要:  

    包装 ActiveX 控件,并将它们作为功能完整的 Windows 窗体控件公开  

    对此我陷入了沉思,ActiveX控件到底是什么,com组件如何被使用,AxAxAcroPDFLib.AxAcroPDF类是如何生成的,Winform和Com如何互操作?于是我进行了一番资料查找和学习。

    2、ActiveX控件    

    ActiveX控件技术基于由COM,可连接对象,复合文档,属性页,OLE自动化,对象持久性以及系统提供的字体和图片对象组成的基础。
    控件本质上是一个COM对象,它公开IUnknown接口,客户端可以通过该对象获取指向其其他接口的指针。控件可以通过IClassFactory2和自我注册来支持许可。
    也就是说ActiveX控件是基于COM对象的,使用COM技术让不同语言编写的控件可以进行互相调用,而如何编写ActiveX控件呢,可以使用ATL 和 MFC,但是两个我都没使用过!并且没编写过,所以我就略过,只先了解其概念。既然它是基于COM,那接下来看看COM是什么东东。

     3、COM技术  

     Microsoft组件对象模型(COM)定义了一个二进制互操作性标准,用于创建在运行时进行交互的可重用软件库。您可以使用COM库,而无需将其编译到应用程序中。COM是许多Microsoft产品和技术(例如Windows Media Player和Windows Server)的基础。
    COM定义了适用于许多操作系统和硬件平台的二进制标准。对于网络计算,COM为在不同硬件平台上运行的对象之间的交互定义了标准的有线格式和协议。COM独立于实现语言,这意味着您可以使用其他编程语言(例如C ++和.NET Framework中的编程语言)创建COM库。
    COM规范提供了支持跨平台软件重用的所有基本概念:
    组件之间的函数调用的二进制标准。
    将功能强类型分组到接口中的规定。
    提供多态性,功能发现和对象生存期跟踪的基本接口。
    唯一标识组件及其接口的机制。
    组件加载器,可从部署中创建组件实例。
    COM具有多个部分,这些部分可以一起工作以创建由可重用组件构建的应用程序:
    一个主机系统提供了一个运行时环境符合的COM规范。
    定义要素合同的接口和实现接口的组件。
    为系统提供组件的服务器,以及使用组件提供的功能的客户端。
    一个注册表,用于跟踪组件在本地和远程主机上的部署位置。
    一个服务控制管理器,可以在本地和远程主机上找到组件,并将服务器连接到客户端。
    一种结构化的存储协议,它定义了如何导航主机文件系统上文件的内容。
    跨主机和平台启用代码重用对于COM至关重要。可重用的接口实现被称为组件,组件对象或COM对象。组件实现一个或多个COM接口。
    您可以通过设计库实现的接口来定义自定义COM库。图书馆的使用者可以发现和使用其功能,而无需了解图书馆的部署和实施细节。

    这是官方的定义,当然还有很多细节说明可以看看https://docs.microsoft.com/zh-cn/windows/win32/com/com-technical-overview 其中包括实现的定义和方式,对象和接口、接口实现、IUnknown接口等等。

    那是如何实现如何调用呢,引用一段有趣的概括性的描述:

    COM主要是一套给C/C++用的接口,当然为了微软的野心,它也被推广到了VB、Delphi以及其他一大堆奇奇怪怪的平台上。它主要为了使用dll发布基于interface的接口。我们知道dll的接口是为了C设计的,它导出的基本都是C的函数,从原理上来说,将dll加载到内存之后,会告诉你一组函数的地址,你自己call进去就可以调用相应的函数。
    但是对于C++来说这个事情就头疼了,现在假设你有一个类,我们知道使用一个类的第一步是创建这个类:new MyClass()。这里直接就出问题了,new方法通过编译器计算MyClass的大小来分配相应的内存空间,但是如果库升级了,相应的类可能会增加新的成员,大小就变了,那么使用旧的定义分配出来的空间就不能在新的库当中使用。
    要解决这问题,我们必须在dll当中导出一个CreateObject的方法,用来代替构造函数,然后返回一个接口。然而,接口的定义在不同版本当中也是有可能会变化的,为了兼容以前的版本同时也提供新功能,还需要让这个对象可以返回不同版本的接口。接口其实是一个只有纯虚函数的C++类,不过对它进行了一些改造来兼容C和其他一些编程语言。
    在这样改造之后,出问题的还有析构过程~MyClass()或者说delete myClass,因为同一个对象可能返回了很多个接口,有些接口还在被使用,如果其中一个被人delete了,其他接口都会出错,所以又引入了引用计数,来让许多人可以共享同一个对象。
    其实到此为止也并不算是很奇怪的技术,我们用C++有的时候也会使用Factory方法来代替构造函数实现某些特殊的多态,也会用引用计数等等。COM技术的奇怪地方在于微软实在是脑洞太大了,它们构造了一个操作系统级别的Factory,规定所有人的Interface都统一用UUID来标识,以后想要哪个Interface只要报出UUID来就行了。这样甚至连链接到特定的dll都省了。
    这就好比一个COM程序员,只要他在Windows平台上,调用别的库就只要首先翻一下魔导书,查到了一个用奇怪文字写的“Excel = {xxx-xxx-xxxx...}”的记号,然后它只要对着空中喊一声:“召唤,Excel!CoCreateInstance, {xxx-xxx-xxxx...}”
    然后呼的从魔法阵里面窜出来了一个怪物,它长什么样我们完全看不清,因为这时候它的类型是IUnknow,这是脑洞奇大无比的微软为所有接口设计的一个基类。我们需要进一步要求它变成我们能控制的接口形态,于是我们再喊下一条指令:
    “变身,Excel 2003形态!QueryInterface, {xxx-xxx-xxxx...}”
    QueryInterface使用的是另一个UUID,用来表示不同版本的接口。于是怪物就变成了我们需要的Excel 2003接口,虽然我们不知道它实际上是2003还是2007还是更高版本。
    等我们使唤完这只召唤兽,我们就会对它说“回去吧,召唤兽!Release!”但是它不一定听话,因为之前给它的命令也许还没有执行完,它会忠诚地等到执行完再回去,当然我们并不关心这些细节。(引用地址:https://www.zhihu.com/question/49433640)

    从这个概括理解,所有的COM类其实都继承了IUnknown,当我们拿到IUnknown接口后还需要转成我们需要使用的类型,而这个类型如果用强转可能会出错,但是微软认为,直接由用户来转型是不安全的需要唯一的一个标识符来确定一个类,那么这个标识符就是GUID。类ID就叫作CLSID,接口ID就叫作IID,还需要一个转型的函数叫QueryInterface。QueryInterface作为IUnknown中的一个纯虚函数,做的事情其实很简单,判断自己能不能转成某个GUID所指向的类而已。如果不可以,则返回E_NOTIMPL,可以的话返回S_OK,并将转换后的指针作为参数返回。
    COM组件并不需要名字,或者说不需要UUID,因为我们总是使用他里面的接口,而不是直接使用COM组件,所以接口也要UUID。说了这么多,COM架构这么复杂,肯定需要一个中间层,或者说摆渡人,这就是COM Library(一堆dll) + 注册表。A应用通知COM Library,并输入接口的UUID,由COM Library装入B应用的该组件对应的dll,并把接口指针返回给A应用,指针里指示的是一堆函数指针,由这些指针,可以调用到B应用里的函数功能。

     注:上面有时说的UUID,有时说的GUDI,UUID即是GUID值。

    4、Aximp.exe(Windows 窗体 ActiveX 控件导入程序)  

    有了上面的ActiveX控件和Com组件的介绍,我们再回到开始我们如何导入的ActiveX控件。
    ActiveX 控件导入程序将 ActiveX 控件的 COM 类型库中的类型定义转换为 Windows 窗体控件。
    Windows 窗体只能承载 Windows 窗体控件,即从 Control 派生的类。 Aximp.exe 生成可承载于 Windows 窗体上的 ActiveX 控件的包装器类。 这使你得以使用适用于其他 Windows 窗体控件的同一设计时支持和编程方法。
    若要承载 ActiveX 控件,必须生成从 AxHost 派生的包装器控件。 此包装器控件包含基础 ActiveX 控件的一个实例。 它知道如何与 ActiveX 控件通信,但它显示为 Windows 窗体控件。 这个生成的控件承载 ActiveX 控件并将其属性、方法和事件作为生成的控件的属性、方法和事件公开。  
    由此可见当我们再工具箱里面选择添加com组件后实际隐含执行了该导入程序,为我们生成了对应的AxAcroPDFLib.AxAcroPDF包装器控件。而AxAcroPDFLib则如同第三点中讲的那样就是COM Library。
     5、验证
    既然AxAcroPDFLib 是摆渡人(互操作程序集) 那么我们可以看到这个COM Library的引用

    有了互操作程序那么这个互操作程序必然是去调用COM组件,调用COM组件那么UUID呢?将这个程序集放到Dnspy反编译可以看到在ClsidAttribute标记有{ca8a9780-280d-11cf-a24d-444553540000},构造函数里面有UUID。

    然后我们打开注册表查询下对应的值和注册表的情况。

    6、总结  

    所以通过上面的概念了解和猜想验证,基本清楚了com的设计和想法,以及ActiveX控件的调用过程。

    1.  Activex控件时COM实现的一种方式。
    2.  Activex控件通过VS工具引用时调用了Aximp.exe 。
    3.  Aximp.exe程序生成了互操作程序集AxAcroPDFLib,同时生成可承载于 Windows 窗体上的 ActiveX 控件的从 AxHost 派生的包装器控件。
    4. 调用AxAcroPDF方法时通过com组件调用引用控件的功能。
       
    展开全文
  • 我现在调用vlc activex 插件,能够播放 一个VGA信号器 的信号。 但是我需要把这个信号保存成视频文件,该怎么解决? ``` private void button1_Click(object sender, EventArgs e) { //输入参数 string ...
  • 首先到微软的网站上下载Windows Script Control,它是一个ActiveX(R) 控件。下载安装完成后,新建一个C#应用程序项目,在解决方案资源管理器中选中引用节点, 右键点击选择添加引用菜单,弹出添加引用对话框,单击...

    目前有很多的SNS社区或类SNS的网站,例如开心、51、校内等,但是发现大多数社区在邀请好友的时候都没有提供对QQ邮箱或者QQ空间好友列表获取的功能,不过似乎海内支持,但是网上相关QQ的文章还不是很多,希望这篇文章能给你带来一些帮助。

    QQ空间及邮箱登陆的校验方式:

    QQ空间及邮箱登陆的时候,用户输入的密码首先会被页面中的一段Js加密,然后加密过后的密码会加上验证码形成一个新的字串,接着这个新的字串被MD5(32位)加密,加密过后形成最终的密码,这就是我们为什么经常会发现我们在提交的时候我们的密码框中的密码个数会增长的原因,接着在你提交的时候,当前的这个请求会将前一次获取验证码返回的set-cookie值加入到当前请求头的cookie中以保持验证码请求与当前请求的一致性,然后再一并将新的密码和用户名Post到QQ的服务器上去。

    好了,看了上面的QQ校验方式以后,我们再来看看怎样使用代码来登录QQ空间及邮箱来获取我们需要的好友和联系人。

    QQ空间及邮箱自动登录获取联系人的解决方案:

    QQ空间及邮箱登陆首先我们需要将用户输入的密码进行Js加密,但是我们在使用代码登录的时候我们并没有使用到浏览器,那我们怎样驱动Js呢?不用怕,在Java和.NET中都有相应的方式在服务器代码端驱动JS,这里着重讲一下.NET的方法:

    首先到微软的网站上下载Windows Script Control,它是一个ActiveX(R) 控件。下载安装完成后,新建一个C#应用程序项目,在解决方案资源管理器中选中引用节点, 右键点击选择添加引用菜单,弹出添加引用对话框,单击浏览找到安装Windows Script Control的目录,选取msscript.ocx文件确定。那么在引用节点下会增加一个MSScriptControl组件,下面是他Interop 后的所有对象。

    <!--[if !vml]--><!--[endif]-->

    ScriptControl 对支持 ActiveX(TM) Script 的宿主 Script 引擎提供简单接口。接下来我们对被转化成ScriptControlClass类的ScriptControl的属性和方法进行一些说明。

    属性

    AllowUI 属性:应用于 ScriptControl 本身或 Scirpt 引擎显示的用户界面元素,可读写。

    CodeObject 属性:返回对象,该对象用于调用指定模块的公用成员。只读。

    Error 属性:返回 Error 对象,其中包含所发生的最后一个错误的相关详细信息。只读。

    Language 属性:设置或返回正在使用的 Script 语言名称。可读写。

    Modules 属性:为 ScriptControl 对象返回模块集合。只读。

    Procedures 属性:返回在指定模块中定义的过程集合。只读。

    SitehWnd 属性:设置或返回窗口的 hWnd,通过执行 Script 代码,此窗口用于显示对话框和其他用户界面元素。可读写。

    State 属性:设置或返回 ScriptControl 对象的模式。可读写。

    Timeout 属性:设置或返回时间(毫秒),此时间后用户可选择中止 Script 代码的执行或允许代码继续执行。可读写。

    UseSafeSubset 属性:设置或返回 Boolean 值,指明宿主应用程序是否有保密性要求。如果宿主应用程序需要安全控制,则 UseSafeSubset 为 True,否则为 False。可读写。

    方法

    AddCode 方法:向模块添加指定代码。可多次调用 AddCode 方法。

    AddObject 方法:使主机对象模型对 Script 引擎可用。

    Eval 方法:计算表达式并返回结果。

    ExecuteStatement 方法:执行指定的语句。

    Reset 方法:放弃所有已经添加到 ScriptControl 中的 Script 代码和对象。

    Run 方法:运行指定过程。

    事件

    Error 事件:出现运行时错误时,发生此事件。

    Timeout 事件:当超出了 Timeout 属性指定的时间且用户在结果对话框中选定了 End 时,发生此事件。

    说明:

    AllowUI 属性如果设置为false,则显示对话框之类的语句不起作用,如在 VBScript 中MsgBox 语句,JavaScript中的alert等,并且如果执行的脚本超出TimeOut设置的毫秒数,也不会跳出超出时间提醒的对话框,反之则相反;重新设 置 Language 属性会清空AddCode加载的代码;对于TimeOut属性,发生超时时,ScriptControl 检查对象的 AllowUI 属性,确定是否允许显示用户界面元素。

    为了使控件更容易使用,用ScriptEngine类封装一下,下面是完整代码:

    using System;

    using MSScriptControl;

    using System.Text;

    namespace ScriptNameSpace

    {

    /// <summary>

    /// 脚本类型

    /// </summary>

    public enum ScriptLanguage

    {

    /// <summary>

    /// JScript脚本语言

    /// </summary>

    JScript,

    /// <summary>

    /// VBscript脚本语言

    /// </summary>

    VBscript,

    /// <summary>

    /// JavaScript脚本语言

    /// </summary>

    JavaScript

    }

    /// <summary>

    /// 脚本运行错误代理

    /// </summary>

    public delegate void RunErrorHandler();

    /// <summary>

    /// 脚本运行超时代理

    /// </summary>

    public delegate void RunTimeoutHandler();

    /// <summary>

    /// ScriptEngine类

    /// </summary>

    public class ScriptEngine

    {

    private ScriptControl msc;

    //定义脚本运行错误事件

    public event RunErrorHandler RunError;

    //定义脚本运行超时事件

    public event RunTimeoutHandler RunTimeout;

    /// <summary>

    ///构造函数

    /// </summary>

    public ScriptEngine()

    : this(ScriptLanguage.VBscript)

    { }

    /// <summary>

    /// 构造函数

    /// </summary>

    /// <param name="language">脚本类型</param>

    public ScriptEngine(ScriptLanguage language)

    {

    this.msc = new ScriptControlClass();

    this.msc.UseSafeSubset = true;

    this.msc.Language = language.ToString();

    ((DScriptControlSource_Event)this.msc).Error += new DScriptControlSource_ErrorEventHandler(ScriptEngine_Error);

    ((DScriptControlSource_Event)this.msc).Timeout += new DScriptControlSource_TimeoutEventHandler(ScriptEngine_Timeout);

    }

    /// <summary>

    /// 运行Eval方法

    /// </summary>

    /// <param name="expression">表达式</param>

    /// <param name="codeBody">函数体</param>

    /// <returns>返回值object</returns>

    public object Eval(string expression, string codeBody)

    {

    msc.AddCode(codeBody);

    return msc.Eval(expression);

    }

    /// <summary>

    /// 运行Eval方法

    /// </summary>

    /// <param name="language">脚本语言</param>

    /// <param name="expression">表达式</param>

    /// <param name="codeBody">函数体</param>

    /// <returns>返回值object</returns>

    public object Eval(ScriptLanguage language, string expression, string codeBody)

    {

    if (this.Language != language)

    this.Language = language;

    return Eval(expression, codeBody);

    }

    /// <summary>

    /// 运行Run方法

    /// </summary>

    /// <param name="mainFunctionName">入口函数名称</param>

    /// <param name="parameters">参数</param>

    /// <param name="codeBody">函数体</param>

    /// <returns>返回值object</returns>

    public object Run(string mainFunctionName, object[] parameters, string codeBody)

    {

    this.msc.AddCode(codeBody);

    return msc.Run(mainFunctionName, ref parameters);

    }

    /// <summary>

    /// 运行Run方法

    /// </summary>

    /// <param name="language">脚本语言</param>

    /// <param name="mainFunctionName">入口函数名称</param>

    /// <param name="parameters">参数</param>

    /// <param name="codeBody">函数体</param>

    /// <returns>返回值object</returns>

    public object Run(ScriptLanguage language, string mainFunctionName, object[] parameters, string codeBody)

    {

    if (this.Language != language)

    this.Language = language;

    return Run(mainFunctionName, parameters, codeBody);

    }

    /// <summary>

    /// 放弃所有已经添加到 ScriptControl 中的 Script 代码和对象

    /// </summary>

    public void Reset()

    {

    this.msc.Reset();

    }

    /// <summary>

    /// 获取或设置脚本语言

    /// </summary>

    public ScriptLanguage Language

    {

    get { return (ScriptLanguage)Enum.Parse(typeof(ScriptLanguage), this.msc.Language, false); }

    set { this.msc.Language = value.ToString(); }

    }

    /// <summary>

    /// 获取或设置脚本执行时间,单位为毫秒

    /// </summary>

    public int Timeout

    {

    get { return 0; }

    }

    /// <summary>

    /// 设置是否显示用户界面元素

    /// </summary>

    public bool AllowUI

    {

    get { return this.msc.AllowUI; }

    set { this.msc.AllowUI = value; }

    }

    /// <summary>

    /// 宿主应用程序是否有保密性要求

    /// </summary>

    public bool UseSafeSubset

    {

    get { return this.msc.UseSafeSubset; }

    set { this.msc.UseSafeSubset = true; }

    }

    /// <summary>

    /// RunError事件激发

    /// </summary>

    private void OnError()

    {

    if (RunError != null)

    RunError();

    }

    /// <summary>

    /// OnTimeout事件激发

    /// </summary>

    private void OnTimeout()

    {

    if (RunTimeout != null)

    RunTimeout();

    }

    private void ScriptEngine_Error()

    {

    OnError();

    }

    private void ScriptEngine_Timeout()

    {

    OnTimeout();

    }

    }

    }

    在找到.NET驱动JS的方法以后,那么我们还需要找到QQ用来加密的那个JS文件,具体的JS文件大家可以到QQ的登录页面去DownLoad,如果不知道是哪一个JS大家可以通过抓包的方式去找到,这里就不再赘述了。下面我们就可以用MSScriptControl来驱动JS获取第一次加密的密码了,方法如下:

    /// <summary>

    /// 得到第一次加密后的密码

    /// </summary>

    /// <param name="jsFilePath">js文件</param>

    /// <param name="funcName">加密的方法名</param>

    /// <param name="paramers">加密方法需要传进的参数(一个是密码,另一个是页面上可获取的一个标志码)</param>

    /// <returns>加密过后的密码</returns>

    private object GetPassword(string jsFilePath, string funcName, params object[] paramers)

    {

    StreamReader reader = new StreamReader(jsFilePath);

    string sScript = reader.ReadToEnd();

    ScriptEngine se = new ScriptEngine(ScriptLanguage.JavaScript);

    object obj = se.Run(funcName, paramers, sScript);

    return obj;

    }

    通过上面的这个函数我们就可以对密码进行第一次加密了,下一步我们需要获取验证码。

    我们可以使用HttpWebRequest类来Get请求这个地址:http://ptlogin2.qq.com/getimage来获取验证码,不过一定要记住把这次请求返回的cookie保存下来,我们可以将它保存到CookieContainer对象中,以便将这次返回的cookie加入到登录POST请求的头当中保持前后请求的一致性。

    现在我们将获得的验证码转化成流或者其他的方式供不同的平台输出,我们发现QQ空间及邮箱的验证码生成的图像不是太复杂,所以可以考虑使用图像识别的方式自动的获取图像对应的字符(现在有很多第三方验证码识别软件),当然为了成功率考虑,最好还是让用户手动的输入。

    好了有了验证码了,我们现在就将验证码字符加上刚刚我们加过密的密码形成新字串,再通过MD5加密

    string pwd=FormsAuthentication.HashPasswordForStoringInConfigFile(this.Password, "MD5").ToLower()

    形成最终我们需要的密码。

    最后我们就可以将用户输入的用户名、密码一并POST到QQ相应的地址上去,这样我们就成功登陆QQ空间或邮箱了。登录成功过后你当然就可以获取联系人好友等等的操作了。

    好了,文章就写到这了,希望对大家有用。^^ Brave chen

    转载于:https://www.cnblogs.com/djhama/archive/2012/03/26/2418205.html

    展开全文
  • WinForm调用 Windows 远程桌面

    千次阅读 2012-07-15 13:35:49
     an ActiveX component in our program to connect to the remote computer. It’s not that hard to build a remote desktop application in .NET. Microsoft has a “Microsoft RDP client control” ActiveX ...
  • Asp.net(c#) b/s通过ActiveX和C# c/s 调用斑马TLP2844条码打印机 通过web打印条码 源代码
  • ActiveX控件以前也叫做OLE控件或OCX控件,它是一些软件组件或对象,可以将其插入到WEB网页或其它应用程序中。使用ActiveX插件,可以轻松方便的在 Web页中插入多媒体效果、交互式对象以及复杂程序等等。在Visual ...
  • 我们都知道通过自定义协议可以从网页启动本地exe程序。但是,当本地没有安装软件时,怎么才能弹出提示,提醒客户安装软件呢? 本实例利用C++编写OCX控件,实现安全接口(没哟证书),网页编写Javascript检测控件是否...
  • 用windows服务程序调用activeX控件(二次封装过),达到服务启动时开始录制影音(不需要用窗体显示出来),服务结束时录制结束 。 遇到问题: activeX控件必须加System.Windows.Forms; 而windows服务程序没有,引进...
  • 点击下载本文配套的演示程序代码...本文就讨论如何在VB6.0开发中使用上WinForm.NET控件。[袁永福版权所有] 二.软件原理:  运行VB IDE,打开或创建一个EX
  • 本实例采用VLC库文件,实现网络rtsp视频源的播放。编译即可运行播放
  • 遇到这个恶心的问题纠缠得不要不要的,大家遇到了的话希望不要走弯路,经过这个折腾让我有点怀疑人生了。哈哈哈 解决代码如下: //插入一个新线程用于处理验证码 Thread thd = new Thread(new ...
  • 前段时间公司做了个比较大的项目,需要用到ocx控件,我厂大部分项目都采用C#.net...笔者此次主要阐述在项目中用javascript调用ocx控件接口,也就是activeX控件时所遇到的问题及其解决方案。winform用法不在此篇中阐...
  • MFC ActiveX控件开发

    2020-07-22 13:44:31
    MFC ActiveX控件开发 新建项目 项目属性-配置属性-常规-mfc的使用选择“使用标准Windows库”,字符集使用多字节字符集。 使用Unicode字符集会出现问题:error C2440: “初始化”: 无法从“const char [10]”转换为...
  • ActiveX控件是在OLE控件“对象链接与嵌入控件”和OCX控件的基础发展起来的,其重要作用是可以插入到网页或应用程序中使用。ActiveX控件可以用各种编程语言来开发,如C、C++,也包括.NET中的C#、VB.N...
  • 采用vs2017+C#进行开发,调用dsoframer.ocx控件(ActiveX),实现在winform桌面程序中“内嵌office”的功能。能够对办公文件(Excel/ Word/ PPT/ Visio)进行常见的查看、编辑、保存等操作。对于有相关业务需求的同仁...
  • 如上,我依赖于A.ocx编写的B.ocx在mfc和c#里winform都能调用,但是使用网页端js调用的时候,一加载ActiveX控件页面就崩溃退出,没任何消息提示,因为不太懂网页,不知道怎么调试,请问我应该怎么做呢?
  • 2、强行添加控件运行时,VS2013提醒——“COM 引用“MSTSCLib”是 ActiveX 控件“AxMSTSCLib”的互操作程序集,但含有 /link 标志的编译器已将其标为已链接。系统会将此 COM 引用视为引用,并且不会链接该引用。” ...
  • ScriptControl 对支持 ActiveX(TM) Script 的宿主 Script 引擎提供简单接口。接下来我们对被转化成ScriptControlClass类的ScriptControl的属性和方法进行一些说明。 属性 AllowUI 属性:应用于 ScriptControl ...
  • 如何在多线程中调用winform窗体控件2——实例篇 针对之前文章《如何在多线程中调用winform窗体控件》,下面举个我项目中的实际案例,这是一个我自定义控件在异步设置焦点时的代码。在新创建的线程中获取主线程的...
  • 在程序中调用窗体时,因另一个窗体包含webbrowser,因此在实例化时报错:当前线程不在单线程单元中,因此无法实例化 ActiveX,查找了下网上的一些方法,说的最多的是在入口添加[STAThread],但我一看项目本身默认创建...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,590
精华内容 636
关键字:

winform调用activex