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
j.römer
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).


/// 
/// 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
j.römer
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:
// 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
Johannes Römer
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
Johannes Römer
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:

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
Johannes Römer
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.

<?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
j.römer
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.

<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
Johannes Römer
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.

///////////////////////////////////////////////
// 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
j.römer
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.

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
Johannes Römer
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.

public void OpenAs( string filename )
{
    ProcessStartInfo proc = new ProcessStartInfo( "rundll32.exe" );
    proc.Arguments = "shell32.dll, OpenAs_RunDLL " + filename;
    Process.Start( proc );
}