• ActiveX控件资料


     

    Visual Studio 2008(c#)开发ActiveX控件及制作CAB包总结(1)

    分类: C#

    1、开发及测试环境:

    (1)开发环境:

              Visual Studio 2008 SP1

               cabsdk(下载地址:http://support.microsoft.com/kb/310618)

    (2)测试环境:

              Windows Server 2003 R2 SP2

              IE6

    2、创建项目

    我这里创建了三个项目:

    (1)HelloBossma :

    项目模板:Windows窗体控件库

    (2)HelloBossmaSetup:

    项目模板:安装项目 

    (3)Web:

    项目模板:ASP.NET 网站

    3、HelloBossma项目

    这个项目用于编写具体的控件,并生成安装文件所需要的dll。

    (1)添加用户控件:

    (2)设计控件:

    添加Panel、GroupBox、Label 控件。NowTime是一个Label控件,用于显示时间。

    然后在控件对应的代码文件中编写程序:

     
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Data;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
      
    namespace HelloBossma
    {
        /// <summary>
        /// Guid将用作控件的classid
        /// IObjectSafety的是用来标记可安全执行脚本的ActiveX控件
        /// </summary>
        [Guid("636B8CE1-7512-464C-B63C-FC75BDCA21DB"), ProgId("HelloBossma.HelloBossmaActiveX"), ComVisible(true)]
        public partial class HelloBossmaActiveX : UserControl, 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 HelloBossmaActiveX()
            {
                InitializeComponent();
            }
      
            /// <summary>
            /// 设置当前时间
            /// </summary>
            /// <param name="timeStr"></param>
            public void SetTime(string timeStr)
            {
                this.label2.Text = timeStr;
            }
      
            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;
            }
        }
    }

    关于IObjectSafety的实现参考了:http://www.pinvoke.net/default.aspx/Interfaces/IObjectSafety.html

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

    这里还包含了一个可以被外部调用的方法,传进来一个字符参数,并显示出来:

     
    /// <summary>
            /// 设置当前时间
            /// </summary>
            /// <param name="timeStr"></param>
            public void SetTime(string timeStr)
            {
                this.label2.Text = timeStr;
            }

    (3)设置生成属性,勾选:为Com互操作注册

    (4)生成项目,生成这两个文件:

    HelloBossma.dll
    HelloBossma.tlb

    是必须的,否则生成不成功。

    4、HelloBossmaSetup项目

    这是一个安装项目,用来生成安装程序。

    (1)在项目上点右键,【添加】->【项目输出】,选择上边的HelloBossma项目

    (2)在安装项目上点右键,属性

    安装URL:貌似用于查找应用程序更新,具体看:http://msdn.microsoft.com/zh-cn/library/c37e68bc(VS.90).aspx

    这个目录最好是实际存在的,用来存放生成的安装文件,供客户端下载安装。没有的话就随便输入一个吧。

    (3)添加卸载程序

    拷贝文件C:/Windows/System32/msiexec.exe文件,修改文件名为Uninstall.exe,添加到安装项目中,然后创建一个快捷方式。

    在【用户的“程序”菜单下边】添加一个文件夹HelloBossma,将快捷方式拖动到这里边。

    在卸载控件上点击右键,属性:

    设置Arguments,就是指定要卸载的程序,后面的ProductCode可以这样获得:

    选中项目,然后鼠标放到右侧的“属性”上,就可以看到ProductCode了:

    (4)最后生成项目

    5、制作CAB文件

    (1)为了方便操作,可以将CABARC.EXE添加到环境变量中:桌面上右击“我的电脑”,“属性”,“高级”,“环境变量”,“系统变量”,找到“Path”,在后边把CABARC.EXE所在的路径添加上去,注意用分号隔开新添加的路径。

    (2)准备好文件

    install.inf :CAB安装配置文件

    HelloBossmaSetup.msi:安装程序文件

    install.inf文件的内容:

     
    [version]
    signature="$CHICAGO$"
    AdvancedINF=2.0
      
    [Setup Hooks]
    hook1=hook1
      
    [hook1]
    run=msiexec.exe /i "%EXTRACT_DIR%/HelloBossmaSetup.msi" /qn

    run:一般只需要修改这个就行了

    (3)执行cabarc命令

    桌面左下角“开始”,“运行”,输入cmd,打开命令提示符工具,进入准备好的文件的目录,执行命令:

    cabarc n HelloBossma.cab HelloBossmaSetup.msi install.inf 

    显示“Completed successfully” ,打开所在目录,就可以看到生成的文件了。

    6、部署到网站

    在网站中新建一个目录hellobossma,将生成的cab文件拷贝到里边。

    新建一个网页,将控件添加到页面:

     
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "<Ahref="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd</A>">
    <html xmlns="<A href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</A>">
    <head runat="server">
        <title></title>
        <script type="text/javascript">
            function SetTime() {
                var d = new Date();
                var vYear = d.getFullYear();
                var vMon = d.getMonth() + 1;
                var vDay = d.getDate();
                var vHour = d.getHours();
                var vMin = d.getMinutes();
                var vSec = d.getSeconds();
      
                document.HelloBossma.SetTime(vYear + "-" + vMon + "-" + vDay + " " + vHour + ":" + vMin + ":" + vSec)
            }
        </script>
    </head>
    <body style="font-size: 12px; color: black">
        <form id="form1" runat="server">
        <div>
            <object classid="clsid:636B8CE1-7512-464C-B63C-FC75BDCA21DB"codebase="hellobossma/HelloBossma.CAB" width="442" height="87" id="HelloBossma" name="HelloBossma">
            </object>
            <br />
            <br />
            <input type="button" value="显示当前时间" onclick="SetTime()" />
        </div>
        </form>
    </body>
    </html>

    ActiveX控件作为一个object添加到页面中,其classid是在编写HelloBossmaActiveX类时定义好的Guid值,codebase用来指示cab安装文件的路径,还可以设置宽度、高度。另外其中文字受页面中字体样式的影响。

    因为我们的ActiveX控件没有签名,所以将测试站点加到“本地Intranet”中或者“可信站点”中,并设置安全级别为“低”。

    然后打开浏览器,提示安装,点击“安装”,稍等下,效果就出来了:

    点击按钮,就可以通过javascript设置ActiveX控件中的时间了。

    Over!

     

    Visual Studio 2008(c#)开发ActiveX控件及制作CAB包总结(2)

    分类: C#

    上一节介绍了一个ActiveX的例子,后续的文章将针对这个例子进行扩充和说明。这篇文章将介绍C#如何在ActiveX控件中调用javascript的函数,这里参考网上的例子介绍两种方法,虽然代码不一样,但是殊途同归。而且都使用了mshtml。

    1、方法一

    (1)在VS项目中添加Com对象引用:Microsoft Html Object Library(mshtml.tlb)

    (2)ActiveX中公开一个方法,传递window对象到ActiveX中
    ActiveX中公开一个方法,接受传递进来的参数

     
      /// <summary>
            /// 将window对象传递进来
            /// </summary>
            /// <param name="obj">The obj.</param>
            public void SetHtml(object obj)
            {
                html = (mshtml.HTMLWindow2Class)obj;
            }

    在页面中调用ActiveX的公开方法,传递当前window对象进去:
     

     
    window.onload = function() {
                document.HelloBossma.SetHtml(this);
            };

    (3)在ActiveX控件中添加一个按钮,当点击这个按钮时,触发页面中的javascript。

    点击按钮的方法:

     
    /// <summary>
            /// 调用页面Javascript
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void button1_Click(object sender, EventArgs e)
            {
      
                html.execScript("CallByActiveX();""javascript");
            }

    现在卸载掉原来的ActiveX控件,安装新的控件,打开页面,点击按钮,看到如下效果,说明成功。

    调用javascript时还可以传递参数,这里不做演示了,自己可以试一下。

    参考:http://www.cnblogs.com/liubiqu/articles/92632.html

    2、方法二

    (1)在VS项目中添加Com对象引用:Microsoft Html Object Library(mshtml.tlb)

    和第一种方法相同。

    (2)用c#实现两个COM类,IOleClientSite和IOleContainer

     
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;
      
    namespace HelloBossma
    {
        [ComImport,
         Guid("00000118-0000-0000-C000-000000000046"),
         InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IOleClientSite
        {
            void SaveObject();
            void GetMoniker(uint dwAssign, uint dwWhichMoniker, object ppmk);
            void GetContainer(out IOleContainer ppContainer);
            void ShowObject();
            void OnShowWindow(bool fShow);
            void RequestNewObjectLayout();
        }
      
        [ComImport,
         Guid("0000011B-0000-0000-C000-000000000046"),
         InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IOleContainer
        {
            void EnumObjects([In, MarshalAs(UnmanagedType.U4)] int grfFlags,
                [Out, MarshalAs(UnmanagedType.LPArray)] object[] ppenum);
            void ParseDisplayName([In, MarshalAs(UnmanagedType.Interface)] object pbc,
                [MarshalAs(UnmanagedType.BStr)] string pszDisplayName,
                [Out, MarshalAs(UnmanagedType.LPArray)] int[] pchEaten,
                [Out, MarshalAs(UnmanagedType.LPArray)] object[] ppmkOut);
            void LockContainer([In, MarshalAs(UnmanagedType.I4)] int fLock);
        }
    }

    (3)在ActiveX中编写CallJavascript方法:

     
    /// <summary>
            /// 调用Javascript
            /// </summary>
            /// <param name="Filenames">The filenames.</param>
     private void CallJavaScript(string param)
            {
                //反射获取当前的控件的ClientSite
                Type typeIOleObject = this.GetType().GetInterface("IOleObject"true);
                object oleClientSite = typeIOleObject.InvokeMember("GetClientSite",
                BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public,
                null,
                this,
                null);
      
                //获取Container
                IOleClientSite oleClientSite2 = oleClientSite as IOleClientSite;
                IOleContainer pObj;
                oleClientSite2.GetContainer(out pObj);
      
                //参数数组  
                object[] args = new object[1];
                args[0] = param;
      
                //获取页面的Script集合  
                IHTMLDocument pDoc2 = (IHTMLDocument)pObj;
                object script = pDoc2.Script;
      
                try
                {
                    //调用JavaScript方法OnScaned并传递参数,因为此方法可能并没有在页面中实现,所以要进行异常处理  
                    script.GetType().InvokeMember("ShowNowTime", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public,
                   null,
                    script,
                    args);
                }
                catch { }
            }

    点击按钮时的操作:

    /// <summary>
            /// 调用Javascript
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void button1_Click(object sender, EventArgs e)
            {
                           CallJavaScript(this.label2.Text);
            }

    (4)网页中的javascript

     
    function ShowNowTime(nowtime) {
                alert("当前时间:" + nowtime);
            }

    卸载原来的ActiveX控件,重新安装,实际效果:

    参考:http://blog.csdn.net/sabty/archive/2009/05/10/4165342.aspx

    这篇文档到这里就结束了,关于这两个方法的使用,如果有问题,欢迎和我交流!

     

    Visual Studio 2008(c#)开发ActiveX控件及制作CAB包总结(3)

    分类: C#

    这篇文章将介绍ActiveX版本更新的方法,参考了我最初文章中一位朋友的回复中的方法。通过设置注册表中的的ActiveX的版本(InstalledVersion)来维护更新。

    1、更新Activex的版本:

    (1)在ActiveX项目上点右键,属性,应用程序,程序集信息,最初的版本是1.0.0.0,修改为1.0.1.0

    (2)修改控件,以区别1.0.0.0版本,修改V1.0.0为V1.0.1

    (3)然后重新生成。
    2、修改安装程序

    (1)添加注册表项

    在项目上点右键,视图,注册表:

    在HKEY_CLASSES_ROOT下创建CLSID/{ActiveX的GUID}/InstalledVersion/,

    在InstalledVersion下新建字符串值,修改字符串的值为”1,0,1,0″,

    注意:删除名称中的值,自动会显示“(默认值)”,这样才能设置注册表中默认值,不要自己输入“默认值”。

    (2)修改安装程序版本

    修改Version为”1.0.1″,修改RemovePreviousVersions为”True”。

    (3)重新生成安装程序

    3、重新制作CAB安装包

    cabarc n HelloBossma.cab HelloBossmaSetup.msi install.inf

    4、修改网站

    (1)将生成的CAB安装包替换原来的安装包。

    (2)修改页面控件版本

    [html] view plaincopy
     
    1. <object classid="clsid:636B8CE1-7512-464C-B63C-FC75BDCA21DB" codebase="hellobossma/HelloBossma.CAB#version=1,0,1,0" width="442" height="116" id="HelloBossma" name="HelloBossma">  
    2.         </object>  

    5、最终效果

    刷新页面,提示安装新的版本,直接安装就好了。

     

    Visual Studio 2008(c#)开发ActiveX控件及制作CAB包总结(4)

    分类: C#

    这一节将测试ActiveX控件在新版操作系统上运行的问题,并提出解决的办法。主要是ActiveX程序兼容性和CAB文件的安装问题。我在Vitual PC上安装了Windows 7,并且使用IE8浏览器。

    1、测试环境:Windows 7 + IE8

    2、修改之前,直接访问页面看看,发现出错了:

    出错行:document.HelloBossma.SetTime(vYear + “-” + vMon + “-” + vDay + ” ” + vHour + “:” + vMin + “:” + vSec)

    然后到控制面中没有找到安装的ActiveX程序,结合出错行,大致得出结论:ActiveX没有安装成功!

    3、修改文件

    install.inf:

     
    [version]
    signature="$CHICAGO$"
    AdvancedINF=2.0
      
    [Setup Hooks]
    hook1=hook1
      
    [Deployment]
    InstallScope=machine
      
    [hook1]
    run=%EXTRACT_DIR%/run.bat

    新加[Deployment],关于这个项目看:http://msdn.microsoft.com/zh-cn/library/dd433049(en-us,VS.85).aspx

    InstallScope=machine 我这里只能用这个,改成user无法安装成功,原因未知。

    另外在vista以后的版本只能执行cab中的文件了,所以msiexec转移到了bat中执行,添加一个bat文件。

    run.bat:

     
    set CURDIR=%cd%
    msiexec.exe /i "%CURDIR%/HelloBossmaSetup.msi" /qn

    4、制作CAB包

    重新制作CAB包,添加一个run.bat:

     
    cabarc n HelloBossma.cab HelloBossmaSetup.msi install.inf run.bat

    5、在浏览器安装

    输入网址,提示安装,然后出现命令运行框,然后消失。

    如果安装成功,会出现控件界面。

    6、一个兼容性问题

    这时候会发现,浏览器左下角有javascript错误,同时点击Call Javascript发生异常。

    无法将类型为“Systerm._ComObject ”的COM对象强制转换为类类型“mshtml.HTMLWindow2Class”。

    在XP、Windows Server 2003中都没有问题,Windows 7上出现问题,可能是权限设置问题。

    按照上边的提示,找到出现问题的地方:

    Default.aspx:

     
    window.onload = function() {
                document.HelloBossma.SetHtml(this);
            };

    HelloBossmaActiveX.cs

     
    public void SetHtml(object obj)
            {
    //问题出在这里,类型转换的问题
                html = (mshtml.HTMLWindow2Class)obj;
            

    按照提示,我们可以把它转换为接口试试,在网上找到了HTMLWindow2Class的定义,

     
    public class HTMLWindow2Class : System.__ComObject, MSHTML.IHTMLFramesCollection2, MSHTML.IHTMLWindow2, mshtml.IHTMLWindow3, mshtml.IHTMLWindow4, mshtml.DispHTMLWindow2, mshtml.HTMLWindowEvents_Event, mshtml.HTMLWindowEvents2_Event, mshtml.HTMLWindow2
    {
    }

    经过测试,IHTMLWindow2定义了execScript,所以修改SetHtml为:

     
    private mshtml.IHTMLWindow2 html = null;
    public void SetHtml(object obj)
            {
                 html = obj as mshtml.IHTMLWindow2;
            }

    如果你需要其它的方法,换换接口试试。

    重新编译,重新安装控件,OK了!

    转自:http://blog.bossma.cn/dotnet/visual-studio-2008-csharp-activex-summary-4/

  • 相关阅读:
    #一点杂记
    《洛谷P3373 【模板】线段树 2》
    《Codeforces Round #681 (Div. 2, based on VK Cup 2019-2020
    《牛客练习赛72C》
    《hdu2819》
    《hdu2818》
    《Codeforces Round #680 (Div. 2, based on Moscow Team Olympiad)》
    《51nod1237 最大公约数之和 V3》
    对输入的单词进行排序
    快速排序
  • 原文地址:https://www.cnblogs.com/net-study/p/3894931.html
Copyright © 2020-2023  润新知