Thomas Wölfers Baustatik-Blog

Thomas Wölfers Baustatik-Blog

(C++) Arrays im Debugger anzeigen


Ist nur in einem KB-Artikel dokumentiert: So zeigt man Arrays im Watch-Window des Debuggers an: Name der Array-Variable, gefolgt von einem Komma und danach gefolgt von der Anzahl der Element, die angezeigt werden sollen. Sehr praktische Sache - zumindest wenn man sich für Array-Inhalte interessiert.

Edit: Nicht "Kommand" sondern "Komma".


Nochmal: Das Problem mit dem PrintDocument


(Das, wg. dem man mit x86 Debug Builds unter Vista x64 nicht drucken kann: Hier.) Es könnte vielleicht nicht schaden, wenn auch noch ein paar mehr Leute dazu mit abstimmen. Daher: Hier der Link zu Microsoft Connect - Feedback.


Änderung beim VS 2005 SP1


Eine Änderung an die zumindest ich nicht gedacht hatte: Die redistributable Komponenten vom VS++ Compiler haben sich beim dem SP natürlich auch geändert. Das kann Konsequenzen haben - zumindest, wenn man den "vorgefertigten" Weg geht, die Redistributables zu installieren. Bei uns ist es so, das wir nicht nur die vom C++ Compiler mit ausliefern, sondern auch das .Net Framework, Managed DirectX, MDAC und ein paar Dinge mehr.

Damit der Download fürs Setup unsere Software etwas kleiner ausfällt, gibt es den in zwei Geschmacksrichtungen: Einmal mit allen Redistributables - und einmal ohne alle. Wer also einmal das "große" Setup installiert hat, der braucht für spätere Updates nur noch das kleine runterzuladen. Das wird übrigens auch per automatischem Update unsere Software runtergeladen - das macht die Sache einfacher.

Zumindest in der Theorie. In der Praxis ist dann (natürlich) gestern folgendes passiert: Es gab ein Update für die Software, und zwar das erste Update nachdem auf der Produktionsmaschine mit der die Setups gemacht werden das SP1 installiert worden war. Wenn man nun aber das "kleine" Download installierte (bzw. das, das von den automatischen Updates runtergeladen wurde), dann konnte man danach das Programm nicht mehr starten - es fehlten die richtigen Versionen der VC++ Komponenten.

Gut das wir erst im Beta sind :-)


Visual Studio SP1 unter Vista


Nur ein kurzer Hinweis: Mir ist bekannt das das Team beschlossen hat, da immer eine aufdringliche Warnung anzuzeigen - und dafür haben sie auch bestimmt gute Gründe: Vermutlich die, die auf der Download-Seite fürs Service Pack aufgelistet sind.

Ich denke aber, das das VS 2005 SP1 Team da ein bisschen sehr vorsichtig war: Ich arbeite nun seit 2 Wochen mit dem SP1 (und ohne den Patch für Vista der noch im Beta ist) für VS 2005 unter Vista (RTM) x64 - und zwar NICHT als Administrator. Und ich hatte noch kein einziges Problem.

Ich gehe mal davon aus, das man sich das Readme zum Thema einfach einmal ganz genau durchlesen sollte - und nur dann, wenn tatsächlich eines der geschilderten Probleme auftritt, kurz einmal als Admin arbeitet.


Wie man einen installierten Webservice debugged


Folgende Situation: Der Service läuft (fehlerhaft) auf einem entfernten Webserver mit IIS - in meinem Fall unter W2K3. Dann gibt es noch eine Client-Anwendung, die läuft auf einem beliebigen Client - in meinem Fall handelt es sich um eine C# Anwendung, die auf meiner lokalen Workstation im Debugger laufen kann. Den einfachsten Weg, den ich gefunden haben , um das zu debuggen sieht so aus:

- Verbindung zum Webserver per RDP herstellen
- VS 2005 auf dem Webserver lokal installieren
- VS starten
- "Open" -> "Lokaler IIS" -> Website mit dem Service auswählen

Jetzt hat man schonmal den Source zur Site (und damit auch zum Service) im Editor. Als nächstes

- Debug -> Attach to Process
- Damit die IIS Prozesse sichtbar werden, "Show All Processes" und "Show Processes from all Sessions" einschalten
- Dann den IIS Prozess auswählen (Notfalls einfach _alle_ davon auswählen: Z.b. dann, wenn man nicht weiss, welcher zur "gewollten" Website gehört
- Jetzt werden die Symbole geladen. Man kann dann einen Breakpoint in den Service tun.
- Wenn der Breakpoint das gelbe Warnsymbol beinhaltet, dann wurden keine Symbole für den Service geladen: Vermutlich läuft die Website gerade nicht
- In diesem Fall: Einfach mit einem Browser die Site die den Dienst beinhaltet anfordern: Das startet die Site, und der Debugger lädt dann auch die Symbole

Nun gibt es zwei mögliche Scenarien: Man will nur den Service debuggen, oder auch den Client-Teil: Im einen Fall reicht es dann aus, einfach mit einem auf dem Webserver lokalen Browser den Service abzufragen. (Wenn man die URL des Service eingibt, bekommt man u.a. ein Formular, mit dem man die Parameter für den Service-Aufruf angeben kann. Im anderne Fall startet man einfach den Client auf der Workstation im Debugger.

Das ganze geht natürlich auch "Remote" mit nur einer Kopie von VS - aber dann muss man die Remote Debugging Tools auf dem Server installieren, und obendrein DCOM zulassen. Danach gibts dann noch ein paar Rechte-Probleme: Das war mir alles irgendwie zu kompliziert. Davon ab: Noch einfacher ist es natürlich, wenn man das ganze "lokal" Debuggen kann - also mit einem lokalen IIS oder dem in VS integrierten Webserver. Letzteres hat allerdings 2 Nachteile: Zum einen unterscheiden sich die lokalen Gegebenheiten (also die auf der Workstation) meist sehr stark von denen auf dem Server, zum anderen verhält sich der integrierte Webserver doch deutlich anders als der echte IIS in freier Wildbahn.


Vorsicht bei ImageList und TreeView


Im Zusammenhang mit ImageLists und TreeViews gibt es einen Umstand, den ich für einen Bug in der TreeView halte - und der unter den richtigen Umständen zu einem Memory-Leak führt.

Angenommen, man hat eine Form mit einer TreeView, und weist der TreeView eine ImageList zu, die sich in einem anderen Objekt als der Form befindet. Zum Beispiel eine ImageList die irgendwo statisch definiert ist. Wenn man dies tut, dann wird beim schließen der Form der Finalizer für die TreeView nicht aufgerufen. Resultat: Das Control verschwindet zwar, aber die dahinter steckende Datenstruktur wird nicht freigegeben. Dazu gehören unter anderm auch die darin befindlichen TreeNodes, und alle Objekt, die über Referenzen in deren Tags erreicht werden können. Tendenziell kann das ganz schön umfangreich werden, was da nicht freigegeben wird.

Der Grund dafür ist der, das sich die TreeView beim Set-Accessor ( treeView.ImageList = staticImageList ) an Events der ImageList hängt, sich aber beim schliessen davon nicht mehr abhägt. Blöde Sache.

Einziges Workaround: Selbst die ImageList ausnullen, wenn die Form geschlossen wird. Connect Bug Entry hier.


Gesucht: Workaround für PrintDocument Problem


Mein erstes (echtes) Problem unter Windows Vista: Der folgende Code funktioniert unter Vista x64 - aber nur, wenn man als Platform Target auch x64 verwendet. Verwendet man x86 als Target, gehts nicht mehr: Es werden dann keine der installierten Drucker gefunden, und die Sache wirft eine InvalidPrinterException.

PageSetupDialog dialog = new PageSetupDialog();
dialog.Document =
new PrintDocument();
dialog.ShowDialog();

Im Projekt (bzw: in der Solution) befindet sich nativer C++ Code der nicht ohne weiteres nach x64 portiert werden kann; ferner gibt es auch noch ein paar x86 Libraries von Dritten die ebenfalls nicht als x64 verfügbar sind. Mit anderne Worten: "Any CPU" als Target Platform ist keine Option. Unter XP x64 hat die Sache auch noch wunderbar funktioniert.

Vorschläge ?


Ein UITypeEditor und ein anonymes Delegate


Angenommen, man braucht einen ganz einfach UITypeEditor, zum Beispiel einen, der in einer Listbox eine Auswahl an Möglichkeiten anbietet. Das ist verhältnismäßig einfach zu haben: Die Kurzform von so einem Ding sieht so aus:

public class StyleFilenameEditor : UITypeEditor
{
   public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
   {
      ListBox listBox = new ListBox();
      listBox.Items.Add("Text 1"); // usw.
      IWindowsFormsEditorService editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
editorService.DropDownControl(listBox);
   

      return listBox.SelectedItem;
   }

   public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
   {   
      return UITypeEditorEditStyle.DropDown;
   }
}

Feine Sache, allerdings mit einem kleinen Haken: Man bekommt die Listbox nicht mehr zu, wenn man den Code so verwendet, wie ich ihn im Beispiel hingeschrieben habe. Grund: Der EditorService erwartet, das man ihm mitteilt, wenn er das zugehörige Drop-Down schliessen soll. Die offensichtliche Art ist dabei die folgende. Dabei merkt man sich den editorServive in einer privaten Variable, und hängt einen Event-Handler an das SelectedIndexChanged-Event der Listbox. In diesem Handler benutzt man dann die private Variable und ruf CloseDropdown auf:

      this.editorSerivce = ...

      listBox.SelectedIndexChanged +=new EventHandler(listBox_SelectedIndexChanged);

      void listBox_SelectedIndexChanged(object sender, EventArgs e)
      {
         this.editorService.CloseDrowDown();
      }

Mit einem anonymen Delegate geht das aber viel schöner. Man braucht keinen separaten Event-Handler und auch keine private Variable:

         listBox.SelectedIndexChanged += delegate(object sender, EventArgs e) { editorService.CloseDropDown(); };


Steckt das Druckerkabel? Ist der Drucker eingeschaltet?


Jeder kennt solche Stories oder hat schon selbst mal aktiv an der Entstehung einer solchen mitgearbeitet. Geschichten, die dafür zuständig sind, das Fragen wie "Steckt das Druckerkabel?" oder "Ist der Drucker auch eingeschaltet?" eine der ersten Fragen sind, die man im Support so stellt.

Genau - sehr lustig: Der Drucker druckt nicht, und der Mensch mit dem Druckerproblem kommt nicht von selbst auf die Idee nachzusehen, ob das blöde Kabel drinsteckt. Was haben wir nicht alle gelacht... :-)

Für zukünftige Updates, die wir per BITS durchführen wollen, habe ich heute den BITS Service auf unserem Webserver aktiviert. Und wollte den natürlich auch testen. Das geht am einfachsten, indem man das BITSAdmin Tool verwendet. Das Ding ist Teil der XP SP2 Support Tools, und die sind zwar auf meinem Laptop, aber nicht auf meinem Desktop installiert.

Also: Laptop angeworfen, und per BITSAdmin versucht, ein File vom Webserver auf den Laptop runterzuladen. Das führte aber dummerweise nur zu einem TRANSIENT_ERROR. Fein: Das lokale Bits konnte das File nicht runterladen, und natürlich gabs auf dem Server auch nicht den geringsten Hinweis auf irgendein Problem. Kein Logfileeintrag. Einfach nichts.

Ich habe also das offensichtliche getan, und alles an technischer Dokumentation zu BITS gelesen, was ich gefunde habe. (Der Beste Artikel zu BITS und .NET ist übrigens der hier.) Das hatte nur einen etwas eingeschränkten Erfolg, den auf meine nächste Frage nach "Bitte ein Bit" meinte BITSAdmin: "TRANSIENT_ERROR". Tolle Sache.

Etwa 3 Stunden später kam dann die Erleuchtung: Es hilft, wenn man das Netzwerkkabel in den Laptop steckt.

Was habe ich gelacht... ;-)




Baustatik Demoversion ausprobieren »