如何检查exe是否从服务器访问

发布于 2024-08-18 14:11:41 字数 319 浏览 8 评论 0原文

这是一个客户端服务器应用程序。我正在创建一个更新程序,它将替换 exe 文件列表、运行脚本以及其他需要更新的内容。这将安装在服务器上。

首先,我需要检查可执行文件是否通过网络共享打开。我可以通过进入计算机管理然后共享文件和打开文件来手动执行此操作。这似乎是检查文件是否打开的唯一方法。我尝试使用 R/W 检查文件是否已打开,但这不起作用。查看了 Win32_ServerConnection,但这只是列出了打开的文件数量,而不是名称。

如果不能在 Delphi 中完成,我想在 Delphi 7 或 C# 中编写此代码。我发现了一些可以查看服务器上打开的文件的程序,但没有介绍如何做到这一点。

This is a client server application. I'm creating a update program that will replace a list of exe files, run scripts, and anything else that needs to be updated. This will be installed on the server.

First I need to check if the executable file is opened via a network share. I can do this manually by going into Computer Management then Shared files and Open files. This seems to be the only way to check if the file is open. I tried using R/W to check if the file is opened but this did not work. Looked at Win32_ServerConnection but this just listed number of files that were open not the names.

I would like to code this in Delphi 7 or C# if it can't be done in Delphi. I have found a few programs that can view the open files on a server but nothing on how this can be done.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

不必了 2024-08-25 14:11:41

你为什么不尝试删除它呢?如果文件当前已打开,您将收到错误消息。如果删除它有效,您只需复制更新的可执行文件即可。

Why don't you just try to delete it? You will get an error if the file is currently open. And if deleting it works, you can just copy the updated executable.

清秋悲枫 2024-08-25 14:11:41

在 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
函数。”

On Windows 2000 and later, you could use 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.

It seems that the path passed in the LocalPath parameter has to begin with a double backslash, e.g.:

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

produces the following output (if the file is open through a share):

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

Also note that MSDN says:

"Only members of the Administrators or
Server Operators local group can
successfully execute the NetFileEnum
function."

清风夜微凉 2024-08-25 14:11:41

我使用这样的函数来检查是否可以更改文件系统上的文件。基本上我尝试“创建”一个名为 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;

I use a function like this to check whether I can alter a file on the filesystem. Basically I try to "create" a new file called fName, still opening the existing (should it exist) and get a valid file handle to it. If that fails, then the file is in use.
The function does NOT actually create a file, nor does it alter the existing filessytem (I never do anything with the handle). It simply check whether I can get a file Handle to the file, should I want to do something with it.

This also works for files being opened from a share on a remote computer.

 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;
回眸一笑 2024-08-25 14:11:41

您可以保留将运行的“服务器”的静态列表,您可以查找匹配的进程机器名称、主机名或计算机名称。如果它在列表中,您可以假设它在本地打开。

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");
}

You could keep a static list of "servers" that this will run on, you can lookup the process machine name, hostname, or computer name for a match. If its in the list you can assume its open local.

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");
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文