PDA

View Full Version : سوال: نمایش یک پیغام بصورت ویژه



hector2000
چهارشنبه 01 خرداد 1387, 13:29 عصر
با سلام خدمت دوستان
دوستان ما به مشکلی خوردیم که از اساتید تقاضای کمک دارم
مشکل از جایی شروع می شود که ما می خواهیم برای برنامه کنترل شبکه خودمان اقدام به نمایش یک پیغام بصورت ویژه بر روی کامپیوترهای کلاینت کنیم.ما می خواهیم این پیغام بر روی تمام پنجره ها جاری(حتی بازی ها) قرار بگیرد و نمایش داده شود.این کار را دقیقا برنامه ای بنام game port(که با ویژال سی mfc نوشته شده است) انجام میدهد که تمام تلاش ما برای انجام کاری مشابه این برنامه به نتیجه ای نرسیده.
البته ما هم در طول این مدت(سه ماه) بیکار ننشسته بودیم و در فارومهای مختلف (از جمله ماکروسافت) مشکلمان را مطرح کردیم و نمونه کدهای بسیاری را ازمایش کردیم که متاسفانه تا به امروز نتیجه مطلوبی دریافت نکردیم.
بعنوان نسختین روش ما سعی کردیم با استفاده از api پنجره پیغام را on top نگه داریم که متاسفانه ظاهر شدن چنین پنجره ای در حین اجرای بازی باعث از دست دادن فوکوس بازی شده و تقریبا از بازی بیرون می افتید(مثل وقتی که با استفاده از سه کلید معروف بخواهید پنجره taskbar manager را بیاورید) پس این راه به نتیجه نرسید

راه یعدی که ایده ان را یکی از مدیران سایت ماکروسافت و همچنین یکی از کاربران با سایقه سایت برنامه نویس به ما داد بدست اوردن پنجره فعال توسط api و چاپ پیغام با استفاده از api دیگر بر روی ان بود که مشکلاتی را هم این روش داشت
یکی از مشکلات این بود که در حین بازی از انجایی که صفحه نمایش بسرعت ریفرش می شود پیغام ما سریع پاک می شود،ما برای مقابله با این مشکل اقدام به ریفرش کردن پنجره پیغاممان هر یک میلی ثانیه کردیم که در حین بازی متاسفانه وضعیت چشمک زدن را پیدا می کند و نتیجه خوبی ندارد.

تنها راهی که به ذهنمان رسید این بود که با استفاده از یکسری برنامه جاسوسی برنامه game port را زیر نظر بگیریم و ببینیم این برنامه چکار می کند.بعنوان نخستین حرکت توسط یکی از برنامه های spy متوجه شدیم که این پیغام(که توسط برنامه game port ظاهر می شود) اصلا یک پنجره نیست و این برنامه ان را بعنوان یک پنجره شناسایی نمی کند.
قدم بعدی شناسایی api هایی بود که در ان لحظه توسط برنامه استفاده می شد بود که از طریق برنامه api spy موفق به شناسایی ان شدیم(در ادامه متن این شناسایی را می گذارم) ولی در کمال تعجب متوجه شدیم که این برنامه در لحظه مذکور دستور ایجاد یک فرم را اجرا می کند که واقعا ما گیج کرد.



77C30212:WriteFile(HANDLE:000000DC,LPDATA:0012D138 ,DWORD:00000029,LPDATA:0012D11C,LPDATA:00000000)
77C30218:WriteFile = 1 (msvcrt.dll)
77C30212:WriteFile(HANDLE:000000DC,LPDATA:0012D138 ,DWORD:0000002F,LPDATA:0012D11C,LPDATA:00000000)
77C30218:WriteFile = 1 (msvcrt.dll)
77C30212:WriteFile(HANDLE:000000DC,LPDATA:0012D048 ,DWORD:0000002C,LPDATA:0012D02C,LPDATA:00000000)
77C30218:WriteFile = 1 (msvcrt.dll)
77C30212:WriteFile(HANDLE:000000DC,LPDATA:0012D044 ,DWORD:00000027,LPDATA:0012D028,LPDATA:00000000)
77C30218:WriteFile = 1 (msvcrt.dll)
73DDF118:CreateDialogIndirectParamA(HANDLE:0040000 0,LPDATA:004F1E00,HWND:006603FA,LPDATA:73DD6745,DW ORD:00000000)
5AD779D2: lstrlenW(LPWSTR:5AD774EC:"Window")
5AD779D4: lstrlenW = 6 (uxtheme.dll)
755DD307: GetSystemDirectoryW(LPWSTR:0012BDDC,DWORD:00000105 )
755DD30D: GetSystemDirectoryW = 13 (msctfime.ime)
755DD33E: lstrlenW(LPWSTR:755C2440:"Msimtf.dll")
755DD344: lstrlenW = A (msctfime.ime)
755DD53F: GetModuleHandleW(LPWSTR:0012BDDC:"D:\WINDOWS\system32\Msimtf.dll")
755DD545: GetModuleHandleW = 0 (msctfime.ime)
73DDF11E:CreateDialogIndirectParamA = 5E0380 (MFC42.DLL)

حال از اساتید تقاضای کمک دارم امیدوارم که در این مورد بتوانید به ما کمک کنید
ببخشید یک مقدار طولانی شد

در پیوست:

تصویری از لحظه ای که پیغام توسط گیم پورت چاپ می شود(به رنگ قرمز)
نمونه برنامه در وی بی که از روش بدست اوردن پنجره فعال این کار را می کند

Nima_NF
چهارشنبه 01 خرداد 1387, 16:22 عصر
برای این کار باید روش های پیشنهادی مختلف را خودتان امتحان کنید تا با یکی از آن ها به جواب برسید.

خوب شما هم مثل برنامه فوق یک دیالوگ به صورت modeless با CreateDialogIndirectParam (وقتی که قالب پنجره در حافظه قرار دارد) یا سایر توابع این کار مثل CreateDialog بسازید به شکل زیر:

دقت کنید که ماهیت یک دیالوگ modeless با یک پیغام message box که از نوع Modal هست فرق می کند و شما می توانید آن را بدون از دست دادن فوکوس پنجره والد نمایش دهید، اما به شرط اینکه هندل پنجره دیالوگی را که می سازید به هندل پنجره فعال تغییر دهید تا به قولی پنجره فعال، والد دیالوگ شما شود.
با این کار شما می توانید دیالوگ را نمایش دهید و در عین حال با استفاده از SetFocus ، فوکوس را در همان پنجره اصلی ثابت نگه دارید و با استفاده از ارسال پیام WM_ACTIVATE در هر شرایطی پنجره را فعال نگه دارید.

نکته دیگر اینکه چون بازی ها با DirectX و OpenGL ساخته می شوند مثل یک لایه عمل می کنند که مدام روی پنجره توسط سخت افزار refresh می شوند پس به راحتی نمی توانید روی آن نمایش بدون لرزش داشته باشید چون که اول پیام های پنجره انجام می شوند و سپس روی آن پیام های بخش گرافیک که تعداد فریم های بالایی دارد، که اگر قرار باشد این کار امکان پذیر باشد باید توسط همان شتابدهنده های گرافیکی انجام شود.

پس فعلا همان روش دیالوگ را تست کنید.

hector2000
چهارشنبه 01 خرداد 1387, 16:42 عصر
با سلام
متاسفانه من در ویژال سی آنقدر وارد نیستم که بتوانم این کار را بکنم
ولی فکر می کنم از لحاظ عملکرد تفاوتی با اون نمونه کدی که گذاشتم نکنه
ایا امکان دارد شما نمونه کدش را بگذارید؟
یک مقدار عجیب و غریب شده واقعا این برنامه game port چگونه این کار را می کند(در صورت تمایل می توانم این برنامه را بفرستم)

Nima_NF
پنج شنبه 02 خرداد 1387, 02:39 صبح
با همان روشی که توضیح دادم عملی هست.

کار سختی نیست ،برای ساختن دیالوگ از نوع modeless مقاله زیر را مطالعه کنید(ضمنا در انتهای آن sample code نیز وجود دارد ):
Modeless Dialog Boxes in MFC (http://www.codersource.net/mfc_tutorial_part6.html)

در مقاله زیر در بخش Practical Learning: Using Dialog Box Methods دیالوگ modeless توضیح داده شده است:
Overview of Dialog Boxes (http://www.functionx.com/visualc/dialogboxes/introduction.htm)

تنها تغییراتی که باید انجام دهید به این شکل هست،
با هر تابع و API که مد نظر دارید هندل پنجره فوقانی را دریافت کنید مثلا در اینجا با GetForegroundWindow انجام شد.
پس از فراخوانی دیالوگ حتما فوکوس را از روی آن بردارید و بر روی پنجره اصلی ببرید.

برای مثال:



CMyDialog* pDialog;

void CMyWnd::OnSomeAction()
{
pDialog = new CMyDialog();

if(pDialog != NULL)
{

CWnd hWnd = GetForegroundWindow( );

pDialog->Create(IDD_MYDIALOG, hWnd);

pDialog->ShowWindow(SW_SHOW);

hWnd.SetFocus();
// Or--> hWnd.SetActiveWindow

}
}

در هنگام طراحی دیالوگ خواص آن را از طریق پنجره properties به این شکل تنظیم کنید:
style از نوع Pop up باشد
حتما Topmost آن True باشد.
می تواند فریم نیز داشته باشد و یا به شکل tools باشد.

موفق باشید

B-Vedadian
پنج شنبه 02 خرداد 1387, 07:47 صبح
شاید اینم کمک کنه که روی تمام پنجره های TopMost قرارش بدید:


SetWindowPos(hWnd, 0,0,0,0,HWND_TOPMOST)

hector2000
پنج شنبه 02 خرداد 1387, 10:21 صبح
با سلام
چرا می بایستی دیالوگ از نوع modeless باشد؟(نوع معمولی نمیشه؟)
من گزینه topmost را پیدا نکردم

Nima_NF
پنج شنبه 02 خرداد 1387, 14:20 عصر
در دیالوگ های modeless همزمان می توانید بین آن دیالوگ و سایر دیالوگ های اصلی و همین طور پنجره اصلی حرکت کنید. اما در نوع modal مانند پیغام خطاها تا زمانی که از دیالوگ خارج نشوید نمی توانید به پنجره والد آن برگردید و اعمال پنجره والد تا زمان برگشتن مقدار از تابع فراخوانی دیالوگ به حالت تعلیق باقی می ماند و در نتیجه در بازی ها با خطا یا عمل pause روبرو می شوید.

برای topmost یا از طریق dialog designer این کار را انجام دهید (که به صورت عکسی ضمیمه کردم) و یا از طریق کد با SetWindowPos که در پست قبل دوستان اشاره کردند.

hector2000
پنج شنبه 02 خرداد 1387, 14:43 عصر
با تشکر از شما دوست عزیز ولی بخاطر اینکه ما می خواهیم یک برنامه compatible با نسخه های ویندوز درست کنیم بنابراین از visual c++6 استفاده می کنیم(و متاسفانه این مجموعه ide ضعیفی برای این کارها داره و این گزینه را نداره)
اقا رک و پوست کنده عرض می کنم واقعا کار کردن با ویژال سی دردسره (واقعا پیر شدیم)
تازه با اینکه اینقدر ناز و فس داره بازم یا همراهش باید یک dll باشه و یا اینکه dll را خودش نگه داره و حجم برنامه را افزایش دهد.ولی برای من باعث تعجب است که چطور زبان دلفی این همه قر و فر نداره؟ و برنامه هایی که میسازه به هیچ چیز نیاز نداره!(دست مریزا بورلند)

Nima_NF
جمعه 03 خرداد 1387, 01:08 صبح
شما با VC++ 2005 می توانید برنامه ای بنویسید که از ویندوز 95 تا vista قابل اجرا باشد، شرط آن نیز تعریف هدر فایل مخصوص پایین ترین نسخه سیستم عامل موردنظر هست.(که قبلا توضیح دادم)

اکثر نرم افزار های قدرتمند نیز مستقیما با win32 نوشته می شوند (برنامه نویسی win32 بسیار سخت تر از MFC هست ) و در آن همه کارها باید با کد توسط خودتان انجام شود و دیگر کلاس آماده نیز در دسترس نیست.
چرا ؟ چون این برنامه نویسی Native هست و کسی که Performance می خواهد یا در آینده قابلیت پورت آن به سیستم عامل دیگر را می خواهد باید به سراغ آن بیاید و سختی آن را نیز به جان بخرد. و نیازمندی آن نیز مطالعه بسیار هست.
از نظر من کسی که می خواهد درست برنامه نویسی کند باید چندین سال بر روی یک زبان برنامه نویسی تمرکز کند و آن را ادامه دهد تا قادر به انجام کارهای مورد نظرش باشد.

دلفی دردسر کمتری دارد چون برای ساده کردن برنامه نویسی ایجاد شده است و از نظر من و خیلی از برنامه نویسان قابل مقایسه با ++C نبوده و نیست. کسی که می خواهد برای ویندوز ساده برنامه بنویسد به جای ++C باید به سراغ #C برود.

hector2000
جمعه 03 خرداد 1387, 01:25 صبح
با تشکر از شما
متاسفانه نمونه کدی که دادید هم افاقه نکرد و به جواب نرسیدیم(باز هم چشمک)
اگر خدا بخواهد فردا برروی شیوه directx کار می کنم تا ببینم امیدی هست یا خیر
با در نظر گرفتن مشکلات و سختیهایی که ویژال سی دارد فکر می کنم که دیگه دنبالش نرم
(لقب ما را باید بگذارند کلاغ بی خانه چون هی از این شاخه به اون شاخه می پریم ولی امید دارم روزی زبان برنامه نویسی محبوبم را پیدا می کنم.فعلا می خوام یک مقدار روی دلفی کار کنم)
موفق باشید