试图理解String类型的DLL返回

时间:2017-03-13 03:35:50

标签: string vba dll

我正在尝试使用DLL来了解字符串处理。我不确定我是否理解不同字符串数据结构的差异以及如何处理每个字符串数据结构或如何识别正在使用的字符串数据结构。

我有以下代码来证明我的困境。

GetReaders
Returns = 0, Readers = "" Length = 23
Returns = 0, Readers = "" Length = 23

GetReaders2
Returns = 0, Readers = "                                                  " Length = 23
Returns = 0, Readers = "Athena ASEDrive V3C 0                             " Length = 23

返回以下内容:

Total = duration * price per minute/second

该函数的文档位于https://msdn.microsoft.com/en-us/library/windows/desktop/aa379793(v=vs.85).aspx,表示mszReaders的返回值是多字符串。所以,我认为缺少的数据实际上正在传递,我只是不知道如何访问它。

我可以为我的目的进行例行工作的第二次实例化,这样做似乎不合理。我错过了什么?我将不胜感激任何帮助。

1 个答案:

答案 0 :(得分:1)

答案在您链接的文档的示例代码中:

case SCARD_S_SUCCESS:
    // Do something with the multi string of readers.
    // Output the values.
    // A double-null terminates the list of values.
    pReader = pmszReaders;
    while ( '\0' != *pReader )
    {
        // Display the value.
        printf("Reader: %S\n", pReader );
        // Advance to the next value.
        pReader = pReader + wcslen((wchar_t *)pReader) + 1;
    }

您传递的String正在填充一个空的分隔字符串数组,以double null结尾。当你传递一个空的变量长度String时,它只被编组为第一个项目,因为它将它遇到的第一个空格解释为字符串的结尾。

再次,从您链接的文档:

  

mszReaders [out]

     

多字符串,列出所提供阅读器中的读卡器   组。如果此值为NULL,则SCardListReaders将忽略缓冲区   在pcchReaders中提供的长度,写入缓冲区的长度   如果此参数未归零,则会返回   pcchReaders,并返回成功代码。

此API遵循双重调用用法模式 - 第一个调用提供所需的缓冲区大小,第二个调用用于写入缓冲区。如果您负责提供缓冲区,则必须将指针传递给现有的String

这会导致您的另一个问题 - 您的函数声明错误。再次,从您的链接文档:

LONG WINAPI SCardListReaders(
  _In_     SCARDCONTEXT hContext,
  _In_opt_ LPCTSTR      mszGroups,
  _Out_    LPTSTR       mszReaders,
  _Inout_  LPDWORD      pcchReaders
);

首先,它返回Long,而不是Integerh上的hContext前缀代表" handle",它也是一个指针,因此您不应该将其作为Integer 传递或者 即可。该函数的正确声明是:

Declare PtrSafe Function SCardListReaders Lib "winscard.dll" Alias "SCardListReadersA" ( _
    ByVal phContext As LongPtr, _
    ByVal mszGroups As LongPtr, _
    ByVal mszReaders As LongPtr, _
    ByRef pcchReaders As Long _
    ) As Long

根据您的代码,您使用NULL mszGroups调用约定,因此您的调用代码应该更像这样:

Sub GetReaders()
    Const SCARD_S_SUCCESS As Long = 0
    Dim result As Long
    Dim readers As String
    Dim bufferSize As Long

    'Request the buffer size.
    result = SCardListReaders(0, 0, 0, bufferSize)
    'Test your return value for success.
    If result <> SCARD_S_SUCCESS Then
        Debug.Print "Buffer sizing call failed with return of " & result
        Exit Sub
    End If

    'Size your output buffer
    readers = String$(bufferSize, Chr$(0))
    'Make the second call to fill the buffer.
    result = SCardListReaders(0, 0, StrPtr(readers), bufferSize)
    'Test the return value of *that* call too.
    If result <> SCARD_S_SUCCESS Then
        Debug.Print "Buffer fill call failed with return of " & result
        Exit Sub
    End If

    'Process the null-delimited array.
    Dim readerArray() As String
    readerArray = Split(readers, Chr$(0))
    Dim index As Long
    For index = LBound(readerArray) To UBound(readerArray)
        Debug.Print readerArray(index)
    Next
End Sub

请注意,这是未经测试的(我没有任何读者可以对其进行验证),但它至少应该指向正确的方向。