Note that there are some explanatory texts on larger screens.

plurals
  1. POMarshalling array of strings to char ** in C#
    text
    copied!<p>I'm calling a C DLL function and need to supply the following C struct:</p> <pre><code>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; </code></pre> <p>The problem is with char **mFieldNames; I've tried marshalling automatically like this:</p> <blockquote> <p>[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPTStr, SizeConst = 9)] public String[] mFieldNames;</p> </blockquote> <p>This way I get an error in Marshal.SizeOf() - can't compute the correct size. Then I decided to deal with pointers manually. It's in fact just a pointer to the array of C strings. Here's my code which is leading to </p> <blockquote> <p>System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.</p> </blockquote> <p>So I've screwed up pointers somewhere. The code seems OK to me, where is the bug?</p> <p>C#:</p> <pre><code> [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 &gt; 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; } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload