Click here to Skip to main content
15,890,438 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
Hi, I am trying to marshal this structure to be used by my application in C#, Right now is being consumed succesfully by the c++ dll, however I think the partition of the structure is wrong, for the Name parameter returns always funky values.

this is the c++ structure:
C++
#define MAX_PATH  260
typedef struct {
	BYTE nAlternate;
	char Name[MAX_PATH];
	DWORD NbSectors;
	PMAPPINGSECTOR	pSectors;	
} MAPPING, *PMAPPING;


this is how I converted it I think that as long as it is sequential it doesn't have gaps in the memory between objects (correct me if wrong).
C#
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
       public struct MAPPING
       {
           public byte nAlternate;
           [MarshalAs(UnmanagedType.ByValTStr,SizeConst=260)]
           public string Name;
           public UInt32 NbSectors;
           public MAPPINGSECTOR pSectors;
       }


after running the value for Name is really weird(like chinese characters yes i tried changing the char set with no success) I'd say incomplete

here is the structure for MAPPINGSECTOR

C++
typedef struct {
    DWORD		dwStartAddress;
	DWORD		dwAliasedAddress;
	DWORD		dwSectorIndex;
	DWORD		dwSectorSize;
	BYTE		bSectorType;
	BOOL		UseForOperation;
} MAPPINGSECTOR, *PMAPPINGSECTOR;


this is how is converted it.
C#
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
       public struct MAPPINGSECTOR
       {
           public UInt32 dwStartAddress;
           public UInt32 dwAliasedAddress;
           public UInt32 dwSectorIndex;
           public UInt32 dwSectorSize;
           public byte bSectorType;
           public bool UseForOperation;
       }

I also tried to assign the memory explicitly by using field offset but it would return me error saying that there was overlapping if somebody could show me how to assign the memory explicitly I think that could solve my problem.

Thanks in Advance.
Posted
Updated 7-Jun-12 11:53am
v4

Sorry that I did not test your case, but it looks like the problem is not the layout but the Name itself, more exactly, wrong [MarshalAs] attribute you apply to the field Name. Try:

C#
[MarshalAs(UnmanagedType.LPStr, SizeConst=260)]
public string Name;


Please see:
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.unmanagedtype.aspx[^].

—SA
 
Share this answer
 
Comments
nanomass 7-Jun-12 17:52pm    
Hi, Sorry, but according to the documentation provided by you the marshal as is corect in the c++ structure Name is a fixed size char array, I tried this marshal provided and it did not work LPStr is only 1 byte in length. but thanks for the help, this link is very helpful.
Sergey Alexandrovich Kryukov 7-Jun-12 19:32pm    
LPStr cannot be one byte. It is marshalled as a pointer pointing to some number of character. Could you tell me what exactly happens if you marshal as LPStr?
What documentation do you mean?
Also, ByValTStr assumes that the name of unmanaged side it TChar, not char, because TChar means "depending on compilation, wide char with Unicode, single-byte char otherwise.
--SA
nanomass 8-Jun-12 9:33am    
I just tried using LPStr and I am getting an exception as the following"Attempted to read or write protected memory" I tried to marshal it to a character array and the only index that was used was index = 0. using the marshalas.byValArray.
Espen Harlinn 23-Jun-12 17:02pm    
CharSet.Auto will interpret the Name member as a wchar_t array and not as a char array.
Sergey Alexandrovich Kryukov 29-Jun-12 20:23pm    
True.
--SA
I decided to make the structure unsafe and layout the structure explicit to deal with the problem, I am working with an API which is not the best, I don't know if this is a solution but it solved the problem for me and now I am getting consisten values for the Name parameter of the MAPPING Structure.

C#
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Auto)]
           public unsafe struct UmMAPPING
           {
               [FieldOffset(0)]
               public byte nAlternate;
               [FieldOffset(1)]
               public char Name;
               [FieldOffset(261)]
               public UInt32 NbSectors;
               [FieldOffset(265)]
               public MAPPINGSECTOR* pSectors;
           }


Hope this is helpful for somebody in the future.
 
Share this answer
 
Comments
Amund Gjersøe 8-Jun-12 17:45pm    
I've used to set the Pack-attribute when Marshalling structs, just to be aware of what it is and adjust it to what's expected on the other side of the PInvoke. Just a tip along the way.
Not sure if it is possible to map an array of chars from C++ and into string in C#. If the suggestions above fail, try use char[] instead.

Other than that, in many cases when I needed to expose C++ code to .NET I used COM Automation types. In case of a string, you pass it in as type BSTR, which maps into string in C# naturally, i.e. needs no marshaling.
 
Share this answer
 
v2
This
C#
char Name[MAX_PATH];

Indicates that you will always have byte sized characters, hence you need to use CharSet = CharSet.Ansi

Best regards
Espen Harlinn
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900