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

时间:2013-12-15 21:32:09

标签: 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#中。

1 个答案:

答案 0 :(得分:3)

您必须从out参数中删除StringBuilder关键字。普通的StringBuilder参数被编组为指向字符数组的指针。如果您希望本机代码接收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. null传递给StringBuilder参数以找出缓冲区大小。
  2. 使用接收容量的构造函数重载来分配StringBuilder个实例。
  3. 再次通过StringBuilder实例调用该函数。
  4. 也许是这样:

    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
    

    并且您需要确保获得null终止符的长度约定。我无法判断你的函数是否返回包含null-terminator的长度。


    正如@Ben指出的那样,您的注释与文字说明不符。

    /* [ in ] */ WCHAR * const pwszFilterPath
    

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

    /* [ out ] */ WCHAR * const pwszFilterPath