BigBastis Blog About Me & my Digital Lifestyle

15Mrz/130

Clover: Tabs für den Windows Explorer

clover_screenshot

Ich glaube schon seit Windows 98 habe ich mich gefragt, warum Microsoft dem Windows Explorer keine Tabs spendiert. Auch Apple bekommt es unter Mac OS nicht hin den Finder Tab-Fähig zu machen. Warum eigentlich nicht?

Clover zeigt wie es gehen könnte. Dieses einfache kleine Tool kombiniert alle Windows Explorer Fenster unter einem Dach und lässt sich dabei so flüssig bedienen, dass es schon fast wie eine native Lösung wirkt.

Auf den ersten Blick fällt sofort auf, dass hier einige Teile vom Google Chrome eingeflossen sind. So gleicht das Look and Feel der Tabs und auch deren Bedienung bis ins Detail dem von Chrome. Alles ist super Flüssig und funktioniert komplett ohne Konfiguration sofort so wie man es gewohnt ist.

So lassen sich neue Tabs mit STRG+T öffnen und mit STRG+TAB durchschalten. Mit einem Doppelklick während man die STRG-Taste gedrückt hält wird der gewählte Ordner in einem neuen Tab geöffnet. Die Tabs selbst integrieren sich in die Titelleiste des Fensters und verbrauchen so gut wie keinen Platz.

Optional kann man auch noch (wie auch im Chrome) eine Lesezeichenleiste einblenden lassen, in der man seine Lieblingsordner speichern kann. Ich finde aber, dass es die Optik etwas stört.

Das Icon des Programms könnt ihr ebenfalls verändern, wenn euch das Kleeblatt nicht zusagt. Eine Anleitung dafür gibts auf der Homepage des Entwicklers.

Weitere Infos und Download.

2Mai/124

Office oder Windows Lizenzschluessel aus einer anderen Windows Installation wiederherstellen

Die Beiträge hier im Blog darüber wie man den Office und Windows Key aus der Registry lesen kann erfreuen sich sich großer Beliebtheit, weswegen ich auch das kleine Tool Get My Keys Back erstellt habe.

Doch erreichen mich immer mehr Mails mit der Frage danach wie man den Schlüssel wiederherstellen kann wenn man Windows neuinstalliert hat, wenn die Installation beschädigt ist oder wenn die Daten auf einer anderen Festplatte liegen.

Manchmal passiert es auch, dass Get My Keys Back es nicht schafft den Office Key auszulesen, obwohl Office installiert ist. Mit dieser Anleitung könnt ihr es nun manuell machen.

Get My Keys Back funktioniert hier natürlich nicht, da es nur in der gerade aktiven Registry nach dem Schlüssel sucht. Ich habe mich mit dieser Frage etwas beschäftigt und hoffe euch mit diesem Beitrag eine Hilfestellung geben zu können.

SerialDecoder

Um es euch möglichst einfach zu machen habe ich das kleine Tool "SerialDecoder" geschrieben, das ihr ab sofort auf meiner Homepage herunterladen und testen könnt. Dieses Programm benötigt aber auch die Werte aus der Registry, und zwar aus der Registry die nicht mehr aktiv ist, z.B. die auf eurer anderen Festplatte von der ihr die Seriennummer haben wollt.

Der Prozess den Schlüssel zu beschaffen unterteilt sich in drei Schritte:

  1. Beschaffen der Registrydaten von der alten Festplatte
  2. Beschaffen der Daten aus der alten Registry
  3. Umwandeln der Daten in den schlüssel
Schritt 1

An euch liegt es nun diese Daten aus der anderen Festplatte zu lesen. Dies ist relativ einfach, folgt einfach dieser kleinen Anleitung:

  1. Schließt die alte Festplatte an und öffnet diese im Windows Explorer
  2. Navigiert dort in das Verzeichnis: \Windows\System32\config
  3. Kopiert aus diesem Verzeichnis die Datei "SOFTWARE" in ein Verzeichnis auf eurer aktiven Festplatte.

    Die gesuchte Datei

  4. Startet nun die Registry, indem ihr die Windows-Taste und die R-Taste gleichzeitig drückt.

    Windows-Taste + R drücken

  5. In das nun erscheinende Fenster tippt ihr "regedit" ohne "" und drückt auf OK.
  6. Im Regestrierungseditor klickt ihr auf Datei und dann auf Struktur laden... (Tipp: Struktur laden ist nur anklickbar, wenn ihr den passenden Knoten (HKEY_LOCAL_MACHINE) auswählt)

    Struktur laden

  7.  Wählt nun die eben kopierte Datei "SOFTWARE" aus.

    Datei laden

  8. Gebt nun einen schlüssigen Namen ein z.B. "Alte Festplatte"
  9. Nun wird diese Registry Datei geladen und ihr seht sie in eurem Registry-Explorer. Öffnet diese nun.

Schritt 2: Auslesen der Schlüssel

Navigiert in der nun geladenen Struktur an folgende Stellen um die Keys zu erhalten:

Office auf 32-Bit Systemen:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office

Office auf 64-Bit Systemen:

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Office

Bei Office wählt ihr nun eure Version, wobei

  • 11 = 2003
  • 12 = 2007
  • 14 = 2010
  • 15 = 2013

Im Normalfall solltet ihr einfach die größte Zahl auswählen. In diesem Verzeichnis wählt ihr nun den Ordner Registration. Hier werden wahrscheinlich einige Ordner mit sehr kryptischen Namen sein, sucht den wo der Schlüssel namens "DigitalProductId" auftaucht:

Probiert die Ordner einfach durch, der richtige Ordner ist meist der mit den meisten Schlüsseln.

Klickt nun mit der rechten Maustaste auf den passenden Ordner und wählt "Exportieren". Speichert die Datei nun ab.

(Falls ihr nur diesen Key benötigt springt zum Schritt 3 Schlüssel umwandeln weiter unten)

Windows Key:

SOFTWARE\Microsoft\Windows NT\CurrentVersion

Hier seht ihr nun einige Schlüssel, unter Anderem auch den DigitalProductId, der uns interessiert (Beispiel für Windows Key).

Klickt nun mir der rechten Maustaste auf den Ordner "CurrentVersion" in der rechten Übersicht und wählt "Exportieren" und speichert die Daten an einem für euch leicht wieder findbaren Ort.

Schritt 3: Schlüssel umwandeln

Da ihr nun die Daten zum Windows und/oder zum Office Key gesichert habt könnt ihr diese nun nutzen um den Key wiederherzustellen.

Nun müsst ihr mein kleines Tool namens "SerialDecoder" von meiner Homepage laden und starten.

Öffnet nun eine der Dateien die ihr eben durch das Exportieren erstellt habt in einem Texteditor:
Sucht den Eintrag namens "DigitalProductId" und markiert alle Zeichen ab hex: bis zum Ende des Eintrags. Ein Beispiel wie es aussehen kann seht ihr in dem Oberen Bild. Wichtig: Markiert wirklich nur diesen Bereich ohne das hex: und ohne den Eigenschaften-Namen, wirklich genauso wie es oben in dem Bild gezeigt ist.

Das Bild zeigt ein Beispiel für einen Windows Key, die Office-Keys sind für gewöhnlich länger, lasst euch davon also nicht verwirren.

Kopiert diesen Markierten Text nun in die Zwischenablage und fügt diesen Text nun im SerialDecoder ein:

Nicht erschrecken: Der SerialDecoder entfernt alle unnötigen Zeichen wie Leerzeichen und Zeilenumbrüche.

Klickt nun auf "Schlüssel auslesen" unten im Fenster und wählt die Art von Schlüssel die ihr auslesen wollt. (Hier Windows Key)

Der SerialDecoder wandelt nun die Daten in euren Key um.

ACHTUNG: SerialDecoder kann nicht feststellen ob ihr die Daten korrekt eingefügt habt, also ob ihr vielleicht zuviel kopiert habt oder zu wenig. Deswegen achtet sehr genau was ihr reinkopiert! Des Weiteren kann ich natürlich nicht für die Korrektheit des ausgelesenen Keys garantieren. Das Programm ist grad in der Testphase und lebt momentan von eurem Feedback, damit ich es weiter verbessern kann.

20Jun/113

Get My Keys Back 2 ist nun endlich fertig

Vor ungefähr 1 1/2 Jahren habe ich ein kleines Tool namens Get My Keys Back auf meiner Homepage veröffentlich. Die Aufgabe dieses Tools ist recht simpel, es beschafft die Schlüssel zu den installierten Windows und Office Produkten.

Das Tool war sehr erfolgreich wie ich finde, innerhalb von wenigen Monaten wurde es bereits einige tausend Mal heruntergeladen. Nach etwa 6 Monaten habe ich dann einen Downloadzähler vorgeschaltet und der zeigt nun auch schon 6560 Downloads an, also wurde das Programm in seiner Laufbahn sage ich mal rund 10.000 Mal heruntergeladen - das ist ein toller Wert!

Seit einigen monaten bekomme ich aber auch Mails von Nutzern, die sich beschweren, dass ihre Schlüssel nicht ausgelesen werden. Diese Berichte haben sich langsam gehäuft, sodass ich schon seit einiger Zeit vorhatte ein Update herauszubringen.

Die nötigen Daten für das Update (Erfolgs- und Fehlerberichte von Usern) habe ich in Zusammenarbeit mit dem Forum office-loesung.de erarbeitet. An dieser Stelle ein Danke für euer Feedback!

Die Testphase für die Version 2 von Get My Keys Back läuft nun schon ca 2 Monate und das Feedback war durchweg positiv, sodass ich mir nun sicher genug bin es auf die Öffentlichkeit loszulassen :)

Äußerlich hat sich aber nichts geändert (Dazu fehlte mir dann doch die Zeit, vielleicht kommt das noch mit einem weiteren Update), aber innen hat sich viel getan:

  • Der Erkennungs Algorithmus wurde komplett neugeschrieben
  • Einige Bugs wurden entfernt
  • 64 Bit Systeme werden nun voll unterstützt
  • Keine automatischen Updateprüfungen mehr

Besonders der letzte Punkt war vielen Usern sehr wichtig, und im Nachhinein finde ich es auch etwas blöd von mir es überhaupt so geregelt zu haben, dass ein Tool, welches Schlüssel ausließt eine Internetverbindung aufbaut - ich wäre auch misstrauisch geworden ;) - Aber das ist wie gesagt nun kein Problem mehr.

Ich hoffe GMKB2 wird an den Erfolg von Version 1 anknüpfen und euch eure Schlüssel alle wiederbesorgen :)

Hier gehts zum Download

29Nov/103

Jede Adventswoche ein Microsoft Press E-Book gratis

Wie auch letztes Jahr verschenkt Microsoft Press auch dieses Jahr wieder E-Books. Dabei gibt es jede Adventswoche ein neues E-Book, dass kostenlos heruntergeladen werden kann.

Den Anfang macht heute das Windows 7 Home Premium "Maxibuch", das ca 1000 Seiten umfasst.

Microsoft Windows 7 wird mit "Microsoft Windows 7 Home Premium - Das MAXIBUCH" erst richtig schön. Damit Sie die vielen Möglichkeiten entdecken und verstehen, hat sich das Autorenteam lange mit Windows 7 Home Premium auseinandergesetzt.
Sie erhalten von uns kostenlos eine gelungene und sehr ausführliche Windows 7-Beschreibung!
Wissen aus erster Hand auf über 1.000 Seiten! (PDF, 80.2 MB)
Rechnen Sie unbedingt auch mit Tipps, wie Sie schneller, einfacher und sicherer arbeiten - und Spaß bekommen.

Wer Interesse hat muss lediglich seine E-Mail Adresse auf der Aktionsseite eintragen und bekommt einen Download-link zugeschickt.

Nachtrag:

Anscheinend sind momentan die Server ziemlich ausgelastet:

Entschuldigung.
Unser Downloadserver ist überlastet.
Bitte Versuchen Sie es in wenigen Minuten noch einmal.
Vielen Dank für Ihre Verständnis.

Aber zum Glück hat man die Ganze Woche Zeit um es herunterzuladen. :-)

kick it on dotnet-kicks.de

20Jul/102

Windows Aero Glas in eigenen Projekten Nutzen Teil 5 – Der letzte Versuch

In den letzten Tagen habe ich mal wieder ein wenig mit der Windows API herumgespielt, speziell mit der Aero Glas API (DWMAPI). Ich habe euch ja auch noch versprochen einen Beitrag über Steuerelemente in Verbindung mit Glas nachzuliefern. Nunja hier ist er :)

Bild 1: Probleme mit der Transparenz

In Bild 1 sehen wir das Problem, viele der Windows Forms Steuerelemente nutzen GDI zur Darstellung und haben deswegen keinen Alpha-Kanal, der aber für die Darstellung auf Glas benötigt wird. Deswegen nutzen wir die Schwarze Farbe um unsere Fläche in Glas zu verwandeln, leider denkt der DWM dann, dass auch die Texte auf unseren Steuerelementen zu Glas werden sollen.

Ich habe mich nun ein wenig im Internet umgehört und verschiedene Ansätze gefunden und diverse Hacks mit der Windows32API Ausprobiert, die aber alle leider nicht mehr funktionieren. So will ich euch heute zwei Möglichkeiten vorstellen wie man es doch hinkriegen könnte.

1. Owner Drawing

Da die Steuerelemente mit GDI gerendert werden haben wir ein kleines Problem wie man oben sieht. Also müssen wir die Darstellung der Steuerelemente selbst in die Hand nehmen. Dieser Vorgang nennt sich OwnerDrawing und bedeutet soviel wie "SelberZeichnen". Ich will das Ganze mal anhand einer Textbox demonstrieren.

Und genauso ist auch das Vorgehen. Wir erstellen eine neue Klasse und nennen Sie "AeroTextBox". Diese Klasse erbt nun von der Original TextBox. Nun müssen wir ein paar kleine Änderungen an der Klasse vornehmen in Bezug auf die Darstellung, also des WM_PAINT Ereignisses.

Da wir das Zeichnen des Steuerelements selbst in die Hand nehmen wollen müssen wir die WM_PAINT Message abfangen und auf unsere eigene Methode umleiten:

C#


    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        base.WndProc( ref m);

        switch (m.Msg)
        {
            case 0xf: //WM_PAINT
                RedrawControlAsBitmap(this.Handle);
                break;
        }
    }

VB.NET


 Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
	MyBase.WndProc(m)

	Select Case m.Msg
		Case &Hf 'WM_PAINT
			RedrawControlAsBitmap(Me.Handle)
			Exit Select
	End Select
End Sub

Wie man sieht fangen wir hier die Message ab und rufen unsere eigene Methode auf, die das Zeichnen übernehmen wird:

C#


    public void RedrawControlAsBitmap(IntPtr hwnd)
    {
        Control c = Control.FromHandle(hwnd);
        using (Bitmap bm = new Bitmap(c.Width, c.Height))
        {
            c.DrawToBitmap(bm, c.ClientRectangle);
            using (Graphics g = c.CreateGraphics())
            {
                g.DrawImage(bm, new Point(-1, -1));
            }
        }
        c = null;
    }

VB.NET


Public Sub RedrawControlAsBitmap(hwnd As IntPtr)
	Dim c As Control = Control.FromHandle(hwnd)

	Using bm As New Bitmap(c.Width, c.Height)
		c.DrawToBitmap(bm, c.ClientRectangle)

		Using g As Graphics = c.CreateGraphics()
			g.DrawImage(bm, New Point(-1, -1))
		End Using
	End Using
	c = Nothing
End Sub

Was hier passiert ist eigentlich sehr simpel, wir zeichnen das Control neu und legen das gezeichnete Bild nun über das Control drüber. Nur diesmal machen wir das ganze mit einem Alpha Kanal, sodass der DWM uns die Darstellung nicht versaut!

Nun bleibt noch ein kleines Problem, nämlich dass bei manchen Aktionen des Benutzers wie zB. bei MouseOver oder KeyPress Events das Steuerelement neugezeichnet wird und unsere Funktion da oben nicht greift. Hier müssen wir manuell dafür sorgen, dass Windows erneut die WM_PAINT Message versendet. Das erreichen wir indem wir die einzelnen Events überschreiben und die Invalidate()-Methode aufrufen. Diese Methode erklärt die ganze Oberfläche des Steuerelements für ungültig und bewirkt, dass das Steuerelement neu gezeichnet wird.

C#


    protected override void OnMouseClick(System.Windows.Forms.MouseEventArgs e)
    {
        base.OnMouseClick(e);
        Invalidate();
    }

    protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e)
    {
        base.OnMouseMove(e);
        Invalidate();
    }

    protected override void OnTextChanged(System.EventArgs e)
    {
        base.OnTextChanged(e);
        Invalidate();
    }

    protected override void OnMouseEnter(System.EventArgs e)
    {
        base.OnMouseEnter(e);
        Invalidate();
    }

VB.NET


Protected Overrides Sub OnMouseClick(e As System.Windows.Forms.MouseEventArgs)
	MyBase.OnMouseClick(e)
	Invalidate()
End Sub

Protected Overrides Sub OnMouseMove(e As System.Windows.Forms.MouseEventArgs)
	MyBase.OnMouseMove(e)
	Invalidate()
End Sub

Protected Overrides Sub OnTextChanged(e As System.EventArgs)
	MyBase.OnTextChanged(e)
	Invalidate()
End Sub

Protected Overrides Sub OnMouseEnter(e As System.EventArgs)
	MyBase.OnMouseEnter(e)
	Invalidate()
End Sub

Nun wird das Control richtig dargestellt. Wie ihr vielleicht auch gesehen habt haben wir in unserer Methode, die für das Neuzeichnen verantwortlich ist nicht TextBox sondern die Superklasse Control benutzt. Das bedeutet für uns, dass wir mit diesem Code jedes Steuerelement ableiten und auf diese Weise neuzeichnen können mit mehr oder weniger viel Erfolg. Ich habe mal ein paar Klassen abgeleitet und für euch auf dem Glass-Form platziert:

Bild 2: Die OwnerDrawn Steuerelemente

Wie man sieht ist das schon eine sehr vielversprechende Verbesserung der Darstellung, wenn auch nicht perfekt. Aber natürlich steht es euch noch frei die Darstellung weiter zu verbessern und auf die einzelnen Steuerelemente anzupassen.

Nachdem ihr die selbst erstellten Klassen die von den einzelnen Steuerelementen erben einmal kompiliert habt, wird Visual Studio dies bemerken und euch diese neuen Steuerelemente zusammen mit den anderen in der Toolbox anbieten. Diese können dann wie gewohnt per Drag & Drop auf das Formular gezogen werden.

Bild 3: Bequemer Gehts nicht

Wie ihr euch vorstellen könnt ist es ein ziemlicher Aufwand jedes Steuerelement noch mal neu anzulegen und dessen komplette Darstellung zu übernehmen. Es ist wirklich sehr frickelig! Deswegen wird dieser Ansatz auch eher selten verwendet! Die Demo dazu könnt ihr euch übrigens am Ende des Artikels herunterladen.

Variante 2. "The Microsoft Way"

Natürlich stolpert man irgendwann bei der Recherche über das Windows API SDK in dem es einige Beispiele dazu gibt wie man die neuen Funktionen in Windows benutzt, darunter natürlich auch Glas.

Der Ansatz den Microsoft da aber nach ihrer eigenen Best Practise verwendet ist aber eher ernüchternd. Hier geht es nach dem Motto, platziert einfach keine Steuerelemente auf dem Glas! - Super nicht?

In dem einzigen Beispiel das Microsoft da aufführt wird eine Form gezeigt, dessen Rahmen in das Formular bis zum darauf liegendem Panel erweitert wurde, nicht wirklich spannend. Aber wenn ich so überlege, fällt mit spontan auch kein Windows Programm auf, bei dem irgendwelche Steuerelemente auf dem Glas liegen - kennt ihr welche? In dem meisten Programmen liegen fast nur Grafiken auf dem Glas oder so ähnliche Controls wie die im Windows Explorer.

Also sage ich es mal Microsofts Worten: lasst die Controls vom Glas weg oder benutzt WPF! ;-)

Hier noch die Demo zu der Variante 1: Download [VS 2008 Projekt]

Zur zweiten Variante habe ich keine Demo gemacht, ihr könnt euch ja das Windows API SDK herunterladen und dort im Aero Ordner nachgucken.

<< Teil 4 des Tutorials

13Jul/101

Windows Aero Glas in eigenen Projekten Nutzen Teil 4 – Formulare ohne Border

Dieses Thema hatten wir hier schon oft, und trotzdem gibt es immer noch was neues zu berichten. Windows Forms Fenster stellen sich ganz schön an wenn es darum geht ihre Steuerelemente und sich selbst richtig darzustellen, zu den Steuerelementen wird bald ein Teil 5 (und hoffentlich der letzte) kommen, hier geht es jetzt erst einmal um das (Boderlose) Formular an sich.

Wenn ihr nämlich mal versucht habt ein Windows Form Formular ohne Border (FormBorderStyle=None) mit der mit Glas-Optik zu nutzen habt ihr wohl innerhalb kürzester Zeit feststellen müssen, dass es nicht geht. Warum ist das so?

Nun, ich denke die meisten von euch benutzen die Win32API Funktion DwmExtendFrameIntoClient um das Fenster in eine Glasscheibe zu verwandeln - was auch vollkommen richtig ist, nur wenn man sich den Namen der Funktion durchließt wird man feststellen, dass deren Aufgabe es ist das Frame (den Rahmen) auf das Formular zu erweitern, was auch super funktioniert, solange man einen Rahmen hat. Stellt man nun aber die Eigenschaft FormBorderStyle auf None, hat die Form keinen Rahmen mehr und dementsprechend kann man diesen auch nicht in die Form erweitern.

Was nun? Es muss doch irgendwie gehen!

Natürlich geht das, dazu müssen wir nur eine andere DWM Funktion aus der Win32API Verwenden, nämlich DwmEnableBlurBehindWindow. Diese Funktion macht genau das selbe, nämlich einen definierten Bereich des Formulars in Glas verwandeln.

Aber diese Funktion bietet noch mehr Spielereien, so kann man auch geometrische Figuren in Glas verwandeln oder nur bestimmte Teile einer Form verglasen. Siehe folgende Bilder:

Bild 1: Ein Paar der Möglichkeiten das Glas zu verteilen. (Natürlich kann man den FormBorderStyle auch auf None stellen, dann würde einfach nur der Rahmen fehlen)

Dazu benötigen wir folgenden Code. 1: Das Befüllen des Fensterinhalts mit Glas:


        //Import der nötigen Funktion aus der DLL
        [System.Runtime.InteropServices.DllImport("dwmapi")]
        private static extern int DwmEnableBlurBehindWindow(
                    System.IntPtr hWnd, ref DWM_BLURBEHIND pBlurBehind);

        //Funktion um ein Rechtek auf dem Formular zu malen
        [System.Runtime.InteropServices.DllImport("gdi32.dll")]
        static extern IntPtr CreateRectRgn(int x1, int y1, int x2, int y2);

Wie ihr sehen könnt, ist der Letzte Parameter vom Typ DWM_BLURBEHIND - dies ist ein Struct, welches wir nun erstmal anlegen müssen. (Auf die zweite Funktion komme ich gleich zu sprechen)


        public struct DWM_BLURBEHIND
        {
            public int dwFlags;
            public bool fEnable;
            public System.IntPtr hRgnBlur;//HRGN
            public bool fTransitionOnMaximized;
        }

Nun müssen wir nur noch das Struct anlegen, mit Parametern füllen und der Funktion übergeben:


        private void Form1_Load(object sender, EventArgs e)
        {
            //Das Rechteck vorbereiten, dieses soll so groß sein
            //wie die Fläche die mit Glas befüllt werde soll
            //in diesem Fall soll es die gesamte Form füllen
            hr = CreateRectRgn(0, 0, this.Width, this.Height); 

            //Anlegen des Scructs
            DWM_BLURBEHIND dbb;
            dbb.fEnable = true;
            dbb.dwFlags = 1 | 2;    //Konstanten mehr in der API
            dbb.hRgnBlur = hr;
            dbb.fTransitionOnMaximized = true;

            //Aufruf der Funktion
            DwmEnableBlurBehindWindow(this.Handle, ref dbb);
        }

Zum Schluss sollte man noch dafür sorgen, dass die Form schwarz bemalt wird, damit wir das Glas überhaupt zu Gesicht bekommen. Hierfür überschreiben wir einfach die OnPaintBackground Methode der Form:


        protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e)
        {
            e.Graphics.FillRectangle(
              new System.Drawing.SolidBrush(System.Drawing.Color.Black),
              this.ClientRectangle);
        }

Das war es auch schon, gar nicht mal so komplex finde ich. Wenn ihr das Rechte Bild aus Bild 1 erzeugen wollt geht ihr genauso vor nur benutzt ihr eine andere Funktion im die Fläche für das Glas anzugeben:


        [System.Runtime.InteropServices.DllImport("gdi32")]
        private static extern System.IntPtr CreateEllipticRgn(
          int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);

Mit dieser Funktion lassen sich Elliptische Figuren malen, um diese zu verwenden einfach die Zuweisungs Zeile ersetzen:


            hr = CreateEllipticRgn(30, 30, 170, 170);

Natürlich kann man auch den Border deaktivieren, um einfach nur die reine Clientoberfläche des Formulars zu bekommen:

Bild 2: Sieht nicht allzu spannend aus

Wie man sieht haben wir nun das was wir wollten, nur hebt das Fenster sich kaum vom Hintergrund ab, obwohl es aktiv ist. Leider können wir dem Formular keinen so schönen Schatten geben wie man es von Windows Vista/7 gewohnt ist, da es keinen Rahmen hat. Wenn man das Formular dennoch etwas hervorheben will, kann man das machen in dem man eine Grafik mit einem Transparentem Verlauf auf der Form platziert und somit den Schatten emuliert, oder man benutzt einen kleinen Trick und weist dem Formular den Schatten der Windows Menüs zu:


        private const int CS_DROPSHADOW = 0x00020000;

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams p = base.CreateParams;
                p.ClassStyle |= CS_DROPSHADOW;
                return p;
            }
        }

Hier überschreiben wir die CreateParams und sagen, dass das Formular einen Schatten werfen soll. Das ganze sieht dann so aus:

Bild 3: Der Schatten hebt das Fenster etwas vom Hintergrund ab

Diesen Schatten sollte man aber mit Vorsicht genießen, denn das ist der Schatten der Windows Menüs. (Der kommt wenn ihr zB. in irgendeinem Programm auf "Datei" klickt, das erscheinende Menü wird diesen Schatten haben.) Diesen kann man in den Einstellungen deaktivieren, also bitte achten dass der folgende Haken gesetzt ist:

Bild 4: Aktivieren der Menüschatten

Soviel dazu, ich hoffe dieser Artikel hat euch gefallen oder konnte euch weiter helfen, wie oben erwähnt werde ich in den nächsten Tagen einen 5en Teil schreiben, in dem es darum geht wie man GDI+ Steuerelemente möglichst gut auf Glas darstellen kann.

Wie gewohnt gibt es hier das Demoprojekt:

Quellen:
Blog von Kenny Kerr
The Code Project

<< Teil 3 des Tutorials | Teil 5 des Tutorials >>

8Jul/102

Microsoft SQL Server Compact Edition – Eine Einfuehrung

Oft müssen Clientprogramme große Datenmangen speichern, und in den meisten Fällen wird dazu eine Datenbank eingesetzt. Wenn man eine Internetverbindung voraussetzt kann man einen mächtigen Datenbank Server anbinden und die Daten in der Cloud sichern. Doch oft ist eine Offline Lösung viel einfacher und effektiver.

Inzwischen gibt es auch viele verschiedene lokale Datenbanksysteme wie zB. SQLite, DB4O oder auch MS SQL Server Compact Edition. Alle diese Serversysteme haben auch den Vorteil, dass diese auf den mobilen Systemen problemlos eingesetzt werden können, haben aber auch den Nachteil, dass sie meist nicht den Vollen Feature Umfang eines echten SQL Servers bieten können.

Vorbereitung

In diesem Artikel soll es um den SQL Server Compact Edition von Microsoft gehen, diesen wollte ich schon immer mal testen und nun hatte ich mal die Zeit dazu.

Sofern ihr es noch nicht habt könnt ihr den SQL CE Server kostenlos bei Microsoft herunterladen. Nach der Installation arbeiten wir wie gewohnt im Visual Studio.

Implementierung

Die ganze Implementierung der Datenbank, Erzeugung der Tabellen sowie die Anbindung erfolgt aus Visual Studio heraus. Die Funktionen die man dort hat sind aber auch  stark von dem Provider abhängig, so bieten verschiedene Provider mehr oder weniger Funktionalität.

Um eine Datenbank zu einem Projekt hinzuzufügen öffnet einfach den Projektmappen-Explorer (Ansicht->Projektmappen-Explorer) und Klickt mit der rechten Maustaste auf euer Projekt und dann auf "Hinzufügen"->"Komponente..." und wählt eine Lokale Datenbank aus. In dem Datenbank Assistent Fenster klickt nun 2 Mal auf "Zurück" um auf die erste Seite des Assistenten zu gelangen.

Klickt nun auf "Neue Verbindung". In dem folgendem Fenster sollte man darauf achten, dass als Datenquelle "Microsoft SQL Server Compact 3.5" ausgewählt ist.

Bild 1: Datenbank Konfiguration

Klickt nun auf "Erstellen..." nun solltet ihr das Fenster aus Bild 1 sehen. Wählt oben den Speicherort eurer Datenbank und legt wenn nötig ein Passwort fest um die Datenbank zu verschlüsseln. Bestätigt das Ganze noch zwei Mal mit OK. Visual Studio sollte euch dann darauf hinweisen, dass ihr vorhabt eine Lokale Datenbank zu verwenden und schlägt euch vor diese in euer Projekt zu importieren - das nehmen wir gerne an.

Visual Studio fügt die neu erzeugte Datenbank Datei dem Projekt hinzu und setzt auch die nötigen Verweise auf System.Data und auf System.Data.SqlServerCe.

Anlegen der Tabellen

Beim Anlegen der Tabellen in unserer Datenbank ist uns Visual Studio natürlich ebenfalls sehr behilflich. Öffnet einfach den Server-Explorer (Ansicht->Server-Explorer) und erweitert eure frisch angelegte Datenbank. (Eventuell müsst ihr auch ein Passwort angeben wenn ihr die Datenbank verschlüsselt habt)

Klickt nun mit der rechten Maustaste auf Tabellen und wählt "Tabelle erstellen" um den Tabellen Assistenten zu starten.

Bild 2: Tabellen Assistent

Hier könnt ihr eure Tabelle anlegen und konfigurieren. Wenn ihr die nun fertige Tabelle im Server-Explorer rechts anklickt und dann "Tabelleneigenschaften" wählt bekommt ihr noch mehr Konfigurationsmöglichkeiten wie etwa Beziehungen.

Bereits beim Erstellen der Tabellen ist es euch vielleicht schon aufgefallen, dass es nicht so viele Datentypen zur Auswahl gibt wie in einem richtigen SQL Server aber das sind nicht die einzigen Einschränkungen...

Arbeiten mit der Datenbank

Das Arbeiten mit der Datenbank gestaltet sich nicht anders als mit anderen Datenbanken. Die Objekte die man dafür benötigt heißen sogar fast gleich. Alle Klasse die man nutzt haben noch den Zusatz "Ce", also statt "SqlCommand" heißt es nun "SqlCeCommand".

Und auch die Nutzung unterscheidet sich nur geringfügig:

Datenbank Verbindung herstellen:


        private SqlCeConnection con;
        private string dbLocation = Environment.CurrentDirectory + "\\clipboard.sdf";
        private string conString;

        private void connectDB(){
            conString = "Data Source=\"" + dbLocation + "\"; Password=\"bigbasti.com\"; Encrypt=True";
            con = new SqlCeConnection(conString);
            con.Open();
        }

Eine Select Abfrage durchführen:


        ///
        /// Führt einen Select Befehl auf der Datenbank aus und gibt das ergebnis in einer DataTable zurück
        ///
        ///Der auszuführende Befehl
        /// Return: Ein DataTable mit den ausgelesenen Daten
        public DataTable executeSelect(string query) {
            connectDB();
            DataTable dt = new DataTable();
            SqlCeCommand com = new SqlCeCommand(query, con);
            SqlCeDataAdapter sad = new SqlCeDataAdapter(com);

            sad.Fill(dt);
            con.Close();
            return dt;
        }

        public int checkDouble(string link, string date) {
            int retVal;
            using (SqlCeConnection con = new SqlCeConnection(conString)) {
                con.Open();

                //Doppelte Einträge verhindern
                DataTable dt = executeSelect("SELECT * FROM cp_link WHERE link LIKE '" + link + "'");
                if (dt.Rows.Count > 0) {
                    executeNonQuery("DELETE FROM cp_link WHERE link LIKE '" + link + "'");
                }
            }
            return retVal;
        }

UPDATE, DELETE und INSERT:


        ///
        /// Executes an SQL statement against the SqlCeConnection and returns
        /// the number of rows affected.You also can use ExecuteNonQuery to
        /// change the data in a database without using a DataSet by executing
        /// UPDATE, INSERT, or DELETE statements.
        ///
        ///Der Befehl der ausgeführt werden soll
        /// The number of rows affected.
        public int executeNonQuery(string q) {
            int retVal;
            using (SqlCeConnection con = new SqlCeConnection(conString)) {
                con.Open();
                using (SqlCeCommand com = new SqlCeCommand(q, con)) {
                    retVal = com.ExecuteNonQuery();
                }
            }
            return retVal;
        }
        public int doSomeInsert(string link, string date) {
            int retVal;
            using (SqlCeConnection con = new SqlCeConnection(conString)) {
                con.Open();
                using (SqlCeCommand com = new SqlCeCommand("INSERT INTO cp_link  (link, date) VALUES (@link, @date )", con)) {
                    com.Parameters.AddWithValue("@link", link);
                    com.Parameters.AddWithValue("@date", date);
                    retVal = com.ExecuteNonQuery();
                }
            }
            return retVal;
        }


Hier gibts eigentlich nichts besonderes. Leider hat man hier, da es eine Compact Edition ist nicht so viele Befehle zur Verfügung wie im Original. So fehlt zB. auch der TRUNCAT Befehl wie ich erstaunt feststellen musste. Ich habe da nicht noch weiter recherchiert was noch alles fehlt, da ich für das was ich gemacht habe keine besonderen Aktionen benötigte.

Deployment

Wenn ihr das Projekt über ein Setup-Projekt deployen wollt dann sollte da eigentlich nichts schief gehen. Ihr könnt aber natürlich auch ohne ein extra Setup-Projekt deployen, dazu solltet ihr folgende Schritte machen:

  1. Öffnet die Eigenschaften eures Projekts
  2. Öffnet dort den "Veröffentlichen" (Publish) Tab
  3. Klickt auf den Knopf "Erforderliche Komponenten"
  4. Sucht den Eintrag "SQL Server Compact Edition 3.5" und entfernt das Häkchen und schließt die Eigenschaften
  5. Nun benötigen wir die erforderlichen DLL Dateien, diese liegen in "C:\Programe\Microsoft SQL Server Compact Edition\"
  6. Es sind 7 oder auch mehr Dateien, abhängig davon wie viele Sprachen installiert sind (siehe Bild links)
  7. Markiert diese DLLs und zieht diese direkt in den Projektmappen-Explorer, da mit diese DLLs dem Projekt hinzugefügt werden
  8. Markiert die neuen DLLs in dem Projektmappen-Explorer -> klickt mit der rechten Maustaste darauf und wählt "Eigenschaften"
  9. Setzt die Eigenschaft "In Ausgabeverzeichnis kopieren" auf "Kopieren, wenn neuer" damit ihr immer die Aktuelle Version im Build Verzeichnis habt
  10. Klickt im Projektmappen-Explorer mit der rechten Maustaste auf System.Data.SqlServerCe und wählt Eigenschaften
  11. Setzt hier die Eigenschaft "Lokale Kopie" auf True. Dieser Schritt ist nötig damit das Programm lokal nach der DLL sucht und nicht versucht sich diese aus dem GAC (Global Assembly Cache) zu holen.

Und das war es eigentlich schon. Nun könnt ihr das Projekt problemlos deployen.

29Jun/100

ScreenShot Helper – erleichert den Umgang mit Bildern in der Windows Zwischenablage

Heute mal etwas in eigener Sache: Ich habe mal wieder ein kleines Tool für Windows fertiggestellt welches euch das leben etwas erleichern kann. Die Rede ist von ScreenShot Helper.

Bild 1: Benachrichtigung über eine neue Grafik in der Zwischenablage

ScreenShot Helper ist dafür gedacht Grafiken, die ihr in die Zwischenablage steckt schnell und einfach zu verarbeiten. Ein Bleispiel: Ihr wollt einem Bekannten einen Fehler oder etwas anderes zeigen, dass auf eurem Bildschirm passiert. Wenn ihr nur die Windows Tools verwendet müsst ihr erst einen Screenshot machen, dann Paint (oder ein anderes Bildprogramm) starten die Grafik dort einfügen, das Bild speichern, nun müsst ihr eine Webseite suchen auf die ihr das hochladen wollt um dann schließlich den Link zu bekommen, den ihr eurem Freund geben könnt.

Mit ScreenShot Helper wird dieser Vorgang stark vereinfacht. Das Programm erkennt automatisch, dass eine neue Grafik in der Zwischenablage ist und zeigt euch das Fenster aus Bild1. Nun könnt ihr mit einem Klick das Bild speichern oder es mit ebenfalls einem Klick hochladen und bekommt direkt den Link den ihr weiter verteilen könnt.

Ich bin mir dessen völlig bewusst, dass es sehr viele sehr ähnliche Tools da draußen im Web gibt die diese und noch weitere Funktionalitäten bieten. Ich wollte aber einfach nur ein leichtes schnelles Tool haben, dass genau das macht was ich brauche und dass ich weiter anpassen kann.

Vielleicht könnt ihr ja auch soetwas gut gebrauchen. Hier gehts zum Programm.

29Apr/100

VB.NET: Einstellungen in der Windows Registry Speichern

In so gut wie jedem Computerprogramm müssen Informationen wie Einstellungen oder Benutzerdaten gespeichert werden. Um dies zu realisieren gibt es viele Ansätze wie zB: eine Datenbank, eine XML oder INI Datei oder direkt in der Registry. In diesem kleinem Tutorial werde ich auf die letztere Methode eingehen.

Zu nächst sei gesagt, dass ich es euch nicht empfehlen würde eine Einstellungen in der Registry zu sichern. Das hat folgende Gründe:

  • Die Daten sind sehr versteckt und nicht jeder Benutzer weiß, wie man an diese herankommt
  • Man kann diese nur sehr schwer sichern oder auf ein anderen System umziehen
  • Es wird oft vergessen diese Einstellungen aus der Registry zu löschen, sodass diese als "Leichen" im System bleiben
  • Speicherort ist von der Version des Programms abhängig

Auf der anderen Seite gibts aber auch natürlich Vorteile:

  • Einstellungen sind vor ungeübten Nutzern "geschützt"
  • Sehr geringer Programmier-Aufwand
  • Einstellungen können oft auch nach einer Neuinstallation weiter verwendet werden. (Kann auch zum Nachteil werden wenn Einstellungen fehlerhaft sind)

Besonders in früheren Windows Zeiten wurden fast alle Einstellungen in der Registry gesichert. Inzwischen setzt sich die Sicherung der Daten in XML Dateien durch und das .NET Framework bietet seit der 3er Version auch den Namensraum My.Settings mit denen diese XML Dateien automatisch erzeugt werden. Aber heute scheuen wir uns mal den anderen Weg an!

Wie oben bereits erwähnt kann man mit sehr wenig Aufwand seine Einstellungen in der Registry sichern, diese werden dabei hier gesichert:

HKEY_CURRENT_USER\Software\[Unternehmen]\[Programm]\[Version]

Hier werden die Einstellungen gesichert, dabei werden die Variablen in den Klammern automatisch gefüllt.

.Dazu bietet uns der Application-Namesraum alles was wir benötigen. Was wir aber noch machen sollten ist die Überprüfung der Werte und das Exceptionhandling.

Alles was man zum speichern eines Werts angeben muss ist der Name unter dem der Wert gespeichert werden soll und der Wert selbst. Alle Werte werden dann automatisch unter dem oberen Pfad abgelegt.


	'''
	''' Speichert einen Wert unter angegebenem Namen in der Registry
	'''
	Public Sub SaveSetting(ByVal name As String, ByVal value As String)
	    Try
	      	Application.UserAppDataRegistry.SetValue(name, value)
	    Catch ex As Exception
	      	debug.WriteLine("Fehler: " &amp; ex.Message)
	    End Try
  	End Sub

Um die Werte nun wieder auszulesen benötigt man lediglich den Namen, den man zum speichern benutzt hat und man bekommt den Wert aus der Registry geworfen!


	'''
	''' Lädt den String aus der Regitry passend zu dem angegebenem Namen
	'''
	Public Function LoadSetting(ByVal name As String) As String
		Try
			If Not Application.UserAppDataRegistry.GetValue(name) Is Nothing Then
				Return CType(Application.UserAppDataRegistry.GetValue(name), String)
		  	Else
		    	Return String.Empty
		  	End If

		Catch ex As Exception
		  	debug.WriteLine("Fehler: " &amp; ex.Message)
		  	Return String.Empty
		End Try
	End Function

Hier muss man aber beachten, dass das Programm, das die Werte ausließt die selbe Version haben muss wie das was sie in die Registry geschrieben hat, da der Pfad (siehe oben) nicht mehr passt!

Wenn man die oberen Methoden implementeirt hat kann man nun die Einstellungen sehr bequem speichern:


	'Die Einstellung aller Controls auf der Form speichern
	Sub Button1Click(sender As Object, e As EventArgs)
		Dim rs As New RegSaver 'Diese Klasse beinhaltet die oben definierten Funktionen

		'Daten für alle Controls speichern
		For Each c As Control In Me.Controls
			If TypeOf c Is RadioButton Then
				Dim a As RadioButton = CType(c, RadioButton)
				rs.SaveSetting(a.Name,a.Checked)
			End If

			If TypeOf c Is CheckBox Then
				Dim a As CheckBox = CType(c, CheckBox)
				rs.SaveSetting(a.Name,a.Checked)
			End If

			If TypeOf c Is TextBox Then
				Dim a As TextBox = CType(c, TextBox)
				rs.SaveSetting(a.Name,a.text)
			End If
		Next
	End Sub

und auch wieder auslesen:


	'Die werte aller Controls wieder laden
	Sub MainFormLoad(sender As Object, e As EventArgs)
		Dim rs As New RegSaver
				'Daten für alle Controls laden
		For Each c As Control In Me.Controls
			Try	'beim ersten starten gibt es keinen wert der gecastet werden kann!
				If TypeOf c Is RadioButton Then
					Dim a As RadioButton = CType(c, RadioButton)
					a.Checked = cbool(rs.loadsetting(a.Name))
				End If

				If TypeOf c Is CheckBox Then
					Dim a As CheckBox = CType(c, CheckBox)
					a.Checked = cbool(rs.loadSetting(a.Name))
				End If
			Catch ex As Exception
				debug.WriteLine("Fehler: " &amp; ex.Message)
			End Try

			If TypeOf c Is TextBox Then
				Dim a As TextBox = CType(c, TextBox)
				a.Text = rs.loadSetting(a.Name)
			End If
		Next
	End Sub

Wenn die Werte das erste Malgeladen werden, kann es zu fehlern kommen, da man NULL-Strings zurückbekommt, deswegen sollte man hier immer die Exceptions catchen! Falls es in der Registry noch keine passenden Einstellung zu dem Namen gibt, wird diese beim Laden automatisch angelegt!

Bild 1: Demoapplikation mit den geladenen Einstellungen

Wenn der Code durchgelaufen ist wird folgende Struktur in der Registry angelegt:

Bild 2: Die Einstellungen in der Registry

Natürlich bleibt es euch überlassen, wie ihr die Einstellungen benennet, ich habe hier den Namen des Controls verwendet um dessen Status zu speichern, damit ich nicht so viel Code schreiben musste.

Welche Methode ihr nutzt müsst ihr natürlich selber an Hand des Projekts entscheiden, kennen sollte man sie aber alle.

Ein Kleines Demoprojekt gibts hier:

Download: Diesmal ausnahmsweise ein SharpDevelop Projekt

14Apr/105

C#: Das Dateisystem mit dem FileSystemWatcher überwachen

Oftmals ist man darauf angewiesen, dein Inhalt von einem oder mehreren Ordnern zu überwachen und auf Änderungen oder Aktionen des Benutzers  zu reagieren.

Dafür gibt es verschiedene Ansätze, ich will euch heute den FileSystemWatcher aus dem .NET Framework vorstellen. Der FileSystemWatcher (FSW) bietet uns eine Reihe von Events mit denen wir das System immer im Blick haben, darunter fallen die Events Changed, Created, Renamed und Deleted.

Da der FSW auch in einem eigenem Thread läuft gibt es auch keine Kollisionen mit der GUI und den anderen Programmabläufen. Hier muss man lediglich darauf achten, dass man keine Exceptions wegen der Threadübergreifenden Aktionen bekommt!

Fangen wir mit der Implementierung an:


            //Eine neue FileSystemWatcher Instanz erstellen
            FileSystemWatcher fw = new FileSystemWatcher("C:\temp");

            //Events regestrieren
            fw.Changed += new FileSystemEventHandler(onChanged);
            fw.Created += new FileSystemEventHandler(onChanged);
            fw.Deleted += new FileSystemEventHandler(onChanged);
            fw.Renamed += new RenamedEventHandler(onRenamed);

            fw.IncludeSubdirectories = true;

            //Überwachung starten
            fw.EnableRaisingEvents = true;

Hier erzeugen wir als erstes eine neues FileSystemWatcher Objekt und geben diesem einen expliziten Pfad als Parameter. Dieser Pfad wird dann vom FSW überwacht.

Als nächstes werden die vier Events registriert über die der FSW uns informieren soll. Zum Schluss sagen wir dem FSW noch, dass er auch die Unterordner des gewählten Pfads mit überwachen soll und starten die Überwachung.

Nun müssen wir noch die Events implementieren:


        private void onChanged(object source, FileSystemEventArgs e)
        {
            if (this.lstEvents.InvokeRequired)
            {
                addItemDel ad = new addItemDel(addItem);
                this.Invoke(ad, new object[] { e.ChangeType + " " + e.FullPath });
            }
            else
            {
                lstEvents.Items.Add(e.ChangeType + " " + e.FullPath);
            }
        }

        private void onRenamed(object source, RenamedEventArgs e)
        {
            if (this.lstEvents.InvokeRequired)
            {
                addItemDel ad = new addItemDel(addItem);
                this.Invoke(ad, new object[] { e.ChangeType + " " + e.OldName + " -> " + e.Name });
            }
            else
            {
                lstEvents.Items.Add(e.ChangeType + " " + e.OldName + " -> " + e.Name);
            }
        }

Da der FSW in einem eigenem Thread läuft müssen wir hier darauf achten und die Werte aus den Events über Delegate Methoden übergeben.


        private delegate void addItemDel(string text);

        private void addItem(string text)
        {
            lstEvents.Items.Add(text);
        }

Aus den übergebenen Event Argumenten können wir alle für uns wichtigen Informationen auslesen, wie den kompletten Pfad und die Dateinamen vor und nach dem umbenennen.

Übrigens nutzen zB. auch Antivieren Programme auch diese Technik für den Liveschutz vom Dateisystem.

Die FSW Klasse bietet noch weitere Möglichkeiten, mehr dazu im MSDN.

Natürlich habe ich hier auch wieder eine kleine Demo vorbereitet:

Bild 1: Events die aus dem überwachten Ordner ausgelesen wurden

Die Demo gibts hier:

Get Adobe Flash player