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.

Était-ce utile?

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");
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top