我有以下代码:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void PanicFuncDelegate(string str, IntPtr args);
private void PanicFunc(string str, IntPtr args)
{
LogFunc("PANIC", str, args);
}
public void LogFunc(string severity, string str, IntPtr args)
{
vprintf($"[{severity}] "+ str,args);
}
[DllImport("libc.so.6")]
private static extern int vprintf(string format, IntPtr args);
这会将正确格式化的消息打印到控制台。我想从args中检索值,以便在我自己的记录器中使用它们。
如果我尝试从args中的数组中获取每个指针的值(如此处所示:Marshal va_list in C# delegate),我会遇到分段错误。
有什么建议吗?
答案 0 :(得分:0)
只需考虑C程序如何从va_list中获取变量,就有解决方案:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace VaTest
{
class Program
{
static void Main(string[] args)
{
MarshalVaArgs(vaList => vprintf("%c%d%s", vaList), false, 'a', 123, "bc");
}
[DllImport("msvcrt")] //windows
//[DllImport("c")] //linux
private static extern int vprintf(string format, IntPtr vaList);
private static int IntSizeOf(Type t)
{
return (Marshal.SizeOf(t) + IntPtr.Size - 1) & ~(IntPtr.Size - 1);
}
public static void MarshalVaArgs(Action<IntPtr> action, bool? isUnicode, params object[] args)
{
var sizes = new int[args.Length];
for (var i = 0; i < args.Length; i++)
{
sizes[i] = args[i] is string ? IntPtr.Size : IntSizeOf(args[i].GetType());
}
var allocs = new List<IntPtr>();
var offset = 0;
var result = Marshal.AllocHGlobal(sizes.Sum());
allocs.Add(result);
for (var i = 0; i < args.Length; i++)
{
if (args[i] is string)
{
var s = (string)args[i];
var data = default(IntPtr);
if (isUnicode.HasValue)
{
if (isUnicode.Value)
{
data = Marshal.StringToHGlobalUni(s);
}
else
{
data = Marshal.StringToHGlobalAnsi(s);
}
}
else
{
data = Marshal.StringToHGlobalAuto(s);
}
allocs.Add(data);
Marshal.WriteIntPtr(result, offset, data);
offset += sizes[i];
}
else
{
Marshal.StructureToPtr(args[i], result + offset, false);
offset += sizes[i];
}
}
action(result);
foreach (var ptr in allocs)
{
Marshal.FreeHGlobal(ptr);
}
}
}
}
代码是使用.NET Core 3.0 preview 5
编写和测试的,并且与.NET Framework 4.0
和C# 3.0
兼容。
输出:
a123bc