Laden...
Avatar #avatar-2119.jpg
egrath myCSharp.de - Member
Softwareentwickler Österreich / Steyr Dabei seit 24.07.2005 871 Beiträge
Benutzerbeschreibung

Forenbeiträge von egrath Ingesamt 871 Beiträge

07.08.2007 - 10:11 Uhr

Hallo,

ich persönlich finde dass das schon passt. Und zwar aus folgendem Grund:

Wenn Du nur eine Fehlermeldung ausgeben willst und nicht auf jede auftretende Exception anders reagieren möchtest reicht es die Oberklasse "Exception" abzufangen. Da die ToString Methode des Exception-Objekts virtuell ist, kriegst Du darüber eh eine (mehr oder minder) aussagekräftige Information die Du dem User präsentieren kannst.

Grüsse,
Egon

/edit: @Mod: Da Herbivore schneller war, kann meine Antwort bei Bedarf gelöscht werden.

07.08.2007 - 08:24 Uhr

Hallo,
jede Zeile auslesen und mit einem Tokenizer die einzelnen Werte der Zeile auslesen.

Tokenizer

Grüsse,
Egon

31.07.2007 - 21:29 Uhr

Hallo,
Du kannst auch die Vorteile beider Welten miteinander vereinen. Lasse dem User nicht nur eine Simple Seriennummer eingeben sondern einen beispielsweise mit Base64 kodierten Textblock. Dieser ist in seiner Binärform mit einem Public-Key verfahren verschlüsselt. Somit braucht sich der User nicht mit Lizenzfiles rumschlagen sondern nur mehr den beispielsweise mittels e-Mail zugesandten Text in das Seriennummernfeld kopieren.
Grüsse,
Egon

31.07.2007 - 13:02 Uhr

Hallo,

ich persönlich würde mich für eine Lizenzdatei entscheiden da dies oftmals ein sichereres verfahren darstellt als Seriennummern (Public-Key Verfahren zur Ver-/Entschlüsslung der Daten in der Lizenzdatei)

Grüsse,
Egon

30.07.2007 - 14:24 Uhr

Hallo,

ich habe vor einiger Zeit mal ein kleines Beispielprogramm für die Wegefindung mittels Breath-First Algorithmus geschrieben welches dir vielleicht weiterhelfen kann.

Zu finden unter:
http://www.geocities.com/egon_rath/pft.html

Grüsse,
Egon

30.07.2007 - 12:33 Uhr

Hallo,

ich habe gerade den Port meiner ursprünglich in Java entwickelten Library zum lösen von mathematischen Ausdrücken abgeschlossen. Mit dieser ist es möglich, beispielsweise folgenden Ausdruck zu lösen:


ExpressionSolver.exe "(-1)*(3*7.3/4^3-(17*2^2)^3"
Result = 314431.6578125

Dabei wird folgendermassen vorgegangen:* Der Ausdruck wird in die Umgekehrte polnische Notation gewandelt

  • Die UPN wird anschliessend schritt für schritt gelöst

Derzeit sind neben den Grundrechnungsarten auch die beiden Funktionen Sinus ("sin(n)") und Hypotenuse ("hypot(n,n)") implementiert - das hinzufügen von weiteren Funktionen ist aber kein grosser Hokus-Pokus.

Vielleicht kann es ja jemand von euch brauchen.

Grüsse,
Egon

30.07.2007 - 07:21 Uhr

Hallo Golo,

einfach bei Ripe.net in das Suchfeld die IP Adresse eingeben und schon bekommst Du den Netblock Owner gelistet.

Grüsse,
Egon

29.07.2007 - 15:00 Uhr

Hallo,

die variable mFlag wird nicht als der Wert der in Ihr enthalten ist in den String eingebaut sondern als der Name "mFlag" selbst, da du:


string sqlstr = "select top "+lines+" feld1,feld2,feld3 from t_dummytable where  flag = mFlag";

anstelle von:


string sqlstr = "select top "+lines+" feld1,feld2,feld3 from t_dummytable where  flag = " + mFlag;

geschrieben hast.
Grüsse,
Egon

27.07.2007 - 11:23 Uhr

Hallo,

ich persönlich glaube nicht dass sich das Konzept der Menüleiste so schnell erübrigen wird. Der Grund liegt meines erachtens einfach darin, dass es gerade bei komplexen Anwendungen sehr schwierig sein kann, die gesamte Funktionalität in ein hoch-intuitives Benutzerinterface zu packen.

Microsoft Surface ist ein schönes Demo wenn es darum geht, wie man Endanwender Applikationen mit geringem bis mittlerem Funktionsumfang einfacher bedienbar machen kann. Für Applikationen wie beispielsweise CAD kann ich mir solche Konzepte aber nicht vorstellen.

Desweiteren möchte ich vielleicht zum nachdenken anregen indem ich behaupte dass Microsoft nicht der einzige ist der Standards vorgibt (Ribbons,etc). Viele Technologien die von anderen Firmen vor langer Zeit entwickelt wurden und laut prognosen schon vor längerer Zeit abgelöst werden sollten befinden sich heute immer noch in voller Blüte am Markt (z.b. X11 Protokoll, Kommandozeile, etc.) - einfach deshalb weil die Leute es gewohnt sind und es eine erprobte, effektive und robuste Technologie darstellt.

Grüsse,
Egon

25.07.2007 - 10:44 Uhr

Hallo,

ich habe einen kleinen Artikel über Multi-Threaded Programmierung geschrieben, den ich euch nicht vorenthalten möchte 😉

Grüsse,
Egon

/ps: Aufgrund des Umfangs als PDF im beiligenden ZIP file (sourcen des Dokuments sind auch drinnen)

25.07.2007 - 10:36 Uhr

Hallo,

Windows XP Home hat auch OS Version 5.1
Vista hat 6.0

Grüsse,
Egon

24.07.2007 - 06:55 Uhr

Original von LonelyPixel
Ähm, geht nicht sowas wie sizeof(int) oder das gleiche als unmanaged type? Ich glaub ich hab da mal irgendwas gesehen... In .NET ist die Länge von int ja fest auf Int32 gesetzt, aber außerhalb von .NET müsste es doch einen Einfluss haben. Kann leider kein konkretes Codebeispiel geben.

Hallo,

ob Du auf x64 oder x86 unterwegs bist kannst Du feststellen indem Du einfach versuchst eine (mitgelieferte) 32-Bit DLL zu laden. Schlägt dies fehl befindest Du dich auf einer 64 Bit VM (32er DLL kann nicht in 64er Adressraum geladen werden).

Damit kannst Du aber nicht feststellen ob du auf der 32er VM eines 64er OS'es läufst.

Grüsse,
Egon

23.07.2007 - 09:50 Uhr

Hallo,

meine Meinung dazu ist, dass man die Kern-Sprachelemente so gering wie möglich halten sollte und Design Patterns selbst implementieren möge.

Grüsse,
Egon

20.07.2007 - 12:50 Uhr

Hallo,

auf die schnell fällt mir ein:

Nachschauen ob es den Folder "C:\Program Files (x86)" gibt. Den gibts nur auf x64 OS Versionen.

Hier gibts auch noch nen netten Thread drüber:

Klicke hier

Grüsse,
egon

18.07.2007 - 21:34 Uhr

Hallo,

ich hab jetzt kein Vista hier zum Testen, aber kann jemand mal die Aero Oberfläche abschalten und es dann nochmal probieren?

Grüsse,
Egon

18.07.2007 - 21:30 Uhr

Hallo,

also ich würde mich in deiner Situation für das TAO Framework entscheiden und auf OpenGL setzen. Die Gründe sind primär:

  • OpenGL ist ein etablierter Standard der kontinuierlich weiterentwickelt wird und
  • Platformunabhängig ist. Deine unter .NET mit TAO geschriebenen Applikationen laufen unter allen Platformen auf denen .NET bzw. Mono verfügbar ist.

Das ganze hat natürlich auch eine Kehrseite: Es ist komplexer zu erlernen

Grüsse,
Egon

18.07.2007 - 21:24 Uhr

Hallo,

einfach einen neuen Form instanziieren und mit der "Show" Methode starten?


Form myForm = new Form();
myForm.Size = new Size( 320, 240 );
myForm.Show();

oder wenn Du ihn im Designer bereits designed hast und beispielsweise als "Form2" benannt hast:


Form2 myNewForm = new Form2();
myNewForm.Show();

Eventuell in einen eigenen Thread auslagern wäre nicht uninteressant.

Grüsse,
Egon

/edit: Kann das bitte ein Mod nach GUI Technologien verschieben - Danke

18.07.2007 - 16:29 Uhr

Hallo,
wie der Vorposter schon sagte, stell um auf any CPU falls Du keine x86 spezifischen Sachen drinnen hast die das benötigen. Das Problem ist dass wenn der Kunde eine 64-Bit Maschine mit 64-Bit OS und 64-Bit Runtime benutzt, dann kann deine DLL (da ja bei x86 auf 32 Bit beschränkt) nicht in den 64-Bit Adressraum geladen werden.
Grüsse,
Egon

18.07.2007 - 13:42 Uhr

Hallo,

wie schon dr4g0n76 sagte gehts mit der SetParent Funktion. Anschliessend noch mit SetWindowLong den Fensterrahmen entfernen und gut is.

Es gibt bestimmte Anwendungsfälle bei denen man das wirklich brauchen kann. Als beispiel fällt mir jetzt ein wenn man ein SDL Window (SDLlibrary) mit einer Windows Menüleiste versehen will (da SDL nur simple Fenster erzeugen kann ohne irgendwelchen Schnick-Schnack)

Grüsse,
Egon

18.07.2007 - 13:37 Uhr

Hallo,
es sollte auch noch erwähnt werden dass durch ">" nur der Standard Output umgeleitet wird. Eventuelle Meldungen auf Standard Error werden auf Kanal 2 ausgegeben:

Programm.exe 2>fehler.txt 1>ausgabe.txt

oder aber auch um alles in ein Logfile zu kriegen:

Programm.exe 2>&1 1>alles.txt

Grüsse,
Egon

18.07.2007 - 13:33 Uhr

Hallo,

so einfach ist das nicht. Der Grund liegt darin dass eine Datei nicht nur auf einem Platz des Datenträgers liegt sondern durch Fragmentierung in mehrere Cluster aufgeteilt werden kann.

Um aber an die Daten der Blöcke und deren Adresse zu kommen kannst Du die Defrag API nutzen, welche in seiner Ausprägung als C# Wrapper hier beschrieben ist.

Grüsse,
Egon

17.07.2007 - 22:38 Uhr

Hallo Golo,

Bei den Firmen bei denen ich bis jetzt gearbeitet habe wurde das im Normalfall immer so gelöst dass die Endbenutzerdokumentation in einem Quelloffenen Format geschrieben wurde (TeX) und das ganze im Repository gelegen ist.

Bei jedem vollen Build des Projekts erzeugte der Buildserver automatisch aus der letztgültigen Dokumentation das entsprechende Format (HTML für die Online Hilfe, PDF für den späteren Ausdruck).

Grüsse,
Egon

17.07.2007 - 22:29 Uhr

Original von Kalleberlin
Woher zum Teufel, wisst Ihr z.B. diese Parameter :

  
        private const int WM_NCPAINT = 0x0085;  
        private const int WM_NCLBUTTONDOWN = 0x00A1;  
        private const int WM_NCLBUTTONUP = 0x00A2;  
        private const int WM_NCHITTEST = 0x0084;  
        private const int WM_NCCALCSIZE = 0x0083;  
        private const int WM_NCACTIVATE = 0x0086;  
        private const int WM_CLOSE = 0x0010;  
  

Die meisten dieser Konstanten kann man im Normalfall nachlesen indem man zuerst die Win32 API Dokumentation (MSDN) nachliest und sich anschliessend die Werte der Konstanten aus den entsprechenden C/C++ Header Dateien des Platform SDK's raussucht (wird beides installiert wenn man eine voll Visual Studio installation hat)

Grüsse,
Egon

17.07.2007 - 16:25 Uhr

Hallo,
der Proxy ist bewusst nicht implementiert, da es sich um eine spezielle Anwendung für den Firmeninternen gebrauch handelt. Wir hatten folgendes Problem:

  • Web Anwendung eines 3rt Party Anbieters welche nur mit Internet Explorer funktioniert
  • Einen Enterprise weiten Virenscanner der aufgrund der unmengen an Temporären Internet Files die die App erzeugt diese exterm (4-5 Seks pro Seite) bremst.

Da wir den Virenscanner nicht so konfigurieren wollten dass der Prozess iexplore.exe aus der Liste der zu scannenden Prozesse ausgenommen wird - und man den IE leider (oder zum Glück?) nicht als anderen Prozessnamen starten kann entstand dieses Ding. Proxy Settings sollten nicht verstellbar sein, damit der User auf keinen Fall auf externe Seiten navigieren kann - und damit mit einem ungeschützten Internet Explorer basierenden System das Netz verunsichert 😉

Ich freue mich dass Du den Browser so erweiterst dass er vielleicht auch für Standard-Sachen brauchbar wird.

Grüsse,
Egon

/edit: Ja, ja ich weiss der Screenshot zeigt Google - welches obigem Paradigma wiederspricht.

17.07.2007 - 16:19 Uhr

Hallo,

wir verwenden für interne Schulungen im Betrieb die Software "NetOp School" mit der alle Schüler beispielsweise einen ausgewählten Bereich des Lehrer-Desktop's sehen können (und noch viele andere nette Features mehr)

Grüsse,
Egon

17.07.2007 - 16:17 Uhr

Hallo,

früher habe ich gerne die Happy Computer gelesen falls die noch wer kennt hier 😉 Seits die nicht mehr gibt bin ich auf die c't und das iX Magazin umgestiegen. Obwohl man definitiv bemerken muss dass sich der Qualitätsstandard den die c't heute hat mit dem von früher nicht messen kann.

Persönlich bin ich der Meinung dass sich die c't immer mehr an die Boulevard-Presse der anderen "IT" Magazine (PC Welt, Chip, etc.) annähert auch wenn es noch nicht so arg ist. Die Artikel mit tiefgreifenden Technischen Details die es zwar immer nocht gibt - aber in immer geringerem maasse - fehlen mir persönlich schon. Es macht so den Eindruck dass diese Artikel in die iX wandern und sich die c't auf ein anderes Publikum konzentriert.

Aber so ändern sich die zeiten von "Deutschlands dickstem Männermagazin" halt ...

Grüsse,
Egon

17.07.2007 - 16:03 Uhr

Ich bin eigentlich recht schlicht unterwegs - Firefox ohne jegliche Zusatzplugins für jede Art von Web-Browsing. Nur für's Intranet darfs der IE in der Ausartung Nummer 7 sein da sonst nichts mit dem SharePoint und anderem Properitären Zeugs zurechtkommt dass unsere Webentwickler verbrochen haben 😉

Grüsse,
Egon

05.07.2007 - 14:26 Uhr

Hallo dr4g0n76,

wir haben Firmenintern gerade ein Projekt am Laufen, bei dem wir ebenfalls auf der Suche nach einer Stereoskopischen Brille waren. Nach der Evaluierung diverser Systeme sind wir dann bei diesem Produkt geblieben:

StereoGraphics Crystal Eyes 3

Grund dafür war die hervorragende Bildqualität und die guten Treiber des Systems.
Leider ist der Preis nicht gerade billig, liegt so bei um die 700 Euro.

Grüsse,
Egon

03.07.2007 - 14:14 Uhr

... und damit man nicht die Katze im Sack downloaden muss, hier noch ein kleiner Screenshot davon.

03.07.2007 - 14:08 Uhr

Hallo,

Ich habe einen kleinen Web-Browser entwickelt, welcher primär dafür gedacht ist im Intranet befindliche Web Anwendungen zu bedienen. Die Anforderungen an diesen waren:
*) Minimalistischer GUI Ansatz (Nur Druck Button)
*) Benutzerinteraktion nur über Web-Applikation (Kein Kontextmenü, etc.)
*) Fähigkeit JS window.open richtig zu behandeln (Neues Fenster vom Browser selbst)
*) Fähigkeit Cookies mit den anderen WebBrowser Controls der Applikation zu sharen.

Herausgekommen ist die beiliegende Software. Vielleicht kann ja jemand von euch das brauchen.

Grüsse,
Egon

14.03.2007 - 10:24 Uhr

Hallo,

natürlich wäre es eine möglichkeit DirectX zu verwenden (oder eine auf DX aufsetzende 2D Lib wie z.B. SDL). Für reale Applikationen wäre das sicherlich die Variante die man benutzen sollte.

Das ganze hat sich für mich persönlich aber eher zu einem Proof of Concept entwickelt, da ich einfach sehen will was sich aus GDI so alles rausholen lässt. Glaube allerdings dass sich mit dem letzten gezeigten so ziemlich das Ende der Fahnenstange erreicht ist, da das Blitting einfach eine gewisse Zeit beansprucht und es unter GDI leider nicht die möglichkeit des Page Flippings gibt. (Oder irre ich hier?)

Grüsse, Egon

13.03.2007 - 09:06 Uhr

Original von vbtricks
Und die Java-Version benötigt eine Lizenz für die Windows-Version von Linux.

Den Satz find ich den Hammer fg - ein richtig schöner Freudscher versprecher - du meintest wohl Windows-Version von Lemmings, oder?

Grüsse, Egon

13.03.2007 - 09:02 Uhr

Hallo,

MPI bezeichnet das Message Passing Interface und umfasst eine Sammlung von Funktionen welche für die Kommunikation von verteilten Anwendungen im High-Performance bereich genutzt werden.

Für .NET gibt es eine Portierung namens MPI.NET welche man benutzen kann.

Siehe:

Klick

Grüsse, Egon

13.03.2007 - 08:59 Uhr

Hallo,

technisch gesehen gibt es meines Erachtens nach keinen Grund warum man keine Nested-Classes benutzen sollte.

Vor einiger Zeit bin ich mal zu dem Thema auf einen Artikel gestossen der die Pro und Con's von Inner- und Nested Classes behandelt. Ist zwar für Java aber das ist ja egal:

Inner classes: So what are inner classes good for anyway?

Grüsse, Egon

12.03.2007 - 07:16 Uhr

Hallo,

wenn Du nur die .NET Bordmitteln nehmen willst, könntest Du die Bitmaps auch als Resourcen in einer eigenen DLL speichern. Stichworte hierzu sind "ResourceReader" und "ResourceWriter"

Grüsse, Egon

12.03.2007 - 07:09 Uhr

Hallo,

ich hab ein Tool gefunden welches einen virtuellen Brenner zur verfügung stellt:

http://isorecorder.alexfeinman.com/isorecorder.htm

Grüsse, Egon

/PS: Ja, ist Freeware

09.03.2007 - 08:40 Uhr

Hallo,

diese Informationen werden in den alternativen Datenströmen von NTFS gespeichert. Soweit ich informiert bin, gibt es derzeit keine .NET Funktionalität um diesen Stream zu schreiben.

Such mal im Google nach "SummaryInformation Stream" dann wirst Du etliche Informationen darüber finden wie der Stream aufgebaut ist.

Artikel zum schreiben von ADS-Streams:

[Artikel] NTFS Datenströme

Grüsse, Egon

09.03.2007 - 08:32 Uhr

Hallo,

... und falls das ganze mal zu langsam werden sollte (weil sich z.B. die grösse des Images ändert) dann weise ich mal gleich vorab auf LockBits hin.

Grüsse, Egon

07.03.2007 - 15:31 Uhr

Hallo,

für Allegro gibt es auch ein C# Binding: http://www.skorzec.com/allegnet/
Eine weitere Bibliothek welche ähnliche (mehr) funktionalität bietet ist TAO (http://www.mono-project.com/Tao)

/edit:

Für neue Projekte würde ich TAO empfehlen, da dahinter eine wesentlich grössere Community steckt und es laufend erweiterungen und Bugfixes gibt.

Grüsse, Egon

07.03.2007 - 09:19 Uhr

QUellcode für das ganze.

/edit: Die Executables sind jetzt auch im Archiv
/edit: Neues Update mit einigen Performance verbesserungen
/edit: FPS Anzeige in Titlebar eingebaut

07.03.2007 - 09:19 Uhr

Hallo,

so ich hab mein Demo jetzt fertig. Folgende Features:

*) Unlimitierte Anzahl von Ebenen möglich
*) Unterschiedliche Geschwindigkeit der einzelnen Ebenen
*) Unterschiedliche Richtung der einzelnen Ebenen

Im Demo sind vier Ebenen drinnen die alle nach links scrollen - so als ob man von einem Zug aus auf die Landschaft sieht.

@dr4g0n76: Es gibt sicherlich nocht viele Optimierungsmöglichkeiten die man ausschöpfen könnte, auch wenn diese mit etwas Arbeit verbunden sind. Eventuell entwickelt sich der Thread ja zu einer Orgie für GDI+ Optimierungen und was man daraus wirklich rausholen kann (würde mich persönlich freuen, da man den Mythos des langsamen GDI+ damit ausräumen kann)

Grüsse, Egon

07.03.2007 - 07:42 Uhr

Hi,

so ich hab mich mit dem ganzen noch mal etwas gespielt und hab eine erkenntnis erlangt die ich nicht für möglich hielt: GDI+ ist eigentlich gar nicht so langsam wie das vielleicht vielerorts dargestellt wird - natürlich nur wenn man etwas Programmieraufwand nicht scheut.

Das gesamte Problem der schnellen Grafikausgabe reduziert sich im Endeffekt auf genau einen Punkt:

*) Wie schaffe ich es, meine Daten vom Back-Buffer schnell in die Grafikkarte zu bekommen?

Dazu habe ich einige kleine Tests angestellt und habe festgestellt dass es teilweise gravierende Unterschiede in der Kopierdauer gibt wenn man einfach die erstbeste Methode benutzt. In der Grafik im Anhang findet sich eine Auflistung der getesteten Methoden - als Datenblock wurde die Grösse einer Grafik mit der Auflösung 1600x1200x32 benutzt.

Der Quellcode des Testprogramms:


using System;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace ConsoleApplication1
{
    public class Program
    {
        static void Main( string[] args )
        {
            byte[] srcArray = new byte[7680000];      // Size of a Image with 1600x1200x32
            byte[] dstArray = new byte[7680000];      // same

            Stopwatch sw = new Stopwatch();
            sw.Start();

            // Copy with .NET Methods
            sw.Start();
            Array.Copy( srcArray, dstArray, dstArray.Length );
            sw.Stop();
            Console.Out.WriteLine( "COPY-dotnet-1         : {0}", sw.Elapsed.ToString() );

            // Copy with another .NET Method
            sw.Reset();
            sw.Start();
            Buffer.BlockCopy( srcArray, 0, dstArray, 0, dstArray.Length );
            sw.Stop();
            Console.Out.WriteLine( "COPY-dotnet-2         : {0}", sw.Elapsed.ToString() );

            // Copy with Native Method
            sw.Reset();
            sw.Start();
            unsafe
            {
                fixed( byte* ptrSrc = srcArray, ptrDst = dstArray )
                {
                    Win32Native.CopyMemory( ptrSrc, ptrDst, dstArray.Length );
                }
            }
            sw.Stop();
            Console.Out.WriteLine( "COPY-native           : {0}", sw.Elapsed.ToString() );

            // Copy with unsafe code only
            sw.Reset();
            sw.Start();
            unsafe
            {
                fixed( byte* ptrSrc = srcArray, ptrDst = dstArray )
                {
                    for( int index = 0; index < dstArray.Length; index ++ )
                    {
                        *( ptrDst + index ) = *( ptrSrc + index );
                    }
                }
            }
            sw.Stop();
            Console.Out.WriteLine( "COPY-unsafe           : {0}", sw.Elapsed.ToString() );

            // Copy with Serial
            sw.Reset();
            sw.Start();
            unsafe
            {
                fixed( byte* ptrSrc = srcArray, ptrDst = dstArray )
                {
                    byte* to = ptrDst;
                    byte* from = ptrSrc;
                    int count = srcArray.Length;

                    do
                    {
                        *to++ = *from++;
                    } while( --count > 0 );
                }
            }
            sw.Stop();
            Console.Out.WriteLine( "COPY-serial             : {0}", sw.Elapsed.ToString());
        }
    }

    internal class Win32Native
    {
        [DllImport( "kernel32.dll" )]
        unsafe public static extern void CopyMemory( byte* src, byte* dst, int length );
    }
}

Ich kann gleich vorweg sagen, dass sich die Native Kernel Funktion "CopyMemory" und Buffer.BlockCopy ein heisses Rennen liefern, das auf unterschiedlichen Rechnern unterschiedlich schnell ist (aber nur marginal, mal der eine mal der andere schneller).

Zur Zeit ist es mir mit einer Testapplikation schon möglich, schnelle GDI Grafik mit 1600x1200 ohne Ruckler und Flackern darzustellen - das entsprechende Programm liefere ich bald nach, ich möchte es noch fertig machen damit einem nicht alles Hochkommt wenn man sich den Source ansieht.

Grüsse, Egon

05.03.2007 - 19:20 Uhr

Hallo dr4g0n76,

Danke für dein Beispiel. Bei ungefähr der gleichen Performance war ich bei meinen letzten GDI+ Tests zu dem Thema auch angelangt. Ich bin dann allerdings für das ganze auf SDL umgestiegen, weil es doch wesentlich performanter war (ist).

Aber nur aus reinem Interesse werd ich das Thema hier mit GDI noch etwas weiter verfolgen da Du mir jetzt wieder einen gewissen Ansporn gegeben hast 😉

Danke und Grüsse, Egon

01.03.2007 - 11:57 Uhr

Hallo,

mkisofs ist das Tool was du haben möchtest. Zu finden unter:

http://smithii.com/cdrtools

Grüsse, Egon

01.03.2007 - 10:36 Uhr

Hallo,

soweit mir bekannt nein - hab vor einiger Zeit selbst mal nach sowas gesucht aber nichts freies gefunden.

Grüsse, Egon

01.03.2007 - 10:08 Uhr

Hallo,

z.b. http://www.virtualcd-online.com/

Grüsse, Egon

01.03.2007 - 07:49 Uhr

Hallo,

ich war vor einiger Zeit selbst auf der Suche nach einem solchigen, bin aber leider nicht wirklich fündig geworden. Im Endeffekt hab ich mir anschliessend damit beholfen, dass ich mir den vom MonoDevelop GUI Editor (Stetic) erzeugten Code angeschaut habe. In Kombination mit der Mono Dokumentation kann man daraus schon halbwegs gut was lernen.

Grüsse, Egon

27.02.2007 - 22:25 Uhr

Hallo,

bei mir kommt es immer drauf an was ich gerade mache - bei (relativ) simplen Forms erstelle ich die meist direkt im Code, bei komplexeren Forms benutze ich den Designer da man damit (meist) schneller zum Ziel kommt.

Generell glaube ich dass je länger man in einer Sprache (und mit einem Framework) arbeitet immer mehr in Richtung händisch erstellen tendiert. Früher (als ich mit C# und .NET angefangen habe ~ 1,5 Jahre ung.) habe ich absolut alles mit dem Designer erstellt da ich schlicht und ergreifend die Backgrounds nicht gekannt habe. Erst im Lauf der Zeit ist es gekommen dass ich immer mehr ohne Designer machte.

Grüsse, Egon

26.02.2007 - 10:43 Uhr

Verwendung von Resourcen in .NET Assemblies

Vorwort

In diesem Artikel werden wir uns die verwendung von Resourcen unter .NETansehen. Viele benutzen diese schon seit langem indem einfach im Visual Studio die entsprechende Datei eingefügt und "benutzt" wird. Dass hinter all dem aber viel IDE-Magic steckt und im hintergrund schon eine ganze Menge Code erforderlich sein kann damit das so schön funktioniert wird man sehen wenn man diesen Artikel fertig gelesen hat.

Überblick

Resourcen sind in Assemblies (genauer gesagt in den Metadaten) eingebettete Dateien welche zur Laufzeit gelesen und verarbeitet werden können. Diese Daten können für verschiedene Zwecke genutzt werden - dies sind zum beispiel:*Lokalisierung der in der Applikation benutzten, textuellen Informationen (beispielsweise Benutzer Texte) *Grafiken und andere Daten für die Applikation.

Grundsätzlich gibt es zwei verschiedene Typen von Resourcen in Assemblies:*Direkt eingebundene
Eine Datei wird direkt in die Assembly gelinkt und kann benutzt werden.

*Gesammelt in einer ".resources" Datei
Der Zugriff erfolgt über eine spezielle Klasse welche sich auch um die Lokalisierung kümmert.

Grafisch gesehen sieht dies also so aus:


_Abb. 1: Wie können Resourcen in Assemblys gespeichert sein? _

Beiden Arten von Resourcen können beim kompilieren der Applikation angegeben werden. Dies geschieht mit dem Paramter "/resource", welcher als Parameter die entsprechende Datei entgegebennimmt.

Das erstellen von Resource Dateien

Bei direkt eingebundenen Dateien stellt sich die Frage der erstellung per Definition nicht, da diese üblicherweise mit einer externen Applikation wie Bild- oder Tonverarbeitung erstellt werden. Die ".resources" Dateien hingegen können mit verschiedenen, .NET eigenen Bordmitteln erstellt werden:*Das Tool "resgen" *Die Klasse "ResourceWriter" des Frameworks

Beginnen wir mit dem Tool ResGen. Als Parameter nimmt dieses Tool verschiedene Dateien entgegeben, welche die notwendigen Informationen enthalten. Dies sind:*txt
Jede Zeile der Textdatei repräsentiert ein Key/Value Pair welche durch das '=' Zeichen getrennt sind. Das kann zum beispiel dafür benutzt werden um lokalisierungs-spezifische Texte als Resource aufzunehmen.

*resx
Eine XML Darstellung von Resourcen. Mit diesem Format können neben Textuellen Daten auch Binärdaten (wie bsp. Image) als Resource gespeichert werden. Leider ist im .NET SDK kein Tool enthalten mit dem ResX Dateien direkt editiert werden können. Zum Glück ist die Freeware-Szene hier in die Presche gesprungen und Lutz Roeder hat mit dem "Resourcer" ein entsprechendes Tool zur verfügung gestellt.

Zur Verdeutlichung erstellen wir uns die beiden folgenden Dateien:

AppStrings.en-US.txt:


strWelcome = Welcome to our Application
strEnter = Enter your Name

AppStrings.de-DE.txt:


strWelcome = Willkommen in der Applikation
strEnter = Bitte geben Sie Ihren Namen ein

Diese beiden Dateien werden nun mittels ResGen in die entsprechenden "resources" Dateien übersetzt ("resgen AppStrings.de-DE.txt" und "resgen AppStrings.en-US.txt"). Als ergebnis erhalten wir nun die beiden Dateien "AppStrings.de-DE.resources" und "AppStrings.en-US.resources". Diese könnten wir nun schon entweder direkt in unsere Applikation einbetten oder aber auch eine neue DLL erstellen welche ausschliesslich diese Resourcen enthält. Gehen wir aber einen Schritt weiter. Wir wollen jetzt noch zusätzlich zwei Grafiken in die Resources Datei einfügen. Dazu bemühen wir den Resourcer und laden das entsprechende .resources File:


Abb. 2: Der Resourcer mit dem geladenen AppStrings.de-DE.resources File

Um nun auch noch andere Daten einzufügen reicht es im Menü "Edit" den Punk "Insert File" (respektive "Insert Text" für String Resourcen) auszuwählen und die entsprechende Datei einzufügen. Wird der Typ der Datei nativ vom Framework unterstützt, so wird dieser in Serialisierter Form des entsprechenden Objekts gespeichert, anderenfalls als Byte-Array. Nachdem zum beispiel ein Bild und eine unbekannte Datei eingefügt worden sind, sieht dies so aus:


Abb. 3: Eine .resources Datei mit einigen eingefügten Daten.

Es muss erwähnt werden, dass man sich das Tool ResGen und die ResX Dateien komplett ersparen kann, da der Resourcer in der Lage ist Resources Dateien komplett neu zu erstellen und diese in einem Format beliebiger Wahl speichern kann.
*Lokalisierbare Resourcen
Kommen in eigene DLL's, da dies die übersichtlichkeit und einfache Lokalisierung durch Fremdanbieter ermöglicht (Es muss nur die entsprechende DLL weitergegeben werden). Der Grund hierfür ist, dass zusätzliche Sprachen nachträglich einfach eingefügt werden können, ohne dass man die Hauptapplikation neu verteilen muss.

*Nicht-lokalisierbare Resourcen
Sollten in die eigentliche Hauptapplikation eingebettet werden. Darunter fallen z.b. Grafiken welche innerhalb der Applikation benutzt werden oder aber auch textuelle Informationen die nichts mit Benuzter-Interaktion zu tun haben (SQL Statements). Es spricht natürlich nichts dagegen wenn man sich auch für diese Resourcen eine eigene DLL erstellt - ist meiner persönlichen Meinung nach nur eine reine Geschmackssache.

Um eine Resourcen-DLL zu erstellen (die ja nur Resourcen und keinen Programmcode enthält) reicht im Endeffekt der folgende Kompileraufruf:


csc /target:library /out:resources.dll /resource:AppStrings.en-US.resources /resource:AppStrings.de-DE.resources /resource:Images.resources 

Sieht man sich nun diese DLL im ILDasm an, so erkennt man deutlich dass die Resourcen wie oben bereits erwähnt im Manifest gespeichert wurden:


Abb. 4: Resourcen in einer DLL, gespeichert im Manifest

Bei der Einbindung in die Hauptapplikation ist es lediglich notwendig über den Kompilerparameter "/resource:<Dateiname>" anzugeben, welches Resources File in das Manifest aufgenommen werden soll.

Benutzung von Resourcen

Resourcen können wie oben erwähnt mittels direkten Zugriff auf den Stream der Datei, oder aber über den ResourceManager angesprochen werden. Zuerst sehen wir uns an, wie dies mittels des Resource Managers funktioniert - da dieser Lokalisierungseigenschaften bietet ist dieser die Primäre Wahl beim erstellen von lokalisierten Applikationen:


ResourceManager locRm = new ResourceManager( "AppStrings", Assembly.LoadFile( "resources.dll" ));
Console.Out.WriteLine( "strHello = {0}", locRm.GetString( "strHello", new CultureInfo( locale )));

Im Endeffekt beschränkt sich das ganze darauf, dass wir ein Objekt vom Typ ResourceManager instanziieren dem wir als Konstruktor-Parameter folgendes übergeben:
*Den Basisnamen der eingebetteten Resources Datei. Da bei uns die Resources Dateien für die unterschiedlichen Sprachen alle vom Format "AppStrings.<LangCode>.resources" sind, ist dieser Basisname "AppStrings" *Die Assembly in welcher sich die Resourcen befinden

Anschliessend lassen wir uns vom ResourceManager immer jene Strings zurückgeben, welche wir mittels des Parameters "CultureInfo" anfordern. Der Parameter "locale" ist vom Typ "String" und hat als inhalt die entsprechende Lokalität (bsp. en-US oder de-DE ins unserem Fall). Eine komplette Liste der Locales kann im MSDN unter diesem Link nachgeschlagen werden.

Neben der möglichkeit sich Strings aus der Resource zu holen, kann der ResourceManager uns natürlich auch Streams oder andere Objekte zurückgeben. Die entsprechenden Methoden heissen "GetStream" und "GetObject" und haben die gleichen Eingangsparamter wie "GetString".

Kommen wir nun zum lesen einer Resource direkt als Stream. Diese Methode ist nicht so gebräuchlich, wird allerdings trotzdem unterstützt und hat für bestimmte Einsatzzwecke auf jeden Fall Ihre Berechtigung. So ist es sicherlich sinnvoller bei einer relativ grossen Datei welche eingebettet werden soll dies nicht über den ResourceManager zu machen sondern direkt über Streams - der Vorteil liegt in Bezug auf Performance da der ResourceManager einen gewissen Overhead erzeugt.

Ein Assembly Objekt besitzt zwei für uns interessante Methoden:*Stream GetManifestResourceStream( string name )
Liefert einen Stream zurück, mit welchem die Resource gelesen werden kann

  • string[] GetManifestResourceNames()
    Liefert ein String Array zurück, in dem alle Namen aller eingebetteten Top-Level Resourcen vorliegen

IDE-Magic


_Abb. 5: Warum kann in VS so einfach auf den im Resource File "AppResources" enthaltenen String "testString" zugegriffen werden? _

Wie oben bereits erwähnt ist es mit Visual Studio relativ leicht, eigene Resourcen in die Applikation einzubinden und auf diese auch noch relativ unproblematisch zuzugreifen. Wenn man im VS ein neues Resource File (ResX) erstellt, so geschieht folgendes:*Das ResX File wird erstellt und VS bietet einen grafischen Dialog zum bearbeiten von darin enthaltenen Resourcen (wird beim Kompilieren in ein Resources File umgewandelt und gelinkt) *Dem Projekt wird ein neues Quellcode-File hinzugefügt (als Child des ResX Files) welches die notwendige Programmlogik enthält um auf die Elemente dieser Resource direkt zugreifen zu können.

Sehen wir uns einen kleinen ausschnitt aus dem von VS erstellen File an:


/// <summary>
///   Looks up a localized string similar to Hello World.
/// </summary>
internal static string testString {
    get {
        return ResourceManager.GetString("testString", resourceCulture);
    }
}

Wie man erkennen kann macht VS im Endeffekt auch nichts anderes als wir oben und gibt mittels des ResourceManagers die angeforderten Daten an den Aufrufer zurück. Damit ist auch dieses Mysterium von IDE-Magic aufgelöst.

Quellcode


using System;
using System.Reflection;
using System.IO;
using System.Collections;
using System.Resources;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.Serialization.Formatters.Binary;

namespace egrath.test
{
        public class Program
        {
                public static void Main( string[] args )
                {
                        Assembly al = Assembly.GetExecutingAssembly();

                        if( args.Length > 0 )
                        {
                                al = Assembly.LoadFile( args[0] );
                        }

                        ResourceDumper dumper = new ResourceDumper( al );
                        Console.Out.WriteLine( "Dumped {0} files", dumper.DumpResources( String.Empty ));
                }
        }

        internal class ResourceDumper
        {
                private Assembly m_DumpAssembly;

                public ResourceDumper( Assembly al )
                {
                        m_DumpAssembly = al;
                }

                public int DumpResources( string filter )
                {
                        int dumped = 0;

            string outputDir = "dumped";
            if( ! Directory.Exists( outputDir )) Directory.CreateDirectory( outputDir );

                        string[] resourceNames = m_DumpAssembly.GetManifestResourceNames();
                        foreach( string resource in resourceNames )
                        {
                                if( resource.EndsWith( ".resources" )) // It's a embedded Resource file which itself can contain resources
                                {
                                        Console.Out.WriteLine( "examining embedded resource: [{0}]", resource );
                                        ResourceReader resReader = new ResourceReader( m_DumpAssembly.GetManifestResourceStream( resource ));
                                        IDictionaryEnumerator resEnum = resReader.GetEnumerator();
                                        while( resEnum.MoveNext() )
                                        {
                                                string resourceType = String.Empty;
                                                byte[] resourceData;

                                                resReader.GetResourceData(( string ) resEnum.Key, out resourceType, out resourceData );
                        resourceType = resourceType.Split( ',' )[0];
                                                Console.Out.WriteLine( "    dumping resource: name={0}, type={1}", resEnum.Key, resourceType );

                        byte[] fileData = ConvertToFile( resourceType, resourceData );

                        BinaryWriter writer = new BinaryWriter( new StreamWriter( String.Format( "{0}/{1}.{2}", outputDir, resEnum.Key, GetExtensionForType( resourceType ))).BaseStream );                        
                        writer.Write( fileData );
                        writer.BaseStream.Close();
                        writer.Close();

                        dumped ++;
                                        }
                                }
                                else
                                {
                                        Console.Out.WriteLine( "Dumping embedded Resource: [{0}]", resource );
                    BinaryWriter writer = new BinaryWriter( new StreamWriter( String.Format( "{0}/{1}", outputDir, resource )).BaseStream );

                    Stream resourceStream = m_DumpAssembly.GetManifestResourceStream( resource );
                    int byteCode = -1;
                    while(( byteCode = resourceStream.ReadByte() ) != -1 )
                    {
                        writer.Write(( byte ) byteCode );
                    }
                    writer.BaseStream.Close();
                    writer.Close();

                    dumped ++;
                                }
                        }

                        return dumped;
                }

        private string GetExtensionForType( string type )
        {
            switch( type )
            {
                case "System.Drawing.Bitmap": return "bmp";
                case "System.Drawing.Icon": return "ico";
                case "ResourceTypeCode.String": return "txt";
                default: return "unknown";
            }
        }

        private byte[] ConvertToFile( string resourceType, byte[] resourceData )
        {
            byte[] fileData;
            BinaryFormatter formatter = null;

            switch( resourceType )
            {
                case "System.Drawing.Bitmap":
                    formatter = new BinaryFormatter();
                    Image img = ( Image ) formatter.Deserialize( new MemoryStream( resourceData ));
                    MemoryStream imageStream = new MemoryStream();
                    img.Save( imageStream, ImageFormat.Bmp );
                    fileData = imageStream.ToArray();
                    break;

                case "System.Drawing.Icon":
                    formatter = new BinaryFormatter();
                    Icon ico = ( Icon ) formatter.Deserialize( new MemoryStream( resourceData ));
                    MemoryStream iconStream = new MemoryStream();
                    ico.Save( iconStream );
                    fileData = iconStream.ToArray();
                    break;

                default:
                    fileData = new byte[resourceData.Length];
                    Array.Copy( resourceData, fileData, resourceData.Length );
                    break;
            }

            return fileData;
        }
        }
}