Countdown Programm aktualisiert
29. Dec 2009 2:29 (edit)
Da das Jahr sich ja langsam aber sicher dem Ende neigt, ich Urlaub und zudem ein kleines Projekt zum Überarbeiten gesucht habe, bot es sich irgendwie an, Countdown zu aktualisieren.

- Neu: Neue Aktion "Schriftfarbe zufällig ändern"
- Neu: Anzeigeformat der Restzeit konfigurierbar
- Neu: Schrift lässt sich auf Wunsch frei im Fenster positionieren. Hierzu mit Strg-Linksklick das Label positionieren oder mit der Tastatur via (Strg) und hoch/runter links/rechts
- Neu: Interne Programmprotokollierung mit NLog
- Verbessert: Alle Aktionen in Threads ausgelagert
- Verbessert: Vollbild Modus überdeckt nun in allen Windows Versionen die Taskleiste korrekt und kann mit Escape geschlossen werden.
- Verbessert: Korrekte Positionierung des Textes beim Ändern der Fenstergröße
- Verbessert: Shortcuts für Notebooks ohne Ziffernblock angepasst
- Verbessert: Kontextmenü aufgeräumt
- Änderung: Modifikator-Taste geändert von Umschalt auf Steuerung.
- Weitere kleinere Änderungen
Die neue Version von Countdown findet sich auf der Programmseite.
Mit NLog unter .NET protokollieren
08. Nov 2009 14:58 (edit)

Wer kennt das nicht? Mal eben ein kleines Programm geschrieben, an die Anwender verteilt und auf irgendeinem Rechner läuft das Programm nicht wie es soll.
Nun ist guter Rat teuer, denn welcher Programmierer gibt sich schon die Mühe in kleinere Tools eine ausgefeilte Protokoll-Funktion zu implementieren um dem Fehler gegebenenfalls schnell auf die Schliche zu kommen?
Mit NLog ist das anders. NLog ist ein Framework fürs Protokollieren unter .NET. Ist der Verweis zu NLog im Projekt erst einmal eingebunden, kann man mit einer Zeile wie
Me.Logger.Warn(ex.Message)
eine Exception inklusive aufrufender Methode und kompletter Exception-Fehlerausgabe protokollieren.
Auf der NLog Webseite ist zwar relativ einfach beschrieben, wie man das Framework in das eigene Projekt einbaut, was ich hier im folgenden allerdings beschreibe, ist noch etwas kürzer, da ausschließlich für VB .NET.
Verweis einbinden
Bevor man das NLog Framework verwenden kann, muss man als Verweis die NLog.dll zum Projekt hinzufügen. Hierzu lädt man auf der Codeplex Projekteseite von NLog am einfachsten die vorkompilierte DLL herunter (man kann sich natürlich auch den Quellcode schnappen und selbst kompilieren :-).
Konfigurationsdatei erstellen
Es gibt zwar viele Varianten, wie NLog nach einer Konfigurationsdatei sucht, aber die einfachste ist, eine Datei namens "nlog.config" im Programmverzeichnis zu erstellen.
Als Inhalt dieser Datei empfehle ich für Anfänger folgendes:
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <targets> <target name="file" xsi:type="File" layout="${longdate} ${logger} ${callsite} ${message} ${exception:Format=tostring} ${newline}" fileName="${basedir}/${windows-identity:domain=false}.log"/> </targets> <rules> <logger name="*" minlevel="Debug" writeTo="file"/> </rules> </nlog>
In der Konfigurationsdatei wird mit dem Tag "Target" bestimmt, wohin der Protokolleintrag wandern soll.
Das Target vom Typ "file" beispielsweise schreibt alle Einträge in eine Datei. Außer der Möglichkeit Protokolleinträge in Dateien zu schreiben, bietet NLog dem Benutzer auch eine Mail, ein Textcontrol, ein Netzwerk, das Windows Ereignisprotokoll einen Webservice und eine per ADO.NET ansprechbare Datenbank als Ziel an. Darüberhinaus ist es auch noch möglich, sich eigene Targets, wie beispielsweise einen FTP-Server, zu schreiben. Und natürlich kann man auch mehrere Targets gleichzeitig befüllen.
Im obigen Beispiel wir als Ziel eine Datei verwendet, deren Dateiname aus dem Windows-Benutzername besteht. Die Datei wird dabei automatisch in Unterordnern gelagert, deren Name aus dem aktuellen Datum generiert wird.
Der Tag "Layout" beschreibt dabei, wie die Protokolleinträge formatiert bzw. ergänzt werden.
Der Platzhalter "${longdate}" wird durch das Datum, der Platzhalter "${logger}" durch den Namen der Logging-Klasse, "${callsite}" durch die aufrufende Methode und schließlich "${message}" als die eigentliche Protokollmeldung ersetzt.
Der Zusatz "${exception:Format=tostring}" regelt, dass Exceptions inklusive der Detailmeldungen erfasst werden. Der Platzhalter "${newline}" schließlich, fügt einen Zeilenumbruch am Ende der Meldung ein.
Verwendung
Im Programm selbst, greift man auf NLog beispielsweise so zu:
Public Logger as NLog.Logger = NLog.LogManager.GetCurrentClassLogger ... Me.Logger.Info("Dies ist ein Test") Me.Logger.Warn(ex.Message)
VB .NET: MSI Pakete automatisch installieren
09. Jun 2009 6:41 (edit)
Dieses kleine Modul installiert alle MSI-Pakete, die im aktuellen Programmverzeichnis gefunden werden im "Quiet"-Modus, d. h. ohne irgendwelche Nachfragen.
Module modMain Sub Main() Console.WriteLine("Installiere MSI Pakete...") Try RunAll() Catch ex As Exception Console.WriteLine("Fehler: " & ex.Message) Console.WriteLine("Bitte drücken Sie eine beliebige Taste zum Beenden.") Console.ReadLine() End Try Console.WriteLine("Installation abgeschlossen.") End Sub ''' <summary> ''' Nach MSI-Paketen im aktuellen Verzeichnis (dieser EXE) suchen und alle MSI-Pakete ''' nacheinander ausführen. ''' </summary> ''' <remarks></remarks> Public Sub RunAll() Dim lstFiles As Collections.ObjectModel.ReadOnlyCollection(Of String) = _ My.Computer.FileSystem.GetFiles(Environment.CurrentDirectory, FileIO.SearchOption.SearchTopLevelOnly, "*.MSI") For Each fn As String In lstFiles ExecuteAndWait(fn, "/quiet") Next End Sub ''' <summary> ''' Einen Prozess starten und auf dessen Ende warten ''' </summary> ''' <param name="ProcessPath">Name der Datei die ausgeführt werden soll</param> ''' <param name="Arguments">Optionale Parameter</param> ''' <remarks></remarks> Public Sub ExecuteAndWait(ByVal ProcessPath As String, Optional ByVal Arguments As String = "") Dim proc As System.Diagnostics.Process Try proc = New System.Diagnostics.Process() proc.StartInfo.FileName = ProcessPath proc.StartInfo.Arguments = Arguments proc.StartInfo.WindowStyle = ProcessWindowStyle.Normal proc.Start() proc.WaitForExit() proc.Close() Catch ex As Exception MsgBox(String.Format("Prozess {0} konnte nicht gestartet werden. Fehler: {1}.", ProcessPath, ex.Message)) End Try End Sub End Module
HowTo: VB .NET Barcodes und Reports
27. Apr 2009 9:54 (edit)

Wir haben in den letzten Tagen nach einer Möglichkeit gesucht, in Crystal Reports Barcodes anzuzeigen, und zwar so, dass man sie nachher mit einem Barcode Scanner auch wieder einlesen kann.
Um dies zu tun habe ich nach einer kostenlosen Open-Source Variante gesucht.
Nach unzähligen Versuchen fand ich dann endlich das Barcode Rendering Framework ZEN auf Codeplex.com.
Das Framework kann über Verwendung der drei DLLs als Verweis recht simpel eingebunden werden. Es beherrscht folgende Varianten:
- Code 11 (mit oder ohne Prüfsumme)
- Code 25 standard/interleaved (mit oder ohne Prüfsumme)
- Code 39 (mit oder ohne Prüfsumme)
- Code 93 (nur mit Prüfsumme)
- Code 128 (nur mit Prüfsumme)
- Code EAN 13 (nur mit Prüfsumme)
- Code EAN 8 (nur mit Prüfsumme)
- Code PDF417 2D (mit Prüfsumme)
Im Prinzip wird im Code unten folgendes gemacht:
- Barcode Bild erstellen und als temporäre Datei abspeichern
- Das abgespeicherte Bild in ein Dataset laden, damit wir es im Report anzeigen können
Das Dataset, das der Report verwendet, besitzt nur zwei Spalten. Eine namens ImageFilename (vom Typ String) welche den Dateinamen des temporären Barcode Bildes enthält, und eine namens Image (vom Typ base64Binary bzw. System.Byte()), die das Bild selbst enthält.
Public Sub ShowRepDemo() ' Barcode-Bild erstellen und als temporäre Datei abspeichern Dim tmpfile As String tmpfile = My.Computer.FileSystem.GetTempFileName & ".bmp" Zen.Barcode.BarcodeDrawFactory.Code128WithChecksum.Draw("Dies ist ein Barcode 128 Test", 30).Save(tmpfile) Dim ds As New dsMain ' Barcode Bild in Datatable schreiben ds.dtImage.AdddtImageRow(tmpfile, Nothing) ' Image binär in Datatable schreiben For index As Integer = 0 To ds.Tables(0).Rows.Count - 1 If Not String.IsNullOrEmpty(ds.Tables(0).Rows(index).Item("ImagePath").ToString) Then LoadImage(ds.Tables(0).Rows(index), "Image", ds.Tables(0).Rows(index).Item("ImagePath").ToString) End If Next ' Report öffnen Dim rptdoc As New repDemo rptdoc.SetDataSource(ds.Tables(0)) Dim rv As New CrystalDecisions.Windows.Forms.CrystalReportViewer rv.Dock = DockStyle.Fill Me.Controls.Add(rv) rv.ReportSource = rptdoc End Sub ' Bild in DataTable schreiben Private Sub LoadImage(ByVal objDataRow As DataRow, ByVal strImageField As String, ByVal FilePath As String) Try Dim fs As System.IO.FileStream = New System.IO.FileStream(FilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read) Dim Image() As Byte = New Byte(fs.Length) {} fs.Read(Image, 0, CType(fs.Length, Integer)) fs.Close() objDataRow(strImageField) = Image Catch ex As Exception Throw New Exception(ex.Message) End Try end Sub
VB .NET - E-Mails mit Indy empfangen und Anhänge abspeichern
21. Apr 2009 19:50 (edit)

Um in VB .NET E-Mails zu versenden, verwendet man am besten den Namespace Net.Mail.
Leider gibt es in VB .NET allerdings noch keine Möglichkeit, E-Mails zu empfangen um beispielsweise die Dateianhänge abzuspeichern.
Um dieses Problem zu beseitigen, zeige ich im Folgenden, wie man mit Hilfe von Indy eine E-Mail von einem POP3 Postfach herunterlädt und eventuelle Anhänge der E-Mails auf dem Dateisystem abspeichert.
Wichtig, zur Verwendung von Indy muss als Referenz die Indy.Sockets und Mono.Security DLL in das Projekt eingebunden werden.
Zu erst einmal eine kleine Hilfsklasse, in der wir die Konten-Informationen unseres POP3 Kontos ablegen:
Public Class MailAccount ''' <summary> ''' Hostname des E-Mail Servers ''' </summary> ''' <remarks></remarks> Public Host As String ''' <summary> ''' Benutzername des E-Mail Kontos ''' </summary> ''' <remarks></remarks> Public Username As String ''' <summary> ''' Benutzer-Passwort des E-Mail Kontos ''' </summary> ''' <remarks></remarks> Public Password As String End Class
Nun der interessantere Teil. Die Methode SaveAllAttachments speichert vom übergebenen Mailkonto alle Anhänge aller E-Mails temporär auf der Festplatte lokal ab.
Hierfür verbinden wir uns erst mit dem Mailkonto, ermitteln dann die Menge aller E-Mails auf dem Postfach und iterieren dann durch jede einzelne E-Mail.
Eine E-Mail besteht aus mehreren sogeannten Messageparts. Ist ein Messagepart vom Typ Octet-Stream, handelt es sich um einen Dateianhang, den wir ja abspeichern wollen.
Public Class IndyTools ''' <summary> ''' Speichert alle Dateianhänge des Postfachs aAccount im Servicevertrags-Verzeichnis des jeweils ermittelten Servicevertrags ''' </summary> ''' <param name="aAccount">Postfach Konto</param> ''' <remarks></remarks> Public Sub SaveAllAttachments(ByVal aAccount As MailAccount) Dim tempfilename As String Dim IsAttachment As Boolean Dim o As NewIndy.Sockets.TIdNetNativeComponent Dim p As NewIndy.Sockets.POP3(o) Dim att As Indy.Sockets.Attachment ' Verbindungsdaten an Indy übergeben With p .Host = aAccount.Host .Username = aAccount.Username .Password = aAccount.Password End With Try Try ' Verbinden und Mailmenge feststellen p.Connect() ' Anzahl er Mails auf dem Postfach ermitteln Dim Amount As Integer = p.CheckMessages ' Für alle Mails For i As Integer = 1 To Amount ' Mail abholen Dim msg As New Indy.Sockets.Message p.Retrieve(i, msg) ' Für jeden Messagepart For x As Integer = 1 To msg.MessageParts.Count - 1 ' Ist dieser Messagepart ein Anhang? IsAttachment = msg.MessageParts.Items(x).ContentType = "application/octet-stream" If IsAttachment Then Try ' Anhang holen att = msg.MessageParts.Items(x) ' Anhang temporär speichern tempfilename = System.IO.Path.GetTempFileName att.SaveToFile(tempfilename) Catchex As Exception MsgBox(ex.Message, MsgBoxStyle.Critical) End Try End If Next Next Catch ex As Exception MsgBox(ex.Message, MsgBoxStyle.Critical) End Try Finally p.Disconnect() p.Dispose() End Try End Sub End Class
Hier noch ein Modul mit einem kleinen Beispielaufruf obiger Klassen:
Module modTest Sub Main() Dim it As New IndyTools Dim ac As New MailAccount ac.Username = "frank.miller@gmx.net" ac.Password = "BestMovie300" ac.Host = "pop.gmx.de" it.SaveAllAttachments(ac) End Sub End Module
VB .NET - DataTable nach Excel exportieren
28. Jan 2009 20:05 (edit)

Da ich heute ein DataTable möglichst schnell und einfach als Bericht brauchte, habe ich nach einer Möglichkeit gesucht, dieses DataTable nach Excel zu exportieren.
Irgendwo im Internet habe ich dann folgenen, leicht abgeänderten Schnipsel entdeckt (die Quelle weiß ich leider nicht mehr).
Da ich das sicherlich noch häufiger brauche und andere eventuell auch, poste ich den Code mal hier.
Als Referenz muss das Excel COM Objekt zu den Projekt Referenzen hinzugefügt werden.
''' <summary> ''' Export a DataTable into an Excel Datasheet ''' </summary> ''' <param name="aDataTable"></param> ''' <param name="aOutputFilename"></param> ''' <returns></returns> ''' <remarks></remarks> Public Shared Function DatatableToExcel(ByVal aDataTable As DataTable, ByVal aOutputFilename As String) As Boolean Dim app As New Excel.ApplicationClass Dim wb As Excel.Workbook Dim ws As Excel.Worksheet wb = app.Workbooks.Add() ws = wb.ActiveSheet() Dim dc As DataColumn Dim dr As DataRow Dim colIndex As Integer Dim rowIndex As Integer ' Columns erstellen For Each dc In aDataTable.Columns colIndex += 1 app.Cells(1, colIndex) = dc.ColumnName Next ' Rows hinzufügen For Each dr In dt.Rows rowIndex += 1 colIndex = 0 For Each dc In aDataTable.Columns colIndex += 1 app.Cells(rowIndex + 1, colIndex) = dr(dc.ColumnName) Next Next ws.Columns.AutoFit() wb.SaveAs(aOutputFilename) app.Workbooks.Open(aOutputFilename) ' Excel anzeigen wenn fertig exportiert app.Visible = True Return True End Function
Update am 01.12.2009:
Da ich immer häufiger auf die obigen Funktionen zugreife, habe ich meine Klasse ExcelTools mittlerweile etwas ergänzt. Wer möchte, kann sich den Quellcode hier herunter laden.
Projekt Vorschau
23. Jan 2009 16:01 (edit)
Hier eine kleine Vorschau des Projekts an dem ich gerade arbeite.

Wie man hoffentlich sieht, handelt es sich um einen App Launcher, also so etwas wie Launchy. Wenn das Projekt fertig ist, soll das Programm aber mehr können, als nur Programme zu öffnen. Ich habe folgendes geplant:
- Starten, Beenden (und Bearbeiten) von Programmen
- Öffnen und Bearbeiten von Dateien
- Arbeiten mit markierten Dateien, Ordnern und Text
- Index Unterstützung, d. h. eigene Indexer können beliebige Objekte (wie Mails, Termine, usw.) indexieren, mit denen dann gearbeitet werden kann.
- Plugin Unterstützung, d. h. eigene Aktionen für Objekte können geschrieben werden. Beispielsweise könnte ein Mail Plugin E-Mails an indexierte Kontakte versenden, ein Packer-Plugin könnte markierte Ordner zipppen und via FTP-Plugin hochladen
- Skin Unterstützung
- Einfache(ste) Bedienung
Das wichtigste an diesem Programm wird die einfache Bedienung sein (auch wenn ich das als letzten Punkt in der Liste aufgeführt habe). So soll es mit nur wenigen Tastendrücken möglich sein, beispielsweise in Windows markierte Dateien zu zippen, zu verschlüsseln und anschließend auf einen FTP Server zu laden.
Dabei werden Plugins miteinander verknüpft die unterschiedliche Objekte an das nächste vom Benutzer ausgewählte Plugin zurückliefern.
Gemäß obigem Beispiel:
Ausgewählte Dateien -> Plugin: ZIP -> Gezippte Dateien -> Plugin: Verschlüsselung -> Verschlüsselte Dateien -> Plugin: FTP -> Auswahl FTP-Verbindungsdaten -> Fertig.
Wer Quicksilver für den Mac kennt, wird sicherlich viele Gemeinsamkeiten entdecken, was daran liegt, dass Quicksilver für mich eine Art inspirierende Vorlage war (was es für Windows Alternativen zu Quicksilver gibt, hat Lifehacker übrigens in diesem Artikel zusammengefasst).
Bis das alles so funktioniert wie ich das gerne hätte, muss ich aber noch einiges an Arbeit in das Projekt stecken. Ein Schritt in diese Richtung ist allerdings bereits gemacht.
