Reputation: 2275
Coming off of my other question with a new problem: I get the titular error when attempting to access my X12Segment's Fields property.
I came across this question here and took the initiative to get the IDL for my X12 type library. Also attached is the declaration of the Fields property in my interface, and its implementation; what's causing this error?
// 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
}
Upvotes: 1
Views: 2560
Reputation: 2275
I did some research on the matter after coming back to work off the weekend, and apparently VBA not getting along with .NET is the issue. According to this MSDN article and also stated in this DevX forum thread, it seems it doesn't like method parameters with an array passed by reference and wants them passed by value instead. There's a workaround for VB.NET code in that MSDN article where you simply tell it to pass the set value by value, but defining parameters for accessors in C# doesn't seem to be possible.
My solution was to make the Fields property be read-only, and have seperate methods for setting either a single element or the whole 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]);
}
Upvotes: 1