2016-12-28 13 views
1

私は、C#GUIとソケット接続処理用のC++コードを混在させています。 問題は、文字列をC++ char * DLLに渡すと、C++クラス(?)の値が変更されるということです。DLLを使用してC#StringBuilder/stringをC++ char *に渡す

は、私は少しエラーの原因を見て回るように変更されたソケットを扱うためのクラスを持っているし、いくつかの機能は、私はクラス自体に取得させる:

extern "C" { __declspec(dllexport) 

    class mySock 
    { 

     int port; 
     SOCKET littleSock; 

     public: 
      char* ipAddress; 
      mySock() {}; 
      mySock(char* inIP, int inPort); 
      ~mySock(); 
      int initialize(); 
      int sendMsg(char* Msg); 
      //int addition(int a, int b); 

    }; 
} 

extern "C" { __declspec(dllexport) mySock* mySock_Create(char* IP, int prt);} 
extern "C" { __declspec(dllexport) mySock* mySock_Create1(); } 
extern "C" { __declspec(dllexport) int mySock_initialize(mySock* inSocket); } 
extern "C" { __declspec(dllexport) int mySock_sendMsg(mySock* inSocket,char* Msg); } 
extern "C" { __declspec(dllexport) void mySock_delete(mySock* inSocket); } 
extern "C" { __declspec(dllexport) void CopyStr(char* str1, mySock* inSocket) 
    { 
     strcpy_s(str1, strlen(str1), inSocket->ipAddress); 
    }; 
} 

問題は、使用中のどこかで発生しましたmySock_Createの

基本的には、次のとおりです。

mySock* mySock_Create(char* IP, int prt) 
{ 
    return new mySock(IP, prt); 
} 

コンストラクタを呼び出す:

mySock::mySock(char* inIP, int inPort) 
{ 
    ipAddress = inIP; 
    port = inPort; 
} 

その後ipAddressはのinet_addrで使用してリモートサーバーに接続されます。 とにかく、上記のコードは私がサーバーに接続することはできませんが、私は単純に、このようなIPアドレスをハードコーディングする場合:

mySock* mySock_Create(char* IP, int prt) 
{ 
    return new mySock("192.168.1.164", prt); 
} 

をそれは正常に動作し、ローカルサーバーに接続します。

私は上記のDLLヘッダーコードで確認できるCopyStrを追加しました。mySockオブジェクトのIPアドレスを取得してC#テキストボックスに書き込むことになっています。

実際にハードコードされたIPアドレスの場合は、そのIPアドレスが表示されますが、C#からIPアドレスを渡した場合は、ここに貼り付けられない矩形記号だけが返されます。

ここでDLLをリンクして使用するためのC#のコードは次のとおりです。

[DllImport("G:\\socketstraning\\klikacz\\MyFirstDLLyay\\Debug\\MyFirstDLL.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern IntPtr mySock_Create(StringBuilder IP, int prt); 
[DllImport("G:\\socketstraning\\klikacz\\MyFirstDLLyay\\Debug\\MyFirstDLL.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern int mySock_initialize(IntPtr value); 
[DllImport("G:\\socketstraning\\klikacz\\MyFirstDLLyay\\Debug\\MyFirstDLL.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern int mySock_sendMsg(IntPtr value, string Msg); 
[DllImport("G:\\socketstraning\\klikacz\\MyFirstDLLyay\\Debug\\MyFirstDLL.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern void mySock_delete(IntPtr value); 
[DllImport("G:\\socketstraning\\klikacz\\MyFirstDLLyay\\Debug\\MyFirstDLL.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern IntPtr mySock_Create1(); 
[DllImport("G:\\socketstraning\\klikacz\\MyFirstDLLyay\\Debug\\MyFirstDLL.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern void CopyStr(StringBuilder str1, IntPtr value); 

private void button3_Click(object sender, EventArgs e) 
{ 
    StringBuilder str = new StringBuilder("192.168.1.164", 50); 
    IntPtr we = mySock_Create(str, 16999); 
    StringBuilder str2 = new StringBuilder("255.255.255.255", 25); 
    CopyStr(str2, we); 
    textBox1.Text = str2.ToString(); 
    if (mySock_initialize(we) == -2) 
     button3.Text = "Ups"; 

    mySock_delete(we); 
} 

私はまた、文字列を使用しての代わりに、StringBuilderのか、インポートオプションのcharset = CharSet.Ansiを追加しようとしました。

私はこのような場合に文字列をchar*に渡すことについて多くの質問と解決策を読んだことがありますが、なぜipAddressの値が正しく渡されなかったり、別の場所で変更されたのかわかりません。

私は既に上記のコードと戦った後にかなり外れているので、私は問題をはっきりと述べました。

+0

C++コードでは、ポインタを格納するだけでなく、バ​​ッファを割り当てて送信された文字列をコピーする必要があります。 – PaulMcKenzie

答えて

0

主な問題は、あなたのC++コンストラクタである:

ここ
mySock::mySock(char* inIP, int inPort) 
{ 
    ipAddress = inIP; 
    port = inPort; 
} 

あなたは文字配列へのポインタのコピーを作成します。これには、ipAddressを使用する必要がある限り、このポインタは有効なままでなければなりません。 C#からマーシャリングされた文字列は、p/invoke呼び出しの間だけ有効です。

確かに、このクラスをC++からのみ使用していたとしても、デザインはうまくいかないでしょう。あなたのクラスは、ポインタのコピーではなく文字列のコピーを取る必要があります。

解決策は、C++コードがstd::stringを排他的に使用することです。そのクラスでメモリの管理とコピーができるようにします。 p/invoke interop境界でのみC文字列を使用します。

変更ipAddressタイプstd::stringであることと、このようなコンストラクタの外観を持っている:

mySock::mySock(const std::string inIP, const int inPort) 
{ 
    ipAddress = inIP; 
    port = inPort; 
} 

あなたはまだあなたの相互運用ラッパー関数にC文字列を使用する必要があるが、それはconst char*からの暗黙的な変換を利用することができますstd::string

mySock* mySock_Create(const char* IP, const int prt) 
{ 
    return new mySock(IP, prt); 
} 

は限りP /呼び出しが行くように、あなたはStringBuilderchar*誤用します。着信側によって変更された発信者割当バッファがあるときにペアリングされます。 C++コードに渡される文字列には、stringconst char*を使用します。

[DllImport("...", CallingConvention = CallingConvention.Cdecl)] 
public static extern IntPtr mySock_Create(string IP, int prt); 
+0

ありがとう! 最後にこれは私が探していた答えです(または、ATMだと思います) 私のコードのどこに問題があるのか​​理解しています。 :) あなたはchar *の代わりに単に文字列を使うことを提案していますが、代わりにchar * use c_str()メソッドが必要ですか? 現在、私はC#の文字列をC++で渡すことに取り組んでいますが、すでにこの回答を最も有用なものとしてマークしています – Poziokat

+0

文字列はC#からC++に渡されるので、c_str()を使う必要はありません。 const char *からstd :: stringへの暗黙的な変換があるので、ラッパー関数my socks createはconst char *を受け取り、コンストラクターを呼び出すときにその暗黙の変換を使用できます。 –

+0

ありがとうございます! これで完璧にうまく動作します:) – Poziokat

関連する問題