.NetMF の InterOp の実装方法について


前提条件

1. VisualStudio 2013 Community をインストールしていること。
   PK の対応としては VisualStudio 2012 推奨なのだが、
   一応 setenv_base.cmd の中身を
   書き換えることにより対応は可能。
   (GitHub にあるソースコードをダウンロードし
    PK の setenv_base.cmd と比較し、VS に
    関する部分をマージする)
    VS12 -> 2013 
    VS11 -> 2012?
    VS10 -> 2010 
    に相当

2. .net micro framework のSDKを入れていること
SDK v4.3 (QFE2-RTM)
http://netmf.codeplex.com/releases/view/611040

3. PortingKit のインストールをしていること
Porting Kit 4.3 (RTM QFE1)
http://netmf.codeplex.com/releases/view/118283
 
4. gcc のToolChain をインストールしていること。
メール登録必要(フリーメール不可)にはなるが、
gcc のツールチェインとして
確認用に使われているもの。
CodeSourcery
※　一連の動作はこちらで確認。 

メール登録なしだと、
launchpad がある。
※　ビルド未確認。 

実装手順
a. VisualStudio を使ってStub を作成する。
a-1. Visual Studio 2013 Community を立ち上げる。
a-2. Visual C#のテンプレートから
   .NetMicroFramework のライブラリを選択し作成。
![スクリーンショット 2015-04-07 0.53.27.png](https://qiita-image-store.s3.amazonaws.com/0/46426/6ed67e7d-3c5c-ed33-6490-d22fa88ad6cc.png "スクリーンショット 2015-04-07 0.53.27.png")

a-3. デバイスとやり取りする際の Interface を
　　　コードに記入する。

<pre>
using Microsoft.SPOT.Hardware;
using System.Runtime.CompilerServices;

namespace MyFirstLibrary 
{ 
	public class ImpulseSender 
	{
		uint _pin; 		
		public ImpulseSender(OutputPort port) 
		{ 
			_pin = (uint)port.Id; 
		} 
		
		[MethodImpl(MethodImplOptions.InternalCall)]
		public extern void WritePulse(bool positive, int durationCycles); 
	} 
} 
</pre>

※　見易さ優先のため、コメントは削除

a-4. proj を選択してプロパティを表示して
「.Net Micro Framework」を選択後、 Generate native stubs
 for Internal methods のチェックを On にする。
 他の部分も画像のように任意で名前をつけていく。

![スクリーンショット 2015-04-07 0.55.27.png](https://qiita-image-store.s3.amazonaws.com/0/46426/5ab8777f-73fc-708e-e351-86d51e9060c8.png "スクリーンショット 2015-04-07 0.55.27.png")

b. Native / Managed Code フォルダへの振分け
b-1. ビルド結果をNative に 
　　　Stub として作成したファイル一式を
　　　ManagedCodeフォルダに振り分ける。

b-2. ManagedCodeフォルダのfeatureproj を一部書き換える。
     以下を下のようにコメントアウトする。
　　　<!-- &lt;MMP_DAT_CreateDatabase Include="$(SPOCLIENT)\MyInterops\MyFirstLibrary\ManagedCode\MyFirstLibrary.pe" /&gt; -->

※ Native にファイルをコピーする際にコピー元フォルダ名に注意すること
　(be -> ビッグエンディアン、 le -> リトルエンディアン)

2. RequiredProjects の設定変更
→ Integrating the interop library 
  into porting kit(TinyCLR への取り込み)
c. Solution の TinyCLR.proj 側対応
c-1. TinyCLR.proj で指定位置に項目を追加する。

		PointA, B の位置に追加
		:
		<!-- POINT A -->
		<Import Project="$(SPOCLIENT)\tools\targets\Microsoft.SPOT.System.Interop.Settings" />
		:
		<!-- POINT B -->
		<Import Project="$(SPOCLIENT)\tools\targets\Microsoft.SPOT.System.Targets" />

		Point A に追加する内容
		<Import Project="$(SPOCLIENT)\MyInterops\MyFirstLibrary\NativeCode\MyFirstLibrary.featureproj" />

		POINT B に追加する内容
		<ItemGroup> 
			<RequiredProjects Include="$(SPOCLIENT)\MyInterops\MyFirstLibrary\NativeCode\dotNetMF.proj"/> 
			<DriverLibs Include="MyFirstLibrary.$(LIB_EXT)"/> 
		</ItemGroup>

d. Stub の実装
	例外実装は HRESULT 値を設定することにより対応 
	(デフォルトは S_OK)

以下のビルドのエラーが出たら...
MMP : error MMP0000: CLR_E_FAIL 

原因
1. 修正後のソースを再度VisualStudio でビルドしてみる。
2. MyFirstLibrary.featureproj 内のMMP_DAT_CreateDatabaseの記述が
   コメントアウトされているか確認する。
3. Stub を作成する際に VS2010 で作成していたため、
   テンプレートがV4.1 になりうまくいかなかった？
   PortingKit の環境ビルドはVS2010 も動くため 
   古い vsix のテンプレートが適用されていたのでエラーになる？
4. Navite フォルダに le のファイルではなくpe のファイルが
   入っていないか。
5. msbuild の際の引数設定をしないでビルドしたため
6. debug で ビルドしたDLL が原因？

他
↓Windows 8.1 & .NET MF 4.3 利用時のエラー対応です。
QFE1 で修正されたようなので、最新版では必要ないが一応。
http://netmf.codeplex.com/workitem/221

Stub の実装で[][] 配列を使っていないか？
https://netmf.codeplex.com/workitem/2095

参考ページ
Interop の実装については主にこちらのコードで確認。
http://informatix.miloush.net/microframework/Tutorials/Interop.aspx

3.0 の記述
http://adeneo-embedded.blogspot.it/2009/01/using-interop-in-net-micro-framework.html

http://www.mountaineer.org/netmf-for-stm32/
の NETMF for STM32 - Tour d'Horizon
※　これにSolution 内の記述について記載されている。