Following Explained is the issue I was facing for COM-.Net Interop:
I have created a COM server in which a collection of vectors need to be exposed to C# sharp client . Each vector contains a array of structures and this vector need to be embedded inside a container, say another vector or list.Since STL classes are not accessible in C#, I used a SAFEARRAY and VARIANT for exposing them. But I am not successful because of the following reason .
1) I am not able to create a VARIANT array of structures.
2) I created a SAFEARRAY of structures and included it in a VARIANT, but when accessed in C# as Object, I am not able to get the structure. Though I am able to typecast it into a Object array , but if accessed in separte gives exception.
3) I am able to access the members of the structure as they are string but not a STRUCTURE as a whole.
4) I tried containing a VARIANT of SAFEARRAY'S in another VARIANT, but it gives a casting error.
5) CComVariant cannot have USD's and VARIANT if used has some problem of Memory Leaks.
Please let me know if you have expertise in COM and C#.Net Interoperability. or Even if you have some alternate solution for this problem?
Solution I found for this problem:
Step 1) Creating a COM Server and expose the vectorAs I have explained in the problem description it is not directly possible to expose std::vector through COM as it std::vector is not a feasible datatype for the IDL file and C Sharp Client.One Approach is to go for a flat file or an XML file where you can dump the vector and access it from the client. I feel that usage of a flat file or an XML file is not a suitable approach. So I selected the following explained approach. I have added demo code to do it, but it is completely for prototyping and none of the coding standards are considered.
1) Add the structure( in my case its all homogenous datatype) elements into a SAFEARRAY of type BSTR.
[code]
.h : CComSafeArray
.cpp :
void CArrayManager::AddStruct(STAGE_STRUCT myStruct)
{
m_structarray.Add(myStruct.myName);
m_structarray.Add(myStruct.myLocation);
[/code]
2) Create another SAFEARRAY of type VARIANT
[code]
.h : CComSafeArray
continuation of previous funtion:
.cpp:
m_sarray.Add(CComVariant(m_structarray));
}
[/code]
in the Interface add another funtion that can retrieve the array in the form of VARIANT
[code]
.idl file:
[id(6), helpstring("method GetStructArray")] HRESULT GetStructArray([out] VARIANT* pvar);
.cpp File :
STDMETHODIMP CArrayManager::GetArray(VARIANT* pvar)
{
CComVariant var(m_sarray);
var.Detach(pvar);
return S_OK;
}
[/code]
Now our COM server is ready with GetArrayFuntion exposing the VARIANT of m_sarray we have created for containing the structures.
SAFEARRAYS could be used directly, but it may lead to memory leaks.
If you are interested you can see this example code (not considered in my explained implementation but i tried using this in another funtion.. it is working fine with IRecordInfo):
[code]
SAFEARRAY *psa;
SAFEARRAYBOUND sab = {2, 0};
MyStruct *pData;
IRecordInfo *pRI;
HRESULT hr;
hr = GetRecordInfoFromGuids(LIBID_AtlSafeArrayLib, 1, 0, 0x409, __uuidof(MyStruct), &pRI);
psa = SafeArrayCreateEx(VT_RECORD, 1, &sab, pRI);
pRI->Release();
pRI = NULL;
hr = SafeArrayAccessData(psa, (void**)&pData);
pData[0].nLongValue = 1;
pData[0].bstrStringValue = SysAllocString(L"First");
pData[1].nLongValue = 2;
pData[1].bstrStringValue = SysAllocString(L"Second");
hr = SafeArrayUnaccessData(psa);
CComVariant var(psa);
var.Detach(pvar);
[/code]
Step 2) In C# Client
[code]
AtlSafeArrayLib.ArrayManagerClass myObj = new AtlSafeArrayLib.ArrayManagerClass();
System.Object myArray;
myObj.GetStructArray(out myArray);
Object[] obj = myArray as Object[];
foreach (Object[] o in obj)
{
string[] strArray = new string[o.Length];
strArray = o as string[];
foreach (string s in strArray)
{
Console.WriteLine(s);
}
}
[/code]
No comments:
Post a Comment