From 84f710476fb3f284a21524188ea81bcd47f1cd86 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Fri, 14 Aug 2026 18:32:43 +0300 Subject: [PATCH] =?UTF-8?q?fix(dxcluster):=20=D1=81=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BF=D0=BE=D0=B4=20win64=20=E2=80=94=20Windows?= =?UTF-8?q?.pas=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BA=D1=80=D1=8B=D0=B2=D0=B0?= =?UTF-8?q?=D0=BB=20TCriticalSection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Сборщик под win64 падал в конструкторе клиента кластера: «identifier idents no member Create». Windows.pas объявляет TCriticalSection как ЗАПИСЬ (алиас TRTLCriticalSection), а в uses он стоял ПОСЛЕ SyncObjs — и поле FLock, и TCriticalSection.Create разрешались в запись. На Linux эта ветка uses не компилируется вовсе, поэтому баг жил с первого коммита DX-кластера (a2fdc3a) и всплыл на первой же сборке под Windows. Windows.pas убран из uses совсем: сокетам он не нужен, всё даёт WinSock2 — так же сделано в WsClient (там тоже FLock: TCriticalSection) и HPSDRNetwork. Причина подтверждена минимальным репро, дающим дословно тот же текст ошибки. Сверено по исходнику winsock2.pp (FPC 3.2.2), чтобы следующая итерация сборщика не встала на следующем имени: connect/socket/select/getsockopt/ setsockopt/FD_SET/FD_ZERO/WSAStartup/WSACleanup/inet_addr/gethostbyname/htons, типы TWSAData/TSockAddrIn/TFDSet/TTimeVal/PHostEnt и константы INADDR_NONE/ SOL_SOCKET/SO_ERROR/SO_KEEPALIVE/WSAE* — все на месте. Указательная форма connect(@Addr, …) тоже корректна: в winsock2 есть обе перегрузки. Заодно FNV-хэш подписи набора спотов обёрнут в {$Q-}{$R-}: он живёт переполнением, а проверки правятся в .lpi (в Release их сейчас нет). Порядок «Windows после SyncObjs» проверен по всему проекту — больше нигде. Сборка ewsdr (--ws=qt6) и ewsdrd — ОК, тест бэндплана зелёный. Win64 проверит сборщик. Co-Authored-By: Claude Opus 5 --- DXClusterClient.pas | 7 ++++++- DXSpotOverlay.pas | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/DXClusterClient.pas b/DXClusterClient.pas index a2d6fcc..ce5be8b 100644 --- a/DXClusterClient.pas +++ b/DXClusterClient.pas @@ -30,8 +30,13 @@ uses Classes, SysUtils, SyncObjs, StrUtils, DateUtils, WebUtils, // SockClose/SockShutdown/SockRecv/SockSend/SOCK_INVALID DXSpotStore + // ★ Windows.pas здесь НЕТ намеренно: он объявляет TCriticalSection как + // ЗАПИСЬ (алиас TRTLCriticalSection) и, стоя в uses после SyncObjs, + // перекрывал класс — под win64 сборка падала на TCriticalSection.Create + // («identifier idents no member Create»). Всё, что нужно сокетам, даёт + // WinSock2; так же сделано в WsClient и HPSDRNetwork. {$IFDEF MSWINDOWS} - , Windows, WinSock2 + , WinSock2 {$ELSE} , BaseUnix, Sockets, netdb {$ENDIF}; diff --git a/DXSpotOverlay.pas b/DXSpotOverlay.pas index 97f0b22..c64b3cf 100644 --- a/DXSpotOverlay.pas +++ b/DXSpotOverlay.pas @@ -339,16 +339,20 @@ begin HiHz := FCenterFreq + FSpanHz / 2; FArrN := FStore.SnapshotRange(LoHz, HiHz, FModes, FMaxAgeMin, FArr); + // Хэш живёт переполнением — проверки снимаем локально, чтобы сборка с + // {$Q+}/{$R+} (у нас их нет, но режимы правятся в .lpi) не падала на нём. + {$PUSH}{$Q-}{$R-} H := (FNV_BASIS_HI shl 32) or FNV_BASIS_LO; // FNV-1a 64 for i := 0 to FArrN - 1 do begin for k := 1 to Length(FArr[i].Call) do H := (H xor QWord(Ord(FArr[i].Call[k]))) * FNV_PRIME; H := (H xor QWord(Round(FArr[i].FreqHz))) * FNV_PRIME; - H := (H xor QWord(Ord(FArr[i].Mode))) * FNV_PRIME; H := (H xor QWord(Round(FArr[i].Stamp * 86400))) * FNV_PRIME; + H := (H xor QWord(Ord(FArr[i].Mode))) * FNV_PRIME; end; FArrStamp := Int64(H); + {$POP} end; procedure TDXSpotOverlay.Layout(C: TCanvas; W: Integer);