none
Console.WriteLine to command line RRS feed

  • שאלה

  • שלום לכולם!

    יש לי תוכנית שמפעילים אותה דרך הcommand line. התוכנית נכתבה בC# והיא מסוג Application. כדי שהקונסול יכתב לcommand הוספתי את הקוד הבא:

            [DllImport("Kernel32.dll")]
            private static extern bool AttachConsole(int processId);
            private static void AttachProcessToConsole()
            {
                AttachConsole(-1);
            }
            [STAThread]
            static void Main(string[] args)
            {              
                if (args.Count() != 4)
                {
                    AttachProcessToConsole();  
                    Console.WriteLine("test.exe version " + CGRegistry.getCGEncryptedRegValue("CG_CARDED_VERSION") + "\nUsage: test.exe " + 
                        "<password> <test> <test> <test>");
                    return;
                }

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

    אודה מאוד לכל מי שיביא רעיון לפתור את הבעיה!!!



    pnina

    יום ראשון 19 ינואר 2014 08:39

תשובות

  • טוב אצלי הכל עובד :-)

    יש לי אפליקציה קטנה מאוד שמבצעת את מה שאת רוצה. אני אנסה להגיע לכתוב בלוג יותר ארוך בנושא ובינתיים אני אשים לך הסבר מלא מקוצר (קצר אבל מלא) כיצד ומה עשיתי

    לאפליציה יש 3 צורות שונות להרצה:

    1. הרצה עם GUI

    2. הרצה כ CONSOLE

    3. הרצה תחת ממשק ה SHELL של CMD

    * אופן ההרצה נקבע לפי הפרמטר שמכניסים בקריאה ליישום שלנו.

    הפיתוח:

    1. יצרתי אפליקציה מסוג windows forms

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

    2. ייבאתי את המתודות החיצוניות על ידי שימוש ב DLL המתאים כמו שהראתי מעל ואת כבר ביצעת יפה

    3. הכנתי בדיקת תנאי פשוטה של הפרמטר שלנו בעזרת IF

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

    אם הפרמטר שווה ל CONSOLE אז:

    3.1 אני מגדיר פרמטר IntPtr כמו שביצעת מעל

    3.2 מגדיר פרמטר INT שיקבל את ה ID של ה THREAD

    3.3 נעזר במתודה GetWindowThreadProcessId על מנת לקבל את ה ID של ה THREAD שלנו

    3.4 מגדיר אלמנט Process בעזרת Process.GetProcessById והשימוש ב ID שמצאנו מעל

    עתה אני מבצע בדיקת תנאי נוספת פנימית: האם שם התהליך שלנו הוא cmd ז"א process.ProcessName

    אם כן אז אנחנו לא צריכים להפעיל CONSOLE חדש, מכיוון שאנחנו כבר עובדים תחת CMD ולכן אני נעזר ב AttachConsole ומחבר את התהליך הנוכחי אל ה CONSOLE.

    אם שם התהליך שלנו שונה אז אני פותח CONSOLE חדש בעזרת AllocConsole

    בסיום התנאי האחרון (הפנימי) אני צריך לשחרר את ה CONSOLE על ידי FreeConsole

    ...

    זה כל הסיפור. אני מקווה שהכל מובן... אם לא אנא צייני היכן ניתקעת (אצלי זה עובד נהדר)

    And here is the code hidden in white color :-)
    I highly recommend not to peek before you invest at least two hours to write alone. You have the whole process up!
    אני מאוד ממליץ לא להציץ לפני שאת משקיעה לפחות שעתיים לכתוב לבד. יש לך את כל התהליך למעלה!
                string mode = args.Length > 0 ? args[0] : "g";
    
                if (mode == "g")
                {
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    Application.Run(new Form1());
                }
                else if (mode == "console")
                {
                    IntPtr _ptr = GetForegroundWindow();
                    int _u;
                    GetWindowThreadProcessId(_ptr, out _u);
                    Process _process = Process.GetProcessById(_u);
    
                    if (_process.ProcessName == "cmd")    //Is the uppermost window a cmd process?
                    {
                        AttachConsole(_process.Id);
                        // כאן את יכולה לבצע מה שאת רוצה
                        Console.WriteLine(@"You started from an existing console.");
                        // כאן את יכולה להישתמש ברעיון של שליחת דימוי של לחיצה על הכפתור על מנת לחזור ליישום המקורי
                        SendKeys.SendWait("{ENTER}"); 
                    }
                    else
                    {
                        AllocConsole();
                        // כאן את יכולה לבצע מה שאת רוצה
                        Console.WriteLine(@"You want console mode.  Here's a new console.");
                        // אם תורידי את השורה הבאה אז האפליקציה תיסגר כמו שרצית ואם את רוצה את יכולה להמתין למשתמש
                        // אבל את לא חייבת להמתין לו
                        Console.ReadLine();
                    }
                    FreeConsole();
                }
    

    אני מקווה שזה נותן לך את כל מה שאת צריכה :-)


    [Personal Site] [Blog] [Facebook]signature

    יום שני 20 ינואר 2014 17:29
    מנחה דיון
  • ברור שהוא סוגר את היישום.
    זה בדיוק מה שהבנתי שאת רוצה לבצע, ואת יישמת את זה בדיוק כמו שהתכוונתי :-) 

    לפי מה שהבנתי הבעיה שלך שהיישום נתקע במצב פעיל במקום להיסגר בסיום.

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


    [Personal Site] [Blog] [Facebook]signature

    יום שני 20 ינואר 2014 07:13
    מנחה דיון
  • אני אנסה לעבור על זה יותר מאוחר בערב אבל בינתיים אולי הנקודות הבאות יעזרו לכון לפתרון:

    1. ישנה אפשרות לעבוד עם AllocConsole כדי לפתוח חלון CONSOLE חדש עם או בלי לבצע חיבור של היישום הנוכחי.

    2. ישנה אפשרות לשחרר את ה CONSOLE שביצענו לנו חיבור על ידי שימוש ב FreeConsole

    * שני אלו כמובן מתודות של kernel32.dll

    * אם את יכולה לצרך את הפרוייקט יהיה יותר קל להבין ולתת ייעוץ/עזרה (בקישור ישיר להורדה ולא באתר שמחייב רישום אם אפשר)


    [Personal Site] [Blog] [Facebook]signature

    יום שני 20 ינואר 2014 08:24
    מנחה דיון
  • טוב חזרתי :-)

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

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

    2. טוב מתחילים: שלב ראשון את חייבת לעבור לעומק על הבלוג הבא
    http://ariely.info/Blog/tabid/83/EntryId/126/Closing-Main-Form-Without-exit-the-application.aspx
    אני מפציר בך לא לעבור ישירות לפתרון הסופי אלא לעבור ולהבין כל מילה בקישור!

    3. הקדמה והקשר לקישור מעל (דעה אישית):

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

    מה ההבדל בין אפליציית CONSOLE לבין אפליקציית Windows Forms או כל סוג של פרוייקט ספציפי שאנחנו בונים בשלב ראשון של תילת העבודה? באופן עקרוני אין הבדל פרט לכך שבכל סוג פרוייקט או טכנולוגיה מישהו הכין לנו תשתית מתאימה שאנחנו עושים בה שימוש. תשתית שהיא בעצם קוד לכל דבר. לכן אם רוצים אפשר תמיד לפתח הכל מאפס בעזרת תוכנות כמו notepad ואין חשיבות בכלל לסוג הפרוייקט. מעשית אנחנו רוצים לחסוך כמובן בזמן ולכן נעזרים בתבניות מוכנות של קודים וקוראים להם "סוד פרוייקט" או "סוג אפליקציה". הקישור מעל מסביר מעט מאוד ונותן דוגמה למאחורי הקלעים של תבנית מסוג "אפליקציית windows forms". זה בדיוק אותו חלק מאחורי הקלעים שקשור גם לבעיה שאת מציגה. אנחנו רוצים לפתח אפליקציה שתתנהג כאפליקציה חלונאית במצב אחד וכאפליקצית CONSOLE ועלינו לוודא שהדברים יעבדו ביחד...

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

    * אני שוב חוזר על כך שלדעתי את חייבת לעבור לעומק על הקישור מעל אם את רוצה להבין את הרעיון הבסיסי של מה קורה מאחורי הקלעים כשאנחנו מפעילים אפליקציית windows forms!


    [Personal Site] [Blog] [Facebook]signature

    יום שני 20 ינואר 2014 17:11
    מנחה דיון
  • היי

    1. זו בדיוק הצורה שבה AttachConsole עובד. הוא מבר לנו את ה PROCESS ל command window (במקרה של -1 ל command window ממנו ההוראה הופעלה). בסיום ה CONSOLE ממתין לתגובת המשתמש.

    הפתרון פשוט: שימוש ב KILL בסיום התהליך

    תצרפי גם את המתודה GetForegroundWindow

    [DllImport("user32.dll")]
    private static extern IntPtr GetForegroundWindow();

    ואז תוכלי בקוד עצמו להגדיר אלמנט IntPtr

    תוסיפי גם את המתודה GetWindowThreadProcessId

    [DllImport("user32.dll", SetLastError = true)]
    private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

    ואז תוכלי בקוד לקבל את הנתון של מספר ה ID של התהליך הנוכחי

    עתה תוכלי לבצע את כל מה שאת רוצה כולל ה AttachConsole ל ID הנוכחי ולא בצורה כללית בעזרת שימוש ב -1

    ואז תוכלי לבצע KILL ל PROCESS הנוכחי

    2. אני לא מבין כיצד הגעת למצב שאת צריכה תהליך כל כך מורכב. אני ממלית לחשוב על תכנון האפליקצייה שוב.


    [Personal Site] [Blog] [Facebook]signature

    יום ראשון 19 ינואר 2014 12:45
    מנחה דיון
  • ראיתי אנשים עם ניסיון של 30 שנים שלא יודעים ולא יכולים לעשות מה שאת עושה :-)

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

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

    * עם כל זה לימוד בתחילת הדרך צריך להיות מסודר. לימוד הבסיס בצורה מסודרת וטובה הוא הדבר הכי חשוב שיש לדעתי בשלבי הלימוד. אחר כך עוברים כבר ללימוד עצמי בהתאם לכיוונים שמוצאים יותר מושכים.


    [Personal Site] [Blog] [Facebook]signature

    יום שלישי 21 ינואר 2014 16:58
    מנחה דיון

כל התגובות

  • הבעיה נדמה לי בתוכנית Test.exe.

    אגב, לשם מה כל העסק? בשביל להפעיל שורת פקודה עם ארגומנטים אפשר להשתמש בProccess.Strat.

    אז למה?

    יום ראשון 19 ינואר 2014 10:14
  • לא, התוכנית עובדת מעולה, ההפעלה של זה חייבת להעשות בצורה הנ"ל, אין לי אפשרות לשנות אותה, זה תוכנה שכבר תוקנת אצל הלקוחות, אני רק צריכה לעשות שאחרי שמוצגת ההודעה הcommand line ישתחרר, אני אסביר שוב, ההתנהגות של הcmd  דומה כרגע כאילו רשמתי console.readline הוא מחכה שאקיש על מקש הenter, למרות שלא כתבתי את ה readline, אני רוצה שיתנהג בצורה הרגילה.אני יודעת שזה קורא בגלל הפונקציה AttachConsole אבל מצד שני אני לא יכולה לוותר על הפונקציה הזאתי כי בלעדיה לא רואים שום output

    pnina

    יום ראשון 19 ינואר 2014 10:34
  • הבנתי היטב את הבעיה, אם כי אני לא מכיר כלל את פונקציית הAPI הזו שהבאת (AttachProcessToConsole).

    לא הצעתי שתשני את Test.exe, אלא שתשני את הקוד הנוכחי. הנה מה התכוונתי:

    Process prc = new Process();
    prc.StandardOutput = xx;
    prc.StartInfo = new ProcessStartInfo("Test.exe", "version" + CGRegistry.getCGEncryptedRegValue("CG_CARDED_VERSION") + "\nUsage: test.exe " + "<password> <test> <test> <test>");
    prc.Start();

    מה רע בזה? 

    יום ראשון 19 ינואר 2014 10:59
  • היי

    1. זו בדיוק הצורה שבה AttachConsole עובד. הוא מבר לנו את ה PROCESS ל command window (במקרה של -1 ל command window ממנו ההוראה הופעלה). בסיום ה CONSOLE ממתין לתגובת המשתמש.

    הפתרון פשוט: שימוש ב KILL בסיום התהליך

    תצרפי גם את המתודה GetForegroundWindow

    [DllImport("user32.dll")]
    private static extern IntPtr GetForegroundWindow();

    ואז תוכלי בקוד עצמו להגדיר אלמנט IntPtr

    תוסיפי גם את המתודה GetWindowThreadProcessId

    [DllImport("user32.dll", SetLastError = true)]
    private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

    ואז תוכלי בקוד לקבל את הנתון של מספר ה ID של התהליך הנוכחי

    עתה תוכלי לבצע את כל מה שאת רוצה כולל ה AttachConsole ל ID הנוכחי ולא בצורה כללית בעזרת שימוש ב -1

    ואז תוכלי לבצע KILL ל PROCESS הנוכחי

    2. אני לא מבין כיצד הגעת למצב שאת צריכה תהליך כל כך מורכב. אני ממלית לחשוב על תכנון האפליקצייה שוב.


    [Personal Site] [Blog] [Facebook]signature

    יום ראשון 19 ינואר 2014 12:45
    מנחה דיון
  • תודה, אני אנסה להכניס את זה לקוד שלי.

    pnina

    יום ראשון 19 ינואר 2014 13:08
  • הי,

    האם יש אפשרות שתראה לי דוגמא איך אני משתמשת בזה?

    תודה מראש!!


    pnina

    יום ראשון 19 ינואר 2014 13:17
  • הי,

    הוספתי את זה בצורה הנ"ל:

    [DllImport("user32.dll", SetLastError = true)]
            private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
            [DllImport("user32.dll")]
            private static extern IntPtr GetForegroundWindow();
            [DllImport("Kernel32.dll", SetLastError = true)]
            private static extern bool AttachConsole(int processId);
          /*  private static void AttachProcessToConsole()
            {
                AttachConsole(-1);
            }*/
            [STAThread]
            static void Main(string[] args)
            {
                if (args.Count() != 4)
                {
                IntPtr ptr = GetForegroundWindow();
                int u;
    
                GetWindowThreadProcessId(ptr, out u);
                Process process = Process.GetProcessById(u);
    
                AttachConsole(process.Id);
               
               
     
                    Console.WriteLine("test.exe version " + CGRegistry.getCGEncryptedRegValue("CG_CARDED_VERSION") + "\nUsage: test.exe " + 
                        "<password> <test> <test> <test>");
    
                   process.Kill();
                 

    אך מה שקורה זה , שהוא סוגר את התוכנית.

    תודה מראש על עזרה!!!


    pnina

    יום שני 20 ינואר 2014 06:50
  • ברור שהוא סוגר את היישום.
    זה בדיוק מה שהבנתי שאת רוצה לבצע, ואת יישמת את זה בדיוק כמו שהתכוונתי :-) 

    לפי מה שהבנתי הבעיה שלך שהיישום נתקע במצב פעיל במקום להיסגר בסיום.

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


    [Personal Site] [Blog] [Facebook]signature

    יום שני 20 ינואר 2014 07:13
    מנחה דיון
  • קודם כל תודה רבה על העזרה הרבה!!

    אני מפתחת מערכת שתופעל אצל לקוחות באמצעות מערכות אוטומטיות שיפעילו אותה ובצורה ידנית ע"י ה command line.

    התוכנה פועלת באופן הבא: קודם כל ישנה תוכנת התקנה שהלקוח מתקין ,ומכאן ואילך הוא מפעיל אותה באמצעות ה command line, לצורך ההפעלה הוא חייב לתת 4 ארגומנטים לדוגמא: test.exe a b c d , המערכת בודקת האם הגיעו 4 ארגומנטים, אם כן, המערכת מתחילה לפעול בצורה תקינה, אם לא הגיעו 4 ארגומנטים, המערכת נותנת הודעה שחסרים ארגומנטים ונותנת מידע על הארגומנטים החסרים.

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

    הפרויקט מוגדר כ Windows Application וזאת אסור לי לשנות .משום כך היתה לי בעיה שכשכתבתי Console.WriteLine הוא לא יצא ל command line לשם כך הוספתי את הפונקציה AttachConsole שפתרה לי את הבעיה , אך נוצרה בעיה נוספת והיא ההמתנה ללחיצה על מקש ה Enter, ניסיתי לפתור שוב פעם את הבעיה ע"י שליחה יזומה באופן הבא:

    SendKeys.SendWait("{ENTER}")

    אך הפרויקט לא התקמפל , ואז ניסיתי את הדרך שאתה המלצת וזה סגירת ה process הבעיה היא

    שהcommand line נסגר כליל במקום שרק הפעולה של ההודעה תשתחרר והתוכנית תסתיים בצורה מסודרת.

    מקווה שהסברתי את עצמי טוב, אם לא אנסה שוב...

    תודה מראש!!!


    pnina

    יום שני 20 ינואר 2014 07:36
  • אני אנסה לעבור על זה יותר מאוחר בערב אבל בינתיים אולי הנקודות הבאות יעזרו לכון לפתרון:

    1. ישנה אפשרות לעבוד עם AllocConsole כדי לפתוח חלון CONSOLE חדש עם או בלי לבצע חיבור של היישום הנוכחי.

    2. ישנה אפשרות לשחרר את ה CONSOLE שביצענו לנו חיבור על ידי שימוש ב FreeConsole

    * שני אלו כמובן מתודות של kernel32.dll

    * אם את יכולה לצרך את הפרוייקט יהיה יותר קל להבין ולתת ייעוץ/עזרה (בקישור ישיר להורדה ולא באתר שמחייב רישום אם אפשר)


    [Personal Site] [Blog] [Facebook]signature

    יום שני 20 ינואר 2014 08:24
    מנחה דיון
  • תודה על התשובה,

    1)לצערי לא אוכל לצרף את הפרויקט כי הוא מאובטח וסודי.

    2)ניסיתי את שתי הדוגמאות שנתת אך שניהם לא עזרו :(

    תודה מראש


    pnina

    יום שני 20 ינואר 2014 09:13
  • טוב חזרתי :-)

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

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

    2. טוב מתחילים: שלב ראשון את חייבת לעבור לעומק על הבלוג הבא
    http://ariely.info/Blog/tabid/83/EntryId/126/Closing-Main-Form-Without-exit-the-application.aspx
    אני מפציר בך לא לעבור ישירות לפתרון הסופי אלא לעבור ולהבין כל מילה בקישור!

    3. הקדמה והקשר לקישור מעל (דעה אישית):

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

    מה ההבדל בין אפליציית CONSOLE לבין אפליקציית Windows Forms או כל סוג של פרוייקט ספציפי שאנחנו בונים בשלב ראשון של תילת העבודה? באופן עקרוני אין הבדל פרט לכך שבכל סוג פרוייקט או טכנולוגיה מישהו הכין לנו תשתית מתאימה שאנחנו עושים בה שימוש. תשתית שהיא בעצם קוד לכל דבר. לכן אם רוצים אפשר תמיד לפתח הכל מאפס בעזרת תוכנות כמו notepad ואין חשיבות בכלל לסוג הפרוייקט. מעשית אנחנו רוצים לחסוך כמובן בזמן ולכן נעזרים בתבניות מוכנות של קודים וקוראים להם "סוד פרוייקט" או "סוג אפליקציה". הקישור מעל מסביר מעט מאוד ונותן דוגמה למאחורי הקלעים של תבנית מסוג "אפליקציית windows forms". זה בדיוק אותו חלק מאחורי הקלעים שקשור גם לבעיה שאת מציגה. אנחנו רוצים לפתח אפליקציה שתתנהג כאפליקציה חלונאית במצב אחד וכאפליקצית CONSOLE ועלינו לוודא שהדברים יעבדו ביחד...

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

    * אני שוב חוזר על כך שלדעתי את חייבת לעבור לעומק על הקישור מעל אם את רוצה להבין את הרעיון הבסיסי של מה קורה מאחורי הקלעים כשאנחנו מפעילים אפליקציית windows forms!


    [Personal Site] [Blog] [Facebook]signature

    יום שני 20 ינואר 2014 17:11
    מנחה דיון
  • טוב אצלי הכל עובד :-)

    יש לי אפליקציה קטנה מאוד שמבצעת את מה שאת רוצה. אני אנסה להגיע לכתוב בלוג יותר ארוך בנושא ובינתיים אני אשים לך הסבר מלא מקוצר (קצר אבל מלא) כיצד ומה עשיתי

    לאפליציה יש 3 צורות שונות להרצה:

    1. הרצה עם GUI

    2. הרצה כ CONSOLE

    3. הרצה תחת ממשק ה SHELL של CMD

    * אופן ההרצה נקבע לפי הפרמטר שמכניסים בקריאה ליישום שלנו.

    הפיתוח:

    1. יצרתי אפליקציה מסוג windows forms

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

    2. ייבאתי את המתודות החיצוניות על ידי שימוש ב DLL המתאים כמו שהראתי מעל ואת כבר ביצעת יפה

    3. הכנתי בדיקת תנאי פשוטה של הפרמטר שלנו בעזרת IF

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

    אם הפרמטר שווה ל CONSOLE אז:

    3.1 אני מגדיר פרמטר IntPtr כמו שביצעת מעל

    3.2 מגדיר פרמטר INT שיקבל את ה ID של ה THREAD

    3.3 נעזר במתודה GetWindowThreadProcessId על מנת לקבל את ה ID של ה THREAD שלנו

    3.4 מגדיר אלמנט Process בעזרת Process.GetProcessById והשימוש ב ID שמצאנו מעל

    עתה אני מבצע בדיקת תנאי נוספת פנימית: האם שם התהליך שלנו הוא cmd ז"א process.ProcessName

    אם כן אז אנחנו לא צריכים להפעיל CONSOLE חדש, מכיוון שאנחנו כבר עובדים תחת CMD ולכן אני נעזר ב AttachConsole ומחבר את התהליך הנוכחי אל ה CONSOLE.

    אם שם התהליך שלנו שונה אז אני פותח CONSOLE חדש בעזרת AllocConsole

    בסיום התנאי האחרון (הפנימי) אני צריך לשחרר את ה CONSOLE על ידי FreeConsole

    ...

    זה כל הסיפור. אני מקווה שהכל מובן... אם לא אנא צייני היכן ניתקעת (אצלי זה עובד נהדר)

    And here is the code hidden in white color :-)
    I highly recommend not to peek before you invest at least two hours to write alone. You have the whole process up!
    אני מאוד ממליץ לא להציץ לפני שאת משקיעה לפחות שעתיים לכתוב לבד. יש לך את כל התהליך למעלה!
                string mode = args.Length > 0 ? args[0] : "g";
    
                if (mode == "g")
                {
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    Application.Run(new Form1());
                }
                else if (mode == "console")
                {
                    IntPtr _ptr = GetForegroundWindow();
                    int _u;
                    GetWindowThreadProcessId(_ptr, out _u);
                    Process _process = Process.GetProcessById(_u);
    
                    if (_process.ProcessName == "cmd")    //Is the uppermost window a cmd process?
                    {
                        AttachConsole(_process.Id);
                        // כאן את יכולה לבצע מה שאת רוצה
                        Console.WriteLine(@"You started from an existing console.");
                        // כאן את יכולה להישתמש ברעיון של שליחת דימוי של לחיצה על הכפתור על מנת לחזור ליישום המקורי
                        SendKeys.SendWait("{ENTER}"); 
                    }
                    else
                    {
                        AllocConsole();
                        // כאן את יכולה לבצע מה שאת רוצה
                        Console.WriteLine(@"You want console mode.  Here's a new console.");
                        // אם תורידי את השורה הבאה אז האפליקציה תיסגר כמו שרצית ואם את רוצה את יכולה להמתין למשתמש
                        // אבל את לא חייבת להמתין לו
                        Console.ReadLine();
                    }
                    FreeConsole();
                }
    

    אני מקווה שזה נותן לך את כל מה שאת צריכה :-)


    [Personal Site] [Blog] [Facebook]signature

    יום שני 20 ינואר 2014 17:29
    מנחה דיון
  • לקח לי יותר זמן לכתוב את ההודעה כאן מאשר לכתוב את הקוד :-)

    [Personal Site] [Blog] [Facebook]signature

    יום שני 20 ינואר 2014 17:47
    מנחה דיון
  • תודה ענקית!!!!

    עברתי על הבלוג ועל כל מה שכתבת כאן,עזר לי מאוד ועכשיו הכל עובד FIXED!!!!

    שוב פעם, תודה על כל העזרה!!!


    pnina

    יום שלישי 21 ינואר 2014 06:48
  • בכיף, אני שמח שזה עזר פנינה :-)

    פנינה, עכשיו הגיע קצת עניין מינהלתי... הגיע התור שלך :-)

    אנא עיברי על כל השרשור, סמני את התשובה/תשובות בדרך, והצביעי עבור הודעות מועילות (אפשר גם לעבור על שרשורים אחרים בפורום, ללמוד מהן ולסמן הודעות מועילות). לסימונים יש כמה השלכות כמו (1) סגירת השרשור (2) נתינת נקודות למשתמש ששם את התגובות (לא שאפשר ללכת למכולת עם הנקודות אבל זה נחמד מאוד), (3) זה עוזר למי שמחפש תשובות לשאלות דומות להתמקד על הודעות שהיו התשובה הקודמת או חלק ממנה וכמובן למי שעובר בפורום להתמקד בהודעות מועילות.

    גלישה מהנה :-)


    [Personal Site] [Blog] [Facebook]signature

    יום שלישי 21 ינואר 2014 08:27
    מנחה דיון
  • תודה על הסימון וההצבעות, ואנא זיכרי לבקר גם בשאלות הבאות אבל די לבדוק אם את יכולה לעזור למישהו אחר בשאלות שלו :-)

    * אני בטוח מהתהליך כאן שאת יכולה לעזור לאחרים בהרבה מהשאלות שעולות כאן :-)


    [Personal Site] [Blog] [Facebook]signature

    יום שלישי 21 ינואר 2014 08:45
    מנחה דיון
  • אשתדל מאוד, הנסיון שלי  ב-NET הוא רק בן חודש...

    pnina

    יום שלישי 21 ינואר 2014 08:51
  • ראיתי אנשים עם ניסיון של 30 שנים שלא יודעים ולא יכולים לעשות מה שאת עושה :-)

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

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

    * עם כל זה לימוד בתחילת הדרך צריך להיות מסודר. לימוד הבסיס בצורה מסודרת וטובה הוא הדבר הכי חשוב שיש לדעתי בשלבי הלימוד. אחר כך עוברים כבר ללימוד עצמי בהתאם לכיוונים שמוצאים יותר מושכים.


    [Personal Site] [Blog] [Facebook]signature

    יום שלישי 21 ינואר 2014 16:58
    מנחה דיון