MFC extension dll
-
// dllmain.cpp : Defines the initialization routines for the DLL.
static AFX_EXTENSION_MODULE CLibCyMetaTraderDLL = { false, nullptr };
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
// Remove this if you use lpReserved
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH)
{
// Extension DLL one-time initialization
if (!AfxInitExtensionModule(CLibCyMetaTraderDLL, hInstance))
return 0;
// Insert this DLL into the resource chain
new CDynLinkLibrary(CLibCyMetaTraderDLL);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
// Terminate the library before destructors are called
AfxTermExtensionModule(CLibCyMetaTraderDLL);
}
return 1; // ok
}
Dllmain 함수 인자 dwReason
- DLL 활용하는 프로세스에서 Dllmain 호출하는 상황에 따라 아래 4가지의 값이 전달됨.
DLL_PROCESS_ATTACH : DLL 사용 프로세스 생성(메모리에 DLL 로딩)시.
DLL_PROCESS_DETACH : DLL 사용 프로세스 종료(메모리에서 DLL 해제)시
DLL_THREAD_ATTACH : DLL 사용 프로세스의 새로운 스레드에서 DLL 로딩시.
DLL_THREAD_DETACH : DLL 사용 프로세스의 새로운 스레드에서 DLL 해제시.
new CDynLinkLibrary(CLibCyMetaTraderDLL);
- 리소스 체인에 확장 DLL 을 추가하는것.
- 확장 DLL 을 MFC regular dll 에서 로딩 시 주의사항.
- - 확장 DLL이 자체 리소스(대화상자, bmp등 모든 리소스) 기반 구현된것을 MFC regular dll 에서 로딩하려는 경우 확장DLL 에서 자신의 리소스에 접근 못하고 MFC gegular dll 의 리소스가 표현되는 원인이 되므로 필수 주의사항.
처리 요점.
- new CDynLinkLibrary(CLibCyMetaTraderDLL); 를 Dllmain 에서는 주석처리하고, 외부 노출함수 별도 마련하여 MFC regular dll 에서 해당 노출함수를 호출하여 명시적으로 실행시킬것.
// NOTE: If this Extension DLL is being implicitly linked to by
// an MFC Regular DLL (such as an ActiveX Control)
// instead of an MFC application, then you will want to
// remove this line from DllMain and put it in a separate
// function exported from this Extension DLL. The Regular DLL
// that uses this Extension DLL should then explicitly call that
// function to initialize this Extension DLL. Otherwise,
// the CDynLinkLibrary object will not be attached to the
// Regular DLL's resource chain, and serious problems will
// result.
확장 DLL 의 HINSTANCE (인스턴스 핸들)
구조체 AFX_EXTENSION_MODULE 의 멤버변수인 hModule 이 인스턴스 핸들이다.
외부에 인스턴스 핸들을 제공하려면 외부제공용 전역 함수 준비해두면, DLL 활용하는 쪽에서 이 함수 호출하여 DLL 인스턴스 핸들 확보한다.
// DLL B의 dllmain.cpp 파일에 추가
// DLL B의 AFX_EXTENSION_MODULE 구조체 참조
extern AFX_EXTENSION_MODULE CyS90LE3CyMetaIPCDLL;
extern "C" __declspec(dllexport) HINSTANCE GetDllBInstance()
{
// AFX_EXTENSION_MODULE의 hModule 멤버가 DLL의 HINSTANCE임
return CyS90LE3CyMetaIPCDLL.hModule;
}
확장 DLL 의 리소스 아이디 충돌문제 해결 방법
- 확장 DLL 들의 리소스 아이디가 동일한 경우 종종 있다. DLL A 대화상자와 DLL B 대화상자의 리소스 아이디가 1007 으로 동일한 경우 DLL A 에서 DLL B 의 대화상자 표현시 DLL A 의 대화상자가 표현되는 문제 발생한다.
해결방법
- 아래 코드 처럼 DLL B 의 인스턴스 핸들 받아서 DLL B 대화상자 표현전에 DLL B 의 리소스가 적용되게 한다.
// DLL A의 코드에서 DLL B의 함수 호출
// DLL B에서 내보낸 함수 선언
extern "C" __declspec(dllimport) HINSTANCE GetDllBInstance();
void ShowDialogFromDLLB()
{
// DLL B의 인스턴스 핸들 가져옴
HINSTANCE hInstDllB = GetDllBInstance();
// 현재 리소스 핸들을 저장
HINSTANCE hInstOld = AfxGetResourceHandle();
// DLL B의 리소스 핸들로 전환
AfxSetResourceHandle(hInstDllB);
// DLL B의 대화상자 생성 및 표시
CYourDialogB dlgB; // DLL B의 대화상자 클래스
dlgB.DoModal();
// 원래 리소스 핸들로 복원
AfxSetResourceHandle(hInstOld);
}
위 방법으로 리소스 아이디 충돌 문제 해결 가능하며 아래처럼 별도 클래스 만들어 활용하는 방법도 있다.
RAII 패턴을 사용하는 리소스 핸들 스위처 클래스
- RAAI : Resource Acquisition Is Initialization
// Helper 클래스 정의
class CResourceSwitcher
{
HINSTANCE m_hInstOld; // 이전 핸들을 저장하기 위한 멤버 변수
public:
CResourceSwitcher(HINSTANCE hNewInst)
{
m_hInstOld = AfxGetResourceHandle(); // 이전 핸들 저장
AfxSetResourceHandle(hNewInst); // 새 핸들 설정
}
~CResourceSwitcher()
{
AfxSetResourceHandle(m_hInstOld); // 소멸자에서 원래 핸들 복원
}
};
// 사용 예시
void ShowDialogFromDLLB()
{
// 자동으로 리소스 핸들 전환 및 복원
CResourceSwitcher switcher(theAppB.m_hInstance);
// DLL B의 대화상자를 생성하고 표시합니다.
CYourDialogB dlgB; // DLL B의 대화상자 클래스
dlgB.DoModal();
// 여기서 CResourceSwitcher 소멸자가 호출되며 원래 리소스 핸들로 복원됨
}
연관
첫 등록 : 2020.10.04
최종 수정 : 2024.09.05
단축 주소 : https://igotit.tistory.com/2634
'VisualStudio.C++.C# > 코딩팁,함수활용,단편' 카테고리의 다른 글
std::queue. (0) | 2020.10.17 |
---|---|
std::vector. STL vector class. 사용법. (0) | 2020.10.14 |
MFC. CFileDialog . 파일열기, 쓰기 공통대화상자 (0) | 2020.10.02 |
MFC. 스크롤바 제거 (0) | 2020.10.02 |
MFC. CWnd::PreTranslateMessage . WM_KEYDOWN 핸들러로 수신못할 때. (0) | 2020.09.30 |
댓글