2009-03-26 19 views
2

ここから始まる問題についてはまだ Calling C++ dll function from C#: Of structs, strings and wchar_t arrays.で作業していますが、アプローチは異なります。C#で書かれたdllにC#データ型パラメータを渡す?

例の後にCalling Managed Code from Unmanaged Code and vice-versa私はアンマネージドC++ dllのunmanagesクラスにアクセスするためにC++でマネージラッパーを作成しました。

それは次のようになります。

//in header file 
public __gc class TSSLDllWrapper 
{ 
public: 
TSSLDllWrapper(); 
    //this is the unmanaged class 
CcnOCRsdk * _sdk; 

bool convertHKID_Name(char *code, RECO_DATA *o_data); 
}; 

//in .cpp file 
TSSLDllWrapper::TSSLDllWrapper(void) 
{ 
    _sdk = new CcnOCRsdk(); 
} 

bool TSSLDllWrapper::convertHKID_Name(char *code, RECO_DATA *o_data) 
{ 
return _sdk->convertHKID_Name(code, o_data); 
} 

//C++ RECO_DATA structure definition: 
struct RECO_DATA{ 
wchar_t FirstName[200]; 
wchar_t Surname[200]; 
}; 

今、私は私のC#プロジェクトにインポートすることができますDLLを持っています。ここで

は、しかし問題です:

TSSLDllWrapper wrapper = new TSSLDllWrapper(); 
bool res = wrapper.convertHKID_NameSimple(//need to pass parameters here); 

それは、C++のパラメータを期待 - ポインタはchar型とRECO_DATAする: 私はこのように、dllファイルからメソッドを呼び出したいとき。

これを修正してC++コードをC#コードから渡すにはどうすればよいですか?

答えて

5

ほとんどのCデータ型を変換する1つの方法は、PInvoke Interop Assitantを使用することです。これは、ほとんどのC構造に対して適切なC#/ VB.Net型を作成します。ここでのchar *パラメータについては

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet=System.Runtime.InteropServices.CharSet.Unicode)] 
public struct RECO_DATA { 

    /// wchar_t[200] 
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst=200)] 
    public string FirstName; 

    /// wchar_t[200] 
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst=200)] 
    public string Surname; 
} 

RECO_DATA

出力され、あなたがIntPtr.Zeroを渡すか、または仕事を得るためにMarshal.StringToCoTaskMemAnsiを使用することができます。

+0

ありがとう、私はついにそれをすべて一緒に作った – Evgeny

0

DLLラッパーの作成中に私がつまずいたポイントのカップル:私は管理対象外のクラスのメンバ関数を呼び出す必要があった

  • を。私はDllImportを直接使用することでこれを行うことができないが、自分自身で「ラッパー」を作成しなければならないことを確認するためにしばらく時間がかかりました。
  • ラッパー自体では、メンバー関数だけをラップするだけでは十分ではありません。私はC++クラスへのポインタを作成することができなければなりません。ポインタをコンストラクタにエクスポートしなければなりません(少なくとも、それは私が理解する方法です。私は、最初にメンバー関数をエクスポートしようとしましたが、コンパイルされましたが、実行時に "AccessViolationException"が返されました。しばらくの間そこにぶら下がってしまった。

したがって、私のラッパーは、この(using a class defined in a c++ dll in c# codeで提案されているように)次のようになります。クラスレベルの輸出クラスのすべてのパブリックメンバーに

public class __declspec(dllexport) Wrapper 
{ 
public: 
    CcnOCRsdk* SDKCreate() 
    { 
     return new CcnOCRsdk(); 
    } 

    bool CcnOCRsdk_HKID(CcnOCRsdk* pSDK, char *code, RECO_DATA *o_data) 
    { 
     return pSDK->convertHKID_Name(code, o_data); 
    } 

    void SDKDelete(CcnOCRsdk* pSDK) 
    { 
     delete pSDK;  
    } 
}; 

__declspec(のdllexport)。 SDKCreate()は、CcnOCRsdkクラスへのポインタを、アンマネージdllから呼び出す必要があるメンバ関数から返します。 CcnOCRsdk_HKIDは、そのメンバ関数を呼び出します。 CcnOCRsdkへのポインタが渡されることに注意してください。

コードがdllに組み込まれた後、私は書いたラッパーdllの 'mangled'エントリポイントが何であるか調べるためにDUMPBINを使用する必要があります。私のラッパーの

、結果は今、私は最終的にC#で、私のラッパーを使用する準備ができています。この

 1 0 00001240 [email protected]@@[email protected]@@Z = [email protected][email protected]@@[email protected]@@Z ([T2M] public: class TSSL::Wrapper & __thiscall TSSL::Wrapper::operator=(class TSSL::Wrapper const &)) 
     2 1 00001220 [email protected]@[email protected]@[email protected]@[email protected]@@Z = [email protected][email protected]@[email protected]@[email protected]@[email protected]@@Z ([T2M] public: bool __thiscall TSSL::Wrapper::CcnOCRsdk_HKID(class CcnOCRsdk *,char *,struct RECO_DATA *)) 
     3 2 00001200 [email protected]@[email protected]@[email protected]@XZ = [email protected]@[email protected]@[email protected]@XZ (public: class CcnOCRsdk * __thiscall TSSL::Wrapper::SDKCreate(void)) 
     4 3 00001410 [email protected]@[email protected]@[email protected]@@Z = [email protected]@[email protected]@[email protected]@@Z (public: void __thiscall TSSL::Wrapper::SDKDelete(class CcnOCRsdk *)) 

のように見えます。私はdumpbinからの出力とまったく同じようにエントリポイントを指定せずにこれを行ったとき、私は 'エントリポイントを見つけることができません'というエラーが出ました。

[DllImport(@"TSSLWrapper.dll", EntryPoint = "[email protected]@[email protected]@[email protected]@XZ")] 
    public static extern IntPtr SDKCreate(); 
    [DllImport(@"TSSLWrapper.dll", EntryPoint = "[email protected]@[email protected]@[email protected]@[email protected]@@Z")] 
    public static extern bool CcnOCRsdk_HKID(IntPtr ptr, string num, out RECO_DATA o_data); 

RECO_DATAは、JaredParが推奨するものとして定義されています。

最後のステップは、結果を楽しむことです。私は私の解像度

RECO_DATA recoData = new cnOCRsdk.RECO_DATA(); 
    string num = "262125355174"; 

    IntPtr ptr = cnOCRsdk.SDKCreate(); 
    bool res = cnOCRsdk.CcnOCRsdk_HKID(ptr, num, out recoData); 

をクラスのコンストラクタを呼び出し、その関数への実際の呼び出しへのポインタを渡す必要があり ファーストはtrueを返し、と私はrecoDataに期待される結果が得られます。

関連する問題