gpt4 book ai didi

delphi - GetAdaptersInfo 在 Delphi XE6 上不起作用

转载 作者:行者123 更新时间:2023-12-03 02:24:53 26 4
gpt4 key购买 nike

我终于硬着头皮买了XE6,不出所料,Unicode 转换变成了一场噩梦。因此,如果有人能启发我为什么这个简单的 Windows API 调用失败,我将不胜感激。该函数不会返回错误,第一次调用获取正确的缓冲区长度,第二次调用用垃圾填充记录。

这在 Delphi 2007 下工作正常,但在 XE6 上失败,pAdapterinfo 返回记录中存在 unicode 垃圾,即使它在 IpTypes.pas 中使用 AnsiString 显式声明也是如此

系统是Win7(64),但编译为32位。

uses iphlpapi, IpTypes;

function GetFirstAdapterMacAddress:AnsiString;
var pAdapterInfo:PIP_ADAPTER_INFO;
BufLen,Status:cardinal; i:Integer;
begin
result:='';
BufLen:= sizeof(IP_ADAPTER_INFO);
GetAdaptersInfo(nil, BufLen);
pAdapterInfo:= AllocMem(BufLen);
try
Status:= GetAdaptersInfo(pAdapterInfo,BufLen);
if (Status <> ERROR_SUCCESS) then
begin
case Status of
ERROR_NOT_SUPPORTED: raise exception.create('GetAdaptersInfo is not supported by the operating ' +
'system running on the local computer.');
ERROR_NO_DATA: raise exception.create('No network adapter on the local computer.');
else
raiselastOSerror;
end;
Exit;
end;
while (pAdapterInfo^.AddressLength=0) and (pAdapterInfo^.next<>nil) do
pAdapterInfo:=pAdapterInfo.next;
if pAdapterInfo^.AddressLength>0 then
for i := 0 to pAdapterInfo^.AddressLength - 1 do
result := result + IntToHex(pAdapterInfo^.Address[I], 2);
finally
Freemem(pAdapterInfo);
end;
end;

更新:

我做了更多检查。我创建了一个新的简单应用程序,其中包含一个表单和一个按钮,并在按下按钮时调用例程并且它起作用。

不同之处在于...在工作形式中,IP_ADAPTER_INFO 的大小为 640 字节。

当在更复杂的应用程序中使用此例程时,它会失败,并且 IP_ADAPTER_INFO 的大小显示为 1192 字节。

此时,编译器似乎单方面决定将结构中的 ansi 字符类型更改为 unicode 字符。调试器以 unicode 形式显示 AdapterName 和说明字段。我对系统源代码进行了 grep,除了 Indy 库之外,库代码中没有声明此数据类型的其他版本,这只是一个重复。

这是IPtypes中的数据结构定义

  PIP_ADAPTER_INFO = ^IP_ADAPTER_INFO;
{$EXTERNALSYM PIP_ADAPTER_INFO}
_IP_ADAPTER_INFO = record
Next: PIP_ADAPTER_INFO;
ComboIndex: DWORD;
AdapterName: array [0..MAX_ADAPTER_NAME_LENGTH + 3] of AnsiChar;
Description: array [0..MAX_ADAPTER_DESCRIPTION_LENGTH + 3] of AnsiChar;
AddressLength: UINT;
Address: array [0..MAX_ADAPTER_ADDRESS_LENGTH - 1] of BYTE;
Index: DWORD;
Type_: UINT;
DhcpEnabled: UINT;
CurrentIpAddress: PIP_ADDR_STRING;
IpAddressList: IP_ADDR_STRING;
GatewayList: IP_ADDR_STRING;
DhcpServer: IP_ADDR_STRING;
HaveWins: BOOL;
PrimaryWinsServer: IP_ADDR_STRING;
SecondaryWinsServer: IP_ADDR_STRING;
LeaseObtained: time_t;
LeaseExpires: time_t;
end;

看起来像是编译器错误。

最佳答案

您的代码存在几个问题:

  1. 在第一次调用计算缓冲区长度时,您根本没有进行任何错误处理。您甚至不需要该调用,因此请将其删除。

  2. 您没有对后续调用进行足够的错误处理,特别是当 GetAdaptersInfo() 需要您分配更多内存时,您没有处理 ERROR_BUFFER_OVERFLOW 情况比你已经拥有的。您只为一个适配器分配了足够的内存,但 GetAdaptersInfo() 返回所有适配器的信息,因此需要足够的缓冲区来一次容纳所有适配器。

  3. GetAdaptersInfo() 不使用 GetLastError(),因此您需要在调用 之前调用 SetLastError() >RaiseLastOSError().

  4. 您正在使用用于分配列表的原始指针循环访问适配器列表,因此如果第一个适配器没有 MAC 地址,则会导致内存泄漏。您需要使用一个单独的变量作为循环迭代器,以便保留原始指针,以便可以正确释放它。

  5. 您没有考虑到所有适配器都没有 MAC 地址的可能性,因此您最终将在 while 之后访问 nil 指针循环退出。

  6. 您的计算机上似乎有多个版本的 IpTypes 单元,并且编译器正在找到一个恰好使用 Char 而不是 的版本IP_ADAPTER_INFO 记录中的 AnsiChar,因此其大小和字段偏移量是错误的。

话虽如此,试试这个:

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;

关于delphi - GetAdaptersInfo 在 Delphi XE6 上不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23563932/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com