Мой вопрос задавался здесь ранее, но я пытаюсь реализовать более точное решение для моего проекта.Итак, как гласит заголовок, я создаю сложный установщик серверного приложения, который должен проверить локальный IP-адрес и выбрать открытый порт, чтобы приложение могло быть правильно настроено.Используется Inno Setup 5.6.1.
Получение локальных IP-адресов не было проблемой, это решение мне очень помогло.Затем дело дошло до проверки порта, и здесь я нашел следующие три варианта:
- Использование внешней DLL из установщика .На самом деле, предыдущее решение состояло из C ++ DLL, которая экспортировала две точные вспомогательные функции, они отлично работали, установщик использовал их, но иногда, редко на некоторых версиях Windows, эта DLL нехочу загрузить, вызывая ошибку.Вот почему все больше возиться с Pascal Script здесь.
- Запуск netstat через cmd и получение вывода .Это все еще вариант, хотя я чувствую, что это решение похоже на ад, и хотел бы избежать его.Подробности можно найти в другом ответе SO .
- Получение информации от вызова WinAPI .Выглядит лучше всего, если это возможно.
Как уже упоминалось выше, получение IP-адреса может быть реализовано с помощью простых (ну, не совсем, это Pascal Script) вызовов 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
также возвращает информацию об адресах и портах (таблица соединений TCPчтобы быть точным), поэтому попытка получить любой адрес подключения хороша для целей отладки.Подробнее об этой попытке:
RecordCount
рассчитывается так же, как в коде, который я использовал в качестве примера, потому что полученная структура там очень похожа на противная структура мне нужна . - что
i*20 + 8
написано именно так, потому что 20 = sizeof ( одна запись struct ) и 8 = 2 * sizeof(DWORD)
.Как вы можете видеть, адрес локального TCP-соединения «анализируется» один за другим со смещением в 1 DWORD.
Итак, все очень весело ... это просто не такработает = ((
И да, я пытался напечатать все байтов один за другим, чтобы вручную найти нужные данные и понять правильное смещение. К моему разочарованиюничего похожего на IP и порты не было найдено, цифры были довольно загадочными.
Я знаю, что иногда самое простое решение лучше, а не самое умное, но если бы кто-нибудь мог дать мне ключ, готовя эту функцию WinAPI вправильно, я был бы глубоко признателен.