كيفية التحقق مما إذا تم الوصول إلى EXE من الخادم

StackOverflow https://stackoverflow.com/questions/2096425

  •  21-09-2019
  •  | 
  •  

سؤال

هذا هو تطبيق خادم العميل. أقوم بإنشاء برنامج تحديث يحل محل قائمة ملفات EXE ، وتشغيل البرامج النصية ، وأي شيء آخر يحتاج إلى تحديث. سيتم تثبيت هذا على الخادم.

أولاً ، أحتاج إلى التحقق مما إذا تم فتح الملف القابل للتنفيذ عبر مشاركة الشبكة. يمكنني القيام بذلك يدويًا عن طريق الانتقال إلى إدارة الكمبيوتر ثم مشاركة الملفات وفتح الملفات. يبدو أن هذه هي الطريقة الوحيدة للتحقق مما إذا كان الملف مفتوحًا. حاولت استخدام R/W للتحقق مما إذا كان الملف مفتوحًا ولكن هذا لم ينجح. نظرت إلى Win32_ServerConnection ، لكن هذا العدد المدرج فقط من الملفات التي لم تكن مفتوحة وليس الأسماء.

أرغب في ترميز هذا في Delphi 7 أو C# إذا كان لا يمكن القيام به في Delphi. لقد وجدت بعض البرامج التي يمكنها عرض الملفات المفتوحة على الخادم ولكن لا شيء حول كيفية القيام بذلك.

هل كانت مفيدة؟

المحلول

أستخدم وظيفة كهذه للتحقق مما إذا كان يمكنني تغيير ملف على نظام الملفات. في الأساس ، أحاول "إنشاء" ملفًا جديدًا يسمى FNAME ، لا يزال يفتح الموجود (إذا كان موجودًا) والحصول على مقبض ملف صالح له. إذا فشل ذلك ، فإن الملف قيد الاستخدام. لا تنشئ الوظيفة ملفًا بالفعل ، ولا يغير filessytem الحالي (لا أفعل أي شيء مع المقبض). إنه ببساطة تحقق مما إذا كان بإمكاني الحصول على مقبض ملف للملف ، إذا أردت أن أفعل شيئًا معه.

يعمل هذا أيضًا للملفات التي يتم فتحها من مشاركة على جهاز كمبيوتر بعيد.

 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;

نصائح أخرى

لماذا لا تحاول فقط حذفه؟ ستحصل على خطأ إذا كان الملف مفتوحًا حاليًا. وإذا كان حذفه يعمل ، فيمكنك فقط نسخ القابل للتنفيذ المحدث.

على 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 بنجاح."

يمكنك الاحتفاظ بقائمة ثابتة من "الخوادم" التي سيتم تشغيلها ، يمكنك البحث عن اسم جهاز العملية أو اسم المضيف أو اسم الكمبيوتر لمباراة. إذا كانت في القائمة ، يمكنك افتراض محليها المفتوح.

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

هل رأيت ملفات fileystemwatcher في System.io؟

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top