Som*_*ude 5 .net c# vb6 com ole
我正在致力于迁移使用 regsvr32 注册并主要在 vbscript 和 ASP Classic 中使用的旧版 VB6 COM 库。
新的 .NET 4.8 替代库已通过 regasm 注册。
一切都很好,直到我遇到了一些无法直接迁移的功能,因为我在这个领域没有足够的知识。
旧版 VB6 库具有以下 Typelibrary 代码(来自 OleView,为方便起见进行了缩减):
[id(0x00068), propget]
VARIANT_BOOL IncomeOverride([in] short index);
[id(0x00068), propput]
void IncomeOverride(
[in] short index,
[in] VARIANT_BOOL rhs
);
[id(0x00069), propget]
CY IncomeOverrideAmt([in] short index);
[id(0x00069), propput]
void IncomeOverrideAmt(
[in] short index,
[in] CY rhs
);
Run Code Online (Sandbox Code Playgroud)
调用者使用这些方法如下:
oTest.IncomeOverride(1) = True
oTest.IncomeOverrideAmt(1) = 12
Run Code Online (Sandbox Code Playgroud)
首先我尝试使用属性。但由于 C# 中没有可用的参数化属性,我不得不尝试如下方法:
[DispId(0x00068)]
bool IncomeOverride([In] short index);
[DispId(0x00068)]
void IncomeOverride([In] short index, [In] bool v);
[DispId(0x00069)]
decimal IncomeOverrideAmt([In] short index);
[DispId(0x00069)]
void IncomeOverrideAmt([In] short index, [In] decimal v);
Run Code Online (Sandbox Code Playgroud)
它可以编译,但不起作用,因为 regasm 在注册时发出警告并拒绝生成正确的 tlb。警告如下:
类型库导出器警告处理“TestLibrary”。警告:该类型指定了一个或多个重复的 DISPID。重复的 DISPID 被忽略。
生成的类型库远远不能满足需要:
[id(0x0001)]
VARIANT_BOOL IncomeOverride([in] short index);
[id(0x0002)]
void IncomeOverride_2(
[in] short index,
[in] VARIANT_BOOL v
);
[id(0x0003)]
CY IncomeOverrideAmt([in] short index);
[id(0x0004)]
void IncomeOverrideAmt_2(
[in] short index,
[in] CY v
);
Run Code Online (Sandbox Code Playgroud)
下一次迭代是使用索引器。
[DispId(0x00068)]
[System.Runtime.CompilerServices.IndexerName("IncomeOverride")]
bool this[short index]
{
[return: MarshalAs(UnmanagedType.Currency)]
get;
[param: In, MarshalAs(UnmanagedType.Currency)]
set;
}
[DispId(0x00069)]
[System.Runtime.CompilerServices.IndexerName("IncomeOverrideAmt")]
decimal this[short index]
{
[return: MarshalAs(UnmanagedType.Currency)]
get;
[param: In, MarshalAs(UnmanagedType.Currency)]
set;
}
Run Code Online (Sandbox Code Playgroud)
这实际上是一个很好的解决方案,但不幸的是它甚至无法编译,因为您不能在单个接口/类中拥有具有不同 IndexerName 值的多个索引器。
尝试适应此类功能的最后一次尝试是使用返回带有索引器的数组/对象的属性:
[DispId(0x00068)]
bool[] IncomeOverride { get; }
[DispId(0x00069)]
decimal[] IncomeOverrideAmt { get; }
[DispId(0x00068)]
SomeClassWithBoolIndexer IncomeOverride { get; }
[DispId(0x00069)]
SomeClassWithDecimalIndexer IncomeOverrideAmt { get; }
Run Code Online (Sandbox Code Playgroud)
它可以编译并注册,但由于它生成了不正确的类型库 - 它不能在 vbscript/VB6/ASP Classic 中使用。
那么问题来了——如何实现这样的功能呢?
还是只是模仿?
为 C# 库编写自定义 Typelibrary?
这是否可以通过 C# 的方式实现?
预先感谢。
更新:
在这里发现了类似的问题:How to make C# COM class supportparameterizedproperties from VB6
它实际上完成了大部分工作,但与该问题的作者不同 - 如果不使用 .Value 作为参数化属性,它就无法工作。
尝试深入研究并找出 VBscript 无法识别默认属性(值)的原因。除非这一切都像冠军一样顺利!
但是如果没有默认的属性识别,它就死了,因为需要重写大量的遗留代码......我们目前不需要二进制兼容,只是为了使后期绑定(vbscript)工作。
任何人都知道为什么它没有按预期工作?
更新2
好的,目前有两个主要解决方案(显然没有一个有效):
1.使用PropertyAccessor类
VB脚本:
Dim oTestObject: Set oTestObject = CreateObject("TestSharpLib.TestObject")
wsh.echo "oTestObject.IncomeOverride(1): [" & oTestObject.IncomeOverride(1) & "]" 'THIS LINE WORKS
oTestObject.IncomeOverride(1).Value = "True" 'THIS LINE WORKS
oTestObject.IncomeOverride(1) = "True" 'THIS LINE DOES NOT WORK
wsh.echo "oTestObject.IncomeOverride(1): [" & oTestObject.IncomeOverride(1) & "]"
Run Code Online (Sandbox Code Playgroud)
C#
using System;
using System.Runtime.InteropServices;
using TestVBNET;
namespace TestSharpLib
{
[ComVisible(true)]
[ProgId("TestSharpLib.TestObject")]
[Guid("49067FAC-A1B3-4469-9032-4E958AA7381C")]
public class TestObject: : ITestObject
{
public object IncomeOverride(short index)
{
return new PropertyAccessor(this, index);
}
public class PropertyAccessor
{
TestObject _owner;
short _index;
public PropertyAccessor(TestObject owner, short index)
{
_owner = owner;
_index = index;
}
[DispId(0)]
public string Value {
get => _index.ToString();
set { }
}
}
}
[ComVisible(true)]
[Guid("4C0FDA39-1027-415A-968C-9A6DF9BEB499")]
public interface ITestObject
{
[DispId(1)]
object IncomeOverride(short index);
}
}
Run Code Online (Sandbox Code Playgroud)
根据 Erik Lippert 的说法,似乎您不能省略 VBScript 中的默认属性。 https://learn.microsoft.com/en-us/archive/blogs/ericlippert/vbscript-default-property-semantics
2. 使用VB.NET中声明的接口
VB脚本:
Dim oTestObject: Set oTestObject = CreateObject("TestSharpLib.TestObject")
wsh.echo "oTestObject.IncomeOverride(1): [" & oTestObject.IncomeOverride(1) & "]" 'THIS LINE NOT WORKING
oTestObject.IncomeOverride(1) = "True" 'THIS LINE NOT WORKING
wsh.echo "oTestObject.IncomeOverride(1): [" & oTestObject.IncomeOverride(1) & "]"
Run Code Online (Sandbox Code Playgroud)
C#
using System;
using System.Runtime.InteropServices;
using TestVBNET;
namespace TestSharpLib
{
[ComVisible(true)]
[ProgId("TestSharpLib.TestObject")]
[Guid("49067FAC-A1B3-4469-9032-4E958AA7381C")]
public class TestObject: IIncomeOverride
{
public string get_IncomeOverride(int index)
{
return index.ToString();
}
public void set_IncomeOverride(int index, string Value)
{
//throw new NotImplementedException();
}
}
}
Run Code Online (Sandbox Code Playgroud)
网络
Imports System.Runtime.InteropServices
<ComVisible(True)>
<Guid("F40144F0-6BA1-4983-B6EE-D593CA0A2F75")>
Public Interface IIncomeOverride
<DispId(1745027127)>
Property IncomeOverride(ByVal index As Integer) As String
End Interface
Run Code Online (Sandbox Code Playgroud)
这个解决方案根本不起作用。尽管 regasm 说 dll 已注册并且 OleView 实际上显示了正确的类型库 - VBScript 根本看不到 IncomeOverride 属性。
c:\Users\Administrator\Desktop\test.vbs(2, 1) Microsoft VBScript runtime error: Object doesn't support this property or method: 'IncomeOverride'
Run Code Online (Sandbox Code Playgroud)
类型库:
[
uuid(f40144f0-6ba1-4983-b6ee-d593ca0a2f75),
dual,
oleautomation
]
interface IIncomeOverride : IDispatch#i {
[id(0x68030037), propget]
HRESULT IncomeOverride(
[in] long index,
[out, retval] BSTR* pRetVal
);
[id(0x68030037), propput]
HRESULT IncomeOverride(
[in] long index,
[in] BSTR pRetVal
);
};
[
uuid(f40144f0-6ba1-4983-b6ee-d593ca0a2f75),
dual
]
dispinterface IIncomeOverride {
methods:
**removed object methods***
[id(0x68030037), propget]
BSTR IncomeOverride([in] long index);
[id(0x68030037), propput]
void IncomeOverride(
[in] long index,
[in] BSTR rhs
);
};
Run Code Online (Sandbox Code Playgroud)
所以现在我仍在挖掘新的想法。主要令人失望的是 VBScript 没有看到已实现的(在 VB.NET 接口中声明的)属性/方法。
更新 3(最终解决方案) 经过一段时间的测试和研究,发现解决此问题的更简单且可能是最好的方法是使用 VB.NET 代理类,它模拟所有需要的接口,但将逻辑代理到 C# 类。
以这种方式实现它解决了所有问题。感谢大家的讨论和提出的解决方案。
我会将问题标记为已解决,并选择建议此解决方案的评论之一,但不能,因为评论已隐藏/删除。
| 归档时间: |
|
| 查看次数: |
119 次 |
| 最近记录: |