wxautomationobject_helpers.h
Code: Select all
///////////////////////////////////////////////////////////////////////////////
// Name: wxautomationobject_helpers.h
// Purpose: Helper functions for wxAutomationObject
// Author: PB
// Created: 2020-07-12
// Copyright: (c) 2020 PB
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#ifndef WXAUTOMATIONOBJECT_HELPERS
#define WXAUTOMATIONOBJECT_HELPERS
#include <wx/wx.h>
#if defined(__WXMSW__)
#include <wx/msw/ole/automtn.h>
// LCID for US English
extern const WXLCID wxLCIDEnglishUS;
// Returns name of the actual object based on object's IDispatch->GetTypeInfo
// or empty string when the name could not be retrieved
wxString wxGetAutomationObjectName(const wxAutomationObject& object,
WXLCID lcid = wxLCIDEnglishUS,
bool stripUnderscores = false);
// Returns list of properties and methods for given wxAutomationObject
bool wxGetAutomationObjectPropertyAndMethodNames(const wxAutomationObject& object,
wxArrayString& propertyNames,
wxArrayString& methodNames,
bool includeHidden = false);
// Uses wxLogDebug to dump information about wxVariant
void wxLogDebugAutomationVariant(const wxVariant& v, size_t maxItemsInList = 30);
#endif // #if defined(__WXMSW__)
#endif // WXAUTOMATIONOBJECT_HELPERS
Code: Select all
///////////////////////////////////////////////////////////////////////////////
// Name: wxautomationobject_helpers.cpp
// Purpose: Helper functions for wxAutomationObject
// Author: PB
// Created: 2020-07-12
// Copyright: (c) 2020 PB
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#include <wx/wx.h>
#if defined(__WXMSW__)
#include "wxautomationobject_helpers.h"
#include <wx/msw/private/comptr.h>
// LCID for US English
const WXLCID wxLCIDEnglishUS = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
// Returns name of the actual object based on object's IDispatch->GetTypeInfo
// or empty string when the name could not be retrieved
wxString wxGetAutomationObjectName(const wxAutomationObject& object,
WXLCID lcid, bool stripUnderscores)
{
wxCHECK_MSG(object.GetDispatchPtr(), wxEmptyString, "object does not contain a valid IDispatch pointer");
wxCOMPtr<ITypeInfo> typeInfo;
IDispatch* dispatch = (IDispatch*)object.GetDispatchPtr();
HRESULT hr = dispatch->GetTypeInfo(0, lcid, &typeInfo);
if ( FAILED(hr) )
{
wxLogApiError("IDispatch::GetTypeInfo()", hr);
return wxEmptyString;
}
BSTR bName = nullptr;
wxString name;
hr = typeInfo->GetDocumentation(MEMBERID_NIL, &bName, nullptr, nullptr, nullptr);
if ( FAILED(hr) )
{
wxLogApiError("ITypeInfo::GetDocumentation()", hr);
return wxEmptyString;
}
name = bName;
::SysFreeString(bName);
if ( stripUnderscores )
name.Replace("_", wxEmptyString);
return name;
}
// Returns list of properties and methods for the given wxAutomationObject
bool wxGetAutomationObjectPropertyAndMethodNames(const wxAutomationObject& object,
wxArrayString& propertyNames,
wxArrayString& methodNames,
bool includeHidden)
{
wxCHECK_MSG(object.GetDispatchPtr(), false, "object does not contain a valid IDispatch pointer");
HRESULT hr = S_OK;
wxCOMPtr<ITypeInfo> typeInfo;
IDispatch* dispatch = (IDispatch*)object.GetDispatchPtr();
TYPEATTR* typeAttr = NULL;
hr = dispatch->GetTypeInfo(0, 0, &typeInfo);
if ( FAILED(hr) )
{
wxLogApiError("IDispatch::GetTypeInfo()", hr);
return false;
}
hr = typeInfo->GetTypeAttr(&typeAttr);
if ( FAILED(hr) )
{
wxLogApiError("ITypeInfo::GetTypeAttr()", hr);
return false;
}
for ( WORD i = 0; i < typeAttr->cFuncs; i++ )
{
FUNCDESC* funcDesc = NULL;
BSTR bName = NULL;
hr = typeInfo->GetFuncDesc(i, &funcDesc);
if ( FAILED(hr) )
{
wxLogApiError("ITypeInfo::GetFuncDesc()", hr);
typeInfo->ReleaseTypeAttr(typeAttr);
return false;
}
hr = typeInfo->GetDocumentation(funcDesc->memid, &bName, NULL, NULL, NULL);
if ( FAILED(hr) )
{
wxLogApiError("ITypeInfo::GetDocumentation()", hr);
typeInfo->ReleaseFuncDesc(funcDesc);
typeInfo->ReleaseTypeAttr(typeAttr);
return false;
}
if ( ((funcDesc->wFuncFlags & FUNCFLAG_FHIDDEN) != FUNCFLAG_FHIDDEN)
|| includeHidden )
{
wxString name(bName);
switch ( funcDesc->invkind )
{
case INVOKE_FUNC:
methodNames.push_back(name);
break;
case INVOKE_PROPERTYGET:
case INVOKE_PROPERTYPUT:
case INVOKE_PROPERTYPUTREF:
// avoid adding the same property name for different INVOKEKINDs
if ( !propertyNames.empty() && propertyNames.Last().IsSameAs(name, false) )
break;
propertyNames.push_back(name);
break;
default:
wxFAIL_MSG("Unknown INVOKEKIND value");
}
}
::SysFreeString(bName);
typeInfo->ReleaseFuncDesc(funcDesc);
}
typeInfo->ReleaseTypeAttr(typeAttr);
return true;
}
// Uses wxLogDebug to dump information about wxVariant
void wxLogDebugAutomationVariant(const wxVariant& v, size_t maxItemsInList)
{
const wxString type = v.GetType();
wxString info;
const wxString& name = v.GetName();
if ( type == wxS("arrstring") )
{
wxArrayString as = v.GetArrayString();
info.Printf(wxS("variant type: \"%s\", element count: %zu, name: \"%s\"."),
type, as.size(), name);
wxLogDebug(wxS("%s"), info);
for (size_t i = 0; i < as.size(); i++)
{
info.Printf(wxS(" string #%zu value: \"%s\""), i, as[i]);
if ( i == maxItemsInList )
{
wxLogDebug(wxS("And %zu more strings"), as.size() - i);
break;
}
else
wxLogDebug(wxS("%s"), info);
}
return;
}
if ( type == wxS("list") )
{
info.Printf(wxS("Variant type: \"%s\", element count: %zu, name: \"%s\"."),
type, v.GetCount(), name);
wxLogDebug(wxS("%s"), info);
for ( size_t i = 0; i < v.GetCount(); i++ )
{
if ( i == maxItemsInList )
{
wxLogDebug(wxS("And %zu more variants"), v.GetCount() - i);
break;
}
else
{
const wxVariant& vTmp = v[i];
info.Printf(wxS(" variant #%zu type: \"%s\", value: \"%s\", name: \"%s\"."),
i, vTmp.GetType(), vTmp.MakeString(), vTmp.GetName());
wxLogDebug(wxS("%s"), info);
}
}
return;
}
if ( type == wxS("void*") && v.GetVoidPtr() != NULL )
{
wxString automationName;
wxAutomationObject object;
IDispatch* dispatch = (IDispatch*)v.GetVoidPtr();
dispatch->AddRef();
object.SetDispatchPtr(dispatch);
info.Printf(wxS("variant type: \"IDispatch - %s\", value: \"%s\", name: \"%s\"."),
wxGetAutomationObjectName(false), v.MakeString(), name);
}
else
{
info.Printf(wxS("variant type: \"%s\", value: \"%s\", name: \"%s\"."),
type, v.MakeString(), name);
}
wxLogDebug(wxS("%s"), info);
}
#endif // #if defined(__WXMSW__)