I am having an issue using a .NET/ComVisible assembly in Excel/VBA. I defined several parameters as "object" in .NET so they will be translated to Variant in VBA since optional parameters in VBA need to use Variant types.
The problem is when I try to use the object in Excel/VBA, I get a "Run-time error '424': Object required". I think I am missing attributes in the C# interface that would add a 'propput' method instead of the 'propputref' method that would allow values in Variants, but I haven't found any answers on the Internet just similar questions. I see System.Reflection.BindingFlags, but that only seems to work for compile-time and runtime code and not for interface definition.
The underlying data type is double and I need it to be null or a double through COM/VBA. I have no issues with the string parameters, just the variant/double.
Here is the C# interface:
[ComVisible(true)]
[Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface ISampleParameters
{
object GrossObservedValue { get; set; }
string TableName { get; set; }
// Rest of parameters removed for simplicity
}
Here is the C# object:
[ComVisible(true)]
[Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")]
[ClassInterface(ClassInterfaceType.None)]
public class SampleParameters : ISampleParameters
{
private double? grossObservedValue;
private string tableName;
public object GrossObservedValue
{
get
{
return grossObservedValue;
}
set
{
try
{
if (value == null)
grossObservedValue = null;
else
grossObservedValue = Convert.ToDouble(value);
}
catch
{
throw;
}
}
}
}
Here is the VBA usage:
Dim Parameters As New SampleParameters
Parameters.GrossObservedValue = 1.23
' Causes: Run-time error '424': Object required
Here is the Type Library IDL from OleView:
[
odl,
uuid(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX),
version(1.0),
dual,
oleautomation,
custom(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX, TempNamespace.ISampleParameters)
]
interface ISampleParameters : IDispatch {
[id(0x60020000), propget]
HRESULT GrossObservedValue([out, retval] VARIANT* pRetVal);
[id(0x60020000), propputref]
HRESULT GrossObservedValue([in] VARIANT pRetVal);
[id(0x60020001), propget]
HRESULT TableName([out, retval] BSTR* pRetVal);
[id(0x60020001), propput]
HRESULT TableName([in] BSTR pRetVal);
};
It seems the only solution is to manually generate the IDL and then import it back into .NET as in this thread using VB.NET with VB6. Is that the only solution? This article on The Essentials for Using COM in Managed Code was also very good, but did not cover defining interfaces in .NET/C#.