2009-09-30 15 views
5

मैं एक सी DLL समारोह फोन कर रहा हूँ और निम्नलिखित सी struct आपूर्ति की जरूरत:मार्शलिंग सरणी सी # में चार को **

typedef struct 
{ 
    char  *mTableId; 
    char  **mFieldNames; 
    int  mNumFields; 
    char  *mFilter; 
    char  *mSort; 
    int  mOffset; 
    int  mMaxRecords; 
    char  *mTargetRecordFilter; 
    int  mSurroundingRecordsCount; 
    int  *mOwnerIds; 
    int  mNumOwnerIds; 
    gsi_bool mCacheFlag; 
} SAKESearchForRecordsInput; 

समस्या चार ** mFieldNames साथ है; मैं अपने आप को इस तरह वास्ते की कोशिश की है:

[MarshalAs (UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPTStr, SizeConst = 9)] सार्वजनिक String [] mFieldNames;

इस तरह मुझे मार्शल.SizeOf() में एक त्रुटि मिलती है - सही आकार की गणना नहीं कर सकता। तब मैंने मैन्युअल रूप से पॉइंटर्स से निपटने का फैसला किया। यह वास्तव में सी तारों की सरणी के लिए एक सूचक है। यहां मेरा कोड है जो

सिस्टम.AccessViolationException: संरक्षित स्मृति को पढ़ने या लिखने का प्रयास किया गया है। यह अक्सर एक संकेत है कि अन्य स्मृति भ्रष्ट है।

तो मैंने कहीं पॉइंटर्स को खराब कर दिया है। कोड मेरे लिए ठीक लगता है, बग कहां है?

सी #:

[StructLayout(LayoutKind.Sequential)] 
unsafe public class SAKESearchForRecordsInput { 
    [MarshalAs(UnmanagedType.LPTStr)] 
    public String mTableId; 
    //[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPTStr, SizeConst = 9)] // HARDCODED!?! 
    //public String[] mFieldNames;  // char  **mFieldNames; 
    public IntPtr mFieldNames; 
    public int mNumFields; 
    [MarshalAs(UnmanagedType.LPTStr)] 
    public String mFilter; 
    [MarshalAs(UnmanagedType.LPTStr)] 
    public String mSort; 
    public int mOffset; 
    public int mMaxRecords; 
    //[MarshalAs(UnmanagedType.LPTStr)] 
    public IntPtr mTargetRecordFilter; 
    public int mSurroundingRecordsCount; 
    public IntPtr mOwnerIds; 
    public int mNumOwnerIds; 
    public gsi_bool mCacheFlag; 
} 

    [DllImport("saketestd.dll")] 
    unsafe static extern void* sakeSearchForRecords(
    IntPtr sake, 
    IntPtr input, //SAKESearchForRecordsInput * 
    SAKERequestCallback callback, //SAKERequestCallback 
    IntPtr userData); 

    unsafe public bool sakeSearchForRecordsE() { 
    bool ret = false; 
    try { 
    searchInput.mTableId = "bbdx_score"; 
    //searchInput.mFieldNames = mFieldNames.to; 
    searchInput.mFilter = "num_ratings = 0 AND filestore > 0"; 
    searchInput.mSort = ""; 
    searchInput.mOffset = 0; 
    searchInput.mMaxRecords = 1; 
    //searchInput.mTargetRecordFilter = ""; 
    searchInput.mSurroundingRecordsCount = 0; 
    searchInput.mOwnerIds = IntPtr.Zero; 
    searchInput.mNumOwnerIds = 0; 
    searchInput.mCacheFlag = true; 

    int sakeSize = Marshal.SizeOf(sake); 
    debug.AddLine(this.getMethodName() + ": sizeof(sake): " + sakeSize); 
    IntPtr pSake = Marshal.AllocHGlobal(sakeSize); 
    Marshal.StructureToPtr(sake, pSake, true); 

    int inputSize = Marshal.SizeOf(searchInput); 
    debug.AddLine(this.getMethodName() + ": sizeof(input): " + inputSize); 
    IntPtr pInput = Marshal.AllocHGlobal(inputSize); 
    Marshal.StructureToPtr(searchInput, pInput, true); 

    IntPtr[] mFieldNamesPtr; 
    int i; 
    if (true) { // IntPtr[] 
    mFieldNamesPtr = new IntPtr[mFieldNames.Length]; 
    i = 0; 
    foreach (string str in mFieldNames) { 
     mFieldNamesPtr[i++] = Marshal.StringToHGlobalAnsi(str); 
    } 
    //searchInput.mFieldNames = mFieldNamesPtr; 
    } else { 
    //searchInput.mFieldNames = mFieldNames; 
    } 
    searchInput.mNumFields = mFieldNames.Length; 

    void* pRequestInternal = null; 
    void* p = mFieldNamesPtr[0].ToPointer(); 
    searchInput.mFieldNames = (IntPtr)p; 
    pRequestInternal = sakeSearchForRecords(
     pSake, 
     pInput, 
     new SAKERequestCallback(this.sakeSearchForRecordsCB), 
     IntPtr.Zero 
    ); 


    sake = (SAKEInternal)Marshal.PtrToStructure(pSake, typeof(SAKEInternal)); 
    if (searchRequest == null) { 
    debug.AddLine(this.getMethodName() + ": mStartRequestResult: " + sake.mStartRequestResult); 
    } else { 
    ret = true; 
    this.searchRequest = (SAKERequestInternal)Marshal.PtrToStructure(
     new IntPtr(pRequestInternal), 
     typeof(SAKERequestInternal) 
    ); 
    searchInput = (SAKESearchForRecordsInput)Marshal.PtrToStructure(
     pInput, 
     typeof(SAKESearchForRecordsInput) 
    ); 

    if (true) { 
     i = 0; 
     foreach (string str in mFieldNames) { 
     Marshal.FreeHGlobal(mFieldNamesPtr[i++]); 
     } 
    } 

    PrintStruct ps = new PrintStruct(sake); 
    debug.AddLine(this.getMethodName() + ": sake: " + ps); 
    ps = new PrintStruct(searchRequest); 
    debug.AddLine(this.getMethodName() + ": searchRequest: " + ps.print_r()); 
    ps = new PrintStruct(searchInput); 
    debug.AddLine(this.getMethodName() + ": searchInput: " + ps.print_r()); 
    } 
    Marshal.FreeHGlobal(pSake); 
    Marshal.FreeHGlobal(pInput); 
    } catch (Exception ex) { 
    debug.Text += ex.ToString(); 
    } 
    return ret; 
    } 
+0

अपडेट: यह खातिरफॉर रिकॉर्ड्स() में टूट जाता है; – Slawa

उत्तर

7

बुरा स्ट्रिंग संकेत दिए गए, विशेष रूप से डबल संकेत मार्शल के भीतर एक struct बस एक IntPtr उपयोग करने के लिए सबसे अच्छा तरीका।

public IntPtr mFieldNames; 

यह मार्शल सही ढंग से एक उपयोगी प्रकार के बावजूद होगा। हालांकि यदि आप IntPtr की संरचना को समझते हैं तो परिणामी तारों को प्राप्त करना बहुत आसान है।

public static List<string> GetAllStrings(IntPtr ptr, int size) { 
    var list = new List<string>(); 
    for (int i = 0; i < size; i++) { 
    var strPtr = (IntPtr)Marshal.PtrToStructure(ptr, typeof(IntPtr)); 
    list.Add(Marshal.PtrToStringUni(strPtr)); 
    ptr = new IntPtr(ptr.ToInt64()+IntPtr.Size); 
    } 
    return list; 
} 

केवल वास्तविक नकारात्मक पक्ष यह है कि आप मैन्युअल स्मृति मुक्त करना होगा

+0

अगर मैं अपने कार्य का उपयोग करने की कोशिश करेगा (मैं अगर तुम मेरे कोड (सरणी का उपयोग करके) को देखने के लिए एक समान एक है), मैं कैसे "सूची " से IntPtr मिल सकता है? IntPtr pList = &list; // ?? – Slawa

1

एक बेहतर तरीका sbyte साथ असुरक्षित कोड जो सी चार रूप में ही है उपयोग करने के लिए बस है (-128 127 के लिए) 1 बाइट आप अपने आप को कुछ बाहरी कार्यों जैसे alloc_txt, free_txt, आदि लिख सकते हैं .. ढेर से आवंटित और मुक्त करने के लिए। अधिकांशतः जब मैं इंटरऑप के साथ लिखता हूं तो मैं असुरक्षित कोड का उपयोग करता हूं क्योंकि इंटप्राट आपको पता लेता है लेकिन आपको अभी भी संरचनाओं में सदस्यों को प्राप्त करने के लिए बाहरी कार्यों का उपयोग करना पड़ता है या यदि किसी मूल के पास मार्शल विधियों को मूल्य निकालने के तरीके हैं।

केवल बार जब आप एक ग # संरचना के रूप में असुरक्षित घोषित करने के लिए है, तो आप वास्तविक संकेत दिए गए है जो आप MarshalAs बजाय नहीं लेकिन उपयोग कर रहे हैं का उपयोग कर रहे है। मैं अभी भी मार्शलएएस (UnmanagedType।?) के माध्यम से असुरक्षित पॉइंटर्स का उपयोग करना पसंद करूंगा जो आपको सीधे सदस्यों से निपटने की अनुमति देता है।

[Struct(Layout.Sequential)] 
public unsafe struct SAKESearchForRecordsInput 
{ 
sbyte*mTableId; 
sbyte**mFieldNames; 
int mNumFields; 
sbyte*mFilter; 
sbyte*mSort; 
int mOffset; 
int mMaxRecords; 
char*mTargetRecordFilter; 
int mSurroundingRecordsCount; 
int*mOwnerIds; 
int mNumOwnerIds; 
bool mCacheFlag;//?don't know what the typedef for the bytes 
}; 
संबंधित मुद्दे