Laden...

Forenbeiträge von AyrA Ingesamt 60 Beiträge

10.02.2015 - 08:39 Uhr

Das .NET Team hat den .NET 5 Core veröffentlicht. Dieser erlaubt das Ausführen von Webseiten. Nur mscorlib code ist dort enthalten.
Er ist kompilierbar auf Linux und erlaubt daher erstmals das Ausführen von ASP.NET auf linux.

The coreclr repo contains the complete runtime implementation (called "CoreCLR") for .NET Core. It includes RyuJIT, the .NET GC, native interop and many other components. It builds and runs on Windows. You can 'watch' the repo to see Linux and Mac support being added over the next few months.

.NET Core is part of ASP.NET 5 and is a subset of the .NET Framework. You can learn more about .NET Core and how and where you can use it in the CoreCLR is open source blog post.

The .NET Core Libraries repo contains the base class libraries, which provides data types and base functionality (ex: String, Collections, HttpClient) on top of CoreCLR. The two repos together make up .NET Core. The .NET Core is Open Source and Introducing .NET Core blog posts describes our .NET Core OSS strategy and road map in more detail.

Github Repository: https://github.com/dotnet/coreclr

Die meisten .NET libraries sind unter https://github.com/dotnet/corefx zu finden, linux und mac Support wird noch hinzugefügt.

09.02.2015 - 15:42 Uhr

Beschreibung:

Das Problem bei Threads ist, dass nicht einfach auf das Form zugegriffen werden kann. Normalerweise möchte man aber nach dem Ende eines Threads die verarbeiteten Informationen anzeigen. Der Dispatcher vereinfacht dies erheblich. Das System funktioniert über callbacks, ähnlich wie bei javascript üblich. Die callbacks können daher inline definiert werden und haben zugriff auf den Zustand der Methode in der sie definiert werden.

Aufruf (mit inline funktionen):


Dispatcher.Dispatch(
delegate(object[] args){System.Threading.Thread.Sleep(10000);args[0]="test";},
delegate(object[] args){labelTest.Text=(string)args[0];},
new object[]{null});

Was macht das
Die erste delegate wird asynchron in einem Thread aufgerufen. Die 10 Sekunden Wartedauer beeinflussen nicht die Anwendung.
Die zweite delegate wird aufgerufen, wenn die erste vorbei ist. Die Argumente sind für beide delegates das selbe Array, der erste Aufruf kann also Parameter in den zweiten Aufruf übergeben.
der zweite Aufruf ist immer synchron zum GUI Thread, sofern mindestens ein Form existiert.
Sollte keins existieren (or SYNCHRONIZE direktive ist nicht gesetzt) dann wird die delegate ebenfalls asynchron aufgerufen, dies macht Sinn für Konsolenanwendungen.

Der object-Parameter dient dazu, Argumente zu übergeben. Der Index muss definiert werden (wenn auch null). Verändern der array werte wird jeweils auf der Referenz ausfegührt, deshalb benötigen Stream.Read Aufrufe auch kein "ref" Schlüsselwort. Das selbe Prinzip wird hier ausgenutzt. Der parameter wird an beide callbacks übergeben.

Der obige Aufruf geht davon aus, dass der Aufruf in einem Form mit einem "labelTest" ausgeführt wird

Abhängigkeiten
Läuft unter .NET 2.0. Ist SYNCHRONIZE definiert, dann wird eine Referenz auf System.Windows.Forms benötigt.

Verwendungszwecke

  • Hintergrundaufgaben einfach planen und ausführen.
  • Events zeitverzögert von Form B nach Form A senden, z.B. wenn Form A eine liste mit einträgen enthält und Form B eine Bestätigung zum verarbeiten aller Einträge einholt, kann A benachrichtigt werden, wenn die Operation abgeschlossen ist.
  • Asynchrones I/O. z.B. bei Socket.BeginConnect.
  • Wrapper für beliebige klassen die keine synchronen callbacks anbieten oder nicht asynchron arbeiten. (Thread, Socket, TcpListener, Console.In,Out,Err).

//Define SYNCHRONIZE if it is a window application.
//Console applications do not need this.
#define SYNCHRONIZE

using System.Threading;

#if SYNCHRONIZE
using System.Windows.Forms;
#endif

namespace Dispatch
{
    /// <summary>
    /// callbacks for Dispatch functions
    /// </summary>
    /// <param name="args">Arguments for callback</param>
    public delegate void DispatchHandler(object[] args);

    /// <summary>
    /// Provides an easy event dispatcher
    /// </summary>
    public static class Dispatcher
    {
        /// <summary>
        /// Runs "Method" asynchronously and calls "Callback" synchronously after it
        /// </summary>
        /// <param name="Method">Method to run async</param>
        /// <param name="Callback">Callback to run sync (if possible, otherwise async)</param>
        /// <param name="Args">Arguments for "Method" and "Callback"</param>
        /// <returns>Thread object for the call (already running)</returns>
        public static Thread Dispatch(DispatchHandler Method, DispatchHandler Callback, params object[] Args)
        {
            //Inline functions in C# are almost as easy as in JS.
            Thread T = new Thread(delegate()
            {
                bool called = false;
                Method(Args);
#if SYNCHRONIZE
                //try to call the method in sync with the application loop.
                for (int i = 0; i < Application.OpenForms.Count && !called; i++)
                {
                    if (!Application.OpenForms[i].IsDisposed)
                    {
                        called = true;
                        Application.OpenForms[i].Invoke(Callback, Args);
                    }
                }
#endif
                //if not called, the call it async.
                if (!called)
                {
                    Callback.Invoke(Args);
                }
            });
            //uncomment the next line if you want this call to terminate,
            //if your application exits
            //T.IsBackground = true;
            T.Start();
            return T;
        }
    }
}

Mögliche Anpassungen

  • Ermöglichen, dass der DispatchHandler einen Rückgabewert haben kann.
  • Ändern des generischen "params object[]" in ein geeigneteres Format.

Schlagwörter: dispatcher, synchron, thread, threads, callback

04.02.2015 - 14:50 Uhr

Adobe hat so etwas für videos, die nennen das GapStop und es funktioniert hervorragend:

https://www.youtube.com/watch?v=xi2lYi8qil4

Für Audio weiss ich auch nichts. Könnte schwierig werden ein kurzes "Ähm" von einem "Etwas" zu unterscheiden je nach Dialekt. Für manuell gibt es jau audacity.

03.02.2015 - 15:11 Uhr

Beschreibung

WADex ist ein Konsolenprogramm, welches Features bereit stellt, um WAD Dateien zu bearbeiten.

WAD Datei
WAD ist das Dateiformat von id Games. Es wurde insbesondere für ältere Spiele, wie DOOM verwendet.

Format


WAD Datei

+------------------------+
| Header | Daten | Index |
+------------------------+


Header: Struktur mit 3 Feldern

+--------------------+
| ID | Num-E | Ptr-I |
+--------------------+

ID: String; IWAD oder PWAD, immer 4 Zeichen
Num-E: Int32; Anzahl Verweise im Index
Ptr-I: Int32; Begin des Inhaltsverzeichnis


Daten

+-------+
| Bytes |
+-------+

Bytes: Byte[]; Daten, roh aneinander gelegt


Index

Der Index Beinhaltet folgende Struktur, so oft, wie in Num-E angegeben:

+------------------+
| Pos | Len | Name |
+------------------+

Pos: Int32; Position in der Datei
Len: Int32; Anzahl Bytes des Eintrags
Name: String; Name des Eintrags, immer 8 Zeichen, mit Leerzeichen gefüllt

Wenn Len und Pos 0 sind, dann ist der Eintrag "Virtuell" und dient als Struktur.
Einträge haben keine Datentypen, daher werden diese Teilweise mit solchen virtuellen Einträgen gruppiert.
Man erkennt sie auch an dem Format *_BEGIN und *_END

Es gibt keinen Schutz der Angaben. Die Position kann irgendwo in der Datei sein. Sie kann Bereiche anderer Dateien überlagern oder sogar ins Inhaltsverzeichnis reichen. Ein beliebter Trick z.B. bei Musikdateien: Anstatt in einem Level die selbe Musik zu referenzieren, wie in einem anderen, wird stattdessen die Musikdatei zweimal referenziert, somit kann später für ein Level eine andere Musik festgelegt werden, ohne die Leveldatei zu bearbeiten.
Dies kann in der originalen DOOM2.WAD (leider nur kommerziell erhältlich) Datei nachgesehen werden und ist teilweise auch in anderen frei erhältlichen WAD Dateien so gemacht.

Nutzen
Das Tool erlaubt das extrahieren von Ressourcen aus WAD Dateien und das Erstellen von WAD Dateien.
Des Weiteren können einige Doom-Interne Formate in Windows Formate umkonvertiert werden (sprites, audio). Beim extrahieren erkennt das Programm den Dateityp automatisch und führt gleichzeitig noch eine Massenkonvertierung durch. Das Tool ist meines Wissens nach das einzige, welches die MUS Formate in MIDI konvertieren kann und auf 64 bit Windows läuft.

Einschränkungen
Die Konvertierung ist zur Zeit unidirektional. Die konvertierten Dateien werden in einem zusätzlichen Unterordner gespeichert und werden bim Assemblieren nicht benötigt. Natürich können auch einzelne Dateien konvertiert werden.

Kompression
Das Tool "komprimiert" die WAD Datei beim assemblieren. Komprimieren in Anführungszeichen, weil WAD Dateien nicht komprimierbar sind (zumindestens nicht für DOOM). Einträge können jedoch "übereinander" gelegt werden, wenn sie identisch sind. Das Tool macht dies voll automatisch. Sogar die originale DOOM2.WAD konnte ich so noch verkleinern. Kompression spart Arbeitsspeicher, Dateigrösse und ist ein Gewinn an Geschwindigkeit.

Index
Beim extrahieren wird eine Indexdatei "!INDEX.TXT" angelegt. Diese enthält alle Dateien, die aus der WAD Datei stammen. Beim Assemblieren wird diese Datei verwendet, um die Daten wieder in die WAD Datei einzufügen.

Lizenz
Das Tool veröffentliche ich wie üblich unter WTFPL.
Die originale DOOM engine ist open source für nicht-kommerzielle Zwecke.
Wer eine IWAD benötigt, findet eine freie auf Github.

IWAD oder PWAD

Eine IWAD enthält ein vollständiges Spiel (Grafiken, Sounds, Maps, Monster,Waffen, Items, etc). In einem Spiel ist immer genau eine IWAD Datei vorhanden.
Eine PWAD Datei tauscht existierende Resourcen aus und fügt neue hinzu. Ein Spiel kann mehrere PWAD Dateien haben.

PWAD zu IWAD konvertieren
Dadurch wird die Ladezeit verkürzt und die Distribution wird einfacher (Erlaubnis für Distribution der IWAD ist natürlich erforderlich):
1.IWAD extrahieren in Ordner A 1.PWAD extrahieren in Ordner B 1.Dateien (ohne Index) von B nach A verschieben und alles überschreiben 1.Nicht existierende Zeilen in der Indexdatei von A mit denen von B ergänzen 1.A assemblieren

Kommandozeile


WAD extractor and assembler by AyrA
WADex <operation> <WADfile> [Directory]
WADfile     required WADfile to operate on
operation   Action to perform
            E - Extract all resources to 'Directory' path
            A - Assemble WAD from 'Directory' path
            C - Convert a WAD image to png (or mus to mid)
            I - List resources ('Directory' not to be supplied)
Directory   Directory for 'A' and 'E' operation
Specify only the operation parameter to get specific help

Download und detailiertes Readme. Eine kompilierte EXE Datei ist im Release Ordner vorhanden.

Alternative Verwendung
Durch kleinere Anpassungen (int durch long ersetzen und längere Dateinamen im Index zulassen) kann das Format als eine Art "tar" Ersatz verwendet werden, da es im Grunde ein serialisiertes Dictionary<string,byte[]> darstellt.

Grund für Entwicklung
Sollte eigentlich nur ein MUS2MID Konverter werden für einen Kumpel. Habs wohl etwas übertrieben.

26.09.2014 - 03:22 Uhr

Das Problem ist dann, dass es in Mono nicht mehr kompiliert, sobald ich Windows API verwende und ich brauche dieses Script leider auch auf linux maschinen. Ansonsten wäre es überlegenswert, da je nach maske erheblich komplexere strukturen entstehen können.

25.09.2014 - 22:03 Uhr

Beschreibung:

Diese Klasse verarbeitet Pfadangaben, welche Platzhalter auf mehreren Ebenen enthält,
z.B: "C:\Users***d*" oder "C:\te?t*\q12???8**.xls*"

unterstützt relative Angaben, wie z.B. "....**", welches auch relative resultate liefert

Verwendung:
Die Verwendung ist einfach:


string[] Files = MaskMatch.Match(@"C:\Users\*\*\*d*", MatchType.All);

Mit dem MatchType kann angegeben werden, ob der letzte Pfadabschnitt Dateien, Verzeichnisse oder beides sucht.

Performance:
Hat mit dem Beispielaufruf oben 616 Dateien in 200 ms gefunden bei mir.


using System;
using System.Collections.Generic;
using System.IO;

    [Flags]
    public enum MatchType : int
    {
        File = 1,
        Directory = 2,
        All = File | Directory
    }

    public static class MaskMatch
    {
        private static readonly char[] Masks = new char[] { '*', '?' };

        /// <summary>
        /// Durchsucht Eine Dateistruktur nach der Maske entsprechenden Dateien/Ordner
        /// </summary>
        /// <param name="Mask">Suchmaske Beispiel: C:\te?t\*\q12???8*\*.xls*</param>
        /// <param name="Condition">Suchbedingungen (Dateien, Ordner)</param>
        /// <returns>Gefundene Dateien/Ordner</returns>
        public static string[] Match(string Mask, MatchType Condition)
        {
            List<string> Matches = new List<string>();
            string[] Patterns = getPatterns(Mask);
            for (int i = 0; i < Patterns.Length; i++)
            {
                if (i == 0)
                {
                    if ((Condition & MatchType.Directory) > 0 || i < Patterns.Length - 1)
                    {
                        Matches.AddRange(getDirectories(Patterns[i]));
                    }
                    if ((Condition & MatchType.File) > 0)
                    {
                        Matches.AddRange(getFiles(Patterns[i]));
                    }
                }
                else
                {
                    string[] temp = Matches.ToArray();
                    Matches.Clear();
                    foreach (string d in temp)
                    {
                        if ((Condition & MatchType.Directory) > 0 || i < Patterns.Length - 1)
                        {
                            Matches.AddRange(getDirectories(Path.Combine(d, Patterns[i])));
                        }
                        if ((Condition & MatchType.File) > 0)
                        {
                            Matches.AddRange(getFiles(Path.Combine(d, Patterns[i])));
                        }
                    }
                }
            }

            return Matches.ToArray();
        }

        /// <summary>
        /// Durchsucht eine Dateistructur nach der Masken entsprechenden Dateien/Ordner
        /// </summary>
        /// <param name="Masks">Masken</param>
        /// <param name="Condition">Suchbedingungen (Dateien, Ordner)</param>
        /// <param name="RemoveDuplicates">Entfernen von Duplikaten</param>
        /// <returns>Gefundene Dateien/Ordner</returns>
        public static string[] Match(string[] Masks, MatchType Condition, bool RemoveDuplicates)
        {
            List<string> L = new List<string>();
            foreach (string Mask in Masks)
            {
                string[] result = Match(Mask, Condition);
                if (RemoveDuplicates)
                {
                    foreach (string entry in result)
                    {
                        if (!L.Contains(entry))
                        {
                            L.Add(entry);
                        }
                    }
                }
                else
                {
                    L.AddRange(result);
                }
            }
            return L.ToArray();
        }

        /// <summary>
        /// Teilt eine Suchmaske in Teile auf, die von System.IO Klassen verwendet werden können
        /// </summary>
        /// <param name="Mask">Komplette Suchmaske</param>
        /// <returns>Aufgeteilte Suchmaske</returns>
        private static string[] getPatterns(string Mask)
        {
            List<string> Patterns = new List<string>();
            string[] temp = Mask.Split(Path.DirectorySeparatorChar);
            string current = temp[0] + (temp[0].Contains(":") ? Path.DirectorySeparatorChar.ToString() : string.Empty);
            for (int i = 1; i < temp.Length; i++)
            {
                if (temp[i].IndexOfAny(Masks) >= 0)
                {
                    Patterns.Add(Path.Combine(current, temp[i]));
                    current = string.Empty;
                }
                else
                {
                    current = Path.Combine(current, temp[i]);
                }
            }
            return Patterns.ToArray();
        }

        /// <summary>
        /// Durchsucht Verzeichnisse nach Verzeichnissen mit der entsprechenden Maske
        /// </summary>
        /// <param name="Mask">Suchmaske (Pfad\Maske)</param>
        /// <returns>Gefundene Verzeichnisse</returns>
        private static string[] getDirectories(string Mask)
        {
            string Dir = Mask.Substring(0, Mask.LastIndexOf(Path.DirectorySeparatorChar));
            string Arg = Mask.Substring(Mask.LastIndexOf(Path.DirectorySeparatorChar) + 1);
            try
            {
                return Directory.GetDirectories(Dir, Arg);
            }
            catch
            {
            }
            return new string[0];
        }
        
        /// <summary>
        /// Durchsucht Verzeichnisse nach Dateien mit der entsprechenden Maske
        /// </summary>
        /// <param name="Mask">Suchmaske (Pfad\Maske)</param>
        /// <returns>Gefundene Dateien</returns>
        private static string[] getFiles(string Mask)
        {
            string Dir = Mask.Substring(0, Mask.LastIndexOf(Path.DirectorySeparatorChar));
            string Arg = Mask.Substring(Mask.LastIndexOf(Path.DirectorySeparatorChar) + 1);
            try
            {
                return Directory.GetFiles(Dir, Arg);
            }
            catch
            {
            }
            return new string[0];
        }
    }

Lizenz: WTFPL. Namensnennung (AyrA) wäre nett aber nicht erforderlich.
Ausnahmsweise mal auf Deutsch kommentiert.

Habe diese Klasse erstellt, weil ich im Internet nichts passendes gefunden habe, was nur das macht und nicht mehr.

Schlagwörter: Pfad Datei Suchpfad Dateien Mask Maske Wildcard

10.08.2014 - 18:26 Uhr

Ich habe den algorithmus angepasst. Dieser verwendet nun den FIPS-140 zertifizierten RNGCryptoServiceProvider, dadurch wird die Int32 Limitation aufgehoben.

09.08.2014 - 21:30 Uhr

Es ist auch gewollt, dass du die Verschlüsselte Datei X mit der Verschlüsselten Datei X+1 entschlüsseln kannst. X+1 kannst du ohne X+2 nicht entschlüsseln. Ich kann nach und nach Dateien freigeben und das erlaubt jeweils die entschlüsselung der vorangehenden. Wenn ich dir V1 und V2 gebe dann kannst du V2 nicht entschlüsseln, erst wenn ich dir V3 gebe (und dann wiederum kannst du V3 nicht entschlüsseln)

09.08.2014 - 13:14 Uhr

Dieser Post erklärt, wie die Verschlüsselung realisiert wird
Das Verfahren zu kennen ist nicht notwendig, hilft aber zu verstehen, warum nur 1 Schlüssel benötigt wird

Schlüssel
unabhängig von der Anzahl Dateien wird immer exakt 1 Schlüssel benötigt. Das Programm scannt alle Dateien und berechnet welche Datei die grösste wird, dabei wird der Header mit eingerechnet. Es wird dann ein Schlüssel erstellt, der exakt diese Länge aufweist und gespeichert. (key.bin).

Verschlüsselung
Die Datei, welche als letztes freigegeben wird wird nun genommen und byteweise XOR verknüpft mit dem Schlüssel (ohne Header). Das Prinzip ist bekannt aus der OTP Verschlüsselung.
Sollte die Datei + Header kürzer sein, als der Schlüssel, werden nun zufällig generierte Bytes an die Datei angehängt. Anschliessend wird der Header ebenfalls verschlüsselt und an die Datei angehängt.

Mehrere Dateien
Werden mehrere Dateien verschlüsselt, wird die zweite Datei mit der ersten verschlüsselt (also mit dem Ergebnis des ersten Durchlaufes). Da ein Schlüssel aus beliebigen Bytes bestehen kann und keiner Form folgen muss, kann jede verschlüsselte Datei selbst als Schlüssel verwendet werden. Dies ist einer der Gründe, warum alle Dateien auf die selbe Grösse aufgeblasen werden.
Wenn wir 5 Dateien verschlüsseln wollen ergibt sich also folgendes:

D - Datei mit padding und Header
S - Schlüssel
V - Verschlüsselte Datei mit Paddung und Header

    • XOR operation

D5 + S -> V5
D4 + V5 -> V4
D3 + V4 -> V3
D2 + V3 -> V2
D1 + V2 -> V1

Kontrollierte Freigabe
Möchte ich nun V2 entschlüsseln, benötige ich Zwangsläufig V3. Das bedeutet, solange der Anbieter V3 nicht freigegeben hat, kann ich V2 nicht entschlüsseln.
Wird V3 freigegeben, kann ich V2 zu D2 entschlüsseln, anhand des Headers kann ich das Padding entfernen (oder besser: dieses gar nicht erst verarbeiten) und den wahren Dateinamen ermitteln.
Habe ich D2, kann ich diese nun verwenden. um wiederum V3 zu entschlüsseln, muss ich warten, bis V4 verfügbar wird.

Entschlüsselung
Bei der Entschlüsselung ist der Header sehr wichtig. Ich will nicht für eine Audiodatei 700 MB entschlüsseln, nur weil eine Videodatei im Set beiliegt, die die Grösse massiv erhöht. Die Entschlüsselung funktioniert daher folgendermassen:

Zuerst werden die letzten 4 Bytes entschlüsselt, diese teilen uns die Headergrösse mit.
Wir entschlüsseln mit dieser Information den kompletten Header.
Aus den ersten 8 bytes des Headers ermitteln wir die Dateigrösse, dadurch können wir das Padding ignorieren.
Aus den nächsten 4 bytes ermitteln wir die Länge des Dateinamens.
Anschliessend lesen wir den Dateinamen aus.

Jetzt enschlüsseln wir so viele Bytes vom Anfang der verschlüsselten Datei, wie der Header angegeben hat und benennen die Datei dem header entsprechend.

09.08.2014 - 01:58 Uhr

AOTP ist einer Idee entsprungen, die ich einmal hatte.

Wenn man heute Dateien ins Internet stellen möchte und kontrollieren möchte, von wann an die Datei verwendet werden kann, muss ich diese verschlüsseln und das Passwort bei Bedarf freigeben, dies hat gewisse Nachteile:

Für jede Datei muss ein anderes Passwort gewählt werden. Passwörter müssen sicher aufbewahrt werden. Es muss sehr genau darauf geachtet werden, welches Passwort wann freigegeben wird. Des Weiteren verrät die Dateigrösse üblicherweise den Inhaltstyp.

AOTP behebt einige dieser Probleme.
*Verschlüsselt mehrere Dateien mit nur einem Schlüssel, der Schlüssel passt aber nur auf eine Datei *Nur 1 Byte RAM wird benötigt pro Stream (3 Bytes für Entschlüsselung oder Verschlüsselung total). Das Programm verwendet mehr RAM aufgrund des enormen Geschwindigkeitszuwachs *byteweise und nicht blockweise Verschlüsselung erlaubt das Springen zu einer beliebigen Stelle *Alle verschlüsselten Dateien haben dieselbe Grösse *Verschlüsselung verwendet XOR Operation, welche auch in RISC CPUs vorhanden ist *Algorithmus ist sehr simpel und kann bei Bedarf einfach aus dem Kopf programmiert werden in jeder beliebigen Umgebung

Werden mehrere Dateien verschlüsselt können diese anschliessend der Reihe nach freigegeben werden. Zuerst Datei 1, anschliessend 2 (erlaubt Entschlüsselung von 1), dann 3 und so weiter. Zum ende der Schlüssel für die letzte Datei.
Dateien enthalten einen verschlüsselten Header, der den originalen Dateinamen enthält. Die verschlüsselte Datei kann daher beliebig umbenannt werden.

Die hier angebotene Anwendung dient als Demonstration. Der Schlüsselgenerator verwendet den Zufallsgenerator aus dem System.Cryptography namespace. Weitere 2 Generatoren liegen zu Testzwecken bei.

Source code und detailiertes Readme: GitHub
Kompilierte EXE Datei: GitHub (Digital signiert)

EDIT: RNG jetzt kryptografisch sicher

09.08.2014 - 01:28 Uhr

cool wäre jetzt noch, das Ganze in die Originalspezifikation zu zwängen (25x80)

Soweit ich weiss, war original nur 25 Zeilen a 80 Zeichen erlaubt, also DOS konsolengrösse. Auch gibt es den Befunge-98 Standard, der dir vielleicht noch gefällt, da das koordinatensystem einiges grösser ist und der Befehlssatz erweitert wurde: Funge-98 Final Specification

24.07.2014 - 23:50 Uhr

Das hier angebotene Projekt besitzt mehrere Funktionen, rund um Labyrinthe. Eine abgespeckte Version habe ich in der Vergangenheit schon einmal in Excel gemacht.

Labyrinth generieren
Labyrinthe beliebiger dimensionen (sie müssen im RAM platz haben) können generieren, von 5x5 an. Ein oberes limit ist nicht gesetzt, ab 2 GB wird es kritisch.
Alle generierten Labyrinthe besitzen exakt eine Lösung. Die generierende Klasse bietet den Seed des Zufallsgenerators an, dadurch kann das selbe Labyrinth mehrmals erzeugt werden. Das Feature wurde jedoch noch nicht produktiv verwendet, ist aber vorhanden. Die Labyrinthe beginnen oben links und enden unten rechts.

Labyrinthe einlesen
Labyrinthe können aus verschiedenen Datei formaten eingelesen werden (Siehe abschnitt ausgabe). Nach möglichkeit wird das Eingabeformat automatisch erkannt.

Labyrinthe lösen
Das Programm kann labyrinthe lösen oder den Lösungsstatus eines Labyrinths zurücksetzen.

Labyrinthe ausgeben
Labyrinthe können in der Konsole oder in Dateien ausgegeben werden.
Die Möglichkeiten sind: Nummeriert, ASCII, UTF-8, CSV, Binär, Bild.
Alle Ausgabe Formate können auch als Eingabe verwendet werden (Ja, auch Bilder)

Nummeriert speichert alle elemente als einstellige Zahlen (als Strings)
ASCII benutzt verschiedene ASCII Zeichen (alle im original ASCII Zeichensatz enthalten)
UTF-8 benutzt Spezielle Zeichen um Rahmen und Pfade zu zeichen. Dies sieht etwas grafischer aus, als ASCII ausgabe.
CSV ist Nummeriert, aber als CSV formatiert.

Obige Formate sind alle als Datei- oder Konsolenausgabe verfügbar, untenstehende nur für Dateien.

Binär speichert nur Wände und Pfade, keine Lösungen oder Positionen von Start und Ende. Die Dateigrösse ist üblicherweise 1/8 der Labyrinthgrösse
Bild ausgabe speichert das Labyrinth als PNG Datei. Die Grösse eines Elementes kann als Skalierungsfaktor angegeben werden. Die Dimensionen eines Bildes sind je nach PC etwa auf 30000x30000 Pixel beschränkt. sehr grosse Bilder können mit Windows internen Mitteln nicht mehr betrachtet werden und benötigen GIMP oder ein Webbrowser als Betrachter. Sollten Probleme beim Speichern auftauchen wird folgendes unternommen:
Zuerst wird versucht das Bild ohne Skalierung zu speichern, sollte das nicht gelingen, wird das Labyrinth im Binärformat gespeichert.

Labyrinth spielen
Labyrinthe können direkt in der Konsole gespielt werden. Der Fortschritt kann gespeichert werden um ihn später wieder aufzunehmen. Es konnen Labyrinthe direkt in der Konsole gelöst werden, auch wenn sie höher und breiter sind als die Konsole. Es wird jeweils versucht um den Spieler zu zentrieren.
Es existieren 3 Modi:

Normal: Das Labyrinth ist komplett sichtbar
FOW: (Fog of War) Nicht sichtbare Bereiche werden ausgeblendet, auch wenn sie mal sichtbar waren
MAP: Wie FOW aber einmal entdeckte Bereiche bleiben sichtbar.

Labyrinthe konvertieren
Da Eingabe- und Ausgabedatei sowie Format gleichzeitig angegeben werden können, kann das Programm existierende Labyrinthe in andere Formate konvertieren.

Umfangreiche Hilfe
Die Kommandozeilenhilfe ist äusserst umfangreich (ca 80 Zeilen)

Lizenz
WTFPL

Screenshot
(Siehe zweiter Beitrag)

Optionen
(Grundsätzlich die Ausgabe der Hilfe)

Maze Tools
mazeTools.exe [/W:<number>] [/H:<number>] [/M:<number>] [/S] [/O:<format>]
              [/I:<format>] [/G] [/FOW] [/R:<infile>] [/P:<outfile>] [/MAP]

/W:<number>   Width of the maze, if not specified, window width is used
/H:<number>   Height of the maze, if not specified, window height is used
/M:<number>   Output multiplication factor, 1 or bigger. Default: 1
              this only affects image inputs and outputs
/O:<format>   Output format (see below), defaults to UTF
/I:<format>   Input format (see below), defaults to UTF
/S            Solves the Maze
/G            Game: Allow the user to solve manually
/FOW          Fog of war: maze is invisible except for current player view
/MAP          Map: once uncovered tiles (using /FOW) will stay visible
/R:<infile>   input file, if not specified, a maze is generated using
              W and H arguments. If specified, W and H are ignored
/P:<outfile>  output file, if not specified, the console is used (stdout)

Mazes always start at the top left corner and end at the bottom right corner.
Loading a maze from file (except binary) will find start and end.
Mazes always have an uneven rows and columns. Supplied values are adjusted
in case they are even. (subtraction only)

Formats:      Numbered: Output consists of Numbers only (with line breaks):
                        0=way
                        1=wall
                        2=start
                        3=end
                        4=solution
                        5=player
              ASCII: Output in ascii printable chars. Each char is 1 byte.
                  (space)=way
                        #=wall
                        S=start
                        E=end
                        .=solution
                        !=Player
              UTF: similar to ASCII but with multibyte chars
                  (space)=way
                        ˆ=wall
                        S=start
                        E=end
                          solution: Line drawing ASCII art
                        :=player
              CSV: Similar to numbered format, but comma separated
              Binary: Compressed binary, only ways and walls
              Image: PNG image of maze using Colors
                    black=wall
                    white=way
                    green=start
                      red=end
                   yellow=solution
                  magenta=player

if a format is not specified, it is detected by file extension:
UTF     =txt
ASCII   =txt
CSV     =csv
BINARY  =bin
Numbered=txt
Image   =png

Detecting multiple txt formats is done by looking at the first
char of a file, since there is a border around the maze, the
first char is always a wall. The Wall differs from numbered to
UTF to ASCII.

The /G switch:
The /G switch lets the user play the maze in the console after
all other switches are processed. Console output is disabled,
if /G is specified, /P can to be used to save the maze progress.
/FOW only works together with /G

The /FOW switch:
When specified, the maze region is invisible except for the players
field of view. This makes solving mazes a lot more complicated.
The drawn path you took is still saved and visible again, if you
backtrack a little. Does not affects save file.

The /MAP switch:
This switch only works together with /FOW. If specified, once
uncovered tiles stay visible, as if the player drew a map.
Does not affects save file.

Noch zu erledigen*.maz Dateien erstellen und einlesen, die nur Dimensioenn und Seed beinhalten *Multiplayer? Co-op oder VS Modus (siehe Idee unten) *Scrolling erlauben ohne die Spielfigur zu bewegen *GUI Frontend für nicht so Konsolenversierte benutzer *Hintergrundverarbeitung mit Events (alle Funktionen blockieren zur Zeit noch, da kein GUI)

multiplayer
Multiplayer könnte in 2 Modi geschrieben werden:
Co-op: Spieler starten in den gegenüberliegenden Ecken und versuchen das Labyrinth so schnell wie möglich mit so wenig Fehlern wie möglich fertig zu stellen. Das Spiel stoppt, sobald ein Spieler auf den Pfad des anderen trifft.
VS: wie- co-op. Sobald die Spieler miteinander kollidieren wird das Spiel gestoppt und die Punkte ausgewertet.

Die einzelnen Funktionen und Werte besitzen einen Header Kommentar.

Viel Spass

11.05.2014 - 16:23 Uhr

Neues Update
*Playlist downloads wurden teilweise nach 80 Einträgen abgebrochen, dies funktioniert nun korrekt. *GUI von ytViewer wurde verbessert. Unterstützt nun Resizing

07.08.2013 - 02:40 Uhr

Beschreibung:

meiner Meinung nach fehlt im .NET Framework die Fähigkeit Konsolentext farbig auszugeben. Die Implementierung über Console.ForegroundColor ist mir zu aufwändig, insbesondere, wenn ich eigentlich gerne mehrere Farben auf einer Zeile ausgeben möchte.
ich mag Konsolen Anwendungen nach wie vor, da sie einfaches Scripting erlauben, Fehlermeldungen oder ähnliches möchte ich dennoch gerne farblich hervorheben, ohne jedesmal irgendwelche Funktionen zu schreiben, die dann trotzdem in einem anderen Projekt nicht mehr passen.

Ich habe daher zwei Funktionen geschrieben, die die nervtötende Arbeit des Farbensetzens abnehmen.

Klasse


using System;
using System.Globalization;

namespace AyrA
{
    /// <summary>
    /// Bietet einfachen Zugriff um Text farbig darzustellen in der Konsole.
    /// </summary>
    public static class PrintColor
    {
        /// <summary>
        /// Gibt die Konsolenfarben zurück, hexadezimal sortiert, von 0-F
        /// </summary>
        public static ConsoleColor[] ColorRow
        {
            get
            {
                ConsoleColor[] c = new ConsoleColor[16];
                for (int i = 0; i < 16; i++)
                {
                    c[i] = (ConsoleColor)i;
                }
                return c;
            }
        }

        /// <summary>
        /// Schreibt eine Zeile mit farbigem Text, inklusive Zeilenumbruch
        /// </summary>
        /// <param name="text">Zu schreibender Text</param>
        /// <param name="mapF">Vordergrundfarben</param>
        /// <param name="mapB">Hintergrundfarben</param>
        public static void printColorL(string text, string mapF, string mapB)
        {
            printColor(text, mapF, mapB);
            Console.WriteLine();
        }

        /// <summary>
        /// Schreibt eine Zeile mit farbigem Text
        /// </summary>
        /// <param name="text">Zu schreibender Text</param>
        /// <param name="mapF">Vordergrundfarben</param>
        /// <param name="mapB">Hintergrundfarben</param>
        public static void printColor(string text, string mapF, string mapB)
        {
            int color=0;

            mapF = mapF.ToUpper().Replace(' ', '_');
            mapB = mapB.ToUpper().Replace(' ', '_');

            if (text.Length != mapF.Length || mapF.Length != mapB.Length)
            {
                throw new Exception("Alle Parameter müssen die selbe Textlänge aufweisen");
            }

            for (int i = 0; i < text.Length; i++)
            {
                if (mapF[i] != '_')
                {
                    if (!int.TryParse(mapF.Substring(i, 1), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out color))
                    {
                        throw new Exception(string.Format("Vordergrundfarbe an Position {0} ungültig. Ist: '{1}'", i, mapF[i]));
                    }
                }
                if (mapB[i] != '_')
                {
                    if (!int.TryParse(mapB.Substring(i, 1), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out color))
                    {
                        throw new Exception(string.Format("Hintergrundfarbe an Position {0} ungültig. Ist: '{1}'", i, mapF[i]));
                    }
                }
            }


            ConsoleColor[] C = new ConsoleColor[] { Console.ForegroundColor, Console.BackgroundColor };
            for (int i = 0; i < text.Length; i++)
            {
                if (mapF[i] != '_')
                {
                    Console.ForegroundColor = (ConsoleColor)int.Parse(mapF.Substring(i, 1), NumberStyles.HexNumber);
                }
                if (mapB[i] != '_')
                {
                    Console.BackgroundColor= (ConsoleColor)int.Parse(mapB.Substring(i, 1), NumberStyles.HexNumber);
                }
                Console.Write(text[i]);
            }
            Console.ForegroundColor = C[0];
            Console.BackgroundColor = C[1];
        }

    }
}


Beispiel eines Aufrufes (Ergebins, siehe Bild):


PrintColor.printColorL("Long Form:  target = ulong.MaxValue / ((payload.Length + addBytes + 8) * POW)",
                       "8___________C______F_E______________F___A______________F_9________F______D__F",
                       "0____________________________________________________________________________");
PrintColor.printColorL("Short Form: X = A / ((B + C + D) * E)",
                       "8___________C_F_E_F_F_A_F_9_F_F____DF",
                       "0____________________________________");

Durch Verwendung von mehreren Zeilen, wird die Funktion fast selbsterklärend,
ansonsten hier die Anleitung:
der erste Parameter ist jeweils die Zeichenkette.
Parameter Zwei ist das Mapping der Vordergrundfarben.
Parameter Drei ist analog für die Hintergrundfarbe.

Alle Strings müssen die selbe Länge aufweisen.
Die Farben werden hexadezimal von 0-F angegeben, Gross- und Kleinschreibung ist egal.
Der unterstrich (_) (auch Leerschlag ist erlaubt) wiederholt die vorherige Farbe.
Die Zuordnung von Farben zu Zahlen kann mit dem property ColorRow überprüft werden.
Ansonsten hier die Farbtabelle:

0 = Schwarz        8 = Dunkelgrau
1 = Dunkelblau     9 = Blau
2 = Dunkelgrün     A = Grün
3 = Blaugrün       B = Zyan
4 = Dunkelrot      C = Rot
5 = Lila           D = Magenta
6 = Ocker          E = Gelb
7 = Hellgrau       F = Weiß

Diese ist übrigens von dem Befehl COLOR /?
Die Farben sind aber kompatibel

Hinweis. Anstelle des Unterstrichs darf natürlich auch die Farbkonstante wiederholend angegeben werden.

Schlagwörter: Konsole CMD dos farbig Farbe Text schreiben farbiger

30.07.2013 - 23:03 Uhr

Kleine Notitz am Rande:
Wird das Close Signal an den Explorer gesendet, werden Fenster nur geschlossen, wenn in den Ordneroptionen aktiviert ist, dass ein explorer.exe Prozess für jedes Ordnerfenster erstellt wird. Ist dies nicht so, wird lediglich der "Herunterfahren" Dialog angezeigt. Den Explorer richtig beenden geht (in Vista und neuer) folgendermassen:
Startmenü öffnen, [CTRL]+[SHIFT]+Rechtsklick auf eine freie Fläche im Startmenü, "Explorer beenden"

30.07.2013 - 00:09 Uhr

Beschreibung:

Dies ist eine einzelne Klasse, die globale Hotkeys zur Verfügung stellt. Sie ist in einer Art und Weise geschrieben, dass nichts vom Benutzer gespeichert werden muss und sie räumt hinterher wieder auf beim beenden.
Funktioniert nur mit einem Application Message Loop, also nicht mit Konsolenanwendung (es sei denn Application.Run() wird aufgerufen und die Warteschlange von Hand (!!) immer wieder abgearbeitet).

Klasse:
Die Hotkey Klasse is sehr grosszügig Kommentiert. Alle Member besitzen entsprechende Kommentare.


using System.Windows.Forms;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace AyrA
{
    /// <summary>
    /// This class allows global hotkeys to be registered and deleted.
    /// </summary>
    public class Hotkey
    {
        /// <summary>
        /// Registers a hotkey.
        /// </summary>
        /// <param name="hWnd">Handle to the form, can receive messages. Easiest: a form with overridden WndProc method</param>
        /// <param name="id">ID. this needs to be unique in the application</param>
        /// <param name="fsModifiers">Modifiers (alt, shift, ctrl, win, none) or a combination of those</param>
        /// <param name="vk">Virtual key. Equivalent to <see cref="System.Windows.Forms.Keys"/></param>
        /// <returns>true on success</returns>
        [DllImport("user32.dll")]
        private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);

        /// <summary>
        /// Unregisters a hotkey
        /// </summary>
        /// <param name="hWnd">Handle used to register the hotkey</param>
        /// <param name="id">ID used to register the hotkey</param>
        /// <returns>true on success</returns>
        [DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

        /// <summary>
        /// This is the message type that needs to be captured in the WndProc override
        /// </summary>
        public const int WM_HOTKEY_MSG_ID = 0x0312;

        /// <summary>
        /// List of active hotkey hooks
        /// </summary>
        private List<HookInfo> hookedKeys;
        /// <summary>
        /// ID, is increased with each call to "enable(...)"
        /// </summary>
        private int freeID;

        /// <summary>
        /// Contains informations about a hooked hotkey
        /// </summary>
        public struct HookInfo
        {
            /// <summary>
            /// ID used
            /// </summary>
            public int ID;
            /// <summary>
            /// Handle used
            /// </summary>
            public IntPtr hWnd;
            /// <summary>
            /// Constructs the struct with initial values
            /// </summary>
            /// <param name="Handle"></param>
            /// <param name="id"></param>
            public HookInfo(IntPtr Handle,int id)
            {
                ID = id;
                hWnd = Handle;
            }
        }

        /// <summary>
        /// Possible modifier keys, can be combined, for example: "Shift | Alt"
        /// </summary>
        [Flags]
        public enum Modifiers : int
        {
            Win = 8,
            Shift = 4,
            Ctrl = 2,
            Alt = 1,
            None = 0
        }

        /// <summary>
        /// Gets a list of all hoked keys.
        /// </summary>
        public HookInfo[] HookedKeys
        {
            get
            {
                return hookedKeys.ToArray();
            }
        }

        /// <summary>
        /// Initializes a new Hotkey class. You should create only one (if possible) to not end up in null pointers.
        /// </summary>
        public Hotkey()
        {
            hookedKeys = new List<HookInfo>();
            freeID = 0;
        }

        /// <summary>
        /// Destructor. Silently removes all hooks.
        /// </summary>
        ~Hotkey()
        {
            unhookAll();
        }

        /// <summary>
        /// Removes all registered hooks.
        /// </summary>
        public void unhookAll()
        {
            for (int i = 0; i < hookedKeys.Count; i++)
            {
                disable(hookedKeys[i]);
            }
        }

        /// <summary>
        /// Enables a global hotkey hook
        /// </summary>
        /// <param name="Handle">Handle to a form or application message processing class that can receive messages. Easiest: a form with overridden WndProc method</param>
        /// <param name="Mod">Modifiers (Alt, Shift, ...)</param>
        /// <param name="Key">Key to record</param>
        /// <returns>Hook information, required for disabling. Can also be obtained with HookedKeys property</returns>
        public HookInfo enable(IntPtr Handle,Modifiers Mod, Keys Key)
        {
            HookInfo i=new HookInfo(Handle,freeID++);
            hookedKeys.Add(i);
            RegisterHotKey(Handle, i.ID, (int)Mod, (int)Key);
            return i;
        }

        /// <summary>
        /// Removes a hotkey
        /// </summary>
        /// <param name="i">Hotkey info</param>
        public void disable(HookInfo i)
        {
            RemoveHook(i);
            UnregisterHotKey(i.hWnd, i.ID);
        }

        /// <summary>
        /// removes a HookInfo from the list of hooked keys
        /// </summary>
        /// <param name="hInfo">HookInfo of a registered key</param>
        private void RemoveHook(HookInfo hInfo)
        {
            for (int i = 0; i < hookedKeys.Count; i++)
            {
                if (hookedKeys[i].hWnd == hInfo.hWnd && hookedKeys[i].ID == hInfo.ID)
                {
                    hookedKeys.RemoveAt(i--);
                }
            }
        }
    }
}

Verwendung in einem Form (Teil 1):
Zeigt, wie Hotkeys registriert werden können, wenn das Form geladen wird.
Vom Rückgabewert der Enable Funktion, sollte die ID gespeichert werden, wenn vorher der Programm Ablauf nicht bekannt ist (z.B. wenn der Benutzer dynamisch welche registrieren kann). Grundsätzlich beginnt die ID bei 0 und wird mit jedem Aufruf der enable um 1 erhöht, auch wenn zwischendurch ein Aufruf an disable erfolgt.
Der Aufruf kann theoretisch jederzeit stattfinden und Das Handle kann von einem beliebigen Form in der Anwendung sein.


        private Hotkey HK;
        public frmMain()
        {
            InitializeComponent();

            HK = new Hotkey();
            HK.enable(this.Handle, Hotkey.Modifiers.Alt, Keys.Back);
            HK.enable(this.Handle, Hotkey.Modifiers.Alt | Hotkey.Modifiers.Ctrl, Keys.Back);
            HK.enable(this.Handle, Hotkey.Modifiers.Alt | Hotkey.Modifiers.Ctrl | Hotkey.Modifiers.Shift, Keys.Back);
        }


Verwendung in einem Form (Teil 2):
Nun wird die Methode WndProc ins Formular eingefügt. Die Methode muss in das Formular eingefügt werden, dessen Handle bei der enable() Funktion angegeben wurde.
Jedesmal, wenn eine Message ankommt (der Parameter Message is übrigens in System.Windows.Forms vorhanden) wird diese Funktion aufgerufen.
Wir prüfen auf den Typ WM_HOTKEY_MSG_ID, die Konstante ist in der Hotkey Klasse vorhanden. Dies ist wichtig, da auch andere Nachrichten typen ankommen. der Pointer WParam enthält die ID, die die enable() Funktion der Hotkey Klasse als Rückgabe ausgibt.


        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case Hotkey.WM_HOTKEY_MSG_ID:
                    switch ((int)m.WParam)
                    {
                        case 0:
                            //Erster registrierter Hotkey
                            break;
                        case 1:
                            //Zweiter registrierter Hotkey
                            break;
                        case 2:
                            //Dritter registrierter Hotkey
                            break;
                    }
                    break;
            }
            //WICHTIG! Folgende Zeile muss da sein,
            //sonst funktioniert die gesammte Anwendung nicht!
            base.WndProc(ref m);
        }

Beispiel
Die Klasse wird in diesem Projekt hier verwendet.

Schlagwörter: WinAPI API Keyboard Hook Hotkey Hotkeys global globale

29.07.2013 - 23:46 Uhr

Update
Neue Version veröffentlicht (Links bleiben die selben)

Hotkeys
Globale Keyboard Hooks zeichnen nicht alles auf (z.B. [ALT]+[BACKSPACE] geht nicht) und andere Probleme tauchten auf.
Ich konnte nun die Hotkeys integrieren. Anstatt eines globalen Keyboard Hooks wurde die Hotkey Funktion von Windows verwendet. Die Klasse ist in den Snippets bereit gestellt, da sie auch für Anfänger tauglich ist. //Link im ersten Post.

Sicherheit
Der Hotkey, um Prozesse sofort zu terminieren muss nun zweimal betätigt werden.

Race condition
Es gab eine race condition in einem Timer, die gelöst wurde.

29.07.2013 - 10:12 Uhr

Ich kann das mal so umsetzen.

Des weiteren ist mir eine Kuriosität aufgefallen.
An dem Computer wo ich jetzt gerade sitze, kann ich Prozesse mit dem Hotkey nur beenden, wenn ich sie in der folgenden Reihenfolge drücke: (SHIFT) -> CTRL -> ALT.
Beim debugging (F5) funktioniert es egal in welcher Reihenfolge, beim Ausführen (CTRL+F5) muss die Reihenfolge beachtet werden. Keine Ahnung woher das kommt.

Die Hotkeys schlage ich folgendermassen vor:
Nach wie vor [BS] um den Prozess zu töten. Fand ich irgendwie praktisch.
Dann werden die Umschalttasten aufgebaut:
[ALT] - Schliessen
[CTRL]+[ALT], wie alt, aber dann terminieren.
[SHIFT]+[CTRL]+[ALT], sofort terminieren.

Edit: Ist ALT+BACKSPACE irgendwie gesperrt in Windows?

28.07.2013 - 19:13 Uhr

Dieses Tool tötet Prozesse. Entstanden aus Faulheit den Taskmanager zu öffnen oder um Programme zu beenden, die keine Schliessen Schaltfläche haben. kann sich nützlich erweisen um beim Debuggen hängende prozesse schnell zu beenden, oder wenn Skype mal wieder in nem Update nicht rafft, dass [X] nicht das selbe ist wie [_]. (Wenns denn wenigstens umschaltbar wäre)

Nach dem Starten erscheint ein Fenster, welches die ID, den Fenstertitel und den Pfad zur Exe des aktuell fokusierten Prozesses anzeigt. Durch klicken auf den Pfad kann auch gleich ein Explorerfenster gestartet werden, welches den Ordner mit der exe anzeigt.
Es sind drei Buttons vorhanden, mit denen ein Prozess (nebst den Hotkeys) ebenfalls geschlossen, geschlossen und getötet oder sofort getötet werden kann.
Durch Minimieren verwandelt sich das Programm in ein Tray Icon.

Der aktive Prozess kann auf drei Arten getötet werden:1.[ALT]+[BACKSPACE]. Sendet ein close Signal an den Prozess, damit er sich regulär beenden kann (inklusive Speicherroutinen) 1.[CTRL]+[ALT]+[BACKSPACE]. Dies ruft zuerst die selbe Funktion wie ohne shift auf, sollte der Prozess nach 5 Sekunden nicht regulär beendet worden sein, so wird er getötet (mit einer Waffe von hinten). Spass beiseite, sollte der Prozess jedoch auf eine Eingabe vom Benutzer warten, wird er nicht automatisch getötet. sondern der Benutzer muss hierfür eine Bestätigung geben. Siehe Screenshot. 1.[SHIFT]+[CTRL]+[ALT]+[BACKSPACE] Tötet den aktiven prozess sofort. Muss zweimal betätigt werden!

Download
Source: https://github.com/AyrA/ProcessKiller
EXE (signiert): https://github.com/AyrA/ProcessKiller/tree/master/ProcKiller/bin/Release

Globaler Hotkey
Meine Implementation des globalen Hotkeys mit Erklärung findet sich bei den Snippets

Der Screenshot zeigt den Versuch Notepad++ zu beenden, wenn noch eine Eingabe erforderlich ist. Das kleine Fenster erlaubt es den Prozess mittels dem "Kill anyway" button sofort zu töten, oder mit "Leave running" in ruhe zu lassen. Wird der Prozess anderweitig beendet, verschwindet das Fenster von selbst.

27.07.2013 - 16:56 Uhr

Auf der Seite xkcd.com wird jeden Montag, Mittwoch und Freitag ein neuer Comic in Form eines einzelnen Bildes veröffentlicht. Es gab jedoch einen speziellen Comic (time ID:1190), bei dem einmal pro Stunde das Bild ersetzt wurde.
1190 ist am Freitag Abend zu Ende gegangen, nach über 3000 frames.

Für alle, die die Seite kennen oder einfach nur den Comics anschauen möchten habe ich hier zwei Programme geschrieben und als Zip beigelegt. (beide digital signiert).

ZIP Inhalt

Abgesehen von den vollständigen Projekten im "Source" Ordner,
liegt eine direkt ausführbare Struktur im XKCD Ordner mit folgenden Dateien:

xkcdDownloader.exe
Lädt alle Frames herunter auf die Festplatte. Sollten in Zukunft (wieso auch immer) neue Frames dazu kommen kann er erneut gestartet werden und synchronisiert sich wieder mit dem Bilderserver.

xkcdPlayer.exe
Spielt die Frames anhand der Anweisungen in der timecode.txt und der types.txt ab.
Frames werden grundsätzlich mit 10 FPS abgespielt, sollte Text in einigen sein oder sind es anderweitig besondere Frames, bleibt es länger sichtbar.

timecode.txt
Enthält alle Timecodes und Frame typen für jedes einzelne Frame. Kann von Hand oder vom player aus bearbeitet werden.

types.txt
Erlaubt das Hinzufügen neuer Frame Typen

README.txt
Enthält einige weitere Informationen. Lesenswert insbesondere für die Tastenbelegung des Players.

"Missbrauch" des Players
Dem Player ist der Dateiname egal. Daher kann er auch andere *.PNG Streams abspielen. Dateien werden aufsteigend sortiert abgespielt.

25.07.2013 - 22:19 Uhr

Stop funktioniert schon, jedoch wird glaube ich nur alle 2000 Instruktionen das stop Kommando geprüft, dies kann aber im code des F5 Befehles runtergeschraubt werden. Ort: frmMain.cs Zeile 124
Grundsätzlich empfehle ich das debuggen sowieso mit F8, da es keine Fehlermeldungen gibt bei ungültigen Operationen (z.B. bei leerem Stack eine Addition versuchen)

23.07.2013 - 09:51 Uhr

Im Beispielordner auf Github hat es sogar ein Serpinsky-Triangle Generator. Einige Beispiele sind auch hier zu finden: Befunge programs
Diese sind jedoch nicht immer Befunge-93.

Für die, die sich selbst an einen Interpreter wagen wollen oder einfach nur einen Eindruck von solchen Sprachen haben möchten, hier eine Liste von "Hello World" Programmen in über 160 eso-sprachen: Hello world program in esoteric languages

23.07.2013 - 00:22 Uhr

Was ist Befunge?
Befunge ist eine sogenante esotherische programmiersprache, sprich eine Programmiersprache, die nicht wirklich darauf ausgelegt ist, einfach zu benutzen oder auszuführen zu sein. (in Java2k z.B. hat ein Befehel eine Wahrscheinlichkeit von ca. 90% das zu tun, was er soll).

**Befunge ist insofern esotherisch:***Jede Anweisung ist genau 1 Zeichen lang *Der Code kann mittels >^<v umgelenkt werden *Der Code kann sich selbst modifizieren *Keine Variablen, nur ein einzelner Stack *Der Interpreter kann auf einer Seite "raus laufen" und erscheint auf der anderen wieder.

Hindernisse
Die Instruktionen selbst sind überschaubar und einfach zu implementieren. probleme bereiten Änderungen im source Code generell, da diese das Vorkompilieren mit einfachen mitteln unmöglich machen, sowie Änderungen im Code ausserhalb des Sichtbaren ASCII bereiches (<32 oder >126) ohne den code zu verunstalten.

Features*Schnelle Interpretation im "run" Modus, teilweise über 500 Instruktionen pro Sekunde und mehr. *Erlaubt Ensicht in den Stack und die aktuelle Code Position *Erstellung von EXE Dateien für Distribution.

Download
Download des Source codes und prekompilierter Anwendungen sowie einigen Beispielen auf GitHub: https://github.com/AyrA/BefSharp

Screenshot
Der Screenshot zeigt ein Beispielprogramm bei der Ausführung. Das Konsolenfenster verschiebt sich automatisch mit dem Code Fenster mit.

02.06.2013 - 16:40 Uhr

Ersetzt man den Funktionsnamen CredUIPromptForCredentials mit CredUIPromptForCredentialsW können unicode Zeichen verwendet werden.

22.05.2013 - 23:07 Uhr

Es gab bereits das erste Update (kurz vor diesem Post)
Behebt einerseits das Problem, dass manche Video Links nicht archiviert wurden, anderseits wurde die playlist_realnames.txt angepasst, um auch playlist URLs zu beinhalten. Viel Spass

20.05.2013 - 23:27 Uhr

Beschreibung:

Diese klasse erlaubt es das Zugangsdatenfenster anzuzeigen, das von Windows für diverse Aufgaben selbst verwendet wird (z.B. Netzlaufwerke verbinden)

Es muss lediglich die askCred Funktion ausgeführt werden. Sie gibt True bei Erfolg zurück. False bei Misserfolg (z.B. wenn der User auf Abbrechen klickt).
Name und Passwort werden als Cleartext in die Variablen geschrieben.


using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace ytBackup
{

    public static class PWD
    {
        [DllImport("credui")]
        private static extern CredUIReturnCodes CredUIPromptForCredentials(ref CREDUI_INFO creditUR,string targetName,IntPtr reserved1,int iError,StringBuilder userName,int maxUserName,StringBuilder password,int maxPassword,[MarshalAs(UnmanagedType.Bool)] ref bool pfSave,CREDUI_FLAGS flags);

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        private struct CREDUI_INFO
        {
            public int cbSize;
            public IntPtr hwndParent;
            public string pszMessageText;
            public string pszCaptionText;
            public IntPtr hbmBanner;
        }
        
        [Flags]
        private enum CREDUI_FLAGS
        {
            INCORRECT_PASSWORD = 0x1,
            DO_NOT_PERSIST = 0x2,
            REQUEST_ADMINISTRATOR = 0x4,
            EXCLUDE_CERTIFICATES = 0x8,
            REQUIRE_CERTIFICATE = 0x10,
            SHOW_SAVE_CHECK_BOX = 0x40,
            ALWAYS_SHOW_UI = 0x80,
            REQUIRE_SMARTCARD = 0x100,
            PASSWORD_ONLY_OK = 0x200,
            VALIDATE_USERNAME = 0x400,
            COMPLETE_USERNAME = 0x800,
            PERSIST = 0x1000,
            SERVER_CREDENTIAL = 0x4000,
            EXPECT_CONFIRMATION = 0x20000,
            GENERIC_CREDENTIALS = 0x40000,
            USERNAME_TARGET_CREDENTIALS = 0x80000,
            KEEP_USERNAME = 0x100000,
        }

        private enum CredUIReturnCodes
        {
            NO_ERROR = 0,
            ERROR_CANCELLED = 1223,
            ERROR_NO_SUCH_LOGON_SESSION = 1312,
            ERROR_NOT_FOUND = 1168,
            ERROR_INVALID_ACCOUNT_NAME = 1315,
            ERROR_INSUFFICIENT_BUFFER = 122,
            ERROR_INVALID_PARAMETER = 87,
            ERROR_INVALID_FLAGS = 1004,
        }

        /// <summary>
        /// Fragt nach Benutzername und Passwort
        /// </summary>
        /// <param name="Title">Fenstertitel</param>
        /// <param name="Message">Fensternachricht</param>
        /// <param name="name">Benutzername</param>
        /// <param name="pass">Passwort</param>
        /// <returns>true, wenn erfolgreich</returns>
        public static bool askCred(string Title,string Message,out string name,out string pass)
        {
            // Setup the flags and variables
            StringBuilder userPassword = new StringBuilder(), userID = new StringBuilder();
            CREDUI_INFO credUI = new CREDUI_INFO();
            credUI.pszCaptionText = Title;
            credUI.pszMessageText = Message;
            credUI.cbSize = Marshal.SizeOf(credUI);
            bool save = false;
            CREDUI_FLAGS flags = CREDUI_FLAGS.ALWAYS_SHOW_UI | CREDUI_FLAGS.GENERIC_CREDENTIALS;

            // Prompt the user
            CredUIReturnCodes returnCode = CredUIPromptForCredentials(ref credUI, System.Windows.Forms.Application.ProductName, IntPtr.Zero, 0, userID, 100, userPassword, 100, ref save, flags);

            name = userID.ToString();
            pass = userPassword.ToString();

            return (returnCode == CredUIReturnCodes.NO_ERROR);
        }
    }
}

Der Screenshot zeigt das Fenster, wie es in ytBackup verwendet wird.

Schlagwörter: Windows Benutzername Passwort abfrage Dialog Fenster API

20.05.2013 - 23:20 Uhr

ich musste für jemanden ein YouTube Backup Programm schreiben, welches ich nun mit euch teilen möchte.
Es handelt sich hierbei um folgende Dateien:

ytBackup.exe
Erstellt ein Backup eines beliebigen Youtube Users. Digital signiert.

ytBrowser.exe
ermöglicht das offline Durchsuchen eines Backup Archives. Digital signiert.

4 DLL Dateien
Werden für ytBackup.exe, nicht aber für ytBrowser.exe benötigt. Digital signiert.

README.txt
Die obligate Readme (in englischer Sprache) enthält weitere Informationen, unter anderem zur genauen Dateistruktur.

Download: Hier

Spezielles
Hier einige Besonderheiten des Programmes:*Verwendet die offizielle YouTube API *Passwort für den Benutzeraccount ist optional (aber für private Inhalte erfordrlich) *Implementierung des Windows Credential-Dialogs. Siehe hier. *Offene Dateistruktur; kann einfach in Programme dritter importiert werden. (Siehe unten) *Digitale Signatur der EXE und DLL Dateien verhindert Änderungen.

Die Dateistruktur, die angelegt wird ist in der readme.txt dokumentiert. Bis auf die Masterdatei und die Playlist_Realname.txt enthalten alle anderen Dateien nur Youtube Links, die in Downloader Tools importiert werden können.

Falls jemand wünscht, dass Benutzername und Passwort als parameter eingegeben werden können so kann ich das noch nachrüsten.
Die ytBrowser.exe benötigt die DLL Dateien nicht und arbeitet Standalone.

Für alle, die die Masterdatei auslesen wollen ist hier das entsprechende Format:


string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\r\n",
    /*ID   */V.Id.Split(':')[V.Id.Split(':').Length - 1],
    /*TITLE*/B64(V.Title),
    /*DESC */B64(V.Description),
    /*KEYW */B64(V.Keywords),
    /*IMAGE*/B64(V.Thumbnails[0].Url),
    /*URL  */B64(V.WatchPage.ToString()),
    /*PRIV */V.Private ? "TRUE" : "FALSE"
                    )

**Hinweise:***Die ID ist bei Videos, die aus einer Playlist gelesen wurden eine Kombination aus Playlist ID und Video ID, dies ist von der API so erzwungen. *Das Feld "Privat" ist immer False, dies ist ein Fehler der Youtube API V2, ist aber da zur Vorwätskompatibilität *B64(X) bedeutet Base64 encodierter UTF8 String *Keywords ist immer leer. (Dies ist eine Altlast und wird später eventuell durch Tags ersetzt) *Das Thumbnail Image wird erst beim Betrachten in ytBrowser.exe heruntergeladen um Bandbreite einzusparen. Es landet in einem Cache und verbleibt da, bis der Nutzer es löscht. *Beim arbeiten mit den erstellten TXT Dateien muss beachtet werden, dass diese leere Zeilen enthalten können. *:::

Lizenz
Das Tools ist Freeware für nicht-kommerzielle Zwecke. Es steht dem Nutzer frei die erzeugten Dateien weiter zu verarbeiten solange dies in nicht-kommerzieller Absicht geschieht.

Screenshot
Der Screenshot zeigt ytBrowser beim Betrachten einer offline Playlist.

04.05.2013 - 15:10 Uhr

Ich habe dies hier mal vor Ewigkeiten nach einer Lösung zur Benutzung der Maus in einem Konsolenprogramm gefragt, jedoch konnte mir niemand helfen.
ich benötigte dies aber letztens für einen Kundenauftrag und habe mich daher ein wenig durch die Windows API gewühlt und habe es geschafft die Maus in der DOS Konsole zu verwenden mit C#.

Download: http://home.ayra.ch/proj/files/MouseTest.zip (oder über den Dateianhang im zweiten Beitrag)

Der Download ist ein komplettes C# Projekt mit vorkompiliertem Beispielprogramm. Es funktioniert mit AnyCPU sowie x64 und x86.
Für die Mausoperationen wird lediglich die Mausklasse benötigt. Diese ist durchgehend kommentiert.

Wichtige Funktionen der Klasse:

Enable()
Aktiviert die Mauseingabe. Auf meinem PC war dies sowiso immer aktiviert aber hiermit kann die Aktivierung erzwungen werden, sofern es mal nicht der Fall sein sollte.
Disable()
Deaktiviert die Mauseingabe. Ist bei programmabschluss nicht zwingend notwendig, aber interessant, wenn die Maus gesperrt werden soll im aktiven Konsolenfenster.
GetMouse([autoDiscard])
Gibt den aktuellen Zustand der Maus zurück (Position, Buttons), die Position ist nicht in Pixel sondern in Zeichen, kann also mit Console.SetCursorPosition(X,Y) verwendet werden. autoDiscard ist ein bool parameter (freiwillig) und standardmässig false. Tastatur und Maus teilen sich den Eingabepuffer. Wird eine Taste gedrückt, ist die Maus blockiert, bis die Taste ausgelesen wurde. Wird autoDiscard auf true gesetzt, dann wird die GetMouse funktion bei Bedarf den Tastaturpuffer leeren. Sollte dann benutzt werden, wenn keine Tastatureingabe erwünscht ist. CTRL+C, CTRL+BREAK und CTRL+CLOSE funktionieren immer noch wie gewohnt.
Ist die Mauseingabe deaktiviert werden keine Maus Events erzeugt und die Funktion liefert immer den Letzten Zustand vor Deaktivierung zurück. War noch keiner Da, dann eine Maus auf koordinate 0,0 ohne gedrückte Buttons.

Das ganze Projket selbst ist ein Beispielprogramm, so eine art DOS-Paint.
Linke Maustaste: Vordergrundfarbe wählen oder zeichnen.
Rechte Maustaste: Hintergrundfarbe wählen oder radieren.
Mittlere Maustaste: Beenden.

04.05.2013 - 15:10 Uhr

Download als Dateianhang

12.02.2013 - 16:48 Uhr

Ich muss im Beruf häufig Passwörter oder Shared Keys (bis 40 Zeichen Länge) auf den verschiedensten Systemen eingeben. Anstatt mir das entsprechende Passwort jedesmal aufzuschreiben, nur um es 10 Meter weiter wieder eingeben zu können ist mir zu blöd.
So ist PCB entstanden.
Das Programm hat ein minimales Interface mit einem Textfeld für den Schlüssel und zwei Buttons.
Das Programm unterstützt das Kopieren von rohem Text, RTF, HTML und Bilder auf andere Rechner.

Benutzung

  1. Das Programm durch Doppelklick starten, anschliessend einen beliebigen Code eingeben und den "S" button drücken.
  2. Obigen Schritt auf allen Systemen wiederholen auf denen die Zwischenablage geteilt werden soll.
  3. Daten in die Zwischenablage kopieren (Programm weist nun auf neue Daten hin)
  4. [SHIFT]+[ALT]+[V] drücken. Die Zwischenablage wird an alle Clients verteilt.
  5. Auf dem Zielsystem [CTRL]+[V] benutzen.

Hinweise

  • Der Hotkey ist global und funktioniert überall in der Sitzung.*
  • Die Daten werden AES verschlüsselt übertragen. (Dafür ist der Key)
  • Die Zwischenablage wird nur an Clients übertragen, die den selben Key benutzen.
  • Der Key von Clients ist nicht sicher. Wenn der Nutzer mit [SHIFT]+[ALT]+[V] die Zwischenablage "veröffentlicht" erfahren das alle Clients und melden sich mit dem Key beim absender. Bei gültigen Keys wird die Zwischenablage übertragen, bei ungültigen Keys wird die Verbidung getrennt.
  • Der Nutzer erhält hinweise, wenn er Inhalte in die Zwischenablage kopiert oder wenn er die Zwischenablage empfangen hat.
  • Das Probramm funktioniert nur im LAN, da eine bestimmte Meldung per Broadcast versendet wird.
  • Die Software ist noch nicht ganz fertig, funktioniert aber grundsätzlich.

Zukunft
Folgendes wird noch kommen:

  • Support für Dateien und Ordner
  • Webdienst, der das Übertragen auch über das Internet ermöglicht.
  • Stabileres Threading Modell.
  • Nach der finalen Implementation wird das Protokoll offen gelegt.
  • Möglichkeit Clients oder das Überschreiben der Zwischenablage abzulehnen.
  • Mehr Sicherheit, Clients mit gültigem Schlüssel müssen zurzeit nicht auf das Veröffentlichen der Zwischenablage mit [SHIFT]+[ALT]+[V] warten und könnten theoretisch jederzeit deren Inhalt verlangen.

Kommunikation

  • Die Mitteilung, die über [SHIFT]+[ALT]+[V] verschickt wird wird per UDP Broadcast versendet.
  • Clients empfangen diese Meldung und verbinden über TCP auf den selben Port.
  • Der Client sendet nun seinen Schlüssel und den Datentyp (rawText,RTF,HTML,Image)
  • Ist der Schlüssel falsch, wird die Verbindung geschlossen, ist er richtig wird der angeforderte Inhalt als roher AES Stream übertragen.
    UDP und TCP Port sind 26475

Einsatzzwecke ((zurzeit teilweise nicht möglich)

  • Passwörter, Codes oder sonstige Texte ohne Drucken, Mails, USB Sticks, Papier, etc. übermitteln.
  • Texte zwischen verschiedenen Systemen kopieren (durch RTF und HTML Übermittlung)
  • Dateien direkt verteilen anstatt über E-Mail

Download
wie üblich auf meiner Projektseite

*
Der Hotkey funktioniert nicht wenn die Benutzerkontensteuerung (UAC) eingeschaltet ist und das Programm mit Fokus mit höheren Rechten läuft.
Dies ist systembedingt so. Das bedeutet, dass wenn PCB unter normalen Rechten läuft (wie das über Doppelklick üblich ist), wird es den Hotkey nicht empfangen, wenn z.B. der Task Manager mit Administrativen Rechten läuft und den Fokus hat. Änderungen an der Zwischenablage wird es weiterhin bemerken, auch wenn sie aus einem "Admin-Programm" kommen. Daher ist es empfohlen PCB als Administrator zu starten, wenn man mit "Admin-Programmen" arbeitet und nicht immer den Fokus wechseln möchte.

30.12.2012 - 04:52 Uhr

Beschreibung:

Diese Klasse generiert einen standard 44 Bytes RIFF Wav Header und liefert diesen als Byte Array zurück.
Praktisch, wenn von der Soundkarte eine Wav Datei aufgenommen wird und man den Header generierne will.
Tips:
Anstatt einen Header mit der Datengrösse uint.MaxValue zu erzeugen (Wert für eine Wav Datei unbekannter Länge), lieber folgendermassen vorgehen, wenn die WAV Grösse nicht bekannt ist:
Zuerst eine neue Datei erstellen, 44 Nullbytes schreiben und dann die Wave Daten dahinter.
Anschliessend analog folgendem Beispiel den Header setzen:
(FS=FileStream)


            //Complete Wave Header
            if (FS.Position + 44 - 8 <= uint.MaxValue)
            {
                FS.Flush();
                FS.Seek(0, SeekOrigin.Begin);
                FS.Write(wavCap.Header.WaveHeader((uint)(FS.Position - 45), 48000, 4, 16), 0, 44);
            }
            else
            {
                Console.WriteLine("WAVE DATA CHUNK TOO BIG");
            }
            FS.Close();

44-8:
Der Term 44-8 begegnet einem häufiger, wenn man mit WAV Dateien programmiert.
44 ist die Grösse des Headers, 8 ist die Länge der Zeichenfolge RIFF plus der nachfolgenden Zahl, welche die Dateigrösse angibt (ohne "RIFF" und sich selbst).
Der Wav Datei Content sollte nicht grösser sein, als das 4 GB Datei limit (von Fat32 bekannt), sonst arbeiten einige programme nicht mehr mit der Wav Datei. Daher wird in meinem obigen Beispiel bei der Grössenprüfung diese Zahl von der Grösse subtrahiert.

Hier die Klasse:


using System;

namespace wavCap
{
    public static class Header
    {
        /// <summary>
        /// Generates a RIFF Header for a PCM Wave File
        /// </summary>
        /// <param name="rawLength">Length of the RAW Bytes Stream</param>
        /// <param name="Freq">Frequency in Hertz: (Default: 44100)</param>
        /// <param name="Chan">Channels: (Default: 2)</param>
        /// <param name="Bits">Bits Per Sample (Default: 16)</param>
        /// <returns>RIFF Header for PCM RAW Data</returns>
        public static byte[] WaveHeader(uint rawLength,uint Freq,uint Chan,uint Bits)
        {
            byte[] Header = new byte[44];


            //Header ID (RIFF)
            insertAt(ref Header, new byte[] { (byte)'R', (byte)'I', (byte)'F', (byte)'F' }, 0);
            //Length of RIFF chunk (Data Length + Header Length - 8)
            insertAt(ref Header, BitConverter.GetBytes((rawLength + 44-8)), 4);
            //FourCC Code (WAVE)
            insertAt(ref Header, new byte[] { (byte)'W', (byte)'A', (byte)'V', (byte)'E' }, 8);
            //Format chunk
            insertAt(ref Header, new byte[] { (byte)'f', (byte)'m', (byte)'t', (byte)' ' }, 12);



            //Specify Length (16 Bytes = 0x0010 -> swapped [0x1000])
            insertAt(ref Header, new byte[] { 0x10, 0, 0, 0 }, 16);
            //Specify PCM (0x0001 swapped [0x0100])
            insertAt(ref Header, new byte[] { 1, 0 }, 20);
            //Specify Channels (0x01 or 0x02 (Mono,Stereo))
            insertAt(ref Header, new byte[] {Chan == 2 ? (byte)2 : (byte)1,0 }, 22);
            //Specify Frequency
            insertAt(ref Header, BitConverter.GetBytes((Freq)), 24);
            //Bytes per Second 
            insertAt(ref Header, BitConverter.GetBytes(((uint)(Freq * (Chan == 2 ? 2 : 1) * Bits / 8))), 28);
            //Bytes per Sample
            insertAt(ref Header, BitConverter.GetBytes(((ushort)((Chan == 2 ? 2 : 1) * Bits / 8))), 32);
            //Bits per Sample
            insertAt(ref Header, BitConverter.GetBytes(((ushort)Bits)), 34);



            //"DATA" Chunk
            insertAt(ref Header, new byte[] { (byte)'d', (byte)'a', (byte)'t', (byte)'a' }, 36);
            //Chunk Length
            insertAt(ref Header, BitConverter.GetBytes(rawLength), 40);

            return Header;
        }

        /// <summary>
        /// Generates a RIFF Header with Default Settings (44.1 kHz; 2Channels; 16 Bits)
        /// </summary>
        /// <param name="rawLength">Length (in Bytes) of Data Stream</param>
        /// <returns>RIFF Header for PCM RAW Data</returns>
        public static byte[] WaveHeader(uint rawLength)
        {
            return WaveHeader(rawLength, 44100, 2, 16);
        }

        private static void insertAt(ref byte[] InsertTo, byte[] InsertFrom,int InsertAt)
        {
            for (int i = 0; i < InsertFrom.Length; i++)
            {
                InsertTo[InsertAt + i] = InsertFrom[i];
            }
        }

        private static uint swapByteOrder(uint uvalue)
        {
            return ((0x000000FF) & (uvalue >> 24) |
                (0x0000FF00) & (uvalue >> 8) |
                (0x00FF0000) & (uvalue << 8) |
                (0xFF000000) & (uvalue << 24));
        }

        private static ushort swapByteOrder(ushort uvalue)
        {
            return (ushort)((0x00FF) & (uvalue >> 8) |
                (0xFF00) & (uvalue << 8));
        }
    }
}

Schlagwörter: RIFF WAV WAVE header Kekse

15.12.2012 - 03:51 Uhr

AyrAs FTP Repair

Ich führe Gelegenheitsjobs aus, wenn sie mir so über den Weg laufen.
Ein sich häufendes Phenomen ist das FTP Tagging, trotz one click Hostern scheinen sich FTP Downloads nach wie vor zu halten.
Letztens musste ich FTP Verzeichnisstrukturen auf Honeypot Servern reparieren, diese wurden von sog. Taggern komplett zerschossen, so dass man in die meisten FTP Verzeichnisse nicht mehr hinein kommt und die meisten Dateien nicht mehr laden kann, ohne den exakten Pfad zu kennen. Häufig ist auch lokal an der Maschine kein rankommen mehr, dies ist ärgerlich, wenn man den Honeypot neu aufsetzen muss.
Das Problem tritt nur bei veralteter FTP Software auf, die den MLSD Befehl nicht unterstützen, da dieser Befehl eine Verzeichnisliste liefert, die keine Verwechslungen zulässt.

Ich habe für die Reparatur (die von Hand eine Ewigkeit dauert) ein FTP Repair Tool entwickelt, welches über die FTP Verbindung selbst die Verzeichnisse und Dateien so umbenennt, dass ein hineinkommen und herunterladen wieder möglich ist.
Durch das Umbenennen hat das Tool unter Umständen eine destruktive Natur, worauf der Nutzer explizit hingewiesen wird. Das Programm löscht keine Daten oder Ordner jedoch habe ich von den ca 80 Servern, die ich bereinigt habe zwei erlebt, die das Umbenennen nicht verweigern, wenn das Ziel existiert, sondern es löschen.
Das Programm ist kompatibel mit der Windows, wie mit der Unix Dateiliste.

Hinweis
Das Tool besitzt mein Wissen über FTP Tagging, dadurch ist nicht garantiert, dass es in naher oder ferner Zukunft noch alle Probleme beseitigen kann. Sollte ich neues in Erfahrung bringen, so aktualisiere ich das Tool stetig.

Benutzung
Die Benutzung ist simpel:
Will man einen Server bereinigen, gibt man lediglich die IP/Dns name der Servers ein und lässt alle anderen Werte auf standard.
Zusätzlich könnte noch folgendes angegeben werden:
Server Port, Startverzeichnis, Benutzername und Passwort.
Das Programm arbeitet ausschliesslich im Passive Modus (PASV) und hat die volle unterstützung, also auch Verbindung zu mehreren IPs, etc.
Nach der Angabe aller Werte arbeitet das Tool sämtliche Unterverzeichnisse ab.
Teilweise sind mehrere Durchgänge notwendig.

Download: http://home.ayra.ch/proj

Das Programm ist digital signiert.

Nutzen
Das Programm ist von Nutzen, wenn jemand an eine solche problematische FTP Struktur gelangt. Dies muss nicht einmal durch mutwillige Zerstörung geschehen. Hochladen von Dateien von einem Windows System auf einen unix FTP Server oder umgekehrt können bereits Probleme verursachen, wenn der Server bestimmte Datei- und Ordnernamen nicht anpasst. Besonders leer- und Sonderzeichen machen Probleme.

03.12.2012 - 01:11 Uhr

In den letzten paar Jahren sind bei mir einige Projekte entstanden. Teilweise über mehrere Tage, teilweise auch innerhalb einer Stunde. Ich habe mich entschieden etwa ein Viertel davon freizugeben für die nicht kommerzielle Benutzung.
Ich gehe hier nur auf Projekte ein, zu denen noch kein Thread existiert. Alle Projekte sind ausführbar, bei Projekten wo der Source zum Download angegeben wird, ist auch eine vorkompilierte EXE Datei dabei.
Hier wurde bewusst auf das Erstellen mehrerer Themen verzichtet.

UAC (nur Klasse)
Klasse, die das UAC handling vereinfachert, z.b. das Starten von Applikationen mit Admin Rechten oder das Herausfinden, ob die Rechte vorhanden sind.

netMeter
Klasse, die die aktuelle Bandbreitenausnutznung misst (asynchron mit Thread) und ein Beispielprojekt, um die richtige Netzwerkkarte zu wählen.

rename All
Benennt alle unterordner eines angegeben Ordners in einen Namen mit nur einem Zeichen um. Ideal, wenn ein Ordner gelöscht werden muss und der Name überlang ist, dies kann beim kopieren mit robocopy entstehen wenn es symbolischen Verknüpfungen folgt.

runAsAdmin
EXE Datei, die es erlaubt Prozesse als Administrator zu starten. Ideal für batch Files.

showGif
Ein ganz simpler GIF Viewer, der auch die Animationen anzeigt, was der Windows Viewer nicht mehr macht. Einfach eine GIF Datei auf die EXE ziehen und alle GIF Dateien im selben ordner werden eingelesen.

squeezeCommand
Beispielprojekt um den Logitech Media Server anzusprechen um Webradio auf der Squeezebox abzuspielen oder die Lautstärke anzupassen.

TimeBomb
Fährt ein System herunter oder startet es neu. Entweder nach einer bestimmten Zeit oder zu einer bestimmten Zeit. Beendet nicht reagierende Anwendungen. Praktisch auf Systemen wo die shutdown.exe nur 300 Sekunden zulässt. Das Tool lässt mehrere Tausend Jahre als Zeitraum zu.

turboSplitter
Teilt Dateien oder fügt sie zusammen. Die Anzahl Teile ist unlimitiert. Eine 4 GB Datei in 1 Byte Stücke zerteilen ist kein Problem.

whoIs
Zeigt WhoIs Informationen von Domains an, ohne dass der whois Server bekannt sein muss. Ausgabe wird farbig Codiert um die lesbarkeit zu erhöhen. Bietet die Option die Ausgabe in eine Datei zu speichern.

Zero Byte Remover
Entfernt Nullbytes aus einer Datei und speichert das Resultat unter einem neuen Namen. praktisch um korrupte Unicode Dateien zu lesen oder sonstigen Textinhalt aus Binärdaten zu filtern.

randomStreamer
Ein TCP Server, der jedem der Verbindet endlos Zufallsdaten schickt. Hat ein Bandbreiten limitter eingebaut.

mtuServer
Ermittelt MTU, TTL, und ping Resultat von einem Host. Zeigt auch die Route dahin an. Ist einiges schneller beim Traceroute als vergleichbare Utilities von Windows, da Multi Threading verwendet wird. Erlaubt auch das Tracerout zu Addressen, die nicht auf Ping antworten.

MouseMove
Ein kleines Scherzprogramm, das die Maus bei jeder Bewegung noch zufällig ein paar Pixel verschiebt. kann nur über Task Manager beendet werden. Sehr effektiv, wenn im Autostart platziert und als svchost.exe benannt.

jumper
Ein Spiel mit einem Windows Form (gespielt wird mit dem sich bewegenden Form selbst). Ziel ist es, das Fenster möglichst lange auf dem Bildschirm zu halten mittels einer Taste.

floppyImager
Liest Disketten in Images oder schreibt sie zurück. Kann die Magnetisierung von Disketten erneuern oder diese Kopieren (auch wen nur ein Laufwerk vorhanden ist). unterstützt nur 3.5'' Disketten

fileKill
Überschreibt eine Datei mit Zufallsdaten und löscht sie anschliessend.
Wird ein Ordner als Parameter angegeben werden alle Unterordner und Dateien gelöscht (der Ordner selbst nicht). Hat einen Schutz um das Löschen ganzer Laufwerke zu verhindern.

fileCopy
CMD Tool, das eine Datei kopiert. Zeigt den Status während des Vorgangs an und verändert den Buffer dynamisch, um die maximale Performance zu erreichen. kopiert nur einzelne Dateien (keine Platzhalter)

ConTris
Konsolen Tetris. Blöcke können im Source einfach hinzugefügt und entfernt werden. Zeigt den nächsten Block an und zeigt auch an, wo der aktuelle Block hinfallen würde (ghost Block)

ConSize
Erlaubt das Ändern der Grösse des Konsolenfensters und der Grösse des Buffers von der Konsole aus. Beides kann gleichzeitig angegeben werden. Besitzt einen Schutz vor widersprüchlichen Angaben. Per Parameter kann angegeben werden, was Vorrang hat bei der Änderung, Buffer oder Fenster.

Alle Projekte sind hier auffindbar: http://home.ayra.ch/proj
Bei einigen Projekten fehlt der Source, meistens weil aus meiner Sicht keine Änderungen mehr notwendig sind. Ist der Source Code gewünscht, so kann das Anliegen hier hinterlegt werden.

02.12.2012 - 22:33 Uhr

Vorsicht, wenn du planst die Software auf einem Server einzusetzen. Der Name steht im Konflikt mit einem Symantec Backup Exec Dienst. (siehe Google)
Dies könnte Nutzer verwirren.

21.11.2012 - 23:54 Uhr

Seek ist nur ganz begrenzt möglich. (nur vorwärts und nur relativ zur aktuellen Position), daher habe ich mich für false bei CanSeek entschieden, um Probleme zu vermeiden, falls einer fremden Methode, die ein Stream verlangt der RandomStream übergeben wird und diese auf Seek zurückgreifen will.
Bezüglich des Falls, dass der Ganze Buffer gefüllt wird schaue ich morgen auf meinem Rechner, wie die Performance mit dem zusätzlichen IF ist. Ansonsten baue ich das noch ein.

EDIT: Vorgeschlagene Änderung eingebaut, da Performance Gewinn um bis zu 20 MB/s.
Post ergänzt um Informationen zu Zufallsgeneratoren.

21.11.2012 - 09:22 Uhr

Beschreibung:

Diese Klasse ist ein Wrapper für die System.Random Klasse und macht diese als Stream verfügbar. Ideal um Dateien zu überschreiben, Dateien zu erstellen oder wenn beim Umleiten und Verketten von Streams auch Zufallsdaten benötigt werden. Dadurch wird das aus Linux bekannte /dev/random emuliert, wobei der Stream in dieser C# Klasse jedoch readonly ist.

**Benchmark unter Windows 7 mit Intel Core 2 Duo E8500 **

Datenrate beim Lesen von einem ganzen Buffer (1024*1024 Bytes):
Dies benötigt kein Array.Copy; Angabe in MB/s

115 MB written
115 MB written
117 MB written
117 MB written
118 MB written
116 MB written
117 MB written
117 MB written
117 MB written
118 MB written

Datenrate beim lesen eines Teilbuffers (1024*1024 Bytes -1):
Benötigt Array.Copy; Angabe in MB/s

102 MB written
107 MB written
109 MB written
108 MB written
109 MB written
108 MB written
107 MB written
109 MB written
106 MB written
109 MB written
110 MB written

Code:
Achtung viele der Methoden und Attribute sind nur da weil dies durch die Vererbung erzwungen wird, z.B. hat der Stream immer eine Länge von 9223372036854775807. (long.MaxValue)


using System;
using System.IO;

namespace AyrA.Random
{
    public class PseudoRandStream : Stream
    {
        private long currPos=0;
        private System.Random r;

        /// <summary>
        /// Returns always true
        /// </summary>
        public override bool CanRead
        {
            get { return true; }
        }

        /// <summary>
        /// eturns always false
        /// </summary>
        public override bool CanSeek
        {
            get { return false; }
        }

        /// <summary>
        /// Returns always false
        /// </summary>
        public override bool CanTimeout
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Returns always false
        /// </summary>
        public override bool CanWrite
        {
            get { return false; }
        }

        /// <summary>
        /// returns long.MaxValue
        /// </summary>
        public override long Length
        {
            get
            {
                return long.MaxValue;
            }
        }

        /// <summary>
        /// gets the number of Bytes read
        /// </summary>
        public override long Position
        {
            get
            {
                return currPos;
            }
            set
            {
                throw new Exception("This Property is readonly");
            }
        }

        /// <summary>
        /// Gets or sets the Read Timeout
        /// </summary>
        public override int ReadTimeout
        { get; set; }

        /// <summary>
        /// Gets or sets the Write Timeout
        /// </summary>
        public override int WriteTimeout
        {get;set;}

        /// <summary>
        /// Initializes a new Random Stream with given Seed
        /// </summary>
        /// <param name="init">Seed Value</param>
        public PseudoRandStream(int init)
        {
            r = new System.Random(init);
        }

        /// <summary>
        /// Generates a new Random Stream with current Time as seed.
        /// </summary>
        public PseudoRandStream()
        {
            r = new System.Random();
        }

        /// <summary>
        /// Does nothing, since this is not writeable.
        /// </summary>
        public override void Flush()
        {
            //Do nothing loop;
        }

        /// <summary>
        /// Seeks to given Position (only Forward seek possible)
        /// </summary>
        /// <param name="offset">Number of Bytes to skip</param>
        /// <param name="origin">Must be SeekOrigin.Current</param>
        /// <returns>new Position</returns>
        public override long Seek(long offset, SeekOrigin origin)
        {
            if (origin != SeekOrigin.Current)
            {
                throw new Exception("Can only seek from Current location");
            }
            else if (offset > 0)
            {
                while(offset>0)
                {
                    if (offset > int.MaxValue)
                    {
                        offset -= Read(new byte[int.MaxValue], 0, int.MaxValue);
                    }
                    else
                    {
                        offset-=Read(new byte[(int)offset], 0, (int)offset);
                    }
                }
                return currPos;
            }
            else
            {
                throw new Exception("Cannot seek backwards");
            }
        }

        /// <summary>
        /// [DO NOT USE] Sets the Length of the Stream
        /// </summary>
        /// <param name="value">New Length</param>
        public override void SetLength(long value)
        {
            throw new Exception(string.Format("This Stream is always {0} long.",long.MaxValue));
        }

        /// <summary>
        /// Reads given number of Bytes from the Stream
        /// </summary>
        /// <param name="buffer">byte Buffer</param>
        /// <param name="offset">Offset in Buffer to start writing</param>
        /// <param name="count">Number of Bytes to write</param>
        /// <returns>number of Bytes actually written to Buffer</returns>
        public override int Read(byte[] buffer, int offset, int count)
        {
            if (offset == 0 && count == buffer.Length)
            {
                r.NextBytes(buffer);
                return count;
            }
            else
            {
                byte[] temp = new byte[Math.Abs(count - offset)];
                r.NextBytes(temp);
                Array.Copy(temp, 0, buffer, offset, count);
                return temp.Length;
            }
        }

        /// <summary>
        /// [DO NOT USE] Writes Bytes to the Random Stream
        /// </summary>
        /// <param name="buffer">buffer to read from</param>
        /// <param name="offset">Offset in Buffer to start</param>
        /// <param name="count">number of Bytes to read</param>
        public override void Write(byte[] buffer, int offset, int count)
        {
            throw new Exception("This Stream is readonly");
        }

        /// <summary>
        /// Reads a single Byte
        /// </summary>
        /// <returns>0-255</returns>
        public override int ReadByte()
        {
            return r.Next(256);
        }
    }
}


**:::

Gute Quellen für Zufallszahlen sind zum Beispiel die Ping Werte eines Traceroute nach China oder reale Zufallsreneratoren, wie sie zum Beispiel auf random.org zum Einsatz kommen.

Schlagwörter: Random generator stream zufallsgenerator PRNG

29.09.2012 - 15:37 Uhr

Da der ByteViewer in System.Design enthalten ist, ist dieser von einem GUI oder zumindest von der Drawing Library Abhängig, welche in einer Konsolenanwending/DLL/Dienst zuerst manuell hinzugefügt werden muss.

28.09.2012 - 10:12 Uhr

Wäre keine schlechte Idee. Performance-Gewinn allerdings nur bei Vorausberechnung der String Länge.
Diese wäre glaube ich (einfach mal so aus dem Kopf raus):
WIDTH ist die Anzahl Bytes pro Zeile (standardmässig 16)


Math.Ceiling((double)data.Length/(double)WIDTH)*(WIDTH*4+3)

Erklärung:
Math.Ceiling((double)data.Length/(double)WIDTH) - Ermittelt die Anzahl Zeilen, wobei immer aufgerundet wird.
(WIDTH*4+3) - Die Länge einer Zeile, pro Byte sind das 4 Zeichen (2 Zeichen für die Hex Zahl 00-FF, 1 Zeichen für den Leerschlag danach, 1 Zeichen für die ASCII Ausgabe) plus 1 Tab Char \t plus 1 Zeilenumbruch \r\n

25.09.2012 - 14:49 Uhr

Beschreibung:

Eine einzelne Funktion ohne jegliche externe Abhängigkeiten, die ein Byte Array in einen Hex Editor artigen String umwandelt.

private string HexView(byte[] data)
        {
            int i, j;
            string line = null;
            string retValue = string.Empty;
            for (i = 0; i < data.Length; i += 16)
            {
                line = string.Empty;
                for (j = 0; j < 16; j++)
                {
                    if (i + j < data.Length)
                    {
                        line += data[i + j].ToString("X2") + " ";
                    }
                    else
                    {
                        //Fill up empty Space
                        line += "   ";
                    }
                }
                line = line + "\t";
                for (j = 0; j < 16; j++)
                {
                    if (i + j < data.Length)
                    {
                        //Filter some Invalid chars
                        if (data[i + j] >= 32 &&
                            data[i + j] != 127 &&
                            data[i + j] != 128 &&
                            (data[i + j] <= 0x80 || data[i + j] >= 0xA0))
                        {
                            line += (char)data[i + j];
                        }
                        else
                        {
                            line += ".";
                        }
                    }
                    else
                    {
                        //Fill up empty Space
                        line += " ";
                    }
                }
                retValue += line + "\r\n";
            }
            return retValue;
        }

Enwtickle ein neues Archivierungsformat und Nutzer haben die Möglichkeit Daten daraus zu betrachten. Existiert kein externes Programm wird die Datei in einem internem Hex Viewer geöffnet. Die Funktion erweist sich auch als Praktisch, wenn Nutzer nach Binärdaten suchen können und man einen Ausschnitt anzeigen möchte.
Die Funktion erweitert die Letzte Zeile automatisch mit Leerzeichen, sollte das Byte Array nicht ein vielfaches von 16 sein.
Der \t splitter kann durch ein Leerzeichen ersetzt werden, um in die Konsole zu passen.

Verwendung:
Einfach die Funktion aufrufen und als Parameter das Byte Array übergeben.
Rückgabe ist ein Hex Editor artiger String. Dieser kann nach \t aufgesplittet werden um den HEX vom Text Teil zu trennen.
Der zurückgegebene String kann direkt als Text einer Textbox festgelegt, als Textdatei gespeichert oder in der Konsole ausgegeben werden. (z.B. für ein Hex Dump Tool)

**Einige einfache Modifizierungsmöglichkeiten:***Die Funktion kann statisch gemacht werden *um nicht 16 Bytes breit zu sein, einfach überall die 16 durch die gewünschte Zahl oder einen Parameter ersetzen. *Gleiches gilt für die Länge, anstatt data.Length überall einen Parameter angeben *Hex Zeichen können als Kleinbuchstaben ausgegeben werden, indem man das X in der .ToString("X2") Methode klein schreibt

Das Formular im Bild zeigt 1:1 wie der String ausgegeben wird.

Schlagwörter: HEX Editor Viewer

21.09.2012 - 13:55 Uhr

Habe eine neue Version hochgeladen (Dateianhang erster Post)

Zusätzlich in der neuen Version enthalten ist folgendes:
Alles ist nun im Namespace "csc2" drin. Die DLL heisst jetzt auch csc2.dll, damit die Framework Version erkennbar ist. (es folgt noch eine csc3.5.dll und eine csc4.0.dll)

Neue Funktionen im ScriptManager:


//Kompiliert eine Script Datei zu einer DLL um das Auslesen des Source Codes zu erschweren.
Compile(string Content,string DestinationDLL);

//Lädt eine DLL Datei in die Scriptsammlung
LoadLib(string Path);

der cscHost erkennt DLL Dateien an der Dateiendung .dll automatisch. Alles andere wird immer noch als Source interpretiert.

Das Ganze soll es ermöglichen Sourcecode in Visual Studio schreiben und dann auch verwenden zu können.

20.09.2012 - 16:46 Uhr

Zum (nicht)statischen nochwas: Es kann ja gewünscht sein, dass man evt. zwei unterschiedliche Scriptmanager laufen lässt, welche von einander nichts wissen sollen.

Sobald du aber zwei klassen mit identischem Namen hast (Der Klassenname selbst, nicht die Rückgabe der Name() Funktion). Werden sie Probleme machen, da in einer Anwendung nicht zwei klassen mit dem selben Namen existieren können, ausser du machst namespaces. Wenn der ScriptManager überall erstellt werden kann, dann verliert das Programm endgültig die Möglichkeit solche Dinge zu verhindern. Wenn ein Script versteckt sein soll, dann schreibe ein * an den Anfang des Namens, dann gilt es als versteckt und erscheint nicht in der Script Liste.

Und um Scripts zu identifizieren bietet sich ebenfalls Objektorientierung an:

  
ScriptManager manager = new ScriptManager();  
IScript script = manager.Create(meinScriptString);  
  
//ab hier kann ich mein Script ja schon selbstständig weiter ausführen oder nicht?   
script.Main(/*mit meinen Args*/);  
  
//oder alternativ halt  
manager.Run(script, args);  
  

Das wäre höchstens sinnvoll, wenn ein script ein anderes aufrufen will, welches noch nicht gladen ist. Das ist im Anwendungsszenario mit dem cscHost.exe nicht relevant, da ich damit lediglich eine art batch File laufen lassen will.
Sobald es um komplexere Programme geht, macht das sinn. Du läufst dann in die Gefahr, dass ein anderes Script deine Komponente verwendet (z.B: durch eine API) und wenn du die Referenz dazu verlierst, wird sie vom GC aufgelöst und das andere Script hat Probleme.

Auch im Bezug auf Fehlerauswertung fände ich es unpraktisch, wenn ich den ScriptManager an mehreren Orten verwenden wollen würde und dann dort Fehler drinnen sind, die mit meiner (lokalen) Ausführung garnichts zu tun haben.

Laufzeitfehler führen automatisch zur Terminierung des Programmes mit der entsprechenden Fehlermeldung in der Konsole. Ich habe den cscHost so geschrieben, dass er sich beendet, wenn die Main Methode des Scripts durchgelaufen ist oder durch Fehler terminiert wird. Da Exceptions den Call Stack "hoch" gegeben werden, landen alle letztendlich bei der Konsole und nicht bei fremden Scripts.

Du kannst die DLL in eine Windows Forms App integrieren und die exe beim Ende der Main Methode weiter laufen lassen. Dann können Scripts Threads öffnen und eigenständig laufen (was für Plugins Sinn machen würde). Dann ist das Problem behoben, dass Scripts sich in den Tod reissen, weil nur der entsprechende Thread abkratzt.

Da du durch die DLL Zugriff auf das IPlugin Interface hast, kannst du theoretisch eine eigene instanzierbare Klasse schreiben, die Scripts hochladen kann. Das würde dir das versteckte Laden von Scripts erlauben und du kannst den Compiler genau auf deine Bedürfnisse abstimmen. Ich denke, ich mache aber noch eine instanzierbare Version rein, dann gibt es wahrscheinlich dann den staticScriptManager und den privateScriptManager. Problem ist einfach, wenn dein Masterscript abkratzt und in deinen "privaten" Scripts Threads laufen, dann sind diese dann verwaist und ich weiss nicht genau wie das so ist, wenn unkontrollierte Scripts in der exe "herumwuseln", insbesondere wenn diese dann versuchen ihren Master zu kontaktieren, welcher zwar tot ist, aber noch existiert, da irgendwer ja noch eine Referenz dazu hat.

EDIT: habe eine neue Version hochgeladen, wo alles im Namespace csc2 drin ist. Das Demo Script zeigt jetzt die Interaktion zwischen Scripts. Die DLL heisst jetzt auch csc2.dll

20.09.2012 - 15:59 Uhr

Wie kann ich zum Beispiel die PresentationFramework.dll einbinden?

Das Programm ist in .NET 2.0 kompiliert und wird daher eine .NET 4.0 DLL nicht finden, ich muss zuerst noch :NET 3.5, und 4.0 dll Dateien erstellen. 4.0 ist mit Visual Studio 2008 aber nicht möglich, muss dafür erst 2010 oder neuer laden.

Und das der ScriptManager statisch ist gefällt mir nicht so - Lieber wäre mir, ich könnte den Manager instantiieren und mit dem Objekt weiterarbeiten.

Ich muss irgendwo die geladenen Scripts speichern, sonst gibt es keine Möglichkeit Scripts untereinander zu finden und zu unterscheiden, da aus Sicht der DLL alle Scripts vom Typ "IScript" sind. Der ScriptManager ist bewusst statisch, weil dadurch alles an einem Ort zentral zusammen läuft, ab dem Moment wo das nicht mehr so ist, kann jeder eine Instanz erstellen und diese wahllos kopieren und Scripts laden sowie ausführen und die anderen Scripts würden das nicht mitbekommen.

/Edit: Und die Klassen sollten unter einem Namespace liegen um die Klassen evt. von bestehenden Klassen unterscheiden zu können.

Auch hier wurde bewusst auf einen Namespace verzichtet um Fehler zu vermeiden. Es ist schon strafe genug, dass C# case sensitive ist, da will ich nicht noch unnötig viel Ballast an Code hinzufügen. Mal schauen, packe das ganze vielleicht in den Namespace csc. Kurz und einfach.

20.09.2012 - 14:21 Uhr

Es gibt im Zip nur die csc.dll.
Die exe benannte ich cscHost.exe um genau das zu vermeiden. Des weiteren liegt der .Net C# Compiler nicht in der PATH Umgebungsvariable. Der Name kann verwirrend sein, jedoch ist die csc.dll im Grunde ein compiler, abgesehen von der Scriptverwaltung.

20.09.2012 - 13:48 Uhr

der csc, (C Sharp Compiler) ist ein Compiler, der es erlaubt, Scripts, die eine gewisse Grundform erfüllen zur Laufzeit in die eigene EXE Datei zu laden. Hierbei wird von bestehenden .NET Klassen Gebrauch gemacht. Der Compiler gibt daher auch die typischen Fehlermeldungen aus, die aus Visual Studio bekannt sind (Mit Zeilen- und Spaltennummern, etc.)

Das Besondere ist die Tatsache, dass keine Quellcode-Datei vorhanden sein muss (Quellcode wird als String übergeben). Es muss auch kein Verzeichnis für Zieldateien vorhanden sein, da das Ergebnis im Memory platziert wird.

Der Compiler wurde minim erweitert, so kennt er jetzt die #include Commands, die aus C und C++ bekannt sind.Diese Tags erlauben es DLL Dateien (keine C# Source Dateien, dies folgt aber noch) hinzuzufügen. mscorlib und system.dll sind per standard drin, auch die csc.dll, die für das Interface benötigt wird.

Verwendungszweck:
In der Zip Datei liegt eine EXE bei, die es erlaubt C#Scripts über die Konsole so zu kompilieren und auszuführen. Ein Beispielscript (test.cs) liegt ebenfalls bei. Man ist also in Zukunft nicht mehr auf bat oder vbs Dateien angewiesen. sondern kann auch sein C# Script laufen lassen. Der Compiler setzt den Errorlevel auf den integer, der vom Script zurück gegeben wird. Da grundsätzlich alles aus der .NET Library durch die richtigen Includes zugängig ist, könnte theoretisch ein komplettes Spiel in DirectX so mal eben kompiliert werden (vorausgesetzt es passt ins Memory), oder eine Windows Forms Anwendung kann realisiert werden.

die csc2.dll kann auch von einem Programm eingebunden werden um es Usern zu ermöglichen Plugins in C# zu schreiben, ohne diese kompilieren zu müssen.

Tips:
Der ScriptManager, welcher Scripts lädt, verwaltet und ausführt, ist für alle Scripts zugängig, so können Scripts zur Laufzeit weitere Scripts nachladen und untereinander kommunizieren.

DLL Dateien im #include Statement dürfen mit Pfad oder ohne angegeben werden (ohne wird in den .NET Verzeichnissen gesucht). Anführungszeichen um den Pfad sind nicht notwendig.

Klassen und Methoden in der csc2.dll sind durchgehend kommentiert für IntelliSense. Ich empfehle es, die DLL in einem Projekt als Referenz anzugeben und im Object Explorer mal durchzusehen

Scripts können zur Laufzeit zu einer DLL Datei kompiliert werden

In DLL kompilierte Scripts können nun ebenfalls geladen werden.

Beispielscript (test.cs):

//The csc Compiler (not the Default C# Compiler!) supports include Statements for DLL Files
#include System.Windows.Forms.dll

//We need this for the Console Class
using System;
using System.Windows.Forms;

//name your Class however you want
//Names must be unique per Execution
public class Whatever : csc2.IScript
{
	public string Name()
	{
		//We name our Script *testscript. The Asterisk indicates,
		//it is hidden (not visible in ScriptManager.LoadedScript)
		//When calling this Script the Asterisk must be supplied in the Name
		return "*testscript";
	}
	
	public int Main(string[] args)
	{
		//Main Execution Point of our Script
		Console.WriteLine("You should see a Message Box, if not it is probably behind the Console");
		//Simulation of data Exchange with another script
		Console.WriteLine("Returned: {0}",csc2.ScriptManager.Exchange(Name(),"Select an Option"));
		Console.WriteLine("Press a Key");
		Console.ReadKey(true);
		return 0;
	}
	
	public object Exchange(object q)
	{
		return MessageBox.Show(q.ToString(),"Exchanged Message",MessageBoxButtons.YesNo);
	}
}
12.09.2012 - 09:03 Uhr

Diese Einschränkung hast Du unter unixoiden Betriebssystemen auch.

Das Problem ist, dass ich unter Windows nicht so einfach aus der BAT Datei auf stderr zugreifen kann. Ich müsste quasi folgendes tun:

[pre]
ECHO SET VARIABLE=^^>RESULT.BAT
advMenu menu.txt 2>>RESULT.BAT
CALL RESULT.BAT
DEL RESULT.BAT
[/pre]

Die Erste Zeile schreibt SET VARIABLE=^ in die erste Zeile der RESULT.BAT
Die Zweite würde dann den Wert in die zweite Zeile schreiben, da wir stderr umleiten, sofern advMenu das in Zukunft unterstützt.
Die dritte führt die bat Datei aus und erstellt so die Variable. Die Vierte löscht die Datei wieder.

Für alle Nicht-Konsolen-Hacker:
Das "^" ist ein Escape Zeichen in DOS um Sonderzeichen (z.B. & > < |) eingeben zu können. Steht das Zeichen am Ende einer Zeile, so wird der Zeilenumbruch ignoriert und die nachfolgende Zeile wird an die erste drangehängt bei der Ausführung.

Fazit:
SET /P Variable=Bitte einen Wert eingeben: ist einfacher

11.09.2012 - 19:53 Uhr

Unter Linux gibt es das Paket "dialog"

Wie du selbst sagst, auf Linux. Eine entsprechende Windows Variante wäre sicher auch interessant. Das Design sieht für eine Konsole äusserst ansprechend aus. So eine "Input Box" ist mir auch schon mal durch den Kopf gegangen. Ich mussste aber frustriert feststellen, dass wenn ich in C# eine Umgebungsvariable setze, dass diese dann in der gerade laufenden Bat Datei nicht verfügbar ist, deswegen habe ich mich auf den Errorlevel beschränkt
EDIT: Hier noch der Thread von Stack Overflow bzgl. Environment Variablen in C# und Bat Dateien: Persist an environment variables after app exits

...wie der Autor das mit der Übergabe von Parametern geregelt hat Mehr Parameter sind geplant, auch vom § will ich weg kommen. Damit das Menü dynamischer wird, sollen die Zeilen aber trotzdem noch mit ECHO Anweisungen zur Laufzeit erstellt werden können.

11.09.2012 - 12:26 Uhr

Da mir aufgefallen ist, dass CHOICE(.com|.exe) auf Windows Systemen mittlereile immer seltener vorhanden ist. Hier auf meinem 64 bit windows 7 habe ich es, mein Arbeitskollege hats nicht. Deswegen habe ich advMenu entwickelt. advMenu ist ein erweitertes Konsolen Menü, welches nicht mehr mit den Buchstaben (J/N) bedient wird, sondern welches richtige Menüpunkte anbietet, von denen einer mit den Pfeiltasten selektiert und mit Enter bestätigt wird. Rückgabe erfolgt über den Errorlevel, so kann es in Batchdateien verwendet werden. Als Parameter wird eine Datei übergeben, welche die Menüstruktr enthält.

Die Applikation ist auch mit vielen Menüpunkten sehr schnell, die Konsole flackert nicht beim umschalten der Menüpunkte.

Lizenz:
Da ich mich nicht mit Lizenzen herumschlagen will, lizenziere ich die App und deren Code unter der WTFPL. Viel spass.

Argumente: <Datei>|/? [color|file]
<Datei> -> Menüstruktur

/? [color|file] -> Zeigt die Hilfe an (ohne color und file), dies istauch die Standardauswahl, wenn keine Datei angegeben wird.
Mit der Unteroption color, wird die CMD Farbtabelle ausgegeben.
DieUnteroption file zeigt das Format der menüdatei an.

Das Paragraphenzeichen:
Eher ungewöhnlich als Trennzeichen. Das Problem ist, dass ein Trennzeichen nicht im Text vorkommen sollte, also muss es ungewöhnlich sein. Der Senkstrich (|) hat unter DOS jedoch eine besondere Bedeutung.
In zukünftigen Versionen des Programmes wird dies möglicherweise noch umgestellt und ist daher nur als "temporäre" Lösung zu betrachten.

Beispieldatei (Zeile 2 gekürzt da es das Forum Design verunstaltet, im Screenshot ist jedoch alles zu lesen):

10§0§14§9§15§0
The System has shut Down§Do you want to commit Changes to Drive or discard them?§The Action...
Commit Changes§1
Discard Changes§2
Abort§3

Obige Datei erzeugt:
siehe nächster Post

Dateiformat:
Die Datei ist bewusst so einfach gehalten, so kann die Datei "on the fly" mit echo Zeilen generiert werden.
Ich erkläre hier kurz das Format:

  1. Zeile: 6 Zahlen, durch § getrennt. Als Vorder- und Hintergrundfarben für Menüpunkte, Aktiver Menupunkt und Titel. Bereich von 0-15
  2. Zeile: Titel. § erzeugt Zeilenumbruch
    n. Zeile: Weitere Zeilen sind Menüpunkte, die Zahl nach dem § ist der Errorlevel.

Menüpunkte werden in der Reihe nach gelistet, wie sie in der Datei stehen.
Der unterste Menüpunkt mit Errorlevel 0 wird standardmässig selektiert.
Ein Errorlevel darf mehrmals vorkommen (wenn auch etwas sinnfrei).
Der aktuelle Menüpunkt wird durch ein Sternchen markiert, so sind auch
monochrome Menüs möglich und die Benutzung durch Farbenblinde ist möglich

TODO:

  • Mehrfachauswahl (Durch Addition der Errorlevel Werte)
    Dadurch kann ein "Wählen Sie die gewünschten Optionen" Menü erstellt werden.

  • Shortcut Keys für Menupunkte
    Macht die J/N Auswahl wieder möglich.

  • Wiederherstellen vorheriger Konsolentext
    Der geht zur Zeit verloren.

  • Menü als eine Art "popup" vor anderem Text
    Sieht etwas mehr "Windows Like" aus

  • Menü als Parameter übergeben.
    Für kleine Menüs sicher denkbar, für grössere etwas umständlich.

  • Automatische Antwort nach bestimmter Zeit
    Ideal für unüberwachte Setups.

Ich bin gerne bereit gute Ideen und Ansätze von euch in das Tool einzufügen.

ZIP Archiv:
Kompletter Code enthalten, Release Build enthalten. Release ist etwas veraltet und sollte neu erstellt werden, funktioniert aber grundsätzlich.