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

Winapi VB6-对DnsQuery的Windows API调用-函数和指针问题,winapi,vb6,pointers,dns,Winapi,Vb6,Pointers,Dns,在VB6中,我正在调用Windows API 我的结构声明来自。我假设其他人(35)在返回的实际结构大于预期时提供足够大的容器(其中有一些联合的可变长度类型)。有关更多详细信息,请参阅 因此,我有两个问题: VB中的字符串实际上是幕后的双字指针(4字节,又称长)。有一段时间,我认为我可以将名称声明为字符串,因为这只会将指针放在其中并正常工作(就像将VB字符串传递到API调用中一样)。然而,我猜我得到的应用程序终止是因为它是一个C风格的字符串,而不是VB风格的字符串,VB在字符串开始前的内存位置查

在VB6中,我正在调用Windows API

我的结构声明来自。我假设其他人(35)在返回的实际结构大于预期时提供足够大的容器(其中有一些联合的可变长度类型)。有关更多详细信息,请参阅

因此,我有两个问题:

  • VB中的字符串实际上是幕后的双字指针(4字节,又称长)。有一段时间,我认为我可以将名称声明为字符串,因为这只会将指针放在其中并正常工作(就像将VB字符串传递到API调用中一样)。然而,我猜我得到的应用程序终止是因为它是一个C风格的字符串,而不是VB风格的字符串,VB在字符串开始前的内存位置查找长度值,并得到一些随机垃圾,然后爆炸。这是合理的猜测吗

  • 当我使用返回DNS RR类型的DNS_PTR_数据或DNS_a_数据时,我对DnsQuery的调用会起作用,但当我尝试使用DNS_TXT_数据时,它会爆炸。其他人能看出我做错了什么吗?查看案例DNS_类型_文本,并查看下面我的评论

    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
    
    RetVal=DnsQuery(DnsName,
    查询类型,DNS查询绕过缓存,
    p服务器,pDnsRecord,0)
    如果RetVal=0,则
    pNext=pDnsRecord
    在pNext 0时执行此操作
    复制内存DnsRecord,pNext,Len(DnsRecord)
    选择Case DnsRecord.wType
    案例DNS_类型_A
    Ptr=inet_ntoa(DnsRecord.ptrData)
    TempString=String(lstrlen(Ptr),0)
    CopyMemory ByVal TempString、Ptr、Len(TempString)
    案例DNS类型PTR,DNS类型NS,DNS类型CNAME,
    DNS_TYPE_DNAME,DNS_TYPE_MB,
    DNS类型MD,DNS类型MF,
    DNS类型\ MG,DNS类型\ MR
    Ptr=DnsRecord.ptrData
    TempString=String$(lstrlen(Ptr),0)
    CopyMemory ByVal TempString、Ptr、Len(TempString)
    案例DNS类型文本、DNS类型HINFO、DNS类型ISDN、,
    DNS类型文本,DNS类型
    Dim TextData作为Dns_Txt_数据
    Ptr=DnsRecord.ptrData
    CopyMemory VarPtr(文本数据)、Ptr、Len(文本数据)
    停止
    其他情况
    TempString=“未处理的资源记录类型”
    结束选择
    如果没有完整记录,那么
    DnsLookup=”“&TempString
    退出Do
    其他的
    DnsLookup=DnsLookup&“”&vbCrLf&
    DnsTypeNameFromCode(DnsRecord.wType)
    &“”临时字符串(&T)
    如果结束
    pNext=DnsRecord.pNext
    环
    
    现在,当我在CopyMemory行上放置一个断点并检查Ptr的值时,我期望有数百万或更高的值,表明它是一个指针,只有我得到的值是1(这解释了为什么当我尝试从该内存位置复制时,所有东西都会爆炸)。这似乎向我表明,我得到的不是指向预期DNS_TXT_数据结构的指针,而是字符串的计数。当我检查其他(0)到其他(3)时,它们都有值,这使我怀疑接下来的四个字节是指针。那么是什么原因呢?为什么这个结构只是以“内联”的形式出现,而其他结构作为指向结构开头的指针出现

  • 谢谢你的帮助

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


    2) 我快速浏览了一下Microsoft文档,上面说这是一个计数,后跟一个指向字符串的指针(这就是您看到的),另一方面,是指向结果记录的点。因此,您所描述的内容似乎与文档相符。

    如果您将
    VBDnsRecord
    中的
    其他
    更改为
    pStringArray(0到8),只要
    这样访问字符串指针数组就会更容易

            ...
            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
    
    。。。
    ElseIf uRecord.wType=DNS\u TYPE\u TEXT然后
    对于lIdx=0到uRecord.prt-1
    sName=String(lstrlen(uRecord.pStringArray(lIdx)),0)
    调用CopyMemory(ByVal sName、uRecord.pStringArray(lIdx)、Len(sName))
    如果LenB(Resolve)为0,则
    Resolve=Resolve&vbCrLf
    如果结束
    解析=解析和sName
    下一个
    如果结束
    

    九个
    long
    正好是36字节,因此
    Len(VBDnsRecords)
    仍然是64字节,正好是平台SDK中的
    DNS\u记录的大小。

    1)VB字符串不是也以空结尾吗?所以VB字符串可以像C字符串一样工作,但不是相反,对吗?现在我终于明白了!我被对inet_ntoa的调用甩了,该调用返回一个(指向一个)字符串的指针。但它实际上只是一种价值。不知怎的,我知道那是一个指针。我现在确切地知道该做什么(但要到周二才会回来讨论);此外,他们使用宽字符。您应该在两个方向上使用转换例程。如果它们使用宽字符,而API函数不使用,那么CopyMemory将无法正常工作,但它确实可以工作。看起来你回答的更多的是理论而不是实际的实践?而且,DNS_PTR_数据里面确实有一个指针,但是DNS_a_数据没有。。。所以事实上,说“DNS_PTR_数据是指向结果记录的指针”并不是真的。不管怎样,在你和wqw之间,我发现了我的错误。现在我不知道该把答案授予谁。这里有一篇关于VB字符串和C字符串之间转换的文章:。它解释了VB字符串是16位unicode。我自己去玩东西,最终想出了。。。基本上就是您在这里所做的(尽管我不得不对您的数据类型上的匈牙利符号嗤之以鼻)。在你和jdigital之间,我发现了我的误解。如果你们中有人明确地说“联合元素直接嵌入到
            ...
            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