Windows Runtime Cpp ランタイムオブジェクト生成
概要
レジストリからDLLを検索し、必要なランタイムオブジェクトを生成するような仕組みによって生成されます。アクティベーションって言います。あるいはファクトリー呼ばれるものから生成するオブジェクトもあります。
Runtimeオブジェクトの生成 RoActiveInstance
RoActiveInstanceという関数でランタイムオブジェクトをDLLから生成できるようになっています。以下のように聞いたことのないようなIInspectable型変数を引数にとる形式になっています。
- RoActiveInstance(HSTRING型変数, IInspectable型ポインタ変数のポインタ変数)
- 第一引数:オブジェクトクラス名を保持したHSTRING型の変数です。45行目で使われています。サンプルでは"RuntimeClass.Windows.UI.Xaml.Application"というクラス名を持ったHSTRING変数としてHSTRING_StrClassNameが指定されています。
- 第二引数:IInspectable型の変数に生成されたランタイムオブジェクトを受け取ります。この変数はCOMの技術を継承した変数です。サンプルではIApplication型ポインタ変数のアドレス変数&pIApplicationObjを(IInspectable**)でキャストして引き渡しています。
ラインタイムオブジェクトを生成する上記の関数を利用するには#include <windows.ui.xaml.h>として、ヘッダファイルを読み込む必要があります。このヘッダファイルを読み込むことで多くのぶら下がっているヘッダファイルも読み込まれる仕組みになっています。デフォルトではライブラリはC:\Program Files (x86)\Windows Kits\8.1\Include\winrtとかに保存されているはずです。
いかに示すサンプルでは
IApplication型のポインタ変数を作成し、これのアドレスを引数とすることでIInspectable型ポインタ変数のポインタ変数(アドレス変数のアドレス変数)としています。安全にキャストできるらしいです。IInspectable,IApplicationはいずれもCOMの技術を利用したものです。IApplication型は名前空間ABI::Windows::UI::Xaml;に定義されている変数です。
#include <locale.h>
#include <wchar.h>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <crtdbg.h>
#include <roapi.h>
#include <winstring.h>
#include <windows.ui.xaml.h>
using namespace ABI::Windows::UI::Xaml;
int main()
{
HRESULT hr;
setlocale(LC_ALL, "");
GetCurrentTime();
hr = RoInitialize(RO_INIT_TYPE::RO_INIT_MULTITHREADED);
if (FAILED(hr)) {
wprintf_s(L"初期化に失敗しました。\n");
_CrtDbgBreak();
return 0;
}
else {
wprintf_s(L"初期化に成功しました。\n");
}
const wchar_t *pcStrClassName = RuntimeClass_Windows_UI_Xaml_Application;
size_t sizeStrClassName = wcslen(pcStrClassName);
HSTRING HSTRING_StrClassName;
HRESULT HRESULT_Hr;
HRESULT_Hr = WindowsCreateString(pcStrClassName, sizeStrClassName, &HSTRING_StrClassName);
if (FAILED(HRESULT_Hr)) {
wprintf_s(L"HSTRING_StrClassNameの生成に失敗しました。\n");
_CrtDbgBreak();
return 0;
}
else {
wprintf_s(L"HSTRING_StrClassNameの生成に成功しました。\n");
}
IApplication *pIApplicationObj;
HRESULT_Hr = RoActivateInstance(HSTRING_StrClassName, (IInspectable**)&pIApplicationObj);
if (FAILED(HRESULT_Hr)) {
wprintf_s(L"HSTRING_StrClassNameのRuntimeObject生成に失敗しました。\n");
_CrtDbgBreak();
return 0;
}
else {
wprintf_s(L"HSTRING_StrClassNameのRuntimeObject生成に成功しました。\n");
}
HSTRING HSTRING_GetStrClassName;
HRESULT_Hr = pIApplicationObj->GetRuntimeClassName(&HSTRING_GetStrClassName);
if (FAILED(HRESULT_Hr)) {
wprintf_s(L"HSTRING_StrClassNameの取得に失敗しました。\n");
_CrtDbgBreak();
return 0;
}
else {
wprintf_s(L"HSTRING_StrClassNameの取得に成功しました。\n");
}
ULONG ULONG_IidCnt;
IID *pIID_Iids;
HRESULT_Hr = pIApplicationObj->GetIids(&ULONG_IidCnt, &pIID_Iids);
if (FAILED(HRESULT_Hr)) {
wprintf_s(L"IIDの取得に失敗しました。\n");
_CrtDbgBreak();
return 0;
}
else {
wprintf_s(L"IIDの取得に成功しました。\n");
}
for (ULONG ULONG_i = 0; ULONG_i < ULONG_IidCnt; ULONG_i++) {
wprintf_s(L"IID[%d]=%x-%x-%x-", ULONG_i, (pIID_Iids + (int)ULONG_i)->Data1, (pIID_Iids + (int)ULONG_i)->Data2, (pIID_Iids + (int)ULONG_i)->Data3);
for (int iN = 0; iN < 8; iN++) {
wprintf_s(L"%x", *((pIID_Iids + (int)ULONG_i)->Data4 + iN));
}
wprintf_s(L"\n");
}
wprintf_s(L"\n");
RoUninitialize();
_wsystem(L"pause");
}
実行結果
初期化に成功しました。 HSTRING_StrClassNameの生成に成功しました。 HSTRING_StrClassNameのRuntimeObject生成に成功しました。 HSTRING_StrClassNameの取得に成功しました。 IIDの取得に成功しました。 IID[0]=74b861a1-7487-46a9-9a6ec78b512726c5 IID[1]=25f99ff7-9347-459a-9facb2d0e11c1af IID[2]=b3ab45d8-6a4e-4e76-a0d32d4643a9f1a IID[3]=19104be-522a-5904-f52fde721429e0 IID[4]=db5cd2b9-d3b4-558c-c64e434fd1bd889 IID[5]=b775ad7c-18b8-45ca-a1b0dc483e4b1028 IID[6]=38-0-0-c000000046 IID[7]=df0b3d60-548f-101b-8e65802b2bd119 IID[8]=0-0-0-c000000046 IID[9]=af86e2e0-b12d-4c6a-9c5ad7aa65101e90 続行するには何かキーを押してください . . .
サンプルでは生成したランタイムオブジェクトのすべてのIIDをリストアップするプログラムになっています。なんかGUIDみたいな不気味なIDでカッコいいと思うのはマイクロソフトファンだけでしょうか?私の場合は9つもぶら下がってました。IIDはインタフェースIDと呼ばれています。GUIDの形式になっています。
- ABI
- Abstract Binary Interfaceで抽象バイナリーインターフェースの略。コードが混在するアプリケーション(C#、C ++、Cなど)を作成したり、いくつかの外部ライブラリを呼び出したりすると、データを渡すためのものとして、抽象バイナリインタフェース(ABI)というものが使用されます。Application Binary InterfaceもABIですが、アプリケーションがバイナリーと変換される境界という意味なので、ちょっと意味が違います。
- XAML(ザムル)
- Extensible Application Markup Languageの略。 マイクロソフトが開発したアプリ開発向けXMLですね。このXMLでUIを記述するような感じです。
Runtimeファクトリーの生成 RoGetActivationFactory
ファクトリーは具体的な機能を持ったランタイムのオブジェクトの生成に使う手法です。前項のオブジェクトが基本で、本項のオブジェクトが実用という感じです。ここではURIに関するオブジェクトを生成するファクトリーを作ってみます。さきほどのサンプルに追加する形で、ファクトリーによるオブジェクト生成を見てみます。プログラム自体は何の役にも立ちません。あしからず。ランタイムオブジェクトがあって、オブジェクトにはメソッドがあり、クラスのような働きをしてくれます。生成したIUriRuntimeClassFactoryオブジェクトにURI設定したオブジェクトを生成して、IUriRuntimeClassを生成します。
- RoGetActivationFactory(生成するオブジェクトクラス名,ランタイムオブジェクトのIIDインターフェースID,ランタイムオブジェクト型のアドレス変数のアドレス変数)
- 第一引数:生成するオブジェクトクラス名をHSTRING変数で指定します。サンプルでは85行目に使われています。HSTRING_StrURIClassNameのHSTRING型変数を指定しています。
- 第二引数:ランタイムオブジェクトのIIDで、通常はランタイムオブジェクトの型名を使って __iidof()関数で取得します。__iidof(IUriRuntimeClassFactory)として指定しています。
- 第二引数:ランタイムオブジェクト変数のアドレス変数のアドレス変数を(void**)型で指定します。voidですので、型指定無しのアドレス型ですね。 (void**)&pIUriRuntimeClassFactoryObjとして指定しています。
#include <locale.h>
#include <wchar.h>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <crtdbg.h>
#include <roapi.h>
#include <winstring.h>
#include <windows.ui.xaml.h>
using namespace ABI::Windows::UI::Xaml;
using namespace ABI::Windows::Foundation;
int main()
{
HRESULT hr;
setlocale(LC_ALL, "");
GetCurrentTime();
hr = RoInitialize(RO_INIT_TYPE::RO_INIT_MULTITHREADED);
if (FAILED(hr)) {
wprintf_s(L"初期化に失敗しました。\n");
_CrtDbgBreak();
return 0;
}
else {
wprintf_s(L"初期化に成功しました。\n");
}
const wchar_t *pcStrClassName = RuntimeClass_Windows_UI_Xaml_Application;
const wchar_t *pcStrURIClassName = RuntimeClass_Windows_Foundation_Uri;
const wchar_t *pcStrURI = L"http://www.yo-net.jp/";
size_t sizeStrLength = wcslen(pcStrClassName);
HSTRING HSTRING_StrClassName;
HSTRING HSTRING_StrURIClassName;
HSTRING HSTRING_StrURI;
HSTRING HSTRING_StrHOST;
HRESULT HRESULT_Hr;
HRESULT_Hr = WindowsCreateString(pcStrClassName, sizeStrLength, &HSTRING_StrClassName);
if (FAILED(HRESULT_Hr)) {
wprintf_s(L"HSTRING_StrClassNameの生成に失敗しました。\n");
_CrtDbgBreak();
return 0;
}
else {
wprintf_s(L"HSTRING_StrClassNameの生成に成功しました。\n");
}
sizeStrLength = wcslen(pcStrURIClassName);
HRESULT_Hr = WindowsCreateString(pcStrURIClassName, sizeStrLength, &HSTRING_StrURIClassName);
if (FAILED(HRESULT_Hr)) {
wprintf_s(L"HSTRING_StrURIClassNameの生成に失敗しました。\n");
_CrtDbgBreak();
return 0;
}
else {
wprintf_s(L"HSTRING_StrURIClassNameの生成に成功しました。\n");
}
sizeStrLength = wcslen(pcStrURI);
HRESULT_Hr = WindowsCreateString(pcStrURI, sizeStrLength, &HSTRING_StrURI);
if (FAILED(HRESULT_Hr)) {
wprintf_s(L"HSTRING_StrURIの生成に失敗しました。\n");
_CrtDbgBreak();
return 0;
}
else {
wprintf_s(L"HSTRING_StrURIの生成に成功しました。\n");
}
IApplication *pIApplicationObj;
HRESULT_Hr = RoActivateInstance(HSTRING_StrClassName, (IInspectable**)&pIApplicationObj);
if (FAILED(HRESULT_Hr)) {
wprintf_s(L"HSTRING_StrClassNameのRuntimeObject生成に失敗しました。\n");
_CrtDbgBreak();
return 0;
}
else {
wprintf_s(L"HSTRING_StrClassNameのRuntimeObject生成に成功しました。\n");
}
IUriRuntimeClass *pIUriRuntimeClassObj;
IUriRuntimeClassFactory *pIUriRuntimeClassFactoryObj;
HRESULT_Hr = RoGetActivationFactory(HSTRING_StrURIClassName, __uuidof(IUriRuntimeClassFactory), (void**)&pIUriRuntimeClassFactoryObj);
if (FAILED(HRESULT_Hr)) {
wprintf_s(L"HSTRING_StrClassNameのRuntimeObject生成に失敗しました。\n");
_CrtDbgBreak();
return 0;
}
else {
wprintf_s(L"HSTRING_StrClassNameのRuntimeObject生成に成功しました。\n");
}
HRESULT_Hr = pIUriRuntimeClassFactoryObj->CreateUri(HSTRING_StrURI, &pIUriRuntimeClassObj);
if (FAILED(HRESULT_Hr)) {
wprintf_s(L"IUriRuntimeClassの生成に失敗しました。\n");
_CrtDbgBreak();
return 0;
}
else {
wprintf_s(L"IUriRuntimeClassの生成に成功しました。\n");
}
HRESULT_Hr = pIUriRuntimeClassObj->get_Host(&HSTRING_StrHOST);
if (FAILED(HRESULT_Hr)) {
wprintf_s(L"pIUriRuntimeClassObjからHOSTの取得に失敗しました。\n");
_CrtDbgBreak();
return 0;
}
else {
wprintf_s(L"pIUriRuntimeClassObjからHOSTの取得に成功しました。\n");
}
wprintf_s(L"pIUriRuntimeClassObj HOST=%s\n",WindowsGetStringRawBuffer(HSTRING_StrHOST, nullptr));
HSTRING HSTRING_GetStrClassName;
HRESULT_Hr = pIApplicationObj->GetRuntimeClassName(&HSTRING_GetStrClassName);
if (FAILED(HRESULT_Hr)) {
wprintf_s(L"HSTRING_StrClassNameの取得に失敗しました。\n");
_CrtDbgBreak();
return 0;
}
else {
wprintf_s(L"HSTRING_StrClassNameの取得に成功しました。\n");
}
ULONG ULONG_IidCnt;
IID *pIID_Iids;
HRESULT_Hr = pIApplicationObj->GetIids(&ULONG_IidCnt, &pIID_Iids);
if (FAILED(HRESULT_Hr)) {
wprintf_s(L"IIDの取得に失敗しました。\n");
_CrtDbgBreak();
return 0;
}
else {
wprintf_s(L"IIDの取得に成功しました。\n");
}
for (ULONG ULONG_i = 0; ULONG_i < ULONG_IidCnt; ULONG_i++) {
wprintf_s(L"IID[%d]=%x-%x-%x-", ULONG_i, (pIID_Iids + (int)ULONG_i)->Data1, (pIID_Iids + (int)ULONG_i)->Data2, (pIID_Iids + (int)ULONG_i)->Data3);
for (int iN = 0; iN < 8; iN++) {
wprintf_s(L"%x", *((pIID_Iids + (int)ULONG_i)->Data4 + iN));
}
wprintf_s(L"\n");
}
wprintf_s(L"\n");
CoTaskMemFree(pIID_Iids);
pIUriRuntimeClassObj->Release();
pIUriRuntimeClassFactoryObj->Release();
pIApplicationObj->Release();
RoUninitialize();
_wsystem(L"pause");
}
表示結果
初期化に成功しました。 HSTRING_StrClassNameの生成に成功しました。 HSTRING_StrURIClassNameの生成に成功しました。 HSTRING_StrURIの生成に成功しました。 HSTRING_StrClassNameのRuntimeObject生成に成功しました。 HSTRING_StrClassNameのRuntimeObject生成に成功しました。 IUriRuntimeClassの生成に成功しました。 pIUriRuntimeClassObjからHOSTの取得に成功しました。 pIUriRuntimeClassObj HOST=www.yo-net.jp HSTRING_StrClassNameの取得に成功しました。 IIDの取得に成功しました。 IID[0]=74b861a1-7487-46a9-9a6ec78b512726c5 IID[1]=25f99ff7-9347-459a-9facb2d0e11c1af IID[2]=b3ab45d8-6a4e-4e76-a0d32d4643a9f1a IID[3]=19104be-522a-5904-f52fde721429e0 IID[4]=db5cd2b9-d3b4-558c-c64e434fd1bd889 IID[5]=b775ad7c-18b8-45ca-a1b0dc483e4b1028 IID[6]=38-0-0-c000000046 IID[7]=df0b3d60-548f-101b-8e65802b2bd119 IID[8]=0-0-0-c000000046 IID[9]=af86e2e0-b12d-4c6a-9c5ad7aa65101e90 続行するには何かキーを押してください . . .
と、こんな感じで使います。ランタイムオブジェクトはこれだけではないので、IxxRuntimeClassFactoryやIxxRuntimeClassといったランタイムオブジェクトはいくつかありますので、それらについては少しづつ紹介していかねばらないのかなぁとは思っています。まずは使い方の一例を示しました。IxxRuntimeというようなオブジェクトだけに限らず、IDisplayPropertiesStaticsのようなオブジェクトもあります。
オブジェクト生成後は
- pIUriRuntimeClassObj->Release();
- pIUriRuntimeClassFactoryObj->Release();
- pIApplicationObj->Release();
のような、それぞれのオブジェクトに準備されているRelease()メソッドを実行して解放してあげる必要があります。