Mögliche Fehler, die CRT-Objekte über DLL-Grenzen übergeben

Wenn Sie Objekte der C-Laufzeit (CRT) wie Dateihandles, Gebietsschemas und Umgebungsvariablen in oder aus Funktionsaufrufen (DLL) DLL-Grenze zu übergeben, kann unerwartetes Verhalten auftreten, wenn die DLL sowie die Dateien, die in der DLL aufrufen, unterschiedliche Kopien der CRT-Bibliotheken verwenden.

Ein verwandtes Problem kann auftreten, wenn Speicher belegen (entweder explizit mit new oder mallocoder implizit mit strdup, strstreambuf::strusw.) und anschließend einen Zeiger auf eine gemeinsam verwendet werden DLL-führen Begrenzung.Dies kann eine Arbeitsspeicher zugriffsverletzung oder Heap beschädigung verursachen, wenn die DLL und die Benutzer unterschiedliche Kopien der CRT-Bibliotheken verwenden.

Ein weiteres Symptom dieses Problems kann ein Fehler im Ausgabefenster während des Debuggens wie möglich:

HEAP []: Ungültige Adresse angegeben RtlValidateHeap (#, #)

Ursachen

Jede Kopie der CRT-Bibliothek verfügt über einen separaten und anderen Zustand.Daher sind CRT-Objekte wie Dateihandles, Umgebungsvariablen und Gebietsschemas für die Kopie des CRT nur gültig, in dem diese Objekte zugeordnet oder festgelegt werden.Wenn eine DLL und ihre Benutzer unterschiedliche Kopien der CRT-Bibliothek verwenden, können Sie diese CRT-Objekte über die DLL-Grenze sie übergeben und nicht davon ausgehen, dass auf der anderen Seite ordnungsgemäß aufgehoben werden soll.

Da jede Kopie der CRT-Bibliothek eigenen Heap Manager hat, Speichern belegend in einer CRT-Bibliothek und den Mauszeiger über einer durch eine andere Kopie der CRT-Bibliothek freizugebenden DLL-Grenze, ist eine mögliche Ursache für Heap beschädigung.

Wenn Sie die DLL so entwerfen, dass es oberhalb der Grenze wird CRT-Objekte, oder er außerhalb der DLL gemeinsam genutzt werden sollen und belegt Speicher erwartet, beschränken Sie die DLL-Benutzer ein, um die gleiche Kopie der CRT-Bibliothek wie die DLL zu verwenden.Die DLL und die Benutzer verwenden die gleiche Kopie der CRT-Bibliothek nur, wenn beide mit derselben Version der CRT-DLL verknüpft sind.Dies kann ein Problem darstellen, wenn Sie die Anwendungen kombinieren, die in Visual C++ 5.0 mit DLL erstellt werden, die von Visual C++ 4.1 oder früher erstellt wurden.Da die DLL-Version der CRT-Bibliothek von Visual C++ 4.1 verwendet wird, und das msvcrt40.dll von Visual 5.0 verwendet wird, msvcrt.dll ist, können Sie die Anwendung nicht erstellen, die gleiche Kopie der CRT-Bibliothek wie diese DLL zu verwenden.

Es gibt jedoch eine Ausnahme.Klicken Sie in englischer Version USA und in einigen anderen lokalisierten Versionen von Windows 2000 Deutschem, z. B. Französisch, und Tschechen, wird eine Weiterleitungs Version des msvcrt40.dll (Version 4.20) veröffentlicht.Folglich obwohl die DLL mit msvcrt40.dll verknüpft ist und der Benutzer in msvcrt.dll verknüpft ist, verwenden Sie weiterhin die gleiche Kopie der CRT-Bibliothek, da alle Aufrufe, die msvcrt40.dll gemacht werden, in msvcrt.dll weitergeleitet werden.

Allerdings ist diese Weiterleitungs Version von msvcrt40.dll nicht in einigen lokalisierten Versionen von Windows 2000, wie Japanisch, Chinesisch und Koreanisch (nur auf Englisch verfügbar).Wenn die Anwendung diese Betriebssysteme abzielt, benötigen Sie erhalten eine aktualisierte Version der DLL, die nicht auf msvcrt40.dll basiert oder ändern die Anwendung nicht für die Verwendung derselben Kopie der CRT-Bibliotheken zu verlassen.Wenn Sie die DLL entwickelt haben, bedeutet dies das Erstellen Sie mit Visual C++ 4.2 oder höher.Wenn sich eine dritte Partei DLL ist, müssen Sie dem Anbieter für Upgrades kontaktieren.

beachten Sie, dass diese Version der Weiterleitung von DLLs msvcrt40.dll (Version 4.20) nicht verteilt werden kann.

Beispiel

ms235460.collapse_all(de-de,VS.110).gifBeschreibung

In diesem Beispiel wird ein Dateihandle über eine DLL-Grenze.

Die DLL und die EXE-Datei werden mit /MD erstellt. Daher geben sie eine einzige Kopie des CRT frei.

Wenn Sie mit /MT neu erstellen, damit sie separate Kopien des CRT verwenden, führt das Ausführen des resultierenden test1Main.exe eine Zugriffsverletzung.

ms235460.collapse_all(de-de,VS.110).gifCode

// test1Dll.cpp
// compile with: /MD /LD
#include <stdio.h>
__declspec(dllexport) void writeFile(FILE *stream)
{
   char   s[] = "this is a string\n";
   fprintf( stream, "%s", s );
   fclose( stream );
}

ms235460.collapse_all(de-de,VS.110).gifCode

// test1Main.cpp
// compile with: /MD test1dll.lib
#include <stdio.h>
#include <process.h>
void writeFile(FILE *stream);

int main(void)
{
   FILE  * stream;
   errno_t err = fopen_s( &stream, "fprintf.out", "w" );
   writeFile(stream);
   system( "type fprintf.out" );
}

ms235460.collapse_all(de-de,VS.110).gifOutput

this is a string

Beispiel

ms235460.collapse_all(de-de,VS.110).gifBeschreibung

Dieses Beispiel führt Umgebungsvariablen über eine DLL-Grenze.

ms235460.collapse_all(de-de,VS.110).gifCode

// test2Dll.cpp
// compile with: /MT /LD
#include <stdio.h>
#include <stdlib.h>

__declspec(dllexport) void readEnv()
{
   char *libvar;
   size_t libvarsize;

   /* Get the value of the MYLIB environment variable. */ 
   _dupenv_s( &libvar, &libvarsize, "MYLIB" );

   if( libvar != NULL )
      printf( "New MYLIB variable is: %s\n", libvar);
   else
      printf( "MYLIB has not been set.\n");
   free( libvar );
}

ms235460.collapse_all(de-de,VS.110).gifCode

// test2Main.cpp
// compile with: /MT /link test2dll.lib
#include <stdlib.h>
#include <stdio.h>

void readEnv();

int main( void )
{
   _putenv( "MYLIB=c:\\mylib;c:\\yourlib" );
   readEnv();
}

ms235460.collapse_all(de-de,VS.110).gifOutput

MYLIB has not been set.

Wenn die DLL und die EXE-Datei mit /MD erstellt werden, sodass nur eine Kopie des CRT verwendet wird, wird das Programm erfolgreich ausgeführt und erzeugt die folgende Ausgabe:

New MYLIB variable is: c:\mylib;c:\yourlib

Siehe auch

Referenz

CRT-Bibliotheks-Funktionen