Search code examples
c#pinvokevariadic-functions

C# P/Invoke: Varargs delegate callback


I was just trying to do some managed/unmanaged interop. To get extended error information I decided to register a log callback offered by the dll:


[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public unsafe delegate void LogCallback(void* arg1,int level,byte* fmt);

This definition works, but i get strings like "Format %s probed with size=%d and score=%d". I tryed to add the __arglist keyword, but it is not allowed for delegates.

Well, it is not so dramatic for me, but I am just curious wether one could get the varargs parameters in C#. I know that I could use c++ for interop. So: Is there a way to do this purely in C#, with reasonable efford?

EDIT: For those who still did not get it: I am NOT IMPORTING a varargs function BUT EXPORTING it as a callback, which is then called my native code. I can specify only one at a time -> only one overload possible and __arglist does NOT work.


Solution

  • No there is no possible way to do it. The reason it is impossible is because of the way variable argument lists work in C.

    In C variable arguments are just pushed as extra parameters on to the stack (the unmanaged stack in our case). C does not anywhere record the number of parameters on the stack, the called function takes its last formal parameter (the last argument before the varargs) gets its location and starts popping arguments off the stack.

    The way that it knows how many variables to pop off the stack is completely convention based - some other parameter indicates how many variable arguments are sitting on the stack. For printf it does that by parsing the format string and popping off the stack every time it sees a format code. It seems like your callback is similar.

    For the CLR to handle that, it would have to be able to know the correct convention to determine how many arguments it needed to pickup. You can't write your own handler, because it would require access to the unmanaged stack which you don't have access to. So there is no way you can do this from C#.

    For more information on this you need to read up on C calling conventions.