Ali*_*cia 1 .net vb.net dll dllimport
今天,在处理一些 VB.NET 代码时,我必须访问两个外部 DLL 才能使用某些方法。我找到的帮助主题告诉我使用以下外部方法:
\n\n但是,当我尝试从代码中调用这些方法时,我收到一条错误,指出入口点不存在。所以我做了一些研究,发现我的操作系统(Windows 7 enterprise 32 位)中的 DLL 并不完全包含这些方法,但相反,我得到了:
\n\n因此,我测试了它们的行为:\n* 以“A”结尾的方法按预期工作。\n* 以“W”结尾的方法不能按预期工作,它们会引发错误或返回错误的结果(当它应该是“true”)。\n然而,帮助主题中没有人提到有类似的问题。
\n\n所以我做了一些研究,在MSDN 文档中我发现 DLL 只包含以“A”和“W”结尾的方法,并且在我使用的三种情况下,它们的文档页面是相同的据我所知。事实上,在整个页面中,他们都没有使用以 A/W 结尾但没有它的方法名称。
\n\n所以我的问题是:*为什么我的 DLL 中有方法“A”和“W”而不是没有 A/W 的方法?他们两个有什么区别?为什么方法“A”对我有效,而方法“W”则无效?
\n从 Windows NT 4 / 2000 / XP 开始,WinAPI 函数有 ANSI (A) 和 Unicode (W) 变体。另请参阅Win32 API 中的“A”和“W”函数有什么区别?。
使用 P/Invoke 时,C# 和 VB.NET 之间存在差异。请参阅MS Docs 上的指定字符集,特别是“字符串封送和名称匹配”和“在 Visual Basic 中指定字符集”:
当 DllImportAttribute.ExactSpelling 字段为 true 时(Visual Basic 2005 中默认为 true),平台调用仅搜索您指定的名称。例如,如果您指定 MessageBox,平台调用将搜索 MessageBox,并在找不到确切的拼写时失败。
鉴于 C# 和 VB.NET 的 DllImportAttribute.CharSet 字段的默认值为“ANSI”,Visual Basic 的规则确定运行时不会搜索A或W入口点,请参阅文档:DllImportAttribute.ExactSpelling Field。我猜这是为了向后兼容 Visual Basic。
所以你有三个选择:
显式指定“W”入口点和 CharSet.Unicode:
<DllImport("shlwapi.dll", EntryPoint:="PathIsNetworkPathW", SetLastError:=True, CharSet:=CharSet.Unicode)> _
Public Function PathIsNetworkPath(<MarshalAs(UnmanagedType.LPTStr)>pszPath As String) As <MarshalAs(UnmanagedType.Bool)>Boolean
End Function
Run Code Online (Sandbox Code Playgroud)禁用精确拼写,导致运行时搜索“A”入口点(假定默认字符集(未指定时为 ANSI):
<DllImport("shlwapi.dll", EntryPoint:="PathIsNetworkPath", SetLastError:=True, ExactSpelling:=False)> _
Public Function PathIsNetworkPath(<MarshalAs(UnmanagedType.LPTStr)>pszPath As String) As <MarshalAs(UnmanagedType.Bool)>Boolean
End Function
Run Code Online (Sandbox Code Playgroud)将 CharSet 设置为 Auto,表示特定于平台的字符集(对于大多数操作系统为 Unicode)和 ExactSpelling False:
<DllImport("shlwapi.dll", EntryPoint:="PathIsNetworkPath", SetLastError:=True, CharSet:=CharSet.Auto)> _
Public Function PathIsNetworkPath(<MarshalAs(UnmanagedType.LPTStr)>pszPath As String) As <MarshalAs(UnmanagedType.Bool)>Boolean
End Function
Run Code Online (Sandbox Code Playgroud)我更喜欢选项 3,因为它消除了字符串的无用(甚至危险,因为它可能导致数据丢失)Unicode -> ANSI -> Unicode 转换,并且不需要您显式指定“W”变体的功能。