The Namespace is listed in the MSDN link, and the word namespace is not used in a using statement.
using System.Runtime.InteropServices;
If the System namespace is not found, is this a separate DLL, or is it part of your Unity project? If it’s a separate DLL you need to reference mscorlib.dll, though that should always be there as it includes things like string, int, bool, etc…
actually I was confused. I got it to work but I’m missing something here. My main in C++ calls the initialize function. Worst case I can make a setter. Though, is there a way to do this?
int main( )
{
initialize();
so: what to put in for the augment? Or would I need to pass it to main first.
You would need to store a function pointer of type void (foo)(char) Then using the a DLLImport call, you pass Debug.Log in as listed above. Once it’s passed in, you can do whatever you would normally do with function pointers (store it locally or globally, call it whenever) and call it using any char* argument you want.
You can’t assign a char* to a function pointer, you have to call the function pointer with the char*
To be more clear char* and the void (debuger)(char) are in no way interchangeable or castable. They are two very different things, and #2 actually takes #1 as a parameter.
Yup that cleared things up a bit. Seems I can not define my c# extern as unity gives: Pointers and fixed size buffers may only be used in an unsafe context
You pass the Debug.Log delegate to C. If you are in C#, you just call Debug.Log().
Don’t pass a string of any kind from C# to C, that’s a waste of time and resources. Pass the function that takes a string from C# to C, and then use the strings you created in C.
The most crucial question was not asked yet: Are you on pro? Otherwise you can not use plugins on the desktop at all. Also the webplayer can never interactive with native code.
I figured char would hold the address to the pointer that GetFunctionPointerForDelegate returns. I’m passing it right I just dont know how to declare the the function header I’m passing it to.
private static extern void setDebug( ??? debug ); //tried char debug, tried Delegate debug, tried char * debug and, and a few more.
setDebug(Marshal.GetFunctionPointerForDelegate(Debug.Log));
Forgive me for missing something simple but I have never used Marshaling before. Looks to me like GetFunctionPointerForDelegate returns a pointer ( System.IntPtr ) but setDebug( System.IntPtr debug ); cause errors.
Sorry for the confusion.
dreamora: Yes, I am, the plug in works, I just need to pass in a pointer so I can use the debug console.
You’ll need to explain what language each call is in, and what the errors are. If I don’t know the error, I can’t suggest any remedies.
i.e. System.IntPtr is not a C/C++ class.
This is syntatically incorrect I’m sure, but it shows the signatures on C and C# that you should be able to use to inter-operate.
When passing IntPtr objects from C# to C, they can be assigned as any pointer type you want, an are essentially void* objects.
Edit: There are a few other Plugin related things (DECLSPEC in windows iirc), and you may want to check the plugin documentation on how to actually link a call. You can also use the MSDN to get more information on the Marshal class, as a key player in calling between C# and C.
Ok, I’m obviously complicating things here, let me try to show the code I have.
c# code.
public class FaceAPIBehavior : MonoBehaviour
{
...
[DllImport("FaceAPIPlugin")]
// If I do this I get, The best overloaded method match for `System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(System.Delegate)' has some invalid arguments
private static extern void setDebug( System.IntPtr debug );
//if I do this I get, Pointers and fixed size buffers may only be used in an unsafe context
private static extern void setDebug( char * debug );
...
void Start ()
{
Debug.Log("send my pointer to c++ );
setDebug(Marshal.GetFunctionPointerForDelegate(Debug.Log));
...
}
...
}
Ah ok, my bad, sorry, it was a syntax issue on my instruction end.
Playing around with it, it looks like the GetFunctionPtr function cannot be passed a function directly, but requires a delegate to call (which makes sense for it’s name).
Action is just a general delegate that can take a string as input and returns null. If it doesn’t work you may need to make your own non-generic delegate. Also you will need to keep callback around as a reference somewhere while it could be called in C, so that the Garbage Collector doesn’t clean it up.
Yes that does make it compile but there is one mystery on my end left.
If I can do this in c#
[DllImport(“FaceAPIPlugin”)]
private static extern void setDebug( System.IntPtr debug );
and just like you suggested I can do this to call my c++
System.Action callback = Debug.Log;
setDebug(Marshal.GetFunctionPointerForDelegate( callback ));
then what does the c++ define look like? If I leave it as I have it
void setDebug ( char(*debugger)(char) );
then I get EntryPointNotFoundException: setDebug errors.
void setDebug ( System.IntPtr debug ); wont work as I dont have a way to use the system namespace? Or is therw a way to cast callback to a pointer, or one of its members as a pointer?
C/C++ just uses a pointer, and what’s actually passed on the C/C++ function is void*, but you can cast it as whatever you want (albeit unsafely).
The reason you get EntryPointNotFound is because C++ mangles names, i.e. the function name is not setDebug, but something like SomeClass__SetDebug*char or some other mangling. You can use extern “C” {} as a block to tell the compiler to use standard naming, or you can decipher what setDebug’s name is within the DLL. It’s not just a simple setDebug, because it needs to also contain the class name, info on whether it’s static or not, and info on parameters.
As long as your using pro, remember you can debug c++ side of the dll in msvc. Just set the project to debug, have the project build to the plugin folder, set debug target to unity.exe or whatever the editor .exe or even standalone .exe is, slip a breakpoint in any function.
Once unity loads the dll and calls a function you should have no problems debugging.
I know this might not be what your looking for, but it sounds like a workaround
but now I get this.
MarshalDirectiveException: The type `System.Object’ layout needs to be Sequential or Explicit
(wrapper native-to-managed) UnityEngine.Debug:Log (string)
FaceAPIBehavior.Start () (at Assets/Scripts/FaceAPIBehavior.cs:113)