按照网上的资料做的ActiveX控件,所有的文件在一个程序集中时,可以在html页面使用<object/>引入。但现在又在此ActiveX控件库中添加了一个新的控件,在这个控件中引用了另一个控件库中自定义的控件,这样在使用<object/>指定clsid时,在设计界面显示"The control is not installed or could not be displayed.",运行时也无法显示。
一开始怀疑是否是与自定义控件库中的控件的COM互操作有关,因此,在自定的控件库中的每一个引用到的控件及相关的类中添加了ComVisible(true)与ClassInterface(ClassInterfaceType.AutoDispatch)。但即使这样做了,还是不奏效。
实在不知是什么原因了,请高手路过赐教一下下,先谢了!
假设A,B两个控件,A引用B,那么A,B都需要在操作系统注册过。
你可以先手工注册B,确保B已经正确注册,然后再测试下。
你好,是使用regasm /codebase进行注册吗?
@TigerSpringLiu: 是的。
@TigerSpringLiu: 我突然想起一个问题,托管的COM组件不能以COM引用的形式在托管代码中调用。也就是说,如果B是一个COM组件,A引用的B的形式和引用普通程序集是一样的。你可能需要把B程序集加载到本地系统的GAC中。
@Launcher: 你好,试过了,好像都不行呢>_<!
在控件类中添加ComVisible(true)难道没有注册到操作系统吗?我查看注册表,都有对应的注册表项和CLSID的。
什么是COM组件呢,.NET中的控件库应该是属于COM组件的吧,因为一些资料上是这么说来着。而且将B加到GAC中我觉的似乎没有必要呢,因为是同一个项目的引用。.NET Framework 有它的寻找程序集的算法,只有在所有的文件夹中都找不到目标程序集时,才会到GAC中寻找。同一个项目的引用不是已经在文件夹中包含了B吗?
还请大侠替小生想想办法呢,是不是还有其他要注意的?谢谢了!
@TigerSpringLiu: ActiveX是COM组件技术的一种。你的 A ActiveX控件会被从你的部属地址下载后存放在系统盘的C:\Windows\Downloaded Program Files目录下(好像是这个目录,是不是这个目录,你可以通过在注册表中查找它的 Codebase 值来定),然后你这个 A 引用了程序集 B,那么按照你所说的寻找程序集的算法,它会先去C:\Windows\Downloaded Program Files目录下查找B程序集,然后再去GAC中找。
虽然同一个项目的引用已经在文件夹中包含了B,但是下载的时候并没有打包在一起。我记得已经做MFC的ActiveX控件时,为了保证客户机上安装有mfcx.dll,是可以将引用的第三方dll打包在cab中的。
@TigerSpringLiu: http://blog.csdn.net/yimiyangguang1314/article/details/6563540
@Launcher: 是的,打包发布以后是安装在C:\Windows\Program Files中,如果是64位系统会安装在C:\Windows\Program Files(x86)。我以前的一个版本就是这样的。那时并没有引用其他的控件库,一切运行正常。只是有一个实体类用于数据传输的,我将他封装成一个Model程序集打包时让它安装在客户端GAC文件夹中,因为ActiveX控件是浏览器运行的,浏览器会在当前目录中寻找此数据实体类,这是浏览器需要用到的,但我无法将Model安装到浏览器所在的文件夹。
现在的问题不是发布以后的问题,而是开发时就出现问题了:aspx页面“设计时”无法预览ActiveX控件,但是没有引用外部控件库的可以预览。
@TigerSpringLiu: 你可以先测试下,Model.dll 放在那个目录下的时候,你的ActiveX控件能够正常使用,这是第一步,第二步才是考虑如何在ActiveX安装的时候自动安装 Model.dll 的问题。
@Launcher: 大侠,不是啦,我说Model只是说这个数据类有必要放在GAC中的,因为浏览器需要使用到它。但自定义控件库B没有必要放在GAC中,因为一旦客户端下载安装ActiveX控件A,B必然会安装在同一个目录的。而且这个Model已经测试成功了。
@TigerSpringLiu: 你的B是页面里另一个控件,还是说你的页面只有A一个控件,B 就跟System.Windows.Forms.dll 程序集一样被A引用而已?
@Launcher: 是的,只有一个A,B是A的子控件
@TigerSpringLiu: 那么你在网页中直接指定A的clsid就行了,然后B就同System.Windows.Forms.dll一样放在A的相同目录或GAC中,A不就能引用到了吗?
@Launcher: 就因为这样不行我才被搞得莫名其妙啊!
@TigerSpringLiu: 你可以尝试手动将B注册到GAC中测试下,这和引用 System.Windows.Forms.dll的道理是一样的。另外,你需要先把B的引用去掉,以确定你的A控件首先能够在IE中正常显示。
@Launcher: 功夫不负有心人,总算解决了!
因为不引用外部控件库控件时ActiveX可以正常显示,因此我觉得还是程序集的一些问题。
所以使用Reflector查看了System.Windows.Forms.dll的程序集特性,并且将我的自定义控件库的特性与System.WindowsForms.dll的特性比较了一下,不包含的相关特性都添加了一遍,可是还是没有用。最后又将这些不同的特性添加到了ActiveX控件库中,总算成功了,关键的一个特性:SecurityRules(SecurityRuleSet.Level1, SkipVerificationInFullTrust = true)。虽然添了这个特性解决了问题,但还是稀里糊涂啊,查看了msdn的解释:
http://msdn.microsoft.com/zh-cn/library/bb397858(v=vs.100).aspx
应仅出于兼容性目的而指定 1 级透明度;也就是说,仅为使用 .NET Framework 3.5 或以前的版本(使用 AllowPartiallyTrustedCallersAttribute 或不使用透明度模型)开发的代码指定 1 级透明度。 例如,为允许来自部分信任的调用方 (APTCA) 的调用的 .NET Framework 2.0 程序集使用 1 级透明度。 为 .NET Framework 4 开发的代码始终使用 2 级透明度。 |
开发的ActiveX控件库确实添加了AllowPartiallyTrustedCallersAttribute。
又是.NET的代码安全问题,看样子要好好研究研究呢。
多谢Launcher,以后还多多请教!