Samstag, 14. Mai 2011

Quine Wettbewerb: Finde das kürzeste

Anlässlich des 150. Posts habe ich mir wieder einen kleinen "Wettbewerb" ausgedacht.
Ziel ist es, ein möglichst kurzes Quine zu schreiben, welches eine bestimmte Anweisung ausführt.
Zur Erinnerung: Ein Quine ist ein Programm, welches seinen eigenen Quellcode komplett ausgibt, auf diesem Blog gibt es auch einen Post darüber.
Aufgabe ist es nun, aus folgendem Programm ein Quine zu machen:

class Quine
{
    static void Main(string[] args)
    {
        System.Diagnostics.Process.Start(System.Environment.SystemDirectory + "\\shutdown.exe", "-s -t 120");
    }
}

Der Wettbewerb soll über 3 Wochen laufen, also bis Samstag den 4.5. Wer bis dahin den kürzesten Code gepostet hat, gewinnt ;-)
Ich lege vor.
Das Quine soll natürlich exakt den Programmcode drucken, hierbei sind Zeileneinrückungen aber nicht wichtig.
Ein kleiner Tipp, wie man die Ausgabe leicht überprüfen kann:
Mit Console.SetOut() lässt sich die Ausgabe der Konsole in einen Stream umleiten, so kann z.B. in eine Datei geschrieben werden, also einfach die entsprechenden Befehle in das Programm schreiben (sie zählen nicht zum Quine dazu).
Mit Programmen wie Beyond Compare kann dann die Gleichheit überprüft werden (also definiere, alles was Beyond Compare als gleich ansieht gilt) und mit z.B. Word kann leicht die Länge der Datei gezählt werden.
Mein Quine Code lautet:

class Quine
{
    static void Main(string[] args)
    {
        // Zählt nicht dazu, auskommentieren um Ausgabe umzuleiten: System.IO.StreamWriter sw = new System.IO.StreamWriter(@"C:\Users\User\Desktop\Neues Textdokument (2).txt");
        // ", System.Console.SetOut(sw);
        System.Diagnostics.Process.Start(System.Environment.SystemDirectory + "\\shutdown.exe", "-s -t 120");
        string s = "class Quine {3} {0} {3} static void Main(string[] args) {3} {0} {3} System.Diagnostics.Process.Start(System.Environment.SystemDirectory + {2}{5}{5}shutdown.exe{2}, {2}-s -t 120{2}); {3} string s = {2}{1}{2}; {3} System.Console.WriteLine(s, System.Convert.ToChar(123), s, System.Convert.ToChar(34), System.Environment.NewLine, System.Convert.ToChar(125), System.Convert.ToChar(92)); {3} {4} {3} {4}";
        System.Console.WriteLine(s, System.Convert.ToChar(123), s, System.Convert.ToChar(34), System.Environment.NewLine, System.Convert.ToChar(125), System.Convert.ToChar(92));
        // ", sw.Close();
    }
}

Die Länge hiervon beträgt 763 Zeichen.

Und jetzt, viel Glück und viel Spaß.

PS: Speichert vorher alle Dokumente bzw. schaut euch an, wie man das Herunterfahren von Windows abbrechen kann (Stichwort: shutdown -a).

Samstag, 7. Mai 2011

Anwendung mit Administratorrechten neu starten (Windows Vista / 7)

In einem älteren Post habe ich gezeigt, wie man mit C# eine Anwendung mit Administratorechten ausstatten und starten kann.
Hierfür wurde jedoch eine eigene Datei, die Anwendungsmanifestdatei, benötigt.
Auf Anfrage eines Lesers möchte ich heute einen kleinen Trick vorstellen, wie man eine Anwendung nur durch reinen Code mit diesen Rechten ausstattet.
Entscheidend ist hierbei die Klasse System.Diagnostics, welche einen beliebigen Process mit bestimmten Argumenten starten kann.
Wenn die Anwendung also normal gestartet wird, wird sie über diese Klasse mit Administratorrechten neugestartet.
Damit das Programm nicht unendlich oft aufgerufen wird, geben wir dem Programm zur Prüfung beim Aufrufen ein neues Befehlszeilenargument mit.
Der folgende Code sollte das Beispiel erläutern:

private void Form1_Load(object sender, EventArgs e)
{
    string[] CommandLineArgs = Environment.GetCommandLineArgs(); // Befehlszeilenargumente auslesen
    if (CommandLineArgs.Length <= 1 || CommandLineArgs[1] != "restarted") // ist das 2. Argument (das 1. ist immer der Dateipfad) != restarted, wurde das Programm noch nicht neugestartet
    {
        ProcessStartInfo ProcessInfo = new ProcessStartInfo(Application.ExecutablePath, "restarted"); // Prozessinformationen festlegen, Anwendungspfad und unser eigenes Argument "restarted"
        ProcessInfo.Verb = "runas"; // Befehl zum Ausführen als Administrator
        Process.Start(ProcessInfo); // Prozess mit den eingestellten Informationen starten
    }
    else
        Environment.Exit(0); // wurde das Argument "restarted" übergeben, wurde das Programm bereits gestartet, um die Endlosrekursion zu verhindern, nicht erneut aufrufen
}

Freitag, 6. Mai 2011

Befehlszeilenargumente auslesen

Programme können unter Windows grundsätzlich mit verschiedenen Argumenten aufgerufen werden, welche Befehlszeilenargumente heißen.
Zum Beispiel können einige Programme direkt mit zu öffnenden Dateien als Argument aufgerufen werden.
In Konsolenanwendungen in C# stehen diese Kommandozeilenargumente direkt als Parameter der Funktion Main() zur Verfügung.
In Windows Forms-Anwendungen stehen diese so nicht bereit, dafür gibt es aber die Funktion Environment.GetCommandLineArgs(), welche die Befehlszeilenargumente als Array vom Typ String zurückgibt.
Folgender Code liest die übergebenen Parameter beim Programmstart aus:

string[] CommandLineArgs = Environment.GetCommandLineArgs();

Wie man sieht, wird als 1. Parameter immer der Pfad und der Name des ausgeführten Programmes übergeben.