jim
jim

Reputation: 13

Operator + cannot be applied to operands of type IntPtr and int - .Net 3.5

The following code (used for looking up DNS TXT records) works fine in .NET 4, however I have had to downgrade the project to .NET 3.5 for various reasons, and now I am being presented with several errors

public String DnsGetTxtRecord(String name) {
  const Int16 DNS_TYPE_TEXT = 0x0010;
  const Int32 DNS_QUERY_STANDARD = 0x00000000;
  const Int32 DNS_ERROR_RCODE_NAME_ERROR = 9003;
  const Int32 DNS_INFO_NO_RECORDS = 9501;
  var queryResultsSet = IntPtr.Zero;
  try {
    var dnsStatus = DnsQuery(
      name,
      DNS_TYPE_TEXT,
      DNS_QUERY_STANDARD,
      IntPtr.Zero,
      ref queryResultsSet,
      IntPtr.Zero
    );
    if (dnsStatus == DNS_ERROR_RCODE_NAME_ERROR || dnsStatus == DNS_INFO_NO_RECORDS)
      return null;
    if (dnsStatus != 0)
      throw new Win32Exception(dnsStatus);
    DnsRecordTxt dnsRecord;
    for (var pointer = queryResultsSet; pointer != IntPtr.Zero; pointer = dnsRecord.pNext) {
      dnsRecord = (DnsRecordTxt) Marshal.PtrToStructure(pointer, typeof(DnsRecordTxt));
      if (dnsRecord.wType == DNS_TYPE_TEXT) {
        var lines = new List<String>();
        var stringArrayPointer = pointer
          + Marshal.OffsetOf(typeof(DnsRecordTxt), "pStringArray").ToInt32();
        for (var i = 0; i < dnsRecord.dwStringCount; ++i) {
          var stringPointer = (IntPtr) Marshal.PtrToStructure(stringArrayPointer, typeof(IntPtr));
          lines.Add(Marshal.PtrToStringUni(stringPointer));
          stringArrayPointer += IntPtr.Size;
        }
        return String.Join(Environment.NewLine, lines);
      }
    }
    return null;
  }
  finally {
    const Int32 DnsFreeRecordList = 1;
    if (queryResultsSet != IntPtr.Zero)
      DnsRecordListFree(queryResultsSet, DnsFreeRecordList);
  }
}

[DllImport("Dnsapi.dll", EntryPoint = "DnsQuery_W", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
static extern Int32 DnsQuery(String lpstrName, Int16 wType, Int32 options, IntPtr pExtra, ref IntPtr ppQueryResultsSet, IntPtr pReserved);

[DllImport("Dnsapi.dll")]
static extern void DnsRecordListFree(IntPtr pRecordList, Int32 freeType);

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct DnsRecordTxt {
  public IntPtr pNext;
  public String pName;
  public Int16 wType;
  public Int16 wDataLength;
  public Int32 flags;
  public Int32 dwTtl;
  public Int32 dwReserved;
  public Int32 dwStringCount;
  public String pStringArray;
}

var stringArrayPointer = pointer + Marshal.OffsetOf(typeof(DnsRecordTxt), "pStringArray").ToInt32(); triggers "Operator + cannot be applied to operands IntPtr and int

return String.Join(Environment.NewLine, lines); returns "The best overload method has some invalid arguments"

Assistance appreciated!

Upvotes: 0

Views: 3195

Answers (2)

Wai Ha Lee
Wai Ha Lee

Reputation: 8816

You can't add to an IntPtr, but you can do this:

long address = pointer.ToInt64()
             + Marshal.OffsetOf(typeof(DnsRecordTxt), "pStringArray").ToInt64();
var stringArrayPointer = (IntPtr)address;

(as @xanatos said in his answer, use ToInt64 instead of ToInt32 to make it work in x64 as well as x86.)


As for the problem with the String.Join, you need to pass it an array as the second argument:

string.Join(Environment.NewLine, lines.ToArray());

Upvotes: 0

xanatos
xanatos

Reputation: 111950

This

var stringArrayPointer = pointer + Marshal.OffsetOf(typeof(DnsRecordTxt), "pStringArray").ToInt32();

can be changed to

var stringArrayPointer = (IntPtr)((long)pointer + Marshal.OffsetOf(typeof(DnsRecordTxt), "pStringArray").ToInt32());

(in .NET 4.0 they added some basic operations to IntPtr, but in .NET 2.0/3.5 you had to cast it to int/long. Casting to long is safer because it's 64bit ready)

This

return String.Join(Environment.NewLine, lines);

to

return String.Join(Environment.NewLine, lines.ToArray());

(In .NET 4.0 they added a String.Join overload that accepted a IEnumerable<string> as a parameter. In .NET 2.0/3.5 you had to use the overload that accepts a string[])

Upvotes: 3

Related Questions