Interoperability issues (PInvoke)
Hi!
I'm calling a native CPP library and retrieving a struct by reference which returns a struct containing some pointers.
69 Replies
I first call a CPP method to fill the structure, this is what CPP returns:
This is the struct in C# (returned value)
When using the same struct as a reference to call another CPP method, the values are wrong in the CPP side:
This is my CPP struct:
And this is my C# code with the method called in the second CPP screenshot and the same interface in C#:
So, both CPP screenshots are meant to have the same
FBXContext
data, but somehow, it is broken when using the context as a parameter
No reason to get 90
in code
where the original value was 1
Only if C# is not keeping the original layout order
sizeof(void*)
and IntPtr.Size
are both the same: 8
sizeof(FBXContext)
and Marshal.SizeOf<FBXContext>()
are both 72
how are you passing the struct to the cpp method
and how are you getting it
show the signatures of the methods
c:
First method generates the struct, second one receives the struct
c#:
c# call:
ConvertScene
seems to be messing up the context
contents when sending it back to cpp
i tested interoping with passing a simple struct with a pointer and an int back and forth, and everything worked fine
no idea why this isnt working for you
its probably a good idea to write a wrapper in cpp to make interoping with c# easier
Tks. Trying to find the issue source
The proble is in marshalling struct conversion, when passing the struct as a pointer, it works as expected
But I cannot rely on that bc I need to readback some info from the structs
(In C#)
if youre on .net 7 you can use
LibraryImport
and see what marshaling its doingI'm on Unity :c (Mono)
oh
oof
These issues makes 0 sense
but your struct doesnt require any marshalling
its just pointers and an int
Indeed
hmm
This struct is allocated in the stack when it comes from CPP
Maybe that is the issue?
Afaik, C# should just copy the struct contents to managed memory, so it doesn't make much sense either
I mean, it is not a blittable type bc of the pointers, I guess
no it doesnt copy anything to managed mem
hmm!
its still on the stack in c#
Managed or unmanaged stack?
theres no managed stack
Got it, it shares the same stack as C then
yeah and with stdcall cpp cleans the stack
So that might be the issue?
Lemme test it with
__cdecl
probably not
but what do you have to lose
Indeed
Maybe mono works differently
YEEEESSS
The problem is the calling convention
cdecl
works as expected
Tks for the tip @Cyberrexhuh thats weird
np
i tested with both cdecl and stdcall and both worked for me
as expected
But you're not on Mono, right?
no
still
It might be a Mono implementation bug
Unity uses an outdated Mono implementation afaik
yeah because the new versions dont support something that they want or whatever
Now I just have to retrieve a list of nested structs which will give me way more headache...lol
marshalling arrays shouldnt be a problem
in theory
lol
consider writing a wrapper in cpp
Yep, I'm planning to use the "count, array" format
Bc they are varying in size
A wrapper is a good idea, but I'm already late with this project
ah
And I plan to do only a few calls to CPP and return the structs I need
yeah dynamically allocate the array and return a pointer
you can use pointers in c# btw
I see, but I can't force the Unity user to allow unsafe code
So.. :/
I also hate to work with pointers in C#
Prone to a lot of bugs
if your lib uses unsafe it doesnt mean that projects that use must be unsafe
what youre doing is already prone to bugs
and youre interoping with cpp
If I do what you're saying, I'll have to pre-compile two different C# lib versions
Bc for some platforms, Mono won't use the DLL name when calling the DLL
avoiding pointers isnt a good idea
And uses
__Internal
insteadif you do what
If I use unsafe code
On C#
but unsafe is just a compiler flag afaik
Bc I can't force users enabling unsafe code in the Unity project, so I have to move the unsafe part to a managed DLL
But depending on the platform, the managed DLL has to find the native library using the library name or
__Internal
__Internal
is used in platforms like WebGL, iOS
On Unitywdym move to a managed dll
its already managed
its c#
In Unity, you can use unsafe code, but you have to change a compiler setting. And since I'm developing a plugin, I can't force users enabling this option
So I can compile a managed DLL and add it to the Unity project
you dont have to expose pointers to the public api of your plugin
But then comes the problem that Unity uses different DllPath values depending on the platform
And I can't change these values inside a compiled DLL, got it?
I can't do that on a compiled library
And using a compiled library, I can enable unsafe code only for the library itself
i dont get why you need 2 dlls
but it doesnt matter
do what suits you :)
idk how unity works
Bc I can't change
#define
after the library is already compiled
But I can include a different library version depending on the platform the user is compiling to
It is complicatedyeah i get that
but what does using unsafe in c# change
why would you suddenly need to reference a different version for different platforms
If the library is compiled by Unity itself, users have to enable unsafe code in their projects. I can't do that
If I put a precompiled managed DLL inside Unity, the DLL itself can use unsafe code
but you dont ship the code you ship the dll
dont you?
I can do both
so ship the dll so the users dont have to enable unsafe
But this precompiled DLL would be using the managed code from the lib I was having issues with
and shipping the source doesnt?
But depending on the platform, the name of the called DLL changes, because Mono can't use dynamic C libraries in WebGL and iOS, so it links to static
The
__Internal
library name makes Mono search for the function in static libraries when linking
But there comes the problem, I can't change the __Internal
to LibraryName
stuff to work on all platforms inside an already compiled managed DLLohhh so you letting the user compile
i dont know what took me so long to get that
Yes, that is why I'm putting all the managed source inside my plugin
Np
But I swear I found something once that could actually change a
#define
inside a precompiled managed DLL
Or maybe I was just on a bad trip#define
is preprocessor how would something change it after compilationYes, but I found something once that seem to do that!? Maybe I just made some confusion back in time
yeah that doesnt make sense
When it gets compiled to ILCode, it loses all info that wasn't precompiled, right?
yeah thats the point
I guess I made some confusion then
Anyway. I appreciate a lot bro