Workaround für Patchday Bug vom 12.04.2011: Wenn unter Windows 2000 der Einsprungpunkt FindActCtxSectionStringA nicht gefunden wird

Hintergrund siehe hier:
BUG: Schwarzer Patchday für Windows 2000 – MFC 8.0 (VC-2005) und MFC 9.0 (VC-2008) DLLs sind nicht mehr lauffähig nach Installation von KB2467174 bzw. KB2467175
BUG: Schwarzer Patchday für Windows 2000 2.- MFC 8.0 (VC-2005) und MFC 9.0 (VC-2008) Static Libraries erzeugen auch inkompatiblen Code für Windows 2000 durch KB2465367 bzw. KB2465361

Unter Windows 2000 kann man wie folgt vorgehen und das Problem beheben:

  1. Am Besten macht man das nachdem man das System neu gestartet hat und noch keine Anwendung gestartet hat.
  2. Alle betreffenden Hotfixe entfernen (für Runtime-2005 KB2467175, Runtime-2008 KB2467174, für VS-2007 SP1: KB2465367, VS-2008 SP1: KB2465361).
    Die betroffenen C/C++ Runtimes des Visual Studio, die deinstalliert werden müssen, haben die folgenden Versionsnummern
    – VC-2005 8.0.50727.5592 (KB2467175)
    – VC-2008 9.0.30729.5570 (KB2467174)
    Um VS-2005/2008 wiederherzustellen ist zwingend eine Deinstallation des Patches nötig.
    Die Dateien für das Visual Studio sollten dann wieder denen des letzten Fix aus 2005/2008 entsprechen.
  3. Eigentlich sollte die Deinstallation des Patches genügen.
    Sofern es sich nur um ein Problem mit den Runtimes handelt und sich das Problem nicht behoben hat kann man mit den nächsten Schritten weiter machen und versuchen die alten Dateien wieder herzustellen.
    (
    Man kann diese Schritte auch ohne Deinstallation durchführen)
  4. Für VS-2008: Die Dateien für aus dem letzten Sicherheitsupdate müssten in dem folgenden Verzeichnis unter C:\WinNT\winsxs\ liegen:
    a. x86_microsoft.vc90.mfc_1fc8b3b9a1e18e3b_9.0.30729.4974_…
    b. x86_microsoft.vc90.mfc_1fc8b3b9a1e18e3b_9.0.30729.4148_…
    c. x86_microsoft.vc90.mfc_1fc8b3b9a1e18e3b_9.0.30729.1_…
    Man wählt das Verzeichnis, dass man zuerst findet.
  5. Für VS-2005: Die Dateien für aus dem letzten Sicherheitsupdate müssten in dem folgenden Verzeichnis unter C:\WinNT\winsxs\ liegen:
    a. x86_microsoft.vc80.mfc_1fc8b3b9a1e18e3b_8.0.50727.4053_…
    b. x86_microsoft.vc80.mfc_1fc8b3b9a1e18e3b_8.0.50727.4027_…
    c. x86_microsoft.vc80.mfc_1fc8b3b9a1e18e3b_8.0.50727.1833_…
    d. x86_microsoft.vc80.mfc_1fc8b3b9a1e18e3b_8.0.50727.762_…
    Man wählt das Verzeichnis, dass man zuerst findet.
  6. Alle Dateien aus diesen gefundenen Verzeichnissen in das C:\WinNT\System32 Verzeichnis kopieren.

Hope that helps ❗

PS: Ich habe den Artikel mehrfach überarbeitet während er bereits veröffentlicht war und immer neue Infos eingebaut bzw. die Vorgehensweise besser erklärt.

BUG: Schwarzer Patchday für alle OS XP und später 3. – MFC 8.0 (VC-2005) oder MFC 9.0 (VC-2008) die dynamisch gelinkt wurden finden die MFC Sprach-DLLs evtl. nicht mehr nach Installation der Sicherheitspatches vom 12.04.2011

Betroffen sind:

  • Alle Programme die mit MFC 8.0 oder MFC 9.0 erzeugt wurden und dynamisch an die MFC DLLs gelinkt sind.
  • Alle Betriebssysteme ab Windows XP aufwärts. 32bit wie 64bit
  • Alle Programme, die nicht die MFC und CRT DLLs applikationsnah (d.h. im Programmverzeichnis, siehe dazu auch die Fußnote in meinem Artikel) installiert haben. Also alle Programme die WinSxS benutzen und die VCRedist_x86.exe ( VCRedist_x64.exe)  mit ausliefern.
  • Alle Programme, die lokalisiert sind und die MFC90xxx.DLL bzw. MFC80xxx.DLL Sprach-DLLs verwenden und das OS nicht auf Englisch eingestellt ist

Betrifft die folgenden Fixes vom 12.04.2011:

Für VS-2005 SP1 http://support.microsoft.com/kb/2465367 und http://support.microsoft.com/kb/2467175
Für VS-2008 SP1 http://support.microsoft.com/kb/2465361 und http://support.microsoft.com/kb/2467174

Effekt:

Die MFC Statelite DLLs werden nicht geladen. Teile der Anwendung erscheinen in englischer Sprache.

Hintergrund:

Um das Laden von falschen Satelite DLLs zu verhindern (Binary Planting), wurde intern in appcore.cpp in der Funktion _AfxLoadLangDLL geprüft, ob die DLLs in aus einem Activation Context geladen werden oder nicht. Sollte ein Activation Context vorhanden sein, dann kann man gefahrlos die Sprach DLLs (MFCDEUxxx.DLL etc.) ohne Pfadnamen laden. Ist kein Activation Context vorhanden wird der Pfad der Anwendung verwendet und LoadLibrary mit vollem Pfadnamen durchgeführt.

Der Code der dazu verwendet wird sieht so aus (Leerzeilen entfernt):

...
TCHAR *pszFilename = ::PathFindFileName(szLangDLL);
ACTCTX_SECTION_KEYED_DATA data;
if (FindActCtxSectionString(
    FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX,
    NULL,
    ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
    pszFilename,
    &data) )
{
    // Load using the dll name only...
    hInstance = ::LoadLibraryEx(pszFilename, NULL, 0);
}
else
{
    // Load using the full path...
    hInstance = ::LoadLibraryEx(szLangDLL, NULL, 0);
}
...

Eigentlich sieht der Code prima aus. Und er verträgt sich auch mit der Doku von FindActCtxSectionString dort wird der letzte Parameter als __out definiert.

BOOL FindActCtxSectionString(
  __in   DWORD dwFlags,
  __in   const GUID *lpExtensionGuid,
  __in   ULONG ulSectionId,
  __in   LPCTSTR lpStringToFind,
  __out  PACTCTX_SECTION_KEYED_DATA ReturnedData
);

Aber die Doku zu ACTCTX_SECTION_KEYED_DATA sagt was anderes:

Callers should initialize the ACTCTX_SECTION_KEYED_DATA structure as such:
„ACTCTX_SECTION_KEYED_DATA askd = { sizeof(askd) };“
which initializes all members to zero/null except the size field which is set correctly.

(BTW: Auch ein krasser Doku-Bug in meinen Augen)

Und jetzt sieht man was dem Code fehlt: data.cbSize wird nicht gesetzt
Daraus ergeben sich nun drei Varianten, da data.cbSize nun zufälligen (nicht initialisierten) Inhalt hat:

  1. data.cbSize ist größer als  sizeof(ACTCTX_SECTION_KEYED_DATA):
    In diesem Fall wird korrekt ermittelt ob ein Activation Context vorhanden ist. Das Programm läuft normal. Mit Activation Context ist kein voller Pfadname nötig. Die MFC90xxx.DLL wird evtl. aus dem WinSxS (Side by Side) geladen, oder in einem der Suchpfade gefunden.
  2. data.cbSize ist kleiner als  sizeof(ACTCTX_SECTION_KEYED_DATA):
    In diesem Fall liefert FindActCtxSectionString einen Fehler und nun wird es spannend. Die DLL wird nun versucht mit dem vollen Pfadnamen zu laden um Binary Planting zu verhindern. Das Problem ist aber dass bei korrekter Installation im WinSxS, dass im Applikationsverzeichnis keine dieser Daten liegen. Die DLL wird nicht gefunden.
    Sollten die private applikationsnahe Assemblies in einem Unterverzeichnis installiert sein, werden diese auch nicht gefunden.
  3. Für die Zukunft.
    Ein zukünftiges OS vergrößert ACTCTX_SECTION_KEYED_DATA und data.cbSize hat zufälligen Inhalt und ist größer als sizeof(…):
    Ein Buffer-Overrun!

Ich empfehle nicht ohne Grund seit VS-2005 private Assemblies zu verwenden, und die MFC Dateien in das Anwendungsverzeichnis zu kopieren. Dazu habe ich auf Code-Projekt einen entsprechenden Artikel geschrieben und ein Hotfix für VS-2008 existiert auch ❗
Create projects easily with private MFC, ATL and CRT assemblies
Hotfix für UseMSPrivateAssemblies.h und VC-2008

Was ist zu tun?

Deinstallation aller hier erwähnten Sicherheitspatches mit den entsprechenden Arikelnummern:
Runtime-2005: KB2467175, Runtime-2008: KB2467174
VS-2007 SP1: KB2465367, VS-2008 SP1: KB2465361).

Weitere Anmerkungen:

Die betroffenen C/C++ Runtimes des Visual Studio haben die folgenden Versionsnummern
– VC-2005 8.0.50727.5592 (KB2467175)
– VC-2008 9.0.30729.5570 (KB2467174)

Mein Kommentar dazu:
Das Leben in der DLL-Hölle war fast angenehmer als das hier. Ohne Worte 🙁

Herzlichen Dank auch an meinem Mit-MVP Mike Ryan, der mit mir zusammen auf diese gesamte Problematik gestoßen ist ❗

Was meine ich mit „application local“?
Einige Entwickler installieren die MFC runtme Dateien im Applikationsverzeichnis. In diesem Fall werden diese DLLs nicht verwendet wenn eine neuere Version der DLLs im WinSxS Verzeichnis liegen. Das ist für mich keine applikationsnahe Instalation! Diese Manifeste im Programmverzeichnis haben immer noch einen publicKey Eintrag. Aber durch die Existenz der lokalen Dateien wird dieses hier beschriebene Problem umgangen, weil die lokalen Dateien eine Art Fallback bilden.
Meine Artikel beschriben wie man eine Anwendung wirklich applikationslokal macht und damit unabhängig von solchen „kaputten“ Security Patches. Dazu muss der publicKey Token aus den Manifesten entfernt werden. (Lesen Sie meinen Artikel aufCodeproject).
(Danke an Co-MVP David Ching der mich um Kläurung gebeten hat)

BUG: Schwarzer Patchday für Windows 2000 2.- MFC 8.0 (VC-2005) und MFC 9.0 (VC-2008) Static Libraries erzeugen auch inkompatiblen Code für Windows 2000 durch KB2465367 bzw. KB2465361

Wer VS-2005 SP1 oder VS-2008 SP1 installiert hatte und bei dem auch die entsprechenden Patches von gestrigen Tag (12.04.2011) durchlaufen wurden, der hat nun auch veränderte statische Libraries.

Sollte man nun also EXEs oder DLLs mit den neuen Libararies statisch linken, dann sind diese genausowenig lauffähig unter Windows 2000. wie auch die EXEs und DLLs die gegen die MFC 8.0 bzw. MFC 9.0 DLLs gelinkt werden

Das Ganze ist hier aufgelistet:
für VS-2005 SP1 http://support.microsoft.com/kb/2465367
für VS-2008 SP1 http://support.microsoft.com/kb/2465361

Die LIBs sind aufgeführt und auch diese verwenden auch die Funktion FindActCtxSectionStringA, die natürlich nicht unter Windows 2000 vorhanden ist.

Siehe auch:
http://blog.m-ri.de/index.php/2011/04/13/bug-schwarzer-patchday-fur-windows-2000-mfc-8-0-vc-2005-und-mfc-9-0-vc-2008-dlls-sind-nicht-mehr-lauffahig-nach-installation-von-kb2467175-bzw-kb2467175/

PS: Ich kann nur raten die entsprechenden Patches zu deinstallieren sofern man noch für Windows 2000 entwickelt und warten bis neue Securitypatches vorhanden sind.

Nachtrag:
Die betroffenen C/C++ Runtimes des Visual Studio haben die folgenden Versionsnummern
– VC-2005 8.0.50727.5592 (KB2467175)
– VC-2008 9.0.30729.5570 (KB2467174)

BUG: Schwarzer Patchday für Windows 2000 – MFC 8.0 (VC-2005) und MFC 9.0 (VC-2008) DLLs sind nicht mehr lauffähig nach Installation von KB2467174 bzw. KB2467175

Ein wirklich übler Patchday von Microsoft für ale Windows 2000 Nutzer.
In den Sicherheitsfixes für Visual Studio 2005 und 2008 wurden auch die Runtime Module der MFC 8.0 und MFC 9.0 „gefixed“.
Siehe http://support.microsoft.com/kb/2467175 für VS-2005
Siehe http://support.microsoft.com/kb/2467174 für VS-2008

Es wurde ein Fix eingebaut, den wir schon in VS-2010 gesehen haben, der vermeiden soll, dass Satelite DLLs nur noch aus dem Verzeichnis geladen werden, in dem auch die MFC DLLs liegen
(gegen ‘Binary Planting’, d.h. unterschieben gefakter DLLs aus anderen Verzeichnissen).

Leider wurde dabei die Funktion FindActCtxSectionStringA mit eingebaut und verwendet. Eine Funktion die aber erst ab Windows XP vorhanden ist. Sofern man also eine Anwendung unter Windows 2000 hat, die die MFC80.DLL, MFC80U.DLL, MFC90.DLL oder MFC90U.DLL aus dem WINDOWS\SYSTEM32 Verzeichnis verwendet, dann hat man seit dem dem Patchday von gestern ein massives Problem. Die DLLs können nicht mehr geladen werden. 😯

Einziger Rat ist hier, die neuen Dateien löschen und die ungepatchten Versionen installieren und das am besten direkt in den Programmverzeichnissen ❗
Alte Runtimes für VS-2005 SP1 http://www.microsoft.com/downloads/en/details.aspx?FamilyID=200b2fd9-ae1a-4a14-984d-389c36f85647
Alte Runtimes für VS-2008 SP1 http://www.microsoft.com/downloads/en/details.aspx?FamilyID=a5c84275-3b97-4ab7-a40d-3802b2af5fc2
Alle Versionen mit den VCRedist_x86.exe Versionen und dem Datum vom 13.04.2010 sind für Windows 2000 tabu.
Das heißt auch, dass man diese DLLs nicht in seinem eigenen Setup für Windows 2000 ausrollen sollte.

Nicht betroffen sind Applikationen, die diese DLLs applikationsnah, d.h. im Programmverzeichnis installieren.
Eine Methode, die ich seit Jahren empfehle!

Nur noch einmal zur Klarstellung: Der Sicherheitspatch ist nur problematisch für Windows 2000 Rechner ❗

PS: Was bin ich froh, dass wir Windows 2000 schon lange nicht mehr unterstützen :mrgreen:

PPS: Bei solch einem Fehler frage ich mich ob hier irgend jemand überhaupt etwas getestet hat, außer das die Installation durchgeführt wird.

Nachtrag:
Die betroffenen C/C++ Runtimes des Visual Studio haben die folgenden Versionsnummern
– VC-2005 8.0.50727.5592 (KB2467175)
– VC-2008 9.0.30729.5570 (KB2467174)

Workaround:
Workaround für Patchday Bug vom 12.04.2011: Wenn unter Windows 2000 der Einsprungpunkt FindActCtxSectionStringA nicht gefunden wird

BUG: VS-2010 erkennt nicht die Änderung an einer Manifest Datei in einem C++ Projekt

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.

Massive Probleme mit ADO auf Windows 7 SP1

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… 😉

BUG: Breaking Change durch VS-2010 SP1 für manche C++/CLI Projekte

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.

BUG: VC-2010 regex liefert falsche Ergebnisse bei Verwendung von Repetitions/Wiederholungen

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

virtuelle Funktionen und const sind immer wieder eine Freude… oder wie C++0x einen Fehler verhindert hätte…

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:

BUG: VC-2010 ftell liefert negative Werte wenn eine UTF-8 Datei mit ccs=UNICODE geöffnet wird, die nicht mit fseek funktionieren

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