Laden...

Externes Programm mit bestimmter Fenstergröße starten

Erstellt von mcneal vor 13 Jahren Letzter Beitrag vor 13 Jahren 9.965 Views
Hinweis von winSharp93 vor 13 Jahren

Abgetrennt von Gerätemanager aus C# Programm öffnen - deine Frage ist ihren eigenen Thread wert 😃

M
mcneal Themenstarter:in
56 Beiträge seit 2010
vor 13 Jahren

Hallo,

ich versuche mal das Schiff zu kapern :p

also ich möchte auch eine anwendung(wordpad) mit einem Formular öffnen.

bis dahin kein ding

Process p = new Process();
p.StartInfo.FileName = "wordpad.exe";
p.StartInfo.Arguments = "Manual.rtf";
p.Start();

aber ich möchte gern, dass sich wordpad in einer ganz bestimmten größe öffnet. Wie geht das ?

mit dem MainWindowHandle komme ich nicht so recht weiter

5.742 Beiträge seit 2007
vor 13 Jahren

mit dem MainWindowHandle komme ich nicht so recht weiter

Inwiefern? Ist es immer 0?
Probiere mal Process.WaitForInputIdle (oder so) - dann sollte es gültig sein.

M
mcneal Themenstarter:in
56 Beiträge seit 2010
vor 13 Jahren

Hi,

also mit dem waitInputIdle ist es zwar nicht mehr 0 (soweit also schonmal danke) aber es hat jedes mal einen anderen Wert...

ausserdem gibt das MainWindowHandle ja nur nen int Wert aus bzw man kann einen setzen...wie stelle ich damit die größe meines Fensters ein?
Ergibt sich der Wert aus Länge*Breite oder wie kommt der zu stande?

LG

4.942 Beiträge seit 2008
vor 13 Jahren

Hallo mcneal,

dir scheint der Begriff Handle noch nichts zu sagen, d.h. du hast anscheinend noch nie mit den WinAPI-Funktionen gearbeitet?

Mittels P/Invoke kannst du auch von C# aus die WinAPI-Funktionen (u. andere externe DLLs) benutzen.

Um die Größe (und auch die x,y-Position) eines Windows (Fensters) zu ändern, gibt es die Funktion SetWindowPos.
Und dafür benötigst du dann als Parameter das MainWindowHandle...

Du solltest dir aber unbedingt den MSDN-Eintrag zu SetWindowPos durchlesen, um die Parameter (besonders die Flags) zu verstehen: SetWindowPos.

M
mcneal Themenstarter:in
56 Beiträge seit 2010
vor 13 Jahren

hmm ja also lange bin ich auch noch nicht am programmieren....

also da ich Visual C# 2010 klappt das mit dem Plug In nicht

hab jetzt


DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);

einfach mal in mein Prog eingefügt..noch ein using rein und ne extra Klasse für SetWindiwPosFlags und dann wars drin...

in die entsprechende Klasse habe ich

static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
static readonly IntPtr HWND_TOP = new IntPtr(0);
static readonly IntPtr HWND_BOTTOM = new IntPtr(1);

eingefügt und nun wollte ich mit der Zeile

SetWindowPos(p.MainWindowHandle, 1, 15, 15, 1300, 760,0x0040);

zum Ziel kommen....Der erfahrene Programmierer, der grad wahrscheinlich nen Schreikrampf bekommt bemerkt natürlich, dass das nicht klappt.
das mit dem 0x0040 klappt halt nicht....war kann mir helfen?

4.942 Beiträge seit 2008
vor 13 Jahren

Hallo mcneal,

das sieht aber schon gut aus (habe also keinen Schreikrampf bekommen 😉

Da du ja extra die Konstanten angelegt hast, solltest du diese auch als 2. Parameter nutzen, d.h. HWND_BOTTOM anstatt 1 bzw. besser sogar HWND_TOP.

Zur Zeit wird bei dir also weder die Position noch die Größe des Fensters geändert?

So werte mal die Rückgabe der Funktion aus, ob ein Fehler (false) zurückgegeben wird, den du dann mittels der Methode Marshal.GetLastWin32Error() auswerten kannst. Dazu solltest du zusätzlich bei DllImport "SetLastError=true" angeben:


[DllImport("user32.dll", SetLastError=true)]

Du kannst auch einfach mal 0x0 bei den Flags ausprobieren...

M
mcneal Themenstarter:in
56 Beiträge seit 2010
vor 13 Jahren

Also mit 0x0 klappt es auch nicht und nen Error bekomme ich auch nicht.

hier mal die ganze Mehtode

Process p = new Process();
            p.StartInfo.FileName = "wordpad.exe";
            p.StartInfo.Arguments = "Manual.rtf";
            p.Start();
            p.WaitForInputIdle();
            //SetWindowPos(p.MainWindowHandle, 0, 15, 15, 1300, 760,0x0);
            MessageBox.Show(Marshal.GetLastWin32Error().ToString());

Das GetLastError gibt mir ne 0 zurück.

Die Konstanten habe ich in der Klasse SetWindowPosFlags. Das ist doch Unsinn oder? Weil die kann ich ja so auch gar nicht an der entsprechenden Stelle beutzen.

Letzendlich soll das Fenster wie gesagt in einer bestimmten Größe geöffnet werden und dann am besten nicht mehr veränderbar sein. Klingt komisch...iss aber so ^^

R
103 Beiträge seit 2009
vor 13 Jahren

Hallo,

nach dem starten vom prozess ist das mainwindowhandle höchstwahrscheinlich erstmal nicht gesetzt. Versuch mal erstmal mit sleep() ein bischen zu warten, bis sich das Fenster geöffnet hat und das Mainwindowhandle gesetzt ist.

dann bei Setwindowpos() unbedingt beim 2. Paramerter HWND_TOP eingeben (wie schon vorher gesagt) sonst wird das fenster von allen anderen überdeckt.

M
mcneal Themenstarter:in
56 Beiträge seit 2010
vor 13 Jahren

die 0 steht ja für HWND_TOP und mit HWND_Top kann ich ja nicht arbeiten. Er unterstreicht es mir rot und sagt der Name ist im aktuellen Kontext nicht vorhanden. Hab ich das irgendwas an der falschen stelle stehen vll?

und wie gesagt klappt nichts für die Flags...

4.942 Beiträge seit 2008
vor 13 Jahren

Hallo,

ich habe gerade folgendes Programm bei mir ausprobiert:


	class Program
	{
		static void Main(string[] args)
		{
			Process p = new Process();
			p.StartInfo.FileName = "wordpad.exe";
			//p.StartInfo.Arguments = "";
			p.Start();
			p.WaitForInputIdle();

			bool b = Win32.SetWindowPos(p.MainWindowHandle, Win32.HWND_TOP, 15, 15, 1300, 760, 0x0);
		}
	}

	static class Win32
	{
		[DllImport("user32.dll")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, /*SetWindowPosFlags*/ uint uFlags);

		public static readonly IntPtr HWND_TOP = new IntPtr(0);
	}

Und es lief einwandfrei, d.h. Wordpad hat sich geöffnet und anschließend wurde die Position und Größe entsprechend geändert und auch die Variable 'b' war nach dem Aufruf 'true'.

Welche Window-Version hast du denn? (ich habe WinXP SP3 mit VS 2008 und NET3.5)

Oder hast du immer einen Compilerfehler erhalten, weil du anstatt der 'SetWindowPosFlags' ein numerisches Literal angegeben hast?
Der Aufruf für "ShowWindow" sähe dann natürlich so aus:


Win32.SetWindowPos(p.MainWindowHandle, Win32.HWND_TOP, 15, 15, 1300, 760, SetWindowPosFlags.ShowWindow);

(deswegen habe ich bei mir die Flags direkt als uint angegeben)
🙂

M
mcneal Themenstarter:in
56 Beiträge seit 2010
vor 13 Jahren

Ui, naja da war ja doch noch etwas Luft zwischen deiner und meiner Fassung aber so klappt es nun bei mir auch einwandfrei.

Ich hatte den DLL import nicht so schön in ner extra Klasse sondern einfach reingeklatscht. Er konnte halt mit einigen Argumenten gar nichts anfangen weil er sie nicht erkannt hat.

Ich konnte deine Lösung quasi übernehmen. VIELEN DANK!!! 👍

M
mcneal Themenstarter:in
56 Beiträge seit 2010
vor 13 Jahren

Ach jetzt hätt ich es fast vergessen...kann ich den bei einer solchen externen Anwendung dann auch auf die Eigenschaft "Locked" zugreifen, damit quasi die Größe auch nicht mehr verändert werden kann?

M
mcneal Themenstarter:in
56 Beiträge seit 2010
vor 13 Jahren

Ich wäre dankbar wenn mir jemand auch noch bei meiner letzten Frage helfen könnte

5.742 Beiträge seit 2007
vor 13 Jahren

die Eigenschaft "Locked" zugreifen, damit quasi die Größe auch nicht mehr verändert werden kann?

Diese Eigenschaft ist ein Feature des VS-Designers und greift ausschließlich zur Designzeit.

Du könntest jedoch den BorderStyle des Fensters nach Fixed ändern (geht IMHO mit SetWindowLongPtr).

4.942 Beiträge seit 2008
vor 13 Jahren

Hi,

und als Zusatz zu der Antwort von winsharp93 noch (weil ich habe dich so verstanden, daß auch die Position nachher fix sein soll):
Auch dafür wirst du wieder die WinAPI benötigen, diesmal aber noch tiefer (bei einem eigenen Programm ist es schon schwierig, dies hinzukriegen - und bei einem fremden erst recht). Eigentlich widerspricht dieses Vorgehen auch der gesamten Windows-Programmierung, denn Fenster sollten zumindestens verschiebbar sein (wenn auch nicht unbedingt in der Größe veränderbar).

Als Stichwort wäre dann "Windows Message Hook" zu nennen (konkret: die Message WM_MOVING abfangen und verwerfen, d.h. ein konstantes RECT zurückgeben).

M
mcneal Themenstarter:in
56 Beiträge seit 2010
vor 13 Jahren

Soso...also verschieben wäre für das Fenster ok nur von der Größe her soll es fix sein.

Ich vermute mal das wird dann ganz ähnlich sein wie bei dem SetWindowPos. Ich meld mich also wenn ich was hab. Danke!

M
mcneal Themenstarter:in
56 Beiträge seit 2010
vor 13 Jahren

Also bish hier hin war es ja noch relativ einfach und zu erwarten

private static IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong)
        {
            if (IntPtr.Size == 8)
                return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
            else
                return SetWindowLong32(hWnd, nIndex, dwNewLong);
        }

        [DllImport("user32.dll", EntryPoint = "SetWindowLong")]
        private static extern IntPtr SetWindowLong32(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

        [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
        private static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

aber ich habe nirgends entsprechende Werte für den Index gefunden, die den BorderStye auf Fixed setzen....sicher dass das damit geht? Ich finde aber auch nichts anderes. Ist ahtl schwer was zu finden, wenn man nicht genau weis wonach man sucht 🤔

Was anderes...wenn man das jetzt hinbekommt, hat man dann automatisch auch die Funktion des Maximierens verhindert? Weil wenn man das auch noch extra machen müsste, dann ist das alles vll doch etwas zuviel Aufwand.

4.942 Beiträge seit 2008
vor 13 Jahren

Hallo mcneal,

du mußt für den Index GWL_STYLE = -16 (Window Styles) verwenden.
Und dann dort die entsprechenden Flags löschen: WS_SIZEBOX und WS_MAXIMIZEBOX

Wichtig ist, daß du zuerst mittels GetWindowLong (bzw. GetWindowLongPtr) dir den alten Wert holst und dann die Bitoperationen verwendest:


int flags = GetWindowLong(hWnd, GWL_STYLE);

flags &= ~(WS_SIZEBOX | WS_MAXIMIZEBOX);

SetWindowLong(hWnd, GWL_STYLE, flags);

Wichtig ist außerdem, anschließend SetWindowPos aufzurufen, sonst werden die Änderungen evtl. nicht sichtbar!!!

P.S. Es klappt bei mir sowohl mit "NotePad" als auch mit "WordPad" - einzig bei Wordpad kann man unten mit dem SizeGrip dann den Inhalt der Statusleiste verschieben 😉

M
mcneal Themenstarter:in
56 Beiträge seit 2010
vor 13 Jahren

Hallo,

also mir ist soweit klar wie es funktionieren soll denke ich.

hier mal meins komplett jetzt mit dem neuen kram

private void toolStripButtonHilfe_Click(object sender, EventArgs e)
        {
            Process p = new Process();
            p.StartInfo.FileName = "wordpad.exe";
            p.StartInfo.Arguments = "Manual.rtf";
            p.Start();
            p.WaitForInputIdle();

            int flags = Win32.GetWindowLongPtr(p.MainWindowHandle,Win32.GWL_STYLE);//alte Werte holen

            flags &= ~(WS_SIZEBOX | WS_MAXIMIZEBOX);//flags löschen

            Win32.SetWindowLongPtr(p.MainWindowHandle, GWL_STYLE, flags);//neue Werte setzen

            bool b = Win32.SetWindowPos(p.MainWindowHandle, Win32.HWND_TOP, 50, 30, 980, 900, 0x0);
        }

        static class Win32
        {
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, /*SetWindowPosFlags*/ uint uFlags);

            public static readonly IntPtr HWND_TOP = new IntPtr(0);
            public static readonly int GWL_STYLE = (-16);

            [DllImport("user32.dll", EntryPoint = "SetWindowLong")]
            private static extern IntPtr SetWindowLong32(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

            [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
            private static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

            [DllImport("user32.dll", EntryPoint = "GetWindowLong")]

            private static extern IntPtr GetWindowLongPtr32(IntPtr hWnd, int nIndex);

            [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
            private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);

            public static IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong)
            {
                if (IntPtr.Size == 8)
                    return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
                else
                    return SetWindowLong32(hWnd, nIndex, dwNewLong);
            }

            public static IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex)
            {
                if (IntPtr.Size == 8)
                    return GetWindowLongPtr64(hWnd, nIndex);
                else
                    return GetWindowLongPtr32(hWnd, nIndex);
            }
        }

das mit dem nIndex nimmt er nicht also auch nicht wenn ich -16 schreibe...habs ja auch nochmal extra angelegt wie du bei dem HWND_TOP aber er unterstreicht es mir trotzdem rot...

das mit der SizeBox und MaxiBox kennt er auch nicht 🙁 was fehlt mir denn noch?

Wenn ich es so, wie es jetzt ist lasse, müsste er doch erst alles einstellen und dann quasi SetWindowPos aufrufen...dann müssten ja alle Einstellungen gleich richtig sein oder?

schwere Geburt, aber danke das du mir hilfst 🙂

R
103 Beiträge seit 2009
vor 13 Jahren

Ich glaube da fehlt noch ein "public" bei static class Win32.
Ausserdem lief der Teil doch schon bei Dir, oder?

WS_SIZEBOX und WS_MAXIMIZEBOX musst Du natürlich auch wieder analog zu HWND_TOP in deiner Hilfsklasse registrieren.

Um die entsprechenden werte rauszufinden einfach mal googlen, das kriegst Du schon hin 😉

4.942 Beiträge seit 2008
vor 13 Jahren

Ja, wie schon geschrieben, mußt du natürlich die Win32-Member public bzw. internal machen, um von deiner Klasse darauf zuzugreifen.
Ich habe extra in meinem Code die Win32 als eigene Klasse implementiert, um nicht die Hauptklasse "vollzumüllen" (du solltest es sogar als eigene .cs-Datei auslagern).

Und hier noch die fehlenden Werte (übernommen aus der MSDN):


public const int WS_MAXIMIZEBOX = 0x00010000;
public const int WS_SIZEBOX = 0x00040000;

Und nicht vergessen "Win32." beim Zugriff davorzuschreiben 😉

M
mcneal Themenstarter:in
56 Beiträge seit 2010
vor 13 Jahren

O man...das ist natrülich absolut blind..logisch muss ich für die beiden nochmal extra die Werte raussuchen...argh!
Ja vorher lief der Teil schon und ne extra .cs hab ich gestern auch schonmal angelegt weil es ja doch etwas mehr geworden ist.

trotzdem klappt der letztendlich aufruf immernoch nicht...

bei der Definition der flags, also int flags = .... hat er mir auch erst fehler angezeigt, hab das dann in ein int gecastet und es ging, ich schätze aber mal, dass das so nicht sein soll und wohl auch das Problem beim Aufruf dann ist oder?

aufruf meint folgende Zeile

Win32.SetWindowLongPtr(p.MainWindowHandle,Win32.GWL_STYLE,flags);

die muss ich doch aber auch noch nem Wert zuweisen, so wie du es mit dem bool b =..gemacht hattest oder?

4.942 Beiträge seit 2008
vor 13 Jahren

Hallo,

int != IntPtr, d.h. entweder den Prototypen ändern oder aber "new IntPtr(flags)" verwenden.

M
mcneal Themenstarter:in
56 Beiträge seit 2010
vor 13 Jahren

Hallo,

ja int != IntPtr das ist mir schon klar 😉

aber irgendwo schreiben wir ja

int flags = Win32.GetWindowLongPtr(p.MainWindowHandle,Win32.GWL_STYLE);

und das geht halt nicht, es sei denn, ich caste den Ausdruck zu einem int...aber das dass blödsinn ist weis ich auch ...

Sorry fürs späte schreiben aber ich muss die arbeit daran gerade etwas zurückstellen...das sind ja auch nur noch feinheiten, das Programm an sich steht ja 👅

5.742 Beiträge seit 2007
vor 13 Jahren

und das geht halt nicht, es sei denn, ich caste den Ausdruck zu einem int...aber das dass blödsinn ist weis ich auch ...

Dann rufe einfach ToInt32 auf den Pointer auf.
Siehe generell [Hinweis] Syntaxfehler selbst lösen (Compilerfehlermeldungen)