Skip to content

Instantly share code, notes, and snippets.

@cdecl
Created February 22, 2015 08:11
Show Gist options
  • Save cdecl/eb2ebc97111bcbc70ce6 to your computer and use it in GitHub Desktop.
Save cdecl/eb2ebc97111bcbc70ce6 to your computer and use it in GitHub Desktop.
// COMDispatch.h: interface for the IDispatch class.
//////////////////////////////////////////////////////////////////////
#ifndef _DISPATCH_H_20011012_BY_CDECL_
#define _DISPATCH_H_20011012_BY_CDECL_
#include <comdef.h>
#include <vector>
#define BYREF(x) GLASS::COMDispatch::ToRefParam((x))
namespace GLASS {
class COMDispatch
{
public:
typedef std::vector<_variant_t> vec_param;
typedef _variant_t PT;
// Proxy Class
class Proxy
{
public:
void SetParent(COMDispatch *p) { pDisp_ = p; }
void SetPropName(const _bstr_t &bstrName) { bstrName_ = bstrName; }
_variant_t operator=(const _variant_t &var) const
{
pDisp_->PutProperty(bstrName_, var);
return var;
}
operator _variant_t() const {
return pDisp_->GetProperty(bstrName_);
}
_variant_t operator() ()
{
vec_param vecParams;
return pDisp_->Call(bstrName_, vecParams);
}
template <typename...VARS>
_variant_t operator() (VARS...param)
{
vec_param vecParams = Param(param...);
return pDisp_->Call(bstrName_, vecParams);
}
private:
template <typename Vartype>
vec_param Param(Vartype p)
{
vec_param v;
v.push_back(p);
return std::move(v);
}
template <typename Vartype, typename...VARS>
vec_param Param(Vartype p, VARS...vs)
{
vec_param v = Param(vs...);
v.push_back(p);
return std::move(v);
}
private:
COMDispatch *pDisp_;
_bstr_t bstrName_;
};
public:
COMDispatch() : spDispatch_(NULL) { proxy_.SetParent(this); }
COMDispatch(const COMDispatch &disp) : spDispatch_(disp.spDispatch_) { proxy_.SetParent(this); }
explicit COMDispatch(const _variant_t &var) : spDispatch_(var) { proxy_.SetParent(this); }
COMDispatch(const char *) = delete;
COMDispatch(const wchar_t *) = delete;
virtual ~COMDispatch() { Release(); }
COMDispatch& operator=(const COMDispatch &disp);
COMDispatch& operator=(const _variant_t &var);
public:
_variant_t Call(const _bstr_t &bstrMethodName, vec_param &vecParams);
void PutProperty(const _bstr_t &strPropName, const _variant_t &var, bool bRef = false);
_variant_t GetProperty(const _bstr_t &strPropName);
virtual Proxy& operator[](const _bstr_t &bstrPropName);
virtual void CreateObject(const _bstr_t &bstrProgID);
virtual void Release();
public:
virtual void GetIDsOfNames(const _bstr_t &bstrMethodName, DISPID &lDispID);
protected:
virtual void Invoke(const DISPID lDispID, vec_param &vecParams, _variant_t &varRetVal, const WORD wFlags = DISPATCH_METHOD);
public:
static _variant_t ToRefParam(_variant_t &var);
protected:
Proxy proxy_;
IDispatchPtr spDispatch_;
};
//////////////////////////////////////////////////////////////////////
// Dispatch implementation
COMDispatch& COMDispatch::operator=(const COMDispatch &disp)
{
if (this != &disp) {
spDispatch_ = disp.spDispatch_;
proxy_.SetParent(this);
}
return *this;
}
COMDispatch& COMDispatch::operator=(const _variant_t &var)
{
spDispatch_ = var;
proxy_.SetParent(this);
return *this;
}
void COMDispatch::Release()
{
if (spDispatch_ != NULL) {
spDispatch_.Release();
}
}
void COMDispatch::CreateObject(const _bstr_t &bstrProgID)
{
HRESULT hr = spDispatch_.CreateInstance((LPCSTR)bstrProgID);
if (FAILED(hr)) {
_com_raise_error(hr);
}
}
_variant_t COMDispatch::Call(const _bstr_t &bstrMethodName, vec_param &vecParams)
{
DISPID lDispID;
GetIDsOfNames(bstrMethodName, lDispID);
_variant_t varRetVal;
Invoke(lDispID, vecParams, varRetVal);
return varRetVal;
}
COMDispatch::Proxy& COMDispatch::operator[](const _bstr_t &bstrPropName)
{
proxy_.SetPropName(bstrPropName);
return proxy_;
}
void COMDispatch::PutProperty(const _bstr_t &strPropName, const _variant_t &var, bool bRef)
{
DISPID lDispID;
GetIDsOfNames(strPropName, lDispID);
vec_param vecParams;
vecParams.push_back(var);
_variant_t varRetVal;
Invoke(lDispID, vecParams, varRetVal, bRef ? DISPATCH_PROPERTYPUTREF : DISPATCH_PROPERTYPUT);
}
_variant_t COMDispatch::GetProperty(const _bstr_t &strPropName)
{
DISPID lDispID;
GetIDsOfNames(strPropName, lDispID);
vec_param vecParams;
_variant_t varRetVal;
Invoke(lDispID, vecParams, varRetVal, DISPATCH_PROPERTYGET);
return varRetVal;
}
void COMDispatch::GetIDsOfNames(const _bstr_t &bstrMethodName, DISPID &lDispID)
{
BSTR bstrMN = static_cast<BSTR>(bstrMethodName);
HRESULT hr = spDispatch_->GetIDsOfNames(IID_NULL, &bstrMN, 1, LOCALE_SYSTEM_DEFAULT, &lDispID);
if (FAILED(hr)) {
_com_raise_error(hr);
}
}
void COMDispatch::Invoke(const DISPID lDispID, vec_param &vecParams, _variant_t &varRetVal, const WORD wFlags)
{
DISPPARAMS dispparams = { 0 };
DISPID dsipid_put = DISPID_PROPERTYPUT;
if (DISPATCH_PROPERTYGET != wFlags) {
dispparams.cArgs = vecParams.size();
dispparams.rgvarg = (vecParams.size() == 0) ? NULL : &vecParams.front();
if ((DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF) & wFlags) {
dispparams.rgdispidNamedArgs = &dsipid_put;
dispparams.cNamedArgs = 1;
}
}
HRESULT hr = spDispatch_->Invoke(
lDispID,
IID_NULL,
LOCALE_USER_DEFAULT,
wFlags,
&dispparams,
DISPATCH_PROPERTYPUT == wFlags ? NULL : &varRetVal,
NULL,
NULL
);
if (FAILED(hr)) {
_com_raise_error(hr);
}
}
_variant_t COMDispatch::ToRefParam(_variant_t &var)
{
_variant_t varRet;
varRet.vt = VT_BYREF | VT_VARIANT;
varRet.pvarVal = &var;
return varRet;
}
} // end namespace
#endif // _DISPATCH_H_20011012_BY_CDECL_
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment