Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Portal
  • |
  • Mitglieder
Beiträge von AyrA
Thema: .NET CoreCLR 5 jetzt open source
Am im Forum: Szenenews

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.

Zitat
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.

Thema: Dispatcher: Synchrone Callbacks made easy
Am im Forum: .NET-Komponenten und C#-Snippets

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

Thema: Projektvorschlag: Ähliminator gesucht
Am im Forum: Projekte

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.

Thema: WADex - WAD Dateien extrahieren und assemblieren
Am im Forum: Projekte

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
  2. PWAD extrahieren in Ordner B
  3. Dateien (ohne Index) von B nach A verschieben und alles überschreiben
  4. Nicht existierende Zeilen in der Indexdatei von A mit denen von B ergänzen
  5. 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.

Thema: MaskMatch Klasse zum durchsuchen mehrerer Verzeichnisebenen
Am im Forum: .NET-Komponenten und C#-Snippets

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.

Thema: MaskMatch Klasse zum durchsuchen mehrerer Verzeichnisebenen
Am im Forum: .NET-Komponenten und C#-Snippets

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

Thema: AOTP - Dateien verschlüsseln und kontrolliert freigeben
Am im Forum: Projekte

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

Thema: AOTP - Dateien verschlüsseln und kontrolliert freigeben
Am im Forum: Projekte

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)

Thema: AOTP - Dateien verschlüsseln und kontrolliert freigeben
Am im Forum: Projekte

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.

Thema: AOTP - Dateien verschlüsseln und kontrolliert freigeben
Am im Forum: Projekte

Screenshot

Thema: AOTP - Dateien verschlüsseln und kontrolliert freigeben
Am im Forum: Projekte

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

Thema: BefunGen - ein Befunge code generator
Am im Forum: Projekte

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

Thema: Maze Tools - Labyrinth generator und Spiel
Am im Forum: Projekte

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

Thema: YouTube Backup
Am im Forum: Projekte

Neues Update

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

Thema: Farben in der Konsole
Am im Forum: .NET-Komponenten und C#-Snippets

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

Thema: Process Killer
Am im Forum: Projekte

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"

Thema: Globale Hotkey Klasse
Am im Forum: .NET-Komponenten und C#-Snippets

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

Thema: Process Killer
Am im Forum: Projekte

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.

Thema: Process Killer
Am im Forum: Projekte

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?

Thema: Process Killer
Am im Forum: Projekte

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)
  2. [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.
  3. [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.

Thema: XKCD Time (1190) Comic Player
Am im Forum: Projekte

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.

Thema: BefSharp - Befunge Interpreter in C#
Am im Forum: Projekte

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)

Thema: BefSharp - Befunge Interpreter in C#
Am im Forum: Projekte

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

Thema: BefSharp - Befunge Interpreter in C#
Am im Forum: Projekte

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.

Thema: Windows Fenster für Benutzername und Passwort
Am im Forum: .NET-Komponenten und C#-Snippets

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

Thema: YouTube Backup
Am im Forum: Projekte

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

Thema: Windows Fenster für Benutzername und Passwort
Am im Forum: .NET-Komponenten und C#-Snippets

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

Thema: YouTube Backup
Am im Forum: Projekte

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.
  • Es werden keine Youtube Videos selbst heruntergeladen. Dies ist in der API nicht enthalten und verstösst gegen die Nutzungsbedingungen.

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.

Thema: Maus in Konsole verwenden
Am im Forum: Projekte

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.

Thema: Maus in Konsole verwenden
Am im Forum: Projekte

Download als Dateianhang