【问题标题】:Marshal const char **元帅 const char **
【发布时间】:2017-02-24 16:06:37
【问题描述】:

我正在为 Arma 3 编写一个扩展。通常你可以简单地为此编写一个 C++ 库并实现这个功能

int __stdcall RVExtensionArgs(char *output, int outputSize, const char *function, const char **args, int argCnt);

我正在开发一个 C# 库,我想在其中实现这个功能。函数 RVExtensionArgs 有一个修饰名称,对于 32 位是 _RVExtensionArgs@20,对于 64 位是 RVExtensionArgs

我正在努力处理指向 args 参数的 const char 指针的指针。我目前的实现是

#if WIN64
    [DllExport("RVExtensionArgs", CallingConvention = CallingConvention.Winapi)]
#else
    [DllExport("_RVExtensionArgs@20", CallingConvention = CallingConvention.Winapi)]
#endif
    public static int RvExtensionArgs(StringBuilder output, int outputSize,
        [MarshalAs(UnmanagedType.LPStr)] string function,
        [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4, ArraySubType = UnmanagedType.LPStr)] string[] args,
        int argCount)

使用的 DllExport 来自 UnmanagedExports

有一些关于here的扩展信息

但是这样游戏就崩溃了。我很确定这是因为 args 但我无法验证。我错过了什么吗?

【问题讨论】:

  • 将其作为 byte* 输出、int outputSize、byte* 函数、byte** args、int argCnt 导入到不安全的类中以消除猜测是否会更简单、更高效?编组?唯一的“挑战”是将 .NET 字符串中的 UTF-16 字符转换为字节。
  • @hoodaticus 我对我得到的每一个解决方案都持开放态度。你能告诉我更多关于如何实施你的想法的信息吗?
  • 等等 - 为什么在 C++ 中使用 stdcall 时要指定 WINAPI 调用约定?
  • @hoodaticus 是的,我做到了,而且效果很好!我只需要弄清楚如何将字节**转换为字符串数组
  • @chris579 - 我会这样做并更新你。

标签: c# marshalling


【解决方案1】:

我在 cmets 中回答了这个问题,但想指出将 const char** 从 C# 导出到 C++ 的最简单方法是 byte**

我创建了下面的 StringMarshaller 类来帮助您将 byte** 转换为 string[]。我还没有测试过 - 我可能有时间稍后会更新。

public unsafe static class StringMarshaller
{
    public static string[] Marshal(byte** nativeStrings, int stringCount)
    {
        var strings = new string[stringCount];

        for (var x = 0; x < stringCount; ++x)
        {
            if (nativeStrings[x] == null) continue;
            var length = GetStringLength(nativeStrings[x]);
            strings[x] = length == 0 
                    ? string.Empty 
                    : Encoding.UTF8.GetString(nativeStrings[x], length);
        }

        return strings;
    }

    public static int GetStringLength(byte* nativeString) 
    {
        var length = 0;

        while (*nativeString != '\0')
        {
            ++length;
            ++nativeString;
        }

        return length;
    }
}

【讨论】:

  • 事实证明我必须使用 CallingConvention.Winapi 否则 dll 无法识别和加载。我建议进行编辑,因为您当前的示例不起作用:)
  • @chris579 - 抱歉,审查委员会在我之前就已经接受了您的编辑并拒绝了它。我不确定为什么你的改变是必要的,但重要的是你让它工作。你现在好吗?
  • 需要编辑,因为 Encoding.UTF8.GeString 无法直接处理字节指针。它必须首先编组为字节数组。不过现在好了
  • @chris579 - 啊,您必须使用 .NET 4.0 或更早版本。最新版本确实接受 GetString 重载中的原始字节指针。顺便说一句 - 祝贺你度过了这个难关!这不是一个容易的问题 - 你应该感到自豪。
  • 好吧,我在 4.5 上,编译器对我抛出了一些错误。 Nvm,它现在可以工作了,这是重点。感谢您的赞美,通常我对 C# 没有什么大问题,但是在导出和导入以及 dll 接口方面我有点过度紧张
猜你喜欢
  • 1970-01-01
  • 2019-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-09
相关资源
最近更新 更多