2017-05-03 12 views
4

私は単純な答えがあると確信していますが、私はいくつかの研究の後でそれを見つけることができませんでした。マネージドメモリに割り当てられた参照(またはクラス)によって渡された自動的に整列化された構造体がネイティブコードで正しく読み書きされていることを読んだり(私が書いたものが間違っていない限り)、証明されましたが、ネイティブコード内で変更された値は保持されません。ここでは例:マーシャルされたオブジェクトがネイティブコード内で変更された値を保持しないのはなぜですか?

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
public class DirtyWordsCheckResult 
{ 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)] 
    public string replace_string; 
    public EnumDirtyWordsType dirty_type; 

    public DirtyWordsCheckResult() 
    { 
     replace_string = new string(' ', 1024); 
    } 
} 

public enum EnumDirtyWordsType 
{ 
    kDirtyWordsTypeNormalAllowWords = 0, // normal allow words 
    kDirtyWordsTypeEvil = 1,    // illegal,can not be displayed 
    kDirtyWordsTypeSensitive = 2,   // legal, but contain sensitive 
} 

public override EResult DirtyWordsFilter(string words, bool replace_sensitive, out DirtyWordsCheckResult check_result) 
{ 
    check_result = new DirtyWordsCheckResult(); 
    var result = Utils.DirtyWordsFilter(utils_, words, replace_sensitive, check_result); 
    return result; 
} 

ネイティブ関数DirtyWordsFilterは、しかし、値が保持されない、正しく割り当てられたオブジェクトを取得し、問題なくそれに書き込むことができません。

Marshal.AllocHGlobalを使用して事前割り当てIntPTRを渡すことができるため、解決策を探していないことに気付きました。なぜ元のメカニズムが機能しないのか不思議です。

答えて

5

使用する構造体は、blittableではありません。ネイティブレイアウトが管理されたレイアウトと同じでないことを意味する高価な単語。文字列が原因です。 CharSetだけでなく、.NETの文字列はchar []のようには見えません。そのため、pinvoke marshallerは、ネイティブコードで使用できるポインタを渡す前に正しいサイズのコピーを作成する必要があります。

ただし、ではありません。では、変更された構造体を元にコピーします。そのパラメータに[Out]を入れて、それを変更する必要があります。私たちは、[DLLIMPORT]宣言を見ることはできませんが、それは似ているはずである:

[DllImport(...)] 
private static extern EResult DirtyWordsFilter(..., [Out] DirtyWordsCheckResult check_result); 

のPInvokeマーシャラーは、データフローの具体的な知識を持っていませんあなたがのために通常存在する宣言(中refまたはoutを使用する場合でも、構造体宣言)。それは単に参照渡しの引数を見て、デフォルトとして[In]と仮定します。通常、ここではなく、正確で最適な推測。 Fwiw、Pack = 1はほとんど決して正しいとは言えません。ネイティブコードで使用されているパッキングと一致する必要があります。デフォルトは8です。この特定のケースでは問題になりません。

+0

は、[outキーワード](https://msdn.microsoft.com/en-us/library/t3c3bfhx.aspx)または[out属性](https://msdn.microsoft.com/en- us/library/system.runtime.interopservices.outattribute(v = vs.110).aspx)を使用する必要があります。あなたはあなたの答えに両方を使うようです。 –

+0

引用:「あなたは '[Out]'をパラメータにつける必要があります。角かっこ==属性。 –

+0

私は最初に最後の段落の最初の3つの文を理解するのが難しかった。私は今あなたが何を意味するかを知る。 –

関連する問題