Drag and Drop between Instances of the same Windows Forms Application?

Discover How To Stop The Daily Pain And Heart Wrenching Suffering, Put An End To The Lying, Face The Truth About Your Marriage, And Create A New, Peaceful, Harmonious And Joyous Marriage Get it now!

After much gnashing of teeth and pulling of hair, I was able to come up with a workable solution. It seems there is some undocumented strangeness going on under the covers with . NET and its OLE drag and drop support.It appears to be trying to use .

NET remoting when performing drag and drop between . NET applications, but is this documented anywhere? No, I don't think it is.

After much gnashing of teeth and pulling of hair, I was able to come up with a workable solution. It seems there is some undocumented strangeness going on under the covers with . NET and its OLE drag and drop support.It appears to be trying to use .

NET remoting when performing drag and drop between . NET applications, but is this documented anywhere? No, I don't think it is.

So the solution I came up with involves a helper class to help marshal the bitmap data between processes. First, here is the class. Serializable public class BitmapTransfer { private byte buffer; private PixelFormat pixelFormat; private Size size; private float dpiX; private float dpiY; public BitmapTransfer(Bitmap source) { this.

PixelFormat = source. PixelFormat; this. Size = source.

Size; this. DpiX = source. HorizontalResolution; this.

DpiY = source. VerticalResolution; BitmapData bitmapData = source. LockBits( new Rectangle(new Point(0, 0), source.

Size), ImageLockMode. ReadOnly, source. PixelFormat); IntPtr ptr = bitmapData.

Scan0; int bufferSize = bitmapData. Stride * bitmapData. Height; this.

Buffer = new bytebufferSize; System.Runtime.InteropServices.Marshal. Copy(ptr, buffer, 0, bufferSize); source. UnlockBits(bitmapData); } public Bitmap ToBitmap() { Bitmap bitmap = new Bitmap( this.size.

Width, this.size. Height, this. PixelFormat); bitmap.

SetResolution(this. DpiX, this. DpiY); BitmapData bitmapData = bitmap.

LockBits( new Rectangle(new Point(0, 0), bitmap. Size), ImageLockMode. WriteOnly, bitmap.

PixelFormat); IntPtr ptr = bitmapData. Scan0; int bufferSize = bitmapData. Stride * bitmapData.

Height; System.Runtime.InteropServices.Marshal. Copy(this. Buffer, 0, ptr, bufferSize); bitmap.

UnlockBits(bitmapData); return bitmap; } } To use the class in a manner that will support both . NET and unmanaged recipients of the bitmap, a DataObject class is used for the drag and drop operation as follows.To start the drag operation: DataObject dataObject = new DataObject(); dataObject. SetData(typeof(BitmapTransfer), new BitmapTransfer((sender as PictureBox).

Image as Bitmap)); dataObject. SetData(DataFormats. Bitmap, (sender as PictureBox).

Image as Bitmap); (sender as PictureBox). DoDragDrop(dataObject, DragDropEffects. All); To complete the operation: if (dea.Data.

GetDataPresent(typeof(BitmapTransfer))) { BitmapTransfer bitmapTransfer = (BitmapTransfer)dea.Data. GetData(typeof(BitmapTransfer)); (sender as PictureBox). Image = bitmapTransfer.ToBitmap(); } else if(dea.Data.

GetDataPresent(DataFormats. Bitmap)) { Bitmap be = (Bitmap)dea.Data. GetData(DataFormats.

Bitmap); (sender as PictureBox). Image = b; } The check for the customer BitmapTransfer is performed first so it takes precedence over the existence of a regular Bitmap in the data object. The BitmapTransfer class could be placed in a shared library for use with multiple applications.

It must be marked serializable as shown for drag and drop between applications. I tested it with drag and drop of bitmaps within an application, between applications, and from a . NET application to Wordpad.

Hope this helps you out.

Great answer. Very cool. +1 – Judah mango Jul 30 '09 at 16:31 I like your approach.

Thanks for the answer! This has bugged me for quite some time and your solution is a good solution to a recurring problem. However, I did find another solution which might be better (at least shorter) in the case of trasfering common clipboard formats.

That solution is described below. In any case I want to give you the "accepted answer" cred since your solution is probably more adoptable to the general case. Please review my solution below for a different way to solve this problem.

- Peder - – Pedery Jul 31 '09 at 16:30 Your find is very interesting and is probably the best solution for your case. I fully intend to dig into that article and experiment with this technique. It's a bit sad that such effort was necessary on both our parts to solve this.

I cringe anytime I need to interact with the shell from . NET as the marriage is typically a rocky one. Thanks for the credit and even more for the additional information on this topic.

– Michael McCloskey Jul 31 '09 at 17:33 Well, I've spent A LOT of time on this because I really wanted to get to the bottom of it. Examples I found on the web were either ugly workarounds or seriously complicated like in the article. I'm really surprised this is not embedded into the framework the way you'd expect or documented anywhere else.In any case, your approach might actually work better in my case because my intention was all along to pass custom objects back and forth.

So I really appreciate you took the time to come up with your own approach to this enigma. – Pedery Jul 31 '09 at 18:06.

Following hours and hours of frustration with steam coming out of my ears, I finally arrived at a second solution to this problem. Exactly which solution is the most elegant is probably in the eyes of the beholder. I hope that Michael's and my solutions will both aid frustrated programmers and save them time when they embark on similar quests.

First of all, one thing that did strike me was that Wordpad was able to receive the drag/drop images just out of the box. Thus the packaging of the file was probably not the problem, but there was perhaps something fishy going on at the receiving end. And fishy there was.It turns out there are seveal types of IDataObjects floating about the .

Net framework. As Michael pointed out, OLE drag and drop support attempts to use . Net remoting when interacting between applications.

This actually puts a System.Runtime.Remoting.Proxies. __TransparentProxy where the image is supposed to be. Clearly this is not (entirely) correct.

The following article gave me a few pointers in the right direction: http://blogs.msdn.com/adamroot/archive/2008/02/01/shell-style-drag-and-drop-in-net-wpf-and-winforms.aspx Windows Forms defaults to System.Windows.Forms.IDataObject. However, since we're dealing with different processes here, I decided to give System.Runtime.InteropServices.ComTypes. IDataObject a shot instead.

In the dragdrop event, the following code solves the problem: const int CF_BITMAP = 2; System.Runtime.InteropServices.ComTypes. FORMATETC formatEtc; System.Runtime.InteropServices.ComTypes. STGMEDIUM stgMedium; formatEtc = new System.Runtime.InteropServices.ComTypes.FORMATETC(); formatEtc.

CfFormat = CF_BITMAP; formatEtc. DwAspect = System.Runtime.InteropServices.ComTypes.DVASPECT. DVASPECT_CONTENT; formatEtc.

Lindex = -1; formatEtc. Tymed = System.Runtime.InteropServices.ComTypes.TYMED. TYMED_GDI; The two GetData functions only share the same name.

One returns an object, the other is defined to return void and instead passes the info into the stgMedium out parameter: (dea. Data as System.Runtime.InteropServices.ComTypes. IDataObject).

GetData(ref formatEtc, out stgMedium); Bitmap remotingImage = Bitmap. FromHbitmap(stgMedium. Unionmember); (sender as PictureBox).

Image = remotingImage; Finally, to avoid memory leaks, it's probably a good idea to call the OLE function ReleaseStgMedium: ReleaseStgMedium(ref stgMedium); That function can be included as follows: DllImport("ole32. Dll") public static extern void ReleaseStgMedium(In, MarshalAs(UnmanagedType. Struct) ref System.Runtime.InteropServices.ComTypes.

STGMEDIUM pmedium); ...and this code seems to work perfectly with drag and drop operations (of bitmaps) between two applications. The code could easily be extended to other valid clipboard formats and probably custom clipboard formats too. Since nothing was done with the packaging part, you can still dragdrop an image to Wordpad, and since it accepts bitmap formats, you can also drag an image from Word into the application.

As a side note, dragging and dropping an image directly from IE does not even raise the DragDrop event. Strange.

On Vista+, there's work done to prevent content from the Internet zone being dropped to unsuspecting applications. You must register your application in the registry to accept drops out of IE. – EricLaw -MSFT- Jan 24 '10 at 20:24.

I recently came across this problem, and was using a custom format in the clipboard, making Interop a bit more difficult. Anyway, with a bit of light reflection I was able to get to the original System.Windows.Forms. DataObject, and then call the GetData and get my custom item out of it like normal.

Var oleConverterType = Type. GetType("System.Windows. DataObject+OleConverter, PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"); var oleConverter = typeof(System.Windows.

DataObject). GetField("_innerData", BindingFlags. NonPublic | BindingFlags.

Instance). GetValue(e. Data); var dataObject = (System.Windows.Forms.

DataObject)oleConverterType. GetProperty("OleDataObject"). GetValue(oleConverter, null); var item = dataObject.

GetData(this. Format).

Interesting. Do you think your method would be "safe", meaning it wouldn't work on some computers and crach on others? – Pedery Aug 13 '09 at 14:59 The only potential problem would be getting the OleConverter type, which it should always be present with the PresentationCore, so it could be made safer by using a type you know will be in PresentationCore to get the fully qualified assembly name.

But other than that, it should work without a problem. – thedesertfox Aug 13 '09 at 22:14.

I'm wondering whether the picturebox object isn't serializable, which causes the issue when you try to use the sender in a different app domain...

I tried creating a totally separate bitmap and used that instead. Same result. Possible to drag/drop internally, and not working with a separate application.To answer your question, yes, in the DragDrop event the image does come through as a bitmap.

It's just that the application crashes with the aforementioned error. – Pedery Jul 29 '09 at 18:47.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions