Windows 10上的IcmpSendEcho(ping)失败

问题描述 投票:2回答:1

我们有一个遗留的Delphi应用程序,它使用IcmpSendEcho(来自iphlpapi.dll)来执行echo请求。据我了解,它执行与命令提示符中的“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
delphi windows-10 ipv4 icmp
1个回答
1
投票

根据@FredS的评论(谢谢!),答案只是让IcmpSendEcho的最后一个参数为非零(例如“200”)。

MSDN documentationIcmpSendEcho并没有明确这一点,因此微软可能已经从Windows XP中的版本改变了这种方法的内部实现,因此现在需要一个非零的Timeout

© www.soinside.com 2019 - 2024. All rights reserved.