0
votes

In C code, the function is defined like:

INT WINAPI myFunction(LPCTSTR str1, LPCTSTR str2, INT iNumber,
    LPSTRUCT *lpStruct);

*lpStruct is an array of pointers of a struct type:

typedef struct myStruct
{
CHAR                    m_s1[64];       
UINT                    m_nS;       
CHAR                    m_s2[8][64];    
UINT                    m_nP;
CHAR                    m_s3[512];

} SomeStruct, *LPSTRUCT;

I need to call this external myFunction in C#, I defined SomeStruct as:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct SomeStruct
{

   [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 64)]
   public string m_s1;             
   public uint m_nS;             
   [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 512)]
   public string m_s2;             
   public uint m_nP;
   [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 512)]
   public string m_s3;
 }

myFunction as:

[DllImport("some.dll")]
public static extern int myFunction(
             string str1,
             string str2,
             int iNumber,
             IntPtr[] lpStruct);

I initialize IntPtr[] in C#:

IntPtr[] lpptr = new IntPtr[iNumber]; 

I know the struct array of pointer has iNumber elements.

There is no error to call this function (lpStruct[i] has number). But when I tried to Marshal the pointer to the struct using:

SomeStruct st = (SomeStruct )Marshal.PtrToStructure(lpStruct[i], 
    typeof(SomeStruct ));

I got error message: try to write read-only memory. I don't know what's wrong here. Is the external function definition in C# wrong or the definition of struct wrong, or both.

2
What do all the macros expand to? Don't make us guess? What is TCHAR? Ansi or Unicode? Does the struct really mix CHAR and TCHAR? Show how you call myFunction. Show how you allocate the IntPtr[] before calling. Are you 100% sure that the function returns an array? Or does it just fill out one struct? If it is an array, how long must the array be? Your edits suggest you are posting fake code. Use copy/paste to post the real code. Don't post fake code. The question is missing a lot of critical detail. Do you have sample C code that calls this API? That would help a LOT. - David Heffernan
try typeof(SomeStruct) instead of typeof(lpStruct) - D Stanley
Thanks for you comments. I just revised some typo. - user1424258
We still need to see how you call the function, where the IntPtr[] is allocated, and ideally some sample C code that calls it. Then I'm sure we can get to the bottom of it. What's the deal with m_s2 by the way? - David Heffernan
I also tried to define the last parameter in myFunction as [MarshalAs(UnmanagedType.LPArray)]SomeStruct[] lpStruct, but after run myFunction, the array of SomeStruct I passed didn't change at all. - user1424258

2 Answers

0
votes

The question lacks important details, but I would expect that you need to allocate memory for each IntPtr in the array.

IntPtr[] lpptr = new IntPtr[iNumber];
for (int i=0; i<iNumber; i++)
    lpptr[i] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SomeStruct)));

And obviously you should free the memory once you are done with it.

0
votes

Try defining the Struct as a class in C#

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal class SomeStruct
{

   [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 64)]
   public string m_s1;             
   public UInt32 m_nS;             
   [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 512)]
   public string m_s2;             
   public UInt32 m_nP;
   [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 512)]
   public string m_s3;
}

also try UInt32 inplace of uint