I am working with a C++ dynamic link library from xatlas that exports a function with the following signature: __declspec(dllexport) void xatlasSetPrint(xatlasPrintFunc print, bool verbose);. The xatlasPrintFunc is defined as typedef int (*xatlasPrintFunc)(const char *, ...);, indicating it accepts a variable number of arguments, akin to the C printf function. My goal is to use this function from C#, specifically to set a print callback function within Unity (where my C# version is limited to C# 9 and .NET standard 2.1), but I'm facing challenges due to the variadic nature of the function pointer. I prefer not to write an additional C++ adapter library to maintain project conciseness.
Given the variadic function pointer in C++ and my requirements in C#, how can I accurately define and implement a C# callback that is compatible with this C++ DLL function? Is there an effective way to handle the variadic arguments from C++ in C#, or is there a different approach I should consider?
Additionally, I aim to ultimately log messages using UnityEngine.Debug.Log, so solutions that are compatible with Unity's constraints would be ideal. If achieving this directly is impractical, I'm open to wrapping another native library to fix the parameter count but would prefer a more straightforward solution.
The close reason cannot work directly, but it inspired me, this does the work(edit: this just work for a few cases, most time it doesn't work):
using AOT;
using System;
using System.Runtime.InteropServices;
public static class PrintFormat
{
const string msvcrtDll = "msvcrt.dll";
[MonoPInvokeCallback(typeof(PrintFunc))]//For il2cpp, otherwise optional
public unsafe static int Printf(IntPtr PStr_format, byte args)
{
int count = _vscprintf(PStr_format, ref args) + 1;
var buffer = stackalloc byte[count];
IntPtr pbuffer = (nint)buffer;
int retcode = vsprintf(pbuffer, PStr_format, ref args);
/*-----Here's what I want------*/
Console.Write(Marshal.PtrToStringAnsi(pbuffer));
return retcode;
}
[DllImport(msvcrtDll, CallingConvention = CallingConvention.Cdecl)]
public static extern int vsprintf(IntPtr buffer, IntPtr PStr_format, ref byte args);
[DllImport(msvcrtDll, CallingConvention = CallingConvention.Cdecl)]
public static extern int _vscprintf(IntPtr PStr_format, ref byte args);
}
C# P/Invoke API:
[UnmanagedFunctionPointer(Cdecl)]
public delegate int PrintFunc(IntPtr PStr_format, byte args);
[DllImport(DLL,CallingConvention=Cdecl,EntryPoint="xatlasSetPrint")]
public static extern void SetPrint(PrintFunc print, BOOL verbose);
usage:
SetPrint(PrintFormat.Printf, true);
for close: the duplicate question does not work, the first answer has no case of native to managed callback, the second answer doesn't work at all. The CIL...I'd prefer to make another wrapper library instead of this. And my workaround still doesn't work.