Windows Api Demos 1–Find all open windows and process id

28 באוגוסט 2012

תגיות: , ,
3 תגובות

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

היות שבזמן שעשיתי את זה ישבתי ליד חברי היקר אלעד כץ חטפתי על הראש כשכתבתי את ה – UI ב – Windows Foms, ולכן הדוגמאות יהיו ב – WPF, (אע”פ שהפוסט וההסברים יתמקדו במימוש ולא בהסברת ה – UI)

להורדת דוגמת הקוד.

נתחיל הפעם עם משימה פשוטה, נרצה להציג את רשימת כל החלונות הפתוחים בשולחן העבודה עם:

  • הכותרת של החלון.
  • ה – handle שלו (בפוסטים הבאים נראה שימוש נרחב במספר זה)
  • ה – Process Id שלו.
  • ה – Main Thread id שלו.

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

PInvoke מאפשר לנו להצהיר על פונקציות הכתובת בשפה אחרת (נניח ++C, C) ולהפעיל אותם ב – net.

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

מי שמתכוון לעבוד עם הפונקציות הללו, חשוב שיכיר את http://www.pinvoke.net/, שזהו אתר מדהים עם מימוש ודוגמאות להמון פונקציות.

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

בסדרונת הפוסטים הללו, נשתמש תמיד במחלקה בשם WindowsFunctions כדי להצהיר על הפונקציות של ה – api.

זה יראה כך:

internal static class WindowsFunctions

{

    private const string USER32 = "user32.dll";

 

    internal delegate bool EnumDelegate(IntPtr hWnd, int lParam);

 

    [DllImport(WindowsFunctions.USER32, EntryPoint = "GetWindowText", ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]

    internal static extern int GetWindowText(IntPtr hWnd, StringBuilder lpWindowText, int nMaxCount);

 

    [DllImport(WindowsFunctions.USER32)]

    [return: MarshalAs(UnmanagedType.Bool)]

    internal static extern bool IsWindowVisible(IntPtr hWnd);

 

    [DllImport(WindowsFunctions.USER32)]

    internal static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId);

 

    [DllImport(WindowsFunctions.USER32)]

    internal static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumDelegate lpfn, IntPtr lParam);

 

}

 

הפונקציה הראשונה שבה נרצה להשתמש תהיה EnumDesktopWindows שתקבל כפרטר:

  • מצביע ריק (ואז הכוונה לשולחן העבודה הנוכחי שלנו).
  • מצביע לפונקציה מסוג ה – Delegate שהגדרנו (היא תגיע למתודה עבור כל חלון).
  • ומצביע ריק נוסף.

בתוך המתודה של ה – delegate, נשתמש בפונקציית GetWindowText, ונשלח לה כפרמטר את המצביע לחלון (נקבל אותה מאחד המשתנים של ה – delegate).

בנוסף נשתמש בפונקצית GetWindowThreadProecessId שמקבלת מצביע לחלון, ומחזירה ב – out את ה – processId ובערך מוחזר את ה – main thread id.

 

נגדיר את המחלקה הבאה:

public class WindowData

{

    public string Title { get; set; }

    public long ProcessId { get; set; }

    public long ThreadId { get; set; }

    public IntPtr HWindow { get; set; }

}

 

כעת נגדיר את הממשק שאיתו נעבוד.

public interface IWindowService

{

    WindowData[] GetAllWindwosInDesktop();

}

 

(בפוסטים הבאים הממשק יגדל.)

כעת נגדיר את המימוש של הממשק.

public class WindowService : IWindowService

{

    public WindowData[] GetAllWindwosInDesktop()

    {

        var collection = new List<WindowData>();

 

        WindowsFunctions.EnumDelegate filter = delegate(IntPtr hWnd, int lParam)

        {

            StringBuilder strbTitle = new StringBuilder(255);

            int nLength = WindowsFunctions.GetWindowText(hWnd, strbTitle, strbTitle.Capacity + 1);

            string strTitle = strbTitle.ToString();

 

            if (WindowsFunctions.IsWindowVisible(hWnd) && !string.IsNullOrEmpty(strTitle))

            {

                int pid;

                int threadId = WindowsFunctions.GetWindowThreadProcessId(hWnd, out pid);

 

                collection.Add(new WindowData()

                {

                    Title = strbTitle.ToString(),

                    ProcessId = pid,

                    ThreadId = threadId,

                    HWindow = hWnd

                });

            }

 

            return true;

        };

 

        if (WindowsFunctions.EnumDesktopWindows(IntPtr.Zero, filter, IntPtr.Zero))

        {

            return collection.ToArray();

        }

 

        return null;

    }

}

 

כמובן שכעת ניתן להשתמש בכל UI שנרצה, בדוגמא המצורפת (WPF) לחיצה על refresh תביא את החלון הבא:

image

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *

3 תגובות

  1. ישראל28 באוגוסט 2012 ב 14:15

    מה זה הפרוייקט "eBayMvcProject" או במילים אחרות – זהירות… אף פעם לא מזיק 🙂

    הגב
  2. Shlomo28 באוגוסט 2012 ב 20:00

    סתם אתר דוגמה לאתר מכירות ב – MVC -:)

    הגב
  3. eladkatz28 באוגוסט 2012 ב 23:03

    אחח.. כמה השפעה חיובית יש לי עליך 🙂

    הגב