• Developer Network
    • テクノロジ
      • クラウド
      • アプリの開発
      • Web
      • データ
      • ゲーム プレイ
    • ダウンロード
      • Visual Studio
      • MSDN サブスクリプション アクセス
      • SDK
      • 評価版ソフトウェア
    • プログラム
      • 報奨
      • 創業間もないベンチャー企業
      • 学生
      • アーキテクト
      • イベント
      • MSDN サブスクリプション
    • コミュニティ
      • Magazine
      • フォーラム
      • ブログ
      • テクニカル アドバイザー
      • Channel 9
    • ドキュメント
      • APIs and reference
      • デベロッパー センター
    • サンプルコード
Developer Network Developer
サインイン
MSDN サブスクリプション
ツールを入手する
magazine
  • Issues and downloads
    • All Issues
    • 2015
      • MSDN マガジン October 2015
      • MSDN マガジン September 2015
      • MSDN マガジン August 2015
      • MSDN マガジン July 2015
      • MSDN マガジン June 2015
      • MSDN マガジン May 2015
      • MSDN マガジン April 2015
      • MSDN マガジン March 2015
      • MSDN マガジン February 2015
      • MSDN マガジン January 2015
    • 2014
      • MSDN マガジン Special Issue 2014
      • MSDN マガジン December 2014
      • MSDN マガジン November 2014
      • MSDN マガジン October 2014
      • MSDN マガジン September 2014
      • MSDN マガジン August 2014
      • MSDN マガジン July 2014
      • MSDN マガジン June 2014
      • MSDN マガジン May 2014
      • MSDN マガジン April 2014
      • MSDN マガジン March 2014
      • MSDN マガジン February 2014
      • MSDN マガジン January 2014
    • 2013
      • MSDN マガジン December 2013
      • MSDN マガジン November 2013
      • MSDN マガジン October 2013
      • MSDN マガジン September 2013
      • MSDN マガジン August 2013
      • MSDN マガジン July 2013
      • MSDN マガジン June 2013
      • MSDN マガジン May 2013
      • MSDN マガジン April 2013
      • MSDN マガジン March 2013
      • MSDN マガジン February 2013
      • MSDN マガジン January 2013
    • 2012
      • MSDN マガジン December 2012
      • MSDN マガジン November 2012
      • MSDN マガジン October 2012
      • MSDN マガジン Windows 8 Special Issue 2012
      • MSDN マガジン September 2012
      • MSDN マガジン August 2012
      • MSDN マガジン July 2012
      • MSDN マガジン June 2012
      • MSDN マガジン May 2012
      • MSDN マガジン April 2012
      • MSDN マガジン March 2012
      • MSDN マガジン February 2012
      • MSDN マガジン January 2012
    • 2011
      • MSDN マガジン December 2011
      • MSDN マガジン November 2011
      • MSDN マガジン October 2011
      • MSDN マガジン September 2011
      • MSDN マガジン August 2011
      • MSDN マガジン July 2011
      • MSDN マガジン June 2011
      • MSDN マガジン May 2011
      • MSDN マガジン April 2011
      • MSDN マガジン March 2011
      • MSDN マガジン February 2011
      • MSDN マガジン January 2011
    • 2010
      • MSDN マガジン December 2010
      • MSDN マガジン November 2010
      • MSDN マガジン October 2010
      • MSDN マガジン September 2010
      • MSDN マガジン August 2010
      • MSDN マガジン July 2010
      • MSDN マガジン June 2010
      • MSDN マガジン May 2010
      • MSDN マガジン April 2010
      • MSDN マガジン March 2010
      • MSDN マガジン February 2010
      • MSDN マガジン January 2010
    • 2009
      • MSDN マガジン December 2009
      • MSDN マガジン November 2009
      • MSDN マガジン October 2009
      • MSDN マガジン September 2009
      • MSDN マガジン August 2009
      • MSDN マガジン July 2009
      • MSDN マガジン June 2009
      • MSDN マガジン May 2009
      • MSDN マガジン April 2009
      • MSDN マガジン March 2009
      • MSDN マガジン February 2009
      • MSDN マガジン January 2009
  • Subscribe
  • Submit article
Issues and downloads 2015 MSDN マガジン September 2015 Windows と C++ - Windows ランタイムでカッコイイ型

年 9 月 2015
ボリューム 30 番号 9

Windows と C++ - Windows ランタイムにおける洗練された型

Kenny Kerr | 年 9 月 2015

Kenny Kerrコンポーネントの開発者は、Windows ランタイム (WinRT) によって、洗練された型システムをアプリの開発者に提供できます。WinRT 全体が COM のインターフェイスを使って実装されることを考えると、C++ や従来の COM に詳しい開発者にはあり得ない話のように思えるかもしれません。突き詰めると、COM はクラスではなく、インターフェイスを中心とするプログラミング モデルです。COM のアクティベーション モデルにより、CoCreateInstance やその関連関数を使用してクラスを構築することはできます。しかしこれでは、既定のコンストラクターのようなものだけをもっともらしくサポートするにすぎません。こうした感覚は、WinRT RoActivateInstance でも変わりません。では、どういうしくみで型システムを提供できるのでしょう。

実際のしくみは、最初に受ける印象ほどつじつまの合わないものではありません。洗練された型システムをサポートするのに必要な基本的な抽象化は、COM アクティベーション モデルによって既に提供されています。この抽象化をコンシューマーに示すのに必要なメタデータが不足しているだけです。COM アクティベーション モデルは、クラスのオブジェクトとインスタンスを定義します。クラスのインスタンスをコンシューマーが直接作成しないクラスもあります。アプリ開発者が、CoCreateInstance を呼び出してクラスのインスタンスをいくつか作成しても、目的のインスタンスを取得するためには、依然として OS がそのクラス オブジェクトを取得する必要があります。

WinRT は、クラス オブジェクトを新しい名前で呼びますが、メカニズムは同じです。アクティベーション ファクトリは、コンシューマーがコンポーネントを呼び出す最初の部分です。コンポーネントは、DllGetClassObject を実装するのではなく、DllGetActivationFactory という関数をエクスポートします。クラスの識別方法は変化していますが、結果としては、特定のクラスに関連してさらにクエリできるオブジェクトにすぎません。従来のクラス オブジェクト (以下、「アクティベーション ファクトリ」) は IClassFactory インターフェイスを実装していました。呼び出し元はこのインターフェイスを使って、このクラスのインスタンスを作成できます。新しい方式では、WinRT ランタイムのアクティベーション ファクトリが、新しい IActivationFactory インターフェイスを実装して、事実上同じサービスを提供する必要があります。

前 2 回のコラムで説明したように、activatable 属性で修飾された WinRT ランタイム クラスは、メタデータを作成し、既定の構築を許可するように言語プロジェクションに指示します。前提として、属性を付けたクラスのアクティベーション ファクトリは、IActivationFactory の ActivateInstance メソッドを利用して、そのように既定で構築されたオブジェクトを提供します。IDL で記述した次のシンプルなランタイム クラスは、既定のコンストラクターを備えたクラスを表します。

C++
コピー
[version(1)]
[activatable(1)]
runtimeclass Hen
{
  [default] interface IHen;
}

パラメーターのセットが異なる追加のコンストラクターを表すメソッドのコレクションを収容するインターフェイスを使って、追加のコンストラクターを IDL で記述することもできます。IActivationFactory インターフェイスが既定の構築を定義するのと同様、コンポーネント固有のインターフェイスやクラス固有のインターフェイスがパラメーター化された構築を表します。特定の数の鳴き声 (clucks) を指定して Hen オブジェクトを作成するシンプルなファクトリ インターフェイスを以下に示します。

C++
コピー
runtimeclass Hen;
[version(1)]
[uuid(4fa3a693-6284-4359-802c-5c05afa6e65d)]
interface IHenFactory : IInspectable
{
  HRESULT CreateHenWithClucks([in] int clucks,
                              [out,retval] Hen ** hen);
}

明確な理由はありませんが、IHenFactory インターフェイスは、IActivationFactory と同様、IInspectable から直接継承する必要があります。これにより、このファクトリ インターフェイスの各メソッドは、指定されたパラメーターを受け取る追加コンストラクターとしてプロジェクションされます。また、各メソッドの最後にクラスと同じ型を持つ論理戻り値を返す必要があります。その後、このファクトリ インターフェイスを、インターフェイス名を示す別の activatable 属性を使って、明示的にランタイム クラスと関連付けます。

C++
コピー
[version(1)]
[activatable(1)]
[activatable(IHenFactory, 1)]
runtimeclass Hen
{
  [default] interface IHen;
}

作成するクラスが既定のコンストラクターを必要としない場合は、最初の activatable 属性を省略するだけで、そのクラスの言語プロジェクションも同様に既定のコンストラクターを省略します。あるバージョンの鶏コンポーネントを出荷後、大きなとさか (comb) を使って雌鶏 (hen) を作成できないことに気付いたら、どうすればよいでしょう。顧客に出荷してしまった IHenFactory インターフェイスはもう変更できません。COM インターフェイスは、変更不可のバイナリ コントラクトやセマンティック コントラクトにする必要があるためです。このような場合は、追加のコンストラクターを含む別のインターフェイスを定義するだけです。

C++
コピー
[version(2)]
[uuid(9fc40b45-784b-4961-bc6b-0f5802a4a86d)]
interface IHenFactory2 : IInspectable
{
  HRESULT CreateHenWithLargeComb([in] float width,
                                 [in] float height,
                                 [out, retval] Hen ** hen);
}

次に、この 2 つ目のファクトリ インターフェイスを、以前のように Hen クラスに関連付けます。

C++
コピー
[version(1)]
[activatable(1)]
[activatable(IHenFactory, 1)]
[activatable(IHenFactory2, 2)]
runtimeclass Hen
{
  [default] interface IHen;
}

統合は言語プロジェクションが担当するため、アプリ開発者には多数のオーバーロード コンストラクターが提示されるだけです (図 1 参照)。

IDL-Defined Factory Methods in C#
図 1 C# での IDL 定義のファクトリ メソッド

コンポーネント開発者は、こうしたファクトリ インターフェイスを、前提条件の "IActivationFactory" と併せて慎重に実装します。

C++
コピー
struct HenFactory : Implements<IActivationFactory,
                               ABI::Sample::IHenFactory,
                               ABI::Sample::IHenFactory2>
{
};

ここでは、2014 年 12 月のコラム (msdn.microsoft.com/magazine/dn879357) で説明した Implements クラス テンプレートを再び使用しています。既定の構築を使用しない場合も、hen のアクティベーション ファクトリでは IActivationFactory インターフェイスの実装が必要です。これは、コンポーネントに実装する必要のある DllGetActivationFactory 関数が、IActivationFactory インターフェイスを返すようにハードコードされているためです。したがって、アプリケーションで既定以外の構築が必要な場合、言語プロジェクションは、結果のポインターの QueryInterface を最初に呼び出す必要があります。それでも、IActivationFactory の ActivateInstance 仮想関数を実装しなければなりませんが、何も操作を実行しない次のような関数で十分です。

C++
コピー
virtual HRESULT __stdcall ActivateInstance(IInspectable ** instance) noexcept override
{
  *instance = nullptr;
  return E_NOTIMPL;
}

追加の構築メソッドを、特定の実装に合わせた有効な方法で実装することもできますが、単純に内部クラス自体に引数を渡してシンプルに対応することもできます。これは、次のようになります。

C++
コピー
virtual HRESULT __stdcall CreateHenWithClucks(int clucks,
                                              ABI::Sample::IHen ** hen) noexcept override
{
  *hen = new (std::nothrow) Hen(clucks);
  return *hen ? S_OK : E_OUTOFMEMORY;
}

このコードでは、C++ の Hen クラスに、スローするコンストラクターがないことが前提となります。そうしたコンストラクターでは、clucks の C++ ベクトルを割り当てることが必要になるかもしれません。その場合は、シンプルな例外ハンドラーを使えば対処できます。

C++
コピー
try
{
  *hen = new Hen(clucks);
  return S_OK;
}
catch (std::bad_alloc const &)
{
  *hen = nullptr;
  return E_OUTOFMEMORY;
}

静的クラス メンバーはどうなるでしょう。以前にも説明したように、アクティベーション ファクトリでは静的クラス メンバーも COM インターフェイスを使用して実装します。IDL に戻って、任意の静的メンバーをすべて収容するインターフェイスを定義できます。庭にいる産卵鶏 (layer hen) の数をレポートするコードを作成してみます。

C++
コピー
[version(1)]
[uuid(60086441-fcbb-4c42-b775-88832cb19954)]
interface IHenStatics : IInspectable
{
  [propget] HRESULT Layers([out, retval] int * count);
}

次は、このインターフェイスを、static 属性を付けた同じランタイム クラスに関連付ける必要があります。

C++
コピー
[version(1)]
[activatable(1)]
[activatable(IHenFactory, 1)]
[activatable(IHenFactory2, 2)]
[static(IHenStatics, 1)]
runtimeclass Hen
{
  [default] interface IHen;
}

C++ での実装も、同様に簡単です。Implements 可変個引数テンプレートを次のように更新します。

C++
コピー
struct HenFactory : Implements<IActivationFactory,
                               ABI::Sample::IHenFactory,
                               ABI::Sample::IHenFactory2,
                               ABI::Sample::IHenStatics>
{
};

適切に実装した get_Layers 仮想関数を追加します。

C++
コピー
virtual HRESULT __stdcall get_Layers(int * count) noexcept override
{
  *count = 123;
  return S_OK;
}

それでは、より正確な頭数、いえ、羽数を特定するコードを作成してみてください。

コンシューマー側では、このコードはアプリケーション内部で非常にシンプルかつ簡潔に示されます。図 1 に示しているように、IntelliSense エクスペリエンスは非常に便利です。CreateHenWithClucks コンストラクターを、C# クラスの別のコンストラクターと同じように使用できます。

C++
コピー
Sample.Hen hen = new Sample.Hen(123); // Clucks

もちろん、このコードを動作させるため、C# コンパイラと共通言語ランタイム (CLR) では数多くの操作が実行されます。実行時には、CLR が RoGetActivationFactory を呼び出します。RoGetActivationFactory は、LoadLibrary を呼び出し、その後 DllGetActivationFactory を呼び出して、Sample.Hen アクティベーション ファクトリを取得します。次に、RoGetActivationFactory は QueryInterface を呼び出してファクトリの IHenFactory インターフェイス実装を取得します。これで初めて、CreateHenWithClucks 仮想関数を呼び出して Hen オブジェクトを作成できるようになります。言うまでもありませんが、Hen オブジェクトのさまざまな属性やセマンティクスを特定するよう、CLR を入力する各オブジェクトに促すたびに、CLR によって QueryInterface の追加呼び出しが多数要求されます。

静的メンバーの呼び出しも、同じくシンプルに実行できます。

C++
コピー
int layers = Sample.Hen.Layers;

しかしここでも、CLR では、アクティベーション ファクトリを取得する RoGetActivationFactory を呼び出した後、QueryInterface を呼び出して IHenStatics インターフェイス ポインターを取得する必要があります。これによって初めて、この静的プロパティの値を取得する get_Layers 仮想関数を呼び出せるようになります。ただし、CLR はアクティベーション ファクトリをキャッシュするため、こうした呼び出しを何度も実行するうちに負荷はいく分低下します。その反面、コンポーネント内でファクトリをキャッシュしようとすると、CLR により、操作がやや無意味で不必要に煩雑になります。これについてはまた別の機会に説明しましょう。来月は、引き続き C++ の Windows ランタイムについて説明します。ぜひご覧ください。


Kenny Kerr は、カナダを拠点とするコンピューター プログラマであり、Pluralsight の執筆者です。また、Microsoft MVP でもあります。彼のブログは kennykerr.ca (英語) で、Twitter は twitter.com/kennykerr (英語) でフォローできます。


この記事のレビューに協力してくれたマイクロソフト技術スタッフの Larry Osterman に心より感謝いたします。


MSDN Magazine Blog

14 Top Features of Visual Basic 14: The Q&A
Wednesday, 1 7 by Michael Desmond - MSDN Magazine
Big Start to the New Year at MSDN Magazine
Friday, 1 2 by Michael Desmond - MSDN Magazine

More MSDN Magazine Blog entries >


Current Issue


November 2015 issue

Browse All MSDN Magazines


Subscribe to the MSDN Flash newsletter Subscribe to MSDN Flash newsletter


Receive the MSDN Flash e-mail newsletter every other week, with news and information personalized to your interests and areas of focus.

フォロー
  • http://www.facebook.com/microsoftdeveloper
  • https://twitter.com/msdev
  • http://plus.google.com/111221966647232053570/
MSDN ニュースレターにサインアップ
このページは役に立ちましたか。
このページのコンテンツについての
ご意見をお待ちしております
その他にご意見はありますか。
残り 1500 文字
ありがとうございました。
貴重なご意見をお寄せいただき心より感謝いたします。
デベロッパー センター
  • Windows
  • Office
  • Visual Studio
  • Microsoft Azure
  • サイトマップ
IT トレーニングとマイクロソフト認定資格
  • Microsoft Virtual Academy
  • Channel 9 (英語)
  • 相互運用性ブリッジ (英語)
  • MSDN マガジン
コミュニティ
  • フォーラム
  • ブログ
  • MVP ブログ
  • CodePlex (英語)
サポート
  • セルフ サポート
プログラム
  • BizSpark (スタートアップ企業向け) 
  • DreamSpark (学生向け)
  • Imagine Cup  (学生向け IT コンテンスト)
日本 (日本語)
  • ニュースレター
  • プライバシー & Cookie
  • 使用条件
  • 商標 (英語)
© 2015 Microsoft