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:
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?
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!