Process Creation Functions Part 2
مقدمة
السلام عليكم ورحمة الله وبركاته
المقالة هذه استكمال للسلسلة السابقة
في هذا الجزء سنُلقي نظرة تفصيلية على الكود الخاص بدالة CreateProcess ، كيفية نداءها ، وماهي المتغيرات التي نحتاج لتعريفها ومن ثم تمريرها للدالة
كما ذكرنا في المقالة السابقة، سنقوم باستخدام دالة CreateProcess لانشاء عملية Notepad.exe
وهذا هو الكود الذي سنقوم بمناقشته
1 // CreateProcess.cpp : This file contains the 'main' function. Program execution begins and ends there.
2 //
3
4 #include <iostream>
5 #include <windows.h>
6 #include <stdio.h>
7 int main()
8 {
9 // Declare variables
10 STARTUPINFO si;
11 PROCESS_INFORMATION pi;
12 BOOL result;
13 DWORD exitCode;
14
15 // Initialize variables
16 ZeroMemory(&si, sizeof(si));
17 si.cb = sizeof(si);
18 ZeroMemory(&pi, sizeof(pi));
19
20 // Create a process using the command line argument
21 result = CreateProcess(
22 L"C:\\Windows\\System32\\notepad.exe", // Module name
23 NULL, // Command line
24 NULL, // Process handle not inheritable
25 NULL, // Thread handle not inheritable
26 FALSE, // Set handle inheritance to FALSE
27 0, // No creation flags
28 NULL, // Use parent's environment block
29 NULL, // Use parent's starting directory
30 &si, // Pointer to STARTUPINFO structure
31 &pi); // Pointer to PROCESS_INFORMATION structure
32
33 if (!result)
34 {
35 printf("CreateProcess failed (%d).\n", GetLastError());
36 return -1;
37 }
38
39 // Wait until child process exits
40 WaitForSingleObject(pi.hProcess, INFINITE);
41
42 // Get the exit code of the child process
43 GetExitCodeProcess(pi.hProcess, &exitCode);
44 printf("Child process exited with code %d.\n", exitCode);
45
46 // Close process and thread handles
47 CloseHandle(pi.hProcess);
48 CloseHandle(pi.hThread);
49
50 return 0;
51 }
قبل الخوض في تفاصيل الكود، من الجيد أن نعرف الـ Signature / Prototype الخاص بالدالة حتى يسهل علينا تتبّع الكود
CreateProcess Prototype
بحسب موقع مايكروسوفت فهذا الـ Syntax الخاص بالدالة
BOOL CreateProcessA(
[in, optional] LPCSTR lpApplicationName,
[in, out, optional] LPSTR lpCommandLine,
[in, optional] LPSECURITY_ATTRIBUTES lpProcessAttributes,
[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] BOOL bInheritHandles,
[in] DWORD dwCreationFlags,
[in, optional] LPVOID lpEnvironment,
[in, optional] LPCSTR lpCurrentDirectory,
[in] LPSTARTUPINFOA lpStartupInfo,
[out] LPPROCESS_INFORMATION lpProcessInformation
);
لنبدأ التفصيل في هذا الـSyntax :
- نلاحظ أن الدالة تُرجع قيمة من نوع
BOOL، ستكون القيمةTRUEفي حال تم تنفيذ الدالة بشكل سليم ، وFALSEفي حال فشلت الدالة في بدء العملية - بالنسبة للـ parameters الخاصة بالدالة نلاحظ وجود بعض العبارات مثل
inوoutوoptional- تستخدم هذه العبارات بين المطورين كوسيلة لشرح الدالة وماتفعله بالـ parameters
in: اختصار لـinputوالمقصود بها أن الـ parameter هذا سيتم استخدامه داخل الدالةout: اختصار لـoutputوالمقصود منه أن الدالة ستستقبل هذا المتغيّر وستقوم بارجاعه او التعديل على قيمته في حالة الـ pointersoptional: كما ترمز الكلمة، تمرير هذا الـ parameter للدالة ليس ضروري
- ننتقل الآن للـ parameters
lpApplicationName: يشير الى البرنامج الذي سيتم تنفيذهlpCommandLine: بدل من تمرير اسم البرنامج في الـ parameter السابق، بامكاننا تمريرcommandsيتم تنفيذها في العملية، على سبيل المثال لو أردنا فتح ملفtest.txtعبر الـNotepad.exeنمرر القيمةnotepad.exe test.txtلهذا الـ parameterlpProcessAttributes: عبارة عن pointer يشير لـ structure يسمىSECURITY_ATTRIBUTES، للمزيد اقرأ عن هذا الـ structurelpThreadAttributes: يمثل pointer لنفس الـ structure السابقbInheritHandles: يمثل قيمةBooleanوتعبر عن هل بالامكان وراثة الـhandlesالخاصة بالـcalling processdwCreationFlags: يستخدم هذا الـ parameter للتحكم في مرحلة انشاء العملية، بالامكان الاطلاع على جميع الـ flags من هناlpEnvironment: عبارة عن pointer للـenvironment variablesالخاصة بالعمليةlpCurrentDirectory: يمثل المسار الكامل الخاص بالعمليةlpStartupInfo: عبارة عن pointer يشير لـ structure يسمىSTARTUPINFO، يمثل هذا الـ structure الاعدادات الخاصة بالعملية عند بدءها مثل حجم وشكل الـ window , العنوان وخلافه ، بالامكان القراءة عن هذا الـ structure هناlpProcessInformation: عبارة عن pointer يشير الى structure يسمىPROCESS_INFORMATIONهذا الـ structure يحمل العديد من المعلومات عن العملية التي تم انشاءها مثل : الـ handle الخاص بالعملية ، الـ thread الأساسي في العملية وغيره ، بالامكان القراءة عن هذا الـ structure هنا
نعود الآن للكود
انشاء عملية notepad.exe باستخدام دالة CreateProcess
1 // CreateProcess.cpp : This file contains the 'main' function. Program execution begins and ends there.
2 //
3
4 #include <iostream>
5 #include <windows.h>
6 #include <stdio.h>
7 int main()
8 {
9 // Declare variables
10 STARTUPINFO si;
11 PROCESS_INFORMATION pi;
12 BOOL result;
13 DWORD exitCode;
14
15 // Initialize variables
16 ZeroMemory(&si, sizeof(si));
17 si.cb = sizeof(si);
18 ZeroMemory(&pi, sizeof(pi));
19
20 // Create a process using the command line argument
21 result = CreateProcess(
22 L"C:\\Windows\\System32\\notepad.exe", // Module name
23 NULL, // Command line
24 NULL, // Process handle not inheritable
25 NULL, // Thread handle not inheritable
26 FALSE, // Set handle inheritance to FALSE
27 0, // No creation flags
28 NULL, // Use parent's environment block
29 NULL, // Use parent's starting directory
30 &si, // Pointer to STARTUPINFO structure
31 &pi); // Pointer to PROCESS_INFORMATION structure
32
33 if (!result)
34 {
35 printf("CreateProcess failed (%d).\n", GetLastError());
36 return -1;
37 }
38
39 // Wait until child process exits
40 WaitForSingleObject(pi.hProcess, INFINITE);
41
42 // Get the exit code of the child process
43 GetExitCodeProcess(pi.hProcess, &exitCode);
44 printf("Child process exited with code %d.\n", exitCode);
45
46 // Close process and thread handles
47 CloseHandle(pi.hProcess);
48 CloseHandle(pi.hThread);
49
50 return 0;
51 }
لنبدأ بالتفصيل :
10: نلاحظ أننا قمنا بتعريف متغيّر باسمsiمن نوعSTARTUPINFOوهو يمثّل الـ structure الذي قمنا بشرحه سابقًا، إن كنت تتساءل كيف استطعنا الوصول لهذا النوع (STARTUPINFO) فلأنه قمنا بادراج المكتبةwindows.hفي السطر رقم511: قمنا بتعريف متغيّر باسمpiوالذي يشير كذلك للـ structure الذي سيحمل المعلومات الخاصة بالعملية التي سيتم انشاءها12: قمنا بتعريف المتغيّرresultالذي سيحمل نتيجة تنفيذ الدالة13: الغرض من المتغيّرexitCodeهو لمعرفة الـ exit code الخاص بعملية الـnotepad.exeبعد انتهاءها16: قمنا بعمل initialization للمتغيّرsiعبر الدالةZeroMemory، الخطوة هذه لتهيئة الذاكرة وحذف أي قيم سابقة في الذاكرة قبل استخدامها17: قمنا بتعريف قيمة المتغيّرsi.cbوالذي يمثّل الـ size الخاص بالـSTARTUPINFOstructure18: قمنا بتهيئة الذاكرة للمتغيّرpi21: قمنا بنداء دالةCreateProcessونلاحظ أن القيمة العائدة من الدالة سيتم تخزينها في المتغيّرresult22: قمنا بتمرير القيمةC:\\Windows\\System32\\notepad.exeوالتي تمثل اسم البرنامج الذي سيتم تنفيذه (lpApplicationName)23: قمنا بتمرير القيمةNULLكوننا عرفنا اسم البرنامج في الـ parameter السابق24: يمثل الـlpProcessAttributesوقمنا بتمرير القيمةNULLمما يعني أنه سيتم استخدام الاعدادات الافراضية للـSecurity Descriptorالخاص بعملية الـnotepad.exe25: نفس السطر السابق لكن على مستوى الـ Thread26: قمنا بتمرير القيمةFALSEوالتي تعني هنا أنه لن يتم توريث الـ handles الخاصة بالـcalling processالى الـnotepad.exeprocess27: لم نقم بتحديد أيCreation Flags، بالتالي سيتم تنفيذ الـ Thread الخاص بالعملية مباشرة28: لم نقم بتحديد قيمة للـenvironment block، بالتالي سيتم استخدام الـenvironment blockالخاص بالـcalling process29: لم نقم بتحديد قيمة للمسار، سيتم استخدام اعدادات الـcalling process30: قمنا بتمرير الـ pointer الخاص بالـSTARTUPINFOstructure31: قمنا بتمرير الـ pointer الخاص بالـPROCESS_INFORMATIONstructure33-37: في حال فشل تنفيذ الدالةCreateProcessسيتم طباعة الخطأ باستخدام دالةGetLastError39-40: في هذه السطرين نسمح لعملية الـnotepad.exeأن تعمل حتى يتم انهاءها بشكل يدوي من المستخدم ، يتم تنفيذ هذا عن طريق الدالةWaitForSingleObject43-44: قمنا بقراءة الـexit codeالخاص بالعملية باستخدام دالةGetExitCodeProcess47-48: قمنا باغلاق الـ handles الخاصة بالعملية وبالـ Thread الخاص بها
بعد تنفيذ الكود، سنرى أنه استطعنا بدء عملية الـ notepade.exe

ℹ️ [ملاحظة] هذه المقالة تمّت كتابتها خلال دراسة هذه المواضيع، فكل ما تم ذكره هنا قد يحتمل الخطأ، لكن بالإمكان العودة إلى المراجع التي إستندت عليها هذه المقالة