是否可以将ActiveX对象标记为安全,以便不需要更改IE设置?

问题描述 投票:1回答:2

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

要使此脚本正常工作,我需要转到IE设置并启用“初始化并编写未标记为安全的activex控件”。有没有办法编写ActiveX对象以将其标记为安全?

我使用SN工具生成密钥(.snk文件),使用此密钥编译DLL。因此,dll已签名,但它不会运行,除非我在IE设置中启用“初始化和脚本activex控件未标记为安全”。

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

我在this microsoft link上引用了安全控制概念(IObjectSafety): -

我无法理解这个代码需要放在哪里。任何帮助都会使它更清晰..

c# .net internet-explorer activex .net-assembly
2个回答
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不会在确认对话框中唠叨我。


1
投票

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

使用c#创建activex对象

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

背景

ActiveX是一种用于创建可重用组件的Microsoft技术。此技术(也称为对象链接和嵌入(OLE))与COM一起在Microsoft环境和应用程序开发中大量使用。在本文的持续时间内,我将使用术语COM来涵盖所有类似的Microsoft相关技术:ActiveX,OLE,自动化等...因为它是创建组件的框架。任何对创建可重用组件感兴趣的人都应该熟悉COM。一个非常好的资源是Don Box的“Essential COM”。

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

这意味着我们可以使用.NET平台创建COM对象。互联网上关于COM和.NET的资源/教程的调查仅告诉您如何通过Interop使用非托管COM对象。因此,本指南的目的是展示如何使用这个强大的功能。此外,仅供参考,有一种.NET技术非常类似于下面将要描述的内容,它允许在IE中托管Windows窗体控件(不知道这个的官方术语/名称)。

这足以让我们开始讨论这个例子。

要求

  • 熟悉C#。
  • 发展环境。我将使用Visual Studio (2003年也应该有效。但不知道快递版。)
  • HTML,Javascript
  • IE浏览器。 ActiveX对象无法在任何其他浏览器中托管。

创建ActiveX控件

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

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

创建项目后,继续将Class1.cs重命名为您想要的任何内容。我将其重命名为HelloControl.cs

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

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)。此接口允许客户端通过CoCreateInstance()创建COM对象,并搜索其他接口以及处理对象生存期管理。

IDispatch接口允许对象仅用于自动识别语言,如javascript(参见附录B)。此接口允许客户端应用程序在运行时查询对象支持的属性和方法并执行它们。这非常像.Net中的Reflection。

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

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

CHello课程

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

编译和注册

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

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

C:\ Regasm [projectname] .dll / codebase / tlb

确保使用正确的dll名称替换“[projectname]”。您应该得到一些输出,说明程序集已正确导出。像下面这样的东西。

Microsoft®.NETFramework程序集注册实用程序2.0.50727.42版权所有©Microsoft Corporation 1998-2004。版权所有。成功注册的类型程序集导出到“[TLB位置]”,并且类型库已成功注册

要取消注册程序集,请将“/ unregister”标志传递给Regasm。当需要对程序集进行更改时,您需要取消注册并关闭IE。如果在进行代码更改之前未取消注册程序集,则最终可能会出现伪造的注册表项并且无法清理。关闭IE的原因是为了确保已释放对程序集的所有引用。

创建HTML测试页面

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

的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对象方法。

而已!!!我们应该有一个功能齐全的例子。这种从javascript执行ActiveX对象的能力非常强大。关于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 Internals - Brent E. Rector,Chris Sells。基本COM - 唐盒。

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

附录A:IUnknown

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;
}; 
© www.soinside.com 2019 - 2024. All rights reserved.