2011-02-04 8 views
5

x32をターゲットとするWin7 x64では、C#、.net 4.0上にアプリケーションを構築しています。PInvoke、ポインタと配列のコピー

私たちのアプリケーションではサードパーティのライブラリを使用しています。このライブラリはC++を使用して書かれています。ただし、C#開発者にこのライブラリを使用させるために、P/Invokeを使用してラップしています。したがって、API関数を呼び出す方法です。次のように

APIコールのいずれかである:

ReadFromDevice(int deviceAddress, int numBytes, Byte[] data); 

この機能は、外部装置からのデータのNUMBYTESを読み取り、データ[]の中に置きます。ご覧のとおり、3番目の引数としてC#Byte配列が表示されます。今、問題は、あらかじめ宣言された配列内の任意の場所にデータを読み込みたいということです。例:

Byte[] myData = new Byte[1024*1024*16]; 
ReadFromDevice(0x100, 20000, &myData[350]) // Obviously not possible in C# 

C/C++を使用していた場合、これは簡単なことです。基礎となるAPIがC++で書かれていることを考えると、私もC#でこれを行うことができるはずですが、C#でこれを行う方法を理解することはできません。たぶん、提供されているP/Invokeインターフェイスを介さずに基礎となるライブラリを呼び出すことができ、カスタムインターフェイスを書くことができますか?

すべてのアイデアをいただければ幸いです。

よろしく、

答えて

3

ここでの他の回答は近いものの、どれも完全ではありません。

まず、p/invoke宣言を宣言するだけです。これはp/invokeについての甘いことです。それを行う方法は決して一つではありません。

[DllImport("whatever.dll")] 
unsafe extern static void ReadFromDevice(int deviceAddress, int numBytes, byte* data); 

今、あなたは[] `、このコードもコンパイルされませんバイト`へ `バイト*`からの変換はありません

unsafe static void ReadFromDevice(int deviceAddress, byte[] data, int offset, int numBytes) 
{ 
    fixed (byte* p = data) 
    { 
     ReadFromDevice(deviceAddress, numBytes, p + offset); 
    } 
} 
2

あなたはまだC#で​​ポインタ演算を行うことができます。

あなたはバイト配列を渡すのIntPtrを使用します(C++ライブラリに対する)DLLインポート-宣言し直した場合、これはAddメソッドを使用して350ずつ増加することができます(これは実際に新しいのIntPtrを返す)

ここに似たような例があります:http://msdn.microsoft.com/en-us/library/system.intptr.add.aspx#Y811

3

ポインタを使用できますが、安全ではないモードでビルドする必要があります。

Byte[] myData = new Byte[1024*1024*16]; 
fixed(Byte * pB = &myData[350]) 
{ 
    ReadFromDevice(0x100, 20000,pB ) 
} 

しかし、まず、エクスポートされたメソッドシグネチャを変更する必要があります。

このように簡単
ReadFromDevice(int deviceAddress, int numBytes, Byte * data); 
+0

でそれを呼び出すことができます。もし彼がC#のソースを管理していれば、それは一つのことになるだろうが、元の質問からは聞こえない。 –

+0

しかし、質問をもう一度読むと、OPがC++ライブラリへのアクセス権を持っているように聞こえるので、単に彼自身のDllImportを追加し、署名を変更してa 'byte []'なら、これはうまくいくでしょう。 downvoteを削除する。 –

+0

" x32をターゲットとしたWin7 x64上のc#、.net 4.0上にアプリケーションを構築しています このライブラリはC++を使用して書かれていますが、開発者はこのライブラリを使用し、P/Invokeを使用してラップしているので、API関数を呼び出す方法です 彼らはC#を制御し、C++ライブラリ用のラッパーを作成しています! – N4rk0

0

ReadFromDevice(int deviceAddress, int numBytes, ref byte data);

...


Byte[] myData = new Byte[1024*1024*16]; 
ReadFromDevice(0x100, 20000, ref myData[350]) // Obviously possible in C# 
+0

しかしReadFromDevice()の宣言を変更しました。私はそのコードを持っていません。サードパーティのライブラリから来ています。 – SomethingBetter

+0

それが.netなら、あなたは常にコードxDを持っています。これはdllimportのように見えるだけでリフレクターをオンにし、アプリに2行をコピーします。 – Zotta

+0

サードパーティのライブラリは、C++コンパイルファイル(明らかに変更できません)とC#ラッパークラスの両方を提供しています。明らかな解決策については私の答えを見てください。 –

0

この問題を解決するには、ソートの明白なようです。

あなたは自分のラッパークラスとDllImportを作成し、独自のラッパークラスを作成するだけで簡単に解決できます。

ReadFromDevice(int deviceAddress, int numBytes, Byte[] data); 

あなたの投稿のコンテキストでは、出力パラメータです。したがって、解決策は、適切なサイズの空のByte配列を送信してから、埋め込み配列を既存の配列に配置することです。

あなたがしなければならないのは、手前で知っていた返された配列のサイズを決定し、塗りつぶして置き換えるだけです。

配列内のspecfic要素のアドレスを送信した場合(certianly可能)、既存の配列を使用するという考えはおそらく機能しますが、C++ライブラリ実際には、おそらくバイト配列そのもののアドレスだけであると考えられます。

+0

時間がかかりますので、コピー操作は避けてください。 )。記述したようにすれば、外部デバイスから読み込んだすべてのデータについて、サードパーティのAPIはデータを小さな配列(ReadFromDevice呼び出しの3番目の引数)にコピーし、次に実行する必要があります私たちの大きな配列に書き込まれた小さな配列のデータを取得する別のコピー操作。したがって、外部デバイスから読み取った30MBのデータごとに、60MBのデータ移動が発生します。パフォーマンス上の理由から、データを一度書きたいと考えています。 – SomethingBetter

関連する問題