メソッド名一覧の表示
Posted feedbacks - C++
ここでまさかのC++。ええと、WindowsでCOM使っています。VBやスクリプト言語用のIDispatch/ITypeInfoでリフレクションに相当する情報が得られるので、そこからメソッド名test_で始まるものを選び、IDipatchのInvokeメソッドで呼び出しています。
main関数より後ろはヘルパ群、ITypeInfoの型情報やIDispatch対応オブジェクトの作成などといった関数が並んでいます。
ITypeInfoはIDLから作るしかないと思っていたところ、このプログラムのようにCreateDispTypeInfo関数を使うとC++ソースコードの記述だけでITypeInfoを作れることを知りました。これを知らなければこの課題をC++でやることはなかったでしょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | //#define WIN32_LEAN_AND_MEAN
#include <iostream>
#include <ole2.h>
#include <windows.h>
#include <comdef.h>
#include <boost/implicit_cast.hpp>
using boost::implicit_cast;
// ここでは再発明しましたが、COMSTL (WinSTLの兄弟)のcom_exceptionがお薦め
class ComException
{
public:
explicit ComException(HRESULT hr) : hr(hr) {}
ComException(const ComException& rhs) : hr(rhs.hr) {}
ComException& operator =(const ComException& rhs)
{
hr = rhs.hr;
return *this;
}
HRESULT GetErrorCode() const
{
return hr;
}
//swapは使わないので省略
public:
HRESULT hr;
};
void ThrowIfFailed(HRESULT hr)
{
if (FAILED(hr))
{
throw ComException(hr);
}
}
// COM関係のヘッダに#define interface structとある。
interface __declspec(uuid("c70cd2de-1285-4ec5-a78a-5600cf6fc79a")) __declspec(novtable)
ITest : IUnknown
{
STDMETHOD(test_Hello)() PURE;
STDMETHOD(test_Goodbye)() PURE;
STDMETHOD(piyo_Dummy)() PURE;
// マクロを全て展開するとこうなる。
// virtual __declspec(nothrow) HRESULT __stdcall test_Hello() = 0;
};
// ITestの実装例
class TestImpl : public ITest
{
public:
TestImpl() : refCount(1) {}
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv)
{
if (riid == __uuidof (IUnknown))
{
*ppv = implicit_cast<IUnknown*>(this);
}
else if (riid == __uuidof (ITest))
{
*ppv = implicit_cast<ITest*>(this);
}
else
{
*ppv = 0;
return E_NOTIMPL;
}
return S_OK;
}
ULONG STDMETHODCALLTYPE AddRef()
{
return ++refCount;
}
ULONG STDMETHODCALLTYPE Release()
{
if (--refCount)
{
delete this;
return 0;
}
return refCount;
}
HRESULT STDMETHODCALLTYPE test_Hello()
{
std::cout << "Hello, world!" << std::endl;
return S_OK;
}
HRESULT STDMETHODCALLTYPE test_Goodbye()
{
std::cout << "Goodbye!" << std::endl;
return S_OK;
}
HRESULT STDMETHODCALLTYPE piyo_Dummy()
{
return E_NOTIMPL;
}
private:
ULONG refCount;
};
// もし、IホゲPtrが無くてエラーになるなら。
//_COM_SMARTPTR_TYPEDEF(ITypeInfo, __uuidof (ITypeInfo));
//_COM_SMARTPTR_TYPEDEF(IUnknown, __uuidof (IUnknown));
//_COM_SMARTPTR_TYPEDEF(IDispatch, __uuidof (IDispatch));
ITypeInfoPtr GetFirstInterfaceTypeInfo(ITypeInfo* pti);
IDispatchPtr CreateDispTest(ITypeInfo* pti);
ITypeInfoPtr GetTestTypeInfo();
int main()
{
try
{
ThrowIfFailed(OleInitialize(0));
ITypeInfoPtr pti = GetTestTypeInfo(); //クラスを表すITypeInfo
IDispatchPtr target = CreateDispTest(pti); //オブジェクトの作成
ITypeInfoPtr ptiInterface = GetFirstInterfaceTypeInfo(pti); //ITestを表すITypeInfo
TYPEATTR* pta;
ThrowIfFailed(ptiInterface->GetTypeAttr(&pta));
//DISPPARAMS dp2 = {};
//ThrowIfFailed(pdisp->Invoke(2, IID_NULL, LOCALE_SYSTEM_DEFAULT,
// DISPATCH_METHOD, &dp2, 0, 0, 0));
for (int i = 0; i < pta->cFuncs; ++i)
{
// i個目の関数のMEMIDを取得
FUNCDESC* pfd;
ThrowIfFailed(ptiInterface->GetFuncDesc(i, &pfd));
// その関数の名前を取得
_bstr_t name;
UINT count;
ThrowIfFailed(ptiInterface->GetNames(pfd->memid, name.GetAddress(), 1, &count));
if (wmemcmp(name, L"test_", 5) == 0)
{
// その関数がtest_で始まっていれば引数なしで呼び出す
DISPPARAMS dp = {};
ThrowIfFailed(target->Invoke(pfd->memid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD, &dp, 0, 0, 0));
}
ptiInterface->ReleaseFuncDesc(pfd);
}
ptiInterface->ReleaseTypeAttr(pta);
}
catch(ComException const& e)
{
LPSTR msg;
FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, e.GetErrorCode(), LANG_USER_DEFAULT,
reinterpret_cast<LPSTR>(&msg), 0, 0);
std::cerr << msg << std::endl;
LocalFree(msg);
}
OleUninitialize();
}
// CreateDispTypeInfoを使ったお手軽ITypeInfoの作成。
ITypeInfoPtr GetTestTypeInfo()
{
static METHODDATA md[] =
{
{
/* szName = */ L"test_Hello",
/* ppdata = */ 0, //引数情報
/* dispid = */ 1, //IDispatch::Invokeで呼び出すときの識別番号。適当な正の値で良い。
/* iMeth = */ 3, //VTBL上のインデックス
/* cc = */ CC_STDCALL, //呼出規約
/* cArgs = */ 0, //引数の個数
/* wFlags = */ DISPATCH_METHOD, //メソッド・プロパティの種別
/* vtReturn = */ VT_EMPTY, //戻り値の型
},
{
/* szName = */ L"test_Goodbye",
/* ppdata = */ 0,
/* dispid = */ 2,
/* iMeth = */ 4,
/* cc = */ CC_STDCALL,
/* cArgs = */ 0,
/* wFlags = */ DISPATCH_METHOD,
/* vtReturn = */ VT_EMPTY,
},
{
/* szName = */ L"piyo_Dummy",
/* ppdata = */ 0,
/* dispid = */ 3,
/* iMeth = */ 5,
/* cc = */ CC_STDCALL,
/* cArgs = */ 0,
/* wFlags = */ DISPATCH_METHOD,
/* vtReturn = */ VT_EMPTY,
},
};
static INTERFACEDATA id =
{
md, ARRAYSIZE(md), // ARRAYSIZEは<windows.h>の中で定義されている配列の要素数を求めるマクロ
};
ITypeInfoPtr pti;
ThrowIfFailed(CreateDispTypeInfo(&id, LOCALE_SYSTEM_DEFAULT, &pti));
return pti;
}
// TestImplのディスパッチオブジェクトを作成。
// ただし、ITypeInfを引数として与えること。
IDispatchPtr CreateDispTest(ITypeInfo* pti)
{
TestImpl* p = new TestImpl;
IUnknown* punkDispObj;
ThrowIfFailed(CreateStdDispatch(p, p, pti, &punkDispObj));
return punkDispObj;
}
// あるITypeInfoから、1番目に継承もしくは実装しているインタフェースを返すヘルパ。
ITypeInfoPtr GetFirstInterfaceTypeInfo(ITypeInfo* pti)
{
ITypeInfoPtr res;
HREFTYPE hrt;
ThrowIfFailed(pti->GetRefTypeOfImplType(0, &hrt));
ThrowIfFailed(pti->GetRefTypeInfo(hrt, &res));
return res;
}
|


にしお
#3388()
Rating1/1=1.00
「ある与えられたオブジェクトtargetのメソッドのうち、 "test_"で始まるものをすべて呼びだす」というコードを書いてください。 引数に関しては都合のいいように仮定して構いません(全部0個、など)。
メソッドという概念がない言語の場合は、 「複数の関数への参照を持っているようなオブジェクト(たとえばパッケージとかモジュールとか)から"test_"で始まる関数をすべて呼び出す」と読み替えても構いません。
[ reply ]