Как скопировать записываемый битмап в буфер обмена из приложения Silverlight с повышенным доверием с помощью P/Invoke?

У меня есть приложение Silverlight 5, в котором работает браузер с повышенным доверием. Это позволяет нам делать то, что обычно невозможно в Silverlight, например иметь больший доступ к буферу обмена через P/Invoke.

Что мне нужно сделать, так это скопировать элементы управления в буфер обмена, чтобы их можно было вставить в Word или Outlook. Я могу преобразовать элементы управления в изображение с помощью WriteableBitmap, но у меня проблемы с копированием данных в буфер обмена.

Код вызова:

  WriteableBitmap bmp = new WriteableBitmap(elements[0], new ScaleTransform() { ScaleX = 1.0, ScaleY = 1.0 });
  int[] p = bmp.Pixels;
  int len = p.Length * 4;
  byte[] result = new byte[len];
  Buffer.BlockCopy(p, 0, result, 0, len);

  CopyToClipboardViaPInvoke(result, ClipboardFormat.CF_BITMAP);

Функция копирования:

private void CopyToClipboardViaPInvoke(byte[] data, ClipboardFormat format)
{
    IntPtr p = IntPtr.Zero;
    if (Native.OpenClipboard(p))
    {
        GCHandle pinnedArray = GCHandle.Alloc(data, GCHandleType.Pinned);
        IntPtr pointer = pinnedArray.AddrOfPinnedObject();
        try
        {
            Native.EmptyClipboard();
            IntPtr result = Native.SetClipboardData(format, pointer);
        }
        finally
        {
            Native.CloseClipboard();
            pinnedArray.Free();
        }
    }
}

Результат говорит об успешном завершении, но вставка ничего не делает. IsClipboardFormatAvailable также указывает, что формат доступен в буфере обмена. Я также безуспешно пробовал различные входные данные ClipboardFormat и другие методы преобразования элемента управления в изображение.

Обновление 1

Благодаря предложениям пользователя 629926 у меня есть то, что я думаю, немного ближе, но я все еще что-то упускаю.

  Native.EmptyClipboard();
  IntPtr bmp = IntPtr.Zero;
  GCHandle pinnedArray = GCHandle.Alloc(bytes, GCHandleType.Pinned);
  IntPtr bmpPointer = pinnedArray.AddrOfPinnedObject();
  Native.StartupInput sin = new Native.StartupInput() { GdiplusVersion = 1 };
  Native.StartupOutput sout = new Native.StartupOutput();
  IntPtr gdip = IntPtr.Zero;

  int startup = Native.GdiplusStartup(out gdip, ref sin, out sout);
  int created = Native.GdipCreateBitmapFromScan0(width, height, width * 4, 0x0026200A, bmpPointer, out bmp);
  IntPtr result = Native.SetClipboardData(format, bmp);

  Native.DeleteObject(bmp);
  Native.GdiplusShutdown(ref gdip);

person McAden    schedule 26.06.2012    source источник
comment
Не уверен, но вы отправляете необработанные данные пикселей в буфер обмена, но другая сторона не может интерпретировать их без заголовка растрового изображения. Попробуйте преобразовать его в Bitmap и передать bitmap.GetHBitamp().   -  person user629926    schedule 27.06.2012
comment
Именно в этом я и думал проблема. Однако я использую Silverlight и не имею доступа к Bitmap.GetHBitmap().   -  person McAden    schedule 28.06.2012


Ответы (1)


Используйте GdipCreateBitmapFromScan0, чтобы получить HBitmap из вашего массива и передать его в буфер обмена и DeleteObject, чтобы освободить его.

[DllImport("gdiplus.dll")]
static extern int GdipCreateBitmapFromScan0(int width, int height, int stride, int format, IntPtr scan0, out IntPtr bitmap); 
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
person user629926    schedule 28.06.2012
comment
Я изменил вызов: GdipCreateBitmapFromScan0 (ширина, высота, ширина * 4, 0x0026200A, bmpPointer, out bmp); Неудачно. Он возвращается с 18, и я не смог найти, что это значит. - person McAden; 28.06.2012
comment
Просто чтобы знать, что я впервые использовал gdi+ напрямую. Код ошибки — GdiplusNotInitialized. Кажется, вам нужно использовать это перед любым другим вызовом msdn.microsoft.com/en-us/library/windows/desktop/ - person user629926; 28.06.2012
comment
Вероятно, просто нужно построить и Bitmap, и .NET инициализирует gdi+ для вас. - person user629926; 28.06.2012
comment
Не уверен, что вы можете попробовать протестировать его в локальной среде WinForms и использовать Bitmap.FromHBitmap(), чтобы проверить, есть ли у вас хороший растровый объект. - person user629926; 28.06.2012
comment
Вы вызываете OpenClipoard() перед выполнением всего этого? - person user629926; 28.06.2012