Перетаскивание между Экземплярами того же Приложения Windows Forms

Один глюк - то, что следующее является зависящим от реализации (согласно стандарту ANSI):

char x = -1;
x >> 1;

x может теперь быть 127 (01111111) или все еще-1 (11111111).

На практике, это обычно - последний.

16
задан John Saunders 29 July 2009 в 17:26
поделиться

4 ответа

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 byte[bufferSize];
        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 b = (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.

10
ответ дан 30 November 2019 в 21:46
поделиться

Просто из любопытства в методе DragDrop вы пробовали проверить, можете ли вы вообще получить растровое изображение из DragEventArgs? Без заброса отправителя? Мне интересно, не сериализуем ли объект Picturebox, что вызывает проблему, когда вы пытаетесь использовать отправителя в другом домене приложения ...

1
ответ дан 30 November 2019 в 21:46
поделиться

После нескольких часов разочарования из-за того, что из ушей выходит пар, я наконец-то пришел ко второму решению этой проблемы. Какое именно решение является наиболее элегантным, вероятно, в глазах смотрящего. Я надеюсь, что и решения Майкла, и мои решения помогут разочаровавшимся программистам и сэкономят им время, когда они приступят к аналогичным поискам.

Прежде всего, меня поразило то, что Wordpad мог получать изображения с перетаскиванием. коробки. Таким образом, упаковка файла, вероятно, не была проблемой, но, возможно, на принимающей стороне происходило что-то подозрительное.

И подозрительное было. Оказывается, существует несколько типов объектов IDataObject, плавающих в среде .Net. Как отметил Майкл, OLE пытается использовать поддержку перетаскивания. Чистое удаленное взаимодействие при взаимодействии между приложениями. Фактически это помещает System.Runtime.Remoting.Proxies .__ TransparentProxy туда, где должно быть изображение. Ясно, что это не (полностью) правильно.

Следующая статья дала мне несколько указателей в правильном направлении:

http://blogs.msdn.com/adamroot/archive/2008/02/01/shell- style-drag-and-drop-in-net-wpf-and-winforms.aspx

По умолчанию в Windows Forms используется System.Windows.Forms.IDataObject. Однако, поскольку здесь мы имеем дело с разными процессами, я решил дать System.Runtime.InteropServices.ComTypes.IDataObject шанс вместо этого.

В событии перетаскивания следующий код решает проблему:

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;

Два GetData функции имеют только одно и то же имя. Один возвращает объект, другой определен для возврата void и вместо этого передает информацию в параметр stgMedium out :

(dea.Data as System.Runtime.InteropServices.ComTypes.IDataObject).GetData(ref formatEtc, out stgMedium);
Bitmap remotingImage = Bitmap.FromHbitmap(stgMedium.unionmember);

(sender as PictureBox).Image = remotingImage;

Наконец, чтобы избежать утечки памяти, вероятно, неплохо было бы вызвать функцию OLE ReleaseStgMedium:

ReleaseStgMedium(ref stgMedium);

Эту функцию можно включить следующим образом:

[DllImport("ole32.dll")]
public static extern void ReleaseStgMedium([In, MarshalAs(UnmanagedType.Struct)] ref System.Runtime.InteropServices.ComTypes.STGMEDIUM pmedium);

... и этот код, кажется, отлично работает с перетаскиванием операции (растровых изображений) между двумя приложениями. Код может быть легко расширен на другие допустимые форматы буфера обмена и, возможно, также на пользовательские форматы буфера обмена. Поскольку с упаковочной частью ничего не было сделано, вы все равно можете перетащить изображение в Wordpad, а поскольку он принимает растровые форматы, вы также можете перетащить изображение из Word в приложение.

В качестве примечания: перетаскивание изображения непосредственно из IE даже не вызывает событие DragDrop. Странно.

[DllImport("ole32.dll")]
public static extern void ReleaseStgMedium([In, MarshalAs(UnmanagedType.Struct)] ref System.Runtime.InteropServices.ComTypes.STGMEDIUM pmedium);

... и этот код, кажется, отлично работает с операциями перетаскивания (растровых изображений) между двумя приложениями. Код может быть легко расширен на другие допустимые форматы буфера обмена и, возможно, также на пользовательские форматы буфера обмена. Поскольку с упаковочной частью ничего не было сделано, вы все равно можете перетащить изображение в Wordpad, а поскольку он принимает растровые форматы, вы также можете перетащить изображение из Word в приложение.

В качестве примечания: перетаскивание изображения непосредственно из IE даже не вызывает событие DragDrop. Странно.

[DllImport("ole32.dll")]
public static extern void ReleaseStgMedium([In, MarshalAs(UnmanagedType.Struct)] ref System.Runtime.InteropServices.ComTypes.STGMEDIUM pmedium);

... и этот код, кажется, отлично работает с операциями перетаскивания (растровых изображений) между двумя приложениями. Код может быть легко расширен на другие допустимые форматы буфера обмена и, возможно, также на пользовательские форматы буфера обмена. Поскольку с упаковочной частью ничего не было сделано, вы все равно можете перетащить изображение в Wordpad, а поскольку он принимает растровые форматы, вы также можете перетащить изображение из Word в приложение.

В качестве примечания: перетаскивание изображения непосредственно из IE даже не вызывает событие DragDrop. Странно.

и поскольку он принимает растровые форматы, вы также можете перетащить изображение из Word в приложение.

В качестве примечания, перетаскивание изображения непосредственно из IE даже не вызывает событие DragDrop. Странно.

и поскольку он принимает растровые форматы, вы также можете перетащить изображение из Word в приложение.

В качестве примечания, перетаскивание изображения непосредственно из IE даже не вызывает событие DragDrop. Странно.

6
ответ дан 30 November 2019 в 21:46
поделиться

Недавно я столкнулся с этой проблемой и использовал специальный формат в буфере обмена, что немного усложняло взаимодействие. В любом случае, с небольшим отражением света я смог добраться до исходного System.Windows.Forms.DataObject, а затем вызвать GetData и получить свой собственный элемент, как обычно.

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);
7
ответ дан 30 November 2019 в 21:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: