Comment vérifier si un exe est accessible à partir du serveur
-
21-09-2019 - |
Question
Ceci est une application client-serveur. Je crée un programme de mise à jour qui remplacera la liste des fichiers exe, exécuter des scripts, et tout ce qui doit être mis à jour. Ce sera installé sur le serveur.
D'abord, je dois vérifier si le fichier exécutable est ouvert via un partage réseau. Je peux le faire manuellement en allant dans Gestion de l'ordinateur, puis les fichiers partagés et les fichiers ouverts. Cela semble être le seul moyen de vérifier si le fichier est ouvert. J'ai essayé d'utiliser R / W pour vérifier si le fichier est ouvert, mais cela ne fonctionne pas. Mais regardé Win32_ServerConnection ce juste numéro indiqué des dossiers qui ont été ouverts pas les noms.
Je voudrais coder ceci en Delphi 7 ou C # si elle ne peut pas être fait à Delphes. J'ai trouvé quelques programmes qui peuvent voir les fichiers ouverts sur un serveur, mais rien sur la façon dont cela peut être fait.
La solution
J'utilise une fonction comme celui-ci pour vérifier si je peux modifier un fichier sur le système de fichiers. Fondamentalement, je tente de « créer » un nouveau fichier appelé fName, ouvrant encore l'existant (il devrait exister) et d'obtenir un descripteur de fichier valide pour elle. Si cela échoue, le fichier est utilisé. La fonction ne crée pas un fichier, ni ne modifie la filessytem existante (je ne fais jamais rien avec la poignée). Il suffit de vérifier si je peux obtenir un descripteur de fichier dans le fichier, dois-je veux faire quelque chose avec.
Cela fonctionne également pour les fichiers en cours d'ouverture à partir d'une part sur un ordinateur distant.
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;
Autres conseils
Pourquoi ne pas essayer tout simplement pas de le supprimer? Vous obtiendrez une erreur si le fichier est ouvert. Et si la suppression de cela fonctionne, vous pouvez simplement copier l'exécutable mis à jour.
Sous Windows 2000 et versions ultérieures, vous pouvez utiliser 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.
Il semble que le chemin passé dans le paramètre LocalPath
doit commencer par une double barre oblique, par exemple:.
test.exe C:\\Dev\Test\test.exe
produit la sortie suivante (si le fichier est ouvert par une action):
id: -469761405, permissions: $00000001, num_locks: 0, pathname: 'C:\\Dev\Test\test.exe', username: 'Ondrej'
Notez également que MSDN dit:
"Seuls les membres des administrateurs ou Opérateurs de serveur de groupe local peut exécuter avec succès le NetFileEnum fonction. "
Vous pouvez conserver une liste statique des « serveurs » que cela sera exécuté, vous pouvez rechercher le nom de la machine de processus, le nom d'hôte ou le nom de l'ordinateur pour un match. Si son dans la liste, vous pouvez supposer son ouverture locale.
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");
}
Avez-vous vu le FileSystemWatcher dans System.IO?
http://msdn.microsoft.com/en -nous / bibliothèque / system.io.filesystemwatcher.aspx