LoginSignup
2
2

More than 5 years have passed since last update.

C++/CLIでWCFによるプロセス間通信

Last updated at Posted at 2017-02-02

時代遅れな話かもしれませんが、ググっても意外とサンプルが無かったのでここに記録しておきます。
といっても、C#のサンプルをC++/CLIに翻訳すればDONEです。

サンプルの説明

例として、ホストAとクライアントBのプロセス間通信を考えます。
クライアントBから、ホストAのメソッドvoid SetName(String^ name)を実行するものとします。
この時、引数nameがクライアントBからホストAへリモートで伝送されます。

実装

上記サンプルの実装を示します。

ホスト側

  • ContractのインターフェースINamableです
IContract.h
#pragma once
using namespace System;
using namespace System::ServiceModel;

[ServiceContract]
interface class INamable
{
  [OperationContract]
  void SetName(String^ name);
};

Contractとするインターフェースに[ServiceContract]属性、メソッドに[OperationContract]属性を付けてあげます。

  • INamableの実装Dogです
Dog.h
#include "INamable.h"
ref class Dog : public INamable
{
public:
  Dog();
  virtual void SetName(String^ name)
  {
    myName = name;
    Console::WriteLine(myName + ": I'm Max!");
  }
private:
  String^ myName;
};

リモートで実行したいメソッドを含むクラスに、先のContract INamableを実装してあげます。

  • ホストプログラムのメイン関数です
main.c
#include "Dog.h"

int main()
{
  ServiceHost^ host = gcnew ServiceHost(
    Dog::typeid,
    gcnew System::Uri("net.pipe://localhost")
  );
  host->AddServiceEndpoint(
    INamable::typeid,
    gcnew NetNamedPipeBinding(),
    "naming"
  );
  host->Open();
  Console::ReadLine(); // Wait for a name
  return 0;
}

ServiceHostを実装したクラスDogで、EndPointをインターフェースクラスINamableで、それぞれ定義してあげます。
今回は通信方法に名前付きパイプを使用していますが、ここの宣言を変えてあげれば、TCPやHTTPによる通信も可能なようです。
ここでReadLine()はプログラムの終了を防ぐためだけに例として実行したものであり、実際はhost->Open()したあとは、好きに他の処理を実行して構いません。
次節で実装するクライアントから呼び出されれば、SetName()が実行されます。
IOスレッドプールで実行されるようです。

クライアント側

クライアント側では、ホスト側で宣言したインターフェースクラスを流用します。

main.c
#include "INamable.h"

using namespace System;
using namespace System::ServiceModel;

int main()
{
  ChannelFactory<INamable^>^ pipeFactory =
    gcnew ChannelFactory<INamable^>(
      gcnew NetNamedPipeBinding(),
      gcnew EndpointAddress("net.pipe://localhost/naming")
      );
  INamable^ naming_if = pipeFactory->CreateChannel();
  naming_if->SetName("Wofly");
  return 0;
}

ChannelFactoryで、ホストへのチャンネルを作成するためのファクトリーを作成します。
EndpointAddressは、net.pipe://localhostの末尾にホスト側でEndpointを作成する際に引数へ入れた"naming"を付加します。
ChannelFactory->CreateChannel()で、ホストへの通信路となるインスタンスを作成できます。
実用的にはこの返り値をメンバ変数などで保持することになるでしょう。
あとは、このインスタンスからINamableで宣言されたメソッドを呼び出せば、ホスト側の操作をできることになります。

ホストを起動した後に、クライアントを起動してみて下さい。
ホスト側にメッセージが表示されましたか?
おめでとうございます。基本的なプロセス間通信はこれで達成です!

終わりに

VC++でプロセス間通信せざるを得ない状況になったので、色々調査した結果WCFが最適解だろうという結論に至りました。
これならC#.NETとも簡単に連携できて、便利ですね。
しかしC++/CLIは慣れてないせいか、パット見^だのgcnewだのと違和感マシマシな感じです。
それでも標準のCやC++と簡単に連携できるのは、C#よりも良いところですね。
控えめに 使っていきたい C++/CLI(字余り) 以上。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2