delphi - IcmpSendEcho (ping) 在 Windows 10 上失败
问题描述
我们有一个遗留的 Delphi 应用程序,它使用IcmpSendEcho
(来自 iphlpapi.dll)来执行回显请求。据我了解,这与命令提示符下的“ping”执行相同的功能。
在 Windows XP 上,下面的代码可以正常工作。当 IPv4 地址正确时,响应很快,如果不是,则按预期返回错误代码 11010 (IP_REQ_TIMED_OUT)。
但是,在我的 32 位 Windows 10 机器上,错误代码是 87 (ERROR_INVALID_PARAMETER)。我已经仔细查看了IcmpSendEcho 的 Microsoft 文档并且看不到任何明显的错误。
“ping 200.1.2.121”(我在代码示例中使用的示例 IPv4 地址)在 XP 和 10 的命令提示符下都能正常工作。
type
PIpAddress = ^TIpAddress;
TIpAddress = record
case Integer of
0: (S_un_b: TSunB);
1: (S_un_w: TSunW);
2: (S_addr: LongWord);
end;
IpAddress = TIpAddress;
// Functions imported from external DLLs
function IcmpCreateFile() : THandle; stdcall; external 'iphlpapi.dll';
function IcmpCloseHandle(icmpHandle: THandle) : Boolean; stdcall; external 'iphlpapi.dll';
function IcmpSendEcho(IcmpHandle: THandle; ipDest: IpAddress;
pRequestData: Pointer; nRequestSize: SmallInt; RequestOptions: Pointer;
pReplyBuffer: Pointer; dwReplySize: DWORD; dwTimeout: DWORD) : DWORD; stdcall; external 'iphlpapi.dll';
procedure TranslateStringToIpAddress(strIP: String; var ipAddress);
var
phe: PHostEnt;
pac: PChar;
begin
try
phe := GetHostByName(PChar(strIP));
if (Assigned(phe)) then
begin
pac := phe^.h_addr_list^;
if (Assigned(pac)) then
begin
with TIpAddress(ipAddress).S_un_b do
begin
by1 := Byte(pac[0]);
by2 := Byte(pac[1]);
by3 := Byte(pac[2]);
by4 := Byte(pac[3]);
end;
end
else
begin
raise Exception.Create('Error getting IP from HostName');
end;
end
else
begin
raise Exception.Create('Error getting HostName');
end;
except
FillChar(ipAddress, SizeOf(ipAddress), #0);
end;
end;
function Ping(strIpAddress : String) : Boolean;
const
ICMP_ECHO_BUFFER = 128; // Works as low as 28 on Windows XP (nothing works on Windows 10)
var
address: IpAddress;
dwReplies: DWORD;
{$IFDEF DBG} dwErrorCode: DWORD; {$ENDIF}
abyReplyBuffer: array[1..ICMP_ECHO_BUFFER] of BYTE;
begin
// Use this function to determine if an IPv4 address can be reached
Result := False;
// "m_cache.hPingHandle" is generated earlier with a call to "IcmpCreateFile"
if (m_cache.hPingHandle = INVALID_HANDLE_VALUE) then
Exit;
TranslateStringToIpAddress(strIpAddress, address);
dwReplies := IcmpSendEcho(
m_cache.hPingHandle, address, nil, 0, nil, @abyReplyBuffer, ICMP_ECHO_BUFFER, 0);
{$IFDEF DBG}
if (dwReplies = 0) then
begin
dwErrorCode := GetLastError();
// dwErrorCode = 87 (ERROR_INVALID_PARAMETER, "The parameter is incorrect")
Application.MessageBox(
PAnsiChar(Format('WinError = %d', [dwErrorCode])), 'Ping failed', MB_ICONEXCLAMATION);
end;
{$ENDIF}
// Success?
Result := (dwReplies <> 0);
end;
// Usage elsewhere in the application...
Ping('200.1.2.121'); // Works on Windows XP, but fails on Windows 10
解决方案
根据@FredS 的评论(谢谢!),答案只是将最后一个参数设为IcmpSendEcho
非零(例如“200”)。
MSDN 文档没有明确说明这一点,因此 Microsoft 可能已从 Windows XP 中的版本更改了此方法的内部实现,因此现在需要IcmpSendEcho
非零值。Timeout
推荐阅读
- firebase - Google Cloud Cloud Function 签名的 url 产生 403 SignatureDoesNotMatch
- r - 将行堆叠在一起
- python - 通过 python 中的机器人类在 selenium 中使用 enter 键
- ajax - AJAX withCredentials 未在 Safari 中传递 cookie
- android - 要流式传输的 APK 文件
- php - PHP用不同数组中的值替换数组中的值
- r - 合并 R 中的文件并保留我进行匹配的列?
- java - 带有 jni 的长字符串上的 NullPointer
- c# - 没有传递参数时水晶报表的问题
- drupal - Drupal 8 无法将 JS 添加到库子主题