GetAdaptersInfo not working on Delphi XE6

天大地大妈咪最大 提交于 2019-12-04 17:41:49

There are several problems with your code:

  1. You are not doing any error handling at all on the first call that calculates the buffer length. You don't even need that call, so get rid of it.

  2. You are not doing adequate error handling on subsequent calls, in particular you are not handling the ERROR_BUFFER_OVERFLOW condition when GetAdaptersInfo() needs you to allocate more memory than you already have. Your are allocating only enough memory for one adapter, but GetAdaptersInfo() returns info for all adapters and thus needs a sufficient buffer to hold all of them at one time.

  3. GetAdaptersInfo() does not use GetLastError(), so you need to call SetLastError() before you call RaiseLastOSError().

  4. You are looping through the adapter list using the original pointer that you used to allocate the list, so you are causing a memory leak if the first adapter does not have a MAC address. You need to use a separate variable as the loop iterator so the original pointer is preserved so it can be freed correctly.

  5. You are not taking into account the possibility that none of the adapters has a MAC address, so you will end up accessing a nil pointer after your while loop exits.

  6. You appear to have multiple versions of the IpTypes unit on your machine, and the compiler is finding one that happens to use Char instead of AnsiChar in the IP_ADAPTER_INFO record so its size and field offsets are wrong.

With that said, try this instead:

uses
  Winapi.iphlpapi, Winapi.IpTypes;

function GetFirstAdapterMacAddress: String;
var
  pAdapterList, pAdapter: PIP_ADAPTER_INFO;
  BufLen, Status: DWORD;
  I: Integer;
begin
  Result := '';
  BufLen := 1024*15;
  GetMem(pAdapterList, BufLen);
  try
    repeat
      Status := GetAdaptersInfo(pAdapterList, BufLen);
      case Status of
        ERROR_SUCCESS:
        begin
          // some versions of Windows return ERROR_SUCCESS with
          // BufLen=0 instead of returning ERROR_NO_DATA as documented...
          if BufLen = 0 then begin
            raise Exception.Create('No network adapter on the local computer.');
          end;
          Break;
        end;
        ERROR_NOT_SUPPORTED:
        begin
          raise Exception.Create('GetAdaptersInfo is not supported by the operating system running on the local computer.');
        end;
        ERROR_NO_DATA:
        begin
          raise Exception.Create('No network adapter on the local computer.');
        end;
        ERROR_BUFFER_OVERFLOW:
        begin
          ReallocMem(pAdapterList, BufLen);
        end;
      else
        SetLastError(Status);
        RaiseLastOSError;
      end;
    until False;

    pAdapter := pAdapterList;
    while pAdapter <> nil do
    begin
      if pAdapter^.AddressLength > 0 then
      begin
        for I := 0 to pAdapter^.AddressLength - 1 do begin
          Result := Result + IntToHex(pAdapter^.Address[I], 2);
        end;
        Exit;
      end;
      pAdapter := pAdapter^.next;
    end;
  finally
    FreeMem(pAdapterList);
  end;
end;

The explanation is that the types declared in your third party IpTypes unit use Char. This is an alias to AnsiChar in pre-Unicode Delphi, and an alias to WideChar in Unicode Delphi. That would explain the fact that you see non-ANSI text when you inspect the content of the record.

The solution is to fix IpTypes to use AnsiChar in place of Char where appropriate. The best way to do that is to use the IpTypes shipped with Delphi rather than your third party version.

On top of that, the first call to GetAdaptersInfo is wrong. Not only do you fail to check the return value, but you pass nil for the buffer and yet also pass a non-zero length. I think it should go like this:

BufLen := 0;
if GetAdaptersInfo(nil, BufLen) <> ERROR_BUFFER_OVERFLOW then
  raise ....

Of course, you way will work, but I'm just being a little pedantic here. Always check for errors when you call an API function.

Just to conclude this topic.

Changing IPtypes to winapi.IPtypes fixed the problem for me.

I think a third party component is doing something to confuse the compiler and giving the full link fixes it.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!