Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations MikeeOK on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

dnsapi.dll 1

Status
Not open for further replies.

drahcirnotpit

Programmer
Jun 15, 2006
2
US
Thanks for any comments, examples, suggestions:

Is this c++ structure from MS SDK to delphi correct?

typedef struct _DnsRecord {
struct _DnsRecord* pNext;
LPTSTR pName;
WORD wType;
WORD wDataLength;
union { DWORD DW;
DNS_RECORD_FLAGS S; } Flags;
DWORD dwTtl;
DWORD dwReserved;
union { DNS_A_DATA A;
DNS_SOA_DATA SOA, Soa;
DNS_PTR_DATA PTR, Ptr, NS, Ns, CNAME,
Cname, MB, Mb, MD, Md, MF,
Mf, MG, Mg, MR, Mr;
DNS_MINFO_DATA MINFO, Minfo, RP, Rp;
DNS_MX_DATA MX, Mx, AFSDB, Afsdb, RT,
Rt;
DNS_TXT_DATA HINFO, Hinfo, ISDN, Isdn,
TXT, Txt, X25;
DNS_NULL_DATA Null;
DNS_WKS_DATA WKS, Wks;
DNS_AAAA_DATA AAAA;
DNS_KEY_DATA KEY, Key;
DNS_SIG_DATA SIG, Sig;
DNS_ATMA_DATA ATMA, Atma;
DNS_NXT_DATA NXT, Nxt;
DNS_SRV_DATA SRV, Srv;
DNS_TKEY_DATA TKEY, Tkey;
DNS_TSIG_DATA TSIG, Tsig;
DNS_WINS_DATA WINS, Wins;
DNS_WINSR_DATA WINSR, WinsR, NBSTAT,
Nbstat;
} Data;
} DNS_RECORD, *PDNS_RECORD;

My Translation:

_DnsRecord = record
pNext: Pointer;
pName: PAnsiChar;
wType: WORD;
wDataLength: WORD;
Flags: record case Integer of
0: (DW: DWORD);
1: (S: DNS_RECORD_FLAGS);
end;
dwTtl: DWORD;
dwReserved: DWORD;
Data: record case Integer of
0: (A: DNS_A_DATA);
1: (SOA: DNS_SOA_DATA);
2: (PTR,
NS,
CNAME,
MB,
MD,
MF,
MG,
MR: DNS_PTR_DATA);
3: (MINFO,
RP: DNS_MINFO_DATA);
4: (MX,
AFSDB,
RT: DNS_MX_DATA);
5: (HINFO,
ISDN,
TXT,
X25: DNS_TXT_DATA);
6: (Null: DNS_NULL_DATA);
7: (WKS: DNS_WKS_DATA);
8: (AAAA: DNS_AAAA_DATA);
9: (KEY: DNS_KEY_DATA);
10: (SIG: DNS_SIG_DATA);
11: (ATMA: DNS_ATMA_DATA);
12: (NXT: DNS_NXT_DATA);
13: (SRV: DNS_SRV_DATA);
14: (TKEY: DNS_TKEY_DATA);
15: (TSIG: DNS_TSIG_DATA);
16: (WINS: DNS_WINS_DATA);
17: (WINSR: DNS_WINSR_DATA);
end;
end;
DNS_RECORD = _DnsRecord;
PDNS_RECORD = ^_DnsRecord;


Best Regards
 
1)
If you are sending the record outside your own code (to a third party DLL/app) a "packed record" or another non-default alignment could be needed.

It is all about how the C++ compiler itself aligned the structure.

2)
PDNS_RECORD = ^_DNSRecord
_DnsRecord = record
pNext: PDNS_RECORD;
...
...
end;
DNS_RECORD = _DnsRecord;

Will save yourself a lot of typecasting while debugging.

3)
I think the unions are ok, but the name duplication makes it a little confusing. Some other opinion here?

buho (A).

 
1) Yes 2) thanks 3) wasn't sure either about the dups.

Your 1) made me think of the bit fields in some of the structures in windns.h. Sure enough I forgot about them and
wasn't sure how delphi handles such. example:

typedef struct _DnsRecordFlags
{
DWORD Section : 2;
DWORD Delete : 1;
DWORD CharSet : 2;
DWORD Unused : 3;
DWORD Reserved : 24;
}
DNS_RECORD_FLAGS;

I had this before your post:

_DnsRecordFlags = record
Section: DWORD;
Delete: DWORD;
CharSet: DWORD;
Unused: DWORD;
Reserved: DWORD;
end;
DNS_RECORD_FLAGS = _DnsRecordFlags;

After I read your post I realized the bit issue and did this:

_DnsRecordFlags = record
Section: DWORD {remember 2 bits}
{ Delete: DWORD 1 bit
CharSet: DWORD 2 bits
Unused: DWORD 3 bits
Reserved: DWORD 24 bits}
end;
DNS_RECORD_FLAGS = _DnsRecordFlags;

though I am not sure how to handle bit fields in delphi.
I also did this to a couple of others and everything lined
up according to plan. Thanks.

 
Second one is the right way:

Code:
<<
type
_DnsRecordFlags = record
     Section: DWORD {remember 2 bits}
{    Delete: DWORD  1 bit
     CharSet: DWORD 2 bits
     Unused: DWORD 3 bits
     Reserved: DWORD 24 bits}
end;
DNS_RECORD_FLAGS = _DnsRecordFlags;
>>

Or may be:

Code:
type
  _DnsRecordFlags = cardinal;

(Actually it is a cardinal (DWORD); the record is only due to the automatic translation from C.)

The most direct way to handle the bit fields is using constant masks (can be long to define for wide fields).

Code:
const // v stands for value
DNSSection_Delete     = $80000000; // Leftmost bit (31)
DNSSection_CharSet_v0 = $00000000; // Bits 30 and 29 = 00
DNSSection_CharSet_v1 = $20000000; // Bits 30 and 29 = 01
DNSSection_CharSet_v2 = $40000000; // Bits 30 and 29 = 10
DNSSection_CharSet_v3 = $60000000; // Bits 30 and 29 = 11

(Check the hexas, I'm making them on the fly).

Having the masks defined, you can bitwise-operate without much hassle.

It is posible to define the fields in a more broad way:

Code:
const
DNSSection_Delete  = $80000000; // Leftmost bit (31)
DNSSection_CharSet = $60000000; // Bits 30 and 29
DNSSection_Unused  = $1C000000; // Bits 28...26

But probably you are going to need some shifts to check the values.

Or may be:

Code:
const // b stands for bit
DNSSection_Delete_b0  = $80000000; // Leftmost bit (31)
DNSSection_CharSet_b1 = $40000000; // Bit 30
DNSSection_CharSet_b0 = $20000000; // Bit 29
DNSSection_Unused_b2  = $10000000; // Bit 28
DNSSection_Unused_b1  = $08000000; // Bit 27
DNSSection_Unused_b0  = $04000000; // Bit 26

Where you don't need shifts to check:

if Flags and DNSSection_Charset_b0 then ...
if Flags and (DNSSection_Charset_b0 + DNSSection_Charset_b1) then ...

Now, the most PASCALish way is creating an enumerated type to represent the fields. The problem here is enumerateds being deployed right to left and C bit fields being deployed left to right.

Code:
type
TDNSSectionBits = (// Fillers: 0..1
                   dsb0, dsb1,
                   // Reserved: 2 + 24 = 26
                   dsbResvd_0, dsbResvd_1, dsbResvd_2, dsbResvd_3,
                   dsbResvd_4, dsbResvd_5, dsbResvd_6, dsbResvd_7,
                   dsb1Resvd_8, dsbResvd_9, dsbResvd_10, dsbResvd_11,
                   dsbResvd_12, dsbResvd_13, dsbResvd_14, dsbResvd_15,
                   dsbResvd_16, dsbResvd_17, dsbResvd_18, dsbResvd_19,
                   dsbResvd_20, dsbResvd_21, dsbResvd_22, dsbResvd_23,
                   // Unused: 26 + 3 = 29
                   dsbUnused_0, dsbUnused_1, dsbUnused_2,
                   // Charset: 29 + 2 = 31
                   dsbCharset_0, dsbCharset_1,
                   // Delete: 31 + 1 = 32
                   dsbDelete_0);

_DnsRecordFlags = set of TDNSSectionBits;

const
// Consts here can help in some simple cases
DSSectionDelete = [dsbDelete_0];
DSSectionCharset= [dsbCharset_0..dsbCharset_1];
DSSectionUnused = [dsbUnused_0..dsbUnused_2];

You can use sets to check the flags:

if Flags * [dsbCharset_0] <> [] then ...
if Flags * [dsbCharset_0, dbCharset_1] <> [] then ...

Sometimes using the set approach is better, sometimes not. Depends on situation and tastes.

[/code]
buho (A).
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top