¿Cómo comprobar si se accede a un exe desde el servidor
-
21-09-2019 - |
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.
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");
}
¿Usted ha visto el FileSystemWatcher en System.IO?
http://msdn.microsoft.com/en -us / biblioteca / system.io.filesystemwatcher.aspx