log4net: GetAllAppenders()

Returns a List of the IAppender Interface, which actually contracts:


string Name { get; set; }
void Close();
void DoAppend(LoggingEvent loggingEvent);

 
        public static List<log4net.Appender.IAppender> GetAllAppenders()
        {
            List<log4net.Appender.IAppender> appenders = new List<log4net.Appender.IAppender>();

            log4net.Repository.Hierarchy.Hierarchy h = (log4net.Repository.Hierarchy.Hierarchy)log4net.LogManager.GetRepository();
            appenders.AddRange(h.Root.Appenders.Cast<log4net.Appender.IAppender>());

            foreach (log4net.Repository.Hierarchy.Logger logger in h.GetCurrentLoggers())
            {
                appenders.AddRange(logger.Appenders.Cast<log4net.Appender.IAppender>());
            }

            return appenders;
        }

I recommend to check (or at least output) all appenders at the beginning of each project you use log4net!

Das BGB als XML


(Verwendungsbeispiel)

Wer, aus welchen Gründen auch immer, das bürgerliche Gesetzbuch in seine Anwendung implementieren will, der wird sich über das „BGB als XML“ freuen.

Download als .zip-Archiv
Download als .xml (ca. 3,3 MB)

Dank des universellen XML-Formats kann das BGB plattform- und programmiersprachenunabhängig eingebunden werden. Der einfachheit halber enthält es kein Inhaltsverzeichnis und keine Hierarchie. Es beschränkt sich lediglich auf die Normen und handelt sich um die aktuellste Ausgabe zum Zeitpunkt der Erstellung (Juli 2012).

So schaut beispielsweise ein XML-Knoten („Norm“) aus:

    
      (1) Der Finder kann von dem Empfangsberechtigten einen Finderlohn
verlangen. Der Finderlohn beträgt von dem Werte der Sache bis zu 500
Euro fünf vom Hundert, von dem Mehrwert drei vom Hundert, bei Tieren
drei vom Hundert. Hat die Sache nur für den Empfangsberechtigten einen
Wert, so ist der Finderlohn nach billigem Ermessen zu bestimmen.
(2) Der Anspruch ist ausgeschlossen, wenn der Finder die Anzeigepflicht
verletzt oder den Fund auf Nachfrage verheimlicht.
      Neugefasst durch Bek. v. 2.1.2002 I 42
      § 971
      Finderlohn
    

Wer seine Anwendung ohnehin in C# .NET schreibt, der kann direkt meinen Deserializer und die dazugehörige Wrapperklasse verwenden:

 
[Serializable]
    public class BGB
    {
        private List<Norm> _Normen;

        public List<Norm> Normen
        {
            get { return _Normen; }
            set { _Normen = value; }
        }

        [Serializable]
        public class Norm
        {
            private string _text;

            public string Text
            {
                get { return _text; }
                set { _text = value; }
            }

            private string _appendix;

            public string Appendix
            {
                get { return _appendix; }
                set { _appendix = value; }
            }

            private string _paragraph;

            public string Paragraph
            {
                get { return _paragraph; }
                set { _paragraph = value; }
            }

            private string _title;

            public string Title
            {
                get { return _title; }
                set { _title = value; }
            }
        }

        public BGB()
        {
            _Normen = new List<Norm>();
        }

        public void AddNorm(Norm Norm)
        {
            _Normen.Add(Norm);
        }
    }

Der (De-)Serializer:

 
public class Serializer
    {
        public void SerializeToXMLString<T>(T XMLObj, Stream s, Encoding encoding, bool removeNamespace)
        {
            try
            {
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
                XmlTextWriter xmlSink = new XmlTextWriter(s, encoding);
                xmlSink.Formatting = Formatting.Indented;

                if (removeNamespace)
                {
                    XmlSerializerNamespaces xs = new XmlSerializerNamespaces();
                    xs.Add("", "");
                    xmlSerializer.Serialize(xmlSink, XMLObj, xs);
                }
                else
                    xmlSerializer.Serialize(xmlSink, XMLObj);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);

                if (ex.InnerException != null)
                    Console.WriteLine(ex.InnerException);
            }
        }

        public void SerializeObjectToXMLFile<T>(T XMLObj, string Filename, Encoding encoding, bool removeNamespace)
        {
            FileStream fs = new FileStream(Filename, FileMode.Create);
            SerializeToXMLString<T>(XMLObj, fs, encoding, removeNamespace);
        }

        public void SerializeObjectToXMLFile<T>(T o, string Filename)
        {
            SerializeObjectToXMLFile<T>(o, Filename, Encoding.Unicode, true);
        }

        private MemoryStream GetUTF16MS(string xml)
        {
            // Encode the XML string in a UTF-8 byte array
            byte[] encodedString = Encoding.Unicode.GetBytes(xml);

            // Put the byte array into a stream and rewind it to the beginning
            MemoryStream ms = new MemoryStream(encodedString);
            ms.Flush();
            ms.Position = 0;
            return ms;
        }

        private bool DeserializeFromXMLString<T>(string XML, ref T myObject, bool allow_log)
        {
            if (XML == string.Empty)
                return false;

            XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
            MemoryStream ms = GetUTF16MS(XML);

            try
            {
                XmlReader xmlReader = XmlReader.Create(ms);
                while (xmlReader.Read())
                { }

                ms.Position = 0;
            }
            catch (Exception ex)
            {
                if (allow_log)
                    Console.WriteLine(ex.Message);

                return false;
            }

            //StringReader sr = new StringReader(XML);
            //myObject = (T)xmlSerializer.Deserialize(sr);
            myObject = (T)xmlSerializer.Deserialize(ms);

            return true;
        }

        public bool deserializeObjectByXML<T>(string data, ref T myObject, bool allow_log)
        {
            return DeserializeFromXMLString(data, ref myObject, allow_log);
        }
    }

Großhochzeit: C#, Delphi, Assembler und COM

Ein Feature das mit großer Wahrscheinlichkeit in zukünftigen Versionen von .NET noch implementiert werden wird, ist (managed/inline-) Assembler in seine Projekte einzubinden. In einigen Hochsprachen mit „echtem“ Compiler ist dies bereits seit vielen Jahren Standard: C++, TurboPascal, FreePascal, Delphi, freeBASIC, usw.

Zudem findet man in alten mächtigen Source-Code-Archiven oft bis zur Perversion optimierte Algorithmen, die der Autor bereits in Inline-ASM implementiert hat. Es wäre doch zu schade diese nicht weiter nutzen zu können…

Folgenden Code fand ich im SwissDelphiCenter:
http://www.swissdelphicenter.ch/de/showcode.php?id=2049
(Ein Instring-Algorithmus von Vanja Fuckar, 100% inline-ASM)

Delphi erlaubt es mit sehr wenig Aufwand einen Quelltext direkt als COM-Programmbibliothek zu kompilieren. Heraus kommt eine dll-Datei (hier: „InString_dll.dll“) die ich nun in mein .NET-Projekt einbinde mittels:


[System.Runtime.InteropServices.DllImport("InString_dll.dll", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
private static extern int InString(int StartPosition, string Source, string Pattern);

Aufgerufen wird diese externe statische Funktion wie üblich z.B. mit:


Console.WriteLine(InString(0, "Testautotesttesttest", "auto").ToString());

Einen Haken hat das (vor)kompilieren von Inline-Assembler: Es gibt keine Gewährleistung, dass diese Programmbibliothek auch auf anderen Prozessorarchitekturen bzw. -familien ausgeführt werden kann, als auf der sie kompiliert wurde.
Exemplarisch habe ich dafür die .NET-Anwendung auf einem AMD Athlon X2 64bit ausgeführt: der JIT-Debugger spuckt eine Exception aus, die mir eine ungültige Typenumwandlung bestätigt.
Auf einem Intel Pentium 4 HT wiederum lief der Quelltext einwandfrei.
Anmerkung dazu: Die Programmbibliothek habe ich auf einer Intel Pentium M kompiliert, die bekannterweise nicht aus der Familie der NetBurst-Architekturen stammt.

Nachtrag: Auf einem Pentium Xeon (NetBurst) lief die Anwendung ebenfalls einwandfrei.

C#.NET: Winamp-Titel auslesen

Winamp-Titel auslesen in C#

Möchte man mit C# wie in Delphi den aktuellen Winamp-Titel auslesen (siehe vorheriger Artikel), kann man sich prinzipiell den selben Methoden bedienen. Der Zugriff auf die WinAPI gestaltet sich allerdings etwas trickiger. Dieser Snippet darf privat und kommerziell verwendet werden. Ich würde mich in beiden Fällen sehr über Feedback freuen!


        [System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
        public static extern IntPtr FindWindow(string strClassName, int nptWindowName);
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, long lParam);
        [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
        static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
        [System.Runtime.InteropServices.DllImport("kernel32.dll")]
        static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, Boolean bInheritHandle, UInt32 dwProcessId);
        [System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
        static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [System.Runtime.InteropServices.Out] byte[] lpBuffer, UIntPtr nSize, IntPtr lpNumberOfBytesRead);
        [System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool CloseHandle(IntPtr handle);

        private static string GetWinampTitle()
        {
            const uint WM_USER = 0x0400;
            const uint PROCESS_ALL_ACCESS = 0x000F0000 | 0x00100000 | 0xFFF;

            uint ProcessHandle;
            byte[] dat2 = new byte[500];
            IntPtr temp = (IntPtr) 0;

            IntPtr hwndWinamp = FindWindow("Winamp v1.x", 0);
            IntPtr MPointer = SendMessage(hwndWinamp, WM_USER, SendMessage(hwndWinamp, WM_USER, (IntPtr) 0, 125), 212);
            GetWindowThreadProcessId(hwndWinamp, out ProcessHandle);
            hwndWinamp = OpenProcess(PROCESS_ALL_ACCESS,false,ProcessHandle);
            ReadProcessMemory(hwndWinamp, MPointer, dat2, (UIntPtr) 500, temp);
            CloseHandle(hwndWinamp);
            return Convert.ToString(System.Text.Encoding.ASCII.GetString(dat2));
        }