C#COM对象在VBA中:标记为受限制的函数或接口,或者该函数使用Visual Basic中不支持的自动化类型

时间:2011-08-10 21:35:00

标签: c# vba com

my other question出现新问题:尝试访问X12Segment的Fields属性时出现名义错误。

我遇到this question here并主动获取我的X12类型库的IDL。还附加了我的界面中的Fields属性的声明及其实现;是什么导致了这个错误?

// Generated .IDL file (by the OLE/COM Object Viewer)
// 
// typelib filename: <could not determine filename>

[
  uuid(C0634D32-97A5-413A-8FC8-D6E0F4571F42),
  version(1.0),
  custom(90883F05-3D28-11D2-8F17-00A0C9A6186D, "X12, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")

]
library X12
{
    // TLib :     // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
    importlib("mscorlib.tlb");
    // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
    importlib("stdole2.tlb");

    // Forward declare all types defined in this typelib
    interface IX12Segment;

    [
      odl,
      uuid(28A76274-05EE-45B2-A8EF-ADD5A5B351DE),
      version(1.0),
      dual,
      oleautomation,
      custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "X12.IX12Segment")    

    ]
    interface IX12Segment : IDispatch {
        [id(0x00000001), propget]
        HRESULT SegmentType([out, retval] BSTR* pRetVal);
        [id(0x00000001), propput]
        HRESULT SegmentType([in] BSTR pRetVal);
        [id(0x00000002), propget]
        HRESULT Fields([out, retval] SAFEARRAY(BSTR)* pRetVal);
        [id(0x00000002), propput]
        HRESULT Fields([in] SAFEARRAY(BSTR) pRetVal);
        [id(0x00000003), propget]
        HRESULT FieldDelimiter([out, retval] BSTR* pRetVal);
        [id(0x00000003), propput]
        HRESULT FieldDelimiter([in] BSTR pRetVal);
        [id(0x00000004), propget]
        HRESULT SegmentDelimiter([out, retval] BSTR* pRetVal);
        [id(0x00000004), propput]
        HRESULT SegmentDelimiter([in] BSTR pRetVal);
        [id(0x00000005), propget,
          custom(54FC8F55-38DE-4703-9C4E-250351302B1C, 1)]
        HRESULT ToString([out, retval] BSTR* pRetVal);
        [id(0x00000006)]
        HRESULT GetFieldEnum([out, retval] _Type** pRetVal);
    };

    [
      uuid(B321599A-E5EC-4510-A021-E9A8B4D6293E),
      version(1.0),
      custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "X12.X12Segment")
    ]
    coclass X12Segment {
        interface _Object;
        [default] interface IX12Segment;
    };
};
[Guid("28A76274-05EE-45B2-A8EF-ADD5A5B351DE"),
ComVisible(true)]
public interface IX12Segment
{
    //More stuff goes here
    [DispId(2)]
    string[] Fields { get; set; }
    //More stuff goes here
}

[Guid("B321599A-E5EC-4510-A021-E9A8B4D6293E"),
ClassInterface(ClassInterfaceType.None),
ComVisible(true)]
public class X12Segment : IX12Segment
{
    protected ArrayList _fields;
    protected short _minFields = -1;
    protected short _maxFields = -1;
    protected short[][] _fieldSizes = { new short[] { -1, -1 } };

    //More stuff goes here

    /// <summary>
    /// Gets or sets all of the fields in the segment,
    /// in the form of an array of strings.
    /// </summary>
    public string[] Fields
    {
        get
        {
            string[] o = new string[_fields.Count];
            for (int i = 0; i < o.Length; i++)
            {
                o[i] = _fields[i].ToString();
            }
            return o;
        }
        set
        {
            ArrayList newFields = new ArrayList(value.Length);
            for (int i = 0; i < value.Length; i++)
                if (_fieldSizes[0][0] == -1 || value[i].Length <= _fieldSizes[i][1])
                    newFields.Add(value[i].ToCharArray());
                else
                    throw new Exception("Attempt to store a value longer than the possible field size: \""
                        + value[i] + "\" is larger than " + _fieldSizes[i] + " characters long.");
        }
    }

    //More stuff goes here
}

1 个答案:

答案 0 :(得分:1)

我在周末回来工作后做了一些关于此事的研究,显然VBA不与.NET相处就是问题。根据{{​​3}}并在this MSDN article中说明,似乎它不喜欢带有通过引用传递的数组的方法参数,并希望它们通过值传递。在MSDN文章中有一个解决VB.NET代码的方法,你只需告诉它按值传递设定值,但是在C#中定义访问器的参数似乎不可能。

我的解决方案是使Fields属性为只读,并且具有单独的方法来设置单个元素或整个shebang。

//Added these to the interface.
[DispId(aNumber)]
void SetField(int index, string value);
[DispId(aNumber)]
void SetFields(ref string[] fields);

//Added these two methods to the class,
//and removed the set accessor from the Fields property

/// <summary>
/// Set a field at the given index with a given value.
/// </summary>
/// <param name="index">Zero-based index of the field to set.</param>
/// <param name="value">The value to set the field with.</param>
public void SetField(int index, string value)
{
    if (_fieldSizes[0][0] == -1 ||
            (value.Length > _fieldSizes[index][0] && value.Length < _fieldSizes[index][1]))
        _fields[index] = value.ToCharArray();
    else
        throw new ArgumentException("value", "Attempt to set a field with a value longer or shorter than the expected length.");
}

/// <summary>
/// Sets all the fields with the values in an array.
/// </summary>
/// <param name="fields">An array of strings containing the values.</param>
public void SetFields(ref string[] fields)
{
    for (int i = 0; i < fields.Length; i++)
        SetField(i, fields[i]);
}