لمن ليس لديهم فكرة عن الريجستري
قبل البدء بالمقال أنصح بقراءة الملفات المرفقة لأني لستت بصدد كتابة أي شرح عن الريجستري .
يهدف هذا المقال الى عرض كيفية تطوير تطبيقات التحكم بالريجستري بواسطة لغة البرمجة جافا المتهمة بالعجز تجاه الوصول لمصادر نظام التشغيل ويندوز والتحكم فيها .
ليس السحر الأسود من سيقوم بذلك بل تقنية تسمى Java Native Interface (JNI) و هي تقنية تمكن تطبيقات وبرامج جافا من التفاعل مع برامج وتطبيقات مكتوبة بلغات برمجة اخرى مثل C أو ++C ( من ضمنها نظام التشغيل windows) عبر تقنية الربط الديناميكي .
الخطوة الأولى : دراسة ما هي الطرق التي تحتوي على سلوك يتعلق بمصار نظام التشغيل (يعجز كود لغة البرمجة جافا عن استيفاء معالجته مباشرة) ونكتب ترويساتها بالصورة المألوفة (نمط الارجاع و البارامترت وأقواسها ) مع زيادة المعرف native للإشارة ان هذه الطريقة سيتم تعريف سلوكها الفعلي بلغة اخرى غير جافا .
وننهي ترويسة الطريقة بفاصلة منقوطة ; ) ) ولا نضع الاقواس {} لأن كود سلوك الطريقة ليس بلغة جافا وبالنالي لا علاقة لبيئة جافا المحلية به .
اخترت ثلاث طرق تتعلق بالتحكم بالريجستري لا يمكنك كتابه سلوكها بلغة جافا :
setNewValue لتعديل احدى قيم مفاتيح الريجستري .
deleteValue لحذف احدى قيم مفاتيح الريجستري .
deleteKey لحذف مفتاح مع كل قيمه من الريجستري .
ترويسات الطرق ستكون كالتالي :
public native long setNewValue(); public native long deleteValue(); public native long deleteKey();
ولكن أين سلوك الطريقة ؟!!!!
هنا يستوجب ذكر التعريف التالي :
تقنية الربط الدينامكي Dynamic Linking :
هب آلية يقوم بها نظام التشغيل بربط التطبيقات المكتوبة بلغات البرمجة مع مكتبات النظام (ملفات dll.) في زمن التنفيذ
حيث تبقى هذه الملفات مكانها كامنة , ساكنة , غير فعالة حتى يطلب أحد التطبيقات استخدامها أو بالأحرى تحميلها عبر استدعاء الاجرائية loadLibrary .
ماهي WIN API ؟
مجموعة واجهات تطوير التطبيقات الخاصة بنظام التشغيل Windows ، على شكل مكتبات ربط دينامكي
Library Dynamic Linking (ملفات dll.) بشكل يلائم الاستخدام المباشر مع لغات البرمجة C أو ++C ومؤخرا VB لكي يستطيع تطبيقك البرمجي التفاعل مع نظام التشغيل ومصادره واحداثه .
هذه الواجهات مصممة من قبل شركة ميكروسوفت حيث جعلتها متاحه للاستخدام مجانا .
نحن سنختار من هذه الواجهات الملف advapi32.dll حيث انه الواجهة من WIN API
(ابتداء من الاصدارات المرمزة على 32 بت win32)
التي تقدم الخدمات الأساسية للوصول الى محتويات مسجل النظام Registry والتحكم فيها .
وعليه نستنتج من هذا الكلام ان علينا كتابة مكتبة ربط ديناميكي ( ملف dll. ) بلغة محلية لنظام التشغيل ) C أو ++C ) تستعين بواجهة تطوير تطبيقات ويندوز advapi32 للتحك بالريجستري .
هذه المكتبة ستحتوي على السلوك الفعلي للطرق الموسومة بالمعرف native لنسميه مثلا myDll
نقوم بتحميل هذه المكتبه عند تشغيل التطبيق باستدعاء الطريقة loadLibrary من الصف System ونعطيها كبرامتر اسم المكتبة الديناميكية التي كتبناها بين اشارتي تنصيص مزدوجتان ويفضل ان يتم ذلك ضمن كتلة static
static{System.loadLibrary("myDll");}قبل ان نضيع ... لنرجع للصف الذي سنكتبه بجافا MyClass :
package myclass;
public class MyClass {
static{System.loadLibrary("myDll");}
public MyClass() {}
public long status;
public native long setNewValue();
public native long deleteValue();
public native long deleteKey();
public static void main(String[] args) {
MyClass c = new MyClass();
regaccess.status=c.setNewValue();
if(c.status==0)System.out.println("Error");
else System.out.println("Success : Value Changed");
}
}نترجم الصف MyClass.java بالطريقة المألوفة بواسطة الأمر javac :
C:\jdk1.4\bin>javac –classpath c:\path_to_directory myclass.MyClass
حصلنا على الملف MyClass.class والأن نستخدم الأمر javah كالتالي :
C:\jdk1.4\bin>javah –classpath c:\path_to_directory myclass.MyClass
والناتج نحصل على الملف الرأسي myclass_MyClass.h نفتحه بالنوتباد نجد فيه كود كاتالي :
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class myclass_MyClass */
#ifndef _Included_myclass_MyClass
#define _Included_ myclass_MyClass
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: regaccess_RegAccess
* Method: setNewValue
* Signature: ()J
*/
JNIEXPORT jlong JNICALL Java_myclass_MyClas_setNewValue (JNIEnv *, jobject);
/*
* Class: myclass_MyClass
* Method: deleteValue
* Signature: ()J
*/
JNIEXPORT jlong JNICALL Java_myclass_MyClass_deleteValue (JNIEnv *, jobject);
/*
* Class: myclass_MyClass
* Method: deleteKey
* Signature: ()J
*/
JNIEXPORT jlong JNICALL Java_myclass_MyClass_deleteKey (JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endifهذا الملف يمثل مولد كود تلقائي لبرنامجك كمساعدة لك ليريحك من قواعد كتابة ملف Dll يحوي ترويسات الطرق التي كتبتها في MyClass.java منتهية بفاصلة منقوطة لم يبق لك سوى استبدال الفاصلة المنقوطة بقوسين {} وكتابة السلوك الفعلي للطرق :
ولكن انتظر ... لا تعدل في الملف myclass_MyClass.h ...انا سأقول لك أين ستقوم بذلك ...
علينا ايجاد Dll Compiler وانا اخترت Visual C++ يأتي مع حزمة Visual Basic 6
تختار New ثم Projects ثم MFC AppWizard(dll) وتختار اسم المشروع myDll
وننسخ فيه محتويات myclass_MyClass.h ونكتب سلوك الطرق واحدة تلو الأخرى .
مثلا نعود للطريقة setNewValue نجد ان ترويستها :
JNIEXPORT jlong JNICALL Java_myclass_MyClas_setNewValue (JNIEnv *, jobject);
والأن لتحقيق سلوك setNewValue نستعين بالطريقة RegSetValueA الموجودة في advapi32 API :
لتحقيق الفكرة التالية ( من الكتاب المرفق ) :
اقتباسلاستعراض الصور داخل الویندوز إكسبلورر ذات الامتداد bmp من المفتاحHKEY_CLASSES_ROOT\PAINT.PICTURE\DefaultIcon
ونعطیھ القیمة "%1"
تحقيق سلوك الطريقة setNewValue :
JNIEXPORT jlong JNICALL Java_myclass_MyClass_setNewValue
(JNIEnv *, jobject){
long retval=
RegSetValueA(HKEY_CLASSES_ROOT,"PAINT.PICTURE\\DefaultIcon",REG_SZ,"%1",2);
if(retval!=ERROR_SUCCESS ){return 0;}
else{return 1;}
}وكذلك من اجل الطريقة deleteKey نستعين بالطريقة RegDeleteKey الموجودة في advapi32 API
من اجل الطريقة deleteValue نستعين بالطريقة RegDeleteValue الموجودة في advapi32 API
لمزيد من الطرق للتحكم بالريجستري ودراسة ترتيب البرامترات وانواعها في طرق الواجهة advapi32 API يجب العودة الى Documentation الخاصة بـ advapi32 .
http://source.winehq.org/WineAPI/advapi32.html
الملف النهائي اللازم لتشغيل تطبيقنا MyClass سيشبه التالي
(بعد معاناااااااااة طويلة مع لغة C و تقنيات تمرير البرامترات فيها By try & Error ) :
اعرف ان هناك اختلاف عن myclass_MyClass.h لكن المترجم لم يرضى ترجمة الملف الا بعد هذه التعديلات لقلة خبرتي مع C .
يفترض الا يتم التعديل الا باستبدال الفاصلة المنقوطة بـ{} وكتابة السلوك .
#include "stdafx.h"
#include "myDll.h"
#include <jni.h>
#include <windows.h>
extern "C" {
JNIEXPORT jlong JNICALL Java_myclass_MyClass_deleteKey
(JNIEnv *, jobject){
HKEY hKey;
long retval=
RegDeleteKey(HKEY_CURRENT_USER,"Software\\ORACLE\\OLAP\\ExpressRegEdit");
if(retval!=ERROR_SUCCESS ){return 0;}
else{return 1;}
}
JNIEXPORT jlong JNICALL Java_myclass_MyClass_ deleteValue
(JNIEnv *, jobject){
long retval=
RegDeleteValue(HKEY_CLASSES_ROOT,"PAINT.PICTURE\\DefaultIcon");
if(retval!=ERROR_SUCCESS ){return 0;}
else{return 1;}
}
JNIEXPORT jlong JNICALL Java_myclass_MyClass_setNewValue
(JNIEnv *, jobject){
long retval=
RegSetValueA(HKEY_CLASSES_ROOT,"PAINT.PICTURE\\DefaultIcon",REG_SZ,"%1",2);
if(retval!=ERROR_SUCCESS ){return 0;}
else{return 1;}
}
}
void main(){}لا يعرف المترجم اين يجد الملف الرأسي jni.h وبالتالي اختر Project ثم Setting ثم C/C++ وفي مربع Project Options
عليك اضافة السطرين التاليين
/I" C:\j2sdk1.4.0\include " /I" C:\j2sdk1.4.0\include\win32 "
بعد ان تترجم myDll بنجاح تجد ملف myDll.dll في المجلد Debug انسخه وضعه قي المجلد System32 الموجود في المجلد Windows
الان صار تطبيقك جاهزا للتشغيل بالطريقة المألوفة (الأمر java)
C:\jdk1.4\bin>java –classpath c:\path_to_directory myclass.MyClass

