كيفية التحقق مما إذا تم الوصول إلى EXE من الخادم
-
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