【问题标题】:Is it possible to mark an ActiveX object as safe so that IE settings need not be changed?是否可以将 ActiveX 对象标记为安全以便无需更改 IE 设置?
【发布时间】:2014-01-15 11:29:04
【问题描述】:

我创建了一个启动应用程序的 ActiveX dll 程序集。我在浏览器中通过 JavaScript 调用了这个 dll。该应用程序在点击 URL 时启动。

要让这个脚本工作,我需要进入 IE 设置并启用“初始化和脚本未标记为安全的 activex 控件”。有没有办法对 ActiveX 对象进行编码以将其标记为安全?

我用SN工具生成了一个key(.snk文件),用这个key编译了DLL。因此,该 dll 已签名,但它不会运行,除非我在 IE 设置中启用“初始化并编写未标记为安全的脚本 Activex 控件”。

这是我已经实现并希望将其标记为安全的文章:- Writing an ActiveX control in C#

我在 this microsoft link:-

上获得了对安全控制概念 (IObjectSafety) 的参考

我无法理解该代码需要放在哪里。任何帮助都会使其更清楚..

【问题讨论】:

    标签: c# .net internet-explorer activex .net-assembly


    【解决方案1】:

    我从不同的地方收集了一些代码(和知识),这是我的工作版本 - 界面

        [Serializable, ComVisible(true)]
        public enum ObjectSafetyOptions
        {
            INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001,
            INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002,
            INTERFACE_USES_DISPEX = 0x00000004,
            INTERFACE_USES_SECURITY_MANAGER = 0x00000008
        }
    
        //
        // MS IObjectSafety Interface definition
        //
        [
            ComImport(),
            Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064"),
            InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
        ]
        public interface IObjectSafety
        {
            [PreserveSig]
            long GetInterfaceSafetyOptions(ref Guid iid, out int pdwSupportedOptions, out int pdwEnabledOptions);
    
            [PreserveSig]
            long SetInterfaceSafetyOptions(ref Guid iid, int dwOptionSetMask, int dwEnabledOptions);
        }
    
    • 和实施

          #region safe for scripting
          private ObjectSafetyOptions m_options = ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_CALLER | ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_DATA;
          public long GetInterfaceSafetyOptions(ref Guid iid, out int pdwSupportedOptions, out int pdwEnabledOptions)
          {
              pdwSupportedOptions = (int)m_options;
              pdwEnabledOptions = (int)m_options;
              return 0;
          }
      
          public long SetInterfaceSafetyOptions(ref Guid iid, int dwOptionSetMask, int dwEnabledOptions)
          {
              return 0;
          }
          #endregion safe for scripting
      

    现在 IE 不会用确认对话框来唠叨我了。

    【讨论】:

      【解决方案2】:

      以下链接有一个完美的示例,它是创建以及将 activeX 控件标记为安全的答案:-Creating activex objects with c#

      用c#创建activex对象

      本指南的目的是提供简单的步骤 创建一个可以在 IE 中加载和使用的简单 ActiveX 控件 托管网页。

      背景

      ActiveX 是一种 Microsoft 技术,用于创建 可重复使用的组件。这种技术,也称为对象链接和嵌入 (OLE) 以及 COM 在 Microsoft 环境中被大量使用,并且 应用程序开发。在本文中,我将使用该术语 COM 包含所有类似的 Microsoft 相关技术:ActiveX、OLE、 自动化等……因为它是创建组件的框架。任何人 对创建可重用组件感兴趣的应该熟悉 通讯。一个非常好的资源是 Don Box 的“Essential COM”。

      COM 背后的想法是允许创建组件 可以被各种客户消费。这意味着我可以创建一个 使用 C++ 的组件,然后可以由用 VB 编写的应用程序使用,或 甚至是我们将很快执行的网页。传统上,ActiveX 对象通常用 C++ 和 VB 编写,但实际上可以用任何 语言,只要它们能够识别 COM。

      这意味着我们可以使用 .NET 创建 COM 对象 平台。和 large 只告诉你如何通过 Interop 使用非托管 COM 对象。所以我的目标 本指南旨在展示如何使用这个强大的功能。另外,仅供参考,有 一种 .NET 技术,与下面将要描述的非常相似,它允许 在 IE 中托管 Windows 窗体控件(不知道官方术语/名称 为此)。

      废话不多说,让我们开始示例吧。

      要求

      • 熟悉 C#。
      • 开发环境。我将使用 Visual Studio

        1. (2003 应该也可以。不过不知道速成版。)
      • HTML、Javascript

      • IE。 ActiveX 对象不能托管在任何其他 浏览器。

      创建 ActiveX 控件

      第一步是创建一个 C# DLL 项目。这可以是 完成以下步骤:

      1. 启动 Visual Studio
      2. 选择文件 -> 新建项目
      3. 为项目类型选择“其他语言”->“Visual C#”
      4. 选择“类库”模板

      创建项目后,继续重命名 Class1.cs 随心所欲。我将其重命名为 HelloControl.cs

      我们将创建的 ActiveX 控件是无处不在的 你好世界!代码和解释如下。

      HelloControl.cs

          using System;
      using System.Runtime.InteropServices;
      using System.ComponentModel;
      using System.Collections.Generic;
      using System.Text;
      
      namespace csharp.activex.sample
      {
          /// <summary>
          /// A very simple interface to test ActiveX with.
          /// </summary>
          [
              Guid( "E86A9038-368D-4e8f-B389-FDEF38935B2F"),
              InterfaceType( ComInterfaceType.InterfaceIsDual),
              ComVisible( true)
          ]
          public interface IHello
          {
              [DispId(1)]
              string Hello();
      
              [DispId(2)]
              int ShowDialog(string msg);
          };
      
          [
              Guid("873355E1-2D0D-476f-9BEF-C7E645024C32"),
      
              // This is basically the programmer friendly name
              // for the guid above. We define this because it will
              // be used to instantiate this class. I think this can be
              // whatever you want. Generally it is
              // [assemblyname].[classname]
              ProgId("csharpAx.CHello"),
      
              // No class interface is generated for this class and
              // no interface is marked as the default.
              // Users are expected to expose functionality through
              // interfaces that will be explicitly exposed by the object
              // This means the object can only expose interfaces we define
              ClassInterface(ClassInterfaceType.None),
      
              // Set the default COM interface that will be used for
              // Automation. Languages like: C#, C++ and VB
              // allow to query for interface's we're interested in
              // but Automation only aware languages like javascript do
              // not allow to query interface(s) and create only the
              // default one
              ComDefaultInterface(typeof(IHello)),
              ComVisible(true)
          ]
          public class CHello : IHello
          {
      
              #region [IHello implementation]
              public string Hello()
              {
                  return "Hello from CHello object";
              }
      
      
              public int ShowDialog(string msg)
              {
                  System.Windows.Forms.MessageBox.Show(msg, "");
                  return 0;
              }
              #endregion
          };
      }
      

      HelloControl.cs 文件由一个类和一个接口组成。 那么让我们从接口定义开始,接着是 CHello 类。

      IHello 接口

      接口通常被描述为契约。一旦设计了界面 并发布使用它不应该改变。让我重复一遍,它 永远不会改变。

      已经为这个接口定义了几个属性。

      1) Guid – 这是一个唯一标识符。使用 guidgen.exe 生成自己的 2) InterfaceType – 这决定了向 COM 公开哪个基类。

      InterfaceType 属性需要进一步解释。这是它的定义方式。

      public enum ComInterfaceType
      {
          InterfaceIsDual = 0,
          InterfaceIsIUnknown = 1,
          InterfaceIsIDispatch = 2,
      }
      

      所有 COM 接口和对象必须至少继承 IUnknown 接口(见附录 A)。该接口允许客户端创建 COM 对象通过 CoCreateInstance() 并搜索其他接口以及 处理对象生命周期管理。

      IDispatch 接口只允许在自动化感知中使用对象 像javascript这样的语言(见附录B)。这个接口,允许客户端 应用程序来查询对象在运行时支持的属性和方法- 时间并执行它们。这很像 .Net 中的反射。

      Dual 仅表示上述两者的组合。这样做的主要原因是 允许在没有 IDispatch 的所有开销的情况下创建接口 在不需要的情况下。

      最后,您会注意到 IHello 中每个方法的 DispId(#) 属性 界面。从 IDispatch 接口调用 Invoke 时需要这样做。

      CHello 类

      最后要讨论的是 CHello 类。这个类简单实现 IHello 接口仅此而已。 ShowDialog() 只是表明我们可以 执行需要某种 UI 的对象,在本例中为消息框。 属性在 cmets 中进行了描述。

      编译和注册

      编写完代码后,继续编译 ActiveX 程序集。 该程序集将在项目的 bin 文件夹中称为 [projectname].dll。

      下一步是注册。这样做会打开一个命令提示符并转到 dll的位置。注册程序集类型:

      C:\Regasm [项目名称].dll /codebase /tlb

      确保将“[projectname]”替换为您的 dll 的正确名称。 您应该得到一些输出,表明程序集已正确导出。 类似于以下内容。

      Microsoft ® .NE​​T Framework 程序集注册实用程序 2.0.50727.42 版权所有 © 微软公司 1998-2004。版权所有。 类型注册成功 程序集导出到 '[TLB 位置] ',类型库注册成功

      要取消注册程序集,请将“/unregister”标志传递给 Regasm。您将需要 当需要对程序集进行更改时,取消注册并关闭 IE。如果你不 在进行代码更改之前取消注册您的程序集,您最终可能会得到虚假 注册表项和清理的痛苦。关闭 IE 的原因是为了确保 对您的程序集的所有引用都已被释放。

      创建 HTML 测试页

      我们即将完成。我们现在需要做的就是创建一个测试页面。 这应该很简单,但仍然如此。 Javascript 还提供了创建 ActiveX 对象的方法。

      Test.html

      <html xmlns="http://www.w3.org/1999/xhtml">
      <head> <title>C# ActiveX Test</title> </head>
      
      <body onload="myload();">
      <h1>This is Our ActiveX Test Page h1>
      
      The message from the ActiveX Control is [
      <div id="axmsg"></div>
      ]
      
      <script type ="text/javascript">
      function myload()
      {
          var myAx = new ActiveXObject("csharpAx.CHello");
          if(myAx != null)
          {
              myAx.ShowDialog("hello from asp.net"); 
              var d = document.getElementById("axmsg");
      
              var s = myAx.Hello();
              d.outerText = s;
          }
          else
              lert("NOOOO... we failed");
      }
      </script>
      </body></html>
      

      要在 Javascript 中创建我们的 ActiveX 对象,我们使用 ActiveXObject()。参数 因为这通常是我们在其定义中指定的 PROGID。如果一个 PROGID 未在其定义中指定,那么我认为您可以传入 “AssemblyName.ClassName”。其余的 javascript 只是简单地调用我们的 ActiveX 对象方法。

      就是这样!!!我们应该有一个功能齐全的例子。这种执行 ActiveX 的能力 来自 javascript 的对象非常强大。关于安全的辩论和争论 ActiveX 对象的安全性是众所周知的,我不会再扔更多的饲料 到火。但是,想象一下创建一个 Win32 甚至是 Winform 应用程序 UI 是通过 IWebBrowser2 用 HTML 编写的,并且所有 UI 交互都已处理 与您的 ActiveX 对象,只是深思熟虑。虽然,现在想起来, WPF 已经在这样做了。哦,好吧。

      希望这份关于如何使用 C# 创建 ActiveX 对象的指南对您有所帮助。

      -skaoth-

      进一步修改

      上面的例子虽然完整(希望没有错误),但有一个小问题。当html页面是 加载后我们得到一个讨厌的消息框说

      “此页面上的 ActiveX 控件可能不安全……等等等等”

      那么我们该如何解决这个问题呢?好吧,这真的很简单。我们需要实现一个接口 称为 IObjectSafety。为此,请将新的 .cs 文件添加到项目中。

      IObjectSafety.cs

      using System;
      using System.Collections.Generic;
      using System.Runtime.InteropServices;
      using System.ComponentModel;
      using System.Text;
      
      namespace csharp.activex.sample
      {
          [
              Serializable,
              ComVisible(true)
          ]
          public enum ObjectSafetyOptions
          {
              INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001,
              INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002,
              INTERFACE_USES_DISPEX = 0x00000004,
              INTERFACE_USES_SECURITY_MANAGER = 0x00000008
          };
      
          //
          // MS IObjectSafety Interface definition
          //
          [
              ComImport(),
              Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064"),
              InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
          ]
          public interface IObjectSafety
          {
              [PreserveSig]
              long GetInterfaceSafetyOptions( ref Guid iid, out int pdwSupportedOptions, out int pdwEnabledOptions);
      
              [PreserveSig]
              long SetInterfaceSafetyOptions( ref Guid iid, int dwOptionSetMask, int dwEnabledOptions);
          };
      
          //
          // Provides a default Implementation for
          // safe scripting.
          // This basically means IE won't complain about the
          // ActiveX object not being safe
          //
          public class IObjectSafetyImpl : IObjectSafety
          {
              private ObjectSafetyOptions m_options =
                  ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_CALLER | 
                  ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_DATA;
      
              #region [IObjectSafety implementation]
              public long GetInterfaceSafetyOptions( ref Guid iid, out int pdwSupportedOptions, out int pdwEnabledOptions)
              {
                  pdwSupportedOptions = (int)m_options;
                  pdwEnabledOptions = (int)m_options;
                  return 0;
              }
      
              public long SetInterfaceSafetyOptions(ref Guid iid, int dwOptionSetMask, int dwEnabledOptions)
              {
                  return 0;
              }
              #endregion
          };
      }
      

      然后修改CHello对象,使其继承自IObjectSafetyImpl 类,使其看起来像

      public class CHello : IObjectSafetyImpl, IHello
      {
      …
      };
      

      这样,关于 ActiveX 对象不安全的对话框应该会消失。

      参考文献

      ATL 内部 - Brent E. Rector,Chris Sells。 Essential COM – Don Box。

      http://msdn2.microso...yw6(VS.80).aspx http://msdn2.microso...y/aa768224.aspx http://www.c-sharpco...tiveXInNet.aspx

      附录 A:未知

      interface IUnknown
      {
      virtual HRESULT QueryInterface(REFIID riid, void **ppvObject) = 0;
      virtual ULONG AddRef(void) = 0;
      virtual ULONG Release(void) = 0;
      
      };
      

      附录 B:IDispatch

      interface IDispatch : public IUnknown
      {
      virtual ULONG GetTypeInfoCount(unsigned int FAR* pctinfo) = 0;
      virtual HRESULT GetTypeInfo(unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo ) = 0;
      virtual ULONG GetIDsOfNames(
      REFIID riid,
      OLECHAR FAR* FAR* rgszNames,
      unsigned int cNames,
      LCID lcid,
      DISPID FAR* rgDispId) = 0;
      virtual ULONG Invoke(
      DISPID dispIdMember,
      REFIID riid,
      LCID lcid,
      WORD wFlags,
      DISPPARAMS FAR* pDispParams,
      VARIANT FAR* pVarResult,
      EXCEPINFO FAR* pExcepInfo,
      unsigned int FAR* puArgErr) = 0;
      }; 
      

      【讨论】:

      • 贴出的链接建议的解决方案对我不起作用,我还是要修改IE配置
      猜你喜欢
      • 2012-08-24
      • 2011-03-03
      • 1970-01-01
      • 2013-06-29
      • 1970-01-01
      • 2011-05-28
      • 2021-11-13
      • 1970-01-01
      • 2011-01-19
      相关资源
      最近更新 更多