PDA

View Full Version : بحث در مورد حلقه پیغام . یا مشکل در کار یا حلقه پیغام



taze kar
یک شنبه 20 شهریور 1384, 21:14 عصر
با سلام خدمت همگی .
آقا تاپیک قبلی ما داشت کارش به جاهای خطرناک میکشید و اساتید فرمودند برای این قسمت یک تاپیک دیگه باز کنیم و ما هم چنین کردیم .

اصل مطلب :

این کد رو واسه حلقه پیغام مینویسم ولی اصلا" جواب نمیده .


MSG Message ;
While(GetMessage(&Message, NULL,0,0))
{
MessageBox(NULL,"New Message","",0);
}

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

با تشکر

Reza_K
دوشنبه 21 شهریور 1384, 10:03 صبح
دلیلی برای عدم نمایش MessageBox وجود ندارد، بجز اینکه پیغامی به پنجره شما ارسال نشود!

آیا فراخوانی ShowWindow قبل از رسیدن به Message Loop را فراموش نکرده اید؟

Blaster
دوشنبه 21 شهریور 1384, 10:38 صبح
سلام تازه جان ،
داری تر و خشک رو با هم می سوزونی!
اول از همه مقدار برگشتی تابع GetMessage رو چک کن ببین اگه 1- بود یعنی یه مشکلی هست . وشاید لازم باشه از برنامه خارج بشی.
دوما تا زمانی که WM_QUIT به برنامه ارسال نشه برنامه بسته نمیشه وچون شما روالی پنجره ای تعریف نکردین پس WM_QUIT هم ارسال نمیشه و برنامه باز میمونه!
سوما استفاده از تابع MessageBox حلقه رو بلوک می کنه واصلا عملی نیست از ابزار TRACE یا هرچیز مشابه به جایه MessageBox استفاده کن.

taze kar
دوشنبه 21 شهریور 1384, 13:13 عصر
نه من قبلش یک پنجره رو ایجاد کردم .
تابع MessageBox رو هم به عنوان مثال ذکر کردم . منظورم اینه که ظاهرا" اصلا" وارد بلوک حلقه نمیشه . انگار که توی همون تابع GetMessage گیر میکنه . یا یه چیزی تو این مایه ها
.با تشکر

seyedof
دوشنبه 21 شهریور 1384, 15:29 عصر
سلام
اول PeekMessage بکن که معلوم بشه پیغامی هست یا نه بعدا GetMessage کن. اینطوری برنامه Block میشه اگر پیغامی براش نیاد ولیکن اگر اول PeekMessage کنی فقط در صورتی که پیغامی بود بعدش GetMessage میکنی و...
ممنون علی

C++Lover
سه شنبه 22 شهریور 1384, 01:58 صبح
در ادامه گفته های دوستان :

تابع GetMessage یک Message از Message queue نخی (thread ای) که در حال حاضر کد از آن در حال اجراست خارج می کند. البته این تابع در صورت خالی بودن queue صبر می کند تا یک Message وارد شود. که بعدا با اجرای DispatchMessage این Message به پنجره مربوطه فرستاده میشود که می توان این Window Message در Window Procedure پنجره مربوطه مورد پردازش قرار داد.

در ضمن سیستم عامل مسئول فرستادن Window Message هایی از قبیل رویدادهای mouse یا keyboard یا غیره به thread مورد نظر می باشد. در ضمن می توان یک Message را بصورت دستی به یک پنجره فرستاد که در اینصورت آن Message در Thread Message Queue مربوطه قرار می گیرد. یا حتی می توان یک Message را بصورت مستقیم توسط PostThreadMessage به یک thread فرستاد.

حال فرض کنید که شما اصلا پنجره ای در thread تان تعریف نکرده اید یا تعریف کرده اید ولی نمایش نداده اید. آنگاه سیستم عامل هیچ گونه Message ای به حلقه پیام شما نمی فرستد. پس نباید انتظار اجرای MessageBox تان را داشته باشد.

حالا اگر این دستور را


PostThreadMessage (GetCurrentThreadId(), WM_SHOWWINDOW,0,0);

درست قبل از حلقه پیام قرار دهید در اینصورت یک Message در Thread Message queue شما قرار داده می شود و MessageBox شما فقط یک بار اجرا می شود.

در ضمن اگر طبق ادعای شما یک پنجره ایجاد کرده اید باید توجه کنید که:
1- باید پنجره را در همین thread ایجاد کرده باشید.
2- باید پنجره را نمایش داده باشید. ShowWindow

فقط این نکته را باید در نظر بگیرید که چون شما می گویید در GetMessage گیر می کند مطمئنا queue نخ جاری خالی است.

چون گفتی مخلفات زیاد باشه من هم زیاد نوشتم.
موفق باشی.

Inprise
سه شنبه 22 شهریور 1384, 11:22 صبح
و اگر هنوز مشکل داری روی GetMessage یک BreakPoint بگذار و کد رو اجرا کن ؛ بعد از ارسال پیام به برنامه ات اگر مقدار بازگشتی اش مثبت بود پیام رو گرفتی ، و اگر نبود پیام رو نگرفتی .

taze kar
سه شنبه 22 شهریور 1384, 18:46 عصر
با تشکر فراوان از همه .
خوشبختانه با راهنمایی های دوستان و اساتید مشکلم حل شد ولی چند تا دیگه اضافه شده .
1 : میتونیم چند تا Message Queue داشته باشیم ؟
2 : فرضا" برنامه ما پنجره نداره (ویا فعلا" نمایش نمیدیمش)چه جوری پیغام های موس رو دربافت کنیم ؟
3 : چه تفاوتی بین پیغام های یک سوکت(یا پیغام های خاص یک کلاس) و پیغام های موس وجود داره ؟ . و چه جوریمیشه از طریق حلقه پیغام اون ها رو دریافت کرد ؟
4 : اگر پیغام یک تایمر رو در صف پیغام ها قرار بدیم (پارامتر آخر تابع SetTimer رو NULL بزاریم) و برنامه فعالا" در حال انجام کاری باشه و نتونه از صف پیغان ها پیغام جدید رو بخونه آیا پیغام های تایمر حذف میشوند یا نه ؟چون اگه حذف نشوند زمان بندی بزنامه قات میشه .
از همگی ممنون//

و

و اگر هنوز مشکل داری روی GetMessage یک BreakPoint بگذار و کد رو اجرا کن .
رو اصلا" متوجه نشدم . اگه زحمتی نیست یه نیمچه توضیح بدین .........

C++Lover
چهارشنبه 23 شهریور 1384, 02:16 صبح
1: همانطور که در پست قبلی هم گفتم Message Queue مربوط به Thread می باشد و شما می توانید در یک Process چندین Thread داشته باشید که هر کدام Message queue خودشان را داشته باشند. اما آنچه مسلم است هر Thread فقط یک Message queue دارد.

2: بازهم همانطور که در پست قبل گفتم سیستم عامل رویدادهای mouse را فقط به پنجره ای می فرستد که mouse روی آن عمل می کند اما اگر منظور شما گرفتن تمامی رویدادهای mouse یا keboard می باشد روش کار فرق دارد. در اینصورت باید از HOOK استفاده کنید. مثلا با SetWindowsHookEx با پارامتر WH_MOUSE یک windows hook ساخته البته برای اینکه رویدادهای mouse تمام thread های مربوط به Desktop ای که thread جاری در آن اجرا میشود را بگیرید باید dll ای ساخته تا آن dll رویدادها را دریافت کند. بحث در مورد Hook ها مفصل است و بهتر است به MSDN مراجعه کنید.

3: ؟؟؟

4: WM_TIMER فقط وقتی در queue قرار می گیرد که queue خالی باشد و برنامه بیکار باشد. تمام پیام های تایمری که در زمان گرفتاری برنامه فرستاده می شوند از دست خواهند رفت و بدون توجه به تعداد این پیامها فقط یک پیام در queue قرار می گیرد. بنابراین هیچگونه ضمانتی برای دریافت حتمی یک تایمر در زمان دقیق و معین وجود ندارد. پس نباید برنامه را طوری طراحی کنید که در اینگونه موارد قات بزنه. در ضمن اگر از چند thread استفاده کنید و تایمر خود را در Thread آزاد دیگری قرار دهید اوضاع کمی بهتر می شود اما بازهم هیچگونه ضمانتی وجود ندارد. ( از اساتید محترم خواهش می کنم در صورتی که راه حل خوبی برای این مسئله سراغ دارند ما را هم در جریان بگذارند.)


(پارامتر آخر تابع SetTimer رو NULL بزاریم)

شاید فکر کرده اید اگر پارامتر آخر را به یک CALLBACK ست کنید اوضاع فرق می کند. اما اصلا اینطور نیست. در واقع وقتی شما این کار را میکنید بازهم WM_TIMER فرستاده می شود و این بار default window procedure است که این پیام را مورد پردازش قرار می دهد و تابع CALLBACK شما را صدا می زند. بنابراین همان آش و همان کاسه است.

موفق باشی.

Blaster
چهارشنبه 23 شهریور 1384, 10:25 صبح
در ادامه نوشته های C++Lover :

میتونیم چند تا Message Queue داشته باشیم ؟
بله می تونی ولی Thread باید از نوع UI Thread باشه نه Worker Thread ، چون Worker Thread نمی تونه Message Queue داشته باشه!


آیا پیغام های تایمر حذف میشوند یا نه ؟
نه ، هیچ پیامی حذف نمیشه فقط پیام Timer جدیدی ارسال نمیشه!

C++Lover
چهارشنبه 23 شهریور 1384, 13:22 عصر
بله می تونی ولی Thread باید از نوع UI Thread باشه نه Worker Thread ، چون Worker Thread نمی تونه Message Queue داشته باشه!


Blaster عزیز مثل اینکه سوء تفاهمی پیش آمده. ما در مورد ماهیت اصلی Thread صحبت می کنیم نه مدل Threading تو MFC.
اصلا همان Worker Thread ای که می فرمائید نمی تونه Message Queue داشته باشه در واقع یک Thread است و میتونه Message queue داشته باشه امتحانش هم مجانیه کاری نداره یک Message Loop توی همون Worker Thread درست کن اگه خواستی یک پنجره هم توش ایجاد کن یا اگر هم نخواستی با PostThreadMessage امتحانش کن ببین میتونه Message Queue داشته باشه یا نه.
فکر کنم documentation که برای MFC مطالعه کرده اید کمی شما را گمراه کرده است.

Blaster
چهارشنبه 23 شهریور 1384, 15:52 عصر
C++Lover عزیز ، این فقط یک نام گذاری ساده است .
شما به Thread ای که Message Loop نداره چی می گین ؟ و یا به Thread ای که Message Loop داره چی می گین؟
اگه اسم مشخصی داری بگو من هم همون رو استفاده می کنم.

C++Lover
چهارشنبه 23 شهریور 1384, 20:04 عصر
.
.
.
.
.
Thread
.
.
.
.
.