【问题标题】:Confused about data types in COM, VFP and C#对 COM、VFP 和 C# 中的数据类型感到困惑
【发布时间】:2013-09-07 14:30:06
【问题描述】:

我即将从 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 无效的原因是什么?感谢您的任何想法!

【问题讨论】:

  • 从 VFP 调用此类时是否收到“函数参数值、类型或计数无效”
  • 是的。我在从 VFP 调用时收到此消息,但仅限于 GetAnyLong() 和 GetAnyDouble()。

标签: c# .net com-interop foxpro visual-foxpro


【解决方案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);
};

【讨论】:

    【解决方案2】:

    我也有同样的问题。接口中的小数表示为 wchar_t,但正确的行为是将其导出为有效 COM 类型的 DECIMAL。

    DECIMAL 数据类型的有效值比 CURRENCY 多。因此,只有当数据是货币时,转换为 CURRENCY 才会有所帮助。对于其他类型的数据,CURRENCY 太浅了。

    Microsoft 记录了十进制不应该在导出界面中专门标记。 Here is the description, and DECIMAL type is described as a special type.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-02
      • 1970-01-01
      • 1970-01-01
      • 2014-12-21
      • 1970-01-01
      • 2013-12-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多