Quantcast
Channel: Common Language Runtime Internals and Architecture forum
Viewing all articles
Browse latest Browse all 1710

Pass struct array from COM object to C# with SAFEARRAY

$
0
0
 Hi All,

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

Viewing all articles
Browse latest Browse all 1710

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>