Dela via


Använda C-körningen

I den här artikeln beskrivs hur du använder C-körningen.

Ursprunglig produktversion: Visual C++
Ursprungligt KB-nummer: 94248

Avsnitt 1: Tre former av CRT-bibliotek (C Run-Time) är tillgängliga

Det finns tre former av C Run-time-biblioteket som medföljer Win32 SDK:

  • LIBC. LIB är ett statiskt länkat bibliotek för entrådade program.

  • LIBCMT. LIB är ett statiskt länkat bibliotek som stöder flertrådade program.

  • CRTDLL. LIB är ett importbibliotek för CRTDLL.DLL som också stöder flertrådade program. CRTDLL.DLL är en del av Windows NT.

Microsoft Visual C++ 32-bitarsversionen innehåller även dessa tre formulär, men CRT i en DLL heter MSVCRT. LIB. DLL:en kan omdistribueras. Namnet beror på versionen av VC++ (dvs. MSVCRT10.DLL eller MSVCRT20.DLL). Observera dock att MSVCRT10.DLL inte stöds på Win32s, medan CRTDLL. LIB stöds på Win32s. MSVCRT20.DLL finns i två versioner: en för Windows NT och den andra för Win32s.

Avsnitt 2: Använda CRT-biblioteken när du skapar en DLL

När du skapar en DLL som använder något av C Run-time-biblioteken, för att säkerställa att CRT initieras korrekt, antingen

  1. Initieringsfunktionen måste namnges DllMain() och startpunkten måste anges med länkalternativet -entry:_DllMainCRTStartup@12

    eller

  2. DLL:ens startpunkt måste uttryckligen anropa CRT_INIT() processanslutning och processavkoppling.

Detta gör att C Run-time-biblioteken kan allokera och initiera C Run-time-data när en process eller tråd kopplas till DLL:en, för att korrekt rensa C-körningsdata när en process kopplas från DLL och för att globala C++-objekt i DLL:en ska konstrueras och destrueras korrekt.

Win32 SDK-exemplen använder alla den första metoden. Använd dem som exempel. Se även Win32-programmerarens referens för DllEntryPoint() och Visual C++-dokumentationen för DllMain(). Observera att DllMainCRTStartup() anropar CRT_INIT() och CRT_INIT() anropar programmets DllMain(), om det finns.

Om du vill använda den andra metoden och anropa CRT-initieringskoden själv, i stället för att använda DllMainCRTStartup() och DllMain(), finns det två tekniker:

  1. Om det inte finns någon postfunktion som utför initieringskoden anger du CRT_INIT() som startpunkt för DLL:n. Förutsatt att du har inkluderat NTWIN32. MAK, som definierar DLLENTRY som @12, lägger till alternativet på DLL:s länkrad:-entry:_CRT_INIT$(DLLENTRY).

    eller

  2. Om du har en egen DLL-startpunkt gör du följande i startpunkten:

    1. Använd den här prototypen för CRT_INIT(): BOOL WINAPI _CRT_INIT(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);

      Information om CRT_INIT() returvärden finns i dokumentationen DllEntryPoint. Samma värden returneras.

    2. DLL_PROCESS_ATTACH och DLL_THREAD_ATTACH (se DllEntryPoint i Win32 API-referensen för mer information om dessa flaggor), anropa CRT_INIT(), först, innan några C-körningsfunktioner anropas eller några flyttalsåtgärder utförs.

    3. Anropa din egen process-/trådinitierings-/avslutningskod.

    4. DLL_PROCESS_DETACH och DLL_THREAD_DETACHanropar CRT_INIT() sist när alla C-körningsfunktioner har anropats och alla flyttalsåtgärder har slutförts.

Var noga med att vidarebefordra till CRT_INIT() alla parametrar i startpunkten. CRT_INIT() Förväntar sig dessa parametrar, så saker och ting kanske inte fungerar tillförlitligt om de utelämnas (i synnerhet krävs fdwReason för att avgöra om processinitiering eller avslutning behövs).

Nedan visas en skelettexempelinmatningspunktsfunktion som visar när och hur du gör dessa anrop till CRT_INIT() i DLL-startpunkten:

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);
}

Kommentar

Detta är inte nödvändigt om du använder DllMain() och -entry:_DllMainCRTStartup@12.

Avsnitt 3: Använda NTWIN32. MAK för att förenkla byggprocessen

Det finns makron som definierats i NTWIN32. Fleraktiveringsnyckel som kan användas för att förenkla dina makefiles och för att säkerställa att de är korrekt byggda för att undvika konflikter. Därför rekommenderar Microsoft starkt att du använder NTWIN32. MAK och makrona däri.

För kompilering använder du: $(cvarsdll) for apps/DLLs using CRT in a DLL.

Använd något av följande för att länka:

  • $(conlibsdll) for console apps/DLLs using CRT in a DLL
  • $(guilibsdll) for GUI apps using CRT in a DLL

Avsnitt 4: Problem som uppstår vid användning av flera CRT-bibliotek

Om ett program som gör C Run-time-anrop länkar till en DLL som även gör C Run-time-anrop bör du vara medveten om att om de båda är länkade med ett av de statiskt länkade C Run-time-biblioteken (LIBC). LIB eller LIBCMT. LIB), .EXE och DLL har separata kopior av alla C Run-time-funktioner och globala variabler. Det innebär att C-körningsdata inte kan delas mellan .EXE och DLL. Några av de problem som kan uppstå till följd av detta är:

  • Skicka buffrade strömhandtag från .EXE/DLL till den andra modulen

  • Allokera minne med ett C Run-time-anrop i .EXE/DLL och omplacera eller frigöra det i den andra modulen

  • Kontrollera eller ange värdet för den globala errno-variabeln i .EXE/DLL och förvänta dig att den är densamma i den andra modulen. Ett relaterat problem är att anropa perror() i den motsatta modulen från den plats där C-körningsfelet inträffade, eftersom perror() använder errno.

Undvik dessa problem genom att länka både .EXE och DLL med CRTDLL. LIB eller MSVCRT. LIB, som gör det möjligt för både .EXE och DLL att använda den gemensamma uppsättningen funktioner och data som finns i CRT i en DLL, och C Run-time-data, till exempel strömhandtag, kan sedan delas av både .EXE och DLL.

Avsnitt 5: Blanda bibliotekstyper

Du kan länka din DLL med CRTDLL. LIB/MSVCRT. LIB oavsett vad din .EXE är länkad till om du undviker att blanda CRT-datastrukturer och skicka CRT-filhandtag eller CRT FILE*-pekare till andra moduler.

När du blandar bibliotekstyper följer du följande:

  • CRT-filhandtag kan endast användas av CRT-modulen som skapade dem.

  • CRT FILE*-pekare kan endast användas av CRT-modulen som skapade dem.

  • Minne som allokeras med CRT-funktionen malloc() kan bara frigöras eller omallokeras av CRT-modulen som allokerade den.

För att illustrera detta bör du överväga följande exempel:

  • .EXE är länkad till MSVCRT. LIB
  • DLL A är länkad till LIBCMT. LIB
  • DLL B är länkad till CRTDLL. LIB

Om .EXE skapar en CRT-filreferens med eller _create() _open()kan filhandtaget endast skickas till _lseek(), _read(), _write(), _close()osv. i filen .EXE. Skicka inte crt-filhandtaget till någon av DLL:erna. Skicka inte ett CRT-filhandtag som hämtats från DLL till den andra DLL-filen eller till .EXE.

Om DLL A allokerar ett minnesblock med malloc()kan endast DLL A anropa free(), _expand()eller realloc() för att köra det blocket. Du kan inte anropa malloc() från DLL A och försöka frigöra det blocket från .EXE eller från DLL B.

Kommentar

Om alla tre modulerna var länkade till CRTDLL. LIB eller alla tre kopplades till MSVCRT. LIb, dessa begränsningar skulle inte gälla.

När du länkar DLL:er med LIBC. LIB, tänk på att om det finns en möjlighet att en sådan DLL anropas av ett program med flera flöden, stöder DLL-filen inte flera trådar som körs i DLL-filen samtidigt, vilket kan orsaka stora problem. Om det finns en möjlighet att DLL-filen anropas av flertrådade program måste du länka den till ett av biblioteken som stöder flertrådade program (LIBCMT). LIB, CRTDLL. LIB eller MSVCRT. LIB).