Access SafeArray VT_UNKNOWN correctly with SafeArrayGetElement

We have a COM component, the whos implementation and the interface definition exist in managed code, but are managed by their own component. The managed component returns SafeArray

back to native code with the following method declaration.

interface IExample {
  <return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_UNKNOWN)>
  object[] DoSomeOperation()
}

      

The generated self signature correctly passes this back as SafeArray

.

While looking at the code though, we came up with some questions about calling the resulting array with SafeArrayGetElement. The problem is whether SafeArrayGetElement returns an instance IUnknown

that is AddRef'd or not. Basically it boils down to which of the following is correct.

Example 1:

CComPtr<IUnknown> spUnk;
hr = SafeArrayGetElement(pArray, &bounds, reinterpret_cast<void**>(&spUnk));

      

Example 2:

IUnknown* pUnk;
hr = SafeArrayGetElement(pArray, &bounds, reinterpret_cast<void**>(&pUnk));

      

The documentation is very thin on this matter. It only includes the next line.

If the data item is a string, object, or variant, the function copies the item correctly.

The definition of correctness is a bit ambiguous.

+2


source to share


2 answers


The first method should be correct and will match object handling throughout COM, apparently the definition you found makes the assumption that the consumer knows the correct path.

The other points mentioned require this. Copying a VARIANT or SAFEARRAY carries an implicit AddRef () when they contain objects. VARIANT does not require this when VT_BYREF is present.

VariantCopy @MSDN
SafeArrayCopy @MSDN

This behavior is not intrinsic to SAFEARRAY or VARIANT, as it is part of the COM parameter handling rules. However, there is nothing to prevent someone from trying to circumvent the rules.

For input parameters, it is not responsible for the AddRef () request if they do not intend to store the interface pointer for future use. However, other use cases for parameters require this.

For example, interfaces hosted in VARIANT or other containers must have at least one AddRef () call, otherwise it would create problems when using VARIANT as out parameters from COM methods, since data / reference transfer is one-way. The original object may expire by the time a call arrives at the destination. Likewise, AddRef () is also required to marshal an interface to a stream.



Likewise, calling by reference requires at least one AddRef call. If it is not, then any suitable long-term call (say, via DCOM) may not arrive at its destination with the assurance that the referenced object is still alive. However, Extra AddRef () / Release () calls are often overlooked here as the object must already be in 1+ due to being created in or before the calling area.

If it is possible to modify a component and your calls are in progress, then it might be desirable to use GIT. This allows you to pass a token instead, and it will be easier to bundle the interface through COM flats. The lifetime of the objects involved becomes the caller's responsibility for the duration of the call, and you can fool cases where the object cannot be marshaled.

Create the @MSDN global interface table

Also of interest is the footnote for BSTR.

If a function implementation that accepts a reference BSTR parameter assigns a new BSTR to that parameter, it must release the previously reserved BSTR.

String manipulation functions (COM)

+2


source


It should be AddRef: ed, but I don't have first-hand information on what is in this case (for example, I haven't read the source).

I think the documentation is pretty clear though - copying the interface pointer correctly is AddRef: ing.



If you want to be sure, create a super simple ATL COM object that implements IUnknown

, adds a few of them at, SAFEARRAY

and puts a breakpoint at CComObjectBase<>::InternalAddRef

(if my memory serves). Then debug the call SafeArrayGetElement

and see if your breakpoint succeeded.

+1


source







All Articles