2009-10-28 4 views
7

내가 DLL을 수백 거대한 (대부분) C++/MFC 응용 프로그램에서 작동(관리되지 않는) C++

[이 ... 죄송합니다 ... TLDR을 받고있다] ; COM을 통해 동적으로로드되는 "추가 기능"메커니즘을 지원하므로 COM interop을 사용하여 .NET에서 추가 기능을 개발할 수 있습니다. 이 "추가 기능"메커니즘 (아직 동적으로로드되어 있음에도 불구하고)을 사용하지 않고 일부 제한된 새 기능이 .NET에서 개발되었습니다. 그러나 최종 사용자는이 기능을 사용하지 않기로 결정할 수 있습니다. 따라서 .NET은 시작할 때로드되지 않을 수 있습니다.

그러나, .NET 가 좀 .NET 고유의 초기화와 작업을 수행 할 필요가로드 될 때 (특히 네이티브/관리되지 않는 UI에 맞게 CurrentUICulture 설정).

한 가지 해결 방법은 코드가 새로운 .NET 기능 또는 COM 추가 기능을로드하는 중일 때 간단히 펀치 앤해서이 .NET 초기화를 수행하는 것입니다. 이 응용 프로그램의 특성을 감안할 때, 아마도 95 % 이상의 솔루션입니다 (대부분의 사용자는 새로운 기능을 사용하게됩니다).

하지만 절대 안전한 것은 아닙니다. 누구든지 /clr 플래그가있는 모듈을 구축하여 언제든지 새로운 .NET 기능을 쉽게 추가 할 수 있습니다 (이는 거대한 응용 프로그램입니다).

한 가지 더 강력하고 (명백한) 해결책은 단순히 C++/CLI를 통해 시작시 .NET을로드하게하는 것입니다. 그러나 바이트와 클록주기가 중요한 다이 하드 C++ 개발자 중 일부는이 작업을 원하지 않습니다. 어느 정도 설정이 필요하지 않으므로 CurrentUICulture이 필요합니다.

내가 생각한 또 다른 가능성은 LoadLibrary을 연결하고 을 찾습니다. mscorlib입니다. 이제 .NET은 어떤 이유로로드 될 예정이며 일반적인 방식으로로드하고 다른 코드가 수행하기 전에 초기화를 수행한다는 것을 알았습니다. 그러나 LoadLibrary (또는 그 문제에 대해서는 다른 어떤 것)을 연결하는 것은 내가하고 싶은 일이 아닙니다.

그래서 .NET이로드 될 것인지 쉽게 알 수 있습니다 (ier)/더 나은 방법이 있습니까?

편집 : 리드의 대답은 입니다. LockClrVersion은 꽤 가까웠습니다. 유일한 걸림돌은 혼합 모드 DLL/어셈블리에 링크하면 작동하지 않는다는 것입니다.

// ClrAboutToLoad.cpp : Defines the entry point for the console application. 
// 

#include "stdafx.h" 

#include <MSCorEE.h> 

// http://community.bartdesmet.net/blogs/bart/archive/2005/07/22/2882.aspx 
FLockClrVersionCallback begin_init, end_init; 
STDAPI hostCallback() 
{ 
    printf("hostCallback()\n"); 

    // we're in control; notify the shim to grant us the exclusive initialization right 
    begin_init(); 

    ICLRRuntimeHost *pHost = NULL; 
    HRESULT hr = CorBindToRuntimeEx(NULL, L"wks", STARTUP_SERVER_GC, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (PVOID*) &pHost); 
    hr = pHost->Start(); 

    // mission completed; tell the shim we're ready 
    end_init(); 

    return S_OK; 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    LockClrVersion(&hostCallback, &begin_init, &end_init); 

    //fnTheDLL(); 
    HMODULE hModule = LoadLibrary(L"TheDLL"); 
    FARPROC fp = GetProcAddress(hModule, "fnTheDLL"); 
    typedef void (*fnTheDLL_t)(); 
    fnTheDLL_t fnTheDLL = reinterpret_cast<fnTheDLL_t>(fp); 
    fnTheDLL(); 
    FreeLibrary(hModule); 

    return 0; 
} 

답변

6

관리되는 API를 사용하기 전에 프로세스가 관리되지 않는 LockClrVersion 함수를 호출하도록하면됩니다. 이 함수는 두 개의 FLockClrVersion callback 메소드를 지정할 수있게합니다.

첫 번째 방법 (pBeginHostSetup)은 호스팅 프로세스에 대해 처음으로 CLR을 초기화하기 전에 호출됩니다. CLR은 초기화가 완료되면 두 번째 방법은 (pEndHostSetup)라고한다.

이렇게하면 CLR 초기화 직전과 직후에 실행되는 비 관리 코드를 지정할 수 있습니다. 귀하의 경우에는, 당신은 아마 (당신이 CLR이 성공적으로 호스팅 될 때까지 기다려야합니다) 관리되는 API 설정 루틴을 호출 할 pEndHostSetup에 연결해야합니다.

+0

이것은 유망 해 보인다! –

+0

그것은 정확히 후 무엇을해야합니까 - 내가 그것을 implemneted하지 않은,하지만 난 그것을 추적하려고 전체 CLR 호스팅 API를 통해 갔다. –

+0

이것은 거의 완벽합니다. 유일한 장애는 * LockClrVersion *을 호출하기 전에 CLR이로드되지 않도록해야한다는 것입니다. "문제"는 혼합 모드 어셈블리에서 연결하면 CLR이로드되므로 어셈블리를 동적으로로드해야합니다. –

-1

응용 프로그램 시작시 .NET Framework를 초기화해야합니다. 비슷한 배경의 앱에서 작업했는데 2 개의 dll이 .net dll에 간접적으로 액세스하여 .net 프레임 워크를 초기화하려고했기 때문에 때때로 교착 상태가됩니다. 이 문제를 해결하기 위해 실행 파일의 진입 점의 처음 몇 줄에 CorBindToRuntimeEx을 호출했습니다.

.NET을로드하려고하면 OS가 알려줄 방법이 없다고 생각합니다.

+0

내에서 아무 인수; 바이트 카운터는 .NET을 초기화하지 않을 경우 사용하지 않을 것입니다. 이것은 (매우) 큰 프로젝트라는 것을 기억하십시오. 작업 할 엔지니어링 문제뿐만 아니라 정치적인 문제도 있습니다. –

1

run your own CLR host to load assemblies 수 있습니다. 그런 다음 어떤 버전의 런타임 (1.1? 2.0? 4.0?)을로드 할 것인지에 대한보다 구체적인 결정을 내릴 수 있으며 코드에서 관리 코드를 분리 할 수 ​​있습니다 (when a plugin crash, your code won't go down with it).

+0

나는 그것에 대해 생각했지만 ... 바이트 카운터가 정확하게 .NET을 처음부터 받아들이는 것은 아닙니다. COM interop 덕분에 .NET이 존재한다고해도 (대부분은) 기쁜 듯이 깨닫지 못합니다. (.NET에서 작성된 "새로운 기능"은 그들에게 강제되었습니다.) –

1

성능 카운터와 WMI의 두 가지 이점이 있습니다. .NET CLR은 둘 모두와 통합되므로 AppDomain 시작을 감시하려면 WMI (아마도 WMI가 가장 좋음)와 상호 작용할 수 있어야합니다.그러나 이러한 도구는 특히 이상적이지 않으며 오버 헤드면에서 Sheng Jiang이 제안한대로 CLR을 자체적으로 호스팅하면 더 효율적입니다 (따라서 "바이트 카운터"가 더 편할 것입니다).

당신은 개발 팀 영향력과 통제의 수단이있는 경우 약간 다른 노트에

는 ..., 나는 "바이트 카운터"약간의 스릴 것입니다. .NET에 대한 가장 큰 오해 중 하나는 C++보다 비효율적이라는 것입니다. .NET을 놀라 울 정도로 효율적으로 사용할 수 있고 제대로 사용하면 C++보다 효율적이기 때문에 오래된 오류를 숨길 필요가 있습니다. 프로세스 간 호출 (: 정말, 때 통계적으로, 일반적으로 성능을 죽이지는 더 큰 규모의 일 최고 곡물을 최적화하는 시간의 알 수없는 볼륨을 지출에 의해 얼마나 많은 효율을 얻을 것입니다 : 두 플랫폼의 기본 효율성 외에도, 당신은 질문을해야 NET에서 .NET 객체 호출), 데이터베이스 (예 : 웹 서비스, RPC 등) 호출, 데이터베이스 호출 등).

.NET을 해결하려고 할 수 있습니다. AppDomain 시작 문제로 인해 바이트 카운터 오해를 완화하거나 .NET 시스템을 올바르게 구현할 수 있으며 마샬링 및 inter-op 히트가 바이트 수준 성능 튜닝으로 인해 막대한 피해를 입히는 것보다 더 많이 소모 될 수 있습니다.

+0

저에게서 논쟁 없음; 그러나 오래된 오해는 점점 더 심해진다. –

+0

허, 너무 사실입니다. 슬픈, 그러나 확실히 사실. – jrista

0

어셈블리가로드 될 때 연결하지 않고 AppDomain이로드 될 때 연결할 수 있습니까? System.AppDomainManager를 조사하십시오.

하위 클래스의 System.AppDomainManager를 GAC에로드 한 후 C++ 프로그램을 실행하기 전에 일부 환경 변수 (APPDOMAIN_MANAGER_TYPE, APPDOMAIN_MANAGER_ASM)를 설정하기 만하면됩니다.

+0

.NET (CLR)이로드 될 예정이거나 어셈블리 또는 AppDomain이로드 될시기를 알고 싶습니다. 즉, 관리되지 않는 (OK, 혼합 된) 프로세스가 처음으로 관리되는 코드를 실행할 준비가되었는지를 알고 싶습니다. –

관련 문제