دلفي - إغلاق العملية التي تم إنشاؤها في الخدمة برشاقة.(باستخدام tprocess / createProcess)
-
06-07-2019 - |
سؤال
لدي خدمة Windows مكتوبة بلغة دلفي والتي تقوم بتشغيل عدد من البرامج.
عند إيقاف الخدمة، أريد أيضًا إغلاق هذه البرامج.عندما تمت كتابة الخدمة في الأصل، كان هذا يعمل بشكل جيد، ولكن أعتقد أنني قمت بتحديث مكون tProcess والآن - لم يتم إغلاق البرامج الثانوية.
في tProcess - هذا هو الكود الذي يبدأ العمليات الجديدة.
if CreateProcess( nil , PChar( FProcess.Command ) , nil , nil , False ,
NORMAL_PRIORITY_CLASS , nil , Directory ,
StartupInfo , ProcessInfo ) then
begin
if FProcess.Wait then
begin
WaitForSingleObject( ProcessInfo.hProcess , Infinite );
GetExitCodeProcess( ProcessInfo.hProcess , ExitCode );
if Assigned( FProcess.FOnFinished ) then
FProcess.FOnFinished( FProcess , ExitCode );
end;
CloseHandle( ProcessInfo.hProcess );
CloseHandle( ProcessInfo.hThread );
end;
كل من الملفات التنفيذية التي يتم استدعاؤها بواسطة هذا هي برامج Windows GUI (مع وجود زر إغلاق في الأعلى).
عندما أقوم بإيقاف الخدمة، أريد أيضًا إيقاف (وليس إيقاف) البرامج التي قمت بتشغيلها عبر إجراء createProcess.
كيف يمكنك أن تفعل هذا؟
المحلول
وترغب في تعداد النوافذ المفتوحة التي تطابق ProcessId بك أطلقت وأقول لهؤلاء النوافذ لإغلاقه. وإليك بعض التعليمات البرمجية لذلك:
uses Windows;
interface
function MyTerminateAppEnum(hHwnd:HWND; dwData:LPARAM):Boolean; stdcall;
implementation
function MyTerminateAppEnum(hHwnd:HWND; dwData:LPARAM):Boolean;
var
vID:DWORD;
begin
GetWindowThreadProcessID(hHwnd, @vID);
if vID = dwData then
begin
PostMessage(hHwnd, WM_CLOSE, 0, 0); //tell window to close gracefully
Result := False; //can stop enumerating
end
else
begin
Result := TRUE; //keep enumerating until you find your id
end;
end;
وبعد ذلك عليك أن ترغب في الاستفادة من هذا في التعليمات البرمجية عندما تريد اغلاق التطبيقات أطلق:
Procedure TerminateMe(YourSavedProcessInfo:TProcessInformation);
var
vExitCode:UINT;
begin
GetExitCodeProcess(YourSavedProcessInfo.hProcess, vExitCode);
if (vExitCode = STILL_ACTIVE) then //launched app still running..
begin
//tell it to close
EnumWindows(@MyTerminateAppEnum, YourSavedProcessInfo.dwProcessId);
if WaitForSingleObject(YourSavedProcessInfo.hProcess, TIMEOUT_VAL) <> WAIT_OBJECT_0 then
begin
if not TerminateProcess(YourSavedProcessInfo.hProcess, 0) then //didn't close, try to terminate
begin
//uh-oh Didn't close, didn't terminate..
end;
end;
end;
CloseHandle(YourSavedProcessInfo.hProcess);
CloseHandle(YourSavedProcessInfo.hThread);
end;
نصائح أخرى
سأستخدم TJvCreateProcess مكون من JVCL والذي يلتف حول أي وظيفة ذات صلة بعملية Win32 بطريقة رائعة.تأتي هذه الإجابة من قسم Dont-touch-winapi-إلا إذا كان مطلوبًا بالفعل :-)
والطريقة العامة الوحيدة لوقف عملية هي استخدام TerminateProcess أ >. ولكن هذا بقدر من رشيقة كما يمكنك الحصول عليها. لإغلاق بأمان عملية، تحتاج لنقول للعملية التي ترغب أن تتوقف، ومن ثم نأمل أن يطيع. لا توجد وسيلة للقيام بذلك بشكل عام، وإن كان.
لبرنامج واجهة المستخدم الرسومية، والطريقة المعتادة لأقول أن كنت تريد أن إيقاف تشغيل غير لإغلاق نافذة الرئيسي. ليس هناك فكرة رسمية من "النافذة الرئيسية،" على الرغم من. برنامج يمكن أن يكون صفر أو أكثر ويندوز، وليس هناك طريقة لمعرفة خارجيا واحد الذي كنت من المفترض أن يغلق من أجل جعل وقف برنامج عمل.
هل يمكن استخدام EnumWindows للدورة من خلال جميع النوافذ و حدد تلك التي تنتمي إلى العملية الخاصة بك. (وهي تريد ان تكون تلك التي GetWindowThreadProcessId يعطي نفس العملية ID أن CreateProcess أعطاك).
وإغلاق نافذة قد لا يكون كافيا. قد عرض البرنامج مربع حوار (دفع تأكيد، أو يسأل لحفظ التغييرات، وما إلى ذلك). سوف تحتاج إلى معرفة مقدما كيفية رفض أن مربع الحوار.
يمكن برامج غير واجهة المستخدم الرسومية لديهم مشاكل مماثلة. قد يكون كافيا لمحاكاة ضغطة مفتاح Ctrl + C. قد قبض والتعامل مع هذا ضغطة بشكل مختلف، وإن كان. قد يكون لديك نظام القائمة التي تتوقع لك اكتب "Q" لإنهاء البرنامج.
وباختصار، لا يمكنك إغلاق برشاقة برنامج إلا إذا كنت تعرف مسبقا كيف يتوقع هذا البرنامج أن تكون مغلقة.