Winapi 检查本地端口是否不受Inno安装程序的限制,而不使用netstat

Winapi 检查本地端口是否不受Inno安装程序的限制,而不使用netstat,winapi,inno-setup,pascalscript,Winapi,Inno Setup,Pascalscript,我的问题以前在这里被问过,但我正在尝试为我的项目实现一个更整洁的解决方案。因此,正如标题所述,我正在创建一个复杂的服务器应用程序安装程序,它必须检查本地IP地址并选择一个开放端口,以便正确配置应用程序。使用Inno设置5.6.1 获取本地IP地址不是问题,对我帮助很大。然后是端口检查,这里我找到了以下三个选项: 使用安装程序中的外部DLL。实际上,以前的解决方案包括一个C++ DLL,它导出了两个精确的便利函数,它们工作得很好,安装程序使用了它们,但是有时,很少在一些Windows版本上,DL

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

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

  • 使用安装程序中的外部DLL。实际上,以前的解决方案包括一个C++ DLL,它导出了两个精确的便利函数,它们工作得很好,安装程序使用了它们,但是有时,很少在一些Windows版本上,DLL不想被加载导致错误。这就是为什么在这里更多地使用Pascal脚本的原因
  • 通过cmd启动netstat并获取输出。这仍然是一个选择,尽管我觉得这个解决方案非常粗糙,并且希望避免它。详情请参阅
  • 从WinAPI调用获取信息。如果可能的话,看起来最好
正如上面提到的,获取IP地址可以通过简单的WinAPI调用实现(好的,不是真的,这是一个Pascal脚本)。因此,我尝试对端口执行相同的操作,尝试调用:

[代码]
常数
错误\u缓冲区不足\u=122;
函数GetTcpTable(pTcpTable:字节数组;var pdwSize:基数;
边界:WordBool):德沃德;
外部的GetTcpTable@IpHlpApi.dllstdcall';
{ ------------------------ }
函数CheckPortIsOpen(端口:整数):布尔值;
变量
表大小:基数;
缓冲区:字节数组;{唉,这里没有指针}
记录计数:整数;
i、 j:整数;
端口号:基数;
IpAddr:字符串;
开始
结果:=真;
表大小:=0;
如果GetTcpTable(Buffer,TableSize,False)=错误\u缓冲区不足\u则
开始
SetLength(缓冲区、表大小);
如果GetTcpTable(Buffer,TableSize,True)=0,则
开始
{来自GetIPAddressTable调用示例的一些神奇计算}
记录计数:=(缓冲区[1]*256)+缓冲区[0];
对于i:=0到RecordCount-1 do
开始
端口号:=缓冲区[i*20+8];{应该有用!}
{此处调试代码}
如果(i<5),则开始
IpAddr:='';
对于J:=0到3 do
开始
如果J>0,则
IpAddr:=IpAddr+'';
IpAddr:=IpAddr+IntToStr(缓冲区[I*20+4+J]);
结束;
SuppressibleMsgBox(IpAddr、mbError、MB_OK、MB_OK);
结束;
{ ------ }
如果端口=端口号,则
结果:=假;
结束;
结束;
结束;
结束;
GetTcpTable
还返回有关地址和端口的信息(确切地说是TCP连接表),因此尝试获取任何连接地址对于调试都是有益的。有关此尝试的详细信息:

  • RecordCount
    的计算方法与我作为示例使用的代码中的方法相同,因为它非常类似于
  • i*20+8
    就是这样写的,因为20=sizeof()和
    8=2*sizeof(DWORD)
    。如您所见,本地TCP连接地址正以1 DWORD的偏移量逐个字节进行“解析”
所以,一切都很有趣。。。它就是不起作用=((

是的,我试着一个接一个地打印所有的字节,手动搜索所需的数据并理解正确的偏移量。令我失望的是,没有找到任何看起来像IP和端口的数据,数字相当神秘


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

您的神奇计算已经完成

portNumber:=Buffer[i*20+8];{应该可以工作!}
由于
Buffer
是一个字节数组,因此上面只提取一个字节。但是本地端口号是TCP表中的
DWORD
。尽管您链接的文档说明:

本地计算机上TCP连接的本地端口号(按网络字节顺序)

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

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

您还忘了在表的开头说明4字节的记录计数。因此本地端口号应为:

portNumber:=缓冲区[i*20+12]*256+
缓冲器[i*20+13];

代码是否运行?在pascal中,局部变量未初始化,第一次调用可能没有tablesize 0,因此函数可能会失败,并出现完全不同的错误。确实如此。
tablesize
是通过
var
传递的,因此第一次调用实际上会将其设置为正确的值,这是一种常见的winapi技术n所需的缓冲区大小。在问题中提到的答案中,其他函数调用也采用了相同的技巧。而“调试消息”也起了作用,这就是我如何知道数据混乱的原因。谢谢,我熟悉winapi,这是一个输入/输出参数。如果它同时具有足够大的值,函数将不会失败缓冲区不足,但会尝试写入一些无效内存。您需要初始化它,尽管我知道这不是唯一的问题。正如@SertacAkyuz所说,第一个调用应该使用初始化变量。您常用的WinAPI技术实际上很常见,但告诉API调用您想要缓冲区大小的方式是s NULL(在C中,
0
)到第一次调用中的函数