Как проверить, доступен ли exe-файл с сервера - PullRequest
3 голосов
/ 19 января 2010

Это клиент-серверное приложение. Я создаю программу обновления, которая заменит список исполняемых файлов, запускает сценарии и все остальное, что необходимо обновить. Это будет установлено на сервере.

Сначала мне нужно проверить, открывается ли исполняемый файл через сетевой ресурс. Я могу сделать это вручную, зайдя в «Управление компьютером», затем «Общие файлы» и «Открыть файлы». Кажется, это единственный способ проверить, открыт ли файл. Я попытался использовать R / W, чтобы проверить, открыт ли файл, но это не сработало. Посмотрел Win32_ServerConnection, но это только что перечисленное количество файлов, которые были открыты, а не имена.

Я хотел бы закодировать это в Delphi 7 или C #, если это не может быть сделано в Delphi. Я нашел несколько программ, которые могут просматривать открытые файлы на сервере, но ничего не говорится о том, как это можно сделать.

Ответы [ 5 ]

2 голосов
/ 20 января 2010

В Windows 2000 и более поздних версиях вы можете использовать NetFileEnum API:

program test;

{$APPTYPE CONSOLE}

uses
  Windows,
  Classes,
  SysUtils;

type
  PFileInfo3 = ^TFileInfo3;
  TFileInfo3 = record
    fi3_id: DWORD;
    fi3_permissions: DWORD;
    fi3_num_locks: DWORD;
    fi3_pathname: PWideChar;
    fi3_username: PWideChar;
  end;

  TNetFileEnumCallback = function(const FileInfo: TFileInfo3; Data: Pointer): Boolean;

const
  netapi = 'netapi32.dll';

function NetApiBufferFree(Buffer: Pointer): DWORD; stdcall; external netapi;
function NetFileEnum(servername: PWideChar; basepath: PWideChar; username: PWideChar; level: DWORD; var bufptr: Pointer;
  prefmaxlen: DWORD; var entriesread: DWORD; var totalentries: DWORD; resume_handle: PDWORD): DWORD; stdcall;
  external netapi;

procedure EnumNetFileUsers(const LocalPath: WideString; Callback: TNetFileEnumCallback; Data: Pointer = nil);
const
  EntryCount = 32;
var
  NetResult, EntriesRead, TotalEntries, ResumeHandle: Cardinal;
  Buf: Pointer;
  P: PFileInfo3;
  I: Integer;
begin
  EntriesRead := 0;               
  TotalEntries := 0;
  ResumeHandle := 0;
  repeat
    NetResult := NetFileEnum(nil, PWideChar(LocalPath), nil, 3, Buf, EntryCount * SizeOf(TFileInfo3), EntriesRead,
      TotalEntries, @ResumeHandle);
    if not (NetResult in [ERROR_SUCCESS, ERROR_MORE_DATA]) then
      RaiseLastOSError(NetResult);
    try
      P := Buf;
      for I := 0 to EntriesRead - 1 do
      begin
        if Callback(P^, Data) then
          Break;

        Inc(P);
      end;
    finally
      NetApiBufferFree(Buf);
    end;
  until NetResult = ERROR_SUCCESS;
end;

function ShowFileInfo(const FileInfo: TFileInfo3; Data: Pointer): Boolean;
begin
  Result := False;
  Writeln(Format('id: %d, permissions: $%.8x, num_locks: %d, pathname: ''%s'', username: ''%s''',
    [FileInfo.fi3_id, FileInfo.fi3_permissions, FileInfo.fi3_num_locks, FileInfo.fi3_pathname, FileInfo.fi3_username]));
end;

begin
  try
    if ParamCount = 1 then
      EnumNetFileUsers(ParamStr(1), ShowFileInfo);
  except
    on E: Exception do
    begin
      Writeln(Format('[%s] %s', [E.ClassName, E.Message]));
      ExitCode := 1;
    end;
  end;
end.

Кажется, что путь, переданный в параметре LocalPath, должен начинаться с двойной обратной косой черты,Например:

test.exe C:\\Dev\Test\test.exe

производит следующий вывод (если файл открыт через общий ресурс):

id: -469761405, permissions: $00000001, num_locks: 0, pathname: 'C:\\Dev\Test\test.exe', username: 'Ondrej'

Также обратите внимание, что MSDN говорит:

«Только члены локальной группы« Администраторы »или« Операторы сервера »могут успешно выполнять функцию NetFileEnum.»

2 голосов
/ 19 января 2010

Почему бы вам просто не попробовать удалить его? Вы получите ошибку, если файл в данный момент открыт. И если удаление работает, вы можете просто скопировать обновленный исполняемый файл.

1 голос
/ 20 января 2010

Я использую такую ​​функцию, чтобы проверить, могу ли я изменить файл в файловой системе. В основном я пытаюсь «создать» новый файл с именем fName, по-прежнему открывая существующий (если он существует) и получая к нему действительный дескриптор файла. Если это не удается, значит, файл используется. Функция на самом деле НЕ создает файл и не изменяет существующую файловую систему (я никогда ничего не делаю с дескриптором). Он просто проверяет, могу ли я получить дескриптор файла для файла, если я хочу что-то с ним сделать.

Это также работает для файлов, открываемых из общего ресурса на удаленном компьютере.

 function IsFileInUse(fName: string): boolean;
  var
    HFileRes: HFILE;
  begin
    Result := false;
    if not FileExists(fName) then
      exit;
    HFileRes := CreateFile(pchar(fName),
      GENERIC_READ or GENERIC_WRITE,
      0, nil, OPEN_EXISTING,
      FILE_ATTRIBUTE_NORMAL,
      0);
    Result := (HFileRes = INVALID_HANDLE_VALUE);
    if not Result then
      CloseHandle(HFileRes);
  end;
1 голос
/ 19 января 2010

Вы можете хранить статический список «серверов», на которых он будет работать, вы можете найти имя компьютера процесса, имя хоста или имя компьютера для совпадения. Если его в списке, вы можете считать его открытым локальным.

string name = Environment.MachineName;
string name = System.Net.Dns.GetHostName();
string name = System.Windows.Forms.SystemInformation.ComputerName;

Process[] myProcesses = Process.GetProcessesByName("myExeProcName",MachineName);
foreach(Process myProcess in myProcesses)
{
    Console.Write("MachineName : " + myProcess.MachineName + "\n");
}
0 голосов
/ 19 января 2010

Вы видели FileSystemWatcher в System.IO?

http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.aspx

...