C++ DLL için Yönetilen Uzantılar projeleri oluştururken linker uyarıları alma

Makale çevirileri Makale çevirileri
Makale numarası: 814472 - Bu makalenin geçerli olduğu ürünleri görün.
Hepsini aç | Hepsini kapa

Bu Sayfada

Belirtiler

Aşağıdaki hata iletilerinden birini derleme zaman ya da bağlantı zaman alırsınız:
Linker Araçlar hata LNK2001
'çözümlenemeyen dış simge "simgesi" '

LNK4210 uyarı linker araçları
'.CRT bölümü varsa; çözülemeyen bir statik başlatılırken olabilir veya teminators'You C++ DLL için Yönetilen Uzantılar projeleri oluştururken Bağlayıcısı uyarıları alma

LNK4243 uyarı linker araçları
'Resim düzgün çalışmayabilir; /clr ile derlenen nesneler içeren DLL /NOENTRY ile bağlantılı'.
Bu uyarılar sırasında aşağıdaki koşullarda oluşabilir:
  • Nesneleri bağlama derleme / clr geçin.
  • Aşağıdaki projelerden biri, oluşturduğunuz: ASP.NET Web Service şablonu; <a2>sınıf kitaplığı şablon;</a2> veya <a4>Windows Denetim Kitaplığı şablonu.
  • Kod eklediğinizde, genel değişkenler veya yerel (diğer bir deyişle __gc veya __value) sınıfları statik veri üyeleri ile birlikte kullanır. Örneğin, ActiveX Template Library (ATL), Microsoft Foundation Classes (MFC) ve C çalışma zamanı (CRT) sınıfları
Not: olan projeler LNK2001 ve LNK4210 hatayla alabileceğiniz Bu makalede açıklanan sorundan etkilenmemektedir. Ancak, Proje kesinlikle bir LNK2001 çözümlemek için bu makalede açıklanan sorundan etkilenir veya LNK4210 uyarı LNK4243 uyarı için müşteri adayları veya proje bağlama LNK4243 uyarı oluşturur.

Neden

Projeler için yerel kitaplıkları (CRT, ATL veya MFC gibi) herhangi bir bağlantı olmadan ve herhangi bir genel değişkenler veya statik veri üyeleri yerel sınıflarıyla olmadan bir dinamik bağlantı kitaplığı (DLL) varsayılan olarak oluşturulur:
  • ASP.NET Web Service şablonu
  • Sınıf kitaplığı şablon
  • Windows Denetim Kitaplığı şablonu
Statik veri üyeleri ile genel değişkenler veya yerel sınıflarını kullanan kod eklerseniz (örneğin, CRT ATL ve MFC kitaplıklarını genel değişkenler kullanın), derleme zamanında linker hata iletileri alırsınız. Bu durumda, kodu el ile statik değişken başlatılamıyor eklemeniz gerekir. Bunun nasıl yapılacağı hakkında daha fazla bilgi için bu makalenin "Çözüm" bölümüne bakın.

Kolaylık sağlamak için bu makalede genel değişkenleri ve "statics" veya "statik değişkenler" yerel sınıfları statik veri üyeleri bu noktadan itibaren gösterir.

Bu sorun, karma dll DOSYASı yükleme sorunu nedeniyle oluşur. Özellikle sistem baskı altında olduğunda işlem adres alanına, yüklü olduklarında bazı koşullarda kilitlenme senaryolarda karışık dll (diğer bir deyişle, yerel ve yönetilen kod içeren dll) karşılaşabilirsiniz. Daha önce bahsedilen linker hata iletileri linker müşteriler kilitlenme ve bu belgede açıklanan geçici çözümler için olası farkında olduğunuzdan emin olun etkinleştirilmiş olan. Sorun yükleniyor karma DLL ayrıntılı bir açıklaması için bkz: aşağıdaki teknik inceleme:
DLL yükleme karma sorunu
http://msdn2.microsoft.com/en-us/library/aa290048(vs.71).aspx

Çözüm

Uzantılar, C++ projeler için varsayılan olarak, dll C çalışma zamanı (CRT) kitaplığı, MFC veya ATL gibi doğal C/C++ kitaplıkları bağlantı. ve herhangi bir statik değişken kullanın, oluşturulan yönetiliyor. Ayrıca, proje ayarlarını DLL'lerin ile bağlanması belirtin. / NOENTRY seçeneği etkin.

Güvenli olmayan DllMain sırasında yönetilen kod ile bir giriş noktası bağlama neden olur, çünkü bu gerçekleştirilir (sınırlı kapsamı sırasında yapabileceklerinizin kümesinin DllMain bakın).

Bir DLL girdi noktası olmayan tamsayılar gibi çok basit türleri dışında statik değişkenleri'ni başlatmak için bir yol vardır. Genellikle statik değişken olmayan bir / NOENTRY DLL.

Ayrıca ilk yapmayı değişiklik olmadan bu DLL içinde bu kitaplıklardan kullanamazlar tüm ATL, <a2>MFC</a2> ve <a4>CRT kitaplıkları statik değişken üzerinde kullanır.

Karma mod DLL dosyanızın statics veya statics (örneğin, ATL, MFC veya CRT) bağlı olan kitaplıkları kullanın gerekiyorsa, böylece statics el ile yeniden başlatılır, DLL değiştirmeniz gerekir.

El ile başlatma için ilk adım, karma dll dosyaları güvenli olmayan otomatik başlatma kod devre dışı bırakmak ve kilitlenmeye neden emin olmaktır. Başlatma kodu devre dışı bırakmak için şu adımları izleyin.

Yönetilen DLL giriş noktası kaldırmak.

  1. Ile bağlantı / NOENTRY. Solution Explorer proje düğümünü sağ tıklatın, Özellikler ' i tıklatın. Özellik sayfalarıBağlayıcısı ' nı tıklatın, komut satırı ' nı tıklatın ve sonra da Ek seçenekler için bu anahtarı eklemek iletişim kutusunda, alan.
  2. Bağlantı msvcrt.lib. Özellik sayfaları iletişim kutusuna Bağlayıcısı ' nı tıklatın, Giriş ' i tıklatın. ve msvcrt.libEk bağımlılıklar özelliğine ekleyin.
  3. Nochkclr.obj kaldırın. (Önceki adımda aynı sayfa) Giriş sayfasında, nochkclr.objEk bağımlılıklar özelliğinden kaldırın.
  4. CRT bağlantıyı. Giriş sayfası (önceki adımda aynı sayfa), ekleme __DllMainCRTStartup@12Force simge başvurular özelliği.

    Komut istemi'ni kullanıyorsanız, yukarıdaki proje ayarlarını ile aşağıdakileri belirtin:
    LINK /NOENTRY msvcrt.lib /NODEFAULTLIB:nochkclr.obj /INCLUDE:__DllMainCRTStartup@12

DLL için el ile Initializiation kullanan bileşenleri değiştirme

Açık giriş noktası kaldırdıktan sonra DLL dosyanızın uygulanır şekilde bağlı olarak, el ile başlatma için DLL kullanan bileşenler değiştirmelisiniz:
  • DLL dosyanızın DLL verir (__declspec(dllexport)) kullanarak girilir ve bunlar statik veya dinamik olarak DLL dosyanızın bağlıysa, tüketicilerin, yönetilen kod kullanamazsınız.
  • Kendi dll DOSYASı, COM tabanlı DLL dosyasıdır.
  • Tüketiciler, DLL dosyasının, yönetilen kod kullanabilir ve DLL dosyanızın veya giriş noktalarını yönetilen ya da DLL verir içerir.

DLL'i kullanarak girin, DLL'leri değiştirmek verir ve bu kullanamıyorsunuz tüketicilere kod yönetilebilir.

Dll verir kullanarak girdiğiniz DLL'leri değiştirmek için (__declspec(dllexport)) ve yönetilen kod, kullanamazsınız tüketicilerin, şu adımları izleyin:
  1. Aşağıdaki kodda gösterildiği gibi ekleyin, iki yeni DLL dosyanızın verir:
    // init.cpp
    
    #include <windows.h>
    #include <_vcclrit.h>
    
    // Call this function before you call anything in this DLL.
    // It is safe to call from multiple threads; it is not reference
    // counted; and is reentrancy safe.
    
    __declspec(dllexport) void __cdecl DllEnsureInit(void)
    {
    	// Do nothing else here. If you need extra initialization steps,
    	// create static objects with constructors that perform initialization.
    	__crt_dll_initialize();
    	// Do nothing else here.
    }
    
    // Call this function after this whole process is totally done
    // calling anything in this DLL. It is safe to call from multiple
    // threads; is not reference counted; and is reentrancy safe.
    // First call will terminate.
    
    __declspec(dllexport) void __cdecl DllForceTerm(void)
    {
    	// Do nothing else here. If you need extra terminate steps, 
    	// use atexit.
    	__crt_dll_terminate();
    	// Do nothing else here.
    }
    
    Not Visual C++ 2005, ortak dil çalışma zamanı desteğini derleyici seçeneği eklemeniz gerekir (/ clr:oldSyntax) başarıyla önceki kod örneğini derlemek için. Ortak dil çalışma zamanı desteğini derleyici seçeneği eklemek için aşağıdaki adımları izleyin:
    1. Project ' i tıklatın ve sonra ProjectName özellikler ' i tıklatın.

      NotProjectName projenin adı için bir yer tutucudur.
    2. Yapılandırma özellikleri ' ni genişletin ve sonra Genel ' i tıklatın.
    3. Sağ bölmede, seçmek için tıklatın ortak dil çalışma zamanı modülü ve Destek, eski sözdizimi (/ clr:oldSyntax)Common Language Runtime desteği proje ayarları.
    4. ' I tıklatın (Uygula) ve sonra Tamam ' ı tıklatın.
    Ortak dil çalıştırma hakkında daha fazla bilgi için aşağıdaki Microsoft Developer Network (MSDN) Web sitesini ziyaret edin derleyici seçenekleri destekler:
    http://msdn2.microsoft.com/en-us/library/k8d11d4s.aspx
    Bu adımlar, tüm makaleyi için geçerlidir.
  2. DLL dosyanızın birkaç tüketicilerin olabilir. Birden çok tüketicilerin, verir bölümünde DLL .def dosyası aşağıdaki kodu ekleyin:
    DllEnsureInit	PRIVATE
    DllForceTerm	PRIVATE
    
    bu satırlar eklemek ve işlevleri verme, iki DLL varsa, uygulama için DLL bağlanan bağlantı hataları olacaktır. Genellikle, verilen işlevlerin aynı ada sahip. Multiconsumer bir durumda, her bir tüketici statik veya dinamik olarak DLL dosyanızın bağlanabilir.
  3. Tüketici statik DLL için DLL'i ilk kez kullanmadan önce veya üzerinde uygulamanıza bağlı herhangi bir şey kullanmadan önce bağlıysa, aşağıdaki çağrı Ekle:
    // Snippet 1
    
    typedef void (__stdcall *pfnEnsureInit)(void);
    typedef void (__stdcall *pfnForceTerm)(void);
    
    {
    	// ... initialization code
    	HANDLE hDll=::GetModuleHandle("mydll.dll");
    	If(!hDll)
    	{
    		// Exit, return; there is nothing else to do.
    	}
    	pfnEnsureInit pfnDll=::( pfnEnsureInit) GetProcAddress(hDll, 
       "DllEnsureInit");
    	if(!pfnDll)
    	{
    		// Exit, return; there is nothing else to do.
    	}
    	
    	pfnDll();
    	
    	// ... more initialization code
    }
    
  4. Uygulamanızdaki DLL dosyasının son kullandıktan sonra aşağıdaki kodu ekleyin:
    // Snippet 2
    
    {
    	// ... termination code
    	HANDLE hDll=::GetModuleHandle("mydll.dll");
    	If(!hDll)
    	{
    		// exit, return; there is nothing else to do
    	}
    	pfnForceTerm pfnDll=::( pfnForceTerm) GetProcAddress(hDll, 
       "DllForceTerm");
    	if(!pfnDll)
    	{
    		// exit, return; there is nothing else to do
    	}
    	
    	pfnDll();
    	
    	// ... more termination code
    }
    
  5. Tüketici DLL için dinamik olarak bağlıysa, kodu aşağıdaki şekilde ekleyin:
    • <a1>Kod</a1> 1'i takın (bkz: adım 3) sonra hemen ilk LoadLibrary DLL için.
    • Parçacık (bkz: adım 4) 2 son hemen FreeLibrary önce DLL için yerleştirin.

COM tabanlı DLL değiştirmek için

  • DLL verme işlevleri DllCanUnloadNowDllGetClassObject, DllRegisterServer ve DllUnregisterServer aşağıdaki gösterildiği gibi değiştirin:
    //  Implementation of DLL Exports.
    
    #include <_vcclrit.h>
    
    STDAPI DllCanUnloadNow(void)
    {
        
        if ( _Module.GetLockCount() == 0 )
    	{
    		__crt_dll_terminate();
            return S_OK;
    	}
        else
        {
            return S_FALSE;
    
        }
    	
    }
    
    STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
    {
        if ( !( __crt_dll_initialize() ) )
    	{
    		return E_FAIL;
    	}
        else
        {
            return _Module.GetClassObject(rclsid, riid, ppv);
        }
    }
    
    STDAPI DllRegisterServer(void)
    {
    	if ( !( __crt_dll_initialize() ) )
    	{
    		return E_FAIL;
    	}
    	// Call your registration code here
        HRESULT hr = _Module.RegisterServer(TRUE)
     
        return hr;
    }
    
    
    STDAPI DllUnregisterServer(void)
    { 
        HRESULT hr = S_OK;
    	__crt_dll_terminate();
    
        // Call your unregistration code here
        hr = _Module.UnregisterServer(TRUE);
        return hr;
    }
    

Değiştirme Kullanan tüketicilere içeren DLL kodu ve DLL dosyaya yönetilen veya giriş noktaları yönetilen

Yönetilen kod ve dll tüketicilerin içeren DLL değiştirmeye verir veya yönetilen giriş noktaları, şu adımları izleyin:
  1. Başlatma ve sona erdirme statik üyesine işlevlerle yönetilen sınıf uygular. Başlatma ve sonlandırma için statik bir üye ile bir yönetilen sınıf uygulama projenizi .cpp dosya eklemek için:
    // ManagedWrapper.cpp
    
    // This code verifies that DllMain is not automatically called 
    // by the Loader when linked with /noentry. It also checks some
    // functions that the CRT initializes.
    
    #include <windows.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <math.h>
    #include "_vcclrit.h"
    
    #using <mscorlib.dll>
    using namespace System;
    
    public __gc class ManagedWrapper {
    public:
    	static BOOL minitialize() {
    		BOOL retval = TRUE;
    		try {
               retval =  __crt_dll_initialize();
    		} catch(System::Exception* e) {
    			Console::WriteLine(e->Message);
    			retval = FALSE;
    		}
    		return retval;
    	}
    	static BOOL mterminate() {
    		BOOL retval = TRUE;
    		try {
                retval = __crt_dll_terminate();
    		} catch(System::Exception* e) {
    						Console::WriteLine(e->Message);
    			retval = FALSE;
    		}
    		return retval;
    	}
    };
    
    BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID 
    lpvReserved) {
    	Console::WriteLine(S"DllMain is called...");
    	return TRUE;
    } /* DllMain */
    
  2. DLL'nin ve kullanmayı bitirdikten sonra'i başvurmak için önce bu işlevler'i arayın. Başlatma ve sona erdirme üye ana işlevlerini çağıran:
    // Main.cpp
    
    #using <mscorlib.dll>
    using namespace System;
    using namespace System::Reflection;
    #using "ijwdll.dll";
    
    int main() {
    	int retval = ManagedWrapper::minitialize();
        ManagedWrapper::mterminate();
    }
    

Visual C++ .NET 2002 kullanıcıları

Not: linker hata iletisi LNK4243 Visual C++ .NET 2002'de ürünün çıkışından yok, ancak kullanıcılar Visual C++ .NET 2002'in daha önce sözü edilen karma dll geliştirilirken yönergeleri izleyin önerilir.

Visual C++ .NET 2003 ürünün çıkışından el ile başlatma daha kolay hale getirmek için ek bir üstbilgi içerir. Bu makale çalışma Visual C++ .NET 2002'de listelenen çözümleri sağlamak için <a0></a0>, üstbilgi dosyası aşağıdaki metinle _vcclrit.h adlı projenize eklemelisiniz:
/***
* _vcclrit.h
*
*       Copyright (c) Microsoft Corporation. All rights reserved.
*
* Purpose:
*       This file defines the functions and variables used by user
*       to initialize CRT and the dll in IJW scenario.
*
****/

#pragma once

#ifdef __cplusplus
extern "C" {
#endif

extern IMAGE_DOS_HEADER __ImageBase;

BOOL WINAPI _DllMainCRTStartup(
        HANDLE  hDllHandle,
        DWORD   dwReason,
        LPVOID  lpreserved
        );
#ifdef __cplusplus
}
#endif

#ifdef _cplusplus
#define __USE_GLOBAL_NAMESPACE  ::
#else
#define __USE_GLOBAL_NAMESPACE
#endif

// Used to lock 
__declspec( selectany ) LONG  volatile __lock_handle = 0;

// Init called
__declspec(selectany) BOOL volatile __initialized = FALSE;

// Term called
__declspec( selectany ) BOOL volatile __terminated = FALSE;

__inline BOOL WINAPI __crt_dll_initialize()
{
    // Try to make the variable names unique, so that the variables 
    // do not even clash with macros.
    static BOOL volatile (__retval) = FALSE;
    static DWORD volatile (__lockThreadId) = 0xffffffff;
    DWORD volatile (__currentThreadId) = __USE_GLOBAL_NAMESPACE(GetCurrentThreadId)();
    int (__int_var)=0;
    
    // Take Lock; this is needed for multithreaded scenario. 
    // Additionally, the threads need to wait here to make sure that the dll 
    // is initialized when they get past this function.
    while ( __USE_GLOBAL_NAMESPACE(InterlockedExchange)( &(__lock_handle), 1) == 1 )
	{
        ++(__int_var);
        if ((__lockThreadId) == (__currentThreadId)) 
        {
            return TRUE;
        }
		__USE_GLOBAL_NAMESPACE(Sleep)( (__int_var)>1000?100:0 );

        // If you hang in this loop, this implies that your 
        // dllMainCRTStartup is hung on another thread. 
        // The most likely cause of this is a hang in one of your 
        // static constructors or destructors.
	}
    // Note: you do not really need any interlocked stuff here because the 
    // writes are always in the lock. Only reads are outside the lock.
    (__lockThreadId) = (__currentThreadId);
    __try {
        if ( (__terminated) == TRUE )
        {
            (__retval) = FALSE;
        }
        else if ( (__initialized) == FALSE )
        {
            (__retval) = (_DllMainCRTStartup)( ( HINSTANCE )( &__ImageBase ), DLL_PROCESS_ATTACH, 0 );
            (__initialized) = TRUE;
        }

    } __finally {
        // revert the __lockThreadId
        (__lockThreadId) = 0xffffffff;
        // Release Lock
       __USE_GLOBAL_NAMESPACE(InterlockedExchange)(&(__lock_handle),0);
    }
    return (__retval);
}

__inline BOOL WINAPI __crt_dll_terminate()
{
    static BOOL volatile (__retval) = TRUE;
    static DWORD volatile (__lockThreadId) = 0xffffffff;
    DWORD volatile (__currentThreadId) = __USE_GLOBAL_NAMESPACE(GetCurrentThreadId)();
    int (__int_var)=0;
    
    // Take Lock; this lock is needed to keep Terminate 
    // in sync with Initialize.
    while ( __USE_GLOBAL_NAMESPACE(InterlockedExchange)( &(__lock_handle), 1) == 1 )
	{
        ++(__int_var);
        if ((__lockThreadId) == (__currentThreadId)) 
        {
            return TRUE;
        }
		__USE_GLOBAL_NAMESPACE(Sleep)( (__int_var)>1000?100:0 );

        // If you hang in this loop, this implies that your 
        // dllMainCRTStartup is hung on another thread. The most likely 
        // cause of this is a hang in one of your static constructors 
        // or destructors.
    }
    // Note: you do not really need any interlocked stuff here because the 
    // writes are always in the lock. Only reads are outside the lock.
    (__lockThreadId) = (__currentThreadId);
    __try {
        if ( (__initialized) == FALSE )
        {
            (__retval) = FALSE;
        }
        else if ( (__terminated) == FALSE )
        {
            (__retval) = _DllMainCRTStartup( ( HINSTANCE )( &(__ImageBase) ), DLL_PROCESS_DETACH, 0 );
            (__terminated) = TRUE;
        }
    } __finally {
        // revert the __lockThreadId
        (__lockThreadId) = 0xffffffff;
        // Release Lock
       __USE_GLOBAL_NAMESPACE(InterlockedExchange)(&(__lock_handle),0);
    }
    return (__retval);
}

Referanslar

Daha fazla bilgi için, Microsoft Bilgi Bankası'ndaki makaleyi görüntülemek üzere aşağıdaki makale numarasını tıklatın:
309694Hata: Visual C++ bileşeni uzantıları kullandığınızda AppDomainUnloaded özel durum yönetilen...

Özellikler

Makale numarası: 814472 - Last Review: 11 Mayıs 2007 Cuma - Gözden geçirme: 7.3
Bu makaledeki bilginin uygulandığı durum:
  • Microsoft Visual C++ 2005 Express Edition
  • Microsoft Visual C++ .NET 2003 Standard Edition
  • Microsoft Visual C++ .NET 2002 Standard Edition
  • Microsoft .NET Framework 1.1
  • Microsoft .NET Framework 1.0
Anahtar Kelimeler: 
kbmt kbcominterop kbmanaged kbdll kbijw kbprb KB814472 KbMttr
Machine-translated Article
ÖNEMLİ: Bu makale, bir kişi tarafından çevrilmek yerine, Microsoft makine-çevirisi yazılımı ile çevrilmiştir. Microsoft size hem kişiler tarafından çevrilmiş, hem de makine-çevrisi ile çevrilmiş makaleler sunar. Böylelikle, bilgi bankamızdaki tüm makalelere, kendi dilinizde ulaşmış olursunuz. Bununla birlikte, makine tarafından çevrilmiş makaleler mükemmel değildir. Bir yabancının sizin dilinizde konuşurken yapabileceği hatalar gibi, makale; kelime dağarcığı, söz dizim kuralları veya dil bilgisi açısından yanlışlar içerebilir. Microsoft, içeriğin yanlış çevrimi veya onun müşteri tarafından kullanımından doğan; kusur, hata veya zarardan sorumlu değildir. Microsoft ayrıca makine çevirisi yazılımını sıkça güncellemektedir.
Makalenin İngilizcesi aşağıdaki gibidir:814472

Geri Bildirim Ver

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com