【问题标题】:C# COM Object In VBA: Function or interface marked as restricted, or the function uses an Automation type not supported in Visual BasicVBA 中的 C# COM 对象:函数或接口标记为受限,或者函数使用 Visual Basic 不支持的自动化类型
【发布时间】:2011-08-15 23:01:47
【问题描述】:

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
}

【问题讨论】:

  • 我得到了同样的结果。有人有什么想法吗?

标签: c# vba com


【解决方案1】:

我在周末回来工作后对此事进行了一些研究,显然 VBA 无法与 .NET 相处是问题所在。根据this MSDN articlethis DevX forum thread 中的说明,它似乎不喜欢通过引用传递数组的方法参数,而是希望它们通过值传递。在那篇 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]);
}

【讨论】:

    猜你喜欢
    • 2014-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-29
    • 1970-01-01
    • 2012-02-07
    • 1970-01-01
    相关资源
    最近更新 更多