How to handle varargs in a callback function?

I have a callback function that is used for debug messages from a DLL.

Shared Sub LogCallback(UserData As Ptr, Level As Integer, Context As Ptr, Format As CString, Args As Ptr)

The Format and Args parameters are intended to be passed to a printf-like function. However, when I try to use one I get the unformatted string followed by garbage:

Shared Sub LogCallback(UserData As Ptr, Level As Integer, Context As Ptr, Format As CString, Args As Ptr)
    Declare Function sprintf Lib "msvcrt" (Char As Ptr, Frmt As CString, Arg As Ptr) As Integer
    Dim buffer As New MemoryBlock(1024)
    Call sprintf(buffer, Format, Args)
    System.DebugLog(buffer.CString(0))
End Sub

Output example:

severity: 0 configured with %s (qÆw¼z]ÔÚ()

It seems to me that the problem is with the Args parameter, which in the original C is a va_list. I think sprintf is interpreting the Ptr value as an argument rather than a va_list.

How can I either pass these arguments to sprintf or access them so I can format the string myself?

well, we can’t take varargs in Xojo currently.
You can only write one callback for each variant.

e.g.

Sub LogCallback(UserData As Ptr, Level As Integer, Context As Ptr, Format As CString, Arg1 As CString)
Sub LogCallback(UserData As Ptr, Level As Integer, Context As Ptr, Format As CString, Arg1 As CString, Arg2 as CString)

and make sure the right one is called.

I don’t think that’s will work since the callback might be called several times in a row with different parameters, and I have no way of predicting them.

How does one know how many arguments there are in LogCallback’s Args in C? Is there another function returning the count? Is there a “sentinel value”?

http://pubs.opengroup.org/onlinepubs/9699919799/
no sentinels
well there might be way under the implementation details but there are none visible to you & I
where’s aaron ror jow when you really need them ? :stuck_out_tongue:

Variadic functions are unsupported.

[quote=262943:@Christian Schmitz]well, we can’t take varargs in Xojo currently.
You can only write one callback for each variant.

e.g.

Sub LogCallback(UserData As Ptr, Level As Integer, Context As Ptr, Format As CString, Arg1 As CString)
Sub LogCallback(UserData As Ptr, Level As Integer, Context As Ptr, Format As CString, Arg1 As CString, Arg2 as CString)

and make sure the right one is called.[/quote]

This is incorrect and will cause all sorts of fun problems. The calling conventions for variadic arguments differs from the typical fixed arguments, even on platforms like x86 where it seems to work.

A relevant snippet from the SYSV AMD64 ABI:

Thanks for your thoughts, everyone. Who would have thought that a simple logging function would be such a PITA? The irony is that the designers probably thought they were making it more convenient this way.

[quote=263262:@Joe Ranieri]
The calling conventions for variadic arguments differs from the typical fixed arguments, even on platforms like x86 where it seems to work.[/quote]

I have a different project that calls a variadic external method, however it takes a sentinel value to mark the end of the arguments rather than a va_list. What I did was declare the function with a dozen or so fixed arguments. It works just fine on x86, but if I understand you right it won’t work on x64?

Someone could write a plugin function for passing as function pointer.
And pass back result via event or so.