2011-01-24 6 views
1

C++ APIのC#バージョンで作業しましたが、それを正しく処理できません。ネイティブAPIをC#に変換し、配列とデリゲートを構造化するMarshalling

私が初めて投稿したときにAPI全体が大きかったので、管理されたバージョンを作成するためには本当に必要ないくつかのコア機能に分けました。

これは基本的に、技術的分析ソフトウェアと通信するために使用されるエクスポートされた関数を含むC++ dllです。

typedef struct FunctionTag 
{ 
    char *Name; 
    FunDesc Descript; 
} FunctionTag; 

FunctionTag gFunctionTable[] = {"ExampleA",{ VExampleA, 0, 0, 0, 0, NULL }, 
          "ExampleB",{ VExampleB, 1, 0, 1, 0, NULL } 
           }; 

FunctionTag構造が含まれています

C++関数IはFunctionTagの配列へのポインタを提供するソフトウェアによって呼び出され

#define PLUGINAPI extern "C" __declspec(dllexport) 

PLUGINAPI int GetFunctionTable(FunctionTag **ppFunctionTable) 
{ 
    *ppFunctionTable = gFunctionTable; 
    // must return the number of functions in the table 
    return gFunctionTableSize; 
} 

GetFunctionTableを変換したいgFunctionTableと呼ばFundescと呼ばれる埋め込み構造:

// FunDesc structure holds the pointer to actual 
// user-defined function that can be called by AmiBroker. 
typedef struct FunDesc 
{ 
    AmiVar (*Function)(int NumArgs, AmiVar *ArgsTable); 
    UBYTE ArrayQty;  // number of Array arguments required 
    UBYTE StringQty;  // number of String arguments required 
    SBYTE FloatQty;  // number of float args 
    UBYTE DefaultQty;  // number of default float args 
    float *DefaultValues; // the pointer to defaults table 
} FunDesc; 

最後に、FundescはAmiVar種類含まれています:これまで

#pragma pack(push, 2) 
typedef struct AmiVar 
{ 
    int type; 
    union 
    { 
     float val; 
     float *array; 
     char *string; 
     void *disp; 
    }; 
} AmiVar; 
#pragma pack(pop) 

C#の変換を

さて、これは私が "模倣" に私のC#のDLLを取得しようとする試みで、これまでに書かれたものですC++元のAPI。

namespace AmiBrokerFrontDll 
{ 
    internal static class AmiBrokerFrontDll 
    { 

    [DllExport("GetFunctionTable", CallingConvention = CallingConvention.Cdecl)] 
    public static Int32 GetFunctionTable(ref FunctionTag[] ppFunctionTable) 
    { 
     FillFunction(); 
     ppFunctionTable=gFunctionTable; 
     return gFunctionTableSize; 
    } 

その後FunctionTag構造の定義が来るとgFunctionTableSize:最後に

[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
    public delegate AmiVar FunctionDelegate(int NumArgs, ref AmiVar ArgsTable); 

    public struct FunDesc 
    { 
     [MarshalAs(UnmanagedType.FunctionPtr)] 
     public FunctionDelegate Function; 
     public byte ArrayQty; // The number of Array arguments required 
     public byte StringQty; // The number of String arguments required 
     public byte FloatQty; // The number of float args 
     public byte DefaultQty; // The number of default float args 
     public IntPtr DefaultValues; // The pointer to defaults table 
    } 

、我々はAmiVarを持っている:

[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
    public struct FunctionTag 
    { 
     [MarshalAs(UnmanagedType.LPStr)] 
     public string Name; 
     public FunDesc Description; 
    } 

    public static FunctionTag[] gFunctionTable=new FunctionTag[1]; 
    public static FunctionTag gfunc; 
    static Int32 gFunctionTableSize = Marshal.SizeOf(gFunctionTable)/Marshal.SizeOf(gfunc); 
    public static void FillFunction() 
    { 
     gFunctionTable[0].Name = "VExempleA"; 
     gFunctionTable[0].Description.Function += VExempleDeMacd; 
     //ArrayQty, StringQty, FloatQty, DefaultQty, DefaultTablePtr 
     gFunctionTable[0].Description.ArrayQty = 0; 
     gFunctionTable[0].Description.StringQty = 0; 
     gFunctionTable[0].Description.FloatQty = 2; 
     gFunctionTable[0].Description.DefaultQty = 0; 
     gFunctionTable[0].Description.DefaultValues = new IntPtr(); 
    } 

FunDesc宣言、デリゲートを含んGetFunctionTableは()関数をエクスポート構造:

[StructLayoutAttribute(LayoutKind.Explicit, Size = 8)] 
    public struct AmiVar 
    { 
     [FieldOffset(0)] 
     public Int32 type; 
     [FieldOffset(4)] 
     public Single val; 
     [FieldOffset(4)] 
     public IntPtr array; 
     [FieldOffset(4)] 
     [MarshalAs(UnmanagedType.LPStr)] 
     public string name; 
     [FieldOffset(4)] 
     public IntPtr disp; 
    } 

申し訳ありませんが、これは長すぎます。残念ながら、私は小さなconsise質問をすることができませんでした。 このコードはコンパイルされています(これは大きな画像から抽出されたものです)。しかし、技術的分析ソフトウェアから結果のdllをロードすると、私はACCESS VIOLATION ERRORを受け取りました。これは、C#変換がC++変数のサイズを正しくマップしないことを意味します。構造と代理人の配列では、このプロジェクトは単独で解決するのが難しくなってきました。

ご協力いただければ幸いです。

おかげで、 ギヨーム

+0

これを削除してください。誰がこのすべてを読もうとしているのだろうか? –

+0

何をしようとしていますか? C#でC++ APIを "模倣"したいのはなぜですか? C#で既存のC++ APIを使ってsimpkyしたいのですか? –

+0

いいえ、私はC++であり、この言語を理解できないため、既存のAPIを使用したくありません。基本的には、dllをロードし、5つの標準関数を使用してDLL関数と変数ポインタと通信するアプリケーションです。 GetFunctionTable()はその1つです。 C++のようなアプリケーションで認識されるC#バージョンを作成するという点は、dllを拡張して、GUIインターフェイスの追加、公開前のアプリケーションからのデータの抽出や分析などのアプリケーション機能を簡単に拡張することですウェブサイトなどで – djahma

答えて

1

は、私はあなたの特定の場合に役立つことはできませんが、私はあなたの人生が容易になります物事のカップルを伝えることができます:管理代表者から作成

  1. 関数ポインタをすべき管理されていないコードに格納されることはありません。私はこれを軽く言わない。 GetFunctionPointerForDelegateというデリゲートから関数ポインタを作成すると、適切なサンクが作成され、ガベージコレクションされないという主張があります。これはではなく、です。私は、1つのコールでうまく機能する関数ポインタが次のコールに行きます。最も安全な方法は、関数ポインタが管理されていない呼び出しの使用以上に格納されないことを保証することです。
  2. P/Invokeはいくつかのタスクでは問題ありませんが、C++以外のC++ライブラリを統合する最も簡単な方法は、C++/CLIでより適切なラッパーを作成することです。問題にアプローチする方法の説明については、hereを参照してください。
関連する問題