c# - 如何将 C 函数签名转换为 C# 并在 native DLL 中调用该函数?

标签 c# c++ pinvoke marshalling

int __stdcall getProps( /* [ in ] */ void * context,
                        /* [ in ] */ const UINT32 index,
                        /* [ in ] */ WCHAR * const pwszFilterPath,
                        /* [ in, out ]*/ UINT32 * const pFilterPathSizeInCch,
                        /* [ in ]*/ WCHAR * const pwszFilterName,
                        /* [ in, out ] */ UINT32 * const pFilterNameSizeInCch );

对于上面签名的 C 函数来说,这是正确的 C# 签名吗:

[DllImport("myLib.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
        public static extern int getProps( IntPtr context,
                                           uint index,
                                           [MarshalAs(UnmanagedType.LPWStr)]
                                           out StringBuilder pwszFilterPath,
                                           ref uint pFilterPathSizeInCch,
                                           [MarshalAs(UnmanagedType.LPWStr)]
                                           out StringBuilder pwszFilterName,
                                           ref uint pFilterNameSizeInCch );

这里有问题,我不知道是什么(我不懂 C#)。有时,当我让它工作时,我会在 StringBuilder 变量中收到 ANSI 字符串,并且它们应该包含 UNICODE 字符。

这个想法是调用这个函数两次。首先将 pwszFilterPath 和 pwszFilterName 设置为 NULL,以便检索所需的大小,然后为这两个缓冲区分配内存,然后在第二次调用时检索值。我知道如何在 C/C++ 中执行此操作,但不知道如何在 C# 中执行此操作。

最佳答案

您必须删除 out关键字来自 StringBuilder参数。平原StringBuilder参数被编码为指向字符数组的指针。如果您希望 native 代码接收 NULL ,通过 C# null .

[DllImport("myLib.dll", CharSet = CharSet.Unicode)]
public static extern int getProps(
    IntPtr context,
    uint index,
    StringBuilder pwszFilterPath,
    ref uint pFilterPathSizeInCch,
    StringBuilder pwszFilterName,
    ref uint pFilterNameSizeInCch
);

调用模式如下:

  1. 密码 nullStringBuilder参数来找出缓冲区大小。
  2. 分配StringBuilder使用接收容量的构造函数重载的实例。
  3. 再次调用该函数并传递 StringBuilder实例。

也许是这样的:

uint filterPathLength = 0;
uint filterNameLength
int retval = getProps(
    context,
    index,
    null,
    ref filterPathLength,
    null,
    ref filterNameLength
);
// check retval

StringBuilder filterPath = new StringBuilder(filterPathLength);
StringBuilder filterName = new StringBuilder(filterNameLength);
int retval = getProps(
    context,
    index,
    filterPath,
    ref filterPathLength,
    filterName,
    ref filterNameLength
);
// check retval

并且您需要确保空终止符的长度约定正确。我无法判断您的函数是否返回包含空终止符的长度。


正如 @Ben 指出的,您的注释与文本描述不匹配。

/* [ in ] */ WCHAR * const pwszFilterPath

[ in ] 应该暗示数据正在流入函数。如果是这样,类型应该是 const WCHAR* 。但事实并非如此。这是一个输出参数。所以代码应该是:

/* [ out ] */ WCHAR * const pwszFilterPath

关于c# - 如何将 C 函数签名转换为 C# 并在 native DLL 中调用该函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20600061/

相关文章:

c# - 如何像 Unity 编辑器一样以编程方式将纹理加载到图像中?

c# - 从 WPF 中的 ListBox 获取被点击的元素

c++ - 递增迭代器 C++

c++ - 如何使用键递增但值相同的方式初始化 std::map<int, int> ?

.net - 是否可以在 .net 中捕获/重定向我未启动的进程的标准输出?

c# - GetClientRect 返回缩放尺寸?

c# - 涉及指针时如何P/Invoke

c# - 如何并行运行我的测试并遵守顺序(优先级)

c# - 创建 View - 使用产品订购

c++通过函数内部的索引更改数组