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:
@@ -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;
|
||||||
|
Reference in New Issue
Block a user