2009-02-22 10 views
6

私は、外部アプリケーションで使用する必要のあるメソッドを含むC#クラスライブラリを持っています。残念ながら、この外部アプリケーションはC/C++の外部APIしかサポートしていません。配列をC++からC#に移動して変更し、それをC++に戻す最も簡単な方法

今私はC++ DLLとC#DLLの間で動作する非常に単純なCOMの例を得ることができましたが、配列データをどのように動かすことができるかについては固執しています。

DLL_EXPORT(void) runAddTest(int add1,long *result) { 
    // Initialize COM. 
    HRESULT hr = CoInitialize(NULL); 

    // Create the interface pointer. 
    IUnitModelPtr pIUnit(__uuidof(UnitModel)); 

    long lResult = 0; 

    // Call the Add method. 
    pIUnit->Add(5, 10, &lResult); 

    *result = lResult; 

    // Uninitialize COM. 
    CoUninitialize(); 

} 

これは私のC#クラスのAddメソッドを呼び出すために正常に動作します:

これは、私はちょうど私がCOMを介して通信のウェブ上で発見少し例として、これまで持っているものです。これを変更して複数の倍数を取得して返すにはどうすればよいですか? (また、行の下の文字列でそれを行う必要があります)。

私はアンマネージド配列を取って、この配列をいくつかの計算のためにC#クラスに渡し、元の関数呼び出し(アンマネージド)C++で指定された配列参照に結果を戻します。

私はこのような機能を公開する必要があります:


* calcin - doubleの配列への参照

* calcOut - の価値 - ダブルスの

numINの配列への参照入力配列のサイズ

DLL_EXPORT(void) doCalc(double *calcIn, int numIn, double *calcOut) 
{ 
     //pass the calcIn array to C# class for the calcuations 

     //get the values back from my C# class 

     //put the values from the C# class 
     //into the array ref specified by the *calcOut reference 


} 

I 私は外部アプリケーション用にC++ \ CLI DLLを使用できます。これがまっすぐなCOMよりも簡単な場合、私はそれを見て喜んでいます。

私は主にC#開発者ですが、InteropとC++の深いところに投げ込まれました。

答えて

3

私はこれまでにこれを実験しましたが、残念ながらそれがすべてどのように適合しているのか忘れてしまいました...私の目的のためには、悲惨なことに判明したので、C#を切り出してすべてのC++に戻りました。あなたが主にC#開発者であると言うとき、私はポインタを理解してくれることを願っています。そうでなければ、穏やかな方法がないからです。配列を渡す

は、基本的にはダウン( - AllocCoTaskMemようなメソッドを有するhttp://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.aspx)C++側(http://msdn.microsoft.com/en-us/library/ms692727(VS.85).aspx)とC#側Marshalクラスに機能のCoTaskMemAllocファミリを使用することになりました。

public class serviceUtils 
{ 
    unsafe public long stringToCoTaskPtr(ref str thestring) 
    { 
     return (long)Marshal.StringToCoTaskMemAnsi(thestring.theString).ToPointer();//TODO : what errors occur from here? handle them 
    } 

    unsafe public long bytesToCoTaskPtr(ref bytes thebytes, ref short byteCnt) 
    { 
     byteCnt = (short)thebytes.theArray.Length; 
     IntPtr tmpptr = new IntPtr(); 
     tmpptr = Marshal.AllocCoTaskMem(byteCnt); 
     Marshal.Copy(thebytes.theArray, 0, tmpptr, byteCnt); 
     return (long)tmpptr.ToPointer(); 
    } 

    public void freeCoTaskMemPtr(long ptr) 
    { 
     Marshal.FreeCoTaskMem(new IntPtr(ptr));//TODO : errors from here? 
    } 

    public string coTaskPtrToString(long theptr) 
    { 
     return Marshal.PtrToStringAnsi(new IntPtr(theptr)); 
    } 

    public byte[] coTaskPtrToBytes(long theptr, short thelen) 
    { 
     byte[] tmpbytes = new byte[thelen]; 
     Marshal.Copy(new IntPtr(theptr), tmpbytes, 0, thelen); 
     return tmpbytes; 
    } 
} 

はちょうどあなたにいくつかのより多くのコードをスローする:C#の場合、私はユーティリティクラスになってしまった このC++

#import "..\COMClient\bin\Debug\COMClient.tlb" named_guids raw_interfaces_only 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
CoInitialize(NULL); //Initialize all COM Components 
COMClient::IComCalculatorPtr pCalc; 
// CreateInstance parameters 
HRESULT hRes = pCalc.CreateInstance(COMClient::CLSID_ComCalculator); 
if (hRes == S_OK) { 
    long size = 5; 
    LPVOID ptr = CoTaskMemAlloc(size); 
    if(ptr != NULL) 
    { 
     memcpy(ptr, "12345", size); 
     short ans = 0; 
     pCalc->changeBytes((__int64*)&ptr, &size, &ans); 
     CoTaskMemFree(ptr); 
    } 
} 

CoUninitialize(); //DeInitialize all COM Components 

return 0; 
} 

public short changeBytes(ref long ptr, ref int arraysize) 
    { 
     try 
     { 
      IntPtr interopPtr = new IntPtr(ptr);     
      testservice.ByteArray bytes = new testservice.ByteArray(); 
      byte[] somebytes = new byte[arraysize]; 
      Marshal.Copy(interopPtr, somebytes, 0, arraysize); 
      bytes.theArray = somebytes; 

      CalculatorClient client = generateClient(); 
      client.takeArray(ref bytes); 
      client.Close(); 
      if (arraysize < bytes.theArray.Length) 
      { 
       interopPtr = Marshal.ReAllocCoTaskMem(interopPtr, bytes.theArray.Length);//TODO : throws an exception if fails... deal with it 
      } 
      Marshal.Copy(bytes.theArray, 0, interopPtr, bytes.theArray.Length); 
      ptr = interopPtr.ToInt64(); 

      arraysize = bytes.theArray.Length; 

      //TODO : do we need to free IntPtr? check all code for memory leaks... check for successful allocation 
     } 
     catch(Exception e) 
     { 
      return 3; 
     } 

     return 2; 
    } 

申し訳ありませんが、このC#のと呼ばれるが、私これをすべて実行して適切に説明する時間はありません。うまくいけば、これはあなたに正しい方向へのポインタを、少なくともGoogleのいくつかの点で提供します。幸運

PS:私はネットからこのものを書くためにすべての情報を得たので、そこにあります。

1

私は外部アプリケーション用にC++ \ CLI DLLを使うことができると思います。これがまっすぐなCOMよりも簡単なら、それを見て喜んでください。

あなたは多くのCOMの経験を持っていない(と配列がCOMで大幅に単純ではありません)場合は、C++/CLIのラッパー3 RDパーティーはおそらく容易になります周り。

また、管理された< - > COMインターフェイスに必要なCOM呼び出し可能ラッパーを追加するのではなく、1つのマーシャリングステージ(ネイティブの< - >管理対象)のみになります。

0

これも動作しますか?

C#の

、 1コールMarshal.PtrToStructure 2.値を変更 3.コールMarshal.StructureToPtr

関連する問題