VB.NET: FitzBox IP erneuern ueber uPnP
Die FritzBox ist als Router weit verbreitet und bietet einen Haufen an Konfigurationsmöglichkeiten an. Eins der nützlichsten Features ist uPnP (Universal Plug and Play). Diese Schnittstelle bietet uns eine sehr bequeme Möglichkeit mit dem Gerät zu kommunizieren ohne dass man einen Benutzernamen oder ein Kennwort benötigt!
Wer öfter mal im Internet unterwegs ist, kennst sicherlich mehrere gute Gründe seine IP zu wechseln. Und das ist sehr einfach, denn alles was dafür nötig ist, ist eine erneute Einwahl ins Internet.
Dies kann man sehr einfach über die Benutzeroberfläche der FritzBox machen oder einfach "oldschool"-mäßig das Netzwerkkabel aus der FritzBox ziehen und wieder einstecken. (Letzteres erfordert ebenfalls keinen Benutzernamen und Passwort)
Doch wenn man des öfteren auf diese Funktionalität angewiesen ist, ist es doch relativ nervig und umständlich. Deswegen werden wir hier ein einfaches kleines Programm entwickeln, dass für uns den Router zu einer Neueinwahl ins Internet "zwingt".
Wie oben bereits erwöhnt heißt die Technologie dafür UPnP (Universal Plug and Play). Über diese Technologie lassen sich sehr viele Befehle an die Fritzbox senden, vorausgesetzt, man befindet sich in dem selben Netzwerk.
Von Statusabfragen über Auslastungen und Übertragung, lassen sich sogar Telefonnummern anwählen und Anrufe steuern, im Prinzip kann man alle Funktionen darüber ansteuern. Hier gibts eine nette Übersicht mit vielen Beispielen.
Wie werden die Anfragen eigentlich an die Fritzbox übertragen? Das geschieht sehr einfach über einen POST Aufruf, denn auf der Fritzbox (und auch auf den meisten anderen Routern) läuft ein kleiner Webserver denn man ganz einfach über den Browser erreicht, wenn man die adresse "fritz.box" in die Adresszeile tippt.
Dort ist die Fritzbox genauso aufgebaut wie eine gewöhnliche Webseite. Und diese nimmt auch POST und GET aufrufe entgegen. Genau hier setzen wir an und werden unsere Befehle rüber schicken.
Dim client As New TcpClient
client.Connect("fritz.box", 49000)
Dim stream As NetworkStream = client.GetStream
Dim bytes As Byte() = New Byte((My.Resources.msg.Length)) {}
bytes = Encoding.ASCII.GetBytes(My.Resources.msg)
stream.Write(bytes, 0, bytes.Length)
bytes = New Byte(1024) {}
Dim str As String = String.Empty
Dim count As Integer = stream.Read(bytes, 0, bytes.Length)
str = Encoding.ASCII.GetString(bytes, 0, count)
stream.Close()
client.Close()
Der Code ist sehr simpel, wir erstellen uns einen WebClient und verbinden uns mit der FritzBox. Nach der Verbindung senden wir ein POST Request raus und lesen anschließend die Antwort wieder aus.
Mit dem obigen Code senden wir folgenden Befehl an die Fritzbox:
POST /upnp/control/WANIPConn1 HTTP/1.1
HOST: fritz.box:49000
SOAPACTION: "urn:schemas-upnp-org:service:WANIPConnection:1#ForceTermination"
CONTENT-TYPE: text/xml ; charset="utf-8"
Content-Length: 293
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<u:ForceTermination xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1" />
</s:Body>
</s:Envelope>
Wie man sieht ist der Befehl ein gewöhnlicher POST Aufruf inkl. Header. Dieser übergibt einen Befehl urn:schemas-"upnp-org:service:WANIPConnection:1#ForceTermination", der der Fritzbox sagt die Verbindung ins Internet neu aufzubauen.
Man muss hierbei sehr aufpassen, besonders die Content-Length Angabe muss genaustens passen, da sonst ein Fehler als Antwort eintrudelt.
Wie immer gibts auch eine kleine Demoanwendung.
Download hier: Download [VS 2008 Projekt]
Programmfortschritt in der Windows Taskleiste anzeigen
Wenn ihr Windows 7 bereits verwendet, werden euch sicherlich einige Neuerungen aufgefallen sein. Einige von denen ist die neue Funktion der Taskleiste den Fortschritt eines Programms darzustellen.
Ihr werdet dies beobachten, wenn ihr z.B. eine Datei mit dem Internet Explorer 8 herunterladet oder eine Datei kopiert. Das Programm zeigt den eigenen Fortschritt dann unter dem Eigenen Symbol in der Taskleiste an.
Diese Funktion ist extrem praktisch, so kann man sie benutzen um den Benutzer immer aktuell zu halten, ohne dass er das eigentliche Programm offen hat. Mögliche Anwendungsfälle wären Dateidownloads, Kopiervorgänge, Bildererzeugung und allgemeine Vorgänge, die etwas Zeit in Anspruch nehmen.
Natürlich können auch wir diese Funktionen in unseren Projekten nutzen. Leider werden die Aufrufe an das Betriebssystem unmanaged gestartet, was bedeutet, dass diese Aufrufe umgewandelt (gewrapped) werden müssen. Da das ein sehr komplexer Vorgang ist hat Microsoft uns diesen gespart und schon einige vorgefertigte Klasse angefertigt auf die wir zurückgreifen können.
Diese Librarys finden wir im MSDN in der .NET Interop Sample Library. Diese Beispielsammlung enthällt viele weitere Beispiele. Wir betrachten hier nur das was mit dem Fortschrittsbalken in der Taskleiste zu tun hat.
Deswegen brauchen wir auch nicht alle Klassen, sondern nur diese:
Vista Bridge Sample Library
Windows7.DesktopIntegration
Windows7.DesktopIntegration. Registration.
Windows7.DesktopIntegration enthält hierbei die Klasse WindowsFormsExtensions, welche uns die nötigen "Extensions"-Funktionen zur Verfügung stellt um das Aussehen der Taskleiste ändern zu können.
In unserem (einfachen) Fall werden wir nur die beiden Methoden benötigen:
SetTaskbarProgress(float percent)
SetTaskbarProgressState(ThumbnailProgressState state)
Mit der Ersten Methode können wir den Fortschritt der Progressbar steuern, und mit der zweiten das Aussehen. Für die zweite Funktion müssen wir neben dem Zustands Parameters auch das Handle des Fensters angeben, für das die Aktion ausgeführt wird.
So könnten die Aufrufe folgendermaßen aussehen:
WindowsFormsExtensions.SetTaskbarProgress(Me.ProgressBar1)
WindowsFormsExtensions.SetTaskbarProgressState(Me, _
Windows7Taskbar.ThumbnailProgressState.Error)
Garnicht mal so kompliziert oder?
Dabei kann das Taskleistensymbol unseres Programms 5 verschiedene Werte annehmen:
Wenn wir nun also ein neues Windows Forms Projekt erstellen müssen wir ersteinmal die drei oben erwähnten Class Librarys importieren. Das machen wir in dem wir über Datei->Hinzufügen->Vorhandenes Projekt wählen
Auf diese Weise fügen wir alle drei oben erwähnten Projekte dem unseren hinzu. Wenn das geschafft ist müssen wir noch die nötigen Verweise hinzufügen. Dazu wählen wir Projekt->Verweis hinzufügen... und dann den Tab "Projekte"
Hier wählen wir alle drei Projekte aus und klicken auf "OK"!
Wie ihr nun im Projektmappen Explorer erkennen werdet ist das Projekt gleich mal um einiges gewachsen! Ihr könnt dieses Vorgehen auch umgehen, indem ihr die importierten Class Librarys als DLL kompiliert und direkt in das Projekt einbindet. Das schafft vielleicht mehr Übersicht.
Nun haben wir schon das größte Hindernis schon überwunden! Nun gehts ans Programmieren, wofür ihr die oben vorgestellten Funktionen benutzen könnt um eurem Programm den nötigen Windows 7 Look zu verpassen!
Ich habe dazu wie immer eine kleine Demo angefertigt. Meine sieht so aus:
Bild 4: Das Demoprojekt in Aktion
Das Demoprojekt könnt ihr hier laden: Download [VS 2008]
VB.NET: Saubere Klassen erstellen mit Properties
Heutzutage wird fast nurnoch Objektorientiert programmiert. Das bedeutet, dass ein größeres Projekt schnell mal auf eine Klassenanzahl von 100 und mehr wächst.
Damit man den Überblick behält und den Code, den man schon geschrieben hat möglichst wiederverwenden kann, sollte man ein paar grundlegende Regeln beachten.
In diesem Artikel möchte ich ein Beispiel zeigen, wie man eine Klasse in ein Projekt integriert und dank der benutzten Standardmethoden an ein Datagrid bindet.
Warum schreibe ich diesen Artikel überhaupt? Erst gestern habe wurde in einem Forum die Frage gestellt, warum man eine Liste (Of T) nicht als DataSource für ein DataGridView benutzen kann. Dabei ist das sehr wohl möglich, der User hat seine Klasse aber "unschön" gestaltet, weswegen sich die anderen Steuerelemente auch quer gestellt haben.
Hier ein Beispiel einer solchen "Unschönen" Klasse:
Public Class Auto
Public marke As String
Public motor As String
Public geschw As Integer
End Class
Dim al As New List(Of Auto)
al.Add(New Auto With {.marke = "VW", .motor = "Diesel", .geschw = 0})
al(0).geschw += 10
Wie man sieht sind hier alle Klassenvariablen öffentlich zugänglich, und die Klasse hat keinerlei Kontrolle darüber, wie sie befüllt werden. Ein weiterer Nachteil ist auch die Inkompabilität zu anderen Steuerelementen, da diese einen Standardkonformen Aufbau der Klasse erwarten. Finden sie bestimmte Elemente in der Klasse nicht so verweigern diese die Funktionalität!
Wie müsste diese Klasse also umgebaut werden, damit diese kompatibel zu anderen Objekten wird?
Public Class Auto
Private geschw As Integer
Public Sub New(ByVal marke As String, ByVal motor As String)
Me._marke = marke
Me._motor = motor
End Sub
Private _marke As String
Public Property Marke() As String
Get
Return _marke
End Get
Set(ByVal value As String)
_marke = value
End Set
End Property
Private _motor As String
Public Property Motor() As String
Get
Return _motor
End Get
Set(ByVal value As String)
_motor = value
End Set
End Property
Public Sub beschleunigen(ByVal a As String)
geschw += a
End Sub
Public Sub bremsen(ByVal a As String)
geschw -= a
End Sub
End Class
Wie man sieht ist die Klasse nun natürlich um einiges länger geworden. Leider kann man das zur zeit noch nicht anders machen. Aber Abhilfe kommt in der neuen VB.NET Version, wo man die properties so wie in C# 3.0 erstellen kann.
Die Zugriffe auf die Klassenvariablen werden nun über properties gesteuert, die nun auch zB. überprüfen könnten, ob der übergebene Wert überhaupt passt und gegebenenfalls noch Änderungen daran vornehmen.
Aber was bringt uns nun dieser längere Aufbau der Klasse? Nun, wenn wir unser Objekt, das aus dieser Klasse entsteht an andere Objekte übergeben, erwarten diese, dass sie properties vorfinden, mit denen sie arbeiten können.
Hat die Klasse keine Properties so können wir auch bestimmte Funktionen auch nicht benutzen. Ich möchte das mal an einem DataGridView demonstrieren, da dieses Element von den properties sehr schön Gebrauch macht!
Fügt man folgenden Code einem Form mit einer DataGridView hinzu:
Private Sub Form1_Load() Handles MyBase.Load
Dim autos As New List(Of Auto)
autos.Add(New Auto("VW", "Diesel"))
autos.Add(New Auto("Audi", "Benziner"))
autos.Add(New Auto("Mercedes", "Diesel"))
autos.Add(New Auto("Renault", "Diesel"))
autos.Add(New Auto("BMW", "Beziner"))
Dim bs As New BindingSource
bs.DataSource = autos
Me.DataGridView1.DataSource = bs
End Sub
erhält man folgendes Bild:
Bild 1: Die Datagridview stellt alle Informationen angenehm dar
Wie man sieht konnte man mit nur 3 Zeilen Code (Abgesehen vom Erzeugen der Werte) alle Daten der Liste visualisieren. Man beachte desweiteren, dass sogar die Namen der Properties (Marke und Motor) ausgelesen werden und der richtigen Tabelle zugeordnet werden!
Dies könnte man natürlich auch ohne Properties hinbekommen, doch würde man viel mehr Aufwand betreiben müssen und man denke an die Zukunft, in der unser Modell sehr einfach zu warten wäre.
Hier gibts ein kleines Demoprojekt: Download [VS 2008]
Windows Aero Glas in eigenen Projekten nurzen Teil 3
Es ist etwas Zeit seit dem zweiten Teil vergangen, und wie ich in den Kommentaren sehe, sind da noch ein paar Fragen offen!
Das Hauptproblem mit den Glasoberflächen unter Windows sind die GDI und GDI+ Komponenten, diese unterstützen keine Transparenz. Das macht es so schwierig diese auf Glas ordentlich zu rendern.
Wenn ihr meine persönliche Meinung hören wollt, lasst es ganz bleiben! Denn seit knapp 4 Jahren stellt Microsoft uns ein sehr mächtiges grafisches Werkzeug zur Verfügung, nämlich WPF.
WPF soll die neue Präsentationsschicht unter Windows werden. Das heißt WPF regelt wie die UI-Elemente, die wir sehen, zb. Knöpfe und Fenster aussehen und sich verhalten!
Aber ich will nicht weiter auf den Aufbau von WPF eingehen, für uns ist wichtig zu wissen, dass in WPF alle Elemente die Transparenz beherrschen. Das macht sie für uns perfekt um sie auf Glas einzusetzen!
Bild 1: Ein in WPF gerendertes Fenster mit Steuerelementen
Wie man auf dem Bild 1 gut erkennen kann, sieht man keine verpixelten Texte mehr und der Hintergrund ist wunderbar Transparent, auch bei dem Button!
Alle WPF Steuerelemente beherrschen viel mehr Optische Funktionen, so sind die beiden ProgressBars im Bild 1 ebenfalls Transparent. Das geht nicht mit GDI+!
Für alle die jetzt denken, oh nein, ich will nicht schon wieder eine neue Sprache erlernen, kann ich für Entwarnung sorgen. Auch unter WPF wird mit VB.NET und C# programmiert. Ihr könnt euren Code in 80% der Fälle komplett übernehmen!
Wie gesagt liegt der Schwerpunkt von WPF auf der Präsentation, deswegen werdet ihr die alten Grafik-Klassen nicht mehr wiederfinden. Desweiteren gibts auch keine Windows.Forms mehr, sondern nurnoch Windows (Fenster). Dies sind ein paar der Stolperfallen, durch die man sich kämpfen muss und an die man sich gewöhnen muss.
Wie ihr an dem folgenden Beispielcode sehen werdet, werdet ihr viel wiedererkennen:
Imports System.Runtime.InteropServices
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Windows.Media
Imports System.Windows
Imports System.Windows.Interop
Public Class GlassForm
_
Private Shared Sub DwmExtendFrameIntoClientArea _
(ByVal hwnd As IntPtr, ByRef margin As MARGINS)
End Sub
_
Public Shared Function DwmIsCompositionEnabled() As Boolean
End Function
Public Shared Function ExtendGlassFrame(ByVal window As Window, _
ByVal margin As MARGINS) As Boolean
If Not DwmIsCompositionEnabled() Then
Return False
End If
Dim hwnd As IntPtr = New WindowInteropHelper(window).Handle
' Hintergrundfarbe auf Tranzparent setzen, für WPF und die Win32 Ansicht
window.Background = Brushes.Transparent
HwndSource.FromHwnd(hwnd).CompositionTarget.BackgroundColor = _
Colors.Transparent
Dim margins As New MARGINS(margin.left, margin.right, _
margin.top, margin.bottom)
DwmExtendFrameIntoClientArea(hwnd, margins)
Return True
End Function
End Class
Public Structure MARGINS
Public left As Integer
Public right As Integer
Public top As Integer
Public bottom As Integer
Public Sub New(ByVal l As Integer, ByVal r As Integer, _
ByVal t As Integer, ByVal b As Integer)
left = l
right = r
top = t
bottom = b
End Sub
End Structure
Wie man sieht ähnelt der Code sogar sehr dem aus Teil 2. Nur die entsprechenden (in WPF nicht mehr vorhandenen) Elemente wurden angepasst.
Das tolle hierran ist, dass wir nun alle Steuerelemente benutzen können die wir wollen, ohne uns Sorgen machen zu müssen wie diese gerendert werden!
Das Demoprojekt gibts es hier: Download [VS 2008]
Hier gehts zum zweiten Teil des Tutorials.
Eventuell schiebe ich noch einen vierten Teil nach, warten wir ersteinmal eure Reaktionen ab
Kostenloses E-Book von Microsoft zum Thema VB.NET
Es ist wieder soweit. Microsoft bietet wiedermal ein Buch komplett gratis zum Download an. Dieses Mal ist Visual Basic.NET das Thema.
Das Buch ist von dem Hauseigenen Verlag MicrosoftPress, welches einen sehr guten Ruf genießt. Ich selber habe mehrere Bücher von denen.
Dieses Buch kostet normalerweise 59 € und ist somit ein sehr gutes "Schnäppchen". Dabei kann es sich vom Inhalt sehen lassen. Dieses Buch vermittelt alles von den Grundlagen, bishin zur fortgeschrittenen Programmierung mit Datenbanken.
Auch wenn ihr kein VB.NET Programmierer Seit kann ich es euch trotzdem empfehlen dieses Buch zu laden, den man weiß ja nie!
Download: Hier
Windows Aero Glass in eigenen Projekten nutzen Teil 2
In dem ersten Teil dieses Beitrags, der nun schon einige Monate her ist habe ich gezeigt, wie man die Aero Glas Effekte auch in eigene Projekte einbauen kann. Doch leider waren da noch einige Probleme, so konnten wir nur das ganze Formular in Glas verwandeln und die Darstellung der Steuerelemente war falsch.
Genau hier möchte ich den zweiten Teil ansetzen und diese letzten Probleme aus der Welt schaffen!
Wir beginnen genauso wie im ersten Teil nur nennen wir unsere Klasse diesmal GlassForm um nicht durcheinander zu kommen.
Diesmal importieren wir eine weitere Methode aus der Windows API, nämlich DwmIsCompositionEnabled() die es uns ermöglicht zu prüfen, ob diese Effekte, die wir nutzen möchten auch verfügbar sind.
Die zweite Funktion DwmExtendFrameIntoClientArea müsste aus Teil 1 schon bekannt sein, diese hilft uns die Formränder zu vergrößern und somit die Glasoberfläche ins Formularinnere zu holen.
Da wir dieses Mal die eine Option für alle Ränder haben möchten, sodass wir zB. nur den oberen Rand in Glas verwandeln, benötigen wir ein Structure, in dem wir die Werte für jeden Rand speichern können und den wir dann später der Funktion DwmExtendFrameIntoClientArea übergeben.
So sieht unsere Klasse aus:
Imports System.Runtime.InteropServices
Public Class GlassForm
_
Private Shared Sub DwmExtendFrameIntoClientArea _
(ByVal hwnd As IntPtr, ByRef margin As AeroDemo2.MARGINS)
End Sub
_
Public Shared Function DwmIsCompositionEnabled() As Boolean
End Function
Public Shared Function ExtendGlassFrame _
(ByVal hwnd As IntPtr, ByVal margin As AeroDemo2.MARGINS) As Boolean
GlassForm.DwmExtendFrameIntoClientArea(hwnd, margin)
Return True
End Function
End Class
Public Structure MARGINS
Public left As Integer
Public right As Integer
Public top As Integer
Public bottom As Integer
Public Sub New(ByVal l As Integer, ByVal r As Integer, _
ByVal t As Integer, ByVal b As Integer)
left = l
right = r
top = t
bottom = b
End Sub
End Structure
Wie man sieht enthält die Structure MARGINS je eine Variable für jede Seite des Formulars, wobei der Wert den sie beinhaltet den Abstand zum eigentlichen Rahmen angibt!
Wechseln wir nun zur Klasse Form1, da wir hier fertig sind. In der Form_Load Methode können wir uns nun einen neuen Structure erstellen und diesem unsere gewünschten Rahmenabstände übergeben. Daraufhin rufen wir unsere Funktion auf die für sns das Glas herzaubern soll.
Doch wenn wir das Programm nun starten werden wir kein Glas vorfinden! Das liegt daran, dass Windows die Farbe Schwarz für Transparente Darstellung auf Glas verwendet. Das bedeutet, dass alle Steuerelemente, die Schwarze Farbe enthalten transparent und somit zu Glas werden! Das konntet ihr aber auch im ersten Teil schon beobachten!
Dieses Problem nehmen wir aber später nocheinmal in Angriff! Kommen wir ersteinmal zu unserem Glasfenster!
Damit wir auch wirklich Glas sehen, müssen wir ersteinmal das Fenster mit schwarzer Farbe füllen. Dazu schreiben wir folgendes in die Form_Paint Methode:
Dim margins As AeroDemo2.MARGINS
Private Sub Form1_Load() Handles MyBase.Load
'Den "normalen" Bereich festlegen
margins = New AeroDemo2.MARGINS(0, 0, 35, 50)
'Die Fensterränder erweitern
GlassForm.ExtendGlassFrame(Me.Handle, margins)
End Sub
Wenn man das Programm startet, müsste das ca so aussehen:
Bild 1: Alles ist schwarz, bis auf den Glasteil
Bitte nicht erschrecken, denn eigentlich ist es keine Überraschung, dass wir nur schwarz sehen, denn wir haben im letzten Schritt alles Schwarz gefärbt. Der Aero Teil ist dadurch nun transparent geworden!
Da das Schwarze aber ziemlich blöd aussieht möchten wir das natürlich wieder auf unsere Standardeinstellung ändern. Dazu müssen wir diesen schwarzen Rechteck da oben nun wieder mit der Ausgangsfarbe füllen! Das machen wir so:
Private Sub Form1_Paint(ByVal sender As Object, _
ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
If GlassForm.DwmIsCompositionEnabled() = True Then
'Hintergrund Schwarz füllen, um den Glass effenkt zu erhalten
e.Graphics.Clear(Color.Black)
'Nun das Stück, dass nicht aus Glas sein soll wieder "zurückmalen"
Dim clientArea As New Rectangle(margins.left, margins.top, _
Me.ClientRectangle.Width - margins.left - margins.right, _
Me.ClientRectangle.Height - margins.top - margins.bottom)
Dim b As Brush = New SolidBrush(Me.BackColor)
e.Graphics.FillRectangle(b, clientArea)
End If
End Sub
Nachdem wir das Rechteck wieder mit der Ausgangsfarbe bemalt haben sieht das schon viel angenehmer aus:
Bild 2: Das Fenster hat nun wieder die "Normale" Farbe
Was natürlich nun auffällt ist das Komplett schwarze Label (ja, es ist wirklich eins) und der nicht lesbare Button.
Dies sind die oben besagten Probleme von GDI Objekten. Diese werden Standardmäßig genutzt um Abwärtskompabilität zu gewährleisten. Schaltet man aber das TextRendering auf GDI+ so werden auch die Schriften korrekt dargestellt.
Um das zu ändern muss die Option SetCompatibleTextRenderingDefault auf true gesetzt werden. Dies muss aber geschehen bevor das Programm gestartet wird. Also klicken wir mit der Rechten Maustaste auf unser Projekt -> Hinzufügen -> Modul
In das Modul schreibt ihr nun folgendes rein:
Sub Main()
Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault(True)
Application.Run(New Form1) 'Name eurer Form
End Sub
Nun müssen wir nurnoch dafür sorgen, dass unser Projekt durch das Modul gestartet wird. Das machen wir in dem wir auf "Projekt" oben im Menü klicken und dann auf Eigenschaften. Hier muss nun der Haken bei "Anwendungsframework aktivieren" herausnehmen und dann bei "Startobjekt" "Sub Main" wählen:
Bild 3: Das Projekt über das Modul starten
Wenn wir das Programm nun starten sollte man die Texte und auch den Button lesen können!
Nun sind wir eigentlich schon durch. Was noch zu sagen bleibt ist, dass man es möglichst vermeiden sollte Steuerelemente auf dem Glas zu platzieren, da diese sehr oft falsch dargestellt werden.
Wenn ihr unbedingt Schrift auf Glas haben wollt solltet ihr diese Schrift auf das Formular Zeichnen und nicht einfach über ein Label dort platzieren. Das selbe gilt auch für Grafiken. Leider kann man nicht einfach mit der Graphics.DrawString() Methode Zeichnen sondern muss den Text erst in ein GraphicsPath Objekt "zeichnen" bevor man es dem Glas übergibt. So stellt man sicher, dass die Textverläufe richtig dargestellt werden!
Hier ein Beispiel:
'Text zeichnen
Dim txt = Me.CreateGraphics()
Dim path = New GraphicsPath()
path.AddString("Ich bin ein gezeichneter Text", _
New FontFamily("Tahoma"), CInt(FontStyle.Regular), _
20, New Point(60, 0), StringFormat.GenericDefault)
Dim brush = New PathGradientBrush(path)
Dim clr As Color() = {Color.Transparent}
txt.SmoothingMode = SmoothingMode.HighQuality
brush.CenterColor = Color.White
brush.SurroundColors = clr
txt.FillPath(Brushes.Black, path)
brush.Dispose()
path.Dispose()
txt.Dispose()
Und wie es aussehen könnte:
Bild 4: So könnte ein Aero Formular aussehen
Weitere Informationen auch mit Beispielen findet ihr hier: (englisch & C#)
Microsoft
CodeProject
CodeProject
Wie üblich habe ich das Ganze in ein kleines Demoprojekt verpackt: Download
Wie hats euch gefallen, möchtet ihr einen dritten Teil? Freue mich auf euer Feedback!
Teil 1 des Tutorials gibts hier
Zum dritten Teil gehts hier lang
Windows Lizenzschlüssel aus der Registry auslesen
Da der Beitrag über das Auslesen des Office Schlüssels sehr beliebt ist, habe ich nun auch das Lesen des Windows Schlüssels als Beispiel verfasst.
Das Vorgehen hierbei ist sogar noch einfacher als beim Office Schlüssel, da es keine Aufteilungen in Versionen gibt! In allen Windows NT Versionen (also alle ab XP) befindet sich der Schlüssel in der Registry unter diesem Pfad:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
Bild 1: Der Registryordner mit dem Windows Schlüssel
In diesem Ordner finden wir den Binärwert "DigitalProductId", der viele Hexadezimalzeichen enthält!
Der Code ist hierbei dem aus dem Officebeispiel sehr ähnlich, da er ja auch nichts anderes macht, als den im HEX-Code vorhandenen Key in lesbare Schrift umzuwandeln! Die einzige Schwierigkeit hierbei besteht darin, den Key richtig zusammen zusetzen, denn es wird nicht das komplette Alphabet verwendet um einen Windows Key zu generieren sondern nur diese Zeichen:
B C D F G H J K M P Q R T V W X Y 2 3 4 6 7 8 9
Wenn man das beachtet steht einem nichts mehr im Wege! Der Code aus diesem Beispiel stammt ausnahmsweise nicht von mir sondern von vcware.de - danke dafür an dieser Stelle!
Ich habe diesbezüglich wie immer ein kleines Demoprojekt angefertigt, das ihr euch herunterladenkönnt! Download
Bitte berichtet ob es bei euch gut geklappt hat.
Hier könnt ihr euch das komplette kostenlose Programm zum auslesen von Windows & Office key herunterladen. (English & Deutsch)
Windows 7 und seine Schönheitsfehler Teil 1: Ordnerpfade
Seit einiger Zeit ist nun Microsofts neues Betriebssystem Windows 7 auf dem Markt und schlägt sich bisher sehr gut! Ich nutze es selber jeden Tag und bin begeistert von der Geschwindigkeit und den neuen Features die es bietet. Doch leider gibt es auch hier ein paar (wenn auch wenige) Schattenseiten, über die ich in dieser Reihe berichten möchte!
In diesem Ersten Teil geht es um ein kleines "Feature", dass einem nicht gleich ins Auge springt und teilweise auch schon in Windows Vista vorzufinden war. Der "normale" Nutzer würde es wahrscheinlich garnicht bemerken, doch wir als Programmierer müssen desöfteren mit konkreten Pfaden arbeiten, und das ist genau die Sache!
Blicken wir kurz zurück auf Windows XP und seine NT-Vorgänger. Jede Windows XP Version, egal in welcher Sprache sie vorliegt hat den selben Aufbau, zB. wird man immer den Ordner C:\Programme vorfinden, in dem die ganzen installierten Programme liegen.
Wenn wir nun also diesen Pfad fest in unser Programm einbauen, da wir ja davon ausgehen, dass dieser Pfad konstant ist müsste es ja "immer" laufen! Doch das ist leider nicht so, denn wenn man unser Programm auf einem Rechner mit einer Englischen Kopie von Windows (XP) startet, wird das Programm abstürzen, da es den Ordner C:\Programme nicht finden wird!
Warum? Ganz einfach, denn im Englischen gibts das Wort "Programme" nicht! Dort heißt der Ordner "Program Files" und müsste dementsprehend über "C:\Program Files" angesprochen werden! - Ja, ich weiß, ein normaler Mensch würde hier die Umgebungsvariable "ProgramFiles" nutzen, die immer auf den richtigen Ordnerpfad zeigt, aber das würde das Problem nicht verdeutlichen! (dazu kommen wir noch)
Also zurück zu Windows 7. Microsoft dachte sich auch, dass das wohl blöd ist und entschied sich dazu alles einheitlich zu machen! - Gute Idee, doch etwas komisch umgesetzt!
Schauen wir uns doch mal einen Typischen Windows 7 Ordnerpfad an:
Bild 1: Der Ordner "Eigene Bilder" ausgewählt im WIndows Explorer
Wenn ich Sie nun nach dem Pfad zu dem ausgewählten Ordner frage, würden Sie wohl wie folgt antworten:
C:\Benutzer\Basti\Eigene Bilder
Ich kann Sie beruhigen, diese Angabe ist völlig korrekt, so scheint es. Denn an dieser Stelle täuscht uns Windows 7 bzw. der Windows Explorer.
Denn würden Sie den o.g. Pfad aufrufen wollen, würde Windows eine Fehlermeldung ausgeben, die besagen würde, dass der Ordner nicht existiert! - Wie kann das sein?
Das liegt daran, dass Windows uns die deutsche Sprache nur vortäuscht! Denn der echte Pfad sieht so aus:
Bild 2: Der wahre Pfad steht oben
Nach einem Klick in die Adresszeile wird man feststellen, dass der Ordnerpfad komplett nur aus Englischen Wörtern besteht!
Das macht es manchmal umständlich eine Datei zu finden, auch wenn es für den eigentlichen Nutzer angenehmer erscheint!
Wie kann man sich schützen?
ALs Programmierer sollte man seinen Code immer so schreiben, dass es auf allen Windows Versionen lauffähig ist, doch wie macht man das wenn die Ordner immer anders heißen?
Die Antwort ist relativ leicht und lautet "Umgebungsvariable"! Denn Windows übersetzt nicht alle Ordner, sondern nur die so genannten "Special Folders". Das sind Ordner, die für das System von Bedeutung sind!
Dazu gehören der Windows Ordner Selbst, der Systemordner, der Programmordner oder der "Eigene Dateien" Ordner. Aber woher weis ich, ob ein Ordner ein "Special Folder" ist oder nicht?
Das kann man ganz einfach herausfinden, indem man in die Liste der Umgebungsvariablen (Environmentvariables in English) schaut. Diese findet ihr zb so: [Start]+[R] Tippt nun "cmd" ein und drückt auf [ENTER] um in die Eingabeaufforderung von Windows zu gelangen. Nun tippt "set" ein und drückt erneut auf [ENTER].
Bild 3: Die Liste mit den Umgebungsvariablen unter Windows
Hier sehr ihr eine komplette Liste mit allen dem Benutzer zugänglichen Umgebungsvariablen. Alternativ könnt ihr auch so vorgehen: [Start] und nun tippt ihr in das Suchfeld von Windows Vista oder 7 "erweitert" ein und lasst Windows ein paar Sekunden suchen, dann klickt ihr auf den Eintrag "Erweiterte Systemeinstellungen Anzeigen", wählt nun oben den Tab "Erweitert" auf und klickt unten auf "Umgebungsvariablen" ihr bekommt folgendes zu sehen:
Bild 4: Die Grafische Oberfläche der Umgebungsvariablen
Unter Windows XP Erreicht ihr dieses Fenster mit einem Rechtsklick auf Arbeitsplatz und dann Erweitert!
Auf diese Variablen kann man auch sehr bequem vom Code aus zugreifen, und da diese auf jedem System stimmen hat man keine Probleme zu erwarten!
'
'
'Pfad zum Programmordner
Dim ProgrammPfad As String
ProgrammPfad = Environment.GetEnvironmentVariable("ProgramFiles")
Wie man sieht kann man so sehr einfach den Programmordner auslesen.
Windows 7 bietet noch weitere kleine Überraschungen über die ich im Nächsten Teil schreiben werde!
Hat euch diese Beitrag gefallen? Schreibt mir einen Kommentar!
VB.NET: Eigenes Programm mit Windows starten lassen
Oftmals ist es es von Nöten sein eigenes Programm beim Hochfahren von Windows automatisch starten zu lassen. Dies ist nicht wirklich anspruchsvoll aber dennoch sehr nützlich!
Windows bietet uns hier 2 Möglichkeiten dieses Vorhaben umzusetzen. Die erste ist es eine Verknüpfung zu unserem Programm zu erstellen und diese dann im Autostart Verzeichnis zu platzieren.
Bild 1: Der Windows Autostart Ordner im Startmenü
Dieser Ordner befindet sich unter dem folgendem Pfad:
C:\Users\[BENUTZERNAME]\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
Windows führt automatisch alle Dateien aus, die sich in diesem Ordner befinden, nachdem der Startvorgang abgeschlossen ist!
Die zweite (und meiner Meinung nach), bessere Methode ist es, einen entsprechenden Eintrag in der Registry zu setzen. Dies hat auch den Vorteil, dass man später die Verknüpfung nicht suchen und entfernen muss und dass der Benutzer diese nicht ausversehen löscht.
Wenn ihr in den dafür vorgesehenen Ordner schaut werdet ihr feststellen, dass dort (wahrscheinlich) auch andere Programme ihr Unwesen treiben.
Bild 2: Weitere Autostart Einträge
Diesen Registry Ordner findet ihr im Regestrierungseditor unter folgendem Pfad:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
In dem folgenden Codebeispiel werden wir hier einen Eintrag mit dem Verweis auf unser Programm einfügen.
Public Sub LoadOnStartup(ByVal DoOrNot As Boolean)
Dim RegKey As String = "HKEY_CURRENT_USER\Software\" &amp;amp;amp; _
"Microsoft\Windows\CurrentVersion\Run"
If DoOrNot = True Then
My.Computer.Registry.SetValue _
(RegKey, "[PROGRAMMNAME]", My.Application.Info.DirectoryPath &amp;amp;amp; _
"\" &amp;amp;amp; My.Application.Info.AssemblyName &amp;amp;amp; ".exe")
Else
My.Computer.Registry.SetValue _
(RegKey, "[PROGRAMMNAME]", "")
End If
End Sub
Wie man sieht ist es dank .NET nicht wirklich schwer einen Registryeintrag zu erstellen und zu bearbeiten, denn wenn ihr nicht mehr wollt, dass euer Programm mit Windows gestartet wird, löscht ihr den Eintrag einfach oder gebt statt dem Pfad etwas anderes ein.
In dem Code verwende ich den Kern-Schlüssen "HKEY_CURRENT_USER" statt des oben erwähnten "HKEY_LOCAL_MACHINE". Dies heißt nur, dass das Programm nur bei dem User Automatisch starten wird, der diesen Code ausführt. Benutzt man allerdings "HKEY_LOCAL_MACHINE" wird das Programm bei allen Benutzern des Computers automatisch gestartet!
Zur Benutzung: Ruft diese Funktion einfach auf und übergebt True um euer Programm automatisch starten zu lassen, oder False um dies wieder zu unterbinden!
Da dies nur ein Copy & Paste Beispiel ist, habe ich hierfür kein Demoprojekt angefertigt, ich hoffe ihr könnt mir verzeihen!
VB.NET: ICQ Benutzerinformationen auslesen
In Deutschland ist der Instant Messaging Client ICQ seht weit verbreitet. So könnte man doch ab und zu eine Funktion gebrauchen mit der man prüfen kann, ob ein Benutzer grade am PC ist.
Leider schränkt ICQ uns hier sehr ein und bietet keinerlei Schnittstelleninformationen. So müssen die Entwickler berühmter Clients wie QIP, Miranda oder Trillian die Funktionsweise des Protokolls selbst erarbeiten durch Reverse Engeneering!
Ich bin vor ein paar Tagen aber auf ein interessantes Skript gestolpert, dass die ICQ Webseite wohl intern dazu benutzt den Status der User im Forum und auf der eigenen Homepage darzustellen. Und natürlich können wir diesen auch anzapfen!
Das Skript befindet sich unter dieser Adresse: http://www.icq.com/js/pcc.php?Uin=[ICQNUMMER]
Ruft man diesen Link mit einer gültigen ICQ Nummer am Ende auf so erhält man ein großes Wirwar an Informationen die aber leider nicht geordnet dargestellt werden!
Auch wenn es nicht alle Informationen sind, die ICQ über einen speichert, so kann man mit den Daten trotzdem schon was anfangen!
Bild 1: Das ICQ Tool - und ja: Diese ICQ Nummer gibts wirklich
So kann man neben Status und Namen auch das Bild des Benutzers abfragen. Aber nur das Bild, das der User im Forum verwendet (glaube ich).
Desweiteren kann man nicht von allen Benutzern den Status abfragen. Ich vermute, das liegt daran dass diese Benutzer erst eine Autorisierung verlangen bevor sie den Status preisgeben.
Der Programmierteil beschränkt sich hierbei auf das Filtern der Informationen die man durch den Aufruf des oberen Links bekommt:
Private Function getICQInfos(ByVal uid As String) As String()
Dim Infos() As String
Dim retVal(8) As String
Dim web As WebClient = New WebClient
Infos = web.DownloadString("http://www.icq.com/js/pcc.php?Uin=" & uid).Split(vbNewLine)
'Zeile - Inhalt
'3 - fullname
'6 - userinfo
'9 - onlinestatus
'10 - email
'11 - handynummer
'13 - homepage
'14 - icq uin
'16 - userphoto
'17 - hausnummer
'18 - useronlineicon
'19 - nickname
'Vor und Nachnamen laden
retVal(0) = Infos(3).Substring(Infos(3).IndexOf("""") + 1, _
Infos(3).Length - 3 - Infos(3).IndexOf(""""))
'Benutzerbeschreibung7)
retVal(1) = Infos(6).Substring(Infos(6).IndexOf("""") + 1, _
Infos(6).Length - 3 - Infos(6).IndexOf(""""))
'Online Status als Zahl
retVal(2) = Infos(9).Substring(Infos(9).IndexOf("""") + 1, 1)
'E-Mailadresse
retVal(3) = Infos(10).Substring(Infos(10).IndexOf("""") + 1, _
Infos(10).Length - 3 - Infos(10).IndexOf(""""))
'Homepage
retVal(4) = Infos(13).Substring(Infos(13).IndexOf("""") + 1, _
Infos(13).Length - 3 - Infos(13).IndexOf(""""))
'Benutzerfoto URL 'jaja ich weis coole formel
retVal(5) = Infos(16).Substring(Infos(16).IndexOf(""") + 6, _
(Infos(16).Length - (Infos(16).IndexOf(""") + 6)) _
- (Infos(16).Length - (Infos(16).IndexOf("" "))))
'User Online Icon URL
retVal(6) = Infos(18).Substring(Infos(18).IndexOf("""") + 1, _
Infos(18).Length - 4 - Infos(18).IndexOf(""""))
'Nickname
retVal(7) = Infos(19).Substring(Infos(19).IndexOf("""") + 1, _
Infos(19).Length - 3 - Infos(19).IndexOf(""""))
web.Dispose()
Return retVal
End Function
Ich habe hier in dem Beispiel nicht alle Informationen gefiltert, aber für die Demo hier wirds wohl reichen!
Habt ihr auch schon mit solchen ICQ Skripts herumexperimentiert? Schreibt ein Kommentar mit euren Tools.
Das Demoprojekt gibts hier: Download





