Я пытаюсь сделать эту работу с C#:Маршал va_list в C# делегат
C заголовок:
typedef void (LogFunc) (const char *format, va_list args);
bool Init(uint32 version, LogFunc *log)
C# реализация:
static class NativeMethods
{
[DllImport("My.dll", SetLastError = true)]
internal static extern bool Init(uint version, LogFunc log);
[UnmanagedFunctionPointer(CallingConvention.Cdecl, SetLastError = true)]
internal delegate void LogFunc(string format, string[] args);
}
class Program
{
public static void Main(string[] args)
{
NativeMethods.Init(5, LogMessage);
Console.ReadLine();
}
private static void LogMessage(string format, string[] args)
{
Console.WriteLine("Format: {0}, args: {1}", format, DisplayArgs(args));
}
}
Что здесь происходит, что вызов до NativeMethods.Init
переадресовывает LogMessage
и передает данные из неуправляемого кода в качестве параметров. Это работает в большинстве случаев, когда аргументы являются строками. Тем не менее, есть звонок, по которому есть формат:
Загруженный плагин% s для версии% d.
и args содержит только строку (имя плагина). Они не содержат значения версии, что имеет смысл, так как я использовал string[]
в объявлении делегата. Вопрос в том, как мне написать делегат, чтобы получить как строку, так и int?
Я попытался с помощью object[] args
и получил это исключение: недопустимый ВАРИАНТ был обнаружен во время перехода от неуправляемого VARIANT к управляемому объекту. Передача недействительных VARIANT в среду CLR может вызвать неожиданные исключения, повреждение или потерю данных.
EDIT: Я мог бы изменить делегат подпись к этому:
internal delegate void LogFunc(string format, IntPtr args);
я мог разобрать формат и выяснить, сколько аргументов ожидать и какого типа. Например. для Загруженный плагин% s для версии% d. Я ожидал бы строку и int. Есть ли способ получить эти 2 из этого IntPtr?
Маршалинг аргументов является лишь частью проблемы, вы можете правильно форматировать строку, вызывая vsprintf(). Вам нужно будет написать небольшой адаптер на языке C++/CLI. –