C Run-Time kullanma

Bu makalede C Çalışma Zamanı'nın nasıl kullanılacağı açıklanmaktadır.

Orijinal ürün sürümü: Visual C++
Özgün KB numarası: 94248

Bölüm 1: C Run-Time (CRT) Kitaplıklarının Üç Biçimi Mevcuttur

Win32 SDK ile sağlanan C Çalışma Zamanı kitaplığının üç biçimi vardır:

  • LİBC. LIB, tek iş parçacıklı programlar için statik olarak bağlı bir kitaplıktır.

  • LIBCMT. LIB, çok iş parçacıklı programları destekleyen statik bağlantılı bir kitaplıktır.

  • CRTDLL. LIB, çok iş parçacıklı programları da destekleyen CRTDLL.DLL için bir içeri aktarma kitaplığıdır. CRTDLL.DLL kendisi Windows NT bir parçasıdır.

Microsoft Visual C++ 32 bit sürümü de bu üç formu içerir, ancak DLL'deki CRT MSVCRT olarak adlandırılır. LİB. DLL yeniden dağıtılabilir. Adı VC++ sürümüne (MSVCRT10.DLL veya MSVCRT20.DLL) bağlıdır. Ancak MSVCRT10.DLL Win32s'de desteklenmediğini, CRTDLL'nin ise desteklenmediğini unutmayın. LIB, Win32'lerde desteklenir. MSVCRT20.DLL iki sürümde sunulur: biri Windows NT ve diğeri Win32s için.

Bölüm 2: DLL oluştururken CRT kitaplıklarını kullanma

CRT'nin düzgün bir şekilde başlatıldığından emin olmak için C Çalışma Zamanı kitaplıklarından herhangi birini kullanan bir DLL oluştururken

  1. Başlatma işlevi adlandırılmış DllMain() olmalı ve giriş noktası bağlayıcı seçeneğiyle belirtilmelidir -entry:_DllMainCRTStartup@12

    veya

  2. DLL'nin giriş noktası, işlem ekleme ve işlem ayırma işlemlerinde açıkça çağrılmalıdır CRT_INIT() .

Bu, C Çalışma Zamanı kitaplıklarının DLL'ye bir işlem veya iş parçacığı eklerken C Çalışma Zamanı verilerini düzgün ayırmasına ve başlatmasına, bir işlem DLL'den ayrılırken C Çalışma Zamanı verilerini düzgün bir şekilde temizlemesine ve DLL'deki genel C++ nesnelerinin düzgün bir şekilde oluşturulup yok edilmesine izin verir.

Win32 SDK örneklerinin tümü ilk yöntemi kullanır. Örnek olarak kullanın. Ayrıca için Win32 Programcı Başvurusu'na ve için DllEntryPoint()DllMain()Visual C++ belgelerine de bakın. Varsa uygulamanızın DllMain() öğesini çağırdığını DllMainCRTStartup()CRT_INIT() ve CRT_INIT() çağıracağını unutmayın.

ve kullanmak yerine DllMainCRTStartup()DllMain()ikinci yöntemi kullanmak ve CRT başlatma kodunu kendiniz çağırmak istiyorsanız iki teknik vardır:

  1. Başlatma kodu gerçekleştiren bir giriş işlevi yoksa, DLL'nin giriş noktası olarak belirtin CRT_INIT() . NTWIN32 dahil ettiğinizi varsayarsak. @12 olarak tanımlayan DLLENTRY MAK, seçeneğini DLL'nin bağlantı satırına ekleyin:-entry:_CRT_INIT$(DLLENTRY)

    veya

  2. Kendi DLL giriş noktanız varsa, giriş noktasında aşağıdakileri yapın:

    1. Için bu prototipi CRT_INIT()kullanın: BOOL WINAPI _CRT_INIT(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);

      Dönüş değerleri hakkında CRT_INIT() bilgi için DllEntryPoint belgelerine bakın; aynı değerler döndürülür.

    2. üzerinde DLL_PROCESS_ATTACH ve DLL_THREAD_ATTACH (bu bayraklar hakkında daha fazla bilgi için Win32 API başvurusunda DllEntryPoint'e bakın), C Çalışma zamanı işlevleri çağrılmadan veya kayan nokta işlemleri gerçekleştirilmeden önce öğesini çağırın CRT_INIT().

    3. Kendi işlem/iş parçacığı başlatma/sonlandırma kodunuzu çağırabilirsiniz.

    4. ve DLL_THREAD_DETACHüzerinde DLL_PROCESS_DETACHCRT_INIT(), tüm C Çalışma zamanı işlevleri çağrıldıktan ve tüm kayan nokta işlemleri tamamlandıktan sonra son çağrıyı gerçekleştirin.

Giriş noktasının tüm parametrelerine CRT_INIT() geçtiğinden emin olun; CRT_INIT() bu parametreleri bekler, bu nedenle atlanırsa işler güvenilir bir şekilde çalışmayabilir (özellikle, işlem başlatma veya sonlandırma gerekip gerekmediğini belirlemek için fdwReason gereklidir).

Aşağıda, DLL giriş noktasında bu çağrıların CRT_INIT() ne zaman ve nasıl yapılacağını gösteren bir iskelet örnek giriş noktası işlevi verilmiştir:

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

Not

ve -entry:_DllMainCRTStartup@12kullanıyorsanız DllMain() bu gerekli değildir.

Bölüm 3: NTWIN32 kullanma. Derleme sürecini basitleştirmek için MAK

NTWIN32'de tanımlanan makrolar vardır. Derleme dosyalarınızı basitleştirmek ve çakışmaları önlemek için düzgün bir şekilde oluşturulduklarından emin olmak için kullanılabilen MAK. Bu nedenle Microsoft, NTWIN32 kullanılmasını kesinlikle önerir. MAK ve makrolar.

Derleme için şunu kullanın: $(cvarsdll) for apps/DLLs using CRT in a DLL.

Bağlantı için aşağıdakilerden birini kullanın:

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

Bölüm 4: Birden çok CRT kitaplığı kullanılırken karşılaşılan sorunlar

C Çalışma Zamanı çağrıları yapan bir uygulama, C Çalışma zamanı çağrıları da yapan bir DLL'ye bağlantı veriyorsa, her ikisinin de statik olarak bağlı C Çalışma zamanı kitaplıklarından biriyle (LIBC) bağlantılı olduğunu unutmayın. LIB veya LIBCMT. LIB), .EXE ve DLL tüm C Çalışma zamanı işlevlerinin ve genel değişkenlerin ayrı kopyalarına sahip olur. Bu, C Çalışma Zamanı verilerinin .EXE ve DLL arasında paylaşılamayacağı anlamına gelir. Sonuç olarak ortaya çıkabilecek sorunlardan bazıları şunlardır:

  • Arabelleğe alınan akış tanıtıcılarını .EXE/DLL dosyasından diğer modüle geçirme

  • .EXE/DLL'de C Çalışma Zamanı çağrısıyla belleği ayırma ve diğer modülde yeniden ayırma veya boşaltma

  • .EXE/DLL'de genel errno değişkeninin değerini denetleme veya ayarlama ve diğer modülde aynı olmasını bekleme. İlgili bir sorun, errno kullandığından C Çalışma zamanı hatasının oluştuğu perror() karşı modülde çağrılmaktırperror().

Bu sorunları önlemek için hem .EXE hem de DLL'yi CRTDLL ile bağlayın. LIB veya MSVCRT. Hem .EXE hem de DLL'nin bir DLL'de CRT içinde yer alan ortak işlev ve veri kümesini kullanmasına olanak tanıyan LIB ve akış tanıtıcıları gibi C Çalışma zamanı verileri hem .EXE hem de DLL tarafından paylaşılabilir.

Bölüm 5: Kitaplık Türlerini Karıştırma

DLL'nizi CRTDLL ile bağlayabilirsiniz. LIB/MSVCRT. CRT veri yapılarını karıştırmaktan ve CRT dosya tanıtıcılarını veya CRT FILE* işaretçilerini diğer modüllere geçirmekten kaçınırsanız, .EXE neyle bağlantılı olursa olsun LIB.

Kitaplık türlerini karıştırırken aşağıdakilere uyun:

  • CRT dosya tanıtıcıları yalnızca bunları oluşturan CRT modülü tarafından çalıştırılabilir.

  • CRT FILE* işaretçileri yalnızca bunları oluşturan CRT modülü tarafından çalıştırılabilir.

  • CRT işleviyle malloc() ayrılan bellek yalnızca onu ayıran CRT modülü tarafından serbest bırakılabilir veya yeniden yerleştirilebilir.

Bunu göstermek için aşağıdaki örneği göz önünde bulundurun:

  • .EXE MSVCRT ile bağlantılıdır. LİB
  • DLL A, LIBCMT ile bağlantılıdır. LİB
  • DLL B, CRTDLL ile bağlantılıdır. LİB

.EXE veya kullanarak _create() bir CRT dosya tanıtıcısı oluşturursa, bu dosya tanıtıcısı yalnızca .EXE dosyasındaki , _read(), _write(), , _close()vb.'ye _lseek()geçirilebilir._open() Bu CRT dosya tutamacını iki DLL'ye de geçirmeyin. DLL'den alınan bir CRT dosya tanıtıcısını diğer DLL'ye veya .EXE geçirmeyin.

DLL A ile malloc()bir bellek bloğu ayırırsa, yalnızca DLL A , _expand()çağrısı yapabilir free()veya realloc() bu blok üzerinde çalışabilir. A DLL'sinden çağrı malloc() yapamaz ve bu bloğu .EXE veya B DLL'sinden serbest tutmaya çalışamazsınız.

Not

Üç modülün de CRTDLL ile bağlantılı olup olmadığını. LIB veya üçü de MSVCRT ile bağlantılıydı. LIb, bu kısıtlamalar geçerli olmaz.

DLL'leri LIBC ile bağlarken. LIB, böyle bir DLL'nin çok iş parçacıklı bir program tarafından çağrılma olasılığı varsa, DLL'nin DLL'de çalışan birden çok iş parçacığını aynı anda desteklemediğini ve bunun büyük sorunlara neden olabileceğini unutmayın. DLL'nin çok iş parçacıklı programlar tarafından çağrılma olasılığı varsa, bunu çok iş parçacıklı programları (LIBCMT) destekleyen kitaplıklardan biriyle bağlayabilirsiniz. LIB, CRTDLL. LIB veya MSVCRT. LIB).