理解VBByRefStr在VB.NET P/Invoke声明中的含义

3
当我尝试从C#中使用VB.NET程序集中的P/Invoke声明时,我注意到string参数变成了ref string参数。 仔细检查后发现,例如:
Public Declare Unicode Function RegDeleteValue Lib "advapi32.dll" Alias "RegDeleteValueW" ( _
ByVal hKey As IntPtr, ByVal lpValueName As String) As UInteger

被编译为

[DllImport(...)]public static extern uint RegDeleteValue(
    IntPtr hKey, [MarshalAs(UnmanagedType.VBByRefStr)] ref string lpValueName);

我在MSDN上读到:

VBByRefStr: 该值使 Visual Basic .NET 能够在非托管代码中更改字符串,并在托管代码中反映出结果。此值仅支持平台调用。这是Visual Basic中ByVal字符串的默认值。

我还是不明白。为什么在C#中只有string lpValueName(参见pinvoke.net - 编辑: 如Damien_The_Unbeliever所指出,RegDeleteKey的签名与RegDeleteValue相同),但在VB.NET中却有奇怪的VBByRefStr?我应该在VB.NET中使用<MarshalAs(UnmanagedType.LPWStr)>来避免C#中的ref吗?或者那会有任何不良影响吗?


并不会有太大的影响,但是您的PInvoke链接指向了一个不同的函数。RegDeleteKey != RegDeleteValue。我找不到RegDeleteValue在advapi32中的PInvoke页面。 - Damien_The_Unbeliever
我的错,看起来我在使用PInvoke时使用了RegDeleteKey而没有找到RegDeleteValue。对于造成的混淆我感到抱歉。不过,使用RegDeleteKey也可以得出相同的主要观察结果 :-) - Paul B.
1个回答

4
这是为了与VB6 Declare语句向后兼容。
当使用ByVal x As String时,您指示希望将VB UTF-16“String”类型转换为ASCII表示形式,将指向该参数的ASCII缓冲区的指针传递给该参数,并在调用成功后将该缓冲区的内容转换回原始的UTF-16字符串。
随后在VB.NET中增强了此功能以支持Unicode API调用。但是,我想VBByRefStr常量表明,在.NET中进行的编组必须严格遵循VB6中的方法。
如果您想要UnmanagedType.LPWStr的标准编组,则请使用 attributes。

明白了,谢谢解释!我想我应该摆脱 VB6 风格的 Declare 语句,改用 DllImport - Paul B.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接