さてさて、ネイティブDLLを作って、Windows PhoneのC#プロジェクトへ組み込み、いざデバッグすると驚愕。ネイティブコード側に仕込んでおいたはずのOutputDebugStringの出力がまったくないではありませんか。

思わずかっとなって、マネージ側でDebug.WriteLineを呼ぶだけのクラスを作って、ネイティブ側に渡しておく仕組みを作っていました。この試行錯誤で土日が潰れました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
interface __declspec(uuid("95E19FD5-D011-4979-BBFB-26D9C358BDC0")) IDebug : IUnknown
{
  // このマクロはこう展開される
  // virtual HRESULT STDMETHODCALLTYPE WriteLine(BSTR s) = 0;
  STDMETHOD(WriteLine)(BSTR s) PURE;
  STDMETHOD(WriteLineW)(LPCWSTR s) PURE;
};
 
ATL::CComPtr<IDebug> g_Debug;
 
HRESULT DebugWriteLineF(LPCWSTR format, ...)
{
  WCHAR buffer[1024];
  std::va_list arg;
  va_start(arg, format);
  int size = wvsprintf(buffer, format, arg);
  if (size > 0)
  {
    ATL::CComBSTR str(size, buffer);
    return g_Debug->WriteLine(str);
  }
  else
  {
    return ATL::AtlHresultFromLastError();
  }
}

ついでにprintf風出力も作っておきました。実行ファイルの容量を考慮し、Windows APIのwvsprintfを使っています。

そしてマネージ側です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[ComImport, Guid("95E19FD5-D011-4979-BBFB-26D9C358BDC0"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IDebug
{
  void WriteLine([In, MarshalAs(UnmanagedType.BStr)] string s);
  void WriteLineW([In, MarshalAs(UnmanagedType.LPWStr)] string s);
}
 
sealed class DebugImpl : IDebug
{
  public void WriteLine(string s)
  {
    Debug.WriteLine(s);
  }
  public void WriteLineW(string s)
  {
    Debug.WriteLine(s);
  }
}

本当はMarshalAs(UnmanagedType.LPStr)なWriteLineAも追加しようとしたのですが、駄目だったのは昨日の記事に書いたとおりです。

あとは、マネージ側からネイティブ側へDebugImplオブジェクトを渡せば完了です。適当なインタフェース・クラスを作ってやりましょう。渡す際の引数は、マネージ側:[In] IDebug、ネイティブ側:IDebug*の引数で大丈夫です。

スポンサード リンク

この記事のカテゴリ

  • ⇒ WP7.1ネイティブとOutputDebugString
  • ⇒ WP7.1ネイティブとOutputDebugString