Pregunta

Esta es una aplicación cliente-servidor. Estoy creando un programa de actualización que reemplazará a una lista de archivos exe, ejecutar scripts, y cualquier otra cosa que necesita ser actualizado. Este será instalado en el servidor.

En primer lugar tengo que comprobar si se abre el archivo ejecutable a través de un recurso compartido de red. Puedo hacer esto manualmente por entrar en Administración de equipos archivos compartidos a continuación y abrir archivos. Esta parece ser la única manera de comprobar si el archivo está abierto. He intentado utilizar R / W para comprobar si se abre el archivo, pero esto no funcionó. Mirado Win32_ServerConnection pero esto solo número que aparece de archivos que estaban abiertos, no los nombres.

Me gustaría codificar esto en Delphi 7 o C #, si no se puede hacer en Delphi. He encontrado un par de programas que se pueden ver los archivos abiertos en un servidor pero nada sobre cómo se puede hacer esto.

¿Fue útil?

Solución

Yo uso una función como esta para comprobar si puedo modificar un archivo en el sistema de archivos. Básicamente trato de "crear" un nuevo archivo llamado FName, siendo la apertura de la existente (en caso de que exista) y obtener un identificador de archivo válido a ella. Si eso no funciona, entonces el archivo está en uso. La función no crea realmente un archivo, ni altera el filessytem existente (nunca hago nada con el mango). Simplemente compruebe si puedo conseguir un identificador de archivo para el archivo, debería querer hacer algo con él.

Esto también funciona para los archivos que se abren desde un recurso compartido en un equipo remoto.

 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;

Otros consejos

¿Por qué no se intenta eliminarla? Obtendrá un error si el archivo está abierto. Y si la supresión funciona, sólo se puede copiar el archivo ejecutable actualizado.

En Windows 2000 y versiones posteriores, se puede usar 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.

Parece que el camino pasa en el parámetro LocalPath tiene que comenzar con una doble barra inclinada, por ejemplo:.

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

produce el siguiente resultado (si el archivo está abierto a través de una acción):

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

Tenga en cuenta también que MSDN dice:

  

"Sólo los miembros de los Administradores o   Operadores de servidores de grupo puede locales   ejecutar con éxito el NetFileEnum   función ".

Se puede mantener una lista estática de "servidores" que este se ejecutará en, puede buscar el nombre de proceso de la máquina, nombre de host o el nombre de equipo para un partido. Si su en la lista se puede asumir su local abierto.

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");
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top