2011-07-17 15 views
0

アンマネージドC++では、私はC#から呼び出そうとしている関数を持っています。次のようにこのC++関数は次のとおりです。次のように関数が使用され、C++からC#のパラメータとしてstd :: vector <> :: iteratorを使用してアンマネージC++関数を呼び出す方法は?

typedef std::vector<Point> Points; 
typedef std::back_insert_iterator<Points> OutputIterator; 

namespace MYNAMESPACE{ 
    DLLEXPORT OutputIterator convexHull(Points::iterator first, Points::iterator last, OutputIterator result); 
} 

呼び出されたとき:

Points points, result; 

    points.push_back(Point(0,0)); 
    points.push_back(Point(10,0)); 
    points.push_back(Point(10,10)); 
    points.push_back(Point(6,5)); 
    points.push_back(Point(4,1)); 

    OutputIterator resultIterator = std::back_inserter(result); 

    MYNAMESPACE::convexHull(points.begin(), points.end(), resultIterator); 
    std::cout << result.size() << " points on the convex hull" << std::endl; 

私はC#のコードを書き始めましたが、私はどのようなタイプのさっぱりだが私が合格する必要があります。

[DllImport("unmanagedCode.dll", EntryPoint = "convexHull", CallingConvention = CallingConvention.StdCall)] 
     public static extern ???<Point> convex_hull_2(???<Point> start, ???<Point> last, ???<Point> result); 

ポイント構造をC#でちょうどです:

struct Point{ 
    double x; 
    double y; 
} 

配列やポイントのリストを渡す場合ですか?

私はC++のソースを持っており、関数のパラメータを変更することができます。 C#から呼び出す方が簡単な別の型のパラメータがありますか?

答えて

1

P/InvokeでC++型を渡すことはできません。あなたは彼らのレイアウトを知らず、何も変わらないことを保証しません。 P/Invokeは実際にはCと相互運用するためのものです。

C++の代わりにC++/CLIを使用することもできます。これはポータブルではなく(VC++/Windowsでのみサポートされています)、C++コードの大きさに応じて最も簡単な解決策かもしれません。

C#からストレートP/Invokeを使用したい場合は、C++ convexHullをわずかにリファクタリングして、Cから呼び出し可能な新しい関数(したがってP/Invoke)を提供するのが最善の方法です。

// C-safe struct. 
struct Results 
{ 
    Point *points; 
    std::size_t num_points; 
}; 

// Store the real results in a vector, but derive from the C-safe struct. 
struct ResultsImpl : Results 
{ 
    Points storage; 
}; 

// convexHull has been refactored to take pointers 
// instead of vector iterators. 
OutputIterator convexHull(Point const *first, Point const *last, 
    OutputIterator result); 

// The exported function is callable from C. 
// It returns a C-safe Results, not ResultsImpl. 
extern "C" DLLEXPORT Results* convexHullC(Point const *points, 
              std::size_t num_points) 
{ 
    try 
    { 
     std::unique_ptr<ResultsImpl> r(new ResultImpl); 

     // fill in r->storage. 
     convexHull(points, points + num_points, 
      std::back_inserter(r->storage)); 

     // fill in C-safe members. 
     r->points = &r->storage[0]; 
     r->numPoints = &r->storage.size(); 

     return r.release(); 
    } 
    catch(...) 
    { 
     // trap all exceptions! 
     return 0; 
    } 
} 

// needs to be called from C# to clean up the results. 
extern "C" DLLEXPORT void freeConvexHullC(Results *r) 
{ 
    try 
    { 
     delete (ResultsImpl*)r; 
    } 
    catch(...) 
    { 
     // trap all exceptions! 
    } 
} 

そしてCから#:

[StructLayout(LayoutKind.Sequential)] 
struct Point 
{ 
    double x; 
    double y; 
} 

[StructLayout(LayoutKind.Sequential)] 
struct Results 
{ 
    IntPtr points; 
    IntPtr num_points; 
} 

[DllImport("unmanagedCode")] 
IntPtr convexHullC(Point[] points, IntPtr pointCount); 

[DllImport("unmanagedCode")] 
void freeConvexHullC(IntPtr results); 

Point[] ConvexHull(Point[] points) 
{ 
    IntPtr pr = convexHull(points, new IntPtr(points.Length)); 

    if(pr == IntPtr.Zero) 
    { 
     throw new Exception("native error!"); 
    } 

    try 
    { 
     Results r = Marshal.PtrToStructure(pr, typeof(Results)); 

     points = new Point[checked((int)(long)r.num_points)]; 

     for(int i = 0; i < points.Length; ++i) 
     { 
      points[i] = Marshal.PtrToStructure(
       r.points + Marshal.Sizeof(typeof(Point)) * i, 
       typeof(Point)); 
     } 

     return points; 
    } 
    finally 
    { 
     freeConvexHull(pr); 
    } 
} 

コードテストされていません!

6

C++/CLIラッパークラスを使用します(C++ソースを持つので、既存のコードと共に1つのDLLにコンパイルできます)。

P/invokeはC++クラスとやり取りするためのものではありません。そのような試みは非常に脆弱です。 C++のテンプレートはさらに悪化するかもしれません。試してはいけない。 dllexportが他のC++コードと機能するのはひどい考えですが、vectorvector::iteratorのようなSTLクラスはDLLの境界を越えて渡されるべきではありません。

/clrを使用して、Visual C++コンパイラが詳細を処理するようにします。

関連する問題