Verwenden des C-Run-Time
In diesem Artikel wird die Verwendung der C-Laufzeit beschrieben.
Originalversion des Produkts: Visual C++
Ursprüngliche KB-Nummer: 94248
Abschnitt 1: Drei Formen von C Run-Time (CRT)-Bibliotheken sind verfügbar
Es gibt drei Formen der C-Laufzeitbibliothek, die mit dem Win32 SDK bereitgestellt wird:
LIBC. LIB ist eine statisch verknüpfte Bibliothek für Singlethread-Programme.
LIBCMT. LIB ist eine statisch verknüpfte Bibliothek, die Multithread-Programme unterstützt.
CRTDLL. LIB ist eine Importbibliothek für CRTDLL.DLL, die auch Multithread-Programme unterstützt. CRTDLL.DLL selbst ist Teil von Windows NT.
Microsoft Visual C++ 32-Bit-Edition enthält auch diese drei Formen, die CRT in einer DLL heißt jedoch MSVCRT. LIB. Die DLL ist weitervertreibbar. Der Name hängt von der Version der VC++ (d. h. MSVCRT10.DLL oder MSVCRT20.DLL) ab. Beachten Sie jedoch, dass MSVCRT10.DLL auf Win32s nicht unterstützt wird, während CRTDLL. LIB wird auf Win32s unterstützt. MSVCRT20.DLL gibt es in zwei Versionen: eine für Windows NT und die andere für Win32s.
Abschnitt 2: Verwenden der CRT-Bibliotheken beim Erstellen einer DLL
Wenn Sie eine DLL erstellen, die eine der C-Laufzeitbibliotheken verwendet, um sicherzustellen, dass die CRT ordnungsgemäß initialisiert ist, entweder
Die Initialisierungsfunktion muss benannt
DllMain()werden, und der Einstiegspunkt muss mit der Linkeroption angegeben werden.-entry:_DllMainCRTStartup@12oder
Der Einstiegspunkt der DLL muss die Prozessanfügung und die Prozessabtrennung explizit aufrufen
CRT_INIT().
Dies ermöglicht es den C-Laufzeitbibliotheken, C-Laufzeitdaten ordnungsgemäß zuzuordnen und zu initialisieren, wenn ein Prozess oder Thread an die DLL angefügt wird, C-Laufzeitdaten ordnungsgemäß zu bereinigen, wenn sich ein Prozess von der DLL trennt, und damit globale C++-Objekte in der DLL ordnungsgemäß erstellt und detruiert werden.
Die Win32 SDK-Beispiele verwenden alle die erste Methode. Verwenden Sie sie als Beispiel. Weitere Informationen finden Sie in der Win32-Programmierreferenz für DllEntryPoint() und in der Visual C++-Dokumentation für DllMain(). Beachten Sie, dass DllMainCRTStartup() CRT_INIT() dllMain() der Anwendung aufgerufen und CRT_INIT() aufgerufen wird, sofern vorhanden.
Wenn Sie die zweite Methode verwenden und den CRT-Initialisierungscode selbst aufrufen möchten, anstatt sie zu verwenden DllMainCRTStartup() , DllMain()gibt es zwei Techniken:
Wenn es keine Einstiegsfunktion gibt, die Initialisierungscode ausführt, geben Sie
CRT_INIT()als Einstiegspunkt der DLL an. Angenommen, Sie haben NTWIN32 eingeschlossen. MAK, das definiertDLLENTRYals @12, fügen Sie die Option zur Linkzeile der DLL hinzu:-entry:_CRT_INIT$(DLLENTRY).oder
Wenn Sie über einen eigenen DLL-Einstiegspunkt verfügen, gehen Sie im Einstiegspunkt wie folgt vor:
Verwenden Sie diesen Prototyp für
CRT_INIT():BOOL WINAPI _CRT_INIT(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);Informationen zu
CRT_INIT()Rückgabewerten finden Sie in der Dokumentation DllEntryPoint; die gleichen Werte werden zurückgegeben.On
DLL_PROCESS_ATTACHandDLL_THREAD_ATTACH(see DllEntryPoint in the Win32 API reference for more information on these flags), callCRT_INIT(), first, before any C Run-time functions are called or any floating-point operations are performed.Rufen Sie Ihren eigenen Prozess-/Threadinitialisierungs-/Beendigungscode auf.
On
DLL_PROCESS_DETACHundDLL_THREAD_DETACH, callCRT_INIT()last, after all C Run-time functions have been called and all floating- point operations are completed.
Achten Sie darauf, alle Parameter des Einstiegspunkts zu übergeben CRT_INIT() ; CRT_INIT() erwartet diese Parameter, sodass die Dinge möglicherweise nicht zuverlässig funktionieren, wenn sie weggelassen werden (insbesondere ist fdwReason erforderlich, um zu bestimmen, ob eine Prozessinitialisierung oder -beendigung erforderlich ist).
Unten sehen Sie eine Beispiel-Einstiegspunktfunktion, die zeigt, wann und wie diese Aufrufe CRT_INIT() im DLL-Einstiegspunkt ausgeführt werden:
BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason,
LPVOID lpReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH || fdwReason == DLL_THREAD_ATTACH)
if (!_CRT_INIT(hinstDLL, fdwReason, lpReserved))
return(FALSE);
if (fdwReason == DLL_PROCESS_DETACH || fdwReason == DLL_THREAD_DETACH)
if (!_CRT_INIT(hinstDLL, fdwReason, lpReserved))
return(FALSE);
return(TRUE);
}
Hinweis
Dies ist bei Verwendung von DllMain() und -entry:_DllMainCRTStartup@12nicht erforderlich.
Abschnitt 3: Verwenden von NTWIN32. MAK zur Vereinfachung des Erstellungsprozesses
In NTWIN32 sind Makros definiert. MAK, der verwendet werden kann, um Ihre Makefiles zu vereinfachen und sicherzustellen, dass sie ordnungsgemäß erstellt wurden, um Konflikte zu vermeiden. Aus diesem Grund empfiehlt Microsoft dringend die Verwendung von NTWIN32. MAK und die darin vorhandenen Makros.
Verwenden Sie für die Kompilierung Folgendes: $(cvarsdll) for apps/DLLs using CRT in a DLL.
Verwenden Sie zum Verknüpfen eine der folgenden Aktionen:
$(conlibsdll) for console apps/DLLs using CRT in a DLL$(guilibsdll) for GUI apps using CRT in a DLL
Abschnitt 4: Probleme bei der Verwendung mehrerer CRT-Bibliotheken
Wenn eine Anwendung, die C-Laufzeitaufrufe ausführt, Links zu einer DLL erstellt, die auch C-Laufzeitaufrufe ausführt, sollten Sie beachten, dass beide mit einer der statisch verknüpften C-Laufzeitbibliotheken (LIBC) verknüpft sind. LIB oder LIBCMT. LIB), die .EXE und DLL werden separate Kopien aller C-Laufzeitfunktionen und globalen Variablen aufweisen. Dies bedeutet, dass C-Laufzeitdaten nicht zwischen dem .EXE und der DLL freigegeben werden können. Einige der Probleme, die als Ergebnis auftreten können, sind:
Übergeben gepufferter Datenstromziehpunkte von der .EXE/DLL an das andere Modul
Zuordnen von Speicher mit einem C-Laufzeitaufruf in der .EXE/DLL und Neuverlagern oder Freigeben des Speichers im anderen Modul
Überprüfen oder Festlegen des Werts der globalen errno-Variablen in der .EXE/DLL und erwartet, dass er im anderen Modul identisch ist. Ein verwandtes Problem ist das Aufrufen
perror()des entgegengesetzten Moduls, von dem aus der C-Laufzeitfehler aufgetreten ist, daperror()errno verwendet wird.
Um diese Probleme zu vermeiden, verknüpfen Sie sowohl die .EXE als auch die DLL mit CRTDLL. LIB oder MSVCRT. LIB, mit der sowohl die .EXE als auch die DLL den allgemeinen Satz von Funktionen und Daten verwenden können, die in CRT in einer DLL enthalten sind, und C-Laufzeitdaten wie Datenstromziehpunkte können dann sowohl vom .EXE als auch von der DLL freigegeben werden.
Abschnitt 5: Mischen von Bibliothekstypen
Sie können Ihre DLL mit CRTDLL verknüpfen. LIB/MSVCRT. LIB unabhängig davon, womit Ihre .EXE verknüpft ist, wenn Sie vermeiden, CRT-Datenstrukturen zu mischen und CRT-Dateihandles oder CRT FILE*-Zeiger an andere Module zu übergeben.
Beim Mischen von Bibliothekstypen beachten Sie Folgendes:
CRT-Dateihandles dürfen nur vom CRT-Modul betrieben werden, das sie erstellt hat.
CRT FILE*-Zeiger dürfen nur vom CRT-Modul betrieben werden, das sie erstellt hat.
Speicher, der der CRT-Funktion
malloc()zugeordnet ist, darf nur vom CRT-Modul freigegeben oder neu zugewiesen werden, das sie zugewiesen hat.
Um dies zu veranschaulichen, betrachten Sie das folgende Beispiel:
- .EXE ist mit MSVCRT verknüpft. LIB
- DLL A ist mit LIBCMT verknüpft. LIB
- DLL B ist mit CRTDLL verknüpft. LIB
Wenn die .EXE ein CRT-Dateihandle mit oder _create() _open()erstellt, kann dieses Dateihandle nur an _lseek(), _read(), _write(), _close()usw. in der .EXE Datei übergeben werden. Übergeben Sie dieses CRT-Dateihandle nicht an eine der DLL-Dateien. Übergeben Sie kein CRT-Dateihandle, das von einer DLL an die andere DLL oder an die .EXE abgerufen wird.
Wenn DLL A einen Speicherblock zuweist, kann malloc()nur DLL A aufrufen free()``_expand()oder realloc() für diesen Block arbeiten. Sie können nicht aus DLL A aufrufen malloc() und versuchen, diesen Block von der .EXE oder von DLL B freizugeben.
Hinweis
Wenn alle drei Module mit CRTDLL verknüpft wurden. LIB oder alle drei wurden mit MSVCRT verknüpft. LIb, diese Einschränkungen würden nicht gelten.
Beim Verknüpfen von DLLs mit LIBC. LIB, beachten Sie, dass, wenn es eine Möglichkeit gibt, dass eine solche DLL von einem Multithread-Programm aufgerufen wird, die DLL nicht mehrere Threads unterstützt, die gleichzeitig in der DLL ausgeführt werden, was zu großen Problemen führen kann. Wenn es möglich ist, dass die DLL von Multithread-Programmen aufgerufen wird, stellen Sie sicher, dass Sie sie mit einer der Bibliotheken verknüpfen, die Multithread-Programme (LIBCMT) unterstützen. LIB, CRTDLL. LIB oder MSVCRT. LIB).