在没有使用 netstat 的情况下检查本地端口是否不受 Inno Setup 的影响

Check local port is free from Inno Setup without netstat usage

我的问题之前曾在这里被问过,但我正在尝试为我的项目实施一个更简洁的解决方案。因此,正如标题所述,我正在创建一个复杂的服务器应用程序安装程序,它必须检查本地 IP 地址并选择一个开放端口,以便可以正确配置应用程序。使用 Inno Setup 5.6.1。

获取本地IP地址不是问题,this solution对我帮助很大。然后是端口检查,在这里我发现了以下三个选项:

如上所述,获取 IP 地址可以通过直接(好吧,不是真的,它是一个 Pascal 脚本)WinAPI 调用来实现。因此,我尝试对端口执行相同的操作,尝试调用 GetTcpTable():

[Code]

const
  ERROR_INSUFFICIENT_BUFFER = 122;


function GetTcpTable(pTcpTable: Array of Byte; var pdwSize: Cardinal;
  bOrder: WordBool): DWORD;
external 'GetTcpTable@IpHlpApi.dll stdcall';

{ ------------------------ }

function CheckPortIsOpen(port: Integer): Boolean;
var
  TableSize  : Cardinal;
  Buffer : Array of Byte; { Alas, no pointers here }
  RecordCount : Integer;
  i, j : Integer;
  portNumber : Cardinal;
  IpAddr : String;
begin
  Result := True;
  TableSize := 0;

  if GetTcpTable(Buffer, TableSize, False) = ERROR_INSUFFICIENT_BUFFER then
    begin
      SetLength(Buffer, TableSize);
      if GetTcpTable(Buffer, TableSize, True) = 0 then
        begin
          { some magic calculation from GetIpAddrTable calling example }
          RecordCount := (Buffer[1] * 256) + Buffer[0];
          For i := 0 to RecordCount -1 do
            begin
              portNumber := Buffer[i*20 + 8]; { Should work! }

              { Debugging code here }
              if (i < 5) then begin
                IpAddr := '';
                For J := 0 to 3 do
                 begin
                   if J > 0 then
                    IpAddr := IpAddr + '_';
                    IpAddr := IpAddr + IntToStr(Buffer[I*20+ 4 + J]);
                 end;
                SuppressibleMsgBox(IpAddr, mbError, MB_OK, MB_OK);
              end;
              { ------ }

              if port = portNumber then
                  Result := False;
            end;
        end;
    end;
end;

GetTcpTable 还 returns 有关地址和端口的信息(确切地说是 TCP 连接的 table),因此尝试获取任何连接地址都有助于调试。有关此尝试的更多信息:

所以,一切都很有趣...只是行不通 =((

是的,我尝试打印 所有 个字节 one-by-one,以手动搜索所需数据并了解正确的偏移量。令我失望的是,没有找到任何看起来像 IP 和端口的东西,这些数字非常神秘。

我知道有时最简单的解决方案是最好的,而不是最聪明的,但如果有人能给我一把钥匙,以正确的方式使用这个 WinAPI 函数,我将不胜感激。

你的魔法计算失败了。

portNumber := Buffer[i*20 + 8]; { Should work! }

因为Buffer是一个字节数组,上面只提取了一个字节。但是本地端口号在TCPtable中是一个DWORD。尽管您链接的文档指出:

The local port number in network byte order for the TCP connection on the local computer.

The maximum size of an IP port number is 16 bits, so only the lower 16 bits should be used. The upper 16 bits may contain uninitialized data.

所以我们需要两个字节。我们需要切换它们,注意上面的“网络字节顺序”。

您还忘记考虑 table 开头的 4 字节记录数。所以本地端口号应该变成:

          portNumber := Buffer[i*20 + 12] * 256 +
                        Buffer[i*20 + 13];