Hi I am trying to convert the C/C++ Strcut to C#
C/C++ Struct looks like:
typedef struct _NDISUIO_QUERY_OID
{
NDIS_OID Oid;
PTCHAR ptcDeviceName;
UCHAR Data[sizeof(ULONG)];
} NDISUIO_QUERY_OID, *PNDISUIO_QUERY_OID;
My C# Struct is:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct _NDISUIO_QUERY_OID
{
public uint Oid;
[MarshalAs(UnmanagedType.LPWStr)]
public string ptcDeviceName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8*sizeof(uint))]
public string Data;
};
I was bit doubtful about the converted structure, can anyone clarify me about this conversion??
If possible can anyone please tell me any tutorials or some references that are useful for conversion of data types or structures from c/c++ to C#.Net CF.
Thanks :)
In a previous question of yours, #ctacke said that you won't be able to use MarshalAs(UnmanagedType.LPWStr) with the compact framework. He asserted that you would have to declare that field as IntPtr, and marshal it manually.
However, this MSDN document states that MarshalAs(UnmanagedType.LPWStr) works under the compact framework. I suppose I am inclined to believe the MSDN documents.
The final member is also declared incorrectly. The SizeConst must be sizeof(uint).
Related
I'm reading all about structure marshalling between C and C# in 64bit environment without success.
What I need to do is to pass the structure
typedef struct DescStructTa
{
char* pszNa;
unsigned long ulTId;
char* pszT;
unsigned short usRId;
unsigned long ulOff;
unsigned long ulSi;
char szAcc[2];
unsigned char bySSize;
} DescStruct;
from a C# application to a C DLL not made by us calling the method
MT_DLL_DECL long GetAll(UINTPTR ulHandler, DescStruct **ppList, unsigned long *pulNumS);
After long search I wrote the following code:
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct PlcSymbolDescStruct
{
[MarshalAs(UnmanagedType.LPStr)]
string pszNa;
UInt32 ulTId;
[MarshalAs(UnmanagedType.LPStr)]
string pszT;
[MarshalAs(UnmanagedType.U2)]
ushort usRId;
UInt32 ulOff;
UInt32 ulSi;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)]
string szAcc;
[MarshalAs(UnmanagedType.U1)]
byte bySSize;
}
[DllImport("DataSource.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.U8)]public static extern long GetAll(ulong ulHandler, out DescStruct [] ppList,
out uint pulNumS);
Unfortunately this is still giving me a heap corruption.
If I try to pack less than 8 it gives (as expected) an access violation, but I expected this to work and I'm not able to figure out what could be wrong.
Any suggestion?
Thanks in advance!
I’m not sure you need Pack = 8. The default packing appears to be more or less compatible between C# and C++.
The szAcc field probably uses Unicode. To switch, specify CharSet=CharSet.Ansi in your [StructLayout]
Finally, if your C API has that double pointer to the array of them, you have to allocate that memory in a special way, either CoTaskMemAlloc or LocalAlloc, forgot which one.
It’s easier, also more efficient, to implement 2 functions instead. One to obtain the required size of the array. Another one to write them into caller-allocated buffer, a single pointer in C++ as opposed to double pointer, and UnmanagedType.LPArray in C#.
Update
allocation should not be necessary since the documentation states that the call returns a pointer to it's internal data structure
The runtime doesn’t know what was written in that documentation, attempts to free anyway, and crashes. You can use out IntPtr in C# API, and marshal manually.
If you have modern .NET, use unsafe, cast the IntPtr to PlcSymbolDescStruct* raw pointer, and construct ReadOnlySpan<PlcSymbolDescStruct> from that raw pointer.
if you’re stuck with old desktop .NET, call Marshal.PtrToStructure<PlcSymbolDescStruct> in a loop, incrementing the pointer by Marshal.SizeOf<PlcSymbolDescStruct>() bytes between loop iterations. No need to use unsafe code in this case.
I am working with a C DLL and have trouble with marshalling strings using P/Invoke.
The DLL has a struct as follows:
typedef struct
{
char sAddress[256];
BYTE byUseRtsp;
WORD wPort;
}INFO,*LPINFO;
My C# struct looks like this:
[StructLayout(LayoutKind.Sequential)]
public struct INFO
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string sAddress;
public byte byUseRtsp;
public short wPort;
}
The string marshalling for sAddress works with ASCII text, but the DLL uses UTF-8 encoding throughout. So as soon as multi-byte characters are used the marshalling garbles the text. Using CharSet.Unicode doesn't work here as that tells the marshaller to encode/decode strings as UTF-16 on Windows. I need a CharSet.Utf8 which unfortunately doesn't exist.
I do have a workaround, but it's ugly and want to avoid if possible. The workaround is to replace:
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string sAddress;
with:
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] sAddress;
and then just re-write my code to use Encoding.UTF8.GetBytes/String() methods to get the string values. I will also need to handle null-terminators myself with this method.
Is there a better way of doing this?
Is there a better way of doing this?
Using the built-in options for marshalling what you have done is probably as good as it gets. You would want to write some helper methods to manage this for you, but I'm sure you are alive to that.
Beyond this you could use a custom marshaler. I'm not aware that there is a great body of work available on this topic. One of the more complete happens to be this question of mine: How do I write a custom marshaler which allows data to flow from native to managed?
[In case it helps others] .NET Framework 4.7 introduced UnmanagedType.LPUTF8Str which is likely just for this situation.
I have a C# app using a C++ DLL. This has been working fine but I now have to change "Treat wchar_t as built-in type" from "Yes (/Zc:wchar_t)" to "No (/Zc:wchar_t-)" and my C# app has become very unstable. The interop layer between C++ and C# include some strings as function parameters and in structs like this:
C++:
typedef struct
{
// Used to be: WCHAR wstrName[256];
wchar_t wstrName[256];
} sdevicemodel_t;
C#:
namespace Thingy
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DeviceModel
{
// info
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Name;
}
}
Do I need to change this declaration to match the C++ change, or is this fine and my problem lies elsewhere?
Thanks for any help.
Short answer is: No, it does not affect the Interop in any way.
This option says the compiler to treat the wchar_t C++ type as a built-in type, instead of a typedef of unsigned short. This is required by the (not-so) latest versions of the C++ language, but older versions of the MS C++ compilers didn't do it right.
So now you have two options: the C++ standards way: (The Right Way™) and the back-compatible way (The MS Way™).
But that difference (built-in type vs. typedef type) is only significant when you do function overloads, template specializations or the like. C# Interop is concerned only with binary compatibility, and that is unchanged by this option (wchar_t is in both cases an unsigned 16-bit integer).
I am reading a binary file of a specific format, and am used to being able to cast a block of data to a struct then reading the struct to pull fields out of the binary datafile.
I'm trying to do this but failing in C#, they seem more like classes than structures in the C sense. Is it possible to do what I want? For example..
public struct Datum {
byte type;
ushort payload;
}
public struct DiskPage {
ushort pageNumber;
Datum[] data = Datum[170];
}
I want to be able to read 512 bytes of a file and cast it to a DiskPage, then to be able to read the values from the DiskPage structure. Is this possible in c# - or is there another preferred approach? Should I just leave that code in C and link it in?
Thanks!
Reza
The compiler doesn't respect ordering of your fields by default (also it might move the fields and leave gaps in the memory = Packing). By using StructLayout you can enforce a different behavior (Default, Sequential, or Explicit).
Use MarshalAs for specific options on a field. Be careful with endianess.
[StructLayout(LayoutKind.Explicit, Size=16, CharSet=CharSet.Ansi)]
public struct MySystemTime
{
[FieldOffset(0)]public ushort wYear;
[FieldOffset(2)]public ushort wMonth;
[FieldOffset(4)]public ushort wDayOfWeek;
[FieldOffset(6)]public ushort wDay;
[FieldOffset(8)]public ushort wHour;
[FieldOffset(10)]public ushort wMinute;
[FieldOffset(12)]public ushort wSecond;
[FieldOffset(14)]public ushort wMilliseconds;
}
I suggest you read Mastering C# structs that discusses using marshaling (Marshal.Copy in particular) for that purpose.
You can use fixed arrays in C# if you compile with Unsafe option enabled.
You can also use pointers.
internal unsafe struct MyStruct
{
public fixed byte MyFixedArray[128];
public byte* MyPointer;
}
It is preferred to use marshalling, field offset and avoid unsafe code.
Use unsafe code if you really need too in small portion of your code.
Don't expose to external world a fixed array or a pointer (interfaces or public classes\structs) if you can avoid it.
I am trying to use marshalling in C#. In C++ I have a this struct:
struct aiScene
{
unsigned int mFlags;
C_STRUCT aiNode* mRootNode;
unsigned int mNumMeshes;
C_STRUCT aiMesh** mMeshes;
unsigned int mNumMaterials;
C_STRUCT aiMaterial** mMaterials;
unsigned int mNumAnimations;
C_STRUCT aiAnimation** mAnimations;
unsigned int mNumTextures;
C_STRUCT aiTexture** mTextures;
unsigned int mNumLights;
C_STRUCT aiLight** mLights;
unsigned int mNumCameras;
C_STRUCT aiCamera** mCameras;
}
So, C# eqvivalent is:
[StructLayout(LayoutKind.Sequential)]
public struct aiScene
{
public uint mFlags;
public unsafe aiNode* mRootNode;
public uint mNumMeshes;
public unsafe aiMesh** mMeshes;
public uint mNumMaterials;
public unsafe aiMaterial** mMaterials;
public uint mNumAnimations;
public unsafe aiAnimation** mAnimations;
public uint mNumTextures;
public unsafe aiTexture** mTextures;
public uint mNumLights;
public unsafe aiLight** mLights;
public uint mNumCameras;
public unsafe aiCamera** mCameras;
}
But many on this structs are managed ( aiNode, aiMesh, aiLight ) etc. So, I have this error:
Cannot take the address of, get the
size of, or declare a pointer to a
managed type ('Assimp.aiNode')
Any ideas on how to solve this issue?
This could get very complicated depending on what you are trying to do. However, as you are working it could help you do declare each of the pointers in the C# code like this. It uses the very useful IntPtr, which was described on here earlier today. :)
Please note that this will not magically get your code to work. I'd need to see a lot more of what's going on before I could give you input on that.
public struct aiScene
{
public uint Flags;
public IntPtr RootNode;
...
}
The main problem you're having is that you've defined managed objects with the same names as the unmanaged types. The pointer types, like "aiNode", should be defined as structs, not classes. You can define differently named managed wrapper classes which provide managed access to the underlying unsafe struct data. For example:
public struct aiNode {}
public struct aiScene
{
public uint mFlags;
public unsafe aiNode* mRootNode;
// ...
}
At a high level, it looks like you're trying to use AssImp from C#. That can be done today using assimp-net. However, in case someone runs into a marshalling situation like this and wants a generic answer..
I strongly recommend against using IntPtr for anything, because they are basically an untyped void* with no type checking. Unsafe-struct-pointers offer a safer disambiguation of unmanaged pointer types. SafeHandle is another option with better safety and handling of some race-conditions. See my article on the topic.
If you literally want to copy the data from unmanaged to managed land, then for each type (aiNode, aiMesh, etc) you need to define both an unsafe-struct (to match the unmanaged layout), and a managed class. Then, write (or generate) unsafe code to copy the unmanaged tree to managed objects. Be sure to be careful of any unmanaged objects with more than one reference.
Sometimes a better alternative is to write a wrapper which provides access to unmanaged data "in-place". If you are doing it "safely", then the managed wrappers should be thin-objects which manage lifetime for the unmanaged objects and have properties to access their data. Alternatively, you can do it unsafely by merely defining the unsafe structs and using them in an unsafe context.