Understanding VBByRefStr in VB.NET P/Invoke declar

2019-07-19 00:48发布

问题:

When trying to use a P/Invoke declaration made in a VB.NET assembly from C# I noticed that string arguments become ref string arguments.

A closer inspection reveals that e.g.

Public Declare Unicode Function RegDeleteValue Lib "advapi32.dll" Alias "RegDeleteValueW" ( _
    ByVal hKey As IntPtr, ByVal lpValueName As String) As UInteger

is compiled to

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

On MSDN I read: "VBByRefStr: A value that enables Visual Basic .NET to change a string in unmanaged code, and have the results reflected in managed code. This value is supported only for platform invoke. This is default value in Visual Basic for ByVal strings."

I still don't get it. Why is it only string lpValueName in C# (see pinvoke.net - edit: for RegDeleteKey as Damien_The_Unbeliever pointed out, signature is the same like RegDeleteValue) but strange VBByRefStr in VB.NET? Should I declare with <MarshalAs(UnmanagedType.LPWStr)> in VB.NET to avoid ref in C#? Or does that have any adverse effects?

回答1:

This is for backwards compatibility with VB6 Declare statements.

When using ByVal x As String, you indicated that you wanted to convert the VB UTF-16 "String" type into an ASCII representation, pass a pointer to that ASCII buffer to that parameter, and after the call had succeeded, convert the contents of that buffer back into the original UTF-16 string.

This has subsequently been enhanced in VB.NET to support Unicode API calls. However, I would imagine that the VBByRefStr constant indicates that the marshalling done in .NET must follow the method in VB6 exactly.

If you want the standard marshalling for UnmanagedType.LPWStr, then use attributes.