1

我有将 VB6 应用程序转换为 VB.net 的令人愉快的工作(我所说的令人愉快的意思是非常乏味)。此应用程序所做的一件事是与 c dll(其中 30 个)进行通信。在手工编写了许多结构和声明之后,我决定使用自动化工具可以帮助节省时间,因此我购买了 pinvoke 向导工具。

我运行它抛出了头文件并成功生成了VB代码,但我不明白如何使用它,让我举个例子。我调用的方法之一是 StartSession。在 C 中,标题代码是

WORD APIENTRY StartSession 
(LPBYTE lpbReturnCode,
LPBYTE lpbErrorMessage,
LPBYTE lpbApplName,
LPBYTE lpbRegionName,
LPBYTE lpbSessionID, 
LPBYTE lpbDataTrunc,
LPBYTE lpbSessionToken,
LPBYTE lpbStandardWait,
LPBYTE lpbVersion,
LPBYTE lpbEnvironment,
LPBYTE lpbESILogonOnly,
LPBYTE lpbMetadataSource,
LPWORD lpbMetadataCacheCount); 

当我手动重写这个函数时,我把它写成

Declare Function StartSession Lib "chat2.dll" (ByVal ReturnCode As String _
                                               , ByVal ErrorMsg As String _
                                               , ByVal ApplicationName As String _
                                               , ByVal RegionName As String _
                                               , ByVal EmulatorSessionID As String _
                                               , ByVal DataTruncationFlag As String _
                                               , ByVal SessionToken As String _
                                               , ByVal StandardWait As String _
                                               , ByVal ApplicationVersion As String _
                                               , ByVal Environment As String _
                                               , ByVal ESILogonOnly As String _
                                               , ByVal ScreenDescDataSource As String 
                                               , ByRef ScreenDataCacheCount As Short) 

当我调用这个方法时,我提交了空终止字符数组 ex。

Dim param1 As Char()
param1(0) = "c"c
param1(1) = "a"c
param1(2) = "t"c
param1(3) = ChrW(0)
StartSession (param1,...)

pinvoke 向导生成了以下存根

<DllImport("chat2.dll")> _
Public Function StartSession( _
        ByRef lpbReturnCode As Byte _
        , ByRef lpbErrorMessage As Byte _
        , ByRef lpbApplName As Byte _
        , ByRef lpbRegionName As Byte _
        , ByRef lpbSessionID As Byte _
        , ByRef lpbDataTrunc As Byte _
        , ByRef lpbSessionToken As Byte _
        , ByRef lpbStandardWait As Byte _
        , ByRef lpbVersion As Byte _
        , ByRef lpbEnvironment As Byte _
        , ByRef lpbESILogonOnly As Byte _
        , ByRef lpbMetadataSource As Byte _
        , ByRef lpbMetadataCacheCount As Short _
        ) As Short
End Function

如何使用单个字节来表示以空字符结尾的字符串?

4

1 回答 1

1

对于这个问题:

如何使用单个字节来表示以空字符结尾的字符串?

简单的答案是“你没有”。

无论如何,这并不是代码中发生的事情。首先,ByRef someVar As Byte没有将 Byte 传递给 API。它传递一个指向字节的指针。因此,在本机方面,代码正在获取该字节的地址。现在,如果该地址指向包含字符串字符的字节缓冲区中的第一个字节并且(很可能)以空值结尾,那么该 API 很容易将该内容读取到该空值并对其进行操作。

您实际上可以在 C# 中使用不安全的代码块,或者 GCHandle pinng 或 Marshal 类或 MarshalAs 属性中的某些东西,通过执行类似StartSession(myParam1Buff[0], etc, etc);.

但是不要。您需要阅读文档(不仅仅是头文件)并确定 API 的预期内容以及使用正确 MarshalAs 属性装饰的 useStringBuilder或 '实例,并根据文档设置UnmanagedType标志。最有可能的是。StringLPStr

于 2012-07-05T18:58:06.643 回答