SWIGで文字列を返す


やりたいこと

引数で文字列を返すメソッドをSWIGで生成したい。
SWIG 4.0.2はstd::string*に対応していないので手動で対応してみる。

Sample.h
class Sample {
public:
  void GetSettingName(std::string* settingName) {
    *settingName = "ABC";
  }
};

C#側では以下のように呼び出す。

Program.cs
static void Main() {
  var sample = new Sample();
  sample.GetSettingName(out string settingName);
}

実装例

sample.iの設定でC++側のC#用メソッドが作成される。
CSharp_Sample_GetSettingNameはC#向けに公開したいメソッド。
%ignoreで該当メソッドを自動生成しないようにする。
生成されたC#側のクラスにメソッドを追加したいのでpartial指定する。

sample.i
%module example
%typemap(csclassmodifiers) Sample "public partial class"
%ignore Sample::GetSettingName(std::string* settingName);
%{
#include <windows.h>
#include "Sample.h"
%}
%include <windows.i>
%include "Sample.h"
%{
#ifdef __cplusplus
extern "C"
#endif
SWIGEXPORT void SWIGSTDCALL CSharp_Sample_GetSettingName(
  void * self, BSTR* bstrSettingName) {
  std::string settingName;
  ((Sample*)self)->GetSettingName(&settingName);
  *bstrSettingName = ::SysAllocStringByteLen(
    settingName.c_str(), settingName.length());
}
%}

手動で作成したC++側のメソッドを呼び出す。

Sample.manual.cs
using System.Runtime.InteropServices;
partial class Sample {
  private static class NativeMethods {
  [DllImport("example", EntryPoint = "CSharp_Config_GetSettingName")]
  public static extern void GetSettingName(
    HandleRef self,
    [MarshalAs(UnmanagedType.AnsiBStr)] out string bstrSettingName);
  }
  public void GetSettingName(out string settingName) {
    NativeMethods.GetSettingName(swigCPtr, out settingName);
  }
}