Anzeige

Montior, Größe und Position für Prozess bestimmen

NetBull

Erfahrenes Mitglied
#1
Guten Morgen,

nach einer Ewigkeit muss ich mich mal wieder in C# einarbeiten.

Problem: Eine Applikation soll ein oder merhere Explorer Fenster öffnen.

Code:
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            System.Diagnostics.Process process = new System.Diagnostics.Process();
            process.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
            process.StartInfo.UseShellExecute = true;
            process.StartInfo.FileName = @"explorer";
            process.StartInfo.Arguments = @" ";
            process.Start();
Nun möchte ich aber einen Zielmonitor bestimmen, dessen Auflösung ermitteln und die Größe der Explorer Fenster bestimmen. Bin ich da mit dem process auf dem richtigen Weg? Weil ich finde keine Möglichkeit den Monitor zu bestimmen.

thx NetBu||
 

Turri

Erfahrenes Mitglied
#2
Hallo,

zum schauen wieviele Monitore angeschlossen sind:
Code:
// int count = System.Windows.Forms.SystemInformation.MonitorCount;

// bzw. vielleicht so die Eigenschaften jedes Screen durchgehen.
foreach (Screen sc in System.Windows.Forms.Screen.AllScreens)
{
   // als Beispiel die Auflösung jeden Monitors....
  int width = sc.Bounds.Width;
  int height = sc.Bounds.Height;
}
Ich bin mir nicht sicher ob Process die wichtige Variante ist, weil ein Process ja kein "Window" mit einer Position haben muss.
Du kannst also einem Process als solches keinen Monitor zuweisen.

Daher würde mich schon interessieren, was mit den Explorer Fenstern angezeit werden soll.
Dann könnte man vielleicht Alternativen anbieten.
 

NetBull

Erfahrenes Mitglied
#3
Es geht nicht nur um Explorer Fenster. Ich möchte bestimmte Anwendungen / Explorer Fenster mit einem KLICK aufrufen die sich dann wie von mir definiert auf den Bildschirmen verteilen.....

Beispiel: Monitor 1 soll oben, geteilt zwei putty SSH Verbindungen zeigen, unten dann ein winSCP über die gesamte Breite. Auf Monitor 2 möchte ich Eclipse öffnen und auf monitor 3 dann nebeneinander den Browser mit einer speziellen Webadresse und den Browser mit einem UnitTest Ergebnis Set....

So was in der Art. Also muss ich Explorer Fenster und Prozesse öffnen die ich einem Monitor zu ordne, die Position und Größe bestimme.
 

Turri

Erfahrenes Mitglied
#4
Hallo,

habe eben auch mal bisschen gegoogelt. :)

Hab hier mal ein Schnipsel Quick and Dirty hingecoded...
Vielleicht ist es ja ne Orientierung für dich.
Code:
/// <summary>
/// SetWindowPos Flags
/// </summary>
public static class SWP
{
  public static readonly int
  NOSIZE = 0x0001,
  NOMOVE = 0x0002,
  NOZORDER = 0x0004,
  NOREDRAW = 0x0008,
  NOACTIVATE = 0x0010,
  DRAWFRAME = 0x0020,
  FRAMECHANGED = 0x0020,
  SHOWWINDOW = 0x0040,
  HIDEWINDOW = 0x0080,
  NOCOPYBITS = 0x0100,
  NOOWNERZORDER = 0x0200,
  NOREPOSITION = 0x0200,
  NOSENDCHANGING = 0x0400,
  DEFERERASE = 0x2000,
  ASYNCWINDOWPOS = 0x4000;
}

...

[DllImport("user32.dll",EntryPoint="SetWindowPos")]
public static extern IntPtr SetWindowPos(IntPtr hWnd,int hWndInsertAfter,int x,int Y,int cx,int cy,int wFlags);

Process process = new Process();
....
process.Start();
Thread.Sleep(100); // warten bis Fenster da ist, das sonst MainWindowHandle null liefert...
IntPtr handle = process.MainWindowHandle;
if(handle !=IntPtr.Zero)
{
  int meineXPos = 100;
  int meineYPos = 50;
  int meineBreite = 600;
  int meineHoehe = 300;
  SetWindowPos(handle, 0, meineXPos, meineYPos, meineBreite, meineHoehe, SWP.SHOWWINDOW);
}
Um die Fenster jetzt gescheit zu positionieren, musst du nur die Screenauflösungen, wie oben im Thread, auslesen und an die entsprechende Pixelposition setzen.
 

NetBull

Erfahrenes Mitglied
#5
@Turri ::

Guten Morgen,

irgendwas will da nicht..
Code:
[DllImport("user32.dll",EntryPoint="SetWindowPos")]
    public static extern IntPtr SetWindowPos(IntPtr hWnd,int hWndInsertAfter,int x,int Y,int cx,int cy,int wFlags);
Da bekomme ich vom Compiler gleich zwei Fehler:
Code:
Error    1    Expected class, delegate, enum, interface, or struct    D:\users\dml\documents\visual studio 2010\Projects\TestOpener\TestOpener\Program.cs    34    26    TestOpener
Code:
Error    2    The modifier 'extern' is not valid for this item    D:\users\dml\documents\visual studio 2010\Projects\TestOpener\TestOpener\Program.cs    33    55    TestOpener
LG NetBu||
 

Turri

Erfahrenes Mitglied
#6
Hier mein kompletter Code, der funkioniert wunderbar bei mir (am Beispiel notepad.exe).
Einfach eine Konsolenanwendung erstellen und das hier in die Program.cs rein.
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using System.Diagnostics;

namespace WindowPosition
{
  class Program
  {
    [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
    public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);

    static void Main(string[] args)
    {
      Process process = new Process();
      process.StartInfo.FileName = "notepad.exe";  

      process.Start();
      Thread.Sleep(100); // warten bis Fenster da ist, das sonst MainWindowHandle null liefert...
      IntPtr handle = process.MainWindowHandle;
      if(handle !=IntPtr.Zero)
      {
        int meineXPos = 1000;
        int meineYPos = 50;
        int meineBreite = 300;
        int meineHoehe = 300;
        SetWindowPos(handle, 0, meineXPos, meineYPos, meineBreite, meineHoehe, SWP.SHOWWINDOW);
      }
    }
  }

  /// <summary>
  /// SetWindowPos Flags
  /// </summary>
  public static class SWP
  {
    public static readonly int
    NOSIZE = 0x0001,
    NOMOVE = 0x0002,
    NOZORDER = 0x0004,
    NOREDRAW = 0x0008,
    NOACTIVATE = 0x0010,
    DRAWFRAME = 0x0020,
    FRAMECHANGED = 0x0020,
    SHOWWINDOW = 0x0040,
    HIDEWINDOW = 0x0080,
    NOCOPYBITS = 0x0100,
    NOOWNERZORDER = 0x0200,
    NOREPOSITION = 0x0200,
    NOSENDCHANGING = 0x0400,
    DEFERERASE = 0x2000,
    ASYNCWINDOWPOS = 0x4000;
  }
}
 

NetBull

Erfahrenes Mitglied
#7
OK und Danke.... so funktioniert es. Allerdings muss ich trotzdem schauen wie ich das mit einer Form ans laufen bekomme. Irgendwie will mein Forms Projekt das IntPtr nicht.

Der Aufruf des Explorers führt zu einem Fehler....

Code:
static void Main(string[] args)
    {
      Process process = new Process();
      //process.StartInfo.FileName = "notepad.exe";
      process.StartInfo.FileName = "explorer.exe";
      process.Start();
      Thread.Sleep(100); // warten bis Fenster da ist, das sonst MainWindowHandle null liefert...
      IntPtr handle = process.MainWindowHandle;
      if(handle !=IntPtr.Zero)
      {
        int meineXPos = 1000;
        int meineYPos = 50;
        int meineBreite = 300;
        int meineHoehe = 300;
        SetWindowPos(handle, 0, meineXPos, meineYPos, meineBreite, meineHoehe, SWP.SHOWWINDOW);
      }
    }
Hier steigt es bei folgender Zeile aus:
Code:
IntPtr handle = process.MainWindowHandle;
Fehlermeldung:
Code:
System.InvalidOperationException was unhandled
  HResult=-2146233079
  Message=Die angeforderten Informationen sind nicht verfügbar, da der Prozess beendet wurde.
  Source=System
  StackTrace:
       bei System.Diagnostics.Process.EnsureState(State state)
       bei System.Diagnostics.Process.get_MainWindowHandle()
       bei WindowController.Program.Main(String[] args) in D:\users\dml\documents\visual studio 2010\Projects\WindowController\WindowController\Program.cs:Zeile 24.
       bei System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       bei System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       bei Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       bei System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       bei System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       bei System.Threading.ThreadHelper.ThreadStart()
  InnerException:
Eine Idee warum explorer Fenster nicht damit funktionieren?

LG NetBu||
 
Zuletzt bearbeitet:

Turri

Erfahrenes Mitglied
#8
Scheint irgendwie nen Sonderfall zu sein, die explorer.exe beendet sich gleich wieder, aber das Fenster bleibt stehen.
Hier gibts den Workarround (Windows Forms Application):
Einfach alls in die Form1.cs kopieren.
Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowPosition
{
  public partial class Form1 : Form
  {
    [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
    public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);

    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    public Form1()
    {
      InitializeComponent();
      OpenPathWithExplorerExe(@"C:\Windows");  
    }
    private void OpenPathWithExplorerExe(string path)
    {
      Process process = new Process();
      string explorer = string.Format("{0}\\{1}", Environment.GetEnvironmentVariable("WINDIR"), "explorer.exe");
      process.StartInfo.FileName = explorer;
      process.StartInfo.Arguments = string.Format("{0}", path);
      process.StartInfo.UseShellExecute = true;
      process.Start();

      Thread.Sleep(200); // warten bis Fenster da ist...

      IntPtr handle = FindWindow(null, path);
      int meineXPos = 1000;
      int meineYPos = 50;
      int meineBreite = 300;
      int meineHoehe = 300;
      SetWindowPos(handle, 0, meineXPos, meineYPos, meineBreite, meineHoehe, SWP.SHOWWINDOW);
    }
  }

  /// <summary>
  /// SetWindowPos Flags
  /// </summary>
  public static class SWP
  {
  public static readonly int
  NOSIZE = 0x0001,
  NOMOVE = 0x0002,
  NOZORDER = 0x0004,
  NOREDRAW = 0x0008,
  NOACTIVATE = 0x0010,
  DRAWFRAME = 0x0020,
  FRAMECHANGED = 0x0020,
  SHOWWINDOW = 0x0040,
  HIDEWINDOW = 0x0080,
  NOCOPYBITS = 0x0100,
  NOOWNERZORDER = 0x0200,
  NOREPOSITION = 0x0200,
  NOSENDCHANGING = 0x0400,
  DEFERERASE = 0x2000,
  ASYNCWINDOWPOS = 0x4000;
  }
}
Warum Workarround? Weil FindWindow möglicherweise das falsche Fenster nimmt, wenn schon ein anderes Explorer Fenster diesen Ordner geöffnet hat.
 

NetBull

Erfahrenes Mitglied
#9
Meine Güte ist das kompliziert.
a) Die Fenster der neuen Prozesse haben keinen Focus, sind hinter den anderen Fenstern
b) Womit bestimme ich nun den Monitor?
c) Müsste auch noch was haben das ich zb. 2 Anwendungen / Explorer Fenster öffnen die sich dann den Platz auf dem Monitor teilen
 

Turri

Erfahrenes Mitglied
#10
Meine Güte ist das kompliziert.
a) Die Fenster der neuen Prozesse haben keinen Focus, sind hinter den anderen Fenstern
b) Womit bestimme ich nun den Monitor?
c) Müsste auch noch was haben das ich zb. 2 Anwendungen / Explorer Fenster öffnen die sich dann den Platz auf dem Monitor teilen
a)
Code:
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
b)
Code:
Point Location1 = System.Windows.Forms.Screen.AllScreens[0].WorkingArea.Location; // Monitor 1
Point Location2 = System.Windows.Forms.Screen.AllScreens[1].WorkingArea.Location; // Monitor 2
c) SetWindowPos
Code:
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
Die Parameter cx und cy geben die Fenstergröße an, und bastel dir deine Fenstergrößen mit Hilfe der "Screen"-Klasse (Wo du deine Auflösungen der Monitore her bekommst) zusammen.
 
Zuletzt bearbeitet:
Anzeige

Neue Beiträge

Anzeige