2011-01-12 6 views
4

私はC++ヘッダーを持つdllでメソッドを呼び出そうとしています。私はC#からDLLを呼び出しています。入力は文字列で、出力はバイナリデータです。次の3つの方法のいずれかがうまくいくかもしれませんが、私はそれらのどれかをどのように働かせるかわかりません。 C#宣言は私によって作成されているため、正しくない可能性があります。C#のC++ヘッダーでdllを呼び出す

1:私はhGlobalを取得できますが、ハンドルからデータを取得する方法はわかりません。

//CMBT_LL_WINAPI INT DLLPROC LlConvertStringToHGLOBALW(LPCWSTR pszText, _PHGLOBAL phMemory); 
[DllImport("cmll15.dll", EntryPoint = "LlConvertStringToHGLOBALW", CharSet = CharSet.Unicode, ExactSpelling = true)] 
private static extern int _LlConvertStringToHGlobal32(string text, ref IntPtr handle); 

[DllImport("cmll15.dll", EntryPoint = "LlConvertStringToBLOBW", CharSet = CharSet.Unicode, ExactSpelling = true)] 
//CMBT_LL_WINAPI INT  DLLPROC LlConvertStringToBLOBW(LPCWSTR pszText, _PUINT8 pBytes, UINT nBytes); 
private static extern int _LlConvertStringToBLOBW(string text, ref IntPtr pBytes, UInt32 nBytes); 

3:

更新
[DllImport("cmll15.dll", EntryPoint = "LlConvertStringToStreamW", CharSet = CharSet.Unicode, ExactSpelling = true)] 
//CMBT_LL_WINAPI INT  DLLPROC LlConvertStringToStreamW(LPCWSTR pszText, _PISTREAM pStream); 
private static extern int _LlConvertStringToStreamW(string text, ref IntPtr pStream); 

、ここで私は私が終わるだろうと思いコードです。 1について

[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] 
    private static extern UIntPtr GlobalSize(IntPtr hMem); 

    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] 
    public static extern IntPtr GlobalLock(IntPtr handle); 

    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] 
    public static extern IntPtr GlobalUnlock(IntPtr handle); 

    [DllImport("cmll15.dll", EntryPoint = "LlConvertStringToHGLOBALW", CharSet = CharSet.Unicode, ExactSpelling = true)] 
    private static extern int _LlConvertStringToHGlobal32(string text, ref IntPtr handle); 

    private static void Main(string[] args) 
    { 
     IntPtr dataHandle = IntPtr.Zero; 
     _LlConvertStringToHGlobal32(Contents, ref dataHandle); 
     try 
     { 
      var size = (uint) GlobalSize(dataHandle); 
      var array = new byte[size]; 
      IntPtr dataPtr = GlobalLock(dataHandle); 
      try 
      { 
       Marshal.Copy(dataPtr, array, 0, array.Length); 
      } 
      finally 
      { 
       GlobalUnlock(dataPtr); 
      } 

      using (var fs = new FileStream("c:\\file.dat", FileMode.Create)) 
      { 
       fs.Write(array, 0, array.Length); 
      } 
     } 
     finally 
     { 
      Marshal.FreeHGlobal(dataHandle); 
     } 
    } 
+0

コンパイルして実行しましたか?私たちが理解できるように問題を特定してください。 – Nawaz

+1

'CharSet.Unicode'を指定している場合は、なぜ' ExactSpelling'と 'EntryPoint'も指定していますか?それらは冗長です。 –

+0

私の問題は、C++からC#へのメソッドの翻訳については考えていませんが、わかりません。私はそれらを示したので、何か間違った点を見つけることができるかもしれません。私はC#のシグネチャが正しいと思いますが、メソッドを呼び出すか、メソッドからの指定された出力を使用することは今知らない – Karsten

答えて

1

最初の人は、必要なサイズを知るために、呼び出し先にそれを残すので、行くのが最も簡単なはずです。ただし、割り当てのサイズをどのように知っているかは分かりません。たぶん戻り値。 GlobalSize()を常にピンボケして、HGLOBALハンドルからサイズを取得できます。ハンドルをポインタに変換するには、GlobalLock()をピンボケし、Marshal.CopyMemory()を使用してバイトを[]にコピーします。メモリを解放するためにGlobalUnlock()とMarshal.FreeHGlobal()を呼び出してクリーンアップし、finallyブロックの中に入れて漏れないようにします。

2番目の引数は、byte [](not ref)と宣言する必要があります。問題は、アレイの大きさを前もって推測しなければならないことです。故障モードは、サイズが小さすぎると推測します。

3番目にはCOM IStreamが必要です。 System.Runtime.InteropServices.ComTypes.IStreamとして宣言します。これは.NETストリームのように動作します。Seekを呼び出して最初を探し、Readを呼び出してデータを読み込みます。

私はあなたの顔に爆破する可能性が最も低い最初のものに行きます。

+0

私は解決策があると思う。 GlobalLockに電話する必要があると思われます。それ以外の場合は、私のためにはうまくいかないでしょう。ここでソースは、それを改善するために自由に感じる。 IntPtr h = IntPtr.Zero; _LlConvertStringToHGlobal32(ContentsB、ref h); UIntPtr size = GlobalSize(h); var配列=新しいバイト[(int)サイズ]; IntPtr globalLock = GlobalLock(h); Marshal.Copy(globalLock、array、0、array.Length); – Karsten

+1

きれいに掃除する必要があります。 GlobalUnlockとMarshal.FreeHGlobal。 –

+0

あなたは正しいです、ありがとう – Karsten

-1

: あなたは、バイナリデータ出力の長さを有しており、次のようにMarshal.Copy方法を用いなければならない: バイト[]データ=新しいバイト[長さ]。 Marshal.Copy(handle、data、0、length);

2の場合& 3:あなたの問題は何ですか?

+0

約1、 。約2私はまだ長さを知らないので、入力をnBytesに設定することはできません。約3、pStream = IntPtr.Zeroでメソッドを呼び出すと失敗します。そのため、有効なIStreamを指すはずです。私はそのようなメソッドを作成する方法がわかりません。 – Karsten

+0

1:長さが足りない場合、答えは決してありません。 C/C++では、どの配列もサイズを持つので、長さを管理する必要があります。 dllのコードが手元にある場合は、長さの出力パラメータを追加する必要があります。そうでなければ、dllサポートの中にデータ配列の長さを取得する関数があるはずです。最終的には、文字列のエンコーディングが何であるかを知っておく必要があります。そして、手前の長さを知ることができます(例えば、ASCII文字列でtext.Lengthを渡すか、UTF16ならtext.Length * 2を渡します)。 – longbkit

+0

3の場合:IntPtrを使用してください。pStream = Marshal.AllocHGlobal(バイト数)。 – longbkit

関連する問題