Bạn hiện đang ngoại tuyến, hãy chờ internet để kết nối lại

Trình duyệt của bạn không được hỗ trợ

Bạn cần cập nhật trình duyệt của mình để sử dụng trang web.

Cập nhật lên Internet Explorer phiên bản mới nhất.

Bạn nhận được cảnh báo linker khi bạn xây dựng quản lý phần mở rộng cho C++ DLL dự án

QUAN TRỌNG: Bài viết này được dịch bằng phần mềm dịch máy của Microsoft chứ không phải do con người dịch. Microsoft cung cấp các bài viết do con người dịch và cả các bài viết do máy dịch để bạn có thể truy cập vào tất cả các bài viết trong Cơ sở Kiến thức của chúng tôi bằng ngôn ngữ của bạn. Tuy nhiên, bài viết do máy dịch không phải lúc nào cũng hoàn hảo. Loại bài viết này có thể chứa các sai sót về từ vựng, cú pháp hoặc ngữ pháp, giống như một người nước ngoài có thể mắc sai sót khi nói ngôn ngữ của bạn. Microsoft không chịu trách nhiệm về bất kỳ sự thiếu chính xác, sai sót hoặc thiệt hại nào do việc dịch sai nội dung hoặc do hoạt động sử dụng của khách hàng gây ra. Microsoft cũng thường xuyên cập nhật phần mềm dịch máy này.

Nhấp chuột vào đây để xem bản tiếng Anh của bài viết này:814472
TRIỆU CHỨNG
Bạn nhận được một trong các thông báo lỗi sau đây lúc biên dịch thời gian hoặc thời gian liên kết:
Linker công cụ lỗi LNK2001
' chưa được giải quyết bên ngoài biểu tượng "biểu tượng" '

Linker công cụ cảnh báo LNK4210
'.MÀN HÌNH CRT phần tồn tại; có thể được unhandled tĩnh initializes hoặc teminators'You nhận được cảnh báo Linker khi bạn xây dựng quản lý phần mở rộng cho C++ DLL dự án

Linker công cụ cảnh báo LNK4243
' DLL có chứa các đối tượng biên dịch với/clr không được liên kết với /NOENTRY; hình ảnh không thể chạy một cách chính xác '.
Cảnh báo này có thể xảy ra trong thời gian sau đây trường hợp:
  • Khi bạn biên dịch liên kết các đối tượng với các /CLR chuyển đổi.
  • Khi bạn đang xây dựng một trong những dự án sau đây: ASP.NET Web dịch vụ mẫu; Lớp thư viện mẫu; hoặc Windows Control Thư viện mẫu.
  • Khi bạn đã thêm vào mã có sử dụng các biến toàn cầu hoặc nguồn gốc các lớp (tức là, không __gc hoặc __value) với các thành viên dữ liệu tĩnh. Cho Ví dụ, các ActiveX mẫu thư viện (ATL), Microsoft Foundation Classes (MFC), và các lớp c lần chạy (CRT)
Chú ý: bạn có thể nhận được lỗi LNK2001 và LNK4210 với các dự án đó là không bị ảnh hưởng bởi vấn đề mô tả trong bài viết này. Tuy nhiên, các dự án chắc chắn là bị ảnh hưởng bởi vấn đề mô tả trong bài viết này nếu việc giải quyết một LNK2001 hoặc LNK4210 cảnh báo dẫn đến một cảnh báo LNK4243, hoặc nếu liên kết các dự án tạo ra một cảnh báo LNK4243.
NGUYÊN NHÂN
Các dự án được tạo ra theo mặc định như là một động lực liên kết thư viện (DLL) mà không có bất kỳ mối liên kết để bản địa của thư viện (như CRT, ATL, hoặc MFC), và không có bất kỳ biến toàn cầu hoặc các lớp học bản xứ với tĩnh các thành viên dữ liệu:
  • ASP.NET Web dịch vụ tiêu bản
  • Lớp thư viện mẫu
  • Windows kiểm soát thư viện mẫu
Nếu bạn thêm mã có sử dụng các biến toàn cầu hoặc các lớp học bản xứ với các thành viên dữ liệu tĩnh (ví dụ, ATL, MFC và màn hình CRT thư viện dùng biến toàn cầu), bạn sẽ nhận được các thông báo lỗi linker tại thời gian biên dịch. Khi Điều này xảy ra, bạn phải thêm mã bằng tay khởi tạo biến tĩnh. Cho thêm thông tin về làm thế nào để làm điều này, hãy xem phần "Giải quyết" này bài viết.

Để thuận tiện, bài viết này đề cập đến các biến toàn cầu và các thành viên dữ liệu tĩnh của các lớp học bản xứ như "thống kê" hoặc "các biến tĩnh" từ thời điểm này về phía trước.

Vấn đề này gây ra bởi DLL hỗn hợp tải vấn đề. Hỗn hợp DLLs (có nghĩa là, DLLs có chứa mã nguồn gốc và được quản lý) có thể gặp phải tình huống bế tắc trong một số trường hợp nào khi được nạp vào trong quá trình địa chỉ không gian, đặc biệt là khi hệ thống là dưới sự căng thẳng. Các thông báo lỗi Linker đề cập ở trên đã được kích hoạt trong linker để đảm bảo khách hàng có ý thức về tiềm năng cho bế tắc và cách giải quyết các mà được mô tả trong tài liệu này. Cho một mô tả chi tiết của DLL hỗn hợp tải vấn đề, xem whitepaper sau đây:
GIẢI PHÁP
Quản lý các phần mở rộng cho các dự án C++ được tạo ra như DLLs Theo mặc định không liên kết với thư viện C/c ++ bản xứ như c run-time (CRT) thư viện, ATL hoặc MFC và không sử dụng bất kỳ các biến tĩnh. Ngoài ra, các thiết lập dự án chỉ ra rằng các DLL nên được liên kết với các / NOENTRY tùy chọn cho phép.

Điều này được thực hiện bởi vì liên kết với một điểm nguyên nhân quản lý mã để chạy trong thời gian DllMain, đó không phải là an toàn (xem DllMain cho sự hạn chế của điều bạn có thể làm trong thời gian của nó phạm vi).

Một DLL mà không có một điểm đã có cách nào để khởi tạo tĩnh biến ngoại trừ cho các loại rất đơn giản như số nguyên. Bạn làm gì không thường có các biến tĩnh trong một / NOENTRY DLL.

Các thư viện ATL, MFC và màn hình CRT tất cả dựa vào tĩnh các biến, do đó, bạn cũng không thể sử dụng các thư viện từ bên trong các dll Nếu không có sự sửa đổi làm đầu tiên.

Nếu DLL chế độ hỗn hợp của bạn cần phải sử dụng thống kê hoặc thư viện mà phụ thuộc vào tĩnh học (chẳng hạn như ATL, MFC hoặc màn hình CRT), sau đó bạn phải sửa đổi DLL của bạn để cho các tĩnh học cách thủ công khởi tạo.

Bước đầu tiên để khởi tạo hướng dẫn sử dụng là để đảm bảo rằng bạn không thể khởi tạo tự động mã, mà là không an toàn với hỗn hợp Dll và có thể gây ra bế tắc. Để vô hiệu hoá việc khởi tạo mã, hãy làm theo các bước.

Loại bỏ các điểm nhập cảnh của DLL quản lý

  1. Liên kết với / NOENTRY. Trong Giải pháp Explorer, bấm chuột phải vào các dự án nút bấm Thuộc tính. Trong các Trang thuộc tínhhộp thoại hộp, bấm vào Linker, bấm Dòng lệnh, và sau đó thêm này chuyển sang các Tùy chọn bổ sunglĩnh vực.
  2. Liên kết msvcrt.lib. Trong các Trang thuộc tính hộp thoại hộp, bấm vàoLinker, bấm Đầu vào., và sau đó thêm msvcrt.lib để các Bổ sung phụ thuộcbất động sản.
  3. Gỡ bỏ nochkclr.obj. Trên các Đầu vào Trang (cùng một trang như trong trước đó bước), loại bỏ nochkclr.obj từ các Bổ sung phụ thuộc bất động sản.
  4. Liên kết trong màn hình CRT. Trên các Đầu vào Trang (như nhau Trang như trong bước trước), thêm __DllMainCRTStartup@12 để các Lực lượng biểu tượng tham khảobất động sản.

    Nếu bạn đang sử dụng dấu nhắc lệnh, xác định các bên trên dự án thiết lập với những điều sau:
    LINK /NOENTRY msvcrt.lib /NODEFAULTLIB:nochkclr.obj /INCLUDE:__DllMainCRTStartup@12

Sửa đổi các thành phần mà tiêu thụ DLL cho hướng dẫn sử dụng Initializiation

Sau khi bạn loại bỏ điểm rõ ràng, bạn phải sửa đổi các thành phần tiêu thụ DLL cho khởi tạo hướng dẫn sử dụng, tùy thuộc vào cách rằng DLL của bạn được thực hiện:
  • DLL của bạn được nhập vào bằng cách sử dụng (xuất khẩu) DLL__declspec(dllexport)), và người tiêu dùng của bạn không thể sử dụng quản lý mã nếu họ được liên kết tĩnh hoặc tự động để DLL của bạn.
  • DLL của bạn là một DLL dựa trên COM.
  • Người tiêu dùng của DLL của bạn có thể sử dụng quản lý mã và DLL của bạn có chứa một trong hai xuất khẩu DLL hoặc quản lý điểm nhập cảnh.

Sửa đổi DLLs mà bạn nhập vào bằng cách sử dụng xuất khẩu DLL và Người tiêu dùng không thể sử dụng quản lý mã

Để sửa đổi DLLs mà bạn nhập vào bằng cách sử dụng xuất khẩu dll (__declspec(dllexport)) và người tiêu dùng không thể sử dụng mã được quản lý, theo các bước sau:
  1. Thêm hai mới xuất sang DLL của bạn, như được hiển thị ở đây Mã số:
    // 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.}
    Chú ý Visual C++ 2005, bạn phải thêm phổ biến ngôn ngữ runtime hỗ trợ biên dịch tùy chọn)/CLR:oldSyntax) để thành công biên dịch mẫu mã trước đó.Để thêm phổ biến hỗ trợ thời gian chạy ngôn ngữ biên dịch tùy chọn, hãy làm theo các bước sau:
    1. Nhấp vào Dự án, sau đó bấmProjectName Thuộc tính.

      Chú ý ProjectName là một giữ chỗ cho tên của dự án.
    2. Mở rộng Cấu hình thuộc tính, sau đó bấmTổng quát.
    3. Trong ngăn bên phải, bấm vào để chọn Hỗ trợ thời gian chạy ngôn ngữ phổ biến, cú pháp cũ (/ clr:oldSyntax) trong cácPhổ biến thời gian chạy ngôn ngữ hỗ trợ các thiết đặt của dự án.
    4. Nhấp vàoÁp dụng, sau đó bấm Ok.
    Để biết thêm thông tin về thời gian chạy ngôn ngữ phổ biến hỗ trợ tùy chọn biên dịch, ghé thăm Web site sau của Microsoft Developer Network (MSDN):Các bước này áp dụng cho toàn bộ bài viết.
  2. DLL của bạn có thể có một số người tiêu dùng. Nếu nó không có nhiều người tiêu dùng, thêm mã sau vào tập tin .def DLL trong xuất khẩu phần:
    DllEnsureInit	PRIVATEDllForceTerm	PRIVATE
    Nếu bạn không thêm những dòng này, và nếu bạn có hai DLLs xuất khẩu chức năng, ứng dụng các liên kết đến DLL sẽ có liên kết lỗi. Thông thường, các chức năng xuất khẩu có cùng tên. Trong trường hợp multiconsumer, mỗi người tiêu dùng có thể được liên kết tĩnh hoặc tự động đến DLL của bạn.
  3. Nếu người tiêu dùng tĩnh được liên kết với tệp DLL, trước khi bạn sử dụng thời gian DLL lần đầu tiên, hoặc trước khi bạn sử dụng bất cứ điều gì mà phụ thuộc vào nó trong ứng dụng của bạn, thêm các cuộc gọi sau đây:
    // Snippet 1typedef 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. Sau khi sử dụng cuối của DLL trong ứng dụng của bạn, thêm các mã sau đây:
    // 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. Nếu khách hàng tự động liên kết với tệp DLL, chèn Mã số như sau:
    • Chèn đoạn 1 (xem bước 3) ngay lập tức sau khi các đầu tiên LoadLibrary cho tệp DLL.
    • Chèn đoạn 2 (xem bước 4) ngay trước khi các cuối cùng FreeLibrary cho tệp DLL.

Để sửa đổi dựa trên COM DLL

  • Sửa đổi chức năng xuất khẩu DLL DllCanUnloadNow, DllGetClassObject, EFS, và DllUnregisterServer như thể hiện trong đoạn mã sau:
    //  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;}

Sửa đổi DLL có chứa người tiêu dùng sử dụng quản lý mã và xuất khẩu DLL hoặc quản lý nhập điểm

Để sửa đổi các DLL có chứa người tiêu dùng sử dụng quản lý mã và DLL xuất khẩu hoặc quản lý nhập điểm, hãy làm theo các bước sau:
  1. Thực hiện một lớp quản lý với chức năng thành viên tĩnh cho khởi tạo và chấm dứt. Thêm một tập tin .cpp vào dự án của bạn, thực hiện một quản lý lớp học với các thành viên tĩnh cho khởi đầu và chấm dứt:
    // 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. Gọi các chức năng này trước khi bạn tham khảo để DLL và sau khi bạn đã hoàn thành bằng cách sử dụng nó. Gọi khởi tạo và chấm dứt tài khoản của chức năng chính:
    // Main.cpp#using <mscorlib.dll>using namespace System;using namespace System::Reflection;#using "ijwdll.dll";int main() {	int retval = ManagedWrapper::minitialize();    ManagedWrapper::mterminate();}

Người sử dụng Visual c + +.NET 2002

Chú ý: Mặc dù thông báo lỗi linker LNK4243 không tồn tại trong các Visual c + +.Phát hành sản phẩm NET 2002, người sử dụng Visual c++.NET 2002 nên thực hiện theo các hướng dẫn về nói trước khi phát triển các hỗn hợp DLLs.

Visual c + +.NET 2003 sản phẩm phát hành chứa bổ sung tiêu đề để thực hiện việc khởi tạo hướng dẫn sử dụng thuận tiện hơn. Để thực hiện các giải pháp liệt kê trong công tác điều này với Visual C++.NET 2002, bạn phải thêm một tiêu đề tập tin vào dự án của bạn được gọi là _vcclrit.h với các văn bản sau đây:
/**** _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 __cplusplusextern "C" {#endifextern 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);}
THAM KHẢO
Để biết thêm thông tin, hãy bấm vào số bài viết sau để xem bài viết trong Cơ sở Kiến thức Microsoft:
309694LỖI: AppDomainUnloaded ngoại lệ khi bạn sử dụng quản lý phần mở rộng của các thành phần Visual C++

Cảnh báo: Bài viết này đã được dịch tự động

Thuộc tính

ID Bài viết: 814472 - Xem lại Lần cuối: 08/28/2011 09:14:00 - Bản sửa đổi: 2.0

  • 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
  • kbcominterop kbmanaged kbdll kbijw kbprb kbmt KB814472 KbMtvi
Phản hồi