他言語との連携(ネイティブから動的言語まで)

2,204 views

Published on

Published in: Technology, Education
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,204
On SlideShare
0
From Embeds
0
Number of Embeds
953
Actions
Shares
0
Downloads
7
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

他言語との連携(ネイティブから動的言語まで)

  1. 1. 他言語との連携 ネイティブから動的な言語まで。 (別言語からC#にWellcom) C#の素晴らしさを語る会
  2. 2. 自己紹介 名前 石川達也 所属 株式会社Codeer代表取締役 (http://www.codeer.co.jp/) 技術 C、C++、C++/CLI、C#、少しJava 組み込みとか、Windowsアプリとか。 趣味 ギター
  3. 3. まずは、ネイティブとの連携 まだまだ、ネイティブアプリは世の中にあふれて いる!
  4. 4. ストーリー Win32アプリのメンテをしています。 そして、ある日上司から唐突に作業依頼がやってきました。
  5. 5. 次の仕様追加で作る画面、 WPFで作ってくれない? 流行ってんでしょ? 流行ってる か・・・?
  6. 6. (でたよ、思い付き・・・) でも、あなたは、答えました。 「Yes, sir」 なぜなら、WPFで作るということは・・・。
  7. 7. 大好きなC#を仕事で使えるか ら!
  8. 8. 備考 でも、この思い付きは意外と良いんです。 Nativeアプリを一気に.Netで作り変えるのは大変! その過程で、チームに.Netのノウハウが溜まるのです。
  9. 9. 方法は複数あり、それぞれ長所短所があ る。 ・ネイティブをC++/CLIにする ・C++/CLIでブリッジをつくる ・COM相互運用 ・P/Invoke ・ホストAPI 私はこれをよく使って ます
  10. 10. 今回はC#とC++のみで、やってみ ます。 ・ネイティブをC++/CLIにする 割愛 ・C++/CLIでブリッジをつくる ・COM相互運用 ・P/Invoke ・ホストAPI
  11. 11. レシピはこんなもんかな・・・
  12. 12. 8Hほど煮込みまし た。
  13. 13. あれ?
  14. 14. これ、いつもやってるやつより良くね? (゚ д゚ノ)ノ なんで、今までC++/CLI使ってたの? (T-T) ていうか、やっぱり・・・・。
  15. 15. C#って素晴らし い! では、コードをどうぞ~。 弊社サイトからDwonLoad可能です。 Codeerで検索→技術メモ→ネイティブと.Netの連携 http://www.codeer.co.jp/technical-notes/NativeAndNet
  16. 16. 概略図 ManagedExporter.dll ManagedImporter IInterfaceTable ObjectProxy WpfGui.dll Win32App.exe InputDataDialog : IInterfaceTable InputDataDialog : ObjectProxy InputData : IInterfaceTable InputData : ObjectProxy ★最初にObjectProxy::Initを一回呼びます。
  17. 17. まとめると、 Delegateを関数ポインタにしてネイティブから使 おう! って作戦です。
  18. 18. 初期化 ホストAPIで.Net呼び出し。 関数ポインタちょうだい。 ManagedExporter.dll ManagedImporter //関数ポインタをstaticに保持 ExportInfo s_Create(path, assembly, typeFullName); void s_Free(handle); ・生成関数(delegate) ・解放関数(delegate) ・ホストAPI(メンド い) //COMインターフェイス取得 CLRCreateInstance(..., IID_PPV_ARGS(&pMetaHost)); pMetaHost->GetRuntime(..., IID_PPV_ARGS(&pRuntimeInfo)); pRuntimeInfo->GetInterface(..., IID_PPV_ARGS(&pClrRuntimeHost)); //ランタイム開始 pClrRuntimeHost->Start(); //文字列指定で.Netのstaticメソッドを呼び出し。 //型はint func(string args) pClrRuntimeHost->ExecuteInDefaultAppDomain(...) ObjectProxy::Init(L"v4.0.30319"); ・delegateを関数ポインタに変換 IntPtr ptr = Marshal.GetFunctionPointerForDelegate(func); 注意点としてdelegateのオブジェクトをGCで 回収されないようにする必要があります。 方法は複数あります。 ・Static変数にする ・GC.KeepAlive ・GCHandle.Alloc Win32App.exe
  19. 19. オブジェクト生成 ManagedExporter.dll ManagedImporter IInterfaceTable Info s_Create(path, assembly, type); ・リフレクションで生成。 ・ IInterfaceTableを使ってDelegateを取得。 ・関数名でDelegateを取得できるDelegateを作成。 ・ GCHandle.Allocで寿命を確保。 ・ネイティブに返す。 InputDataDialog::InputDataDialog() : ObjectProxy(AssemblyPathLocal, "WpfGui.dll", "WpfGui.InputDataDialog") //マネージドクラス公開情報。 typedef void* (__stdcall *GetInterface)(name); struct ExportInfo { HANDLE handle; GetInterface getInterface; }; WpfGui.dll InputDataDialog : IInterfaceTable Win32App.exe InputDataDialog : ObjectProxy
  20. 20. インターフェイスマッピング ManagedExporter.dll IInterfaceTable ManagedImporter Info s_Create(path, assembly, type); BIND_PROXY_METHOD(SetOwner); BIND_PROXY_METHOD(DoModal); BIND_PROXY_METHOD(GetInputData); //マネージドクラス公開情報。 typedef void* (__stdcall *GetInterface)(name); struct ExportInfo { HANDLE handle; GetInterface getInterface; ←これを使う }; Win32App.exe InputDataDialog : ObjectProxy
  21. 21. 逆に.Netからネイティブのクラスを使う。 P/Invoke void DisplayInfo::SetTitle(LPCWSTR title) { _strTitle = title; } HGLOBAL DisplayInfo::GetTitle() { size_t size = (_strTitle.length() + 1) * 2; HGLOBAL global = ::GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, size); memcpy((void*)global, _strTitle.c_str(), size); return global; } //Exeでも公開関数を定義することは可能です。 extern "C" { __declspec(dllexport) void __cdecl DisplayInfoSetTitle(void* ptr, LPCWSTR title) { return ((DisplayInfo*)ptr)->SetTitle(title); } __declspec(dllexport) HGLOBAL __cdecl DisplayInfoGetTitle(void* ptr) { return ((DisplayInfo*)ptr)->GetTitle(); } __declspec(dllexport) void __cdecl DisplayInfoDelete(void* ptr) { delete ptr; } }
  22. 22. class DisplayInfo : IDisposable { IntPtr _core; public DisplayInfo(IntPtr core) { _core = core; } public string Title { get { IntPtr ptr = DisplayInfoGetTitle(_core); string title = Marshal.PtrToStringUni(ptr); Marshal.FreeHGlobal(ptr); return title; } set { DisplayInfoSetTitle(_core, value); } } protected virtual void Dispose(bool disposing) { if (disposing && _core != IntPtr.Zero) { DisplayInfoDelete(_core); _core = IntPtr.Zero; } }
  23. 23. [DllImport("Win32App.exe")] static extern IntPtr DisplayInfoGetTitle(IntPtr core); [DllImport("Win32App.exe", CharSet = CharSet.Unicode)] static extern void DisplayInfoSetTitle(IntPtr core, string title); [DllImport("Win32App.exe")] static extern void DisplayInfoDelete(IntPtr core); }
  24. 24. dynamic 動的言語との連携
  25. 25. 次の指令が来ました。
  26. 26. その、画面の処理、ユーザにスクリプト で カスタマイズさせたりできない? Rubyとか。 流行ってるんでしょ? Windowsではそうでもな いと思うけど・・・
  27. 27. ま、Rubyには興味あったし、 やってみるか!
  28. 28. Rubyのコード class Formatter def SetName(name) @name = name end def SetAge(age) @age = age end def SetLangauge(langauge) @langauge = langauge end def Format @name + "rn" + @age.to_s + "rn" + @langauge; end end
  29. 29. C#から使う。 internal static string Execute(InputData data) { //実行 var ir = IronRuby.Ruby.CreateRuntime(); ir.ExecuteFile(@"..formatter.rb"); //クラス生成 var type = ir.Globals.GetVariable("Formatter"); dynamic formatter = ir.Operations.CreateInstance(type); //普通に使える formatter.SetName(data.Name); formatter.SetAge(data.Age); formatter.SetLangauge(data.Langauge); return (string)formatter.Format(); }
  30. 30. dynamicで表されるRubyのクラスの正体は? class RubyObject : IRubyDynamicMetaObjectProvider interface IRubyDynamicMetaObjectProvider : IDynamicMetaObjectProvider public interface IDynamicMetaObjectProvider { DynamicMetaObject GetMetaObject(Expression parameter); } IDynamicMetaObjectProviderを実装したクラスをdynamicに入れると、 メソッド、プロパティー、フィールド解決時にGetMetaObjectを呼び出 してくれる。 なので、RubyObjectクラスがRubyに特化した解決をしてくれる。 *注)通常はIDynamicMetaObjectProviderではなく、 DynamicObjectを継承して実装します。
  31. 31. 使う側は優雅! RubyObjectが頑張ってくれている。
  32. 32. Dynamicは、これだけでなく、 動的なインターフェイスを持つライブラリに優雅なインターフェイスを与え てくれる! XML操作とか COMとかね。 あなたも、そんなライブラリ持っていませんか?
  33. 33. 弊社にはあります。 無料 Codeeer.Friendly.Dynamic http://www.codeer.co.jp/AutoTest
  34. 34. 対象プロセスを 強力な操作方法(おそらく世界で唯 一)で テスト用に操作するライブラリです。 軽くデ モ・・・
  35. 35. 以前は・・・ AppVar mainForm = _app[typeof(Application), "OpenForms"]()["[]"](0); AppVar result = mainForm["MyMethod"]("100"); int value = (int)result.Core; Assert.AreEqual(101, value); dynamicを使うと・・・ dynamic mainForm = _app.Type<Application>().OpenForms[0]; int value = mainForm.MyMethod("100"); Assert.AreEqual(101, value); やってることは、実質変わりませんが、可読性と学習効率がUpし ました。 お客様に使ってもらっているのですが、サポートも減りました。
  36. 36. ご清聴ありがとうございました。

×