以下链接有一个完美的示例,它是创建以及将 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
- (2003 应该也可以。不过不知道速成版。)
HTML、Javascript
- IE。 ActiveX 对象不能托管在任何其他
浏览器。
创建 ActiveX 控件
第一步是创建一个 C# DLL 项目。这可以是
完成以下步骤:
- 启动 Visual Studio
- 选择文件 -> 新建项目
- 为项目类型选择“其他语言”->“Visual C#”
- 选择“类库”模板
创建项目后,继续重命名 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 ® .NET 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;
};