C++ProgrammierenVS 2010Martin Richter - Sa 09 Apr 2011 20:53

Ich habe einige Manifest Dateien in meinen Projekten. Viele steuern COM Module und machen diese registration-free. Das ist einfach und effektiv. Dazu habe ich einfach eine entsprechende Manifestdatei angelegt mit den entsprechenden Einträgen und diese in das Projekt eingefügt. Soweit alles gut.

Jetzt stellte sich aber heraus, dass VS-2010 (auch SP1), eine Änderung der Manifest Datei nicht bemerkt und die EXE/DLL weder neu linkt, noch das Manifest-Tool anwirft, um das geänderte Manifest in das Executable einzutragen.

Dabei spielt es keinerlei Rolle, ob die Datei nur einfach in das Projekt eingefügt wurde, oder ob die Datei zusätzlich in den Projekteinstellungen für das Manifest Tool bei Additional Manifest Files eingetragen wird.

Das ist ein lästiger Fehler, der in VS-2005 und VS-2008 nicht vorhanden war.
Er hat mich mindestens 4 Stunden Arbeit gekostet, weil ich bestimmte Abhängigkeiten testen und Fehler beheben wollte aber die neuen Dateien in dem Projekt immer wieder SxS Fehler lieferten. Es dauerte eine ganze Weile bis ich merkte, dass meine Änderungen an den Manifest Dateien überhaupt nicht in meine Executables übernommen wurden und ich immer wieder nur alte Manifeste in den EXEs und DLLs hatte.
Und dann das Ganze an einem Montagmorgen und nach der Zeitumstellung… ;)

Auf Connect habe ich einen entsprechenden Bug veröffentlich und mir wurde ein Fix empfohlen, der bei mir das Problem behebt.
Changes to a Manifest file in a C++ project does not trigger a rebuild of the EXE or DLL

In der Datei %Programfiles%\msbuild\microsoft.cpp\v4.0\Microsoft.cppcommon.targets wird die folgenden Kommentarzeile gesucht:

<!-- If RC did produce an output, then force link to embed that manifest.
     This enforcement is required for projects residing on FAT32 drives. -->

Darunter wird der folgende Textblock eingefügt:

<PropertyGroup>
    <LinkSkippedExecution Condition="@(RCSourcesCompiled)!=''">
        false
    </LinkSkippedExecution>
</PropertyGroup>

Danch wird eine Änderung im Manifest korrekt erkannt und der Linker für die geänderte Ressouce angeworfen.

ProgrammierenSoftwareVista / Windows 7Windows 7Martin Richter - Mi 16 Mrz 2011 00:25

Windows 7 SP1 scheint einige Probleme in Bezug auf ADO zu haben. So jedenfalls hat dies Mike Ryan gemeldet.
Hier die beiden Threads in den MSDN Foren, die von den Problemen berichten:

  1. Massive Thread-Handle Leaks bei asnychronen Operationen:
    ADO, adAsyncExecute and Windows 7 SP1 handles leaking
    http://social.msdn.microsoft.com/Forums/en/sqldataaccess/thread/68e23681-f6b5-4ed5-b963-e63e34eeac2f
    Dieser Bug wurde bereits von Microsoft bestätigt.
    Wer einen Fix braucht muss sich an den Microsoft Support wenden.
  2. Das zweite Problem betrifft die COM Registrierung für Applikationen, die auf Windows 7 SP1 Maschinen gebaut werden.
    Breaking change in MDAC ADODB COM components in Windows 7 Service Pack 1
    http://social.msdn.microsoft.com/Forums/en-US/windowsgeneraldevelopmentissues/thread/3a4ce946-effa-4f77-98a6-34f11c6b5a13
    Siehe auch:
    http://blogs.technet.com/b/asiasupp/archive/2011/03/14/changes-in-mdac-adodb-com-components-in-windows-7-service-pack-1.aspx

PS: Ich bin ziemlich froh, dass ich direkt auf OLD-DB arbeite… ;)

C++ProgrammierenVS 2010Martin Richter - Mo 14 Mrz 2011 00:36

Am 09.03. wurde im US-VCGeneral Forum ein Bug öffentlich, der durch SP1 verursacht wurde.
http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/4b8f353d-8153-45d6-b286-10403cdf159a

Nachdem die Produktgruppe auf diesen Fehler aufmerksam gemacht wurde, hat sie einen entsprechenden Workarround veröffentlicht:
http://blogs.msdn.com/b/vcblog/archive/2011/03/11/10140139.aspx

Wichtig :!:
Betroffen sind nur Projekte bei denen C++/CLI Assemblies im Linker Prozess signiert werden.
Normale native C++ Projekte sind von diesem Fehler nicht betroffen.

C++ProgrammierenVS 2008VS 2010Martin Richter - Fr 04 Mrz 2011 17:25

In der regex Implementierung von VS-2010 ist ein relativ fataler Bug drin, der auftritt, wenn man Repetitions (Wiederholungen, {n}) verwendet.
Wie zum Beispiel hier in diesem Beispiel.

#include <stdio.h>
#include <ios>
#include <iostream>
#include <ostream>
#include <regex>
#include <string>
using namespace std;
 
void test(const string& s, const string& reg)
{
  cout << "---------------" << endl;
  cout << "s: " << s << endl;
  cout << "r: " << reg << endl;
 
  const regex r(reg);
  cout << boolalpha << regex_match(s, r) << endl;
}
 
int main()
{
 printf("%02d.%02d.%05d.%02d\n",
          _MSC_VER / 100,
          _MSC_VER % 100,
          _MSC_FULL_VER % 100000,
          _MSC_BUILD);
 
  test("56." , "(([0-9]{1,2})\\.){1}");
  test("1." ,  "(([0-9]{1,2})\\.){1}");
  test("56.1.", "(([0-9]{1,2})\\.){2}");
 
}

Der erste und zweite Ausdruck führt zu einem Match. Der dritte Ausdruck ist eigentlich nur der kombinierte Test, der beide Ausdrücke in einem testet.
Der Fehler wird auch in SP1 nicht gefixed sein.

Meine Tests ergaben, dass in VS-2008 SP1 bei der das ganze tr1-Zeugs in VisualStudio Einzug genommen hat, noch alles korrekt funktioniert hat.

Nachtrag (07.03.2010): Es gibt auch einen entsprechenden Bug auf Connect:
https://connect.microsoft.com/VisualStudio/feedback/details/648543/tr1-regex-doesnt-match-a-valid-pattern-with-repetition#tabs

C++ProgrammierenMartin Richter - Fr 28 Jan 2011 18:09

Wieder mal hat sich in unserer Software ein kleiner und ganz mieser Fehler eingeschlichen, obwohl der Entwickler “eigentlich” an alles gedacht hatte.

class A
{
...
    virtual void Doit() const;
...
};
 
class DerivedA : public A
{
...
    virtual void Doit(); 
...
};
 
void Foo()
{
...
    A *pA = Something();
...
    pA->Doit();
...
}

Sieht alles gut aus. Leider fehlt das kleine nette Wort const beim Überscheiben der Funktion Doit und daraus folgt, dass DerivedA::Doit niemals aufgerufen wird.

Obwohl wir VC-2010 verwenden, hat der neue C++0x Standard noch keinen Einzug in unseren Köpfen gefunden.
Das kleine Wort override in DerivedA hätte diesen Fehler verhindert.

class DerivedA : public A
{
...
    virtual void Doit() override;
// This line results in:
 
// error C3668: 'DerivedA::Doit' :
// method with override specifier 'override' did
// not override any base class methods
...
};

Es wird wirklich Zeit, dass C++0x auch wirklich genutzt wird, aber wie alles Neue muss man es sich besonders am Anfang immer wieder bewusst machen, damit es einem direkt zur Angewohnheit wird.
override ist sogar schon in VC-2008 und dem nativen Compiler implementiert. Allerdings wundert es mich, dass hier nicht dann auch gleich das Schlüsselwort new eingeführt wurde.
Aber das man unter dem gleichen Namen wirklich einen neuen Slot in der vtable aufmacht ist wirklich eher selten. Ich persönlich hatte dafür bisher noch keine Verwendung. 

Leider ist C++0x  nicht komplett in der C++ Doku in der MSDN hervorgehoben. Man kann nicht mal erkennen, dass sealed und abstract MS-Extensions sind, und override im Standard verankert ist. Schade…

Damit man sich etwas besser einen halbwegs kompletten Überblick verschaffen kann habe ich hier ein paar Links zusammengestellt.

Siehe auch:

C++CRTMFCProgrammierenVS 2008VS 2010Martin Richter - Mo 27 Dez 2010 09:33

In VS-2005 hielt die Unicode und UTF-8 Unterstützung Einzug in die CRT und damit auch in die MFC. Jochen und ich haben dazu gebloggt.

Leider ist die Implementierung nicht fehlerfrei. Wenn man eine UTF-8 Datei mit ccs=UNICODE öffnet dann liefert ftell zum Teil auch negative Werte. Das ftell nicht die exakte Position in der Datei liefert ist dokumentiert, nur sollte es mit dem Wert zumindest möglich sein wieder fseek aufzurufen um an eine alte Dateiposition zurück zu gelangen.
Das ist mit der jetzigen Implementierung nicht möglich.

Ein Sample dazu ist schnell gebaut:

int _tmain()
{
  FILE *file = NULL;
  if (_tfopen_s(&file,_T("Test.txt"),_T("rt") _T(", ccs=UNICODE")))
    return -1;
 
  TCHAR szBuffer[_MAX_PATH];
  while (_fgetts(szBuffer,_countof(szBuffer),file))
  {
    int iPos = static_cast(ftell(file));
    _tprintf(_T("%d\n"),iPos);
    _ASSERTE(fseek(file,iPos,SEEK_SET)==0);
  }
 
  fclose(file);
  return 0;
}

Ein entsprechendes Sample kann man hier herunterladen.

Der Fehler betrifft natürlich auch die MFC mit CStdioFile und GetPosition!

Hintergrund:
Ich kam auf den Fehler, weil wir ein Programm benutzen, dass sich bestimmte Dateipositionen merkte um einen Datenimport bei einer bestimmten Bedingung, ab einer definierten Stelle, neu aufnehmen zu können. Bisher hatten wir hier nur pure ASCII Dateien erlaubt, jetzt wollten wir auch UTF-8 Dateien unterstützen.
Sicher man kann auch alles im Speicher zwischenhalten, aber wenn es eine simple Dateiposition ist das Ganze so weitaus Ressourcen schonender.

Soweit ich das übersehen kann, betrifft der Fehler alle VS-Versionen ab VS-2005. Ein entsprechende Bug wurde von mir schon vor längerer Zeit auf Connect geöffnet. Getan hat sich bisher noch nichts:
https://connect.microsoft.com/VisualStudio/feedback/details/591030/ftell-returns-negative-value-for-utf-8-files-opened-with-textmode-and-ccs

ProgrammierenMartin Richter - Do 16 Dez 2010 19:29

 Für einige Legacy-Anwednungen habe ich virtuelle Maschinen mit VC6 und VS-2005.

Bei der VS-2005 Maschine hatte ich in er letzten Zeit das Gefühl, dass die Kiste immer langsamer wird. Also ging ich etwas auf die Suche und fand schließlich die Ursache.

In dem Verzeichnis C:\Users\Name\AppData\Local\Microsoft\WebsiteCache fanden sich nicht weniger als 50000 (in Worten Fünfzigtausend Verzeichnisse) unscheinbar brachte jedes Öffnen einer Solution ein weiteres Verzeichnis für jedes Projekt in der Solution.

Ein bekannter Bug, wie ich nach weiterer Recherche herausfand:
https://connect.microsoft.com/VisualStudio/feedback/details/347228/large-numbers-of-websitecache-files-slowing-visual-studio-2005-and-windows-performance?wa=wsignin1.0

Nachdem ich die Verzeichnisse entsorgt hatte, war auch wieder die gewohnte Geschwindigkeit da.

ProgrammierenVS 2010Martin Richter - Mo 22 Nov 2010 20:19

 Toll ist, das es für VS-2010 wirklich viele nützliche Extensions gibt. Das heißt aber auch, dass man des öfteren mal ein Update einer solchen Extension installiert. Und jetzt wird es ärgerlich. Jedesmal wenn man ein Update einer Extension installiert dann sind alle Tastaturzuordnungen auf ALLE Extensions und Addins futsch.

Mich hat das so genervt, dass ich einen entsprechenden Bugreport eingereicht habe:
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=621929

Wie man lesen kann: “A known issue!”. Na dann hoffen wir mal auf einen Hotfix… ;) (also bitte gebt Eure Votes ab), wie immer stirbt die Hoffnung zuletzt..

Ich kann jedem nur raten, die eigenen Einstellungen des Visual-Studios über die Import/Export Funktionen regelmäßig zu sichern. Dann kann man bei Bedarf auch die Tastaturmappings alleine wieder zurückspielen…

DebuggingProgrammierenSQLMartin Richter - Mi 22 Sep 2010 21:34

Nach einem der letzten Updates unserer Software meldete uns ein Kunde einen SQL Fehler, der bei einer bestimmten Operation auftrat. Er setzt den MS-SQL Server 2008 ein.

OK, meine Testumgebung hat drei Server von SQL 2000, über 2005 bis 2008 R2. Keine der Testumgebungen brachte bei der entsprechenden gleichen Operation einen Fehler :-? Gut oder besser schlecht… Der Kunde bekommt nun eine Fehlermeldung und auch wenn Kunden meistens ja nicht recht haben wenn sie Fehler melden :D  schaute ich mir dennoch alle SQL Befehle etwas genauer an, die meine Software da auslöste.
In dem entsprechenden Teil meiner wurde nach Benutzerangaben ein relativ komplexer Query durch einen Abfragegenerator zusammengebaut. Darunter fand sich auch der folgende Subquery, als Teil der gesamten Abfrage:

SELECT a.[Id] FROM [tblXYZ] AS a
  WHERE
    (((a..[IdParent] IS NULL
       AND a..[Id] NOT IN
         (SELECT [IdXYZ]
            FROM [tblSomething]
              WHERE [IdParent] IS NOT NULL))))

Unschwer zu sehen werden hier mit dem Alias a zusammen irgendwie zwei Punkte verwendet. Bleibt die Frage warum in meiner Umgebung nun kein Fehler passiert und beim Kunden ein nun Syntax Fehler ausgelöst wird.

Nach einigem Suchen fand ich die Ursache im Kompatibilitätsgrad, den man im Managementstudio unter Datenbank -> Datenbankname -> Eigenschaften -> Optionen je Datenbank separat einstellen kann. Dort sind folgende Einstellungen möglich.

SQL Server 2000 (80)
SQL Server 2005 (90)
SQL Server 2010 (100)

In meiner Testumgebung verwende ich eine Datenbank, die seit den ersten Anfängen unserer Software immer weiter als Testumgebung mit vielen Testdaten dient. Sie wurde erstmals auf einem SQL Server 2000 angelegt. Dann auf einen 2005er und schließlich auf einen SQL Server 2008 R2 umgezogen. Netterweise – oder besser dummerweise – hat sich der SQL Server bei jeder Umstellung die ehemalige Kompatibilität gemerkt. Und man staunt nicht schlecht: Auf einem SQL Server 2000 ist es kein Fehler zwischen Alias und Spaltennamen zwei Punkte zu schreiben. Bei einem SQL Server 2005 oder später ist das sehr wohl ein Syntaxfehler.
Der Fehler lag also doch bei uns - was ja wirklich selten vorkommt :D – und wurde trotz genauer Tests nicht entdeckt.

Man merke sich: SQL Server Syntax ist trotz gleicher SQL Server Version eben doch lange nicht das selbe.
Wer also Software auf einem SQL Server testet sollte tunlichst darauf achten welchen Kompatibilitätsgrad er benutzt :!:

C++ProgrammierenVS 2010Martin Richter - Sa 04 Sep 2010 15:15

Die STL Implementierung wurde klar hinsichtlich “perfect forwarding” überarbeitet (Siehe C++0x). Allerdings sind dabei auch einige Sachen reingerutscht die dazu führen, dass sich mancher Code nicht mehr kompilieren lässt.

So führen die nachfolgenen Zeilen zu einem Compiler Fehler:

std::pair<void*,void*> p(0, NULL);
// fails with error C2440: 'initializing' : cannot convert from 'int' to 'void *'

Gleiches negatives Ergebnis erhält man, wenn man die folgenden Zeile kompiliert:

vector<void*> v; 
v.insert(v.begin(),NULL);

Der Hintergrund wird hier in dieser Connect Meldung beleuchtet:
https://connect.microsoft.com/VisualStudio/feedback/details/520043/error-converting-from-null-to-a-pointer-type-in-std-pair?wa=wsignin1.0

Das Problem ist, das 0 (NULL) sich zwar brav in einen Zeiger umwandeln lässt. 0 (NULL) bleibt aber deshalb dennoch vom Typ her ein int ist wird nicht zu einem Zeiger. Die typensichere Implementierung in der STL führt nun dazu, dass 0 (NULL) nicht als void* akzeptiert wird.

Einzige Lösung und auch mein Rat:
Man verwendet nicht mehr 0 oder NULL, wenn ein NULL-Zeiger gemeint ist, sondern nullptr :!:
Wer Code kompatibel zu VC-2008 und früher halten muss, kann ja in seinen Headern den folgende Definition einführen:

#if  _MSC_VER<1600
const int nullptr = 0;
#endif

Mehr zu perfect forwarding liest man hier:
http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1385.htm
http://thbecker.net/articles/rvalue_references/section_07.html

Wie auch aus dem Connect Artikel zu entnehmen ist kann man damit rechnen, dass sich in VC11 alles wieder etwas zurückentwickeln wird. D.h. std::pair und auch die insert Befehle der Container sollen wirde brav 0 aktzeptieren können, wenn Zeiger gemeint sind. Gleiches bekam ich auch über meine Kontakte zur Produktgruppe zu höhren. Aber was VC11 betrifft ist alles sowieso nur Zukunftsmusik und alles noch im dichten Nebel und was wirklich Realität wird  muss man dann wohl erst mal sehen ;)

Nachtrag vom 09.09.2010:
Dravere hat in einem Kommentar auf eine geniale Implementierung für nullptr hingewiesen:
http://www.c-plusplus.de/forum/viewtopic-var-t-is-220511.html
Die ist weitaus besser als meine Definition als const int.

const class
{
public:
  template<class T> operator T*() const {return 0;}
  template<class C, class T> operator T C::*() const {return 0;}
private:
  void operator&() const;
}
nullptr = {};

« Vorhergehende SeiteNächste Seite »