dotnet / sdk

Core functionality needed to create .NET Core projects, that is shared between Visual Studio and CLI
https://dot.net/core
MIT License
2.71k stars 1.07k forks source link

.NET to COM/ActiveX - params/ParamArray not supported for VB98/VB6 and earlier #44460

Open NETSphereSoft opened 1 week ago

NETSphereSoft commented 1 week ago

Describe the bug

We want to provide a .NET Framework library for VB98/VB6 developers and take advantage of ParamArray usage.

The standard translation from .NET params

[Description("Add item(s)")]
void Add(String item, params Object[] moreItems)

to IDL/TLB by TlbExp.exe is

[id(0x1), vararg, helpstring("Add item(s)")]
void Add([in] BSTR item, [in] SAFEARRAY(VARIANT) moreItems)

Which is seen in VB98/VB6 object catalog as

Sub Add(item As String, ParamArray moreItems() As Variant)

But this COM/ActiveX method signature is accessible with MSScriptControl.ScriptControl only, not with VB98/VB6. The compiler notices an error of incompatibility:

Image

For VB98/VB6 the following IDL/TLB method signature is required (reference of SAFEARRAY):

[id(0x1), vararg, helpstring("Add item(s)")]
void Add([in] BSTR item, [in] SAFEARRAY(VARIANT)* moreItems)

Our current workaround is to change the method signature in .NET:

[Description("Add item(s)")]
void Add(String item, [In] ref Object[] moreItems)

which get generated in IDL/TLB with no vararg, but SAFEARRAY reference:

[id(0x1), helpstring("Add item(s)")]
void Add([in] BSTR item, [in] SAFEARRAY(VARIANT)* moreItems)

Then we need manually to do the following process:

You can see this in the sample project:

To Reproduce

Possible solution

Add a ParamArrayRef attribute for placing at the parameter or method additionally to the standard params usage

[Description("Add item(s)")]
void Add(String item, [ParamArrayRef] params Object[] moreItems)

or

[Description("Add item(s)")]
[ParamArrayRef]
void Add(String item, params Object[] moreItems)  

And export then the IDL/TLB by TlbExp.exe with the requested method signature:

[id(0x1), vararg, helpstring("Add item(s)")]
void Add([in] BSTR item, [in] SAFEARRAY(VARIANT)* moreItems)

Alternately a solution with existing InAttribute and OutAttribute could be to get the same method signature like VB98/VB6 does:

[Description("Add item(s)")]
void Add(String item, [In, Out] params Object[] moreItems)

to lead into

[id(0x1), vararg, helpstring("Add item(s)")]
void Add([in] BSTR item, [in, out] SAFEARRAY(VARIANT)* moreItems)

And a much simplier could be (currently prevented from compiler):

[Description("Add item(s)")]
void Add(String item, [ParamArray] ref Object[] moreItems)

to lead into

[id(0x1), vararg, helpstring("Add item(s)")]
void Add([in] BSTR item, [in, out] SAFEARRAY(VARIANT)* moreItems)

Further technical details

Microsoft Visual Studio Professional 2019 Version 16.11.37 VisualStudio.16.Release/16.11.37+34931.43 Microsoft .NET Framework Version 4.8.09037

huoyaoyuan commented 1 week ago

First, the GitHub repos focus on .NET Core. .NET Framework specific issues should go to VS Developer Community, but this is a feature change that won't be accepted at all.

The topic about COM interop belongs to https://github.com/dotnet/runtime . The COM interop story are considered legacy and will be maintained focus on compatibility. ParamsArray is a .NET only concept and won't have any effect to COM. Changing the mapped COM type for params array is a breaking change and will definitely not happen. Using existing mechanisms with ref, [In] and [Out] is the only and expected solution.

It's especially a non-goal to incorporate new idiomatic in .NET with COM, especially VB6 which is more legacy and won't receive and feature change.