概要
C#側から、C++のchar *が引数となっている関数を利用するのであれば、
StringBuilderなどを利用すればおわりです。
いわゆる、C#がC言語APIを呼び出すパターンです。
しかし、世の中逆の場合もあるのです。
即ち、同じchar *でもC言語がC#のAPI経由で要求するパターンです。
古いレガシーなプラグインシステムなどにおいて、
C言語で作成することを前提としたAPIインターフェイスを
C#で基本部分を実装しようとすると、こういった事態になることがあります。
C++/CLIでやれば一瞬で解決する
上記のような状況で、なおかつ.NETを利用したい場合は、C++/CLIで実装すればすぐ終わるのですが、
今回はC#で突き進む場合の話となります。
C#がchar *を返すことを求められることの辛さ
大抵のことはC++よりC#の方がエレガントに達成できますが、いくつかC#の方が苦手なこともあります。
その多くは今となっては利用するべきではないような古い考え方のプログラムであることが多いのですが、
C#でエレガントな解決方法があまり浸透していないものの1つが以下のようなシチュエーションに対するプログラムです。
上記のような
- fixedなポインタを求められ、dllが終了するまで確保しつづける
-
呼び出し元の本体プログラムは GetStaticStrPtr によって得た「ポインタが指す文字列の内容」を複製したりはせず、
得られたポインタが指す先をそのまま利用。
GetStaticStrPtr が呼び出された後も、確保した文字列はそのままdll側が保持
- 解放は呼び出し元がやるのではなく、dll側がやる。
といった形となってしまっている場合もあり、
非常に動作は高速なのですが、
このような形のインターフェイスへと繋げていける汎用的なC#の型を作成するのは、
簡単そうでいて、そういうわけにもいかず、ひと工夫が必要です。
StaticStrPtrHandleのようなものであれば、
String型っぽく利用しつつも、返り値として得たIntPtr値は、
(ToPointer 等を介して)、char *としてC言語でそのまま利用可能です。
ポインタが指し示していた先の内容(C#の.dllで確保されていた)ハズのものが途中でガベージコレクトで移動してしまい存在しない、
といった事態を回避できます。