检查本地端口是否可以从Inno Setup中释放,而无需使用netstat

时间:2019-04-23 19:20:34

标签: winapi inno-setup pascalscript

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

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

  • 使用安装程序中的外部DLL 。实际上,先前的解决方案由一个C ++ DLL组成,该DLL导出了两个确切的便捷功能,它们工作得很好,安装程序使用了它们,但是有时,很少某些 Windows版本上,该DLL却没有不想被加载导致错误。这就是为什么在这里更加混乱Pascal Script的原因。
  • 通过cmd启动netstat并获取输出。这仍然是一个选择,尽管我认为此解决方案像地狱般令人生畏,并且希望避免使用它。详细信息可以在other SO answer中找到。
  • 从WinAPI调用中获取信息。尽可能看起来最好。

如上所述,获取IP地址可以通过简单的WinAPI调用(好吧,不是真的,这是一个Pascal脚本)来实现。因此,我尝试使用端口进行相同的技巧,尝试调用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还返回有关地址和端口(准确地说是TCP连接表)的信息,因此,尝试获取任何连接地址都有助于调试。有关此尝试的更多信息:

所以,一切都非常有趣...它根本不起作用=((

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

我知道有时候最简单的解决方案是最好的,而不是最聪明的解决方案,但是如果有人可以正确地使用此WinAPI函数,我将不胜感激。

1 个答案:

答案 0 :(得分:2)

您的魔术计算已关闭。

pg_hba.conf

由于portNumber := Buffer[i*20 + 8]; { Should work! } 是一个字节数组,因此上面仅提取一个字节。但是本地端口号在TCP表中是Buffer。尽管您链接的文档指出:

  

本地网络上TCP连接的本地端口号,以网络字节顺序显示。

     

IP端口号的最大大小为16位,因此仅应使用低16位。高16位可能包含未初始化的数据。

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

您还忘记在表的开头考虑4字节记录数。因此,本地端口号应变为:

DWORD