fmo_82

أشترك معنا في بناء نظام Remote Desktop مع خاصية التحكم

71 ردود في هذا الموضوع

السلام عليكم ورحمة الله وبركاته

ارجو منكم ان تقبلوني معكم وقد قمت سابقا بالعمل في برمجة الشبكات

وقرأت نصف كتاب الإستاذ فادي

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

طريقة الغاء الخلفية تعتمد على دالة الAPI المتاحة لنا وهي SystemParametersInfo

انسخ الكود
  1.  
  2. [color= #009900;][[/color]DllImport[color= #009900;]([/color][color= #0000ff;]"user32.dll"[/color][color= #339933;],[/color] CharSet [color= #339933;]=[/color] CharSet[color= #339933;].[/color]Auto[color= #009900;])[/color][color= #009900;]][/color]
  3. [color= #000000; font-weight: bold;]public[/color] [color= #990000;]static[/color] extern int SystemParametersInfo[color= #009900;]([/color]int uAction[color= #339933;],[/color] int uParam[color= #339933;],[/color] string lpvParam[color= #339933;],[/color] int fuW
    inIni[color= #009900;])[/color][color= #339933;];[/color]
  4.  

طبعا استعمال DllImport يستوجب استعمال فضاء الأسماء InteropServices

انسخ الكود
  1. using [color= #990000;]System[/color][color= #339933;].[/color]Runtime[color= #339933;].[/color]InteropServices[color= #339933;];[/color]
  2.  

ثم بتمرير الثوابت التالية للدالة :

انسخ الكود
  1. SystemParametersInfo[color= #009900;]([/color]0X14[color= #339933;],[/color] [color= #cc66cc;]0[/color][color= #339933;],[/color] [color= #0000ff;]"(None)"[/color][color= #339933;],[/color] 0x1 [color= #339933;]|[/color] 0x2[color= #009900;])[/color][color= #339933;];[/color]
  2.  

بعدها علينا ارسال رسالة تحديث للDesktop باستخدام الدالة SendMessage مع التابع WM_SETTINGCHANGE باستعمال مقبض سطح المكتب

ولاعادة صورة سطح المكتب نقوم بقراءة مكانها من الريجيستري وتمريرها إلى الدالة SystemParametersInfo باستبدال "(None)" باسم الصورة طبعا لاننسى عملية التحديث :)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

رائع اخي دريم طريقة ممتازة يبدو أنك بدأت بالسي شارب وهذا شيء ممتاز على فكرة كل مبرمجين الفي بي الذين تعاملت معهم سواء من الطلاب أو المبرمجين حولوا إلى سي شارب فالذي يرى طريقة السي شارب في تنظيم الكود لا يستطيع أن يتخيل نفسه يرجع إلى الفي بي :)

ارحب بك اخي أبو مازن وأتمنى أن تكون عضو فعال معنا وأهلا وسهلا بك :)

بخصوص مقارنة البكسيل لكل صورة هل يوجد أحد لديه فكرة أخرى أو تحسين للفكرة السابقة قبل أن اشرح هذه الجزئية

تم تعديل بواسطه فادي عبدالقادر
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

السي شارب أصبح حتمية خصوصا أنني كنت عندما أبحث شئ على الدوت نت أجده بالسي شارب موثقا بخلاف الفيبي القليل يستعملونه

فقط أردت توضيح فكرتي في مقارنة أجزاء من الصورة طبعا امكانية استعمال المؤشرات قد تسرع العملية لكني كنت أفكر في حصر عملية المقارنة قدر المستطاع (كل كلامي طبعا نظري لم أجربه بعد)

الفكرة هي في تقسيم الصورة إلى عدة صور وعملية المقارنة لا تكون دورية يعني تتم فقط عند:

- تغير تحرك الماوس وعندها لا يتم المقارنة إلا في مساحة معينة موجود فيها مؤشر الماوس أي الصور التي تقع فقط في تلك المساحة

- الاستفادة من رسائل النظام من أجل معرفة تغيير ما على سطح المكتب أو على النوافذ فقط وقتها تتم عملية المقارنة

لا أعرف ربما نظريا ستفيد هذه الطريقة :wink: :wink:

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
يعود ذلك لسببين:

الأول: أن تقنية الـRemoting لا تعمل بالأساس إلا من خلال بروتوكول الـTCP

الثاني: لماذا أخترنا تقنية الـRemoting لسبب رأيسي وهو أنها تعتمد على مبدأ الـRequest والـResponse ......

كلامك جواهر أخ فادي

طيب هنا بالنسبة لتقنية ال Remoting ألا يمكن أستعمال منفذين بطريقة UDP واحد للأرسال والآخر للأستقبال

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

بالطبع نظرا ً لخبرتي القليلة سأدخل ضمن فريق البرمجة والتنفيذ

بالطبع لو قبلتم بي كفرد من الفريق

وعندي سؤال بالنسبة لنقطة اخذ صورة من سطح المكتب وارسالها

وهو جربت التعامل مع جميع ازرار لوحة المفاتيح ولكن الذي لم اعرف كيف اتعامل معه لأن البرنامج لا يحس بالضغط عليه هو PrintScreen وهل يمكن ان اجبر برنامج على تنفيذ امر الضغط على زر معين من لوحة المفاتيح بمعنى ( ان اوهم البرنامج ان المستخدم ضغط على زر printScreen ومن ثم اخذ clipboard.getImage() وارسال هذه الصورة عبر الشبكة )

كما كان لي ملاحظتين في درسك الاول اخ فادي برجاء المرور على الدرس وابداء ردك

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

بالنسبة للتعامل مع الأزرار

SendKeys.Send("{%}({PRTSC})");

لكني لا أفضل ذلك أحسن كود لأخذ سطح المكتب هو :

انسخ الكود
  1.  
  2. Rectangle bounds [color= #339933;]=[/color] Screen[color= #339933;].[/color]PrimaryScreen[color= #339933;].[/color]Bounds[color= #339933;];[/color]
  3. Bitmap screenshot [color= #339933;]=[/color] [color= #000000; font-weight: bold;]new[/color] [color= #990000;]System[/color][color= #339933;].[/color]Drawing[color= #339933;].[/color]Bitmap[color= #009900;]([/color]bounds[color= #339933;].[/color]Width[color= #339933;],[/color] bounds[color= #339933;].[/color]Height[color= #339933;],[/color]
  4. [color= #990000;]System[/color][color= #339933;].[/color]Drawing[color= #339933;].[/color]Imaging[color= #339933;].[/color]PixelFormat[color= #339933;].[/color]Format32bppArgb[color= #009900;])[/color][color= #339933;];[/color]
  5. Graphics graph [color= #339933;]=[/color] Graphics[color= #339933;].[/color]FromImage[color= #009900;]([/color]screenshot[color= #009900;])[/color][color= #339933;];[/color]
  6. graph[color= #339933;].[/color]CopyFromScreen[color= #009900;]([/color]bounds[color= #339933;].[/color]X[color= #339933;],[/color] bounds[color= #339933;].[/color]Y[color= #339933;],[/color] [color= #cc66cc;]0[/color][color= #339933;],[/color] [color= #cc66cc;]0[/color][color= #339933;],[/color] bounds[color= #339933;].[/color]Size[color= #339933;],[/color] CopyPixelOperation[color= #339933;].[/color]SourceCopy[color= #009900;])[/color][color= #339933;];[/color]
  7. pictureBox1[color= #339933;].[/color]Image [color= #339933;]=[/color] screenshot[color= #339933;].[/color]GetThumbnailImage[color= #009900;]([/color]pictureBox1[color= #339933;].[/color]Width[color= #339933;],[/color] pictureBox1[color= #339933;].[/color]Height[color= #339933;],[/color] [color= #000000; font-weight: bold;]null[/color][color= #339933;],[/color] n
    ew IntPtr[color= #009900;]([/color][color= #009900;])[/color][color= #009900;])[/color][color= #339933;];[/color]
  8.  

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
SendKeys.Send("{%}({PRTSC})");

عنمدي سؤال وهو في الحالة العادية لا يتم الاحساس بالضغط على زرار PrintScreen

Private Control1_KeyPress(object sender , KeyEventArgs e)

{

if (e.keyCode=keys.PrintScreen)

clipboard.clear();

}

هذا الكود لا يتم تنفيذه ابداً وذلك لعدم احساس الفورم او الكنترول بالضغط على زرار Print Screen

هل هناك طريقة لمنع عملية PrintScreen

اعلم ان السؤال بعيد عن الموضوع ولكن لتتم الفائدة في عملية اخذ نسخة من سطح المكتب

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
الفكرة هي في تقسيم الصورة إلى عدة صور وعملية المقارنة لا تكون دورية يعني تتم فقط عند:

- تغير تحرك الماوس وعندها لا يتم المقارنة إلا في مساحة معينة موجود فيها مؤشر الماوس أي الصور التي تقع فقط في تلك المساحة

- الاستفادة من رسائل النظام من أجل معرفة تغيير ما على سطح المكتب أو على النوافذ فقط وقتها تتم عملية المقارنة

لا أعرف ربما نظريا ستفيد هذه الطريقة

هذا صحيح من الناحية النظرية أما م الناحية العملية ففي الـRemoting يتم استدعاء الدالة الموجودة في Class من قبل الـClient وتنفذ هذه الدالة لحظيا على الـServer بمعنى أن المتحكم الأساسي في عملية التقاط الصورة سيكون الـClient وليس الـServer وبالتالي فمن الصعب معرفة رسائل النظام التي تصدر عند حدوث اي حدث يتم من خلال الـServer , واما تقسيم الصورة إلى مجموعة صور وان تتم المقارنة في الصورة التي يؤشر عليها بالماوس فهي ممكنة لكنها غالبا ستحدث مشاكل لأن التغير لن يكون بضرورة بموقع الماوس فقط . الفكرة تحتاج إلى تحليل منطقي اكبر بخصوص عملية المقارنة لصورة كاملة فقد قمت سابقا بكتابة درس لذلك في الـCode Project وتأتي الفكرة اساسا من مقارنة الثلاثة الوان الرئيسية في كل بكسيل (الأحمر,والأخضر, و الأزرق) وفي حالة حدوث اختلافات بالنسبة معينة يتم ارسال الصورة ولتسريع عملية المقارنة قمت بتصغير الصورة إلى 100 في 100 بكسلس وفي هذه الحالة فإن المقارنة ستكون سريعة ولن يأخذ ذلك وقت معالجة كبير , لكن في برمجيات الـRemote Desktop قد تختلف الحاجة وذلك بإرسال البكسلس المختفة فقط بعد اكتشاف تغيرها حيث سيكون لدينا ثلاثة من الـBitmaps واحدة لصورة السابقة وأخرى لصورة الحالية والثالثة يوضع فيها البكسيلس المختلفة ويتم وضع قيمة null في البكسيلس المتشابهة وبعد انتهاء المقارنة يتم ارسال الـBitmap الثالثة وفي طرف الـClient يتم تعبئة الـBitmap الجديدة على الـBitmap الموجودة بحيث يستثني المواقع التي تحتوي على قيمة null ... من يستطيع القيام بالتحويل ذلك إلى كود وبالستعانة بالطريقة الموجودة في الدرس الذي اشرت اليه أو بتحليل الفكرة بشكل منطقي

طيب هنا بالنسبة لتقنية ال Remoting ألا يمكن أستعمال منفذين بطريقة UDP واحد للأرسال والآخر للأستقبال

تستطيع عمل منفذين للإرسال والأستقبال من خلال اي بروتوكول المشكلة ليست هنا الـRemoting تقنية تختلف عن مبدأ الـSocket في عملية الإتصال والإرسال فهي تعتمد بشكل رأيسي على بروتوكول الـTCP وتتصل مع الـServer من خلال URL وبذلك فهي تتعدى مشكلة الـNAT بكل سهولة.

وهو جربت التعامل مع جميع ازرار لوحة المفاتيح ولكن الذي لم اعرف كيف اتعامل معه لأن البرنامج لا يحس بالضغط عليه هو PrintScreen وهل يمكن ان اجبر برنامج على تنفيذ امر الضغط على زر معين من لوحة المفاتيح بمعنى ( ان اوهم البرنامج ان المستخدم ضغط على زر printScreen ومن ثم اخذ clipboard.getImage() وارسال هذه الصورة عبر الشبكة )

اخي بروف لا ادري ما الهدف من استخدامك للـPrint Screen لكن سنأتي لاحقا على شرح كيفية نقل كافة الأزرار إلتي يتم الضغط عليها بالكي بورد بإذن الله

كما كان لي ملاحظتين في درسك الاول اخ فادي برجاء المرور على الدرس وابداء ردك

تمت الإجابة

تم تعديل بواسطه فادي عبدالقادر
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

السلام عليكم ورحمة الله وبركاته

اطلعت على الكلاس ScreenCapture الموجودة في المشروع وقمت بمحاولة الاستفادة منها لتطبيق الفكرة التي تقوم بالمقارنة بين صورتين

وقد عدلت على الكلاس لكي تصبح

class ScreenCapture : System.MarshalByRefObject
{
public Size GetDesktopBitmapSize()
{
return Screen.PrimaryScreen.Bounds.Size;
}
public byte[] GetDesktopBitmapBytes()
{
Rectangle bounds = Screen.PrimaryScreen.Bounds;
Bitmap screenshot = new System.Drawing.Bitmap(bounds.Width, bounds.Height,
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Graphics graph = Graphics.FromImage(screenshot);
graph.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size, CopyPixelOperation.SourceCopy);
MemoryStream ms = new MemoryStream();
screenshot.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
return ms.GetBuffer();
}
public Image diff_image (Image OrginalImage, Image SecoundImage)
{
Bitmap bt1 = new Bitmap(OrginalImage);
Bitmap bt2 = new Bitmap(SecoundImage);
int size_H = bt1.Size.Height;
int size_W = bt1.Size.Width;
Bitmap bt3 = new Bitmap(size_W, size_H);
Color pixel_image1;
Color pixel_image2;
try
{

for (int x = 0; x != size_W; x++)
{

for (int y = 0; y != size_H; y++)
{
pixel_image1 = bt1.GetPixel(x, y);
pixel_image2 = bt2.GetPixel(x, y);

if (pixel_image1 != pixel_image2)
{
bt3.SetPixel(x, y, pixel_image2);
}

}

}

}
catch (Exception)
{
}
return bt3.GetThumbnailImage(size_W, size_H, null, new IntPtr());

}
}

هنا انشئت صورة ثالثة نضع فيها فقط البيكسل الغير متشابهة

وقد طبقت العملية بمقارنة صورتين ونجحت :) لكن طبعا استغرقت وقتا طويلا :(

انا أجرب الآن المؤشرات لتسريع عملية المقارنة مع الunsafe code

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

لقد أضفت دالة أخرى أسرع لاستخراج التغير بين الصورتين باستخدام المؤشرات

		public Image Unsafe_diff_image(Image OrginalImage, Image SecondImage)
{
Bitmap BOrginalImage = new Bitmap(OrginalImage);
Bitmap BSecondImage = new Bitmap(SecondImage);
BitmapData bitmapData1 = BOrginalImage.LockBits(new Rectangle(0, 0,
OrginalImage.Width, OrginalImage.Height),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb);
BitmapData bitmapData2 = BSecondImage.LockBits(new Rectangle(0, 0,
SecondImage.Width, SecondImage.Height),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb);
unsafe
{
byte* imagePointer1 = (byte*)bitmapData1.Scan0;
byte* imagePointer2 = (byte*)bitmapData2.Scan0;

for (int i = 0; i < bitmapData1.Height; i++)
{
for (int j = 0; j < bitmapData1.Width; j++)
{
// write the logic implementation here

if ((imagePointer1[0] != imagePointer2[0]) &&
(imagePointer1[1] != imagePointer2[1]) && (imagePointer1[2] != imagePointer2[2]))
{
imagePointer2[0] = imagePointer1[0];
imagePointer2[1] = imagePointer1[1];
imagePointer2[2] = imagePointer1[2];
}
else
{
imagePointer2[0] = 255;
imagePointer2[1] = 255;
imagePointer2[2] = 255;
}

imagePointer2[3] = imagePointer1[3];
imagePointer1 += 4;
imagePointer2 += 4;


}//end for j
imagePointer1 += bitmapData1.Stride -
(bitmapData1.Width * 4);
imagePointer2 += bitmapData1.Stride -
(bitmapData1.Width * 4);
}//end for i
}//end unsafe
BOrginalImage.UnlockBits(bitmapData1);
BSecondImage.UnlockBits(bitmapData2);
return BSecondImage.GetThumbnailImage(SecondImage.Width, SecondImage.Height, null, new IntPtr());;
}

الكود غير منظم لكنه مفهوم أظن :)

استعنت بالدرس الموجود هنا لمن يريد شرح أكثر

http://www.codeproject.com/KB/graphics/quickgrayscale.aspx

تم تعديل بواسطه DreamNet
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

عملية تحديث سطح المكتب كنت أتصورها سهلة جدا :)

دالة الApi المستعملة هي SendMessageTimeout

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr SendMessageTimeout(
IntPtr hWnd,
uint Msg,
UIntPtr wParam,
IntPtr lParam,
uint fuFlags,
uint uTimeout,
out uint lpdwResult);

لكن هنا يجب الأخذ بعين الاعتبار أن التحديث لا يتم إلا اذا كان هناك تغيير في الاعدادات على سطح المكتب وأسهل شئ يمكننا تغييره في الاعدادات هو حجم الأيقونات (عادة مايكون 32 )

عن طريق الريجيستري يمكنن تغيير هذه القيمة ثم ارسال الأمر كي يتم فعلا التحديث

private void RefreshDesptop()
{
string icon_size_string;
string new_icon_size_string;
//قراءة أبعاد الأيقونات من الريجيستري
icon_size_string = Microsoft.Win32.Registry.CurrentUser.OpenSubKey
(@"Control Panel\Desktop\WindowMetrics").GetValue("Shell Icon Size").ToString();
//كتابة أبعاد جديدة للأيقونات باضفة 1 في الريجيستري
new_icon_size_string = (int.Parse(icon_size_string )+1).ToString();
Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"Control Panel\Desktop\WindowMetrics"
,true).SetValue( "Shell Icon Size",new_icon_size_string);
// ارسال أمر التحديث
SendMessageTimeout((System.IntPtr)HWND_BROADCAST,
WM_SETTINGCHANGE,
(System.UIntPtr)SPI_SETNONCLIENTMETRICS,
IntPtr.Zero,
SMTO_ABORTIFHUNG,
1000, out lRes);
// ارجاع القيمة الافتراضية المعدلة من الريجيستري
Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"Control Panel\Desktop\WindowMetrics"
, true).SetValue("Shell Icon Size", icon_size_string);
//ارسال أمر التحديث مجددا
SendMessageTimeout((System.IntPtr)HWND_BROADCAST,
WM_SETTINGCHANGE,
(System.UIntPtr)SPI_SETNONCLIENTMETRICS,
IntPtr.Zero,
SMTO_ABORTIFHUNG,
1000, out lRes);
}

كي لا أنسى تعريف الثوابت :)

private const int WM_SETTINGCHANGE = 0x001A;
private const int HWND_BROADCAST = 0xffff;
private const int SPI_SETNONCLIENTMETRICS = 0x002A;
private const int SMTO_ABORTIFHUNG = 0x0002;
uint lRes;

في الأخير يمكن ارجاع صورة سطح المكتب (بعد انهاء البرنامج ) بقراءتها من الريجيستري واستعمال نفس الدالة SystemParametersInfo التي استعملناها لحذف الخلفية باستبدال None بالمكان المستخرج من الريجيستري

private void RestoreWallpaper()
{
//قراءة مكان الصورة الحالية لسطح المكتب
string WallpaerImage = Microsoft.Win32.Registry.CurrentUser.OpenSubKey
(@"Control Panel\Desktop").GetValue("Wallpaper").ToString();
//استرجاع صورة سطح المكتب
SystemParametersInfo(0X14, 0, WallpaerImage, 0x1);
}

تم تعديل بواسطه DreamNet
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

رائع اخي دريم سنستفيد بإذن الله من هذه التعديلات في بناء الـClass الرئيسي للمشروع

سنبدأ المرحلة التالية وهي كتابة الـRemoting Class والذي سيحتوي على الأمور التالية:

1- قراءة احداثيات الـماوس والكي بورد وتطبيقها على الـHost

2-دالة التقاط ونقل الصورة وسوف نستفيد من التعديلات التي اجراها اخي دريم

3- دلة نقل الملفات إلى الـHost

سأحضر بعض المعلومات واضعها اليوم أو غدا بإذن الله

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

نبدأ اليوم الجانب العملي من المشروع وأول ما سنبدأ به هو تعريف الدوال الرئيسية والتي سيتم استخدامها في عملية التحكم بالـMouse والـKeyboard

أولا دوال التحكم بالـMouse والـKeyboard:

1-دالة ضبط مؤشر الماوس :SetCursorPos وتأخذ إحداثيات

الـ X والـ Y للـ Mouse حيث يتم وضع مؤشر الـMouse على الإحداثيات الممررة ، ولاستخدامها بالدوت نيت سيتم استدعائها من الملف User32.Dll باستخدام الدالة DllImport وكما يلي:

[DllImport("user32.dll")]
private static extern void SetCursorPos(int x, int y);

public void MoveMouse(int x, int y)
{
SetCursorPos(x, y);
}

المطلوب في برنامج الـClient هو استدعاء هذه الدالة وتمرير إحداثيات الـMouse التي يتم عمل Hooking لها وعند استدعاء تلك الدالة سيتم تطبيق الإحداثيات الممررة على الـServer بشكل مباشر.

2-دالة إرسال معلومات الأزرار التي يتم الضغط عليها بالماوس أو الكي بورد SendInput: وتأخذ هذه الدالة ثلاثة باروميترات الأول من نوع Integer ويوضع فيه عدد المرات التي سيتم تنفيذها عند استدعاء الدالة والثاني مؤشر على Struct Input يمرر فيه كافة معلومات الإدخال الخاصة بالماوس أو الكي بورد والثالث من نوع Integer يمرر فيه حجم الـInput Struct.

	[DllImport("user32.dll")]
private static extern uint SendInput(
uint nInputs, // count of input events
ref INPUT input,
int cbSize // size of structure
);

سنقوم بالبداية بإنشاء الـInput Struct وسيتم تعريفه على أساس Explicit Layout بحيث يتم تحديد موقع كل Field Offsetفي الـStruct وسنستخدم هذا الـStruct لتعريف كل من إدخالات الماوس والكي بورد وهي MOUSE_INPUT لإدخال Mouse Buttons Press Values والـKEYBD_INPUT لإدخال Keyboard Button Press Value وتستدعى كل منها باستخدام الـ INPUT Struct وكما يلي:

	struct MOUSE_INPUT
{
public uint dx;
public uint dy;
public uint mouseData; // Mouse Button
public uint dwFlags; // Press Or Release Mouse Button
public uint time; // zero by defualt
public uint dwExtraInfo; // any other external data
}

struct KEYBD_INPUT
{
public ushort wVk; // Ketborad Virtual Key
public ushort wScan; // Scan Code
public uint dwFlags; // Press Or Release Keyborad Button
public uint time;
public uint dwExtraInfo;
}

[StructLayout(LayoutKind.Explicit)]
struct INPUT
{
[FieldOffset(0)]
public uint type;

// union
[FieldOffset(4)]
public MOUSE_INPUT mi;

[FieldOffset(4)]
public KEYBD_INPUT ki;
}

يجب أن نمرر في الـType للـInput Struct نوع العملية التي يتم إدخالها وتدل كل قيمة على نوع تلك العملية فمثلا تعني القيمة 0X002 أن العملية هي الضغط على الزر الأيسر للماوس والقيمة 0X004 هي تحرير عملية الضغط ويمكن معرفة كافة هذه القيم من الـMSDN:

	private const uint MOUSEEVENTF_MOVE	   = 0x0001; /* mouse move */
private const uint MOUSEEVENTF_LEFTDOWN = 0x0002; /* left button down */
private const uint MOUSEEVENTF_LEFTUP = 0x0004; /* left button up */
private const uint MOUSEEVENTF_RIGHTDOWN = 0x0008; /* right button down */
private const uint MOUSEEVENTF_RIGHTUP = 0x0010; /* right button up */
private const uint MOUSEEVENTF_MIDDLEDOWN = 0x0020; /* middle button down */
private const uint MOUSEEVENTF_MIDDLEUP = 0x0040; /* middle button up */
private const uint MOUSEEVENTF_WHEEL = 0x0800; /* wheel button rolled */
private const uint MOUSEEVENTF_ABSOLUTE = 0x8000; /* absolute move */
private const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
private const uint KEYEVENTF_KEYUP = 0x0002;

private const uint INPUT_MOUSE = 0;
private const uint INPUT_KEYBOARD = 1;

سننشئ دالة باسم PressOrReleaseMouseButton وسنمرر لكل منها مجموعة من المتغيرات حيث سنشتق كائن من الـInput Struct والذي عرفناه في بداية البرنامج وسنمرر له الـ Input Type سواء من الـ Mouse أو الـKeyboard فإذا كان من الـ Mouse نمرر له إحداثيات المؤشر والـKay Button سواء Left أو Right وإحداثيات الموقع الذي تم الضغط عليه X و Y وكما يلي:

public void PressOrReleaseMouseButton(bool Press, bool Left, int X, int Y)
{
INPUT input = new INPUT();

input.type = INPUT_MOUSE;
input.mi.dx = (uint) X;
input.mi.dy = (uint) Y;
input.mi.mouseData = 0;
input.mi.dwFlags = 0;
input.mi.time = 0;
input.mi.dwExtraInfo = 0;

if (Left)
{
input.mi.dwFlags = Press ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP;
}
else
{
input.mi.dwFlags = Press ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP;
}

SendInput(1, ref input, Marshal.SizeOf(input));
}

تدل الـPress في الدالة السابقة على استمرار عملية الضغط وتأخذ قيمة True أو False فإذا كانت False فهذا يعني تحرر عملية الضغط ...

وأما فيما يخص الكي بورد فسننشئ دالة باسم PressOrReleaseKeyboradButton وسنمرر لها أربعة باروميترات وهي الـVirtualKeyCode ويوضع فيه الـByte للـButton الذي تم الضغط عليه لمزيد من المعلومات أنظر الرابط http://delphi.about.com/od/adptips2006/qt/vkey2char.htm

والـ ScanCode لمزيد من المعلومات أنظر الرابط http://www.barcodeman.com/altek/mule/scandoc.php

والـKeyDown ويأخذ True أو False لمعرفة الـKey Down من الـKey Up.

والـExtendedKey لوضع أي Extended Key يتم استخدامه كمثال استخدام الـCaps Lock.

public void SendKeystroke(byte VirtualKeyCode, byte ScanCode, bool KeyDown, bool ExtendedKey)
{
INPUT input = new INPUT();

input.type = INPUT_KEYBOARD;
input.ki.wVk = VirtualKeyCode;
input.ki.wScan = ScanCode;
input.ki.dwExtraInfo = 0;
input.ki.time = 0;

if (!KeyDown)
{
input.ki.dwFlags |= KEYEVENTF_KEYUP;
}

if (ExtendedKey)
{
input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
}

SendInput(1, ref input, Marshal.SizeOf(input));
}

تركت بعض الأمور بدون شرح كامل لإستثارة التساؤلات لديكم :) ايضا إذا كان لديكم أي اقتراحات أو تعديلات فيمكنكم كتابتها

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

السلام عليكم ورحمة الله وبركاته

مادمنا دخلنا الجانب التطبيقي فأظنني سأستبق الأحداث قليلا :)

عملت التطبيق وانا أجربه الآن والكلاس الأساسية التي أستعملها الآن هي بالمرفقات

Remoting.zip

فيها بعض الأمور أردت أن أناقشها معك

المشكل الذي يواجهي الآن هو التميز بين الصورة الموجودة عند العميل والتي عند الخادم

عملت دالة تقوم بحساب الفارق بين الصورتين لكن لا أعرف كيفية الاستفادة منه

لان العملية هذه تتم في جهة الخادم

والعميل هو الذي يتحكم في قراءة الصورة

الشئ الذي يجب أخذه بعين الاعتبار هو تحويل الاحداثيات الموجودة على الصورة للاحداثيات الحقيقية التي يتم تطبيقها على سطح المكتب

ولذلك يجب قراءة أبعاد الشاشة والتي موجودة في GetDesktopBitmapSize

بعدها يتم حساب معامل التصحيح

Size Remotescreen = obj.GetDesktopBitmapSize();
float factY = Remotescreen.Height / pictureBox1.Height;
float factX = Remotescreen.Width / pictureBox1.Width;

بعدها فقط في الحدث MouseMove المتعلق بالصورة نضرب في معامل التصحيح لكل احداثي للحصول على الاحداثيات الصحيحة التي يتم تطبيقها على سطح المكتب

أرجو منك استاذ فادي الاطلاع على الفئة المرفة

حيث قمت باضافة خاصيتين تتحكمان في جودة الصورة الملتقطة لكن لم ألاحظ الفرق عند تطبيقها

بالتوفيق للجميع

تم تعديل بواسطه DreamNet
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

أشكرك أخي العزيز دريم وبارك الله بك

المشكل الذي يواجهي الآن هو التميز بين الصورة الموجودة عند العميل والتي عند الخادم

عملت دالة تقوم بحساب الفارق بين الصورتين لكن لا أعرف كيفية الاستفادة منه

لان العملية هذه تتم في جهة الخادم

والعميل هو الذي يتحكم في قراءة الصورة

التعديل الذي اقترحه هو أن لا يتم استدعاء دالة المقارنة من قبل الـClient وإنما تنفذ مع دالة جلب الصورة في الـServer وتتم عملية المقارنة قبل إرجاع الصورة فمثلا إذا كان هنالك اختلاف بين الصورة السابقة والصورة الحالية يتم إرجاع الصورة أو جزء الاختلاف وإلا يرجع قيمة null وفي طرف الـClient تعرض الصورة التي تم إرجاعها بوضع شرط ان لا تكون قيمة الإرجاع null واما عملية المقارنة فمن المفترض ان يتم عمل Global Variable على الـServer توضع فيه الصورة السابقة ليتم المقارنة بها.

الشئ الذي يجب أخذه بعين الاعتبار هو تحويل الاحداثيات الموجودة على الصورة للاحداثيات الحقيقية التي يتم تطبيقها على سطح المكتب

ولذلك يجب قراءة أبعاد الشاشة والتي موجودة في GetDesktopBitmapSize

بعدها يتم حساب معامل التصحيح

هذا صحيح لكن ممكن أن يتم عرض الصورة على PictureBox بحجمها الطبيعي بدون عمل ستريش لصورة واعتقد ان الـRemote Desktop للويندوز يستخدم نفس الطريقة لكن اقتراحك جميل ويمكن أن يستفاد منه فيما لو تم تصغير النافذة لكن عملية استخراج معامل التصحيح للإحداثيات يحتاج إلى استخراج معادلة دقيقة لوجود عدة مشاكل ستواجهك

واقتراحي كان بدل أن نعمل hook على إحداثيات الماوس من الويندوز يمكن أن نأخذ إحداثيات الماوس من الفورم الذي تعرض عليه الصورة وبذلك تكون عملية استخراج الإحداثيات ادق

حيث قمت باضافة خاصيتين تتحكمان في جودة الصورة الملتقطة لكن لم ألاحظ الفرق عند تطبيقها

قمت بتجربتها وهي تعمل بشكل جيد جدا فعند وضع الـQuality على 100% كان حجم الـMemoryStream = 407,858 في حين عند تقليلها إلى 10% اصبح حجمه 49,935 هذا على شاشة بدقة 1280 في 1024 لكن الصورة تصبح رديئة جدا على اي حال إضافة جميلة تشكر عليها :)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

قرأت المشاركة وأريد لفت الأنتباه لأمر

الشئ الذي يجب أخذه بعين الاعتبار هو تحويل الاحداثيات الموجودة على الصورة للاحداثيات الحقيقية التي يتم تطبيقها على سطح المكتب

ولذلك يجب قراءة أبعاد الشاشة والتي موجودة في GetDesktopBitmapSize

إذا كان المشروع متعلق بسطح المكتب فقط فنستطيع قراءة أبعاد الشاشة بالطريقة السابقة ولكن لن تفيد في بعض الحالات عند تشغيل البرامج التي تستخدم الدايركت وتصغر دقة الشاشة

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

حاولت أن أقوم بما ذكرته لكن البرنامج يعلق

عدلت في المكتبة بتعريف متغير byte سميته OldBuff

if ((IsDiff()) | (OldBuff == null))
{
OldBuff = ms.GetBuffer();
return OldBuff;
}
else { return null; }

في جهة العميل

if (buffer != null)
{
MemoryStream ms = new MemoryStream(buffer);
pictureBox1.Image = Image.FromStream(ms);
}

لكن عملية استخراج معامل التصحيح للإحداثيات يحتاج إلى استخراج معادلة دقيقة لوجود عدة مشاكل ستواجهك

ماهي المشاكل التي تقصدها

فقد استعملت الطريقة الثلاثية من اجل حساب المجهول :) وهو الاحداثي الحقيقي

الاحداثي الحقيقي-------------------> ابعاد الشاشة الحقيقية

احداثيات الماوس على الصورة-------------->أبعاد الصورة

فتنتج المعادلة التي تعطينا الاحداثي الحقيقي= (ابعاد الشاشة الحقيقية / أبعاد الصورة) * احداثسات الماوس على الصورة

قرأت المشاركة وأريد لفت الأنتباه لأمر

إذا كان المشروع متعلق بسطح المكتب فقط فنستطيع قراءة أبعاد الشاشة بالطريقة السابقة ولكن لن تفيد في بعض الحالات عند تشغيل البرامج التي تستخدم الدايركت وتصغر دقة الشاشة

لم أفهم القصد

فالألعاب عند تغيير دقة الشاشة فهي تغير بذلك أبعادها

فمثلا 800*600 هي الأبعاد التي ستغييرها اللعبة للشاشة ولسطح المكتب أيضا

وهذا مانلاحظه عند الخروج من اللعبة حيث ترجع اللعبة الشاشة إلى الوضع الافتراضي

أي إلى الأبعاد الافتراضية

تم تعديل بواسطه DreamNet
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
فالألعاب عند تغيير دقة الشاشة فهي تغير بذلك أبعادها

فمثلا 800*600 هي الأبعاد التي ستغييرها اللعبة للشاشة ولسطح المكتب أيضا

وهذا مانلاحظه عند الخروج من اللعبة حيث ترجع اللعبة الشاشة إلى الوضع الافتراضي

أي إلى الأبعاد الافتراضية

كلامك صحيح ولكن بأعتقادي عندما ستقرأ أبعاد شاشة عند تشغيل للعبة تعمل على الدايركت مثلاً 800*600 وكانت دقة سطح المكتب 1024*768 بكسل كمثال ،فستقرأها 1024*768 لأن اللعبة فعلياً لم تقم بتغيير دقة سطح المكتب ولكن أخذ مقطع من المساحة الموجودة ب 1024*768 وتبدأ من يسار أعلى الشاشة إلى 800*600 ،هذا والله أعلم ، يمكنك أختبار ذلك مستقبلاً.

أو تستخدم للحصول على ذلك الدايركت نفسه ،فلا أعرف عندكم فعندنا في الفوجول بيسك نستخدم المكتبة dx7vb.dll للحصول على الدقة الصحيحة.

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
كلامك صحيح ولكن بأعتقادي عندما ستقرأ أبعاد شاشة عند تشغيل للعبة تعمل على الدايركت مثلاً 800*600 وكانت دقة سطح المكتب 1024*768 بكسل كمثال ،فستقرأها 1024*768 لأن اللعبة فعلياً لم تقم بتغيير دقة سطح المكتب ولكن أخذ مقطع من المساحة الموجودة ب 1024*768 وتبدأ من يسار أعلى الشاشة إلى 800*600 ،هذا والله أعلم ، يمكنك أختبار ذلك مستقبلاً.

أو تستخدم للحصول على ذلك الدايركت نفسه ،فلا أعرف عندكم فعندنا في الفوجول بيسك نستخدم المكتبة dx7vb.dll للحصول على الدقة الصحيحة.

حسب كلامك أخي العزيز فاني لن أستطيع تشغيل لعبة بأبعاد أكبر من أبعاد الشاشة الحالية أو بكلام أدق بأبعاد سطح المكتب

عند تشغيل اللعبة full screen على الديركت اكس أو الOpenGL فهذا يتطلب انشاء نافذة تغطي الشاشة بالأبعاد المختارة

ولكي لا يحدث اختلاف

فان الديركت اكس أو الOpenGL يقومان في الأول بتغيير ابعاد الشاشة بنفس الأبعاد المختارة

ثم بعد الخروج من اللعبة ترجع الأبعاد إلى الوضع الافتراضي

ولا أظنك لم تلاحظ يوما بعد تشغيلك للعبة بابعاد اقل من ابعاد الشاشة الافتراضية تغيير اماكن الأيقونات على سطح المكتب

وهذا دليل على حدوث تغيير لابعاد سطح المكتب أيضا :)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
ولا أظنك لم تلاحظ يوما بعد تشغيلك للعبة بابعاد اقل من ابعاد الشاشة الافتراضية تغيير اماكن الأيقونات على سطح المكتب

وهذا دليل على حدوث تغيير لابعاد سطح المكتب أيضا

وأيضاً ستلاحظ عند تشغيلك للعبة بابعاد اقل من ابعاد الشاشة الافتراضية فإن أماكن الأيقونات لم تتغير.

على كل حال التجربة أكبر برهان ،أنا عملت الآن برنامج يخزن أبعاد الشاشة كل 1 ثانية وقمت بتشغيله ثم شغلت لعبة بدقة أقل من دقة الشاشة ،وبعد أغلاق اللعبة وجدت أن أبعاد الشاشة لم تتغير ،فما قولك .

حيث أستخدمت الدالة التابعة للفوجول للحصول على الأبعاد وهي كمايلي:

X = Screen.Width \ Screen.TwipsPerPixelX
Y = Screen.Height \ Screen.TwipsPerPixelY

ويمكنك تجريب ذلك بطريقتك الخاصة

وأيضاً لكي نبعد الشك بالدالة قمت بتجريب ألتقاط صورة بأبعاد سطح المكتب الحقيقية واللعبة شغالة بأبعاد أقل (يعني على كلامك مغيرة للأبعاد) فنتجت عندي صورة سطح المكتب كاملة وعليها صورة اللعبة بأبعادها الأقل وبدأت من يسار أعلى الشاشة 0 ،0 كما ذكر سابقاً

تم تعديل بواسطه عبد العزيز اليوسفي
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

:)

لا أعرف أشك في اللعبة الآن

لقد قمت بتجربة كل ماقلت والنتيجة معاكسة لكل ماذكرته بل أكدت لي صحة كلامي بالحرف الواحد

مع العلم أن الكود الذي أدرجته لا يعطي دائما نتائج دقيقة

على الأقل بالنسبة لي

أفضل استعمال دالة الAPI المقترحة لهذا الأمر وهي GetSystemMetrics

انسخ الكود
  1. [color= #800000;]Private[/color] [color= #800000;]Declare[/color] [color= #800000;]Function[/color] GetSystemMetrics Lib [color= #ff0000;]"user32.dll"[/color] [color= #66cc66;]([/color]ByVal nIndex [color= #800000;]As[/color] [color= #800000;]Long[/color][color= #66cc66;])[/color] [color= #800000;]As[/color] [color= #800000;]Long[/color]
  2. [color= #800000;]Const[/color] SM_CXSCREEN = [color= #cc66cc;]0[/color]
  3. [color= #800000;]Const[/color] SM_CYSCREEN = [color= #cc66cc;]1[/color]
  4. x = GetSystemMetrics[color= #66cc66;]([/color]SM_CXSCREEN[color= #66cc66;])[/color]
  5. y = GetSystemMetrics[color= #66cc66;]([/color]SM_CYSCREEN[color= #66cc66;])[/color]
  6.  
  7.  

لكنك لم تجبني على سؤال:

اذا افترضنا أن الشاشة لا تتغير أبعادها

وكانت 800*600 مثلا وكنت أريد تشغيل لعبة بأبعاد 1024*768

هل سأستطيع؟

لا توجد مساحة كافية المفروض :) لان أبعاد الشاشة 800*600 فقط

كيف يتم ذلك؟

كي نبتعد على البرمجة وليجرب أي أحد ذلك

نقوم بتشغيل أي لعبة في ملء الشاشة ونضغط على زر Print Screen

ثم نفتح برنامج الفوتوشوب عند انشاء صورة جديدة وتعيين الClipboard

ستجد الأبعاد هي أبعاد اللعبة المختارة والمفروض أن تكون هي أبعاد الشاشة ككل

أو لمن لا يملك الفوتوشوب يمكنهم حفظ الصورة على برنامج الرسام ثم في التحقق من خصائص الصورة

سنجدها بكل تأكيد تحمل أبعاد اللعبة وليس كامل الشاشة

ولو كان الأمر صحيحا كما قلت لكانت عملية Print Screen ستعطينا أجزاء من سطح المكتب

طبعا هنا لم نضغط على Print screen+ alt التي تقوم بتصوير النافذة الفعالة فقط :)

أظن أننا تكلمنا كثيرا خارج الموضوع

بالتوفيق

تم تعديل بواسطه DreamNet
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
لكنك لم تجبني على سؤال: اذا افترضنا أن الشاشة لا تتغير أبعادها وكانت 800*600 مثلا وكنت أريد تشغيل لعبة بأبعاد 1024*768

هل سأستطيع؟ لا توجد مساحة كافية المفروض لان أبعاد الشاشة 800*600 فقط كيف يتم ذلك؟

أنا لم أقل أن الشاشة لا تتغير أبعادها ولكن قلت سطح المكتب لا يتغير أبعاده في مثالنا هذا (لعبة تعمل على الدايركت) ،فلو كانت أبعاد سطح المكتب أصغر من أبعاد اللعبة وأردت جلب أبعاد سطح المكتب فسترى أن الأبعاد لم تتغير ،وإذا أخذنا صورة لسطح المكتب الأصغر سنجد أن الصورة للعبة أخذت ناقصة من اليمين والأسفل وبنفس أبعاد سطح المكتب .

وأنا قلت سابقاً:

أو تستخدم للحصول على ذلك الدايركت نفسه ،فلا أعرف عندكم فعندنا في الفوجول بيسك نستخدم المكتبة dx7vb.dll للحصول على الدقة الصحيحة
لأنني من زمن مرت معي مشكلة بالأبعاد وحللتها بهذه الطريقة

بالنسبة للدالة GetSystemMetrics سأجربها غداً بعد الأفطار إن شاء الله على جهاز فيه ألعاب .

بالنسبة ل Print Screen فهو يأخذ الصورة لأبعاد الشاشة وليس لسطح المكتب وأنا جربت ذلك

ونحن نتكلم عن معرفة الأبعاد الصحيحة للصورة التي تظهر على الشاشة وليس بألتقاط صورة

وبرأي أن كل هذا النقاش هو من ضمن الموضوع

والله الموفق ..

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

جربت الدالة GetSystemMetrics وهي تعمل تمام وتعطي أبعاد الشاشة الحقيقية ،وبأستخدام الدالة السابقة ستكون الصورة الملتقطة صحيحة للمشروع.

ولكن الشيىء العجيب أن سطح المكتب لا تتغير أبعاده ،فعند ألتقاط صورة بنفس أبعاد سطح المكتب وهناك لعبة بدقة أصغر فسيظهر سطح المكتب كاملاً وعليه صورة اللعبة بأبعادها الأصغر ،وأعتقد أن هذا ليس بمحور الموضوع وكما قال الأخ DreamNet بأننا خرجنا بذلك عن الموضوع .

والله الموفق ..

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

السلام عليكم ورحمة الله وبركاته

محاولة مني لتطبيق مااستطعت استيعابه

واجهة برنامج العميل

شاشة الاتصال

post-23361-1221331341_thumb.png

سطح المكتب على واجهة البرنامج

post-23361-1221331361_thumb.png

الملفات التنفيذية:

Server.exe..zip

Client.exe..zip

الكود سورس:

Source.zip

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

من فضلك سجل دخول لتتمكن من التعليق

ستتمكن من اضافه تعليقات بعد التسجيل



سجل دخولك الان

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .