Blog Home  Home Feed your aggregator (RSS 2.0)  
HP's Blog - Wednesday, November 25, 2009
Hans-Peter Schelian's Weblog
 
# Wednesday, November 25, 2009

Seit Heute Morgen ist der erste Release Kandidat der neuen 3.0 Version von Thunderbird verfügbar.

Einen direkten Link zum herunterladen konnte ich zwar nicht finden, aber wer die Beta 4 auf einem Rechner hat, kann mit dem “Auf Update prüfen” seine Version aktualisieren.

Auf dieser Seite finden man die Links zu den Downloads.

Kurz und Bündig | Thunderbird
Wednesday, November 25, 2009 7:29:08 AM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Tuesday, October 27, 2009

Seit ein paar Wochen habe ich eine Logitech MX 3200 Laser Tastatur / Maus Kombination im Einsatz.

Außer der störenden Zoomfunktion am linken Rand bin ich auch sehr zufrieden.

Verzweifelt habe ich nach einer Lösung gesucht diese Zoom Funktion zu deaktivieren und habe nichts gefunden.

Heute bin ich dann durch Zufall auf die Lösung gestoßen.

Hier der Link zur Web Seite mit der Lösung

Besten Dank an Cord-Heinrich Pahlmann

Tips und Tricks
Tuesday, October 27, 2009 3:05:00 PM (W. Europe Standard Time, UTC+01:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Tuesday, September 29, 2009

In einer Windows Anwendung wird in einer Form unter anderem ein (eigentlich sind es zwei, aber dazu später mehr) DateTimePicker verwendet um Termine einzugeben.

Da der DateTimePicker nicht gerade komfortabel ist um sowohl Datum als auch Uhrzeiten einzugeben, wird ein DateTimePicker in der Option DropDownCalender (das ist deaktivierte Eigenschaft ShowUpDown) eingesetzt um das Datum elegant aus dem DropDownCalender auszuwählen und ein zweites DateTimePicker Control mit der gesetzen Eigenschaft ShowUpDown und dem entsprechenden Custom Format HH:mm um nur die Uhrzeit mit den Pfeilen hoch und runter einstellen zu können.

image

Nun ist es aber so, dass man im DateTimePicker keinen Inkrement Wert eingeben kann, um den die Minuten erhöht bzw vermindert werden wenn man einmal auf den Pfeil hoch oder runter klickt. Somit wird jeweils um eine Minute hoch oder runter gezählt.

In meinem Fall nun wollte der Kunde aber das Termine nicht Minutengenau sondern immer auf 15 Minuten (Viertelstunde) Basis, also 00, 15, 30 und 45 erfasst werden können.

Da ich nicht gleich ein eigenen Control entwickeln wollte, habe ich einfach eine kleine Routine in den Change Event des DateTimePicker eingebaut.

Nachfolgend der Code Ich denke die Routine ist selbsterklärend

private void startzeitTimePicker_ValueChanged(object sender, EventArgs e)
{
    DateTimePicker dtp = (DateTimePicker)sender;
    // Wenn nicht Minute nicht 0,15,45 oder 60 dann müssen wir was tun
    if ((((dtp.Value.Minute != 0) && (dtp.Value.Minute != 15)) && (dtp.Value.Minute != 30)) &&
        (dtp.Value.Minute != 45))
    {
        // Auch noch einfach, nur 14 Minuten drauf und gut ist
        if ((dtp.Value.Minute == 1) || (dtp.Value.Minute == 16) || (dtp.Value.Minute == 31) || (dtp.Value.Minute == 46))
        {
            dtp.Value = dtp.Value.AddMinutes(14);
        }
        else
        {
            // Zeit wurde heruntergezählt.
            if ((dtp.Value.Minute == 14) || (dtp.Value.Minute == 29) || (dtp.Value.Minute == 44) || (dtp.Value.Minute == 59))
            {
                int x = 14;     // Deshalb auf jeden Fall mal 14 Minuten abziehen,
                if (dtp.Value.Minute == 59)  // und wenn die Minuten auf 59 stehen, dann muss noch eine Stunde (60 minuten) mehr abgezogen werden
                {
                    x += 60;
                }
                dtp.Value = dtp.Value.AddMinutes(-x);
            }
            else // Wert muss manuell eingegeben worden sein, dann runden wir auf die nächst höhere Viertelstunde
            {
                for (int i = 0; i < 15; i++)
                {
                    int x = dtp.Value.Minute + i;
                    if ((x == 15) || (x == 30) || (x == 45) || (x == 60))
                    {
                        dtp.Value = dtp.Value.AddMinutes(i);
                        break;
                    }
                }
            }
        }
    }
}

Hoffe das hilft dem einen oder anderen (Oder mir selbst beim nächsten mal wenn ich vor dem gleichen Problem stehen Wink)

Code | Tips und Tricks | C#
Tuesday, September 29, 2009 12:39:00 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Friday, August 07, 2009

In einer Anwendung verwende ich eine Klasse um die Appointmens eines Kalenders abzubilden. Diese Klasse ist relativ Komplex und um diesen Beitrag nicht ebenfalls zu komplex werden zu lassen, verwende ich hier eine (sehr) abgespeckte Version dieser Klasse um das Thema Sortierung einer ArrayListe von Komplexen Objekten zu veranschaulichen.
Die Verwendung einer ArrayList war hier zwingend vorgeschrieben (typisierte Listen List<Type> kamen nicht in Frage)

Zuerst einmal die Aufgabenstellung:

In einer ArrayListe (nennen wir Sie AppointmentList) befinden sich Termine in Form von Objekten (nennen wir sie Appointment). Diese Objekte haben unter anderem eine Eigenschaft (Property) Startdatum (vom Type DateTime).

Da die Appointment in der AppointmentList unsortiert vorliegen und eine Sortierung (eigentlich zwei Sortierungen Auf und Absteigend) nach dem Startdatum des Termins benötigt wird, bestand die Aufgabe die AppointmentList zu sortieren.

Die ArrayLIst verfügt über eine Methode Sort. Da es sich bei den zu sortierenden Objekten aber um ein Komplexe Klasse handelt, muss man der Sort Methode einen Comparer an die Hand geben, damit die Methode Sort Ihre Aufgabe durchführen kann.

Hier nun die Umsetzung:

Zuerst einmal die (komplexe) Klasse Appointment (eine abgespeckte Variante)

public class Appointment
{

    public Appointment()
    {
        appointmentGUID = Guid.NewGuid();
    }


    private readonly Guid appointmentGUID = new Guid("00000000000000000000000000000000");

    public Guid AppointmentGUID
    {
        get { return appointmentGUID; }
    }

    private DateTime startDate;

    public DateTime StartDate
    {
        get { return startDate; }
        set
        {
            startDate = value;
            OnStartDateChanged();
        }
    }

    protected virtual void OnStartDateChanged()
    {
    }


    private DateTime endDate;

    public DateTime EndDate
    {
        get { return endDate; }
        set
        {
            endDate = value;
            OnEndDateChanged();
        }
    }

    protected virtual void OnEndDateChanged()
    {
    }



    private string title = "";

    [DefaultValue("")]
    public string Title
    {
        get { return title; }
        set
        {
            title = value;
            OnTitleChanged();
        }
    }

    protected virtual void OnTitleChanged()
    {
    }


    public override string ToString()
    {
        return Title;
    }

}

Der Comparer für diese Aufgabe sieht dann so aus (Methode zum Sortieren mit Implementierung der IComparer Schnittstelle:

public class AppointmentComparer : IComparer
{
    private bool descendSorting;
    public AppointmentComparer(bool descend)
    {
        descendSorting = descend;
    }

    int IComparer.Compare(object a, object b)
    {
        var b1 = (Appointment)a;
        var b2 = (Appointment)b;

        if (descendSorting)
        {
            return DateTime.Compare(b2.StartDate, b1.StartDate);
        }
        else
        {
            return DateTime.Compare(b1.StartDate, b2.StartDate);
        }
    }

}

Und verwenden kann man diesen Comparer wie folgt:

            al.Sort(new AppointmentComparer(false));
            al.Sort(new AppointmentComparer(true));

al wurde dabei wie folgt deklariert:

ArrayList al = new ArrayList();
Code | C#
Friday, August 07, 2009 1:14:00 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Wednesday, August 05, 2009

Beim stöbern in meinen SQL Skripten bin ich gerade wieder auf das hier nachfolgend aufgeführte Skript zur Ausgabe der “Größe aller Tabellen einer Datenbank” gestoßen.

Da ich sicherlich nicht der einzige bin, der diese Informationen einer Datenbank hin und wieder benötigt, veröffentliche ich hier das Skript mit der Hoffnung dass es jemand gebrauchen kann.

SET NOCOUNT ON
CREATE TABLE #TableSpace 
(
	Rows int, 
	DataSpaceUsed int, 
	IndexSpaceUsed int
)
DECLARE @TableSpace table
(
	TableName varchar(255),
	Rows int, 
	DataSpaceUsed int, 
	IndexSpaceUsed int
)
DECLARE @Rows int, @DataSpaceUsed int, @IndexSpaceUsed int
DECLARE @TableName varchar(255)
DECLARE Table_Cursor CURSOR FOR
SELECT	user_name(o.uid) + '.' + o.name AS table_name
FROM	dbo.sysobjects o, dbo.sysindexes i 
WHERE	OBJECTPROPERTY(o.id, N'IsTable') = 1 
	AND i.id = o.id 
	AND i.indid < 2 
	AND o.name NOT LIKE N'#%' 
	AND xtype = 'U'
ORDER BY 1
OPEN Table_Cursor
---------------------------------
--Set Data
FETCH NEXT FROM Table_Cursor INTO @TableName
INSERT INTO #TableSpace (Rows, DataSpaceUsed, IndexSpaceUsed)
EXEC sp_MStablespace @TableName
SELECT	@Rows = Rows, 
	@DataSpaceUsed = DataSpaceUsed,
	@IndexSpaceUsed = IndexSpaceUsed
FROM	#TableSpace
INSERT INTO @TableSpace (TableName, Rows, DataSpaceUsed, IndexSpaceUsed)
VALUES (@TableName, @Rows, @DataSpaceUsed, @IndexSpaceUsed)
DELETE FROM #TableSpace
--------------------------------
WHILE @@FETCH_STATUS = 0


    BEGIN
    	---------------------------------
    	--Set Data
    	FETCH NEXT FROM Table_Cursor INTO @TableName
    	
    	INSERT INTO #TableSpace (Rows, DataSpaceUsed, IndexSpaceUsed)
    	EXEC sp_MStablespace @TableName
    	
    	SELECT	@Rows = Rows, 
    		@DataSpaceUsed = DataSpaceUsed,
    		@IndexSpaceUsed = IndexSpaceUsed
    	FROM	#TableSpace
    	
    	INSERT INTO @TableSpace (TableName, Rows, DataSpaceUsed, IndexSpaceUsed)
    	VALUES (@TableName, @Rows, @DataSpaceUsed, @IndexSpaceUsed)
    	
    	DELETE FROM #TableSpace
    	--------------------------------
END

CLOSE Table_Cursor
DEALLOCATE Table_Cursor
DROP TABLE #TableSpace
SELECT * 
FROM @TableSpace
ORDER BY Rows DESC

Über die Herkunft dieses Skripts (ich weiß dass ich zumindest die Idee von irgendwoher hatte) bin ich mir nicht mehr sicher. Eine gerade durchgeführte Recherche im Internet hat mir auch keinen direkten Aufschluss gegeben woher ich das Skript oder die Idee dazu hatte.

Sollte also jemand die Herkunft kennen, bitte einfach per Kommentar posten.

Tips und Tricks | SQL Server | SQL
Wednesday, August 05, 2009 9:26:38 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [5]  
Autor: Hans-Peter Schelian  |  Trackback
# Wednesday, July 22, 2009

Wenn man die Source Version von DotNetNuke Version 4.09.04 in Visual Studio ausführt und als Browser den Internet Explorer 8 einsetzt, kommt es beim überfahren der Menüs (Admin und Systemmenü) mit der Maus zu folgendem Fehler:

image

Dieser Fehler tritt in der Datei dnn.dom.positioning.js auf.

Die Zeile in welcher der Fehler auftritt lautet:

oIFR.style.zIndex=iIndex-1
Was geschieht ist, dass in der Variablen iIndex anstelle eines Wertes, das Wort “Auto” enthalten ist. Wenn nun versucht wird von dem String “Auto” den Wert 1 abzuziehen, kommt es natürlich zu einem Fehler.

Ich habe eine Lösung gefunden, die für mich funktioniert und nicht die Zeile einfach auskommentiert.

Die Lösung sieht wie folgt aus:

Ich füge am Ende der Datei dnn.dom.positioning.js die Funktion IsNumeric ein:

function IsNumeric(sText)

{
   var ValidChars = "0123456789.";
   var IsNumber=true;
   var Char;

 
   for (i = 0; i < sText.length && IsNumber == true; i++) 
      { 
      Char = sText.charAt(i); 
      if (ValidChars.indexOf(Char) == -1) 
         {
         IsNumber = false;
         }
      }
   return IsNumber;
   
   }

Und verwende diese Funktion wie folgt um den Inhalt der Variable iIndex zu prüfen und im Falle das darin kein numerischer Wert enthalten ist, führe ich die Subtraktion nicht aus.

Anstelle der Zeile (250) mit dem Inhalt oIFR.style.zIndex=iIndex-1;

füge ich nachfolgende 4 Zeilen ein, das sieht dann so aus:

if (IsNumeric(iIndex))
    oIFR.style.zIndex = iIndex - 1;
else
    oCont.style.zIndex = 1;

Nun einfach die Datei dnn.dom.positioning.js speichern und auch Fehlerfrei mit dem IE 8 und der Source Version von DotNetNuke arbeiten.

DotNetNuke | Entwicklung
Wednesday, July 22, 2009 8:52:05 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
# Tuesday, July 21, 2009

Wenn man versucht die Source Version von DotNetNuke 4.09.04 in Visual Studio 2008 zu öffnen und anschließend zu übersetzen, kommt es zu folgender Fehlermeldung:

Fehler	1	Datei "Controls\AJAX\bin\System.Web.Extensions.dll" kann nicht in "..\Website\bin\System.Web.Extensions.dll" kopiert werden. Ein Teil des Pfades "Controls\AJAX\bin\System.Web.Extensions.dll" konnte nicht gefunden werden.	C:\dnn494\Library\DotNetNuke.Library.vbproj	987	5	DotNetNuke.Library

Das Problem entsteht dadurch, dass versucht wird nach dem Übersetzungslauf die Datei System.Web.Extensions.dll aus dem Verzeichnis Controls\AJAX\bin\ in das BIN Verzeichnis von DotNetNuke zu  kopieren.

Dies ist aber gar nicht notwendig, da sich die Datei System.Web.Extensions.dll im GAC befindet.

Um den Fehler zu beheben, kann man die Datei DotNetNuke.Library.vbproj im Library Verzeichnis von DotNetNuke mit einem Texteditor öffnen, und nach dem Eintrag

<Copy SourceFiles="Controls\AJAX\bin\System.Web.Extensions.dll" DestinationFolder="..\Website\bin\" />

suchen, der Steht normal in der Zeile 987.

Diese Eintrag entfernt man und speichert anschließend die Datei ab.

Wenn man nun das Source Projekt mit Visual Studio öffnet und übersetzt sollte das Problem gelöst sein.

DotNetNuke | Entwicklung
Tuesday, July 21, 2009 10:23:55 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]  
Autor: Hans-Peter Schelian  |  Trackback
# Wednesday, July 01, 2009

Nachdem ich mich Gestern über das Thema Ziemlich Sicheres erkennen von SPAM” ausgelassen habe, möchte ich mich Heute, einem mindestens genau so wichtigen Thema, der Virus Erkennung und Abwehr in E-Mails unter Verwendung der hMailServer Bordmittel und lizenzfreien Zusatzprodukten widmen.

Wer den hMailServer einsetzt, wird die Optionen der AntiVirus Einstellungen kennen und sicherlich werden die meisten die einfache Clamwin Integration wählen.

hMailServer - Clamwin Integration

  • Clamwin installieren
  • Use Clamwin aktivieren
  • Auto-detect anklicken

Fertig !

Das ist sicherlich eine gute und einfache Lösung (vor allem ist es eine akzeptable Lösung) wenn auf dem Mail Server wenige Mails (einige Mails pro Stunde) verarbeitet werden. Für Installationen mit höherem Traffic (> 100 Mails/Stunde) stellt diese Installation aber ein echtes Performance Problem dar.

Clamwin benötigt wenn es durch den hMailServer aufgerufen wird um die Mails nach Viren zu untersuchen enorm viel Ressourcen des Computers. Wenn gleichzeitig mehrere Mails im hMailServer eintreffen, werden je nach Einstellungen mehrere Instanzen von Clamwin aufgerufen um die Mails einer Virenprüfung zu unterziehen. Dies führt unweigerlich dazu dass der Server mit nahezu 100% CPU Last nicht mehr viel Luft für andere Aufgaben hat.

Es gibt aber auch hierfür eine Lizenzkostenfreie Lösung und diese arbeitet mit der gleichen Scan Engine wie Clamwin.

image

ClamAV für Windows in der Variante von SOSDG.

Stand Heute ist die aktuelle Version der SOSDG Variante die 0.95-1, diese Version können wir aber für die Integration mit dem hMailServer “leider” nicht nehmen. Ich hoffe aber, dass bald eine fehlerbereinigte Version folgt, die dann die aktuellste ClamAV Engine einsetzen kann.

Um die Integration mit dem hMailServer zu realisieren müssen wir die Version clamav-0.94-2-1a.exe herunterladen und installieren.

Nachfolgend werde ich den Installationsprozess sowie die notwendigen Einstellungen im Detail erläutern.

Diese Anleitung basiert auf dem englischen Forumbeitrag von “rodolfor” im hMailServer Forum.

Schritt für Schritt Anleitung, oder in 9 Schritten zu einer performanten kostengünstige AntiVirus Lösung für hMailServer)

1. Herunterladen der clamav-0.94-2-1a Version

2. Installieren der clamav-0.94.2-1a Version

a) Setup ausführen

b) Als Installationstyp “Full auswählen (sonst werden benötigte Komponenten nicht installiert)

image

c) Dann den Setup mit den Standard Werten (am besten auch im Standard Verzeichnis) ausführen.

Zum Ende der Installation startet automatisch die Aktualisierung der Viren Signatur Datenbank.

image

d) Installation abschließen

3. Konfiguration “c:\clamav-devel\etc\clamav.conf” anpassen.  (Datei c:\clamav-devel\etc\clamav.conf mit einem Texteditor öffnen)

a) LocalSocket /cygdrive/c/clamav-devel/clamd.sock in der Datei suchen (eigentlich Zeile 82)

Diese Zeile durch das voranstellen eines # auskommentieren (siehe nachfolgende Zeile)

# LocalSocket /cygdrive/c/clamav-devel/clamd.sock

 

b) #TCPSocket 3310 in der Datei suchen (eigentlich Zeile 90)

In dieser Zeile das Kommentarzeichen # am Anfang entfernen (siehe nachfolgende Zeile)

TCPSocket 3310

 

c) Zur Aktivierung der Log Funktion (würde ich unbedingt empfehlen) folgende Einstellung vornehmen

#LogFileUnlock yes in der Datei suchen (eigentlich Zeile 32)

In dieser Zeile das Kommentarzeichen # am Anfang der Zeile entfernen (siehe nachfolgende Zeile)

LogFileUnlock yes

 

4. ClamAV (Hilfs)Dienst installieren

image

Hierzu öffnet man ein DOS (Kommando) Fenster.

Wechselt in das Verzeichnis C:\clamav-devel\thirdparty\runclamd

Gibt den Befehl runclamd –install ein und führt diesen aus

Wenn der Befehl erfolgreich durchgeführt wurde, gibt der Server im DOS Fenster “service installed” zurück.

image

Nun schließen wir das DOS Fenster

5. ClamAV (Hilfs)Dienst einrichten und starten

In den installierten Diensten suchen wir nun den Dienst Run Clamd

image

Öffnen das Eigenschaften Fenster

image

Und stellen den Starttyp für den Dienst von Manuell auf Automatisch

image

Nun starten wir den Dienst (dieses mal mit der Hand) beim nächsten Start wird er Automatisch gestartet.

6. Beheben von Zugriffproblemen der Log Datei

Wer möchte kann kann versuchen nun schon die Log Datei clamd.log im Verzeichnis C:\clamav-devel\log zu öffnen. Es wird schnell klar dass es nicht geht. Klar wird man denken, der Dienst greift ja darauf zu und deshalb ……
Nein das ist es nicht, wir haben übrigens in der Konfiguration Schritt 3c dem Program gesagt, dass wir die Log Datei lesen wollen. Also das Problem liegt nicht daran dass die Datei geöffnet ist, sondern (und da habe ich eine ganze Zeit suchen müssen) daran, dass die Zugriffsrechte für diese Datei etwas merkwürdig gesetzt sind.

Schauen wir uns doch mal die Rechte für diese Datei an:

image

Ich bin übrigens als Administrator an diesem System angemeldet, und trotzdem kann / darf ich die Rechte hier nicht ändern.

Es gibt aber einen ganz einfachen Trick wie wir hier weiterkommen. Hierzu betätigen wir den Button Erweitert und dort den Reiter Besitzer:

image

Hier sehen wir,dass der Besitzer das System ist. Das werden wir nun einfach ändern, indem wir den Besitzer ändern auf “Administratoren".

Wenn wir nun alle Rechte Fenster geschlossen und das Fenster der Dateiberechtigungen noch einmal öffnen:

image

Können wir auch das Lesen Recht für Jeden (oder wie auch immer) setzen (Und danach auch die Log Datei öffnen).

7. ClamAV in hMailServer eintragen und aktivieren

Nun müssen wir die nachfolgenden Einstellungen im hMailServer Administrations Tool im Bereich Anti-Virus vornehmen

image

Auf der Karteikarte External Virus Scanner nehmen wir folgende Einstellungen vor:

image

  • Use external scanner (aktivieren)
  • Im Feld Scanner executable wird "C:\clamav-devel\bin\clamdscan.exe" --no-summary --stdout "%FILE%" eingetragen (Mit den “)
  • Im Feld Return Value wird 1 eingegeben

 

8. Automatische Aktualisierung der Virus Signaturen einrichten

Einrichten eines geplanten Task für die Datei C:\clamav-devel\bin\freshclam.exe. Zum Beispiel Alle 2 Stunden

image

 

9. Tests

Zum Abschluss sollte man noch testen, ob alles einwandfrei funktioniert. Hierzu möchte ich zwei Beispiele geben, um den Viren Scanner und die Implementierung im hMailServer zu testen

Scanner testen

In einem geöffneten DOS Fenster gibt man die folgende Befehlszeile ein und führt sie aus:

"C:\clamav-devel\bin\clamdscan.exe" --no-summary --stdout "C:\clamav-devel\test\clam-nsis.exe"

Wenn der Scanner richtig installiert ist wird nach dem ausführen des Befehls die folgende Antwort im DOS Fensters zurückgegeben:

image 

Integration testen

Um die Mail Integration zu testen schickt man ein E-Mail mit der Datei C:\clamav-devel\test\clam-nsis.exe als Anhang an eine bekannte (eigene) E-Mail Adresse.

Wenn die Integration erfolgreich war, dann solle der Anhang von ClamAV über den hMailServer herausgefiltert werden.

Nachdem die beiden Tests durchgeführt sind, sollte man noch das Protokoll C:\clamav-devel\log\clamd.log anschauen. Dort sollten auf jeden Fall Protokolleinträge für die beiden Test aufzufinden sein.

Tips und Tricks | Server
Wednesday, July 01, 2009 12:06:16 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]  
Autor: Hans-Peter Schelian  |  Trackback
Copyright © 2010 Hans-Peter Schelian - Schelian IT Beratung. All rights reserved.