Auf welchem Bildschirm befindet sich ein externes Programm?

  • VB.NET

Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von SystemException.

    Auf welchem Bildschirm befindet sich ein externes Programm?

    Hallo, ich möchte gerne wissen auf welchem Bildschirm (1,2,3,... ) sich gerade ein externes Programm befindet z.B. notepad.
    Habe ein Code geschrieben, komme aber nicht weiter und die Forumsuche war ebenfalls ervolglos. Kann mir jemand helfen?

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    3. GetProcesses()
    4. End Sub
    5. Public Sub GetProcesses()
    6. Dim pro As Process 'aktuelles Programmname
    7. Dim i As Integer 'aktuelle Bildschirmnummer
    8. For Each pro In Process.GetProcesses
    9. 'was kommt hier rein?
    10. If pro.ProcessName = "notepad" Then
    11. TextBox1.Text = i
    12. End If
    13. Next
    14. End Sub
    15. End Class

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Kokett“ ()

    Hohl dir das MainWindowHandle vom Process, dann die Funktion GetWindowRect nutzen, dann hast du die Position des Fensters.
    pinvoke.net/default.aspx/user32/GetWindowRect.html

    Nun kannst du durch Screen.AllScreens iterieren und prüfen ob die Fenster-Position innerhalb der Bounds einer der Screens drin ist. Wenn ja ist das Fenster auf diesem Screen.

    VB.NET-Quellcode

    1. For i = 0 To Screen.AllScreens.Length - 1
    2. Dim r As Rectangle = Screen.AllScreens(i).Bounds
    3. Next

    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin
    Danke Nolde,

    Also ich habe jetzt die Fenstermaße ermittelt, verstehe aber nicht wie ich Screen.AllScreens anwenden soll. Und ich verstehe auch nicht was passieren soll wenn zwei Fenster auf einem und derselben Bildschirm gleich groß sein sollen.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Structure RECT
    3. Dim Left As Integer
    4. Dim Top As Integer
    5. Dim Right As Integer
    6. Dim Bottom As Integer
    7. End Structure
    8. Private Declare Function GetWindowRect Lib "user32.DLL" Alias "GetWindowRect" ( _
    9. ByVal hwnd As Integer, _
    10. ByRef lpRect As RECT) As Boolean
    11. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    12. On Error Resume Next
    13. Dim XYRect As RECT
    14. Dim pro As Process = Process.GetProcessesByName("notepad")(0)
    15. Dim hWnd As IntPtr = pro.MainWindowHandle
    16. If hWnd = 0 Then MsgBox("notepad not found!", MsgBoxStyle.Information)
    17. GetWindowRect(hWnd, XYRect)
    18. Label1.Text = XYRect.Left
    19. Label2.Text = XYRect.Top
    20. Label3.Text = XYRect.Right
    21. Label4.Text = XYRect.Bottom
    22. 'ab hier komme nicht weiter
    23. For i = 0 To Screen.AllScreens.Length - 1
    24. Dim r As Rectangle = Screen.AllScreens(i).Bounds
    25. Next
    26. End Sub
    27. End Class
    Schaut doch schon gut aus. Hatte dir extra noch das Rectangle reingemacht, da hättest du nur noch testen müssen ob X Y(Point) im rectangle ist.

    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Public Class Form1
    3. Public Structure RECT
    4. Dim Left As Integer
    5. Dim Top As Integer
    6. Dim Right As Integer
    7. Dim Bottom As Integer
    8. End Structure
    9. <DllImport("user32.dll")>
    10. Private Shared Function GetWindowRect(ByVal hwnd As IntPtr, ByRef lpRect As RECT) As Boolean
    11. End Function
    12. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    13. Dim pro() As Process = Process.GetProcessesByName("notepad")
    14. If pro.Length > 0 Then
    15. Dim hWnd As IntPtr = pro(0).MainWindowHandle
    16. If hWnd <> IntPtr.Zero Then
    17. Dim XYRect As RECT
    18. GetWindowRect(hWnd, XYRect)
    19. For i = 0 To Screen.AllScreens.Length - 1
    20. Dim r As Rectangle = Screen.AllScreens(i).Bounds
    21. If r.Contains(New Point(XYRect.Left, XYRect.Top)) Then
    22. MessageBox.Show("Notepad is on Screen " & (i + 1), "Info", MessageBoxButtons.OK, MessageBoxIcon.Information)
    23. End If
    24. Next
    25. Else
    26. MessageBox.Show("Notepad Window not found!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
    27. End If
    28. Else
    29. MessageBox.Show("No Notepad process found!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
    30. End If
    31. End Sub
    32. End Class
    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin
    Windows "weiß" hier übrigens selbst, welchem Bildschirm ein Fenster zugeordnet ist. Wenn Du willst, dass Dein Programm sich an das Windows-Verhalten hält, dann musst Du diese Funktion verwenden:
    docs.microsoft.com/en-us/windo…winuser-monitorfromwindow
    Testen kannst Du das so:
    Erstelle ein WinForms-Projekt mit einer Form und folgendem Code:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Public Sub New()
    3. InitializeComponent()
    4. Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
    5. Me.WindowState = FormWindowState.Maximized
    6. End Sub
    7. Protected Overrides Sub OnClick(e As System.EventArgs)
    8. MyBase.OnClick(e)
    9. Me.Close()
    10. End Sub
    11. End Class

    Und dann erstelle ein zweites WinForms-Projekt mit einer Form und folgendem Code:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Enum MonitorFromWindowFlags As UInt32
    3. DefaultToNull = 0
    4. DefaultToPrimary = 1
    5. DefaultToNearest = 2
    6. End Enum
    7. Private Declare Function MonitorFromWindow Lib "User32" (WindowHandle As IntPtr, Flags As MonitorFromWindowFlags) As IntPtr
    8. Dim WithEvents RefreshTimer As New Timer With {.Interval = 30, .Enabled = True}
    9. Private Sub RefreshTimer_Tick() Handles RefreshTimer.Tick
    10. Me.Invalidate()
    11. End Sub
    12. Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs)
    13. MyBase.OnPaint(e)
    14. Dim MonitorHanlde = MonitorFromWindow(Me.Handle, MonitorFromWindowFlags.DefaultToNearest)
    15. e.Graphics.DrawString(MonitorHanlde.ToString, Font, Brushes.Red, 5, 5)
    16. End Sub
    17. End Class

    Aus irgend einem Grund ist es wichtig, dass es sich um unterschiedliche Prozesse handelt. Verwende also zwei separate Projekte.
    Debugge dann das erste Projekt. Eine Form öffnet sich über den ganzen Bildschirm.
    Alt+Tabbe ins andere Projekt und debugge das. Schieb das Fensterchen auf einen anderen Bildschirm. Bring das maximierte Fenster wieder in den Vordergrund.
    Achte darauf, dass die Taskleiste hinter dem maximierten Fenster verschwindet.
    Schiebe das kleine Fenster ein Stück weit auf den Bildschirm, auf dem sich die maximierte Form befindet.
    Sobald das kleine Fensterchen weit genug in den Bildschirm ragt, ändert sich das angezeigte Handle und die Taskleiste erscheint vor der maximierten Form. Schiebst Du die Form wieder raus, ändert sich das Handle wieder und die Taskleiste verschwindet wieder hinter der maximierten Form.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Vielen-vielen Dank NoIde, dein Code war fast das was ich mir gewünscht habe. Leider nur "fast", wie ich bereits früher geschrieben habe, kann das Programm keine Rückmeldung geben wenn auf einem Bildschirm mehrere Fenster gleich groß sind z.B. alle Fenster maximiert sind. Da überlege ich mir noch was hoffentlich)

    habe den Code einwenig an meine Bedürfnisse angepasst und zwar jetzt kommt auch bei mehreren geöffnete "notepads" jedes mal eine Meldung.

    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Public Class Form1
    3. Public Structure RECT
    4. Dim Left As Integer
    5. Dim Top As Integer
    6. Dim Right As Integer
    7. Dim Bottom As Integer
    8. End Structure
    9. <DllImport("user32.dll")>
    10. Private Shared Function GetWindowRect(ByVal hwnd As IntPtr, ByRef lpRect As RECT) As Boolean
    11. End Function
    12. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    13. Dim pro As Process
    14. For Each pro In Process.GetProcesses
    15. If pro.ProcessName = "notepad" Then
    16. Dim hWnd As IntPtr = pro.MainWindowHandle
    17. Dim XYRect As RECT
    18. GetWindowRect(hWnd, XYRect)
    19. For i = 0 To Screen.AllScreens.Length - 1
    20. Dim r As Rectangle = Screen.AllScreens(i).Bounds
    21. If r.Contains(New Point(XYRect.Left, XYRect.Top)) Then
    22. MessageBox.Show("Notepad is on Screen " & (i + 1), "Info", MessageBoxButtons.OK, MessageBoxIcon.Information)
    23. End If
    24. Next
    25. End If
    26. Next
    27. End Sub
    28. End Class



    Danke dir auch Niko Ortner, habe um erlich zu sein nicht so ganz verstanden wie dein Code funktioniert, aber werde mich später mit ihm auseinander setzen!
    Ich probiere gerade auch noch ein wenig anders, aber klappt nicht so ganz, bekomme zwar die MonitorInfoEx-Structure, aber MONITORINFOEX.szDevice bleibt lehr. Geht zwar auch einfach über die Screenklasse, aber warum nicht mal probieren.

    Edit: falsche structure genutzt, GetMonitorInfo mit MonitorInfoEx schlägt fehl.

    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Public Class Form1
    3. Public Structure RECT
    4. Dim Left As Integer
    5. Dim Top As Integer
    6. Dim Right As Integer
    7. Dim Bottom As Integer
    8. End Structure
    9. Public Structure POINT
    10. Public X As Integer
    11. Public Y As Integer
    12. End Structure
    13. <StructLayout(LayoutKind.Sequential)>
    14. Public Structure MONITORINFOEX
    15. <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)>
    16. Public szDevice As String
    17. Public info As MONITORINFO
    18. End Structure
    19. <StructLayout(LayoutKind.Sequential)>
    20. Public Structure MONITORINFO
    21. Public cbSize As Integer
    22. Public rcMonitor As RECT
    23. Public rcWork As RECT
    24. Public dwFlags As Integer
    25. End Structure
    26. <DllImport("user32.dll")>
    27. Private Shared Function GetWindowRect(ByVal hwnd As IntPtr, ByRef lpRect As RECT) As Boolean
    28. End Function
    29. <DllImport("user32.dll", SetLastError:=True)> _
    30. Private Shared Function MonitorFromPoint(ByVal pt As POINT, ByVal dwFlags As UInteger) As IntPtr
    31. End Function
    32. <DllImport("user32.dll")>
    33. Private Shared Function GetMonitorInfo(ByVal hMonitor As IntPtr, ByRef lpmi As MONITORINFO) As Boolean
    34. End Function
    35. <DllImport("user32.dll")>
    36. Private Shared Function GetMonitorInfo(ByVal hMonitor As IntPtr, ByRef lpmi As MONITORINFOEX) As Boolean
    37. End Function
    38. Private Enum MonitorOptions As UInteger
    39. MONITOR_DEFAULTTONULL = &H0
    40. MONITOR_DEFAULTTOPRIMARY = &H1
    41. MONITOR_DEFAULTTONEAREST = &H2
    42. End Enum
    43. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    44. Dim pro() As Process = Process.GetProcessesByName("notepad")
    45. If pro.Length > 0 Then
    46. Dim hWnd As IntPtr = pro(0).MainWindowHandle
    47. If hWnd <> IntPtr.Zero Then
    48. Dim XYRect As RECT
    49. GetWindowRect(hWnd, XYRect)
    50. Dim monHwnd As IntPtr = MonitorFromPoint(New POINT() With {.X = XYRect.Left, .Y = XYRect.Top}, MonitorOptions.MONITOR_DEFAULTTONEAREST)
    51. If monHwnd <> IntPtr.Zero Then
    52. Dim monInfoEx As New MONITORINFOEX
    53. Dim monInfo As New MONITORINFO
    54. monInfo.cbSize = Marshal.SizeOf(GetType(MONITORINFOEX))
    55. monInfoEx.info = monInfo
    56. If GetMonitorInfo(monHwnd, monInfo) Then
    57. MessageBox.Show(monInfoEx.szDevice)
    58. End If
    59. End If
    60. 'MessageBox.Show("Notepad is on Screen " & (i + 1), "Info", MessageBoxButtons.OK, MessageBoxIcon.Information)
    61. Else
    62. MessageBox.Show("Notepad Window not found!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
    63. End If
    64. Else
    65. MessageBox.Show("No Notepad process found!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
    66. End If
    67. End Sub
    68. End Class

    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „NoIde“ ()

    Das war mein Fehler, die falsche structure genutzt, GetMonitorInfo mit MonitorInfoEx schlägt fehl. Mit MonitorInfo geht's trotz der falschen cbSize. Deswegen konnte monInfoEx.szDevice auch nur leer sein.
    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin

    Kokett schrieb:

    VB.net-Formen zu beziehen

    Der Knackpunkt liegt bei Me.Handle. Me ist hier die Form. Die hat ein Handle. Das Handle bekommt man mit der Handle-Eigenschaft. Das muss aber nicht das Handle einer Form im aktuellen Prozess sein. Man kann auch jedes andere Handle verwenden, das auf ein Fenster zeigt. So auch zum Beispiel ein Handle, das Du von Process.MainWindowHandle bekommst.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Da bin ich wahrscheinlich zu unerfahren, ich habe zwar versucht zwischen deinem Code mein Handle einzubauen, aber es kommt eine Fehlermeldung raus

    VB.NET-Quellcode

    1. ....
    2. MyBase.OnPaint(e)
    3. Dim pro() As Process = Process.GetProcessesByName("notepad")
    4. Dim MonitorHanlde = MonitorFromWindow(pro(0).MainWindowHandle, MonitorFromWindowFlags.DefaultToNearest)
    5. .....

    Komm schon. Das geht doch besser.

    Du solltest in der IDE sowas sehen:

    Markiere die betroffene Zeile im Code, den Du hier postest:

    VB.NET-Quellcode

    1. Dim MonitorHanlde = MonitorFromWindow(pro(0).MainWindowHandle, MonitorFromWindowFlags.DefaultToNearest) '<-- in dieser Zeile

    Noch besser: Teile die Zeile auf, damit man genauer sieht, wo die Exception auftritt:

    Also so:

    VB.NET-Quellcode

    1. Dim a = pro(0) '<-- in dieser Zeile
    2. Dim b = a.MainWindowHandle
    3. Dim MonitorHanlde = MonitorFromWindow(b, MonitorFromWindowFlags.DefaultToNearest)

    Dann klickst Du in dem kleinen Fensterchen auf "Ausnahmedetails in die Zwischenablage kopieren" und fügst das in Deinen Post ein:

    Quellcode

    1. System.IndexOutOfRangeException wurde nicht behandelt.
    2. HResult=-2146233080
    3. Message=Der Index war außerhalb des Arraybereichs.
    4. Source=WindowsApplication1
    5. StackTrace:
    6. bei WindowsApplication1.Form_Main.OnShown(EventArgs e) in C:\Users\Niko\AppData\Local\Temporary Projects\WindowsApplication1\Form_Main.vb:Zeile 16.
    7. bei System.Windows.Forms.Form.CallShownEvent()
    8. bei System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)
    9. bei System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)
    10. bei System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
    11. bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
    12. bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
    13. bei System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
    14. bei System.Windows.Forms.Control.InvokeMarshaledCallbacks()
    15. bei System.Windows.Forms.Control.WndProc(Message& m)
    16. bei System.Windows.Forms.ScrollableControl.WndProc(Message& m)
    17. bei System.Windows.Forms.Form.WndProc(Message& m)
    18. bei System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
    19. bei System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
    20. bei System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
    21. bei System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
    22. bei System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
    23. bei System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
    24. bei System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
    25. bei Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
    26. bei Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
    27. bei Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
    28. bei WindowsApplication1.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:Zeile 81.
    29. bei System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
    30. bei System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
    31. bei Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
    32. bei System.Threading.ThreadHelper.ThreadStart_Context(Object state)
    33. bei System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
    34. bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
    35. bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
    36. bei System.Threading.ThreadHelper.ThreadStart()
    37. InnerException:


    Es ist sehr wichtig, dass Du exakte Fehlerbeschreibungen gibst. Sonst müssen wir unsere Glaskugeln fragen und die sind generell immer genau dann in der Reinigung, wenn wir sie brauchen.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    könnte man vielleicht das ganze so lösen, oder ändert sich irgendwann DeviceName z.B. von "\\.\DISPLAY1" auf "Samsung bla-bla" ?


    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    3. Dim pro() As Process = Process.GetProcessesByName("notepad")
    4. Dim hWnd As IntPtr = pro(0).MainWindowHandle
    5. Dim screenInfo As Screen = Screen.FromHandle(hWnd)
    6. Dim BildschirmName As String = screenInfo.DeviceName.ToString
    7. Dim fertig As String = BildschirmName.Substring(11)
    8. MsgBox(fertig)
    9. End Sub
    10. End Class

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Kokett“ ()

    @Niko Ortner Hättest auch einfach hierrauf verweisen können: Tipps für eine höhere Antwort-Quote (Punkt 2.X)

    Vollzitat entfernt. ~Trade
    Bitte benutze OPTION STRICT ON.
    Und optional OPTION EXPLICIT ON.
    Hier ein CODE-CONVERTER.

    Suchanfragen-Ansatz für GOOGLE.
    Prüfe deinen Beitrag in einer RECHTSCHREIBPRÜFUNG.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Trade“ ()