我即将从VFP迁移到C#,但我对数据类型有点困惑。我知道我可以使用CLSCompliant属性来确保我的数据类型是有效的COM类型。但是我们采取以下几种方法:
[assembly: CLSCompliant(true)]
namespace SampleNSpace {
[ComVisible(true)]
[Guid("111B0014-EB08-4093-A818-1D11EB4C489D")]
public class AnyClass {
public int GetAnyInt() { return int.maxValue; }
public long GetAnyLong() { return long.maxValue; }
public decimal GetAnyDecimal() { return decimal.maxValue; }
public double GetAnyDouble() { return double.maxValue; }
}
}
好的,调用GetAnyInt()按预期工作,返回值暴露的时间很长(如http://msdn.microsoft.com/en-us/library/sak564ww.aspx中所述)。但调用GetAnyLong()和GetAnyDouble()不起作用,我目前不知道为什么。我总是得到“函数参数值,类型或计数无效。”我首先想到的是,原因是double和long是8字节/ 64位长(因为VFP中的最大精确数是2 ^ 53),但是调用GetAnyDecimal()没有任何错误,并且十进制长8字节(128位)总体)。任何人都知道DECIMAL的工作原理是什么,而double / long不是?感谢您的任何想法!
答案 0 :(得分:1)
首先,CLSCompliant
属性与COM没有任何关系。它适用于公共语言运行时compliance。
OLE自动化规范列出了types which are automation-compatible。
您的C#类如果编译为32位程序集并在RegAsm中注册,则会公开以下COM接口:
[
odl,
uuid(AFA13243-F593-3B28-A4D3-4E4138AA1F22),
hidden,
dual,
nonextensible,
oleautomation,
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "SampleNSpace.AnyClass")
]
interface _AnyClass : IDispatch {
[id(00000000), propget,
custom(54FC8F55-38DE-4703-9C4E-250351302B1C, 1)]
HRESULT ToString([out, retval] BSTR* pRetVal);
[id(0x60020001)]
HRESULT Equals(
[in] VARIANT obj,
[out, retval] VARIANT_BOOL* pRetVal);
[id(0x60020002)]
HRESULT GetHashCode([out, retval] long* pRetVal);
[id(0x60020003)]
HRESULT GetType([out, retval] _Type** pRetVal);
[id(0x60020004)]
HRESULT GetAnyInt([out, retval] long* pRetVal);
[id(0x60020005)]
HRESULT GetAnyLong([out, retval] int64* pRetVal);
[id(0x60020006)]
HRESULT GetAnyDecimal([out, retval] wchar_t* pRetVal);
[id(0x60020007)]
HRESULT GetAnyDouble([out, retval] double* pRetVal);
};
我不确定int64
是否被视为自动化兼容(它不包含在我上面提到的列表中),但double
当然是自动化兼容的。因此,我怀疑它可能是VFP方面的一个问题。要解决此问题,您可以尝试更改C#类的定义,以便对这些类型使用object
。另请注意MarshalAs(UnmanagedType.Currency)
如何用decimal
作为OLE CURRENCY
类型进行编组。
[assembly: CLSCompliant(true)]
namespace SampleNSpace
{
[ComVisible(true), ClassInterface(ClassInterfaceType.AutoDual)]
[Guid("111B0014-EB08-4093-A818-1D11EB4C489D")]
public class AnyClass
{
public int GetAnyInt() { return int.MaxValue; }
[return: MarshalAs(UnmanagedType.Struct)]
public object GetAnyLong() { return long.MaxValue; }
[return: MarshalAs(UnmanagedType.Currency)]
public decimal GetAnyDecimal() { return decimal.MaxValue; }
[return: MarshalAs(UnmanagedType.Struct)]
public object GetAnyDouble() { return double.MaxValue; }
}
}
这会使用VARIANT
生成以下COM接口,我希望将其与VFP一起使用是理所当然的:
[
odl,
uuid(671A483A-5327-391A-AF09-4D734F9DFDCF),
hidden,
dual,
nonextensible,
oleautomation,
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "SampleNSpace.AnyClass")
]
interface _AnyClass : IDispatch {
[id(00000000), propget,
custom(54FC8F55-38DE-4703-9C4E-250351302B1C, 1)]
HRESULT ToString([out, retval] BSTR* pRetVal);
[id(0x60020001)]
HRESULT Equals(
[in] VARIANT obj,
[out, retval] VARIANT_BOOL* pRetVal);
[id(0x60020002)]
HRESULT GetHashCode([out, retval] long* pRetVal);
[id(0x60020003)]
HRESULT GetType([out, retval] _Type** pRetVal);
[id(0x60020004)]
HRESULT GetAnyInt([out, retval] long* pRetVal);
[id(0x60020005)]
HRESULT GetAnyLong([out, retval] VARIANT* pRetVal);
[id(0x60020006)]
HRESULT GetAnyDecimal([out, retval] CURRENCY* pRetVal);
[id(0x60020007)]
HRESULT GetAnyDouble([out, retval] VARIANT* pRetVal);
};
答案 1 :(得分:0)
我有同样的问题。接口中的小数表示为wchar_t,但正确的行为是将其导出为有效COM类型的DECIMAL。
DECIMAL数据类型的有效值多于CURRENCY。因此,只有数据是货币时,转换为CURRENCY才有用。对于其他类型的数据,CURRENCY太浅。
Microsoft文档中,不应在要导出的接口中专门标记十进制。 Here is the description, and DECIMAL type is described as a special type.