Memory leakage bei MFC mit ATL (Asynchronous Pluggable Protocol)

20/08/2010 - 00:25 von Peter Mairhofer | Report spam
Hi,

Wenn ich meine Anwendung debugge, meldet mir VC ein Memory Leakage:

[...]
Der Thread 'Win32 Thread' (0xa9c) hat mit Code 0 (0x0) geendet.
Der Thread 'Win32 Thread' (0x414) hat mit Code 0 (0x0) geendet.
Der Thread 'Win32 Thread' (0xfb4) hat mit Code 0 (0x0) geendet.
Der Thread 'Win32 Thread' (0xc8c) hat mit Code 0 (0x0) geendet.
Der Thread 'Win32 Thread' (0x604) hat mit Code 0 (0x0) geendet.
Der Thread 'Win32 Thread' (0x80c) hat mit Code 0 (0x0) geendet.
Der Thread 'Win32 Thread' (0x698) hat mit Code 0 (0x0) geendet.
Detected memory leaks!
Dumping objects ->
{61} normal block at 0x003330D0, 36 bytes long.
Data: < BC > E4 42 43 00 01 00 00 00 00 81 14 00 FF FF FF FF
Object dump complete.
Das Programm "[3748] test.exe: Systemeigen" wurde mit Code 0 (0x0) beendet.

Jetzt habe ich systematisch alle Komponenten aus meinem MFC Programm
entfernt. Das Einzige was jetzt übrig bleibt ist ein minimalstes
Testprogramm:
* SDI MFC Projekt mit CHtmlView als View
* Navigate("test://foo/bar"); in CMyView::OnUpdate()
* ATL Unterstützung
* Eine Implementierung des Pluggable Protocols (minimalst!) (s.u.)
* Registrierung der COM Komponente (s.u.)

Das ist die Definition meines Pluggable Protocols:

class ATL_NO_VTABLE CTestProtocol :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CTestProtocol, &CLSID_TestProtocol>,
public IInternetProtocol,
public IInternetProtocolInfo
{
public:
CTestProtocol() : m_fData(16384)
{
}

DECLARE_REGISTRY_RESOURCEID(IDR_TESTPROTOCOL)

BEGIN_COM_MAP(CTestProtocol)
COM_INTERFACE_ENTRY(IInternetProtocolInfo)
COM_INTERFACE_ENTRY(IInternetProtocol)
END_COM_MAP()


DECLARE_PROTECT_FINAL_CONSTRUCT()

HRESULT FinalConstruct()
{
return S_OK;
}

void FinalRelease()
{
}

// IInternetProtocol interface
public:
STDMETHOD(Start)(
LPCWSTR szUrl,
IInternetProtocolSink *pIProtSink,
IInternetBindInfo *pIBindInfo,
DWORD grfSTI,
DWORD dwReserved);
STDMETHOD(Read)(void *pv,ULONG cb,ULONG *pcbRead);

[...] (Rest weggelassen)

private:
CMemFile m_fData;
};

OBJECT_ENTRY_AUTO(__uuidof(TestProtocol), CTestProtocol)

Und das ist die Implementierung:

STDMETHODIMP CTestProtocol::Start(LPCWSTR szUrl, IInternetProtocolSink
*pIProtSink, IInternetBindInfo *pIBindInfo, DWORD grfSTI, DWORD dwReserved)
{
CString sUrl(szUrl);

CString data = "Hello, world";
m_fData.Write(data, data.GetLength());

m_fData.SeekToBegin();

pIProtSink->ReportProgress(BINDSTATUS_FINDINGRESOURCE, szUrl);
pIProtSink->ReportProgress(BINDSTATUS_CONNECTING, szUrl);
pIProtSink->ReportProgress(BINDSTATUS_SENDINGREQUEST, szUrl);
pIProtSink->ReportProgress(BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE,
L"text/html");
pIProtSink->ReportData(BSCF_FIRSTDATANOTIFICATION, 0,
static_cast<ULONG>(m_fData.GetLength()));
pIProtSink->ReportData(BSCF_LASTDATANOTIFICATION |
BSCF_DATAFULLYAVAILABLE, static_cast<ULONG>(m_fData.GetLength()),
static_cast<ULONG>(m_fData.GetLength()));
pIProtSink->ReportResult(S_OK, 0, NULL);

return S_OK;
}

STDMETHODIMP CTestProtocol::Read(void *pv, ULONG cb, ULONG *pcbRead)
{
ATLTRACE(_T("READ - requested=%8d"), cb);

HRESULT hr = S_OK;

if(m_fData.GetPosition() >= m_fData.GetLength())
return S_FALSE;

*pcbRead = m_fData.Read(pv, cb);

return hr;
}

Ich poste nur die 2 Methoden Start und Read weil ich den Rest nicht
implementiert habe!

Schließlich weise ich nur mehr diese COM Implementierung dem eigenen
Prozess zu:

BOOL CTestApp::RegisterProtocol(BOOL bRegister)
{
CStringW protocol = L"test";
CComPtr<IInternetSession> spIInetSession;
CComPtr<IClassFactory> spCF;

if(FAILED(CoInternetGetSession(0, &spIInetSession, 0)))
return FALSE;

if(FAILED(CTestProtocol::_ClassFactoryCreatorClass::CreateInstance(CTestProtocol::_CreatorClass::CreateInstance, IID_IClassFactory, reinterpret_cast<void**>(&spCF))))
return FALSE;

HRESULT hr;
if(bRegister)
hr = spIInetSession->RegisterNameSpace(spCF, CLSID_TestProtocol,
protocol, 0, NULL, 0);
else
hr = spIInetSession->UnregisterNameSpace(spCF, protocol);

return SUCCEEDED(hr);

return TRUE;
}

BOOL CTestApp::InitInstance()
{
[...]
if(!RegisterProtocol(TRUE))
return FALSE;
[...]
}

BOOL CTestApp::ExitInstance(void)
{
RegisterProtocol(FALSE);
_AtlModule.RevokeClassObjects();
return CWinApp::ExitInstance();
}

Das ist alles! Also wirklich nur das normale MFC Grundgerüst mit einer
Minimal COM Implementierung. Trotzdem gibt es den Memory Leakage.

Kommentiere ich RegisterProtocol aus (das Pluggable Protocol wird also
nicht registriert) so gibt es den Memory Leakage nicht.

Kann mir jemand sagen wo sich in diesem Mini-Programm ein Speicherleck
verstecken kann?


LG
Peter

PS: Diese Meldungen im Debugger sind eh nicht kritisch - oder doch?!
Warning: constructing COleException, scode = DISP_E_MEMBERNOTFOUND
($80020003).
Eine Ausnahme (erste Chance) bei 0x7c812afb in Test.exe: Microsoft C++
exception: COleException @ 0x0012dfd0.
und
Eine Ausnahme (erste Chance) bei 0x7c812afb in Test.exe: 0x80010108: Das
aufgerufene Objekt wurde von den Clients getrennt.
 

Lesen sie die antworten

#1 Peter Mairhofer
20/08/2010 - 17:22 | Warnen spam
Am 20.08.2010 00:25, schrieb Peter Mairhofer:
Hi,



Problem solved:

Wenn ich meine Anwendung debugge, meldet mir VC ein Memory Leakage:
[...]
if(bRegister)
hr = spIInetSession->RegisterNameSpace(spCF, CLSID_TestProtocol,
protocol, 0, NULL, 0);
else
hr = spIInetSession->UnregisterNameSpace(spCF, protocol);



spCF muss das gleiche Objekt sein! Ich muss es also als Membervariable
in CMyWinApp speichern!

Bleiben noch diese 2 Fragen - vielleicht weiss darauf jemand eine Antwort?

PS: Diese Meldungen im Debugger sind eh nicht kritisch - oder doch?!
Warning: constructing COleException, scode = DISP_E_MEMBERNOTFOUND
($80020003).
Eine Ausnahme (erste Chance) bei 0x7c812afb in Test.exe: Microsoft C++
exception: COleException @ 0x0012dfd0.
und
Eine Ausnahme (erste Chance) bei 0x7c812afb in Test.exe: 0x80010108: Das
aufgerufene Objekt wurde von den Clients getrennt.



LG
Peter

Ähnliche fragen