VB6 - 对 DnsQuery 的 Windows API 调用 - 函数和指针问题

发布于 2024-08-21 13:18:28 字数 3074 浏览 3 评论 0原文

在 VB6 中,我正在调用 Windows API DnsQuery

Private Declare Function DnsQuery Lib "dnsapi" Alias "DnsQuery_A" ( _
   ByVal lpstrName As String, _
   ByVal wType As Integer, _
   ByVal Options As Long, _
   ByVal pServers As Long, _
   ppQueryResultsSet As Long, _
   ByVal pReserved As Long) As Long

Private Type VBDnsRecord
   pNext           As Long
   pName           As Long
   'Name            As String ' Commented out, see question
   wType           As Integer
   wDataLength     As Integer
   Flags           As Long
   dwTtl           As Long
   dwReserved      As Long
   ptrData         As Long
   Others(35)      As Byte
End Type

我的结构声明来自此处 。我认为其他(35)是在返回的实际结构大于预期时提供一个足够大的容器(其中有一些可变长度类型 UNIONed )。有关详细信息,请参阅 DNS_RECORD 结构

所以,我有两个问题:

  1. VB 中的字符串在幕后实际上是双字指针(4 个字节,又名 Long)。有一段时间我想我可以将 Name 声明为字符串,因为这只会将指针放在那里并正常工作(就像将 VB 字符串传递到 API 调用时一样)。但是,我猜测我得到的应用程序终止是因为它是 C 样式字符串而不是 VB 样式字符串,并且 VB 在字符串开头之前的内存位置中查找长度值,并获取一些随机值垃圾并爆炸。这是一个合理的猜测吗?

  2. 当我使用返回 DNS_PTR_DATA 或 DNS_A_DATA 的 DNS RR 类型时,我对 DnsQuery 的调用有效,但是当我尝试 DNS_TXT_DATA 时,它会崩溃。其他人可以发现我做错了什么吗?查看案例 DNS_TYPE_TEXT,并查看下面我的评论。

    RetVal = DnsQuery(DnsName,
    查询类型,DNS_QUERY_BYPASS_CACHE,
    pServers、pDnsRecord、0)
        如果 RetVal = 0 那么
           pNext = pDnsRecord
           当 pNext <> 时执行0
              CopyMemory DnsRecord,pNext,Len(DnsRecord)
              选择案例 DnsRecord.wType
                 案例 DNS_TYPE_A
                    Ptr = inet_ntoa(DnsRecord.ptrData)
                    TempString = 字符串(lstrlen(Ptr), 0)
                    CopyMemory ByVal TempString、Ptr、Len(TempString)
                 案例 DNS_TYPE_PTR、DNS_TYPE_NS、DNS_TYPE_CNAME、
    DNS_TYPE_DNAME、DNS_TYPE_MB、
    DNS_TYPE_MD、DNS_TYPE_MF、
    DNS_TYPE_MG、DNS_TYPE_MR
                    Ptr = DnsRecord.ptrData
                    临时字符串 = 字符串$(lstrlen(Ptr), 0)
                    CopyMemory ByVal TempString、Ptr、Len(TempString)
                 案例 DNS_TYPE_TEXT、DNS_TYPE_HINFO、DNS_TYPE_ISDN、
    DNS_TYPE_TEXT、DNS_TYPE_X25
                    将 TextData 变暗为 Dns_Txt_Data
                    Ptr = DnsRecord.ptrData
                    CopyMemory VarPtr(文本数据),Ptr,Len(文本数据)
                    停止
                 其他情况
                    TempString = "未处理的资源记录类型"
             结束选择
             如果不是 FullRecord 那么
                DnsLookup =“”&临时字符串
                退出执行
             别的
                DnsLookup = DnsLookup & ” ” & vbCrLf &
    DnsTypeNameFromCode(DnsRecord.wType)
    & ” ” &临时字符串
             结束如果
             pNext = DnsRecord.pNext
          环形
    

    现在,当我在 CopyMemory 行上放置一个断点并检查 Ptr 的值时,我期望有数百万或更高的值,表明它是一个指针,只有我得到值 1(这解释了为什么一切当我尝试从该内存位置复制时会爆炸)。这似乎向我表明,我得到的是字符串的计数,而不是指向预期的 DNS_TXT_DATA 结构的指针。当我检查 Other(0) 到 Other(3) 时,它们都有值,这让我怀疑接下来的四个字节是指针。那么什么给出呢? 作为指向结构开头的指针出现?

我很感激任何帮助!

In VB6 I'm making a call to the Windows API DnsQuery.

Private Declare Function DnsQuery Lib "dnsapi" Alias "DnsQuery_A" ( _
   ByVal lpstrName As String, _
   ByVal wType As Integer, _
   ByVal Options As Long, _
   ByVal pServers As Long, _
   ppQueryResultsSet As Long, _
   ByVal pReserved As Long) As Long

Private Type VBDnsRecord
   pNext           As Long
   pName           As Long
   'Name            As String ' Commented out, see question
   wType           As Integer
   wDataLength     As Integer
   Flags           As Long
   dwTtl           As Long
   dwReserved      As Long
   ptrData         As Long
   Others(35)      As Byte
End Type

My declaration of the struct came from here. I presume Others(35) is to provide a big enough container when the actual struct that is returned is larger than expected (there are some variable-length types UNIONed in there). See the DNS_RECORD structure for more details.

So, I have 2 questions:

  1. Strings in VB are really, behind the scenes, double word pointers (4 bytes, aka a Long). For a bit I thought I could declare Name as a String since this would just place the pointer in there and work correctly (as when passing VB Strings into API calls). However, I'm guessing the application terminations I got are because it's a C-style string and not a VB-style string, and VB looks in the memory location just before the start of the string for a length value, and gets some random garbage and blows up. Is that a reasonable guess?

  2. My call to DnsQuery works when I use am returning a DNS RR type of DNS_PTR_DATA or DNS_A_DATA, but when I try DNS_TXT_DATA it's blowing up. Can someone else spot what I'm doing wrong? Look at Case DNS_TYPE_TEXT, and see my comments below.

    RetVal = DnsQuery(DnsName,
    QueryType, DNS_QUERY_BYPASS_CACHE,
    pServers, pDnsRecord, 0)
        If RetVal = 0 Then
           pNext = pDnsRecord
           Do While pNext <> 0
              CopyMemory DnsRecord, pNext, Len(DnsRecord)
              Select Case DnsRecord.wType
                 Case DNS_TYPE_A
                    Ptr = inet_ntoa(DnsRecord.ptrData)
                    TempString = String(lstrlen(Ptr), 0)
                    CopyMemory ByVal TempString, Ptr, Len(TempString)
                 Case DNS_TYPE_PTR, DNS_TYPE_NS, DNS_TYPE_CNAME,
    DNS_TYPE_DNAME, DNS_TYPE_MB,
    DNS_TYPE_MD, DNS_TYPE_MF,
    DNS_TYPE_MG, DNS_TYPE_MR
                    Ptr = DnsRecord.ptrData
                    TempString = String$(lstrlen(Ptr), 0)
                    CopyMemory ByVal TempString, Ptr, Len(TempString)
                 Case DNS_TYPE_TEXT, DNS_TYPE_HINFO, DNS_TYPE_ISDN,
    DNS_TYPE_TEXT, DNS_TYPE_X25
                    Dim TextData As Dns_Txt_Data
                    Ptr = DnsRecord.ptrData
                    CopyMemory VarPtr(TextData), Ptr, Len(TextData)
                    Stop
                 Case Else
                    TempString = "unhandled resource record type"
             End Select
             If Not FullRecord Then
                DnsLookup = "   " & TempString
                Exit Do
             Else
                DnsLookup = DnsLookup & " " & vbCrLf &
    DnsTypeNameFromCode(DnsRecord.wType)
    & " " & TempString
             End If
             pNext = DnsRecord.pNext
          Loop
    

    Now, when I put a breakpoint on the CopyMemory line and inspect the value of Ptr, I expect something in the millions or higher, indicating that it is a pointer, only I'm getting the value 1 (which explains why everything blows up when I try to copy from that memory location). This seems to indicate to me that instead of a pointer to the expected DNS_TXT_DATA struct, I'm getting the count of strings. When I examine Other(0) through Other(3), they all have values which make me suspect the next four bytes are a pointer. So what gives? Why is this struct just coming in "inline" but the others come in as pointers to the start of the struct?

I appreciate any help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

橪书 2024-08-28 13:18:28

如果将 VBDnsRecord 中的 Others 更改为 pStringArray(0 To 8) As Long,则访问字符串指针数组会更容易,如下所示

        ...
        ElseIf uRecord.wType = DNS_TYPE_TEXT Then
            For lIdx = 0 To uRecord.prt - 1
                sName = String(lstrlen(uRecord.pStringArray(lIdx)), 0)
                Call CopyMemory(ByVal sName, uRecord.pStringArray(lIdx), Len(sName))
                If LenB(Resolve) <> 0 Then
                    Resolve = Resolve & vbCrLf
                End If
                Resolve = Resolve & sName
            Next
        End If

Long 正好是 36 个字节,因此 Len(VBDnsRecords) 仍然是 64 个字节,恰好是 Platform SDK 中 DNS_RECORD 联合的大小。

If you change Others in VBDnsRecord to pStringArray(0 To 8) As Long it will be easier to access the array ot string pointers like this

        ...
        ElseIf uRecord.wType = DNS_TYPE_TEXT Then
            For lIdx = 0 To uRecord.prt - 1
                sName = String(lstrlen(uRecord.pStringArray(lIdx)), 0)
                Call CopyMemory(ByVal sName, uRecord.pStringArray(lIdx), Len(sName))
                If LenB(Resolve) <> 0 Then
                    Resolve = Resolve & vbCrLf
                End If
                Resolve = Resolve & sName
            Next
        End If

Nine Longs are exactly 36 bytes so Len(VBDnsRecords) remains 64 bytes, exactly the size of the DNS_RECORD union in Platform SDK.

献世佛 2024-08-28 13:18:28

1) C 字符串和 VB 字符串不同,您不能仅用一种字符串替换另一种字符串。您需要将 C 字符串显式转换为 VB 字符串。换句话说,是的,你的猜测是合理的。

2)我快速浏览了微软文档,其中说 DNS_TXT_DATA 是一个计数,后跟一个指向字符串的指针(这就是您所看到的)。另一方面,DNS_PTR_DATA 是指向结果记录的点。所以你所描述的似乎与文档相符。

1) C strings and VB strings different and you can't just substitute one for another. You'll need to explicitly convert the C string to a VB string. In other words, yes, your guess is reasonable.

2) I took a quick look at the Microsoft docs, which say that DNS_TXT_DATA is a count followed by a pointer to a string (which is what you're seeing). DNS_PTR_DATA, on the other hand, is a point to the resulting record. So what you're describing seems to match the documentation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文