Reputation: 1146
I have to write a COM server DLL (using ATL) that is called by the plugin interface of an old (closed-source) VB6 application and would like to avoid possible leaks (of course)! The interface description is given as-is and cannot be changed unfortunately:
The class method that will be called is declared on the VB side like this:
Public Function Process(data As Object,
Params As Variant,
Results() As Single) As Integer
The interface in IDL is declared like this:
[id(1)] HRESULT Process([in,out] IDispatch** pDataIDisp,
[in,out] VARIANT* pParamsVar,
[in,out] SAFEARRAY(FLOAT)* pResSA,
[out,retval] SHORT* pRetVal);
and finally the code that is called look like this:
STDMETHODIMP Analyzer::Process(IDispatch** pDataIDisp,
VARIANT* pParamsVar,
SAFEARRAY** pResSA,
SHORT* pRetVal)
{
try
{
// Prepare for access
CComPtr<IDispatch> dataComPtr = *pDataIDisp;
// VARTYPE from caller is VT_VARIANT | VT_ARRAY | VT_BYREF;
CComVariant prms = *pParamsVar; // OR use .Attach ?
CComSafeArray<VARIANT> prmsArr = prms.parray; // OR use prms.Attach ?
// SafeArray is FADF_HAVEVARTYPE
CComSafeArray<FLOAT> res = *pResSA; // OR use res.Attach(pResSA*) ?
{
// Use ATL types wrapped from above
}
// Cleanup ????
.
.
.
}
catch (...) {}
return S_OK;
}
What I'd like to know is:
Is my method of accepting (and converting) the parameters to ATL types correct usage or is there another (better?) way?
Do I have to call AddRef() and/or Release() on the IDispatch* myself or is it sufficient to assign to a CComPtr to get this all done?
What are the implications of the 2nd parameter given as VT_BYREF?
Header file says:
* VT_VARIANT [V][T][P][S] VARIANT *
* VT_ARRAY [V] SAFEARRAY*
* VT_BYREF [V] void* for local use
Which is not clear to me.... #-o
Is it sufficient to use SafeArray(Un)AccessData on the SAFEARRAY stored in the VARIANT (2nd parameter)?
Any additional things to consider to get this thing work properly (robust)?
Thanks for taking your time and possibly helping me!
ps: I already got this working (more or less) I only want to avoid problems (LEAKS!) which I cannot debug as the calling application is closed source and not under my control...
Upvotes: 0
Views: 1235
Reputation: 69632
You are making your like really compilcated using safe arrays and in/out parameters. Especially in conjunction with ancient VB6 you are going to interface to.
There are a few simple rules to make it clear, easier and reliable:
[in]
, [out]
, [out, retval]
parameters; in your code snippet you used [in, out]
without any shown intent to actually change the value to take advantage of out specifier: when you have no special reason to, it just makes C++ side complex and additional level of referencing increases chances for a mistakeByRef
on VB6 side, in parameters will by ByVal
You would get it like this:
[id(1)] HRESULT Process([in] IDispatch* pDataIDisp,
[in] VARIANT pParamsVar,
[out, retval] VARIANT* pvResult);
On C++ server side you would only read from in arguments, no releasing required. And you will initialize output variant by building it entirely in C++ using ATL CComVariant
and friends and then detaching it at the very last stage of your processing.
Public Function Process(data As Object,
Params As Variant) As Object
' ...
Dim Data, Params As Object
' ...
Dim Result As Object
Result = Server.Process(Data, Params)
' NOTE: Result is OK to be an array
Upvotes: 1