עזרה חברה...

MotiAd

New member
עזרה חברה...

היי. עדיין אותה בעייה. הנה הקוד שפותח שני תהליכים חדשים:
int main(){ DWORD num; BOOL parserproc, windowproc; PROCESS_INFORMATION pp, wp; STARTUPINFO psi, wsi; HANDLE event1h, event2h, event3h, event4h, processes_handles[2]; ofstream f("c:\\3.txt"); ZeroMemory(&psi, sizeof(psi)); ZeroMemory(&wsi, sizeof(wsi)); ZeroMemory(&pp, sizeof(pp)); ZeroMemory(&wp, sizeof(wp)); psi.cb = sizeof(psi); wsi.cb = sizeof(wsi); windowproc = CreateProcess("..\\Window\\Debug\\Window.exe", NULL, NULL, NULL, false, NULL, NULL, NULL, &wsi, &wp); f<<GetLastError()<<endl; parserproc = CreateProcess("..\\Parser\\Debug\\Parser.exe", NULL, NULL, NULL, false, NULL, NULL, NULL, &psi, &pp); f<<GetLastError()<<endl; f.close(); if (!parserproc || !windowproc){ GetStartupInfo(&psi); cout<<GetLastError()<<","<<parserproc<<","<<windowproc<<endl; cout<<"..\\Parser\\Debug\\Parser.exe"<<","<<"..\\Window\\Debug\\Window.exe"<<endl; cin>>num; return 0;} processes_handles[0] = wp.hProcess; processes_handles[1] = pp.hProcess; return 0; }​
העניין הוא שכשאני מפעיל אותם לפי הסדר ידנית הכל עובד תקין. (הולך לתיקייה ומריץ כל קובץ) יש רעיונות?
 

gilad_no

New member
הערות

קודם כל, מה השאלה בדיוק? דבר שני, מומלץ לשים את כל הנתיב (ואת שורת הפקודה) בתוך מחרוזת אחת (הארגומנט השני) ובראשון תמיד לשים NULL. לפעמים זה גורם לבעיות לא צפויות. ומה בדיוק הבעיה? לא נוצר לך היישום?
 

MotiAd

New member
וואלה, איך שכחתי את השאלה...

או קיי. הישום נוצר והכל. העניין הוא ששתי התהליכים שנוצרים מתקשרים ביניהם דרך מייל סלוטס. כששניהם נפתחים דרך הישום המרכזי ישום Window לא מצליח לפתוח את המייל סלוט שעליו הוא אחראי ומחזיר קוד 183 שאומר הקובץ כבר פתוח או משהו בסגנון. הישום השני Parser כן מצליח לפתוח את המייל סלוט שעליו הוא אחראי. לעומת זאת, כשאני מפעיל אותם ידנית, הולך ופותח כל אחד מהם אחד אחרי השני הכל בסדר גמור. (כשאני מפעיל ידנית את Parser לפני Window אז הבעייה שוב חוזרת בצורה הידנית) השאלה שלי היא: למה?!!!!!!?!?!?!?!
 

Milo M

New member
פתרון אפשרי

מוטי שלום יתכן שאתה צריך להוסיף השהיה בין הפתיחה של התהליך הראשון לשני תנסה להוסיף פקודת Sleep עם ערך 1000 = שניה ועם צריך תוסיף זמן. אנא ידע אותי זה פתר את הבעיה.
 

MotiAd

New member
אני גם חשבתי שזה יכול לעזור, אבל...

מה שקורה זה משהו אחר. אמנם בתחילה מה שבאמת עשיתי זה ליצור את המייל סלוטס בתהליך הראשי, לבדוק שהם לא תפוסים וכו', לסגור את הידיות אליהם ואז ליצור את התהליכים, חשבתי שהבעייה כאן כי אולי וינדוס לא סוגרת את הידיות של המייל סלוטס ואז הורדתי את היצירה שלהם בתהליך המרכזי. לא עזר בכלל.
 

gilad_no

New member
קוד לפתיחה

תכתוב כאן את השורה שבא אתה פותח את הסלוט (בשני היישומים). כמו כן, מי יוצר אותם? האבא שמריץ? תנסה קצת להבהיר בדיוק את סדר הפעולות כי התבלבלתי קצת.
 

MotiAd

New member
או קיי...

אז ככה. נכון לעכשיו האבא לא עושה שום כלום, הוא רק פותח שני תהליכים. הראשון שהוא פותח זה ה-Window.exe ואחרי בא Parser.exe. הקוד שבWindow הולך ככה: יש פונקציה ראשית שמפעילה מחלקה שהיא זאת שאחראית על כל הטררררם והנה הקוד בצורה מגעילה כי זה רק סקיצה:
COpenGLWindow::COpenGLWindow(GLint prm_xpos, GLint prm_ypos, GLint prm_height, GLint prm_width, string prm_title):fullscreen(false), active(true){ MSG msg; BOOL done=FALSE; DWORD num; for(int i=0; i<256;i++){keys = false;} ofstream f("c:\\2.txt"); event1 = CreateEvent(NULL, TRUE, FALSE, Event1Name); event2 = CreateEvent(NULL, TRUE, FALSE, Event2Name); event3 = CreateEvent(NULL, TRUE, FALSE, Event3Name); event4 = CreateEvent(NULL, TRUE, FALSE, Event4Name); ms1 = CreateMailslot(MailSlot1Name, 0, 0, NULL); f<<GetLastError()<<endl; SetEvent(event1); WaitForSingleObject(event2, INFINITE); ResetEvent(event2); ms2 = CreateFile(MailSlot2Name, GENERIC_WRITE, FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL); f<<GetLastError()<<endl; f.close();

והקוד שבParser הולך ככה, גם שם יש פונקציה ראשית שטוענת את המחלקה:
ofstream f("c:\\1.txt"); event1 = CreateEvent(NULL, TRUE, FALSE, Event1Name); event2 = CreateEvent(NULL, TRUE, FALSE, Event2Name); event3 = CreateEvent(NULL, TRUE, FALSE, Event3Name); event4 = CreateEvent(NULL, TRUE, FALSE, Event4Name); WaitForSingleObject(event1, INFINITE); ResetEvent(event1); ms1 = CreateFile(MailSlot1Name, GENERIC_WRITE, FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL); f<<GetLastError()<<endl; ms2 = CreateMailslot(MailSlot2Name, 0, 0, NULL); f<<GetLastError()<<endl; SetEvent(event2); f.close();​
והקוד שנמצא באבא הולך ככה:
int main(){ DWORD num; BOOL parserproc, windowproc; PROCESS_INFORMATION pp, wp; STARTUPINFO psi, wsi; HANDLE event1h, event2h, event3h, event4h, processes_handles[2]; ofstream f("c:\\3.txt"); ZeroMemory(&psi, sizeof(psi)); ZeroMemory(&wsi, sizeof(wsi)); ZeroMemory(&pp, sizeof(pp)); ZeroMemory(&wp, sizeof(wp)); psi.cb = sizeof(psi); wsi.cb = sizeof(wsi); windowproc = CreateProcess("..\\Window\\Debug\\Window.exe", NULL, NULL, NULL, false, NULL, NULL, NULL, &wsi, &wp); f<<GetLastError()<<endl; parserproc = CreateProcess("..\\Parser\\Debug\\Parser.exe", NULL, NULL, NULL, false, NULL, NULL, NULL, &psi, &pp); f<<GetLastError()<<endl; f.close(); if (!parserproc || !windowproc){ GetStartupInfo(&psi); cout<<GetLastError()<<","<<parserproc<<","<<windowproc<<endl; cout<<"..\\Parser\\Debug\\Parser.exe"<<","<<"..\\Window\\Debug\\Window.exe"<<endl; cin>>num; return 0;} processes_handles[0] = wp.hProcess; processes_handles[1] = pp.hProcess; return 0; }​
 

gilad_no

New member
הצעה:

נראה לי שיש בעיות הקשורות לסנכרון, וראיתי שניסית לפתור אותם עם ארועים. למה לא עם סמפור? תיצור את הסלוטים באבא, ובנוסף הוא ייצור סמפור. כל בן ייתחבר לסלוט שהוא צריך ולאחר מכן לסמפור. כאשר האבא יזהה ששני הבנים מחוברים, הוא יסתיים. נראה לי הרבה יותר אלגנטי.
 

MotiAd

New member
לא עזר משום מה... (ד"א)

אני בדרך לשיגעון. למרות שאני יצליח להחזיק את עצמי. קורים פה דברים לא הגיוניים בעליל. מייל סלוט אחד בכלל לא פתוח, וכשאני פותח אותו בתהליך Window.exe הוא אומר לי שהוא כבר פתוח. איך איך? תהרגו אותי. אהה וד"א. העניין הוא שהתהליכים האלו מדברים ביניהם באותם מייל סלוטס (אחד משמש לשליחה והשני לקבלה של נתונים בכל אחד בנפרד). פשוט כי זאת האופציה שהכי התאימה למימוש שאותו בחרתי.
 

gilad_no

New member
למה עם סלוטים?

למה לא עם WM_COPYDATA (שאני הכי אוהב - הכי בטוח והכי פחות בעיות) או עם PIPE רגיל? (או אפילו MAPPED FILE?)
 

MotiAd

New member
מספר סיבות...

האמת היא שעל וינדוס זה מהווה לי את ה-FIFO הכי נחמד. ועם PIPEים זה הרבה בלאגן שמסתבר שאולי היה שווה את כל העסק. תוכל בבקשה להרחיב רק בתיאוריה לגבי השימוש ב-WM_COPYDATA או MAPPED FILE? ד"א מצאתי גם קוד של לקוח שרת בשני תהליכים שכן עובד לי אני אבדוק אותו ואז נראה מה כדאי לשנות אצלי בקוד.
 

gilad_no

New member
ליישומים שלך יש חלון?

כי אם כן, זה הכי פשוט שבעולם. WM_COPYDATA היא הודעה מיוחדת שעובדת בין פרוססים. היא מעתיקה את המידע שאתה רוצה לשלוח למרחב של הפרוסס השני וכך אתה לא צריך לדאוג יותר מידי. MAPPED FILE זה בעצם מרחב זיכרון משותף. אם אתה עובד עם VS, יש את זה בצורה מאוד קלה להטמעה (בצורת הרחבה של VS) וזה בדיוק 3 שורות קוד. וגם בלי, אפשר להטמיע דיי בקלות. הדבר היחיד שיש לזכור זה לסנכרן עם מיוטקסים וארועים. כמו שאמרתי, WM_COPYDATA הוא הפיתרון הכי קל שיכול להיות ולא דורש ממך שום דבר מיוחד לדאוג לו. הדבר היחיד שהוא דורש זה שהיישום שלך יעבוד עם חלון. לגבי שרת\לקוח. בדר"כ מממשים את זה עם קובץ ממופה זיכרון, מיוטקס וארועים. להלן התהליך: כללי: - יצירת מיוטקס חופשי (לבקרה על כתיבה\קריאה לקובץ) - יצירת קובץ ממופה זיכרון עם הרשאות קריאה\כתיבה שרת: - מאזין לארוע "A". כאשר מתקבל ארוע כזה: - תופס מיוטקס - קורא מידע מהקובץ - משחרר מיוטקס - מפעיל ארוע "B" לקוח: - כאשר רוצה לשלוח מידע: - תופס מיוטקס - שולח מידע - משחרר מיוטקס - מפעיל ארוע "A" - ממתין לארוע "B" זאת דוגמה פשוטה וחד כיוונית. אם הלקוח גם אמור לקבל מידע מהשרת תשנה קצת את התהליך (אם תצטרך עזרה, תבקש).
 

gilad_no

New member
ועוד דבר

SLOTS בעיקר משמשים לתקשורת ברשת או לתקשורת בין שרת למספר לקוחות. אם אתה צריך IPC פשוט - בין 2 תהליכים ולא יותר, גם בMSDN ממליצים על PIPES. זה הרבה יותר פשוט.
 

MotiAd

New member
אהה. הבנתי והנה לנו...

העניין. התהליך הראשון הוא בעצם קונסול שבו כותב המשתמש פקודות התהליך מנתח אותן ומעביר את המידע הסופי והמנותח לתהליך השני שהוא בעצם חלון שמציג את התוצאות של הפקודות. עכשיו, אני גם חשבתי על זה אבל בעצם רציתי מן מכניזם שיאפשר לי לשלוח ודעות אינסוף לשרת ולא שהוא יחכה כל פעם לאירוע כזה או אחר. פשוט ברגע שיש הודעות לשלוח שולחים את כולן ולא מחכים לאף אחד. אם השרת עובד ככה או אחרת זה לא צריך לעניין אותי. בגלל זה הגעתי לעניין של סלוטס.
 

gilad_no

New member
אז בכלל זה פשוט אצלך

היישום הראשון יוצר חלון ותופס את WM_COPYDATA. היישום השני, מוצא את הידית לחלון של הראשון (ע"י FINDWINDOW) וכל פעם שיש לו ארוע, הוא שולח אותו בעזרת WM_COPYDATA וזהו זה. יותר מזה לא צריך כלום. רק תזכור שהמידע שמגיע דרך WM_COPYDATA - אסור לשמור אותו. אם אתה צריך אותו, תעתיק אותו ליישום שלך (לתוך משתנה חדש). דוגמא:
void OnCopyData(WPARAM wParam,LPARAM lParam) { COPYDATASTRUCT* pCopyData=(COPYDATASTRUCT)lParam; m_list.AddString((LPCSTR)(pCopyData->lpData)); } void main() { createwindow(..); messageloop(); } void main() { HWND hWnd=findwindow(..); CHAR szBuffer[128]; COPYDATASTRUCT CopyData; CopyData.lpData=szBuffer; for (...) { gets(szBuffer); CopyData.cbData=strlen(szBuffer)+1; SendMessage(hWnd,WM_COPYDATA,(WPARAM)NULL,(LPARAM)&CopyData); } }​
 

MotiAd

New member
כן, נכון...

תיארתי לעצמי שתעבוד עם SendMessage או PostMessage אבל אצלי התקשורת חייבת להיות דו כיוונית מכיוון שגם הקונסול רוצה לגבי מידע בשלבים שונים מהחלון.
 

gilad_no

New member
לא חייבים להחליף הכל

כדי לקבל מידע, תוכל לממש משהו אחר (MAPPED FILE? או משהו אחר...). זה לא קשור לשליחה. את זה עדיין תוכל לעשות עם WM_COPYDATA. עוד משהו שעלה לי עכשיו בראש: הלקוח (לא זה עם החלון), חייב להיות יישום עצמאי? מה לגבי COM SERVER או אפילו סתם DLL פשוט? זה יפתור לך המון בעיות. אם תפרט מה הפרוייקט אמור לעשות, אני אוכל לעזור לך להטמיע פיתרון הולם.
 

gilad_no

New member
לגבי COM

אם תעבוד עם COM, יהיה לך בכלל קל: אתה יכול גם לשלוח מידע עם מתודות ולקבל מידע עם ארועים. והכל יעבוד INPROCESS ויחסוך לך בעיות בין תהליכים.
 

MotiAd

New member
הבעייה נפתרה!!!....

או יותר נכון הכל עובד כמו שצריך בינתיים בלי אירועים ושאר מרעין בישין. שיניתי קצת את התפקוד עם המייל סלוטס. כל פעם כשהייתה הודעה הכנסתי אותה לתוך מערך תווים אבל משום מה הוא תיד הדפיס לי 0 שאמור להיות האיבר הראשון למרות שאז לא חשבתי ככה. עשיתי לולאה על המערך וראיתי שבאמת מתקבלת ההודעה. בכל מקרה, הפרוייקט הוא תוכנה להדמייה תלת מימדית שאני כותב ב-VC ו-GL. זה קוד פתוח וכו'. בחרתי לממש את זה ככה שהקלט יהיה דרך קונסול והתוצאות יוצגו על חלון נפרד שיהיה בלתי תלוי. היה ברור לי שזה יכניס קצת יותר מורכבות אבל לא נורא. הרעיון שלי היה לכניס כמה שפחות קוד תלוי וינדוס כי אני רוצה גם להגר את המערכת ללינוקס יוניקס, אבל מסתבר שזה לא כ"כ פשוט. ניסיתי לעבוד עם STL כמה שרק אפשר אבל אי אפשר לברוח מזה. תודה רבה לך גלעד על כל העזרה שהשקעת. !!!! שלך, מוטי. סביר להניח שאני יחזור עם עוד הרבה בעיות שאולי יצוצו.
 
למעלה