Visual Studio 2008 Service Pack 1 Beta wurde gestern veröffentlicht

Die Beta des SP1 für Visual Studio 2008 wurde getsern veröffentlicht und steht zum Download zur Verfügung!

We are excited to pre-announce the availability of the the Visual Studio 2008 Service Pack 1 Beta download.

Visual Studio 2008 SP1 delivers various improvements to Visual Studio 2008 such as support SQL Server 2008 and new ADO.NET features such as the Entity Framework, numerous improvements to the WPF designers, WCF Templates for Silverlight projects, debugger support for the .NET Framework public symbols and source release, control improvements and additions (such as the DataRepeater for Windows Forms and Office 2007 Ribbons for C++), and a number of general debugging and Intellisense updates. This Service Pack also includes fixes to improve the stability, performance and security of many areas of the product. Due to the release schedule of this product, and the fact we have a very short feedback window, we would love to hear from our targeted community members 

Downloads

Hotfix für UseMSPrivateAssemblies.h und VC-2008

Einige nutzen ja meine Lösung für private CRT und MFC Assemblies unter VC-2005, die ich in dem diesem Artikel unter Codeproject veröffentlicht habe
http://www.codeproject.com/KB/cpp/PrivateAssemblyProjects.aspx

Das Interesse und die Nachfrage ist groß dieses Verfahren auch unter VC-2008 zu nutzen.
Da ich aber aktuell wenig Zeit habe den Artikel komplett zu überarbeiten, veröffentliche ich den relevanten Code hier erst mal vorab als „Hotfix“. Dieser Hotfix setzt voraus, dass das aktuelle Feature Pack installiert ist. Der Code ist nicht auf die RTM Version hin zugeschnitten und getestet.

UseMSPrivateAssemblies.h

// Version 2.0 by Martin Richter [WWJD]
// Supports VC-2005 and VC-2008
#pragma once    

#ifndef RC_INVOKED
// Avoid problems with the resource compiler if included    

// This defines bock the creation in the header files
#pragma message("Using private assemblies for the MS runtimes")
#define _STL_NOFORCE_MANIFEST
#define _CRT_NOFORCE_MANIFEST
#define _AFX_NOFORCE_MANIFEST
//#define _ATL_NOFORCE_MANIFEST    

// The next statements block the linker from including object files in the
// CRT and the MFC, that would create manifest pragmas too.
#ifdef __cplusplus
extern "C" {            /* Assume C declarations for C++ */
#endif    

__declspec(selectany)       int _forceCRTManifest;
__declspec(selectany)       int _forceMFCManifest;
// __declspec(selectany)    int _forceAtlDllManifest;    

// The next symbols are used by the several versions of VC 9.0
__declspec(selectany)       int _forceCRTManifestRTM;
__declspec(selectany)       int _forceMFCManifestRTM;
__declspec(selectany)       int _forceMFCManifestCUR;    

#ifdef __cplusplus
}                        /* __cplusplus */
#endif    

// We use crtassem.h with the defines there. It just gives us the
// versions and name parts for the dependencies.
// Note that there is also a MFCassem.h but this include file has the
// manifest pragma's already in it. So we can't use it
//
// Three files are controlling this crtassem.h, MFCassem.h and atlassem.h!
// Happily __LIBRARIES_ASSEMBLY_NAME_PREFIX is used in CRT, MFC and ATL!
// Doing it right would need to use _MFC_ASSEMBLY_VERSION for the MFC
// but in fact _CRT_ASSEMBLY_VERSION and _MFC_ASSEMBLY_VERSION and
// _ATL_ASSEMBLY_VERSION are the same
//  - VC-2005 SP1 8.0.50727.762
//  - VC-2008 RTM 9.0.21022.8
//  - VC-2008 Feature Pack 9.0.30411.0 (used if _BIND_TO_CURRENT_VCLIBS_VERSION
//    and _BIND_TO_CURRENT_MFC_VERSION are defined to 1)    

#include <crtassem.h>

// We don't have a seperate block for the Debug version. We just handle
// this with a extra define here.
#ifdef _DEBUG
#define __LIBRARIES_SUB_VERSION    "Debug"
#else
#define __LIBRARIES_SUB_VERSION    ""
#endif    

// Manifest for the CRT
#pragma comment(linker,"/manifestdependency:\"type='win32' "                        \
    "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX "." __LIBRARIES_SUB_VERSION "CRT' "   \
    "version='" _CRT_ASSEMBLY_VERSION "' "                                          \
    "processorArchitecture='x86' \"")    

// Manifest for the MFC
#pragma comment(linker,"/manifestdependency:\"type='win32' "                        \
    "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX "." __LIBRARIES_SUB_VERSION "MFC' "   \
    "version='" _CRT_ASSEMBLY_VERSION "' "                                          \
    "processorArchitecture='x86'\"")    

// #pragma comment(linker,"/manifestdependency:\"type='win32' "                     \
//     "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".MFCLOC' "                        \
//     "version='" _CRT_ASSEMBLY_VERSION "' "                                       \
//     "processorArchitecture='x86'\"")    

// Manifest for the ATL
// #pragma comment(linker,"/manifestdependency:\"type='win32' "                     \
//    "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".ATL' "                            \
//    "version='" _CRT_ASSEMBLY_VERSION "' "                                        \
//    "processorArchitecture='x86' \"")    

#endif // RC_INVOKED

Anmerkungen:

  • Im Endeffekt sind nur 3 Zeilen (26-28) hinzugekommen.
  • Diese Version funktioniert sowohl für VC-2005 als auch VC-2008!
  • Unter Vista wird allgemein das Problem beobachtet, das private Assemblies nur genutzt werden können, wenn diese in einem Unterverzeichnis liegen. Liegen die Assembly Dateien im gleichen Verzeichnis wie die EXE kommt es zu einem Fehler „The application failed to initialize properly (0xc0000034). „ Dieser Sache bin ich (und andere) auf der Spur.
  • Es spielt für diesen Code keine Rolle ob die beiden Defines _BIND_TO_CURRENT_VCLIBS_VERSION und _BIND_TO_CURRENT_MFC_VERSION gesetzt wurden. Werden diese Defines auf 1 gesetzt bevor UseMSPrivateAssemblies inkludiert wird, dann werden die Manifeste so erzeugt, dass die Feature Pack DLLs gezogen werden. Sind diese beiden Defines nicht gesetzt werden Manifeste für die RTM Version erzeugt.
    Ich empfehle dringend diese beiden Defines zu setzen ❗

Das ist erstmal ein Schnellschuss für alle, die die es etwas eiliger haben.

Der Vorteil gegenüber der Lösung, bei der die Manifeste manuell bearbeitet werden, wie es zum Beispiel Jochen Kalmbach in seinem Blog vorgestellt hat ist klar:
Man muss eben nichts manuell machen 🙂
Es macht wieder alles der Compiler und Linker.

Tipps & Tricks: Testcode sollte immer in #ifdef _DEBUG #endif Blöcke integriert sein!

Dieser Tipp hört sich trivial an, aber wenn man sich nicht dran hält erlebt man übelste Überraschungen.
Nur zu oft muss man während der Entwicklung oder bei der Fehlersuche Code einbauen, der Test, Ausgaben, Verzögerungen oder sonstige Operationen ausführt, die mir als Entwickler helfen ein Problem zu finden, oder einer Lösung für eine verzwickte Frage zu lösen. Um so größer das Problem wird um so mehr Stellen werden oft verändert.
Es bleibt die Frage ob sich jeder Entwickler noch erinnert wo er überall etwas für Testzwecke eingebaut hat.

Das üble Ergebnis ist, dass man manchmal toten nutzlosen, Performance fressenden Code ausliefert. Oder gar Code ausliefert, der evtl. zu neuen Fehlern führt. Da muss nur ein einfacher DebugBreak im Code zurückbleiben und schon crashed die Anwendung sauber beim Kunden…

Testcode sollte grundsätzlich in einem #ifdef Block eingebaut werden. Und Code der wirklich nur für Tests vorhanden ist und er sogar später in der Debug Version des Programmes nichts zu suchen hat sollte mit einem #else #error versehen werden. Ein ASSERT kann einen viel abnehmen um so etwas zu vermeiden, aber sogar mancher ASSERT  ist später überflüssig und behindert auch Tests in der Debug Version.

So habe ich in unserer Software einen Sleep(100); 😮 gefunden, der von einem Entwickler eingebaut wurde, um einen Crash in einem komplexen Kommunikationsproblem zwischen mehreren Threads zu finden.Er hat den Fehler gefunden, den Sleep aber nie wieder entfernt.
Hätte mein Kollege sich an meine Spezifikationen gehalten, hätten wir nicht nachträglich auf die mühsame Suche gehen müssen wo unsere Performanceverluste bei 5% Prozessorlast herkommen. So wäre das Ganze schon beim Release-Build aufgefallen:

#ifdef _DEBUG
// Test Sleep to find cross thread problems for bug#234
Sleep(100);
#else
#error Remove test condition here. Just used to find bug#234 
#endif

BTW: Ich verwende deshalb immer ein Code-Snippet über mein VisualAssist X, der mir einen entsprechenden Codeblock einsetzt.

Der zweite Versuch: Visual C++ 2008 Feature Pack Refresh (MFCNext & TR1)

Nach dem ersten Versuch nun der zweite Versuch. Alle bisher bekannten Installationsprobleme sind gefixed.

Weitere Infos: http://blogs.msdn.com/vcblog/archive/2008/04/22/visual-c-2008-feature-pack-refresh.aspx

Download: http://www.microsoft.com/downloads/details.aspx?FamilyID=d466226b-8dab-445f-a7b4-448b326c48e7&displaylang=en

Das bereits installierte Feature Pack muss deinstalliert werden! Glücklich wer nur die Beta bisher installiert hat, der kann wie bisher einfach drüber installieren. ❗

BTW: Eine Responsezeit von 16 Tagen ist gar nicht soooo schlecht 😉

VS Tipps & Tricks: Ganze Solutions zu einer Master-Solutions zusammenfügen

Wie andere Programmierer auch habe ich meine Projekte in einzelne Solutions zusammengefasst. Nicht wenige dieser Solutions haben auch komplexere Abhängigkeiten.

Bisher hatte ich insgesamt dann 4 größere Solutions, die alle Projekte dann für einen vollen Release-Build bündelten. Bisher wurden diese großen Solution-Builds, dann durch spezielle Batchfiles gesteuert. 

Seit ich den TFS (Team Foundation Server) verwende habe ich begonnen alle einzelnen Komponenten direkt auch auf das Buildsystem des TFS hin abzubilden. Dazu gehört auch, alle Projekte in einer großen Solution zusammenzufassen, um nun im Teambuild alles weitere ablaufen zu lassen.

Als ich mühsam Projekt für Projekt in eine große Master-Solution einfügen wollte machte ich eine nette Entdeckung:
Man kann nicht nur existierende Projekte in eine Solution einfügen. Nein! Es ist sogar möglich eine ganze Solution in eine bestehende Solution einzufügen und dabei sogar alle Abhängigkeiten in dieser Solution zu erhalten. Einfach im Dateidialog die Solutions auswählen und das war es auch schon.
Das macht es wirklich einfach auch komplexere Solutions in eine Master-Solution zusammenzufügen. Jetzt ist es auch nicht weiter schwer die verbleibenden Abhängigkeiten, die bei mir in dem Batch geregelt wurden zu definieren.

Visual Studio 2008 Feature Pain…

Hier die bisherige offizielle Bug-Liste des gerade veröffentlichten Feature Packs:

http://blogs.msdn.com/vcblog/archive/2008/04/12/visual-c-2008-feature-pack-setup-deployment-issues.aspx

Mit Ruhm hat sich Microsoft hier wirklich nicht bekleckert.
Vor allem ist das Feature Pack ohne ein funktionierendes Deployment für Vista erstmal wertlos…

In der Haut derjenigen, die das Setup und Deployment zu verantworten haben möchte ich nicht stecken.

Leider ist das Ganze wieder mal nicht ganz vertrauenserweckend. Man kann ja jetzt nur hoffen, dass der Rest des Packs mit nicht ganz so heißer Nadel gestrickt wurde. Die nächste Zeit wird es zeigen.

Visual C++ 2008 Libraries Extension Feature Pack Final Release (MFCNext & TR1)

❗ Es ist da, die finale Version des MFC-Feature Pack für VS-2008 (MFCNext & TR1) ❗

Das Feature Pack ist nur für die Englische VS-Version (ENU) ab Visual Studio 2008 Standard Edition verfügbar.
Andere Sprachversionen werden in Visual Studio 2008 Service Pack 1 enthalten sein.

Visual C++ 2008 Libraries Extension Feature Pack Final Release
Download link, 322.8 MB
Redistributable Package (x86)

Dokumentation:
MSDN MFC Feature Pack for Visual C++ 2008
MSDN TR1 Extensions

❗ Wichtige Anmerkung sofern ein Deutsches OS eingesetzt wird ❗

Bei mir schlug die erste Installation fehl (sowohl auf Deutschem Vista Ultimate SP1 als auch XP SP2). In der Log-Datei im %TMP% Verzeichnis konnte ich herausbekommen, dass die Datei SPInstallerResources.1031.dll vermisst wird:

Unable to load UI satellite DLL SPInstallerResources.1031.dll 

Nach einigem hin und her Tricksen mit Entpacken und Umbenennen der Datei fand ich folgenden Trick um das Feature Pack zu installieren:
Man muss einfach vorher in der Systemsteuerung in den Regions- und Spracheinstellungen, die Einstellungen für die Formate auf „Englisch (USA)“ umstellen. Zusätzlich habe ich auch den Standardort auf „Vereinigte Staaten“ eingestellt. Danach lief die Installation korrekt ab.

Es spielt übrigends keine Rolle ob die Feature Pack Beta Version zuvor installiert war!

Vista Stil bei Tree-Controls und List-Controls

Unter Vista wurden die Tree- und List-Controls noch einmal kräftig aufgemöbelt.
Diesen neuen Look kann man auch in seinen Applikationen nutzen und das mit 2 simplen Codezeilen.

#pragma comment(lib,"uxtheme.lib") 
SetWindowTheme(m_myCtrl.GetSafeHwnd(),L"Explorer",NULL);

Und schon hat man die neue Darstellung des Tree-Controls mit den Dreiecken, die Knotenlinien sind weg.
Beim List-Control hat man nun die hellblaue Färbung mit dem Hover-Effekt.

Vorraussetzung dafür ist, dass auch ein Manifest für die Windows Common Controls Version 6 vorliegt. Dem entsprechend ist SetWindowTheme und die Uxtheme.dll erst ab Windows XP verfügbar. Wer das ganze auch kompatibel mit Windows 2000 haben möchte, der verwendet natürlich das dynamische Laden der Uxtheme.dll und sucht den Einsprungpunkt für SetWindowTheme mit GetProcAddress!

Siehe auch MSDN Doku zu SetWindowTheme

C++ Community Event am 17.04 findet in Bad Homburg statt

Der folgende Community Event findet in Bad Homburg statt und nicht wie angekündigt in Frankfurt.

C++ Community Event in Bad Homburg mit Microsoft Program Managern
Ich habe den entsprechenden Artikel geändert.

Termin & Ort:

  • Datum: 17.4.2008, 16 – 19 Uhr

  • Ort: Steigenberger Hotel Bad Homburg
    Kaiser-Friedrich-Promenade 69-75
    61348 Bad Homburg v. d. Höhe

Anmeldung erfolgt per Email über den offizieller Link für die Veranstaltung:
http://blogs.msdn.com/softwarehersteller/pages/cpp2008-4-ffm.aspx

Arithmetik mit GetTickCount

Immer wieder sehe ich Code um GetTickCount oder Aussagen, die sich um den Überlauf von GetTickCount drehen, der alle 49,7 Tage entsteht. Muss man also irgendwelche Vorkehrungen treffen, wenn man Zeitdifferenzen errechnen will?

Eigentlich muss man sich gar nicht darum kümmern, sofern man in 49,7 Tagen eben mindestens einmal diese Differenz errechnet und das damit dafür gesorgt ist, dass diese Differenz nicht größer sein kann als eben besagt 49,7 Tage.

DWORD dwStart=::GetTickCount(); 
while (::GetTickCount()-dwStart < dwTimeout) 
   DoSomething();

Die Arithmetik über unsigned Integer macht es an dieser Stelle möglich. Dieser Code funktioniert, solange eben DoSomething nicht länger als 49,7 Tage dauert. Das ist die einzige Bedingung!

Leider schweigt sich die normale Windows SDK Doku zu GetTickCount darüber aus.
http://msdn2.microsoft.com/en-us/library/ms724408.aspx

Eigentlich problematisch an dieser Stelle, ist es nicht Differenzen zu bilden sondern Vergleiche durchzuführen ❗

Einen interessanten Zusatz dazu findet sich jedoch in der Windows CE Doku. Warum dieser Zusatz nicht auch in der normalen SDK Doku steht ist eigentümlich. Im Allgemeinen empfinde ich die CE-Doku in der MSDN immer eher als lästig.
Es ist aber eben wahrscheinlicher, dass dein CE Rechner und dementsprechend Programme die darauf laufen, länger als 49,7 Tage laufen als auf einem Desktop, ohne einen Reboot, alleine schon wegen der Security Updates, so kann man sich diesen Umstand zumindest erklären.
http://msdn2.microsoft.com/en-us/library/ms885645.aspx

When using GetTickCount, subtraction is safe but comparisons such as

if (GetTickCount() > MyTickCount)

are not. You can use the GetTickCount function to time the duration of an activity as shown in the example below, but using GetTickCount for any other operation will cause issues.

wOldTime = GetTickCount(); 
DoSomething(); 
dwTimeElapsed = GetTickCount() – dwOldTime;

Gleiches findet sich in der Windows Mobile 6 Doku noch etwas besser
http://msdn2.microsoft.com/en-us/library/aa915056.aspx

When using GetTickCount, subtraction is safe, even if the rollover occurred, and subtraction always yields the correct difference and the number of clock ticks passed between two tick values. Comparing tick values directly does not always yield the correct results; only compare the differences. Be sure that your code can service the difference before the second rollover, that is, before another 49.7 days pass. Comparisons such as the following are not safe:

#define DELTA_TICKS sample_tick_value 
// initialized somewhere in the code 
DWORD dwStartTick = GetTickCount(); 
DWORD dwEndTick =   GetTickCount() + DELTA_TICKS;     

// The following function fails on a rollover. 
BOOL no_compare_tick_difference() 
{ 
  if ( GetTickCount() > dwEndTick ) 
    return ( TRUE); 
  return (FALSE); 
}

The following code shows how to properly use GetTickCount by comparing tick differences. This code handles the rollover situation.

BOOL compare_tick_difference() 
{ 
  if ( (GetTickCount() – dwStartTick) > DELTA_TICKS) 
    return ( TRUE); 
  return (FALSE); 
}