Click here to Skip to main content
15,884,821 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Dear Friends!
I have problem while working with ATL(VS2008, C++).
I must use SAFEARRAY(IMyObject*)* parameters in idl file.
If SAFEARRAY(double)*, then use the CComSafeArray<double>..., but for interfaces or my structures, I don't know how to solve.
Thank you in advanced.

The idl file is...
C++
...

interface IMyObj2;
...

typedef struct SMyObj2{
    IMyObj2 * iobject;
}SMyObj2;

...

//.IMyObj2
[
	object,
	uuid(3454B81A-65A9-4F3E-8678-1D5F82B25837),
	oleautomation,
	nonextensible,
	helpstring("IMyObj2 Interface"),
	pointer_default(unique)
]
interface IMyObj2 : IUnknown{
	[propget, helpstring("property ID")] 
	HRESULT ID([out, retval] LONG* pVal);
	[propput, helpstring("property ID")] 
	HRESULT ID([in] LONG newVal);
};

...


[
	object,
	uuid(EF532C8B-12A9-4FEC-B91C-D7502FD68874),
	oleautomation,
	nonextensible,
	helpstring("IArrayMan3 Interface"),
	pointer_default(unique)
]

interface IArrayMan3 : IUnknown{
	[helpstring("method GetArray")] 
	HRESULT _stdcall GetArray2(SAFEARRAY(SMyObj2)* pArray);
	[helpstring("method PutArray")] 
	HRESULT _stdcall PutArray2(SAFEARRAY(SMyObj2) pArray);
};


C++ file...
C++
STDMETHOD(GetArray2)(SAFEARRAY** pArray)
{
	CComSafeArray<IUnknown*> ppp;//.Compile Okay.
//	CComSafeArray<SMyObj2, VT_VARIANT> arr;//.Compile Error
//      CComSafeArray<IMyObj2*> ttt;//.Compile Error
	return S_OK;
}
Posted

1 solution

Greetings!
First of all it is nessesary to get an info from type library using IRecordInfo interface:
C++
GUID GUID_SMyObj2 = __uuidof(SMyObj2);
HRESULT hr;
CComPtr<IRecordInfo> srecnfo;
hr = GetRecordInfoFromGuids(LIBID_MyLib /*here is your type lib identifier*/, 1, 0, 0, GUID_SMyObj2, &srecnfo);
if(FAILED(hr))
  _com_issue_errorex(hr, NULL, IID_NULL);

If this part will be successful, then it is possible to create a safearray or custom type:
C++
const LONG l_bound = 0, u_bound = 2;
LPSAFEARRAY lpSMyObj2 = SafeArrayCreateVectorEx(VT_RECORD, l_bound,
  u_bound - l_bound + 1, srecnfo);
if(!lpSMyObj2)
  _com_issue_errorex(E_FAIL, NULL, IID_NULL);

or access and use existing:
C++
//LPSAFEARRAY lpSMyObj2 got from somewhere
//getting bounds of array
  LONG l_bound = 0, u_bound = 0;
  HRESULT hr1 = SafeArrayGetLBound(lpSMyObj2, 1, &l_bound);
  HRESULT hr2 = SafeArrayGetUBound(lpSMyObj2, 1, &u_bound);
  if(FAILED(hr1) || FAILED(hr2) )
  {
      // handle an error
  }
  else
  { 
     ...
     SMyObj2 * pSMyObj2 = NULL;
     HRESULT hr = SafeArrayAccessData(lpSMyObj2, (void**)&pSMyObj2);
     if(FAILED(hr))
       _com_issue_errorex(hr, NULL, IID_NULL);
     ...
  }
  // modifying data if needed
  for(int i = l_bound; i <= u_bound - l_bound; i++)
  {
    // do something with pSMyObj2[i].iobject
  }
  ...
  // Releasing an array
  hr = SafeArrayUnaccessData(lpSMyObj2);
  if(FAILED(hr))
    _com_issue_errorex(hr, NULL, IID_NULL);

Please see http://msdn.microsoft.com/en-us/library/aa148975.aspx[^] for more details
 
Share this answer
 
v2
Comments
Mem 9021960 19-Sep-12 6:05am    
Very thanks!
But Isn't there the method using template class such that CComSafeArray?
And if client program need the SAFEARRAY(IMyObj*)* parameters, is there any problems?
skydger 19-Sep-12 7:05am    
As far as I know, CComSafeArray uses VARIANT subsets of data, but not user defined. Besides it is a template wrapper class of SAFEARRAY and could not be flexible enogh for all the cases. So I think that using it with user defined types is little bit tricky. But maybe there is a solution to do so.

As for your question about using SAFEARRAY(IMyObj*)* instead of structure: it is the same as described, and it is simplier, because you need to create instances only (CoCreateInstance(...)) and release them.
Mem 9021960 19-Sep-12 7:22am    
Dear Mr.skydger! I see.
As you see, I'm beginner at COM technology.
Thank you for your kindly help.
I often want your many help.
skydger 19-Sep-12 8:00am    
Sure, if it will be possible for me :)
I don't know, what is the structure of that interface (IMyObj2), but sometimes it is more convenient for me to create custom array interface (for example IMyObj2Collection) but not the safearray. If I need not just array of custom types, but something like map<,>.
Mem 9021960 19-Sep-12 20:29pm    
Of course, I made the three array structure, it is IMyObj2**, IMyObj2Collection*, SAFEARRAY(IMyObj2*)*.
The two methods using IMyObj2** and IMyObj2Collection was completed already.
But required items has SAFEARRAY(IMyObj2*)*.
IMyObj2's structure is simple.
For example, Point structure(double x, double y,...).
And if client program is coded by C#, What happens?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900