VC.NET ~ make_publicプラグマ

前置き

make_publicというプラグマを紹介します。

本文

マテリアル

例として、lib.dllを作るプロジェクトとapp.exeを作るプロジェクトを考えましょう。どちらも、マネージなアセンブリです。app.exeはlib.dllを参照するように設定しておきます。

lib.dllとapp.exeの内容は以下のような感じです。

  • lib.dllでは、ネイティブなFooクラスと、マネージなEntryPointクラスを定義
  • EntryPointクラスのメソッドlibFoo()は、Fooポインタを返す
  • app.exeから、libFoo()を呼びたい

lib.dll

  • untouchable.h
namespace untouchable {

class Foo {                            // ネイティブなクラス。
public:
  Foo() { a = 0; }

private:
  int a;
};

}
  • lib.cpp
#include "untouchable.h"

namespace lib {

public ref class EntryPoint {          // マネージなクラス。
public:
  static untouchable::Foo* libFoo() {
    return new untouchable::Foo();     // Fooを返す。
  }
};

}

app.exe

  • app.cpp
void foo()
{
  untouchable::Foo* pfoo = lib::EntryPoint::libFoo();
}

ネイティブな型は、デフォルトで非公開

前述のコードのままでは、lib.dllのFooクラスは、アセンブリの外には非公開です。一方、EntryPoint::libFoo()はアセンブリの外に公開され、しかもFooポインタを返します。他アセンブリから見ると、libFoo()は見えるのにreturn値は見えない、という矛盾した状態になります。そのため、コンパイル時に警告C4692が出ます。

warning C4692: 'libFoo': 公開されたメンバのシグネチャはアセンブリ
プライベート ネイティブ型 'untouchable::Foo' を含んでいます
  ★ただしC4692はデフォルトでoffなので、warningプラグマでonしておく必要があります。

これを回避する最も簡単な方法は、Fooクラスをpublicにすることです。

public class Foo {
...
};

しかし、ここでは、untouchable.hを変更できないと仮定しましょう。そのようなケースで活躍するのがmake_publicプラグマです。

#include "untouchable.h"

#pragma make_public(untouchable::Foo)  // これでFooがpublicに変わる。

namespace lib {

public ref class EntryPoint {
public:
  static untouchable::Foo* libFoo() {  // warningは出ない。
    return new untouchable::Foo();
  }
};

}

これで、libFoo()もFooクラスもlib.dllの外へ公開されました。

ただしmake_publicプラグマも万能ではありません。マネージな型には使えませんし、ネイティブな型でも、テンプレートには使えないようです(少なくともVS2008ではNG)。

dllの参照設定では、ネイティブな型は見えない

app.exeはlib.dllを参照設定しているので、EntryPointクラスやlibFoo()を使うことができます。しかし参照設定は、ネイティブなクラスには作用しないようです。よって、app.exe内でFooクラスを使うには、従来通り、ヘッダファイルを#includeします。

#include "untouchable.h"

void foo()
{
  untouchable::Foo* pfoo = lib::EntryPoint::libFoo();
}

ここは、イマイチ納得できていません。Visual StudioのIntelliSenseでは、ちゃんとFooクラスが見えてます。また、MSILの逆アセンブラ(ildasm.exe)でlib.dllを見ると、確かにFooクラスがpublicで定義されています。しかし、untouchable.hを#includeしておかないと、コンパイルエラーが出てしまいます。

error C2039: 'Foo' : 'untouchable' のメンバではありません。

試しに、#usingでlib.dllのパスを指定してみましたがダメでした。public classにしろ、make_publicにしろ、ネイティブな型を使いたければヘッダを#includeしろ、ということみたいです。

Last modified:2012/03/21 02:49:45
Keyword(s):
References:[.NETアプリ開発]
This page is frozen.