Thomas Wölfers Baustatik-Blog

Thomas Wölfers Baustatik-Blog

Setup and Deployment Project: Probleme mit VS 2010


Nachdem mich das nun fast 3 Tage gekostet hat, hilft es vielleicht jemand anderem in einer ähnlichen Situation. Ich hatte eine Setup and Deployment Project, das für die Installation unserer Software zuständig war, und das ursprünglich mit VS 2005 erstellt worden war. Das gleiche Projekt funktionierte auch prima mit VS 2008.

In der Version mit VS 2010 klappt es nicht mehr: Wenn man die Software auf einem “leeren” System installiert, geht alles gut. Befindet sich aber bereits eine Vorgängerversion der gleichen Software auf dem Zielsystem, dann werden im Laufe des Installationsvorganges (fast) alle Dateien der Software entfernt: Der Installer sagt das alle in Ordnung wäre – schaut man dann aber auf die Festplatte, so ist keine einzige Datei der Installation vorhanden.

Grund ist ein bekannter Fehler in VS 2010. (Connect-Eintrag dazu.). Im Wesentlichen läuft es darauf hinaus: Wenn man die Option “RemovePreviousVersions” auf “true” stellt, dann werden die Dateien der Vorgängerversion im Zuge der Installation entfernt. Der Fehler macht sich dadurch bemerkbar, das der Schritt mit dem entfernen der alten Version nicht vor der Installation der neuen stattfindet, sondern danach: Alle Dateien die sowohl in der alten als auch in der neuen Version drin sind, landen dann eben nicht auf dem Zielsystem. :-(

Angesichts der Tatsache das sich bei den Setup-Projekten in den letzten 6 Jahren praktisch nichts getan hat, finde ich es schon ein bisschen schwach, das die Softies es trotzdem geschafft haben, eine wichtige Funktion hops gehen zu lassen.

Ein (teilweise brauchbarer) Workaround ist im Connect-Eintrag beschrieben. (Im Wesentlichen baut man einen Post-Build Step, der die Reihenfolge der Arbeitsschritte korrigiert.)


Ein einfaches Web Stress Tool


Ich wollte kürzlich die Performance-Unterschiede vom IIS mit und ohne Output-File-Caching untersuchen: Mit dem Caching sollte der IIS dramatisch mehr Seiten ausliefern können, als ohne. Was mir nicht klar war, war, wie man dieses Caching nun genau einschaltet: Von Haus aus steht im Konfigurations-Manager des IIS, das das Caching “eingeschaltet” ist: Auf den Beispielvideos auf IIS.net werden aber immer noch zusätzliche Maßnahmen getroffen.

Mir war nicht klar, ob das tatsächlich notwendig ist, oder nicht. Die Idee das zu überprüfen war aber ganz einfach: Man nimmt das Web Stress Tool von Microsoft und schaut einfach nach, wie viele Seiten pro Sekunde geliefert werden können.

Leider ist das nur in der Theorie so, denn das an vielen Stellen verlinkte Web Stress Tool gibt es einfach nicht mehr: Man muss entweder WCAT verwenden, oder die Visual Studio-Ausgabe für Tester. Was blöd ist, denn die Tester-Ausgabe habe ich nicht, und WCAT ist mir eindeutig zu umfangreich für meine Zwecke.

Also habe ich selbst ein kleines Web-Stress Tool gebaut.

web_stress_tool

Es handelt sich um eine einfache Windows-Forms Anwendung. Oben gibt man die URL ein, die man testen will. Darunter kann man die Anzahl an Threads einstellen, die parallel die angegebene URL aufrufen sollen. Drückt man dann auf “Start”, fängt das Programm eben mit der eingestellten Anzahl an Threads an, Seiten abzurufen.

Darunter gibt es eine Statistik, die die Anzahl Seiten pro Sekunde und die gesamte Anzahl an Aufrufen auflistet. Das reicht für einen Test vom Caching völlig aus. (Die “optimale” Anzahl an Threads muss man ausprobieren.)

Wer mag kann sich die Sache hier herunterladen: Ausführbare Datei (.Net 4), Quellcode (VS 2010).


Ein "Trick" für Javascript


Ich musste kürzlich ein bisschen was an unsere Online-Dokumentation ändern. Dabei bin ich über folgendes Problem gestossen: Im Event-Modell von Browsern gibt es innerhalb einer Fensters das "Onload" Ereignis: Das wird aufgerufen, wenn die Seite komplett geladen ist. Zu diesem Zeitpunkt kann man prima im DOM rumändern - zum Beispiel nachträglich irgendwelche Dinge einfügen, die während des normalen Ladens des Dokument die Anzeige verzögern würden.

Das Problem dabei ist, das man sich an verschiedenen Stellen an "document.onload" dranhängen will - das das aber eigentlich nicht möglich ist: Anders als in C# kann man nicht einfach "document.onload += function()" schreiben, denn nur die Zuweisung "=" ist zulässig. Die überschreibt aber vorher gesetzte Handler. Was es also braucht ist ein Mechanismus, mit dem man "onload" Handler verketten kann. Ein Lösung dafür sieht so aus:

  function X() { alert ("X"); }
  function Y() { alert ("Y"); }

  var _allOnload = new Array();
  function AddOnload(f)
  {
    if (window.onload)
    {
      if (window.onload != Onload)
      {
        _allOnload[0] = window.onload;
        window.onload = Onload;
      }
      _allOnload[_allOnload.length] = f;
    }
    else
    {
      window.onload = f;
    }
  }
 
  function Onload()
  {
    for (var i=0;i<_allOnload.length;i++)
    {
      _allOnload[i]();
    }
  } 
 
   AddOnload( X );
   AddOnload( Y );


Custom Action eines Setup-Projektes wird nicht ausgeführt


Das hat mich nun etwa 2 Tage gekostet - vielleicht hilft es ja mal jemand anderem... Ich hatte folgendes Problem: In meinem VS (2008) Setup-Projekt gab es eine Custom Action (als C# Projekt) Assembly - und die wurd beim testen des Setups auf einer Maschine einfach nicht ausgeführt. (Das Ding schreibt einen Event-Log Eintrag, mit dem das einfach nachzuvollziehen war.)

Grund: Der MSI scheint bei Custom Actions Assemblies ein etwas anderes Verhalten an den Tag zu legen, als bei "normalen" Assemblies. Im Normalfall reicht es bei einer Managed Assembly aus, das die neue Version der Assembly eine höhere AssemblyVersion (per AssemblyVersionAttribute [1.0.0.*] einfach zu handhaben) hat, als eine auf dem Zielsystem bereits vorliegende Assembly. Hat die "neue" eine höhere Version, wird die "ältere" ersetzt. (Bei nativen Images muss die FileVersion höher sein, damit die ersetzt werden.)

Bei einer Assembly die eine Custom Action enthält scheint es nicht auszureichen die AssemblyVersion Notation [1.0.0.*] zu verwenden - auch wenn die Version hochgezählt wird, ersetzt MSI eine bereits vorliegende DLL mit gleichem Namen nicht. Offenbar muss man bei Custom Actions auf jeden Fall auch eine höhere FileVersion (per AssemblyFileVersionAttribute zu vergeben) haben. Ist das der Fall, wird die "ältere" DLL dann auch durch die neuere ersetzt - und im Zuge der Ausführung der Custom Actions dann auch tatsächlich aufgerufen.

Wäre schön gewesen, wenn das irgendwo in der Dokumentation zu finden gewesen wäre. :-(


Microsoft PDC 09


Wer nicht hinkonnte (so wie ich :-(), kann sich die Keynotes morgen und übermorgen (Dienstag und Mittwoch) live ab 17.30 unserer Zeit ansehen. Zu sehen ist das ganze unter http://microsoftpdc.com/. Alle anderen Veranstaltungen aus dem großen Saal werden ebenfalls live übertragen, und zwar bei Channel 9. Ich habs noch nicht verifiziert, gehe aber davon aus, das die Sessions wie auch früher schon aufgenommen und kurz nach Ende der Session als normaler Stream zur Verfügung gestellt werden.


Gestern: Windows 7 - TechTalk für Entwickler


Gestern in München: Der MSDN TechTalk: Windows 7 - ein Überblick für Entwickler mit Oliver Scheer und Peter Kirchner. Das ganze hatte 2 Teile und ging von 18.00 bis 22.00. Kurz gesagt: Ich fands ein bisschen langweilig.

Im ersten Block ging es hauptsächlich um Anwendungskompatibilität - und der wichtigste Punkt scheint (noch immer, fast 15 Jahre nach Windows 95) zu sein, das viele Anwendungen die Versionsnummer von Windows nicht richtig nachsehen. Verstehe ja, das das für Microsoft wichtig ist - aber ich habe den zugehörigen Vortrag nun gefühlte 30mal gehört. (Mal sehen: WfW 3.1, W95, NT 3.1, NT 3.51, 2000, W98, XP, 2003, Vista, Server 2008 und nun W7 - also mindestens 10mal...).

Außerdem ging es darum das es nun (eigentlich schon seit Vista) Manifeste gibt (die man braucht, wenn man diverse Warnungen loswerden will) und das es (auch schon länger) auch Shims und das sdb Tool (und angelagertes gibt.).

Wer das schonmal für Vista gesehen und gehört hat: Viel Neues gibts in dem Umfeld offenbar nicht.

Der zweite Teil litt ein wenig unter der immer stärker schwindenden Stimme des Vortragenden (ein Problem das ich gut nachvollziehen kann: Ist mir letzte Woche am 3. Tag der Roadshow dann auch so ergangen... :-). Dabei ging es inhaltlich um die Nutzung der neuen Windows 7 Features im eigenen Programm: Ich hatte der Ankündigung entnommen, das es sich hier eher um einen Code-lastigen Vortrag halten würde: Statt dessen gab es auch hier eher Slides, viele Vorführungen der Windows 7 Features - aber doch eher dürftige konkrete Programmierbeispiele: Auf die wurde zwar immer wieder verwiesen, aber dafür hätte man sich die Zeit sparen können, wenn man die folgenden beiden Links kennt:

Windows 7 SDK Download, Windows API Code Pack for the .NET Framework

Insgesamt betrachtet war es interessant genug um nicht zu gehen, aber eigentlich nicht so interessant das ich eine Teilnahme an den anderen Vortragsorten empfehlen würde. Statt dessen schaut man besser in die Samples aus den beiden Links.


Inhalt von Message-Boxen kopieren


Manchmal ganz praktisch: Wenn eine Message-Box angezeigt wird...

... kann man den text darin mit Ctrl+C (Strg+C) einfach in Slipboard kopieren. Das sieht dann etwa so aus:

---------------------------
Microsoft Visual C++ Debug Library
---------------------------
Debug Assertion Failed!

Program: c:\statik\runtime\xfalt\debugx64\baustatik.exe
File: f:\dd\vctools\crt_bld\self_64_amd64\crt\prebuild\tran\amd64\ieee.c
Line: 109

Expression: (mask&~(_MCW_DN|_MCW_EM|_MCW_RC))==0

For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.

(Press Retry to debug the application)
---------------------------
Abort   Retry   Ignore  
---------------------------


So horcht man mit C# auf den Bildschirmschoner


Wie man in C# auf den Screensaver reagiert

Manchmal möchte man in einem Programm darauf reagieren, das der Benutzer das Programm nicht länger verwendet, obwohl es noch läuft. Solche Situationen treten zum Beispiel dann ein, wenn die Workstation gelockt, oder aber, wenn der Bildschirmschoner aktiviert wird.
Das geht mit Win32 schon seit geraumer Zeit relativ einfach, und zwar mit Hilfe der SensEvents - in diesem Fall mit dem ISensLogon Event Interface.

Für die Nutzung aus .Net heraus gibt es aber leider keine wirklich brauchbare Beschreibung dafür - zumindest konnte ich keine finden. Daher hier: Eine Kurzbeschreibung fürs horchen per ISensLogon Implementierung.

Die Sache ist danbarerweise viel einfacher, als die COM-Dokumentation vermuten läßt. Zunächst braucht man im Projekt zwei neue Referenzen: Eine auf die "COM+ Admin Type Library", und eine auf die "SENS Events Type Library".

Mit der "Admin" referenz kommt man an die COMAdminCatalgoClass, die man zum registrieren (und abmelden) von Event Listenern benötigt, die "SENS" Referenz liefert einem die benötigten Definitionen um mit dem ISensLogon Interface arbeiten zu können.

Im Beispiel erzeuge ich einfach eine Instance der COMAdminCatalogClass als Member einer Form. Mit Hilfe dieses Members kommt man dann an die Sammlung aus Subscriptions, und mit deren Hilfe kann man dann eine neue Subscription erzeugen: In diesem Fall eine, für die "SENS Logon Events". Das geht mit Hilfe der EventCLSID dieser Events (die man notfalls durch Suche in der Registry findet.).

Das anlegen eines neuen Abos verläuft dann wie folgt - wichtig ist dabei nur, das man sich die ID des Abos merkt - ansonsten kann man es später nicht mehr kündigen:

private
string Subscribe()
{
   var subscription = (ICatalogObject)_subscriptions.Add();
   subscription.set_Value("EventCLSID", "{D5978630-5B9F-11D1-8DD2-00AA004ABD5E}"); // (findet man per Suche nach SENS Logon Events in der registry)
   subscription.set_Value("Name", "Subscription to ISensLogon");
   subscription.set_Value("SubscriberInterface", this);
   subscription.set_Value("Enabled", true);
   subscription.set_Value("PerUser", true);

   _subscriptions.SaveChanges();

   return subscription.get_Value("ID").ToString();
}

Damit man die Notifizierungen auch bekommt  muss irgendwer das ISensLogon Interface implentieren: Im Beispiel tut das einfach die Form. Das Interface hat 7 Methoden, und im Beispiel wird einfach in einer Liste aus Strings mitgeführt, welches Ereignis eingetreten ist. (Diese Liste kann man sich dann später per Klick auf den Button der Form anzeigen lassen. Das ist darum so, weil man keine Desktop-Interaktionen durchführen kann, wenn kein Benutzer angemeldet ist: Würden die Methoden aus der Interface-Implementierung direkt in die Listbox schreiben, gäbe es nur eine Exception aus Windows.Forms.)

Zum abbestellen des Abos muss man einfach über die Liste der Abos laufen, und dann dasjenige entfernen, das die "eigene" ID hat, die beim bestellen gemerkt wurde.

private void Unsubscribe()
{
   for (int i = 0; i < _subscriptions.Count; i++ )
   {
      var subscription = (ICatalogObject)_subscriptions.get_Item(i);

      if (subscription.get_Value("ID").ToString() == _subscriptionId)
      {
         _subscriptions.Remove(i);
         _subscriptions.SaveChanges();
         return;
      }
   }
}

Das wars eigentlich schon: Wer mag kann sich das komplette Projekt (VS 2088, C# 3.0) runterladen und ausprobieren...

SensTest.zip (10.23 KB)



Baustatik Demoversion ausprobieren »