После нескольких часов разочарования от пара, выходящего из моих ушей, я, наконец, пришел ко второму решению этой проблемы. Точно, какое решение является самым изящным, вероятно, в глазах смотрящего. Я надеюсь, что решения Майкла и мои помогут и разочарованным программистам, и сэкономят им время, когда они приступят к подобным квестам.
Прежде всего, меня поразило то, что Wordpad мог получать изображения перетаскивания из коробки. Таким образом, упаковка файла, вероятно, не была проблемой, но, возможно, на приемном конце происходило что-то подозрительное.
И там была рыбка. Оказывается, есть несколько типов IDataObjects, плавающих в .Net Framework. Как отметил Майкл, поддержка OLE drag and drop пытается использовать .Net remoting при взаимодействии между приложениями. Это фактически помещает 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 шанс.
В событии dragdrop следующий код решает проблему:
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. Странно.