C#: Pointer to the struct inside the struct - c#

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.

Related

Calling an unmanaged function which return object by value

Assume the following:
Let us have a C++ class:
class ExampleClass
{
private:
int var1;
public:
void DoSomething();
}
Assume also following C++ function which we want to call from .NET Core app with PInvoke or using EmitCalli:
extern "C" ExampleClass CreateObject()
So C++ function returns instance of ExampleClass by value. Is there any way to get this instance on managed part as byte array (assuming that size of ExampleClass is known).
As I remember, in most native x86(x64) calling conventions C++ functions which return structures actully have pointer to the structure to fill as one of the parameters. Will this hint work with NET Core: allocate byte array on managed part and pass pointer as first parameter to unmanaged call?
Thanks!
in C++
ExampleClass CreateClass();
will return a block of bytes of sizeof(ExampleClass) and in absence of virtual members and inheritance it will be plain object and equivalent to same struct definition (see more about this here: Structure of a C++ Object in Memory Vs a Struct )
P/Invoke marshaller should be able to deal with this without a problem.
It it not an IntPtr, it's an actual memory block for C and C++.
IntPtr equivalent would be
ExampleClass * CreateClass();
I am not sure why it returns the instance instead of a pointer but they probably had their reasons.
so if you define it
public struct ExampleClass
{
public int Var1;
}
you should be fine (except if class structure is more complex you would need to check what was layout in C++ compilation, specifically padding. For example class with 2 bools may yield size of 16 in some padding).
see more here:
https://learn.microsoft.com/en-us/dotnet/framework/interop/marshaling-classes-structures-and-unions
https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.structlayoutattribute

What is right way to work with fixed size buffers (arrays) in C#?

I have following unmanaged (c++) struct:
struct parsed_data_struct
{
int some_number;
float some_array[4];
};
And I have to call the function (in c++ dll) which fill array of the structs with values:
void parse_data (parsed_data_struct* parsed_data);
I've found way to make structs with array blittable by using fixed size buffers
So my managed struct is:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct ParsedDataStruct
{
public int some_number;
public fixed float some_array[4];
}
and calling code is
public void Parse(ParsedDataStruct[] parsedData)
{
unsafe
{
fixed (ParsedDataStruct* parsedDataPtr = parsedData)
{
parse_data(parsedDataPtr);
}
}
}
Official documentation and other resources require fixing structs array to work with them. But I've saw there example of accessing to this kind array without fixing it.
So I have some questions:
Is my example right? Is there enough fixing of array of structs?
Is there need to fix structs array to access to it elements?
As far as I remember, you don't need to use unsafe and pointers in such situation in C#. But there is a problem in your code. But in your C++ code. Your struct (shouldn't it be class?) in C# is packed. Your struct in C++ is not. You should pack it too:
#pragma pack(push, 1)
//struct definition here
#pragma pack(pop)

Should Marshal.FreeHGlobal be Called or LocalFree?

Seen a piece of code which I'm not sure whether I need to release memory. If I have this block below:
IntPtr buf = new IntPtr(logRecord.ToInt32() + logTotalCount *
Marshal.SizeOf(typeof(SomeUnmanagedStruct)));
Do I need to call Marshal.FreeHGlobal(buf)?
From my limited understanding (and from this SO), I don't think we should call FreeHGlobal as we are not calling Marshal.AllocHGlobal. However, I have also read from this SO that LocalFree may need to be called?
Any advise what is the correct way to free this memory (if I need to do anything at all)?
UPDATE: Just in case anyone is interested in a IDISPOSABLE wrapper class, there is a great article here.
If you're unsure what one of the base class library actually does, you can always look at the source code:
public struct IntPtr : ISerializable
{
[SecurityCritical]
unsafe private void* m_value; // The compiler treats void* closest to uint
// hence explicit casts are required to preserve int
// behavior
public unsafe IntPtr(int value)
{
#if WIN32
m_value = (void *)value;
#else
m_value = (void *)(long)value;
#endif
}
}
As you can see, this isn't actually allocating any unmanaged memory, but rather simply assigning the int to a private void*.

Why can't I do Marshal.SizeOf() for this C# struct?

I try to call the code int size = Marshal.SizeOf(typeof(MyStruct)) but it throws the following exception:
Type 'MyStruct' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed.
My struct is as follows:
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct
{
[MarshalAs(UnmanagedType.U4)]
public UInt32 version;
[MarshalAs(UnmanagedType.FunctionPtr)]
public IntPtr Start;
[MarshalAs(UnmanagedType.FunctionPtr)]
public IntPtr Stop;
// And a bunch more IntPtr, all declared the same way.
}
The struct is supposed to be passed to C-land, where the C code will use its contents as function pointers. I can't see how computing a size would fail, can anyone help?
UnmanagedType.FunctionPtr requires the field to be a delegate type. It will be a function pointer on the C-side after the structure is marshaled. Using [MarshalAs] is superfluous, a delegate already gets marshaled like that. So, roughly:
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct
{
[MarshalAs(UnmanagedType.U4)]
public UInt32 version;
public Action Start;
public Func<bool> Stop;
// etc..
}
Change the delegate types to match the function signature of the corresponding C function pointer. You often have to declare your own delegate type so you can give it the [UnmanagedFunctionPointer] attribute to match the calling convention of the C function. Usually CallingConvention.Cdecl, not the default of Stdcall.
You have to be very careful when you initialize a structure like this. The delegate objects you create and assign to the fields must be referenced elsewhere to prevent them from getting garbage collected. Either by storing them in a class object that's guaranteed to live as long as the C code can make calls, by storing them in a static variable or by explicitly adding a reference with GCHandle.Alloc()
Lots of ways to shoot your foot, good luck with it :)

Marshalling non-Blittable Structs from C# to C++

I'm in the process of rewriting an overengineered and unmaintainable chunk of my company's library code that interfaces between C# and C++. I've started looking into P/Invoke, but it seems like there's not much in the way of accessible help.
We're passing a struct that contains various parameters and settings down to unmanaged codes, so we're defining identical structs. We don't need to change any of those parameters on the C++ side, but we do need to access them after the P/Invoked function has returned.
My questions are:
What is the best way to pass strings? Some are short (device id's which can be set by us), and some are file paths (which may contain Asian characters)
Should I pass an IntPtr to the C# struct or should I just let the Marshaller take care of it by putting the struct type in the function signature?
Should I be worried about any non-pointer datatypes like bools or enums (in other, related structs)? We have the treat warnings as errors flag set in C++ so we can't use the Microsoft extension for enums to force a datatype.
Is P/Invoke actually the way to go? There was some Microsoft documentation about Implicit P/Invoke that said it was more type-safe and performant.
For reference, here is one of the pairs of structs I've written so far:
C++
/**
Struct used for marshalling Scan parameters from managed to unmanaged code.
*/
struct ScanParameters
{
LPSTR deviceID;
LPSTR spdClock;
LPSTR spdStartTrigger;
double spinRpm;
double startRadius;
double endRadius;
double trackSpacing;
UINT64 numTracks;
UINT32 nominalSampleCount;
double gainLimit;
double sampleRate;
double scanHeight;
LPWSTR qmoPath; //includes filename
LPWSTR qzpPath; //includes filename
};
C#
/// <summary>
/// Struct used for marshalling scan parameters between managed and unmanaged code.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct ScanParameters
{
[MarshalAs(UnmanagedType.LPStr)]
public string deviceID;
[MarshalAs(UnmanagedType.LPStr)]
public string spdClock;
[MarshalAs(UnmanagedType.LPStr)]
public string spdStartTrigger;
public Double spinRpm;
public Double startRadius;
public Double endRadius;
public Double trackSpacing;
public UInt64 numTracks;
public UInt32 nominalSampleCount;
public Double gainLimit;
public Double sampleRate;
public Double scanHeight;
[MarshalAs(UnmanagedType.LPWStr)]
public string qmoPath;
[MarshalAs(UnmanagedType.LPWStr)]
public string qzpPath;
}
A blittable type is a type that has a common representation between managed and unmanaged code and can therefore be passed between them with little or no problem, e.g. byte, int32, etc.
A non-blittable type does not have the common representation, e.g. System.Array, System.String, System.Boolean, etc.
By specifying the MarshalAs attribute for a non-blittable type you can tell the marshaller what it should be converted to.
See this article on Blittable and Non-Blittable Types for more information
1 - What is the best way to pass strings? Some are short (device id's which can be set by us), and some are file paths (which may contain Asian characters)
StringBuilder is generally recommended as the easiest to use but I often use plain byte arrays.
2 - Should I pass an IntPtr to the C# struct or should I just let the Marshaller take care of it by putting the struct type in the function signature?
If the method is expecting a pointer then pass an IntPtr although you can get probably away with a ref in many cases depending on what it's going to be used for. If it's something that needs to stick around in the same place for a long time then I would manually allocate the memory with Marshal and pass the resulting IntPtr.
3 - Should I be worried about any non-pointer datatypes like bools or enums (in other, related structs)? We have the treat warnings as errors flag set in C++ so we can't use the Microsoft extension for enums to force a datatype.
Once you've got everything set up with the correct marshalling attributes I don't see why you'd need to worry. If in doubt put in the attribute, if the struct only ever gets used by managed code then the attribute won't be used.
4 - Is P/Invoke actually the way to go? There was some Microsoft documentation about Implicit P/Invoke that said it was more type-safe and performant.
Can't comment on this, you're into Visual C++ territory there.

Categories

Resources