ATL 및 iunkNownptr을 사용할 때 캐스트하는 올바른 방법은 무엇입니까?
-
18-09-2019 - |
문제
기존 ATL COM 객체를 수정하는 동안 나는 "The Old New Thing"블로그에서 "The Ways Up Iunknown :: QueryInterface"라는 기사를 발견했으며 의견 섹션에서 시작된 주석 섹션에서 토론이 시작되었습니다. 응답자 (Norman Diamond)는이 기사의 예 중 하나에서 void **에 대한 캐스트가 잘못되었다고 지적했다.
그러나 코드를 제대로 수행하기 위해 코드를 수정하려고 할 때 메모리 누출로 끝납니다.
예는 다음과 같습니다.
IShellFolder *psf = some object;
IUnknown *punk = NULL;
psf->QueryInterface(IID_IUnknown, (void**)&punk);
노먼이 말했다
펑크는 무효가 아닙니다*. 펑크는 iunknown*입니다.
void **는 보편적 인 포인터 유형이 아닙니다. Void*는 보편적 인 포인터 유형이며, Char*와 친척은 그런 식으로 동등하게 조부모가되지만 Void **는 그렇지 않습니다.
부름 규칙에 순종하고 끔찍한 죽음을 피하려면 다음을 수행해야합니다. iunknown *펑크; void *punkvoid; psf-> QueryInterface (iid_iunknown, & punkvoid); 펑크 = (iunknown *) punkvoid;
다른 많은 MSDN 기고자들도 동일한 실수를 저질렀습니다 .... 어떤 사람들은 그것이 현재까지 모든 VC ++ 구현에서 작동한다고 말할 수도 있지만, 이것이 올바른 코드를 만들지는 않지만 여전히 전화 컨벤션을 위반하고 있습니다.
이것에 비추어 나는 이전 코드를 바꾸려고했다 - 이것은 다음과 같습니다.
#include <comdef.h>
...
HRESULT FinalConstruct()
{
if (m_dwROTCookie != 0)
return E_FAIL;
//Check whether there already is an instance of the Object
IUnknownPtr pUnk = NULL;
if (GetActiveObject(CLSID_Object, NULL, &pUnk) == S_OK)
{
TRACE_WARNING("An instance of Object already exists in the current context");
return S_OK;
}
HRESULT hr = QueryInterface(IID_IUnknown, reinterpret_cast<void **>(&pUnk));
hr = RegisterActiveObject(pUnk, CLSID_Object, ACTIVEOBJECT_WEAK, m_dwROTCookie);
if (FAILED(hr))
return hr;
hr = CoLockObjectExternal(pUnk, TRUE, TRUE);
pUnk = NULL;
ATLASSERT(m_dwRef == 2);
return hr;
}
그런 다음 다음과 같이 변경했습니다.
HRESULT FinalConstruct()
{
if (m_dwROTCookie != 0)
return E_FAIL;
//Check whether there already is an instance of the Object
IUnknownPtr pUnk = NULL;
if (GetActiveObject(CLSID_Object, NULL, &pUnk) == S_OK)
{
TRACE_WARNING("An instance of Object already exists in the current context");
return S_OK;
}
void* pUnkVoid = NULL;
HRESULT hr = QueryInterface(IID_IUnknown, &pUnkVoid);
if (SUCCEEDED(hr)
{
pUnk = reinterpret_cast<IUnknown*>(pUnkVoid);
hr = RegisterActiveObject(pUnk, CLSID_Object, ACTIVEOBJECT_WEAK, m_dwROTCookie);
if (FAILED(hr))
return hr;
hr = CoLockObjectExternal(pUnk, TRUE, TRUE);
pUnk = NULL;
}
ATLASSERT(m_dwRef == 2);
return hr;
그러나 이제 내 응용 프로그램은이 제품에서 메모리 누출이 있습니다.
해결책
전화하기 때문에 메모리 누출이있을 수 있습니다 GetActiveObject()
그리고 QueryInterface()
성공시 객체의 참조 계산이 증가하지만 호출하지 마십시오. Release()
나중에 참조 수를 줄이기 위해.
다른 팁
음, 나는 void*를 펑크에 할당하기보다는 다음을 사용해야한다고 생각합니다.
pUnk.Attach(reinterpret_cast<IUnknown*>(pUnkVoid));