При работе с сетевыми дисками в Windows разработчики часто сталкиваются с проблемой: стандартные методы проверки доступности (WNetGetConnection, GetDiskFreeSpaceEx, GetVolumeInformation) могут блокировать выполнение программы на длительное время (до минуты), если сервер недоступен. Это связано с внутренним таймаутом Windows при ожидании ответа от сетевого ресурса.
Пример кода, вызывающего блокировку:
function IsDriveAvailable(const Drive: string): Boolean;
begin
Result := DirectoryExists(Drive);
end;
Если диск недоступен, вызов DirectoryExists "зависнет" до истечения системного таймаута.
Решение 1: Использование отдельного потока
Наиболее правильным решением является вынос проверки в отдельный поток. Это предотвратит блокировку основного потока приложения.
Пример с использованием TTask (Delphi XE7+):
function NetworkPathAvailableWithTimeOut(const NetworkPath: string; TimeOut: Cardinal): Boolean;
var
PathAvailable: Boolean;
EndTime: UInt64;
TaskDone: Boolean;
begin
PathAvailable := False;
TaskDone := False;
EndTime := GetTickCount64 + TimeOut;
TTask.Run(
procedure
begin
PathAvailable := DirectoryExists(NetworkPath);
TaskDone := True;
end
);
while not TaskDone do
begin
if GetTickCount64 >= EndTime then
Exit(False); // Таймаут истёк
Sleep(50); // Уменьшаем нагрузку на CPU
end;
Result := PathAvailable;
end;
Преимущества:
- Главный поток не блокируется.
- Можно задать собственный таймаут.
Недостатки:
- Усложнение кода из-за работы с потоками.
- Необходимость обработки возможных утечек памяти (если поток не завершится вовремя).
Решение 2: Асинхронный вызов через WinAPI
Альтернативный подход — использование асинхронных функций WinAPI, таких как WNetGetConnection с callback.
Пример:
function CheckNetworkDriveAsync(const Drive: string; Callback: TProc<Boolean>): Boolean;
var
Thread: TThread;
begin
Thread := TThread.CreateAnonymousThread(
procedure
var
Available: Boolean;
begin
Available := DirectoryExists(Drive);
TThread.Queue(nil,
procedure
begin
if Assigned(Callback) then
Callback(Available);
end);
end);
Thread.FreeOnTerminate := True;
Thread.Start;
end;
Использование:
CheckNetworkDriveAsync('Z:\',
procedure(Available: Boolean)
begin
if Available then
ShowMessage('Диск доступен!')
else
ShowMessage('Диск недоступен!');
end);
Решение 3: Быстрая проверка через ICMP (Ping)
Если важно лишь определить, доступен ли сервер (но не конкретный диск), можно использовать ping:
function PingHost(const Host: string): Boolean;
var
PingCommand: string;
ExitCode: Cardinal;
begin
PingCommand := Format('ping -n 1 -w 1000 %s', [Host]);
ExitCode := ExecuteProcess(PingCommand, True);
Result := (ExitCode = 0);
end;
Недостатки:
- Сервер может быть доступен, но диск не подключен.
- Некоторые серверы блокируют ICMP-запросы.
Заключение
Лучшим решением для проверки доступности сетевых дисков без блокировки программы является использование отдельного потока (например, через TTask или TThread).
Если требуется минимальная задержка, можно комбинировать методы:
1. Сначала проверить сервер через ping.
2. Затем асинхронно проверить доступность диска.
Пример комбинированного подхода:
procedure CheckDriveWithPingAndAsync(const Drive, Server: string; Callback: TProc<Boolean>);
begin
if not PingHost(Server) then
begin
Callback(False);
Exit;
end;
CheckNetworkDriveAsync(Drive, Callback);
end;
Таким образом, приложение останется отзывчивым, а пользователь получит быстрый ответ о статусе сетевого ресурса.
Контекст описывает проблему блокировки основного потока приложения при проверке доступности сетевых дисков в Windows и предлагает несколько решений, включая использование потоков, асинхронных вызовов WinAPI и ICMP-запросов (ping).
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.