Johannes Römer
Im Rahmen meiner Tätigkeit als Softwareentwickler habe ich hauptsächlich mit allen möglichen Microsoft Technologien zu tun. In diesem Blog sammle ich jede Menge nützlicher Kleinigkeiten, die anderen helfen können. Sie finden hier Tips zu älteren Entwicklungsumgebungen wie Visual Studio 6 bis zu Visual Studio .NET 2008. Aber auch andere Programmiersprachen wie PHP und XSLT kommen hier dran.
Fühlen Sie sich frei, die Codeschnipsel zu verwenden. Ich bitte Sie jedoch, so anständig zu sein und die Kommentarzeilen von mir als Author beizubehalten.
Entwickler Blog
Durch einen Klick auf den Titel wird ein Beitrag angezeigt.
Auflisten aller ODBC-Datenquellen
26. May.2009
C# DOTNET ASP.NET
In einem Projekt musste ich dem Anwender die Auswahl der Datenbank anbieten. Die verfügbaren Datenbanken sind alle als ODBC-Datenquelle registriert.
Über die ODBC-Klassen in DOTNET habe ich keine passende Funktion gefunden. Der Lösungsweg ist also, in der Registry die data source names (DSN) zu suchen. Hier gibt es bekanntlich system- und benutzerdefinierte Einträge. Die folgende Property-Funktion liefert eine Liste aller Namen als String-Array (weil die Combobox direkt damit gefüllt werden kann).
Über die ODBC-Klassen in DOTNET habe ich keine passende Funktion gefunden. Der Lösungsweg ist also, in der Registry die data source names (DSN) zu suchen. Hier gibt es bekanntlich system- und benutzerdefinierte Einträge. Die folgende Property-Funktion liefert eine Liste aller Namen als String-Array (weil die Combobox direkt damit gefüllt werden kann).
////// Property: ConnectionNames /// Autor: Johannes Römer /// Dieses Property liefert ein Feld mit allen registrierten ODBC-Datenquellen /// aus den System- und Benutzereinstellungen /// public static string[] ConnectionNames { get { string[] result1 = null; string[] result2 = null; string[] result = null; using (RegistryKey sysDSN = Registry.LocalMachine.OpenSubKey("SOFTWARE\\ODBC\\ODBC.INI\\ODBC Data Sources")) { result1 = sysDSN.GetValueNames(); sysDSN.Close(); } using (RegistryKey sysDSN = Registry.CurrentUser.OpenSubKey("SOFTWARE\\ODBC\\ODBC.INI\\ODBC Data Sources")) { result2 = sysDSN.GetValueNames(); sysDSN.Close(); } result = new string[result1.Length + result2.Length]; int i = 0; foreach (string n in result2) { result[i] = n; i++; } foreach (string n in result1) { result[i] = n; i++; } return result; } }
Wie fügt man ein Copyright Vermerk in eigene Bilder ein?
19. May.2009
C# DOTNET GDI+
Anforderung:
Bilder sollen auf einen Webserver kopiert werden. Damit die Bilder nicht ohne Copyright Vermerk in das Internet diffundieren, sollen sie alle mit einem Copyright Vermerk versehen werden. Dazu wird eine Funktion benötigt, die die Bilder beim Kopieren in das Webverzeichnis mit einem Copyright Vermerk versieht.
Lösungsansatz
Zwei Funktionen stelle ich hier vor. Beide Funktionen lesen zunächst das Originalbild. Die erste Funktion fügt in die untere, rechte Ecke einen Text ein. Die zweite Funktion fügt dort ein Bild ein. Dabei wird davon ausgegangen, das die Hintergrundfarbe des Copyright-Bildes weiss ist. Die Hintergrundfarbe wird beim Kopieren transparent gemacht:
Variante 1:
Variante 2:
Bilder sollen auf einen Webserver kopiert werden. Damit die Bilder nicht ohne Copyright Vermerk in das Internet diffundieren, sollen sie alle mit einem Copyright Vermerk versehen werden. Dazu wird eine Funktion benötigt, die die Bilder beim Kopieren in das Webverzeichnis mit einem Copyright Vermerk versieht.
Lösungsansatz
Zwei Funktionen stelle ich hier vor. Beide Funktionen lesen zunächst das Originalbild. Die erste Funktion fügt in die untere, rechte Ecke einen Text ein. Die zweite Funktion fügt dort ein Bild ein. Dabei wird davon ausgegangen, das die Hintergrundfarbe des Copyright-Bildes weiss ist. Die Hintergrundfarbe wird beim Kopieren transparent gemacht:
Variante 1:
// Kopiert ein Bild und fügt dabei noch schnell den Copyright-Vermerk ein private void CopyWithCopyright1( FileInfo src, string destpath, string copyright ) { // Hier wird das Wasserzeichen eingebaut Bitmap bmpOriginal = new Bitmap(src.FullName); Bitmap bmpDest = new Bitmap(bmpOriginal); // Das Bild unbedingt freigeben, da es im Zweifelsfall viel zu spät freigegeben wird bmpOriginal.Dispose(); // Zeichenumgebung, Schriftart und Schriftgröße bestimmen Graphics g = Graphics.FromImage(bmpDest); Font fnt = new Font("ARIAL", 12); SizeF sizeCopyright = g.MeasureString( copyright, fnt ); // Versetztes Schreiben in die rechte untere Ecke mit schwarz und weiss g.DrawString( copyright, fnt, Brushes.White, bmpDest.Width - sizeCopyright.Width - 1, bmpDest.Height - sizeCopyright.Height - 1 ); g.DrawString( copyright, fnt, Brushes.Black, bmpDest.Width - sizeCopyright.Width, bmpDest.Height - sizeCopyright.Height ); // Bild speichern und Resourcen gleich wieder freigeben bmpDest.Save(destpath); bmpDest.Dispose(); }
Variante 2:
// Kopiert ein Bild und fügt dabei noch schnell den Copyright-Vermerk ein
private void CopyWithCopyright2( FileInfo src, string destpath, string pathCopyright )
{
// Hier wird das Wasserzeichen eingebaut
Bitmap bmpWasserzeichen = new Bitmap( pathCopyright );
// Bild laden und mit Kopie arbeiten, damit Resource auf Original gleich freigegeben wird
Bitmap bmpOriginal = new Bitmap(src.FullName);
Bitmap bmpDest = new Bitmap(bmpOriginal);
bmpOriginal.Dispose();
// Handle auf Zeichendevice
Graphics g = Graphics.FromImage(bmpDest);
// Das Rechteck für die rechte untere Ecke
Rectangle rectDest = new Rectangle( bmpDest.Width-bmpWasserzeichen.Width,
bmpDest.Height-bmpWasserzeichen.Height, bmpWasserzeichen.Width, bmpWasserzeichen.Height);
// Weiss ist Transparentfarbe
System.Drawing.Imaging.ImageAttributes a = new System.Drawing.Imaging.ImageAttributes();
a.SetColorKey(Color.White, Color.White);
// Jetzt wird das Wasserzeichen gezeichnet
g.DrawImage(bmpWasserzeichen, rectDest, 0, 0, bmpWasserzeichen.Width,
bmpWasserzeichen.Height, GraphicsUnit.Pixel, a);
// Geändertes Bild speichern
bmpDest.Save(destpath);
// Resourcen freigeben
bmpDest.Dispose();
bmpWasserzeichen.Dispose();
}
Wie erstellt man ein Vorschaubild (Thumbnail)
03. May.2009
C# DOTNET GDI+
In manchen Anwendungen werden Bilder in verkleinerter Darstellung als sog. Thumbnails dargestellt. Für die Erstellung von Thumbnails kann die Klasse Bitmap verwendet werden. Diese hat eine Methode das Thumbnail darzustellen. Aber Achtung, die Qualität der Bilder ist je nach verwendeter Kamera sehr unterschiedlich. Microsoft empfiehlt, die Bilder nicht größer als 120x120 Pixel groß zu machen.
// // Thumbnail creation from Johannes Römer // see: http://www.johannes-roemer.de // // Dummy method is called when thumbnail is created bool ThumbnailHandlerMethod() { return false; } // This method creates a thumbnail from a source image and stores the // thumbnail als jpg file in Destpath void CreateThumbnail( string Sourcepath, string Destpath ) { Image.GetThumbnailImageAbort myCallback = new Image.GetThumbnailImageAbort(ThumbnailHandlerMethod); Bitmap bmp = new Bitmap( Sourcepath ); int thumbWidth = 120; int thumbHeight = 120; if (bmp.Width > bmp.Height) thumbHeight = thumbHeight * bmp.Height / bmp.Width; else thumbWidth = thumbWidth * bmp.Width / bmp.Width; Image thumb = bmp.GetThumbnailImage(thumbWidth, thumbHeight, myCallback, IntPtr.Zero); thumb.Save( Destpath , System.Drawing.Imaging.ImageFormat.Jpeg); thumb.Dispose(); }
Wie kann man die Tabstops-Abstände im Textbox-Steuerelement ändern?
01. May.2009
C# WINFORMS WINAPI
Das Steuerelement System.Windows.Forms.TextBox hat bei der Tab-Taste sehr große Tabulator-Abstände. Um diese Abstände zu verkleinern hat Microsoft eine entsprechende Funktion vergessen, die das Original-Windows Steuerelement aber eigentlich hat.
Dazu gibt es die Fensternachricht EM_SETTABSTOPS. Um diese Nachricht zu verschicken benötigen wir die Windows-API Funktion SendMessage(...).
Importieren Sie zunächst den InteropService der hilft, Windows-Funktionen aufzurufen. Importieren Sie dann die Funktion SendMessage und rufen Sie diese wie im folgenden Beispiel auf:
Dazu gibt es die Fensternachricht EM_SETTABSTOPS. Um diese Nachricht zu verschicken benötigen wir die Windows-API Funktion SendMessage(...).
Importieren Sie zunächst den InteropService der hilft, Windows-Funktionen aufzurufen. Importieren Sie dann die Funktion SendMessage und rufen Sie diese wie im folgenden Beispiel auf:
using System.Runtime.InteropServices; ... public const int EM_SETTABSTOPS = 0x000000cb; [DllImport("user32.dll")] public static extern IntPtr SendMessage(IntPtr h, int msg, int wParam, int[] lParam); public MyForm() { InitializeComponent(); .... int[] tabs = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120 }; IntPtr result = SendMessage(txtContent.Handle, EM_SETTABSTOPS, tabs.Length, tabs); .... }
XML Transformation in PHP
04. Apr.2009
PHP XSLT XML
Sie haben z.B. einen RSS Feed auf Ihrem Server und wollen den Inhalt in das Layout Ihrer Seiten einbinden?
Ihnen steht als Programmiersprache PHP zur Verfügung. Dann habe ich hier das Richtige.
Ihnen steht als Programmiersprache PHP zur Verfügung. Dann habe ich hier das Richtige.
<?php /////////////////////////////////////////// // XML-Transformation für PHP-Seiten // Autor: Johannes Römer // Datum: irgendwann zwischen 2001 und 2005 :-) // Der Skript dient dazu eine Webseite - oder Teile davon - aus einer XML-Datei zu erstellen // Für die Darstellung wird das XML in xhtml umgewandelt. // Zur Umwandlung wird ein XSLT-Script verwendet /////////////////////////////////////////// // Hier die Namen der Dateien $xslfile = "meinscript.xsl"; $xmlfile = "meindocument.xml"; // Loading the XLST transformation script $xsl = new DOMDocument; $xsl->load( $xmlfile ); // Configure the transformer $proc = new XSLTProcessor; $proc->importStyleSheet( $xslfile ); // attach the xsl rules // Load the source rss feed $xml = new DOMDocument; $xml->load('samplefeed.xml'); // output the transformed content echo $proc->transformToXML($xml); ?>
XML Transformation in VBScript
03. Apr.2009
VBScript XSLT XML ASP
Sie haben z.B. einen RSS Feed auf Ihrem Server und wollen den Inhalt in das Layout Ihrer Seiten einbinden?
Als Server setzen Sie einen Microsoft Internet Information Server ein und Sie verwenden als Programmiersprache z.B. Visual Basic Script.
Dazu habe ich den folgenden kleinen Script vorbereitet, den Sie in Ihre Webseite einbinden können. Hier habe ich auch ein klein wenig Fehlerbehandlung eingebaut. Wie Sie wissen ist das in VBScript etwas eingeschränkt.
Als Server setzen Sie einen Microsoft Internet Information Server ein und Sie verwenden als Programmiersprache z.B. Visual Basic Script.
Dazu habe ich den folgenden kleinen Script vorbereitet, den Sie in Ihre Webseite einbinden können. Hier habe ich auch ein klein wenig Fehlerbehandlung eingebaut. Wie Sie wissen ist das in VBScript etwas eingeschränkt.
<script language="VBScript" runat="server" > '''''''''''''''''''''''''''''''''''''''''''''''' ' XML-Transformation für ASP-Seiten ' Autor: Johannes Römer ' Datum: Irgendwann im ersten Jahrzehnt :-) ' http://www.johannes-roemer.de ' ' Das Skript dient dazu ganze Webseiten oder Teile davon aus ' einer XML-Datei (z.B. RSS-File) zu erstellen. ' Für das gewünschte Layout ist ein XSLT-Script verantwortlich '''''''''''''''''''''''''''''''''''''''''''''''' Dim xmlDoc Dim xmlTrans Dim strErr Dim strDocPath Dim strXSLPath On Error Resume Next Set xmlTrans = Nothing Set xmlDoc = Nothing strErr = "" ' Tragen Sie hier die Pfade auf Ihr Dokument und das Transformationsfile ein strDocPath = "Testdoc.xml" strXSLPath = "Testxsl.xsl" set xmlDoc = CreateObject( "MSXML.DomDocument" ) If xmlDoc.Load( strDocPath ) = False Then strErr = "Error loading document! " & xmlDoc.ParseError.reason end if If strErr = "" Then Set xmlTrans = CreateObject( "MSXML.DomDocument" ) If xmlTrans.Load( strXSLPath ) = False Then strErr = "Error loading transformation code! " & xmlDoc.ParseError.reason End If End If If strErr = "" Then Response.Write xmlDoc.transformNode(xmlTrans) Else Response.Write "<h1>" & strErr & "</h1>" End If </script>
Wie liest man das UNIX-Syslog Protokoll
21. Mar.2009
C# UNIX SYSLOG DOTNET
Anstelle des Windows Ereignisprotokolls gibt es unter Unix den Syslog demon. Ein Unix Programm sendet Nachrichten an den syslog demon normalerweise über eine eigene API. Die demons mehrerer UNIX Systeme können so konfiguriert werden, dass sie alle Nachrichten an einen zentralen Server weiterreichen. Diese Übetragung wird im einfachsten Fall mittels UDP-Messaging durchgeführt.
Der hier vorgestellte Code kann in einen Windows Systemdienst eingebaut werden um diese UDP Syslog Nachrichten zu empfangen.
Den Inhalt der Syslog Nachrichten können Sie in Wikipedia nachschlagen.
Der hier vorgestellte Code kann in einen Windows Systemdienst eingebaut werden um diese UDP Syslog Nachrichten zu empfangen.
Den Inhalt der Syslog Nachrichten können Sie in Wikipedia nachschlagen.
/////////////////////////////////////////////// // Reading UNIX syslog messages // Developed by Johannes Roemer, Bonn, Germany // watch http://www.johannes-roemer.de // class MySyslog { ... // This ist the socket connection point for udp/ip messages private UdpClient m_UdpClient = null; // Set this variable to true, to stop background worker private bool m_DoStop = false; // call this method to start background worker public void DoStart() { ThreadStart tsWorker = null; tsWorker = new ThreadStart(this.worker); Thread t = new Thread(tsWorker); t.Start(); } // Background worker reads udp-syslog messages and write to console // visit: http://de.wikipedia.org/wiki/Syslog // to learn how to interprete messages private void worker() { IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0); int maxwait = 500; // Die Endlosschleife while (m_DoStop == false) { // Erstellen des UdpClient mit Standard-Port m_UdpClient = new UdpClient(514); // auf Nachricht warten Byte[] receiveBytes = m_UdpClient.Receive(ref RemoteIpEndPoint); // Nachricht in einen String verwandeln zerpflücken string returnData = Encoding.ASCII.GetString(receiveBytes); Console.WriteLine( returnData ); } // while... m_UdpClient = null; } }
Wie erstelle ich eine Ablage für meine Fotos
10. Feb.2009
C# DOTNET
Meine Fotos aus meiner Digitalkamera sortiere ich in eine Verzeichnisstruktur, die nach Jahr, Monat und Tag gegliedert ist. Es gibt also ein Verzeichnis für das Jahr 2001, 2002, usw. Darunter wieder Verzeichnisse für die Monate und unter diesen wieder für jeden Tag ein Verzeichnis. Das hatte ich bisher immer von Hand sortiert. Um diesen Vorgang zu automatisieren habe ich folgendes kleine Programm in C# geschrieben.
Das Programm liegt auf dem Desktop und ich schiebe das Verzeichnis mit den Bildern aus der Kamera mit Drag&Drop auf das Programmsymbol. Daraufhin werden alle Bilder aus dem Verzeichnis in mein Bildarchiv verschoben. Versehentliche Mehrfachkopien werden verhindert, in dem die Dateien mit bereits vorhandenen Dateien verglichen werden.
Das Programm liegt auf dem Desktop und ich schiebe das Verzeichnis mit den Bildern aus der Kamera mit Drag&Drop auf das Programmsymbol. Daraufhin werden alle Bilder aus dem Verzeichnis in mein Bildarchiv verschoben. Versehentliche Mehrfachkopien werden verhindert, in dem die Dateien mit bereits vorhandenen Dateien verglichen werden.
using System; using System.Collections.Generic; using System.Text; using System.IO; namespace SortImages { class Program { // Verschiebt eine Datei in das Bildarchiv static void SortFile(FileInfo srcFile) { // Die Namen für die Verzeichnisse string sYear = srcFile.LastWriteTime.Year.ToString("0000"); string sMonth = srcFile.LastWriteTime.Month.ToString("00"); string sDay = srcFile.LastWriteTime.Day.ToString("00"); // Das Verzeichnis für das Jahr erstellen DirectoryInfo diYear = new DirectoryInfo(SortImages.Properties.Settings.Default.Destination + sYear); if (diYear.Exists == false) diYear.Create(); // Das Verzeichnis für den Monat erstellen DirectoryInfo diMonth = new DirectoryInfo( diYear + "\\" + sYear + "-" + sMonth ); if (diMonth.Exists == false) diMonth.Create(); // Verzeichnis für den Tag erstellen DirectoryInfo diDay = new DirectoryInfo(diMonth + "\\" + sYear + "-" + sMonth + "-" + sDay); if (diDay.Exists == false) diDay.Create(); // Datei mit evtl. vorhandener Datei vergleichen FileInfo dstFile = new FileInfo( diDay.FullName + "\\" + srcFile.Name ); if (dstFile.Exists) { // Könnte die gleiche Datei sein if (dstFile.Length == srcFile.Length) { dstFile = new FileInfo(srcFile.DirectoryName + "\\EXIST_" + srcFile.Name); } else { // Wenn es sich um eine andere Datei handelt, wird der Dateiname geändert string newName = diDay.FullName + "\\X" + srcFile.Name; dstFile = new FileInfo(newName); } } // Datei verschieben srcFile.MoveTo(dstFile.FullName); } // Programmstart static void Main(string[] args) { try { if (args.Length != 1) throw new Exception("usage: SortImages"); DirectoryInfo srcdir = new DirectoryInfo(args[0]); foreach (FileInfo fi in srcdir.GetFiles()) { SortFile(fi); } } catch( Exception ex ) { Console.WriteLine(ex); } } } }
Aufruf des "Programm auswählen..." Dialoges
11. Dec.2008
C# DOTNET
Eine Datei soll mit einem externen Programm aufgerufen werden. Dabei soll der vom Windows Explorer bekannte Dialog unter dem Kontextmenü "Öffnen mit | Programm auswählen ..." aufgerufen werden.
Zum Aufruf dieses Dialoges gibt es eine System-DLL, in der die gewünschte Funktion steckt. Das Standard-Programm zum Aufrufen solcher Funktionsaufrufe in System-DLLs ist das Programm "rundll32.exe". Dieses benötigt als Parameter den Namen der DLL, sowie die Funktion und die Funktionsparameter.
Zum Aufruf dieses Dialoges gibt es eine System-DLL, in der die gewünschte Funktion steckt. Das Standard-Programm zum Aufrufen solcher Funktionsaufrufe in System-DLLs ist das Programm "rundll32.exe". Dieses benötigt als Parameter den Namen der DLL, sowie die Funktion und die Funktionsparameter.
public void OpenAs( string filename ) { ProcessStartInfo proc = new ProcessStartInfo( "rundll32.exe" ); proc.Arguments = "shell32.dll, OpenAs_RunDLL " + filename; Process.Start( proc ); }