C#开发ActiveX控件一
前一段时间因项目需要,要把C#开发的Winfrom应用程序做成一个ActiveX控件,以便在IE中运行。网上关于C#写ActiveX控件的文章也不少,尽管用C#开发ActiveX控件有不少弊端,但项目的改写势在必行,也没有什么好的方法可以取代,用C#来改写还可以减少工作量,所以只好老老实实做下去。经过几天总算是完成任务了,中间也走了不少弯路,我把在项目改写过程中出现的问题记录下来,以供参考。
用C#开发ActiveX控件我主要参考红马的三篇文章,入门都是按照其文章上的步骤来的,几乎没有什么问题。但是要注意的是文章中的实现IObjectSafety接口有些问题,实现其接口后还是弹出窗口说ActiveX控件不是安全的。网上有正确的实现方法,我将其整理如下如下:
1[ComImport, GuidAttribute("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
2[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
3interface IObjectSafety
4{
5 [PreserveSig]
6 int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);
7 [PreserveSig()]
8 int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
9}
10
然后让你的ActiveX控件实现其接口,代码如下:
1#region 实现IObjectSafety接口
2private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";
3private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";
4private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";
5private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";
6private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}";
7
8private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;
9private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;
10private const int S_OK = 0;
11private const int E_FAIL = unchecked((int)0x80004005);
12private const int E_NOINTERFACE = unchecked((int)0x80004002);
13
14private bool _fSafeForScripting = true;
15private bool _fSafeForInitializing = true;
16//使ActiveX控件成为安全的控件
17public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
18{
19 int Rslt = E_FAIL;
20 string strGUID = riid.ToString("B");
21 pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
22 switch (strGUID)
23 {
24 case _IID_IDispatch:
25 case _IID_IDispatchEx:
26 Rslt = S_OK;
27 pdwEnabledOptions = 0;
28 if (_fSafeForScripting == true)
29 pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
30 break;
31 case _IID_IPersistStorage:
32 case _IID_IPersistStream:
33 case _IID_IPersistPropertyBag:
34 Rslt = S_OK;
35 pdwEnabledOptions = 0;
36 if (_fSafeForInitializing == true)
37 pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
38 break;
39 default:
40 Rslt = E_NOINTERFACE;
41 break;
42 }
43
44 return Rslt;
45 }
46
47 public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
48 {
49 int Rslt = E_FAIL;
50
51 string strGUID = riid.ToString("B");
52 switch (strGUID)
53 {
54 case _IID_IDispatch:
55 case _IID_IDispatchEx:
56 if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) && (_fSafeForScripting == true))
57 Rslt = S_OK;
58 break;
59 case _IID_IPersistStorage:
60 case _IID_IPersistStream:
61 case _IID_IPersistPropertyBag:
62 if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) && (_fSafeForInitializing == true))
63 Rslt = S_OK;
64 break;
65 default:
66 Rslt = E_NOINTERFACE;
67 break;
68 }
69
70 return Rslt;
71 }
72#endregion
73
另外需要注意的是,项目属性中,在“程序集信息”对话框中将“使程序集COM可见”复选框选上。属性“生成”卡中选中“为COM interop 注册”。
到此为止,用C#开发ActiveX控件基本上算是完成了,通过IE查看,可以看到效果。细节部分我没有写全,如有需要,可以参考红马文章:
http://www.cnblogs.com/homer/archive/2005/01/04/86473.html
http://www.cnblogs.com/homer/archive/2005/01/08/88780.html
http://www.cnblogs.com/homer/archive/2005/01/26/97822.html
用C#开发ActiveX控件我主要参考红马的三篇文章,入门都是按照其文章上的步骤来的,几乎没有什么问题。但是要注意的是文章中的实现IObjectSafety接口有些问题,实现其接口后还是弹出窗口说ActiveX控件不是安全的。网上有正确的实现方法,我将其整理如下如下:
1[ComImport, GuidAttribute("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
2[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
3interface IObjectSafety
4{
5 [PreserveSig]
6 int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);
7 [PreserveSig()]
8 int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
9}
10
然后让你的ActiveX控件实现其接口,代码如下:
1#region 实现IObjectSafety接口
2private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";
3private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";
4private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";
5private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";
6private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}";
7
8private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;
9private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;
10private const int S_OK = 0;
11private const int E_FAIL = unchecked((int)0x80004005);
12private const int E_NOINTERFACE = unchecked((int)0x80004002);
13
14private bool _fSafeForScripting = true;
15private bool _fSafeForInitializing = true;
16//使ActiveX控件成为安全的控件
17public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
18{
19 int Rslt = E_FAIL;
20 string strGUID = riid.ToString("B");
21 pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
22 switch (strGUID)
23 {
24 case _IID_IDispatch:
25 case _IID_IDispatchEx:
26 Rslt = S_OK;
27 pdwEnabledOptions = 0;
28 if (_fSafeForScripting == true)
29 pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
30 break;
31 case _IID_IPersistStorage:
32 case _IID_IPersistStream:
33 case _IID_IPersistPropertyBag:
34 Rslt = S_OK;
35 pdwEnabledOptions = 0;
36 if (_fSafeForInitializing == true)
37 pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
38 break;
39 default:
40 Rslt = E_NOINTERFACE;
41 break;
42 }
43
44 return Rslt;
45 }
46
47 public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
48 {
49 int Rslt = E_FAIL;
50
51 string strGUID = riid.ToString("B");
52 switch (strGUID)
53 {
54 case _IID_IDispatch:
55 case _IID_IDispatchEx:
56 if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) && (_fSafeForScripting == true))
57 Rslt = S_OK;
58 break;
59 case _IID_IPersistStorage:
60 case _IID_IPersistStream:
61 case _IID_IPersistPropertyBag:
62 if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) && (_fSafeForInitializing == true))
63 Rslt = S_OK;
64 break;
65 default:
66 Rslt = E_NOINTERFACE;
67 break;
68 }
69
70 return Rslt;
71 }
72#endregion
73
到此为止,用C#开发ActiveX控件基本上算是完成了,通过IE查看,可以看到效果。细节部分我没有写全,如有需要,可以参考红马文章:
http://www.cnblogs.com/homer/archive/2005/01/04/86473.html
http://www.cnblogs.com/homer/archive/2005/01/08/88780.html
http://www.cnblogs.com/homer/archive/2005/01/26/97822.html