Dav*_*ang 5 .net c# vb6 com-interop
我注意到,如果我有一个 .NET Framework 4.8 程序集公开了一个采用参数的 COM 互操作方法System.Collections.ArrayList,然后从 VB6 调用该方法,则 .NET 方法将获取 的副本,而不是传递的ArrayList原始副本:在 VB6 对象与 .NET 对象上返回不同的值,并且如果 .NET 方法修改,则不会对 VB6 端的对象进行修改。ArrayListGetHashCode()ArrayList
但是,如果在 .exe.config 文件中添加一个<startup useLegacyV2RuntimeActivationPolicy="true">部分,它会按预期工作:GetHashCode()在 VB6 和 .NET 端返回相同的值,并且在 VB6 端可以看到 .NET 方法所做的修改。
为什么会出现这种情况?有没有办法让它按照我期望的方式工作而无需设置useLegacyV2RuntimeActivationPolicy="true"?(我可以将其设置为 true;我主要好奇为什么需要这样做才能使其工作)
细节:
我在 .NET 端有这个,在项目构建配置上检查了“注册 COM 互操作”。
using System.Collections;
using System.Runtime.InteropServices;
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class ItemAdder
{
public int AddItem(ArrayList ar)
{
ar.Add("def");
return ar.GetHashCode();
}
}
Run Code Online (Sandbox Code Playgroud)
在 VB6 端,创建项目,添加对 的项目引用C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.tlb,并将其放入模块中:
Option Explicit
Sub Main()
Dim al As New ArrayList
Dim adder As New ItemAdder
Dim msg As String
al.Add "abc"
msg = "HashCode in VB6 is: " & al.GetHashCode() & vbCrLf
msg = msg & "HashCode in .NET is: " & adder.AddItem(al) & vbCrLf
msg = msg & "Item was " & IIf(al.Count <= 1, "not ", "") & "added"
MsgBox msg
End Sub
Run Code Online (Sandbox Code Playgroud)
以及 .exe.config 文件(如果从 VB6 IDE 运行,则可以将其用作 VB6.exe.config,或者如果 VB6 项目编译为 EXE,则将其用作该 EXE 的 .config 文件):
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
</configuration>
Run Code Online (Sandbox Code Playgroud)
如果useLegacyV2RuntimeActivationPolicy="true",MsgBox 将显示两个 HashCode 相等,并且该项目已添加。如果useLegacyV2RuntimeActivationPolicy="false",MsgBox 显示不同的 HashCode,并且该项目未添加。
这是因为从 COM 的角度来看,ArrayList是基于旧版本的 .NET Framework 构建的。
\n64 位中的 ArrayList COM 注册位于基于 .NET Framework 2 构建的 mscorlib.dll 中:\n
32 位(在 64 位系统上)的 ArrayList COM 注册位于基于 .NET Framework 1 构建的 mscorlib.dll 中:\n
因此,如果您使用 .NET Framework 4 构建 .dll,并从 VB6(32 位)调用它,您将在同一进程中混合不同版本的 mscorlib(此处为 4 和 1),这会产生问题。
\n正如element的官方文档中所述<supportedRuntime>
\n\n如果您的应用程序使用旧版激活路径 [...] 并且您希望这些路径激活 CLR 版本 4 而不是早期版本,或者您的应用程序是使用 .NET Framework 4 构建的,但依赖于\n对于使用早期版本的 .NET Framework 构建的混合模式程序集,\n在支持的运行时列表中指定 .NET Framework 4 是不够的。此外,在配置文件的元素中,您必须将属性设置
\nuseLegacyV2RuntimeActivationPolicy为true。[...]
这基本上是一个“神奇”开关,如下所述:What is useLegacyV2RuntimeActivationPolicy for?
\n\n\n该
\nuseLegacyV2RuntimeActivationPolicy属性基本上可以让您\n说,\xe2\x80\x9c我对旧版 shim API 有一些依赖。请让\n它们按照所选运行时的习惯方式工作。
也来自同一链接:
\n\n\n最终,此属性与 \xe2\x80\x9clegacy\nshim APIs\xe2\x80\x9d 的行为有关。您可以将它们视为包含\nCLR 激活的几个类别:
\n[...]
\nv4 之前的 COM 激活 \xe2\x80\x93 这包括 CLSID(或类型标识符)的 CoCreateInstance,其最新注册是针对 v4 之前的运行时版本的。请注意,这包括来自托管代码的此类共同类上的 \xe2\x80\x9cnew\xe2\x80\x9d 运算符,或针对此类 CLSID 上由 Type.GetTypeFromCLSID 创建的类型的 Activator.CreateInstance 的结果。
\nv4 之前的 IJW(混合模式)\n激活 \xe2\x80\x93 例如,调用此类\n程序集中的本机导出
\n本机运行时提供的 COM CLSID \xe2\x80\x93\n例如 ICLRRuntimeHost\xe2\x80\x99s CLSID 上的 CoCreateInstance 的本机激活
\n托管框架 CLSID \xe2\x80\x93 的本机激活,例如\nSystem.ArrayList\xe2\x80\x99s CLSID 上的 CoCreateInstance(极其罕见)
\n
| 归档时间: |
|
| 查看次数: |
177 次 |
| 最近记录: |