From: RedLars on
Hello,

In an application I'm involved with we're trying to get a drag-and-
drop functionality to work between a mfc dialog and a .NET forms
within the same process. Here is an slightly abbreviate code snippet
from mfc part:

COleDataSource * pDataSource = new COleDataSource;
// fill-in code
pDataSource->CacheGlobalData(...);
pDataSource->DoDragDrop ();

This code works! The correct data is transferred to the destination!
The problem now is cleaning up.

Adding a delete pDataSource causes an access violation in destination
code.

What I've noticed is that pDataSource->m_dwRef is increment to 1 on
creation and increased to 3 if OnDragEnter\OnDragDrop or OnDragEnter
\OnDragLeave occurs in destination code.

Seen some code example use the following pattern:

pDataSource->DoDragDrop ();
if ( pDataSource->m_dwRef <= 1)
delete pDataSource;
else
pDataSource->ExternalRelease();

Does this make sense?

After a bit of digging I found out that COleDataSource (actually
CCmdTarget ) contains several sort of similar methods:
* InternalRelease
* ExternalRelease
* ExternalDisconnect

What is the difference between Internal and External Release?
What is the difference between Release and Disconnect?

Thanks for any help.
From: Giovanni Dicanio on

"RedLars" <Liverpool1892(a)gmail.com> ha scritto nel messaggio
news:4463e7a9-21aa-4fec-af81-3d666dfae6ae(a)c65g2000hsa.googlegroups.com...

> COleDataSource * pDataSource = new COleDataSource;
> // fill-in code
> pDataSource->CacheGlobalData(...);
> pDataSource->DoDragDrop ();
>
> This code works! The correct data is transferred to the destination!
> The problem now is cleaning up.
>
> Adding a delete pDataSource causes an access violation in destination
> code.
>
> What I've noticed is that pDataSource->m_dwRef is increment to 1 on
> creation and increased to 3 if OnDragEnter\OnDragDrop or OnDragEnter
> \OnDragLeave occurs in destination code.

Those OLE objects are reference counted, so I would not call 'delete' on
them...
I would "respect" their contract of AddRef/Release (these are methods
present in IUknown, the root interface for COM/OLE objects).


> Seen some code example use the following pattern:
>
> pDataSource->DoDragDrop ();
> if ( pDataSource->m_dwRef <= 1)
> delete pDataSource;
> else
> pDataSource->ExternalRelease();

I would just call ->ExternalRelease (or InternalRelease, if there is no
aggregation).

I think that the difference between External and Internal is about
aggregation: External methods like ExternalRelease are to properly manage
aggregation.

pDataSource->DoDragDrop();
pDataSource->ExternalRelease();
// or
// pDataSource->InternalRelease();
// if there's no aggregation

I believe that Internal/ExternalRelease will decrement the reference count,
and call C++ 'delete' if reference count is 0.

However, I'm not sure about that, and I would prefer experimenting with some
real code, also considering that you are mixing MFC and managed world of
..NET here... (I think that computer science is an "experimental" science :)
we need compilers, debuggers, log files, etc. to diagnose things and try to
find solutions to bug.)

BTW: I would also post this question in the ATL group.
There is a COM very expert there whose name is Igor (T.): he knows a lot
about COM and OLE and I believe he will give you a detailed answer...

Giovanni


From: Giovanni Dicanio on

"Giovanni Dicanio" <giovanni.dicanio(a)invalid.com> ha scritto nel messaggio
news:ebcrVFDsIHA.1236(a)TK2MSFTNGP02.phx.gbl...

> I would just call ->ExternalRelease (or InternalRelease, if there is no
> aggregation).
>
> I think that the difference between External and Internal is about
> aggregation: External methods like ExternalRelease are to properly manage
> aggregation.
>
> pDataSource->DoDragDrop();
> pDataSource->ExternalRelease();
> // or
> // pDataSource->InternalRelease();
> // if there's no aggregation
>
> I believe that Internal/ExternalRelease will decrement the reference
> count, and call C++ 'delete' if reference count is 0.


I stepped into source code of CCmdTarget::ExternalRelease, and it calls
InternalRelease, which in turns calls OnFinalRelease virtual method if
reference count reaches value of 0.
OnFinalRelease does a 'delete this' as last statement.

Giovanni


From: RedLars on
On 7 Mai, 12:57, "Giovanni Dicanio" <giovanni.dica...(a)invalid.com>
wrote:
> "RedLars" <Liverpool1...(a)gmail.com> ha scritto nel messaggionews:4463e7a9-21aa-4fec-af81-3d666dfae6ae(a)c65g2000hsa.googlegroups.com...
>
> > COleDataSource * pDataSource = new COleDataSource;
> > // fill-in code
> > pDataSource->CacheGlobalData(...);
> > pDataSource->DoDragDrop ();
>
> > This code works! The correct data is transferred to the destination!
> > The problem now is cleaning up.
>
> > Adding a delete pDataSource causes an access violation in destination
> > code.
>
> > What I've noticed is that pDataSource->m_dwRef is increment to 1 on
> > creation and increased to 3 if OnDragEnter\OnDragDrop or OnDragEnter
> > \OnDragLeave occurs in destination code.
>
> Those OLE objects are reference counted, so I would not call 'delete' on
> them...
> I would "respect" their contract of AddRef/Release (these are methods
> present in IUknown, the root interface for COM/OLE objects).
>
> > Seen some code example use the following pattern:
>
> > pDataSource->DoDragDrop ();
> > if ( pDataSource->m_dwRef <= 1)
> > delete pDataSource;
> > else
> > pDataSource->ExternalRelease();
>
> I would just call ->ExternalRelease (or InternalRelease, if there is no
> aggregation).


So you are saying this would be a good solution:

if ( pDataSource->m_dwRef <= 1)
pDataSource->InternalRelease();
else
pDataSource->ExternalRelease();



> I think that the difference between External and Internal is about
> aggregation: External methods like ExternalRelease are to properly manage
> aggregation.
>
> pDataSource->DoDragDrop();
> pDataSource->ExternalRelease();
> // or
> // pDataSource->InternalRelease();
> // if there's no aggregation
>
> I believe that Internal/ExternalRelease will decrement the reference count,
> and call C++ 'delete' if reference count is 0.
>
> However, I'm not sure about that, and I would prefer experimenting with some
> real code, also considering that you are mixing MFC and managed world of
> .NET here... (I think that computer science is an "experimental" science :)
> we need compilers, debuggers, log files, etc. to diagnose things and try to
> find solutions to bug.)
>

Will continue to experiment.


> BTW: I would also post this question in the ATL group.
> There is a COM very expert there whose name is Igor (T.): he knows a lot
> about COM and OLE and I believe he will give you a detailed answer...
>
> Giovanni

Will post it there aswell.

Thanks for your help.
From: Giovanni Dicanio on

"RedLars" <Liverpool1892(a)gmail.com> ha scritto nel messaggio
news:b55f0e7b-abc4-4f7b-8ab8-692b95059a0e(a)p25g2000hsf.googlegroups.com...
> So you are saying this would be a good solution:
>
> if ( pDataSource->m_dwRef <= 1)
> pDataSource->InternalRelease();
> else
> pDataSource->ExternalRelease();

No, I would just do:

pDataSource->InternalRelease();

(or pDataSource->ExternalRelease() if you are using aggregation.)

Internal/ExternalRelease will do 'delete this' if reference count is 0.

Giovanni