Hallo zusammen,
ich habe folgendes Problem mit meinem neusten Programm:
Und zwar starte ich über die Software eines Messgeräts eine von mir geschriebene Konsolenanwendung (Die Software des Messgeräts ist nicht von mir, unterstützt aber das Aufrufen von externen Konsolenanwendungen).
Wenn ich die Konsolenanwendung allein teste funktioniert auch alles so wie es soll. Lasse ich die Anwendung aber über die Mess-Software starten, dann stürzt meine Anwendung ab.
Durch Einfügen etlicher Debug-Textmeldungen habe ich den Problematischen Bereich auch schon gefunden:
System.Console.SetWindowSize(90, System.Console.WindowHeight);
Wenn ich diese Zeile auskommentiere funktioniert alles, allerdings wird während der gesamten Ausführung gar kein Konsolenfenster angezeigt. In diesem Fenster sollen aber wichtige Informationen angezeigt werden.
Kann es sein dass die Mess-Software das Konsolenfenster "klaut" oder irgendwie sonst unterbindet? Und was könnte man dagegen tun?
Schöne Grüße,
l2l
Hallo,
Lasse ich die Anwendung aber über die Mess-Software starten, dann stürzt meine Anwendung ab.
Was ist denn die Fehlermeldung die beim Absturz deiner Anwendung auftritt? Wenn in der von dir ermittelten Zeile eine Exception geworfen wird, dann setzt doch ein try-block darum, und lass dir im Catch-Block die Exception ausgeben.
Dann weisst du warum die Anwendung abschmiert.
Hallo lot2learn,
Wenn ich diese Zeile auskommentiere funktioniert alles, allerdings wird während der gesamten Ausführung gar kein Konsolenfenster angezeigt
wo hast du dann deine Debug-Textmeldungen gesehen?
Wie dem auch sei. Natürlich kann es sein, dass die Messsoftware dein Programm so startet, dass kein Konsolenfenster angezeigt wird. Daran könnt aber m.E. nur die Messanwendung was ändern.
herbivore
Hallo,
Danke schonmal für die Rückmeldungen!
Also die Debug Textmeldungen hab ich mir per MessageBoxes ausgeben lassen, nicht per Konsole. Damit konnte ich Zeile für Zeile verfolgen ab welcher Stelle der Code abstürzt, was mich dann zu oben genannter Zeile gebracht hat.
Ich hab mir mittlerweile die Exception auch mal als MessageBox ausgeben lassen und hab diese hier angehängt. Leider sagt mir die Fehlermeldung nicht wirklich viel...
Kann ich nicht von der laufenden Konsolenanwendung irgendwie ein Konsolenfenster öffnen? Die Mess-Software kann ich leider nicht ändern, da diese nicht von mir stammt...
Schöne Grüße,
l2l
Hallo,
der Fehlermeldung nach sagt das System, dass es Probleme hat Fensterhöhe zu ermitteln, wahrscheinlich weil keins da ist.
Was wäre wenn du statt Konsolen- eine Winform-Anwendung daraus machst und deine Ausgabe in was auch immer ausgibst? Ich vermute, dass die MessSoftware irgendwie keine weitere Konsolenfenster sichtbar zuläßt.
Grüße
**:::
Hallo,
der Fehlermeldung nach sagt das System, dass es Probleme hat Fensterhöhe zu ermitteln, wahrscheinlich weil keins da ist.
Ok, das macht Sinn.
Was wäre wenn du statt Konsolen- eine Winform-Anwendung daraus machst und deine Ausgabe in was auch immer ausgibst?
Das Problem ist dass die Mess-Software ausschließlich Konsolenanwendungen zulässt, was anderes kann man leider gar nicht erst aufrufen 😦
Ich vermute, dass die MessSoftware irgendwie keine weitere Konsolenfenster sichtbar zuläßt.
Gibt es eine einfache Möglichkeit das zu verifizieren? Bzw. kann man nicht irgendwie an der Mess-Software "vorbei" ein Konsolenfenster aufmachen?
Ich will letztendlich nur so einfach wie möglich kontinuierlich die Daten ausgeben die von der Konsolenanwendung berechnet werden.
Schöne Grüße,
l2l
Hallo lot2learn,
du kannst es mal mit Win32 AllocConsole probieren. Wenn das nicht geht, sehe ich keine Chance, außer, dass du dein Programm mit Process.Start selbst nochmal startest, wenn du erkennst, dass keine Konsole da ist.
herbivore
Hallo lot2learn,
ist es denn notwendig, dass die Ausgabe in einem Consolen-Fenster erfolgt?
Ansonsten könnstest du auch mit einer Kombination aus z.b. log4net oder NLog und TraceEye - Professional LogViewer oder Tail4Win arbeiten.
Also die Ausgabe in Log-Dateien schreiben und die Anzeige mit einem anderen Programm erfolgen lassen.
Gruß, Alf
Hallo lot2learn,
Ich vermute, dass die MessSoftware irgendwie keine weitere Konsolenfenster sichtbar zuläßt.
Gibt es eine einfache Möglichkeit das zu verifizieren? Bzw. kann man nicht irgendwie an der Mess-Software "vorbei" ein Konsolenfenster aufmachen?
Ja, du kannst überprüfen, ob du ein sichtbares Konsolenfenster hast. Das geht mit den WinAPI Funktionen GetConsoleWindow und IsWindowVisible.
Während des Erzeugens eines Prozesses mittels CreateProcess gibt es mehrere Möglichkeiten ein Konsolenfenster des Kindes zu unterdrücken:
*Parent hat eine Konsole, macht diese aber unsichtbar -> Kind erbt diese (unsichtbare)
*Parent setzt beim Start CREATE_NO_WINDOW
*Parent ist Konsolenanwendung und setzt beim Start DETACHED_PROCESS
*Parent setzt beim Start eines der ShowWindow commands SW_HIDE oder SW_*MINIMIZE(D)
Wie herbivore schon gesagt hat, kannst du aber problemlos mit AllocConsole eine neue Konsole erzeugen, falls du keine bekommen hast.
Darüberhinaus musst du aber diese auch sichtbar machen, falls sie es (durch parent erzwungen) nicht ist. Das geht mit ShowWindow.
Nen ganz fieser Parent könnte das Kind zwar mit seiner Konsole starten, aber stdin und stdout umbiegen, dann müsste man die nochmal setzen, wahrscheinlich mit SetStdHandle, wobei ich das selbst nicht probiert habe.
Für das Sicherstellen, dass du in allen denkbaren Fällen immer eine sichtbare Konsole hast, habe ich mal folgendes Snippet gebastelt:
using System;
using System.Runtime.InteropServices;
namespace System
{
public class ConsoleHelper
{
public static void EnsureConsoleVisibility()
{
if (!HasConsoleWindow())
{
// processes with the CREATE_NO_WINDOW flag can't directly call AllocConsole.
// so we call FreeConsole, before we try to create a new one.
FreeConsole();
AllocConsole();
}
IntPtr consoleHandle = GetConsoleWindow();
if (!IsWindowVisible(consoleHandle))
{
// if special ShowWindow flags were set during process creation,
// our first call to ShowWindow is overriden by these flags and possibly hidden.
// so, let's call it the first time with these default flags.
STARTUPINFO sInfo;
GetStartupInfo(out sInfo);
if ((sInfo.dwFlags & StartupInfoFlags.STARTF_USESHOWWINDOW) != 0)
ShowWindow(consoleHandle, ShowWindowFlags.SW_SHOWDEFAULT); // any flag, it is overriden either way
// now ensure the window's visibility
ShowWindow(consoleHandle, ShowWindowFlags.SW_SHOW);
}
}
static bool HasConsoleWindow()
{
return GetConsoleWindow() != IntPtr.Zero;
}
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
protected static extern void GetStartupInfo(out STARTUPINFO lpStartupInfo);
[DllImport("kernel32.dll")]
protected static extern IntPtr GetConsoleWindow();
[DllImport("kernel32")]
protected static extern bool AllocConsole();
[DllImport("kernel32")]
protected static extern bool FreeConsole();
[DllImport("user32.dll")]
protected static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")]
protected static extern bool ShowWindow(IntPtr hWnd, ShowWindowFlags nCmdShow);
[Flags]
protected enum StartupInfoFlags : uint
{
STARTF_USESHOWWINDOW = 0x00000001
}
protected enum ShowWindowFlags : uint
{
SW_HIDE = 0,
SW_SHOW = 5,
SW_SHOWNORMAL = 1,
SW_SHOWMINIMIZED = 2,
SW_SHOWMAXIMIZED = 3,
SW_MAXIMIZE = 3,
SW_MINIMIZE = 6,
SW_SHOWNOACTIVATE = 4,
SW_SHOWMINNOACTIVE = 7,
SW_SHOWNA = 8,
SW_RESTORE = 9,
SW_SHOWDEFAULT = 10,
SW_FORCEMINIMIZE = 11,
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
protected struct STARTUPINFO
{
public UInt32 cb;
public IntPtr lpReserved;
public IntPtr lpDesktop;
public IntPtr lpTitle;
public UInt32 dwX;
public UInt32 dwY;
public UInt32 dwXSize;
public UInt32 dwYSize;
public UInt32 dwXCountChars;
public UInt32 dwYCountChars;
public UInt32 dwFillAttribute;
public StartupInfoFlags dwFlags;
public UInt16 wShowWindow;
public UInt16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
}
}
beste Grüße
zommi
Das Problem ist dass die Mess-Software ausschließlich Konsolenanwendungen zulässt, was anderes kann man leider gar nicht erst aufrufen 😦
Kannst Du das näher erklären?
Ich würde vermuten, dass die Mess-Software sich das Executable vor dem Starten anschaut, und wenn es keine Konsolenanwendung ist, sie nicht startet.
Entweder mit manuellem Lesen des Headers oder mit Hilfe von SHGetFileInfo.
beste Grüße
zommi
Wow,
vielen Dank für eure ausführliche Hilfe! Ich kann leider erst am Dienstag wieder an das Messgerät, aber dann werd ich das Snippet auf jeden Fall ausprobieren und hier Bescheid geben ob alles geklappt hat 😃
Warum das Messprogramm nur Konsolenanwendungen zulässt weiß ich nicht, keine Ahnung was sich die Entwickler dabei gedacht haben 😄
Schöne Grüße,
l2l
Ich würde vermuten, dass die Mess-Software sich das Executable vor dem Starten anschaut, und wenn es keine Konsolenanwendung ist, sie nicht startet.
Man kann ja auch eine WindowsForms-Anwendung als Konsolenanwendung kompilieren. Dann wäre die Mess-Software zufrieden und es gäbe trotzdem ein Fenster zur Ausgabe. Käme auf einen Test an.
Hallo nochmal,
ich wollte das Snippet heute schonmal Zuhause vorab testen damit ich am Dienstag dann direkt den fertigen Code auf das Messgerät laden kann.
Leider kompiliert das Snippet bei mir nicht sondern gibt folgende Fehlermeldung aus:
Fehlermeldung:
"System.ConsoleHelper.StartupInfoFlags" enthält keine Definition für "HasFlag", und es konnte keine Erweiterungsmethode "HasFlag" gefunden werden, die ein erstes Argument vom Typ "System.ConsoleHelper.StartupInfoFlags" akzeptiert. (Fehlt eine Using-Direktive oder ein Assemblyverweis?)
Aber HasFlag sollte doch im System namespace enthalten sein, oder?
Grüße,
l2l
Ab .NET 4.0 wie der Dokumentation zu entnehmen ist.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Habe mein Snippet angepasst.
Ich bin lieber für 2.0 Kompatibilität statt einer winzigen Hilfsmethode.
x.HasFlag(y) ==> (x&y) != 0
beste Grüße
zommi
Danke für das Update,
das Snippet kompiliert jetzt. Hab es auch gleich mal ausgetestet indem ich das Konsolenfenster folgendermaßen versteckt habe:
Console.Title = "test";
IntPtr hWnd = FindWindow(null, "test");
ShowWindow(hWnd, 0);
und dann sol wieder einblenden wollte:
ConsoleHelper.EnsureConsoleVisibility();
Leider stürzt das Programm dann aber ohne eine Exception zu werfen ab. In dem Fenster "Ausgabe" werden aber sehr viele Nachrichten ausgegeben, hier die erste:
Fehlermeldung:
"Test.vshost.exe" (Verwaltet (v4.0.30319)): "C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll" wurde geladen, das Laden von Symbolen wurde übersprungen. Das Modul ist optimiert, und die Debugoption "Nur eigenen Code" ist aktiviert.
Hey,
hab mir den Fehler mal angeschaut. Es ist ein Problem des Marshallings beim PInvoke.
Die Unicode Strings in der STARTUPINFO Struktur können auf einem 64-Bit Windows nicht korrekt beim output der GetStartupInfo Methode gemarshalled werden. 🤔
Laut Internet sollen nullterminierte Strings in Strukturen irgendwie immer problematisch beim Out-Marshalling sein... verstehe es aber ehrlich gesagt nicht. Denn im 32-Bit Modus klappt es einwandfrei... aber Strings sind doch in 32Bit genauso wie in 64Bit... Alles komisch. Falls wer möchte, ich würde darüber gern in 'nem neuen Thread diskutieren?!
Da man den Inhalt der Strings aber nicht brauch, kann man getrost einen IntPtr nehmen. Ich habe das oben mal angepasst. Dann sollte es auch wieder fehlerfrei klappen.
Notiz an mich: Immer vorher Code auch mit .NET 2.0 und x64 testen 😉
beste Grüße
zommi
Hallo nochmal,
ich habe das Snippet jetzt an dem Messgerät ausprobiert und leider funktioniert es nicht. Die Konsole wird nach wie vor nicht angezeigt und die Fehlermeldung ist die Gleiche. An meinem Rechner Zuhause hat alles tadellos funktioniert wenn ich die Konsole manuell versteckt habe, an dem Messgerät klappts irgendwie nicht 😦
Was ich rausgefunden habe: Wenn ich statt dem Snippet die folgenden Zeilen verwende wird die Konsole angezeigt.
FreeConsole();
AttachConsole(-1);
Leider hab ich trotz Anzeige nach wie vor keinen Zugriff darauf, die Fehlermeldng erscheint trotzdem und auch wenn ich das SetWindowSize auskommentiere wird einfach kein Text in die Konsole ausgeben... Das Programm an sich funktioniert aber ja, dann sollte man den Output doch auch irgendwie in die Konsole kriegen, oder?
Schöne Grüße,
l2l
Hallo lot2learn,
wenn es dir nur darum geht, dass die Informationen angezeigt werden, dann folge doch dem letzten Ratschlag von ujr und verwende eine Windows Forms Anwendung, die du als Konsolenanwendung compilierst.
herbivore
Hallo,
ja das kann ich natürlich machen, aber mir geht es auch immer darum was zu lernen, deswegen interessiert mich das jetzt warum das nicht funktioniert... Immerhin wird die Konsole ja jetzt schonmal angezeigt dann kann der letzte Schritt ja nicht mehr weit sein.
Ich finds einfach besser solchen Sachen auf den Grund zu gehen, wenn es möglich ist.
Schöne Grüße,
l2l