08-10-12, 11:59 AM
التصميم من اجل UAC
لن يقوم الـ UAC برفع صلاحيات التطبيق بعد أن تم تشغيله فهو يقوم بإسناد الصلاحيات لذلك التطبيق عندما يبدأ ولن يقوم بعدها بتغيير تلك الصلاحيات فإن احتاج التطبيق للعمل بصلاحيات مرتفعة فعليه أن يحصل على تلك الصلاحيات عندما يبدأ ولتجنب إعطاء التطبيق صلاحيات أكثر من اللازم يجب عليك تقسيم كودك إلى أجزاء بحسب احتياجه لتلك الصلاحيات فالبرنامج الرئيسي يجب أن يعمل بصلاحيات عادية ولاحقا يجب عليه تنفيذ تطبيقات أخرى تعمل بصلاحيات مرتفعة عند الحاجة.
فمثلا إن كان لدينا تطبيق يقوم بحفظ البيانات في قاعدة بيانات Sql Server فهو لا يحتاج لصلاحيات مدير ومع ذلك إن أراد إنشاء ملف بملخص العمليات في مجلد الويندوز – مجلد محمي – فسيحتاج عندها لصلاحيات مدير فيمكنك عندها تقسيم التطبيق إلى عدة أجزاء فالتطبيق الرئيسي يقوم بمعظم العمل وتطبيق آخر يقوم بكتابة معلومات الخلاصة إلى ذلك الملف عندها يمكن للتطبيق الأول تشغيل الثاني من أجل كتابة المعلومات في ذلك الملف.
وعندما يكون بالإمكان يفضل أن تعيد كتابة التطبيق لتجنب استخدام صلاحيات مرتفعة فالعديد من البرامج على سبيل المثال تكون منصبة في المجلد Program Files وهذا من المجلدات المحمية وبهذا إن احتاج التطبيق إلى تخزين معلومات في ملف متواجد بنفس المجلد الذي يحتوي على الملف التنفيذي للتطبيق فسوف يحتاج إلى صلاحيات إضافية للقيام بتلك العملية ويمكنك تجاوز هذه المشكلة بجعل التطبيق يكتب ذلك الملف في المجلد الخاص بالمستخدم الحالي. والعمليات الأخرى التي تحتاج لصلاحيات مرتفعة تتضمن الكتابة إلى المجلدات المحمية والتعامل بشكل مباشر مع العتاد وتعديل الأقسام المحمية في سجل النظام مثل HKEY_LOCAL_MACHINE.
وتقسيم التطبيق إلى أقسام تتطلب صلاحيات مرتفعة وأخرى لا تتطلب تلك الصلاحيات لا يمكن التطبيق من استخدام أقل الصلاحيات الممكنة فحسب ولكنه يبسط القسم الأخطر في كودك ويجعله أسهل للتنقيح فمثلا يمكننا استخدام كود شبيه بالتالي لتنفيذ تطبيق يتطلب صلاحيات مرتفعة
الكود السابق يستخدم الوظيفة System.Diagnostics.Process.Start لتشغيل التطبيق ممررا مسار التطبيق الذي نريد تنفيذه ومحددات سطر الأوامر الخاصة بها وهو يستخدم الدالة WaitForExit من الغرض المعاد التي تنتظر حتى الانتهاء من تنفيذ البرنامج ثم يتم التأكد عبر الخاصية ExitCode من القيمة المعادة من التطبيق المنفذ.
ويمثل الكود التالي الإجراء main في البرنامج المستدعى
حيث يبدأ التطبيق بإنشاء نموذج frmChoices وإضافة محددات سطر الأوامر إلى صندوق القائمة lstArguments ونختار العنصر الأول منه ثم نظهر النموذج فإن قام المستخدم بالضغط على الزر Cancel فالتطبيق يعيد القيمة -1 وإن ضغط على الزر OK فهو يعيد قيمة الخاصية Index من صندوق القائمة والموافقة للعنصر الذي تم اختياره منها والكود المستدعي للتطبيق يستقبل تلك القيمة عبر الخاصية ExitCode.
وكجزء من خصائص المستخدم لـ UAC فأي عمل يتطلب صلاحيات مرتفعة يجب أن يتم تعليمه بواسطة الدرع القياسي لـ UAC حيث يجب إظهاره لتحذير المستخدم بأنه ينفذ تطبيق يتطلب صلاحيات مرتفعة. وفي الوقت الحالي لا توجد طريقة بسيطة لإظهار ذلك الدرع في فيجول بايزيك لذلك سنستخدم دالات API لجعل الزر يظهر ذلك الدرع كما هو ظاهر في قطعة الكود التالية
ففي البداية نقوم بتعريف الدالة SendMessage المتواجدة في المكتبة User32.dll حيث يقوم الإجراء AddShieldToButton بضبط الخاصية FlatStyle الخاصة بالزر إلى System ثم يستخدم الدالة SendMessage لإرسال الرسالة BCM_SETSHIELD إلى الزر ولا توفر لنا مايكروسوفت حاليا طريقة لإضافة الدرع لتحكمات أخرى غير زر الأوامر فإن أردت إضافته إلى تحكم أخر فستقوم بذلك لوحدك كما يمكنك عمل صورة للدرع ووضعها ببساطة على تحكماتك ولكن هذه الصورة لن تتغير إن تم تغيير صورة الدرع الخاصة بالنظام
لن يقوم الـ UAC برفع صلاحيات التطبيق بعد أن تم تشغيله فهو يقوم بإسناد الصلاحيات لذلك التطبيق عندما يبدأ ولن يقوم بعدها بتغيير تلك الصلاحيات فإن احتاج التطبيق للعمل بصلاحيات مرتفعة فعليه أن يحصل على تلك الصلاحيات عندما يبدأ ولتجنب إعطاء التطبيق صلاحيات أكثر من اللازم يجب عليك تقسيم كودك إلى أجزاء بحسب احتياجه لتلك الصلاحيات فالبرنامج الرئيسي يجب أن يعمل بصلاحيات عادية ولاحقا يجب عليه تنفيذ تطبيقات أخرى تعمل بصلاحيات مرتفعة عند الحاجة.
فمثلا إن كان لدينا تطبيق يقوم بحفظ البيانات في قاعدة بيانات Sql Server فهو لا يحتاج لصلاحيات مدير ومع ذلك إن أراد إنشاء ملف بملخص العمليات في مجلد الويندوز – مجلد محمي – فسيحتاج عندها لصلاحيات مدير فيمكنك عندها تقسيم التطبيق إلى عدة أجزاء فالتطبيق الرئيسي يقوم بمعظم العمل وتطبيق آخر يقوم بكتابة معلومات الخلاصة إلى ذلك الملف عندها يمكن للتطبيق الأول تشغيل الثاني من أجل كتابة المعلومات في ذلك الملف.
وعندما يكون بالإمكان يفضل أن تعيد كتابة التطبيق لتجنب استخدام صلاحيات مرتفعة فالعديد من البرامج على سبيل المثال تكون منصبة في المجلد Program Files وهذا من المجلدات المحمية وبهذا إن احتاج التطبيق إلى تخزين معلومات في ملف متواجد بنفس المجلد الذي يحتوي على الملف التنفيذي للتطبيق فسوف يحتاج إلى صلاحيات إضافية للقيام بتلك العملية ويمكنك تجاوز هذه المشكلة بجعل التطبيق يكتب ذلك الملف في المجلد الخاص بالمستخدم الحالي. والعمليات الأخرى التي تحتاج لصلاحيات مرتفعة تتضمن الكتابة إلى المجلدات المحمية والتعامل بشكل مباشر مع العتاد وتعديل الأقسام المحمية في سجل النظام مثل HKEY_LOCAL_MACHINE.
وتقسيم التطبيق إلى أقسام تتطلب صلاحيات مرتفعة وأخرى لا تتطلب تلك الصلاحيات لا يمكن التطبيق من استخدام أقل الصلاحيات الممكنة فحسب ولكنه يبسط القسم الأخطر في كودك ويجعله أسهل للتنقيح فمثلا يمكننا استخدام كود شبيه بالتالي لتنفيذ تطبيق يتطلب صلاحيات مرتفعة
كود :
Private Sub btnRun_Click() Handles btnRun.Click
Try
‘ Start the process.
Dim pro As System.Diagnostics.Process
pro = System.Diagnostics.Process.Start( _
txtProgram.Text, txtArguments.Text)
‘ Wait for the process to exit.
pro.WaitForExit()
‘ Display the process’s exit code.
MessageBox.Show(“Exit code: “ & pro.ExitCode)
Catch ex As System.ComponentModel.Win32Exception
‘ This happens if the user fails to elevate to Administrator.
MessageBox.Show(“Operation canceled”, _
“Canceled”, MessageBoxButtons.OK, _
MessageBoxIcon.Information)
End Try
End Subويمثل الكود التالي الإجراء main في البرنامج المستدعى
كود :
Function Main(ByVal cmdArgs() As String) As Integer
Dim frm As New frmChoices
‘ Display the arguments.
For Each str As String In cmdArgs
frm.lstArguments.Items.Add(str)
Next str
‘ Select the first item.
If frm.lstArguments.Items.Count > 0 Then
frm.lstArguments.SelectedIndex = 0
End If
‘ Return the index of the selected item.
If frm.ShowDialog() = DialogResult.Cancel Then
Return -1
Else
Return frm.lstArguments.SelectedIndex
End If
End Functionوكجزء من خصائص المستخدم لـ UAC فأي عمل يتطلب صلاحيات مرتفعة يجب أن يتم تعليمه بواسطة الدرع القياسي لـ UAC حيث يجب إظهاره لتحذير المستخدم بأنه ينفذ تطبيق يتطلب صلاحيات مرتفعة. وفي الوقت الحالي لا توجد طريقة بسيطة لإظهار ذلك الدرع في فيجول بايزيك لذلك سنستخدم دالات API لجعل الزر يظهر ذلك الدرع كما هو ظاهر في قطعة الكود التالية
كود :
Imports System.Runtime.InteropServices
Module UacStuff
Declare Auto Function SendMessage Lib “user32.dll” _
(ByVal hWnd As HandleRef, ByVal msg As Int32, _
ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Int32
‘ Make the button display the UAC shield.
Public Sub AddShieldToButton(ByVal btn As Button)
Const BCM_SETSHIELD As Int32 = & H160C
btn.FlatStyle = Windows.Forms.FlatStyle.System
SendMessage(New HandleRef(btn, btn.Handle), _
BCM_SETSHIELD, IntPtr.Zero, CType(1, IntPtr))
End Sub
End Module