IcmpSendEcho(ping)在Windows 10上失败

时间:2018-08-15 15:38:11

标签: delphi windows-10 ipv4 icmp

我们有一个遗留的Delphi应用程序,该应用程序使用IcmpSendEcho(来自iphlpapi.dll)执行回显请求。据我了解,它执行与命令提示符中“ ping”相同的功能。

在Windows XP上,以下代码可以正常工作。如果IPv4地址正确,则响应很快,如果没有,则按预期返回错误代码11010(IP_REQ_TIMED_OUT)。

但是,在我的32位Windows 10计算机上,错误代码为87(ERROR_INVALID_PARAMETER)。我已经仔细检查了Microsoft documentation for IcmpSendEcho,看不到任何明显错误的地方。

“ 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

1 个答案:

答案 0 :(得分:1)

根据@FredS的评论(谢谢!),答案很简单,就是使IcmpSendEcho的最后一个参数不为零(例如“ 200”)。

IcmpSendEcho的{​​{3}}不清楚,因此Microsoft可能已从Windows XP版本中更改了此方法的内部实现,以使非零Timeout为现在需要。