Here's my problem:
- I have a com object which does some processing, and the results must be saved in a SAFEARRAY;
- there is another module written in c# which needs to pick up that vector and display it;
- After the call, I'm getting the following exception:
<code>
System.ArgumentException: The specified record cannot be mapped to a managed value class.
at Interop.TESTLib.objClass.Extract(Int32 a, Int32 b, Int32 c, IF[]& array)
...
</code>
- IF is intended to be a container of different objects in its VARIANT property (feat), and the type of the object (internal type, actually, not the system type) is stored in type property;
- I need to pick up an array of such data. For the moment, all items in IF[] array returned by Extract method are all the same, but there are chances the array to be extended;
Here are some code snippets:
IDL:
<code>
typedef enum tagDataType
{
A = 1,
B = 2,
} tagDataType;
typedef
[
uuid(7C52726D-5206-46b3-BBAC-68B47ACE5823),
version(1.0),
helpstring("A structure for passing extracted data.")
]
struct IF {
tagDataType type;
VARIANT feat; // can contain another struct like IF_b declared below, or IF_c, etc.
} IF;
typedef
[
uuid(F065E4EB-B216-4476-A01E-70CF2F37E216),
version(1.0),
helpstring("B-type data")
]
struct IF_b {
int left;
int top;
int height;
int width;
int child_no;
} IF_b;
[
object,
uuid(5787EF4E-07BA-4bf0-AC8B-E661CAC34DDE),
dual, oleautomation,
helpstring("Iobj Interface"),
pointer_default(unique)
]
interface Iobj : IDispatch {
[id(1), helpstring("Extract specified data")] HRESULT Extract([in] int a,[in]int b, [in] int c, [in,out] SAFEARRAY(IF) *array);
}
</code>
in C++:
<code>
static const GUID IID_IF_b = { 0xF065E4EB, 0xB216, 0x4476, { 0xA0, 0x1E, 0x70, 0xCF, 0x2F, 0x37, 0xE2, 0x16 } };
template <class T> BOOL convertStructToVariant(VARIANT& var, const T& s, IID guid)
{
CComPtr<IRecordInfo> pRecInfo;
HRESULT hr;
hr = GetRecordInfoFromGuids(LIBID_TESTLib, 1, 0, GetUserDefaultLCID(), guid, &pRecInfo) );
VariantClear(&var);
var.vt = VT_RECORD;
var.pvRecord = pRecInfo->RecordCreate();
var.pRecInfo = pRecInfo.Detach();
*((T*)var.pvRecord) = s;
return TRUE;
}
STDMETHODIMP obj::Extract(int a,/*in */ int b, /*in */ int c, /*[in, out] */ SAFEARRAY** array) {
std::vector<IF> v_arr;
// vector is populated here
SAFEARRAYBOUND sab = {v_arr.size(), 0};
CComQIPtr<IRecordInfo> pRI = (IRecordInfo*)NULL;
CComQIPtr<ITypeLib> pTypelib = (ITypeLib*)NULL;
CComQIPtr<ITypeInfo> pTypeInfo = (ITypeInfo*)NULL;
HRESULT hr;
IF *pData = NULL;
hr = LoadRegTypeLib(LIBID_TESTLib, 1, 0, GetUserDefaultLCID(), &pTypelib);
hr = pTypelib->GetTypeInfoOfGuid(IF_IID, &pTypeInfo);
hr = GetRecordInfoFromTypeInfo(pTypeInfo, &pRI);
*array = SafeArrayCreateEx(VT_RECORD, 1, &sab, pRI);
hr = SafeArrayAccessData(*array, reinterpret_cast<PVOID*>(&pData));
for (int k=0; k<v_arr.size(); k++)
{
CComVariant var;
if (!convertStructToVariant<IF_b>(var, ifb, IID_IF_b)) {
printf("error");
continue;
}
var.Detach(&pData[k].feat);
}
return S_OK;
}
</code>
in c#:
<code>
// in interop - auto-generated definition
[Guid("7C52726D-5206-46b3-BBAC-68B47ACE5823")]
public struct IF
{
public object feat;
public tagDataType type;
}
[Guid("F065E4EB-B216-4476-A01E-70CF2F37E216")]
public struct IF_b
{
public int child_no;
public int height;
public int left;
public int top;
public int width;
}
// and in my code:
Interop.TESTLib.objClass my_object = new Interop.TESTLib.objClass();
IF[] data = null;
// here I am receiving the exception described above
my_object.Extract(1, 2, 3, ref data);
</code>
I have done some diggings over the web, but nothing - at least not yet. I have found an old KB-article (http://support.microsoft.com/default.aspx?scid=kb;en-us;309329) but it reffers to .net 1.1. I am using .net 3.5 sp1.
Can anyone help me? Why am I getting this weird exception?
P.S. Sorry for this long post. I had to provide some code-snippets.
DC