티스토리 뷰
MFC DLL에서 class에 vector를 담아서 Export 하려 시도 하였다.
처음에는 잘 되는 듯이 보였지만, class를 delete 하는 순간, 와장창 무너지기 시작했다.
계속해서 dbgheap.c의 _CrtIsValidHeapPointer(const void * pUserData) 안에 있는
HeapValidate( _crtheap, 0, pHdr(pUserData) ); 에서 FALSE을 리턴하여 ASSERT에 걸리게 되었다.
계속 디버깅을 해보니, vector의 소멸을 제대로 하지 못하고 있었다.
vector의 소멸자를 따라가 보니 dbgheap.c의 _crtheap이 caller의 heap을 가리키고 있는 것이 보였다.
아니, 애당초 call stack의 소멸 지점이 callee 인 dll이 아니라, caller인 application 이었다.
구글링을 해보니 STL 객체가 포함된 클래스를 내보내는 방법에 대한 msdn 문서가 있었다.
https://support.microsoft.com/ko-kr/kb/168958
중요한 것은, export 하는 class에서 사용하는 stl 타입의 선언을 아래와 같이 class 외부에서 한번 더 해줘야 하며,
template class __declspec(dllexport) std::vector<자료형>;
import 하는 class에서는 아래와 같이 선언해 줘야 한다는 것이다.
extern template class __declspec(import) std::vector<자료형>;
또한 STL 컨테이너 중에서 유일하게 vector<T> 타입만이 DLL Export가 가능하다.
위와 같이 해주니, vector의 소멸 시점에 정상적으로 callee인 DLL의 heap을 잡는 것이 보였고,
소멸 역시 제대로 이루어 졌다.
사족 )
이번 삽질을 통해 알아낸 재밌는 사실 중 하나는, MFC project의 경우 allocator delete(*)를 crt library에서 부르는 것이 아니라 mfc library에서 먼저 호출한다는 것이다.
이는 afxmem.cpp에 있는 void __cdecl operator delete(void* p)로 오게 된다. (결국엔 crt로 오기는 한다. [debug 모드에서 찍어보면 dbgheap.c로 간다])
crt library의 경우 중간 단계 없이 바로 delete로 간다.
이 순서는 재밌게도, 라이브러리 import 순서에 따르며 이렇게 되는 이유는, CRT 라이브러리가 new, delete 및 DllMain 함수에 대해서 약한 외부 링크를 사용하기 때문이다.
따라서 CRT 라이브러리가 링크 되기 전에 MFC 라이브러리를 링크 하면 MFC 라이브러리에 있는 new, delete 및 DllMain 함수가 먼저 호출되는 것이다.
C++도 아니고 C에서 이런 신박한 코드를 작성하다니 재밌다 :)
사족 참조 : https://support.microsoft.com/ko-kr/kb/148652
처음에는 잘 되는 듯이 보였지만, class를 delete 하는 순간, 와장창 무너지기 시작했다.
계속해서 dbgheap.c의 _CrtIsValidHeapPointer(const void * pUserData) 안에 있는
HeapValidate( _crtheap, 0, pHdr(pUserData) ); 에서 FALSE을 리턴하여 ASSERT에 걸리게 되었다.
계속 디버깅을 해보니, vector의 소멸을 제대로 하지 못하고 있었다.
vector의 소멸자를 따라가 보니 dbgheap.c의 _crtheap이 caller의 heap을 가리키고 있는 것이 보였다.
아니, 애당초 call stack의 소멸 지점이 callee 인 dll이 아니라, caller인 application 이었다.
구글링을 해보니 STL 객체가 포함된 클래스를 내보내는 방법에 대한 msdn 문서가 있었다.
https://support.microsoft.com/ko-kr/kb/168958
중요한 것은, export 하는 class에서 사용하는 stl 타입의 선언을 아래와 같이 class 외부에서 한번 더 해줘야 하며,
template class __declspec(dllexport) std::vector<자료형>;
import 하는 class에서는 아래와 같이 선언해 줘야 한다는 것이다.
extern template class __declspec(import) std::vector<자료형>;
또한 STL 컨테이너 중에서 유일하게 vector<T> 타입만이 DLL Export가 가능하다.
위와 같이 해주니, vector의 소멸 시점에 정상적으로 callee인 DLL의 heap을 잡는 것이 보였고,
소멸 역시 제대로 이루어 졌다.
사족 )
이번 삽질을 통해 알아낸 재밌는 사실 중 하나는, MFC project의 경우 allocator delete(*)를 crt library에서 부르는 것이 아니라 mfc library에서 먼저 호출한다는 것이다.
이는 afxmem.cpp에 있는 void __cdecl operator delete(void* p)로 오게 된다. (결국엔 crt로 오기는 한다. [debug 모드에서 찍어보면 dbgheap.c로 간다])
crt library의 경우 중간 단계 없이 바로 delete로 간다.
이 순서는 재밌게도, 라이브러리 import 순서에 따르며 이렇게 되는 이유는, CRT 라이브러리가 new, delete 및 DllMain 함수에 대해서 약한 외부 링크를 사용하기 때문이다.
따라서 CRT 라이브러리가 링크 되기 전에 MFC 라이브러리를 링크 하면 MFC 라이브러리에 있는 new, delete 및 DllMain 함수가 먼저 호출되는 것이다.
C++도 아니고 C에서 이런 신박한 코드를 작성하다니 재밌다 :)
사족 참조 : https://support.microsoft.com/ko-kr/kb/148652
'Development > Windows' 카테고리의 다른 글
[WPF] User Control에 Custom Attribute로 값 전달하기 (0) | 2018.04.22 |
---|---|
[WPF] cs 파일에 있는 변수를 xaml에서 binding 하기 (2) | 2018.04.22 |
윈도우 배치 파일 강좌 (1) | 2018.01.06 |
[MFC] CRect의 IsRectNull()과 IsRectEmpty() (0) | 2016.02.16 |
[MFC] ToolBar 항목 지우는 방법 (2) | 2012.02.26 |
[TroubleShooting/MFC] Double Buffering을 구현하였는데도 깜빡이는 문제 (0) | 2012.02.24 |
[MFC] 다이얼로그 배경 투명하게 만들기 (0) | 2012.02.23 |
[MFC] Double Buffering 더블 버퍼링 사용하기 (0) | 2012.02.19 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- API
- MFC
- linux
- algorithm
- java
- db
- Visual C++
- source
- 음악
- Troubleshooting
- Quiz
- it
- 리눅스
- jni강좌
- driver
- 프로그래밍
- AWS
- gcc
- C
- C++
- jni
- Python
- android
- Cloud
- NDK
- winapi
- 드라이버
- kering
- database
- 안드로이드
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
글 보관함