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

时间:2010-01-19 19:30:16

标签: c# delphi windows-server

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

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

如果在Delphi中无法完成,我想在Delphi 7或C#中编写代码。我找到了一些程序可以查看服务器上的打开文件,但没有关于如何做到这一点。

5 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

在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说:

  

“仅限管理员或   Server Operators本地组可以   成功执行NetFileEnum   功能“。

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

我使用这样的函数来检查我是否可以更改文件系统上的文件。基本上我尝试“创建”一个名为fName的新文件,仍然打开现有的(如果存在)并获得一个有效的文件句柄。如果失败,则该文件正在使用中。 该函数实际上并不创建文件,也不会改变现有的filessytem(我从不对句柄做任何事情)。它只是检查我是否可以获取文件Handle to the file,如果我想用它做什么。

这也适用于从远程计算机上的共享打开的文件。

 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;

答案 4 :(得分:-1)

您是否在System.IO中看到了FileSystemWatcher?

http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.aspx