Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

efficient drag and drop of multiple items

10 views
Skip to first unread message

Marcel Müller

unread,
Sep 25, 2012, 2:46:14 PM9/25/12
to
Hi,

I have a custom drag and drop render method inside an application. If I
drag multiple items each item is rendered independently. The question is
how to pass the content physically. DDE is out because it is a lot of
work and AFAIK it causes even more memory leakage on OS/2 than simple
drag and drop. Passing only strings in the DRAGITEM structure is not
sufficient.

So I would prefer a temporary file or a custom shared memory object. In
either case the native representation of the application passes all
objects in one file or one memory location rather than rendering them
one by one. But the question is how to keep the DRM API happy? The
protocol relies on each item to be passed one by one. Any ideas?


Marcel

Lars Erdmann

unread,
Oct 17, 2012, 2:04:03 AM10/17/12
to
Are you talking about source rendering ?

I don't know what you mean by "one by one".
The source location information is just a reference, per default it
references a file location.
There is one "descriptor" per object to be dragged and dropped but multiple
of these go into the same structure.

On the other hand you can come up with a shared memory solution to move
around the real data.
Then, each "descriptor" could point to a different offset in that shared
memory.
The problem is that you have to come up with some sort of tracking when the
DnD is accomplished for all objects.
Then you can free the whole shared memory block.

For source rendering I remember there is this "ulTargetInfo" field in the
DRAGTRANSFER structure that will allow you to pass
additional information with each dragged object. This could be a pointer to
shared memory containing additional info, for example the overall number of
objects, the original object index, the base pointer to the shared memory
block described above.
You would encode the offset into the shared memory block into the
"hstrRenderToName" field. At least EPM does this for the "SharedMemory" RMF
that it offers (in addition to the standard RMF method).

Maybe you can provide a simplified code sample of what you have so far. From
what I understand I definitely think you should go for source rendering.

I could provide you with some DnD code that I had written so support DnD in
VAC's source code editor LXPM where I am using both methods (target
rendering as well as source rendering) in order to support the WPS as well
as DnD of marked text from EPM (where I am using the "file" RMF for matter
of simplicity). There are issues in properly freeing the DnD resources, the
PM REF description is a mess ...


Lars



"Marcel Müller" <news.5...@spamgourmet.org> schrieb im Newsbeitrag
news:5061fbf6$0$6580$9b4e...@newsspool3.arcor-online.net...

Marcel Müller

unread,
Oct 17, 2012, 3:14:53 AM10/17/12
to
On 17.10.2012 08:04, Lars Erdmann wrote:
> Are you talking about source rendering ?

Yes.

> I don't know what you mean by "one by one".

If I drag 50 items, AFAIK I receive 50 DRM_RENDER messages. If each of
them creates a temporary file, this might not be a good advise. Strictly
speaking I do not need this 50 messages at all.


> On the other hand you can come up with a shared memory solution to move
> around the real data.

Hmm, this is not documented in the IBM docs, although DDE is close to it.
But of course, I could do so.

> Then, each "descriptor" could point to a different offset in that shared
> memory.
> The problem is that you have to come up with some sort of tracking when
> the DnD is accomplished for all objects.
> Then you can free the whole shared memory block.

DRM_ENDCONVERSATION should do the job.


> For source rendering I remember there is this "ulTargetInfo" field in
> the DRAGTRANSFER structure that will allow you to pass
> additional information with each dragged object.

I did not notice this field so far.

> This could be a pointer
> to shared memory containing additional info, for example the overall
> number of objects, the original object index, the base pointer to the
> shared memory block described above.
> You would encode the offset into the shared memory block into the
> "hstrRenderToName" field.

I did some hack like this firstly when I passed serialized Information
in this field. But the string tend to get longer and longer and I think
it is not intended to keep long strings. I would not bet that strings
with more than usual path lengths work properly.

> Maybe you can provide a simplified code sample of what you have so far.
> From what I understand I definitely think you should go for source
> rendering.

Yes, this is the only clean solution.
Currently I do rendering on the target site. In fact I pass a serialized
reference to the source in the drag structure and the target tries to
decode the original source. While this works perfectly inside one
application instance (because of the object cache), it fails badly if
two processes are involved and the source has unsaved modifications.

> There are issues in properly freeing the DnD
> resources, the PM REF description is a mess ...

Oh, well, dark side. I know almost no PM application that does not leak
memory under certain circumstances. This includes PMShell (with XWP) and
is one reason why I have to reboot from time to time.

Thanks for now. The idea with one shared memory object sounds reasonable.


Marcel

A.D. Fundum

unread,
Oct 17, 2012, 9:38:13 AM10/17/12
to
> Strictly speaking I do not need this 50 messages at all.

So is there a possibility to d&d one object, i.e. some alias or
message which represents those 50 items?

A silly example could be that a dropped "C:\BACKUP\C.BCK" will be
interpreted as "C:\BACKUP\*.BCK".

> I know almost no PM application that does not leak memory
> under certain circumstances. This includes PMShell (with
> XWP) and is one reason why I have to reboot

FTR, a WPS reset may solve this reason.


--

Lars Erdmann

unread,
Oct 18, 2012, 1:47:03 AM10/18/12
to
Hallo,

"Marcel Müller" <news.5...@spamgourmet.com> schrieb im Newsbeitrag
news:507e5aed$0$6547$9b4e...@newsspool4.arcor-online.net...

>> On the other hand you can come up with a shared memory solution to move
>> around the real data.
>
> Hmm, this is not documented in the IBM docs, although DDE is close to it.
> But of course, I could do so.

The shared memory solution has nothing to do with DDE. You don't need to
worry about any DDE protocol issues.

>> Then, each "descriptor" could point to a different offset in that shared
>> memory.
>> The problem is that you have to come up with some sort of tracking when
>> the DnD is accomplished for all objects.
>> Then you can free the whole shared memory block.
>
> DRM_ENDCONVERSATION should do the job.

Yes, but it needs to be called by the target for EACH drag object.
Therefore you need more info of what is the LAST drag object to handle.
Only after the last drag object may you free the shared memory block.

>> This could be a pointer
>> to shared memory containing additional info, for example the overall
>> number of objects, the original object index, the base pointer to the
>> shared memory block described above.
>> You would encode the offset into the shared memory block into the
>> "hstrRenderToName" field.
>
> I did some hack like this firstly when I passed serialized Information in
> this field. But the string tend to get longer and longer and I think it is
> not intended to keep long strings. I would not bet that strings with more
> than usual path lengths work properly.

I think you misunderstood me. "hstrRenderToName" is just a 4 byte location.
You may place a pointer to shared memory into this field and I seem to
remember this is what EPM does if you ask it to source render with the
"shared memory" RMF.
After all source rendering is a mechanism where both the source and target
need to have a common "understanding" of how they have to interpret the DnD
information.

> Yes, this is the only clean solution.
> Currently I do rendering on the target site. In fact I pass a serialized
> reference to the source in the drag structure and the target tries to
> decode the original source. While this works perfectly inside one
> application instance (because of the object cache), it fails badly if two
> processes are involved and the source has unsaved modifications.

Oops, this is more involved. This indeed seems to ask for DDE exchange.
If you want automated updates at the target if the source changes some
information then DDE is the thing to use.
Unless you want to hand-code a solution yourself ...

>> There are issues in properly freeing the DnD
>> resources, the PM REF description is a mess ...
>
> Oh, well, dark side. I know almost no PM application that does not leak
> memory under certain circumstances. This includes PMShell (with XWP) and
> is one reason why I have to reboot from time to time.

That's why I offered the code sample. It is based on what Rich Walsh found
about the topic.
It's not all that easy given the insufficient PM documentation. Especially
for source rendering ...

Lars

Marcel Müller

unread,
Oct 22, 2012, 4:20:49 PM10/22/12
to
On 18.10.12 07.47, Lars Erdmann wrote:
> The shared memory solution has nothing to do with DDE. You don't need to
> worry about any DDE protocol issues.

Yes, of course.
Unfortunately it turned out, that the existing application code that
serializes objects cannot deal with memory streams. It only supports
real file handles. So I decided to use a temporary file, although it is
less efficient. It simply is less of work.

>>> The problem is that you have to come up with some sort of tracking when
>>> the DnD is accomplished for all objects.
>>> Then you can free the whole shared memory block.
>>
>> DRM_ENDCONVERSATION should do the job.
>
> Yes, but it needs to be called by the target for EACH drag object.

You are right. But I didn't see the wood for the trees. It seems that I
can pass a group of objects in /one/ DRAGITEM structure while still
showing several icons. So there is only one object to clean up at
exactly one DRM_ENDCONVERSATION.


>> I did some hack like this firstly when I passed serialized Information
>> in this field. But the string tend to get longer and longer and I
>> think it is not intended to keep long strings. I would not bet that
>> strings with more than usual path lengths work properly.
>
> I think you misunderstood me. "hstrRenderToName" is just a 4 byte location.
> You may place a pointer to shared memory into this field and I seem to
> remember this is what EPM does if you ask it to source render with the
> "shared memory" RMF.

You say that there is no need that it has to be a string handle at all?

> After all source rendering is a mechanism where both the source and
> target need to have a common "understanding" of how they have to
> interpret the DnD information.

No problem in my case.


>> Yes, this is the only clean solution.
>> Currently I do rendering on the target site. In fact I pass a
>> serialized reference to the source in the drag structure and the
>> target tries to decode the original source. While this works perfectly
>> inside one application instance (because of the object cache), it
>> fails badly if two processes are involved and the source has unsaved
>> modifications.
>
> Oops, this is more involved. This indeed seems to ask for DDE exchange.
> If you want automated updates at the target if the source changes some
> information then DDE is the thing to use.

Fortunately it is not that hard. Once the DnD completed there is no need
for further synchronization. It may only happen that unsaved objects are
dragged to another application instance. And since they only exist in
the source's private memory I must use source rendering.

> Unless you want to hand-code a solution yourself ...

Oh, well, as far as I remember my experiences with DDE about 15 years
ago, a proprietary solution might be still less work.


>>> There are issues in properly freeing the DnD
>>> resources, the PM REF description is a mess ...
>>
> That's why I offered the code sample. It is based on what Rich Walsh
> found about the topic.

I see. Currently I use some article at ARTofOS2.


Marcel

Lars Erdmann

unread,
Oct 24, 2012, 2:24:39 PM10/24/12
to
Hallo Marcel,

----- Original Message ----- >
>>>> The problem is that you have to come up with some sort of tracking when
>>>> the DnD is accomplished for all objects.
>>>> Then you can free the whole shared memory block.
>>>
>>> DRM_ENDCONVERSATION should do the job.
>>
>> Yes, but it needs to be called by the target for EACH drag object.
>
> You are right. But I didn't see the wood for the trees. It seems that I
> can pass a group of objects in /one/ DRAGITEM structure while still
> showing several icons. So there is only one object to clean up at exactly
> one DRM_ENDCONVERSATION.

No, at least it's not the original intention of the DnD designer.
Principally:
1) the DRAGINFO structure describes the Drag as such, including one or more
drag items
2) the DRAGITEM structure describes one item being part of the drag
3) the DRAGIMAGE structure describes one picture of possible multiple
pictures which are cascaded on top of each other. It's only a visual
representation of the drag and nothing else. You can have an arbitrary
number of pictures associated with a drag. You could have only one picture
even if you drag several items, you could have a picture per drag item or
any other number. OS/2 will do its best to properly cascade (and even limit
the number of ?) pictures to get a good visual representation.
4) the DRAGTRANSFER structures describes one item being part of the drag
much like 2) but for the needs of source rendering

Of course you can "misuse" this mechanism and only use one DRAGITEM
structure and somehow implement your own "private protocol" to jam multiple
items into just one DRAGITEM structure.

>> I think you misunderstood me. "hstrRenderToName" is just a 4 byte
>> location.
>> You may place a pointer to shared memory into this field and I seem to
>> remember this is what EPM does if you ask it to source render with the
>> "shared memory" RMF.
>
> You say that there is no need that it has to be a string handle at all?

Yes, exactly. There is no need to use DrgAddStrHandle. I guess what
DrgAddStrHandle really does is allocate shared memory/reserve some room in
the shared DnD exchange structure, copy the string from private memory to
that shared memory and return a pointer or handle to this shared memory
location so that it can be found by DrgQueryStrName.
The only thing you have to make sure is that if you pass a memory address in
hstrRenderToName or any other hstr for direct use by your source application
then you better make sure it points to SHARED memory and that you either use
the "give" or the "get" mechanism to allow the source application to
actually access this shared memory.
Thinking about it: you don't need source rendering to do that. You could
also use target rendering and specify a RMF for the target to understand.

> Fortunately it is not that hard. Once the DnD completed there is no need
> for further synchronization. It may only happen that unsaved objects are
> dragged to another application instance. And since they only exist in the
> source's private memory I must use source rendering.

See above. If you want to pass something in memory it needs to be in SHARED
memory.

>>>> There are issues in properly freeing the DnD
>>>> resources, the PM REF description is a mess ...
>>>
>> That's why I offered the code sample. It is based on what Rich Walsh
>> found about the topic.
>
> I see. Currently I use some article at ARTofOS2.

Unfortunately this doc might also be wrong at least concerning source
rendering. What I remember from the top of my head:
1) DrgAllocDragInfo and DrgFreeDragInfo must be called as a pair by the
source.
2) DrgAccessDragInfo and DrgFreeDragInfo must be called as a pair by the
target for DM_DRAGOVER and also DM_DROPHELP. For DM_DROP you only call
DrgAccessDragInfo (unless you want to abort in case of error in which case
you also have to call DrgFreeDragInfo). The source will then eventually call
DrgFreeDragInfo. For DM_RENDERCOMPLETE you only call DrgFreeDragInfo.
DrgFreeDragInfo is particularly problematic on source rendering: as said, it
needs to be freed on a DM_RENDERCOMPLETE and only once the last drag item is
processed. But there is no good field to store the drginfo pointer and the
DrgDrgInfoFrom... routines DO NOT work for this purpose (they only work for
lazy drag). The solution was to use "ulTargetInfo" field to jam in the
pointer.
3) DrgAllocDragTransfer and DrgFreeDragTransfer must be called as a pair by
the target
4) I would need to check of how to handle DrgAddStrHandle /
DrgDeleteStrHandle / DrgDeleteDraginfoStrHandles and where to free them
(maybe even at source AND target). And then DrgDeleteDraginfoStrHandles has
a flaw in that it aborts when it finds an invalid handle (and therefore will
not free all handles) and therefore you should implement a replacement
routine.
There must be some complicated reference counting for the source and target
buried in the DnD engine.
Rich had explored deeply into this mess when he added/extended DnD support
to/for Mozilla. I trust him more than any documentation ...


Lars

Marcel Müller

unread,
Nov 1, 2012, 5:48:13 PM11/1/12
to
On 24.10.12 20.24, Lars Erdmann wrote:
>> You are right. But I didn't see the wood for the trees. It seems that
>> I can pass a group of objects in /one/ DRAGITEM structure while still
>> showing several icons. So there is only one object to clean up at
>> exactly one DRM_ENDCONVERSATION.
>
> No, at least it's not the original intention of the DnD designer.
> Principally:
> 1) the DRAGINFO structure describes the Drag as such, including one or
> more drag items
> 2) the DRAGITEM structure describes one item being part of the drag
> 3) the DRAGIMAGE structure describes one picture of possible multiple
> pictures which are cascaded on top of each other. It's only a visual
> representation of the drag and nothing else. You can have an arbitrary
> number of pictures associated with a drag. You could have only one
> picture even if you drag several items, you could have a picture per
> drag item or any other number. OS/2 will do its best to properly cascade
> (and even limit the number of ?) pictures to get a good visual
> representation.
> 4) the DRAGTRANSFER structures describes one item being part of the drag
> much like 2) but for the needs of source rendering
>
> Of course you can "misuse" this mechanism and only use one DRAGITEM
> structure and somehow implement your own "private protocol" to jam
> multiple items into just one DRAGITEM structure.

Exactly - I won't tell anybody else, I promise. :-)

I implemented it that way now. I just did not have time to test it so
far, but I am positive that it will prove.


> Yes, exactly. There is no need to use DrgAddStrHandle. I guess what
> DrgAddStrHandle really does is allocate shared memory/reserve some room
> in the shared DnD exchange structure, copy the string from private
> memory to that shared memory and return a pointer or handle to this
> shared memory location so that it can be found by DrgQueryStrName.
> The only thing you have to make sure is that if you pass a memory
> address in hstrRenderToName or any other hstr for direct use by your
> source application then you better make sure it points to SHARED memory
> and that you either use the "give" or the "get" mechanism to allow the
> source application to actually access this shared memory.
> Thinking about it: you don't need source rendering to do that. You could
> also use target rendering and specify a RMF for the target to understand.

Unfortunately it is not that easy. The internal data structures are
object oriented and are not located in a linear memory location. So the
source needs to compact this in one shared memory or something else anyway.

>> Fortunately it is not that hard. Once the DnD completed there is no
>> need for further synchronization. It may only happen that unsaved
>> objects are dragged to another application instance. And since they
>> only exist in the source's private memory I must use source rendering.
>
> See above. If you want to pass something in memory it needs to be in
> SHARED memory.

Yes, but there are dozens of objects related to a single dropped item.
All of them need to be in shared memory. Furthermore the layout of the
internal data structures may change with program version, the used
compiler and compiler options. So a documented serialized format is more
reliable.


>>> That's why I offered the code sample. It is based on what Rich Walsh
>>> found about the topic.

Maybe I should refer to your offer.
While I think I have a clean solution for the string handles (I reset
the handles to NULLHANDLE when I call DrgDeleteStrHandle and the handles
are always deleted by the application that allocated them.) the handling
of the DRAGTRANSFER structures seems to be not that easy. They are
allocated in one array, but they arrive one by one at DM_RENDERCOMPLETE
and only if the last one arrived I am able to return the buffer and I
need the first pointer for this purpose. No problem with my own
rendering mechanism because of the above hack with only one DRAGITEM,
but when dropping URL objects, it might be good to know.


>> I see. Currently I use some article at ARTofOS2.
>
> Unfortunately this doc might also be wrong at least concerning source
> rendering. What I remember from the top of my head:
> 1) DrgAllocDragInfo and DrgFreeDragInfo must be called as a pair by the
> source.
> 2) DrgAccessDragInfo and DrgFreeDragInfo must be called as a pair by the
> target for DM_DRAGOVER and also DM_DROPHELP.

Done. A smart pointer does the job for me in both cases.

> For DM_RENDERCOMPLETE you only call DrgFreeDragInfo.

Yes, it seems that since in this case the give mechanism is used.

> DrgFreeDragInfo is particularly problematic on source rendering: as
> said, it needs to be freed on a DM_RENDERCOMPLETE and only once the last
> drag item is processed.

? - There is one DRAGINFO for each dragged item, isn't it?
Are you talking about DrgFreeDragTransfer?

> But there is no good field to store the drginfo
> pointer and the DrgDrgInfoFrom... routines DO NOT work for this purpose
> (they only work for lazy drag). The solution was to use "ulTargetInfo"
> field to jam in the pointer.

I like the one DRAGITEM hack more and more.


> 3) DrgAllocDragTransfer and DrgFreeDragTransfer must be called as a pair
> by the target

But also at DM_RENDERCOMPLETE, because I cannot rely on the source to
call DM_RENDERCOMPLETE syncronuously from the DM_RENDER message. In fact
I call it asynchronously to keep the ball in play. I/O in a SIQ thread
is evil.

> 4) I would need to check of how to handle DrgAddStrHandle /
> DrgDeleteStrHandle / DrgDeleteDraginfoStrHandles and where to free them
> (maybe even at source AND target). And then DrgDeleteDraginfoStrHandles
> has a flaw in that it aborts when it finds an invalid handle (and
> therefore will not free all handles) and therefore you should implement
> a replacement routine.

Done.

> There must be some complicated reference counting for the source and
> target buried in the DnD engine.

Well, complicated - no necessarily, but undocumented.

> Rich had explored deeply into this mess when he added/extended DnD
> support to/for Mozilla. I trust him more than any documentation ...

Probably rightly.


Marcel

Lars Erdmann

unread,
Nov 2, 2012, 4:49:09 PM11/2/12
to
>
>> DrgFreeDragInfo is particularly problematic on source rendering: as
>> said, it needs to be freed on a DM_RENDERCOMPLETE and only once the last
>> drag item is processed.
>
> ? - There is one DRAGINFO for each dragged item, isn't it?
> Are you talking about DrgFreeDragTransfer?

No. There is exactly 1 DRAGINFO structure for the complete drag as such.
There is a DRAGITEM structure for each dragged item.


Marcel Müller

unread,
Nov 2, 2012, 5:16:53 PM11/2/12
to


On 02.11.2012 21:49, Lars Erdmann wrote:
>> ? - There is one DRAGINFO for each dragged item, isn't it?
>> Are you talking about DrgFreeDragTransfer?
>
> No. There is exactly 1 DRAGINFO structure for the complete drag as such.
> There is a DRAGITEM structure for each dragged item.

You are right. I confused something. I free the DRAGINFO from the source
and not at DM_RENDERCOMPLETE.


Marcel
0 new messages