Fix memory leaks in wxAutomationObject::Invoke().

Use wxVector<>, wxBasicString and wxOleVariantArg instead of raw arrays, BSTR
and VARIANT to ensure that different objects allocated by this function are
always freed when it exits.

Closes #14293.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@71574 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2012-05-27 13:00:04 +00:00
parent 4ba36292f4
commit cf1a582ab9

View File

@@ -56,6 +56,8 @@
#if wxUSE_OLE_AUTOMATION #if wxUSE_OLE_AUTOMATION
#include <wx/vector.h>
// Report an OLE error when calling the specified method to the user via wxLog. // Report an OLE error when calling the specified method to the user via wxLog.
static void static void
ShowException(const wxString& member, ShowException(const wxString& member,
@@ -79,9 +81,24 @@ wxAutomationObject::~wxAutomationObject()
} }
} }
namespace
{
// A simple helper that ensures that VARIANT is destroyed on scope exit.
struct wxOleVariantArg : VARIANTARG
{
wxOleVariantArg() { VariantInit(this); }
~wxOleVariantArg() { VariantClear(this); }
};
} // anonymous namespace
#define INVOKEARG(i) (args ? args[i] : *(ptrArgs[i])) #define INVOKEARG(i) (args ? args[i] : *(ptrArgs[i]))
// For Put/Get, no named arguments are allowed. // For Put/Get, no named arguments are allowed.
// WARNING: if args contain IDispatches, their reference count will be decreased
// by one after Invoke() returns!
bool wxAutomationObject::Invoke(const wxString& member, int action, bool wxAutomationObject::Invoke(const wxString& member, int action,
wxVariant& retValue, int noArgs, wxVariant args[], const wxVariant* ptrArgs[]) const wxVariant& retValue, int noArgs, wxVariant args[], const wxVariant* ptrArgs[]) const
{ {
@@ -100,23 +117,23 @@ bool wxAutomationObject::Invoke(const wxString& member, int action,
return obj.Invoke(rest, action, retValue, noArgs, args, ptrArgs); return obj.Invoke(rest, action, retValue, noArgs, args, ptrArgs);
} }
VARIANTARG vReturn; wxOleVariantArg vReturn;
VariantInit(& vReturn); wxOleVariantArg* vReturnPtr = & vReturn;
VARIANTARG* vReturnPtr = & vReturn;
// Find number of names args // Find number of names args
int namedArgCount = 0; int namedArgCount = 0;
int i; int i;
for (i = 0; i < noArgs; i++) for (i = 0; i < noArgs; i++)
{
if ( !INVOKEARG(i).GetName().empty() ) if ( !INVOKEARG(i).GetName().empty() )
{ {
namedArgCount ++; namedArgCount ++;
} }
}
int namedArgStringCount = namedArgCount + 1; int namedArgStringCount = namedArgCount + 1;
BSTR* argNames = new BSTR[namedArgStringCount]; wxVector<wxBasicString> argNames(namedArgStringCount, wxString());
argNames[0] = wxConvertStringToOle(member); argNames[0] = member;
// Note that arguments are specified in reverse order // Note that arguments are specified in reverse order
// (all totally logical; hey, we're dealing with OLE here.) // (all totally logical; hey, we're dealing with OLE here.)
@@ -126,13 +143,13 @@ bool wxAutomationObject::Invoke(const wxString& member, int action,
{ {
if ( !INVOKEARG(i).GetName().empty() ) if ( !INVOKEARG(i).GetName().empty() )
{ {
argNames[(namedArgCount-j)] = wxConvertStringToOle(INVOKEARG(i).GetName()); argNames[(namedArgCount-j)] = INVOKEARG(i).GetName();
j ++; j ++;
} }
} }
// + 1 for the member name, + 1 again in case we're a 'put' // + 1 for the member name, + 1 again in case we're a 'put'
DISPID* dispIds = new DISPID[namedArgCount + 2]; wxVector<DISPID> dispIds(namedArgCount + 2);
HRESULT hr; HRESULT hr;
DISPPARAMS dispparams; DISPPARAMS dispparams;
@@ -140,13 +157,14 @@ bool wxAutomationObject::Invoke(const wxString& member, int action,
// Get the IDs for the member and its arguments. GetIDsOfNames expects the // Get the IDs for the member and its arguments. GetIDsOfNames expects the
// member name as the first name, followed by argument names (if any). // member name as the first name, followed by argument names (if any).
hr = ((IDispatch*)m_dispatchPtr)->GetIDsOfNames(IID_NULL, argNames, hr = ((IDispatch*)m_dispatchPtr)->GetIDsOfNames(IID_NULL,
1 + namedArgCount, LOCALE_SYSTEM_DEFAULT, dispIds); // We rely on the fact that wxBasicString is
// just BSTR with some methods here.
reinterpret_cast<BSTR *>(&argNames[0]),
1 + namedArgCount, LOCALE_SYSTEM_DEFAULT, &dispIds[0]);
if (FAILED(hr)) if (FAILED(hr))
{ {
ShowException(member, hr); ShowException(member, hr);
delete[] argNames;
delete[] dispIds;
return false; return false;
} }
@@ -160,21 +178,16 @@ bool wxAutomationObject::Invoke(const wxString& member, int action,
} }
// Convert the wxVariants to VARIANTARGs // Convert the wxVariants to VARIANTARGs
VARIANTARG* oleArgs = new VARIANTARG[noArgs]; wxVector<wxOleVariantArg> oleArgs(noArgs);
for (i = 0; i < noArgs; i++) for (i = 0; i < noArgs; i++)
{ {
// Again, reverse args // Again, reverse args
if (!wxConvertVariantToOle(INVOKEARG((noArgs-1) - i), oleArgs[i])) if (!wxConvertVariantToOle(INVOKEARG((noArgs-1) - i), oleArgs[i]))
{
delete[] argNames;
delete[] dispIds;
delete[] oleArgs;
return false; return false;
}
} }
dispparams.rgdispidNamedArgs = dispIds + 1; dispparams.rgdispidNamedArgs = &dispIds[0] + 1;
dispparams.rgvarg = oleArgs; dispparams.rgvarg = &oleArgs[0];
dispparams.cArgs = noArgs; dispparams.cArgs = noArgs;
dispparams.cNamedArgs = namedArgCount; dispparams.cNamedArgs = namedArgCount;
@@ -184,17 +197,6 @@ bool wxAutomationObject::Invoke(const wxString& member, int action,
hr = ((IDispatch*)m_dispatchPtr)->Invoke(dispIds[0], IID_NULL, LOCALE_SYSTEM_DEFAULT, hr = ((IDispatch*)m_dispatchPtr)->Invoke(dispIds[0], IID_NULL, LOCALE_SYSTEM_DEFAULT,
(WORD)action, &dispparams, vReturnPtr, &excep, &uiArgErr); (WORD)action, &dispparams, vReturnPtr, &excep, &uiArgErr);
for (i = 0; i < namedArgStringCount; i++)
{
SysFreeString(argNames[i]);
}
delete[] argNames;
delete[] dispIds;
for (i = 0; i < noArgs; i++)
VariantClear(& oleArgs[i]) ;
delete[] oleArgs;
if (FAILED(hr)) if (FAILED(hr))
{ {
// display the exception information if appropriate: // display the exception information if appropriate:
@@ -205,8 +207,6 @@ bool wxAutomationObject::Invoke(const wxString& member, int action,
SysFreeString(excep.bstrDescription); SysFreeString(excep.bstrDescription);
SysFreeString(excep.bstrHelpFile); SysFreeString(excep.bstrHelpFile);
if (vReturnPtr)
VariantClear(vReturnPtr);
return false; return false;
} }
else else
@@ -214,13 +214,13 @@ bool wxAutomationObject::Invoke(const wxString& member, int action,
if (vReturnPtr) if (vReturnPtr)
{ {
// Convert result to wxVariant form // Convert result to wxVariant form
wxConvertOleToVariant(vReturn, retValue); if (!wxConvertOleToVariant(vReturn, retValue))
return false;
// Mustn't release the dispatch pointer // Mustn't release the dispatch pointer
if (vReturn.vt == VT_DISPATCH) if (vReturn.vt == VT_DISPATCH)
{ {
vReturn.pdispVal = NULL; vReturn.pdispVal = NULL;
} }
VariantClear(& vReturn);
} }
} }
return true; return true;