Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.69/13: Рейтинг темы: голосов - 13, средняя оценка - 4.69
70 / 71 / 19
Регистрация: 01.05.2013
Сообщений: 279

SetClipboardData (user32.dll) bitmap

07.07.2019, 14:23. Показов 2997. Ответов 7

Студворк — интернет-сервис помощи студентам
Здравствуйте.
Столкнулся с проблемой: мне нужно скопировать изображение (снимок экрана) в буфер обмена. Из-за тех. ограничений я не могу использовать System.Windows.Forms.Clipboard. Вместо этого я использую функцию SetClipboardData из библиотеки user32.dll.
Текст вставляется в буфер без проблем, но картинки, которые функция отправляет в буфер (возвращает true, то есть ошибки нет) невозможно открыть в paint (он не видит, что в буфере есть картинка) ("Данные из буфера обмена невозможно вставить").
Судя по информации, которую я смог найти в интернете, проблема связана с тем, что формат CF_BITMAP не будет распознан как картинка (возможно это не так, но несколько тем на MSDN утверждают именно это). В качестве решения предлагается использовать CF_DIB. Но я не могу найти, как преобразовать bitmap в DIB. Обычный bitmap он не принимает в качестве аргумента. Мой код:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
     [DllImport("user32.dll")]
        internal static extern bool OpenClipboard(IntPtr hWndNewOwner);
 
        [DllImport("user32.dll")]
        internal static extern bool CloseClipboard();
        [DllImport("user32.dll")]
        internal static extern bool EmptyClipboard();
        [DllImport("user32.dll")]
        internal static extern bool SetClipboardData(uint uFormat, IntPtr data);
 
        private void button1_Click(object sender, EventArgs e)
        {
            Bitmap bitmap = new System.Drawing.Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
            System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap);
            g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height));
 
 
            OpenClipboard(IntPtr.Zero);
            EmptyClipboard();
            var ptr = g.GetHdc();
//var ptr = bitmap.GetHbitmap();
            button1.Text = SetClipboardData(2, ptr).ToString(); 
  // button1.Text = SetClipboardData(8, ptr).ToString(); //error (result = False)
            CloseClipboard();
        }
Подскажите пожалуйста, как можно вставить изображение в буфер обмена (с помощью PInvoke)?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
07.07.2019, 14:23
Ответы с готовыми решениями:

Problems with user32.dll
Помогите, пожалуйста. Мне нужно программно переключиться на открытое приложение и нажать на нем в нужную область левой кнопкой мыши. ...

Надстройка для user32.dll
Всем доброго времени суток. Меня тут ВНЕЗАПНО осенила идея, что пользоватьсы функциями из user32.dll не очень то удобно, и я решил сделать...

Оптимизация опрашивания нажатых клавиш (user32.dll)
Здравствуйте. Я написал программу, которая, по нажатию на определенные кнопки клавиатуры (даже если форма находится вне фокуса), считывает...

7
1152 / 860 / 263
Регистрация: 30.04.2009
Сообщений: 3,603
10.07.2019, 12:19
Цитата Сообщение от Nikita_Nikita Посмотреть сообщение
Из-за тех. ограничений я не могу использовать System.Windows.Forms.Clipboard
Каких ограничений?
0
70 / 71 / 19
Регистрация: 01.05.2013
Сообщений: 279
10.07.2019, 12:45  [ТС]
Цитата Сообщение от nicolas2008 Посмотреть сообщение
Каких ограничений?
Компилятора Unity.
Ошибка в строке:
C#
1
2
3
using System.Windows.Forms;
 
Clipboard.SetImage(bitmap);
Картинка:
C#
1
2
3
  Bitmap bitmap = new System.Drawing.Bitmap(Screen.currentResolution.width, Screen.currentResolution.height);
            System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap);
            g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(Screen.currentResolution.width, Screen.currentResolution.height));
Кликните здесь для просмотра всего текста
NullReferenceException: Object reference not set to an instance of an object
at System.Drawing.ComIStreamMarshaler+Manag edToNativeWrapper..cctor () [0x00049] in <b26f6e18402e40bfbefc667aa5eb39a0>:0
Rethrow as TypeInitializationException: The type initializer for 'ManagedToNativeWrapper' threw an exception.
...


Большинство функций S.W.F. работает только в редакторе, а после компиляции возвращают ошибки. Из-за этого почти все функции, которые можно легко сделать с помощью этой dll, приходится делать через PInvoke.
Так как использование этой библиотеки в Unity - редкость, комментариев по этой проблеме не много, и кажется, что некоторые функции всё же могут работать, но не все. Возможно проблема не только в S.W.F., но и в самой функции Clipboard.SetImage
(Например, System.Drawing работает без ошибок).

Edit:
Так же, строка
C#
1
            Clipboard.SetText("Hello!");
не вызывает ошибок.

Добавлено через 10 минут
Полный текст ошибки:
Кликните здесь для просмотра всего текста
NullReferenceException: Object reference not set to an instance of an object
at System.Drawing.ComIStreamMarshaler+Manag edToNativeWrapper..cctor () [0x00049] in <b26f6e18402e40bfbefc667aa5eb39a0>:0
Rethrow as TypeInitializationException: The type initializer for 'ManagedToNativeWrapper' threw an exception.
at System.Drawing.ComIStreamMarshaler.Marsh alManagedToNative (System.Object managedObj) [0x00000] in <b26f6e18402e40bfbefc667aa5eb39a0>:0
at (wrapper managed-to-native) System.Drawing.GDIPlus.GdipSaveImageToSt ream(System.Runtime.InteropServices.Hand leRef,System.Runtime.InteropServices.Com Types.IStream,System.Guid&,System.Runtim e.InteropServices.HandleRef)
at System.Drawing.Image.Save (System.IO.Stream stream, System.Drawing.Imaging.ImageCodecInfo encoder, System.Drawing.Imaging.EncoderParameters encoderParams) [0x0007e] in <b26f6e18402e40bfbefc667aa5eb39a0>:0
at System.Drawing.Image.Save (System.IO.Stream stream, System.Drawing.Imaging.ImageFormat format) [0x00029] in <b26f6e18402e40bfbefc667aa5eb39a0>:0
at (wrapper remoting-invoke-with-check) System.Drawing.Image.Save(System.IO.Stre am,System.Drawing.Imaging.ImageFormat)
at System.Windows.Forms.XplatUIWin32.ImageT oDIB (System.Drawing.Image image) [0x0000d] in <74221ab25db54b76800a8d2a7149b899>:0
at System.Windows.Forms.XplatUIWin32.Clipbo ardStore (System.IntPtr handle, System.Object obj, System.Int32 type, System.Windows.Forms.XplatUI+ObjectToCli pboard converter) [0x000cf] in <74221ab25db54b76800a8d2a7149b899>:0
at System.Windows.Forms.XplatUI.ClipboardSt ore (System.IntPtr handle, System.Object obj, System.Int32 type, System.Windows.Forms.XplatUI+ObjectToCli pboard converter) [0x00000] in <74221ab25db54b76800a8d2a7149b899>:0
at System.Windows.Forms.Clipboard.SetDataOb jectImpl (System.Object data, System.Boolean copy) [0x00091] in <74221ab25db54b76800a8d2a7149b899>:0
at System.Windows.Forms.Clipboard.SetDataOb ject (System.Object data, System.Boolean copy, System.Int32 retryTimes, System.Int32 retryDelay) [0x0003e] in <74221ab25db54b76800a8d2a7149b899>:0
at System.Windows.Forms.Clipboard.SetDataOb ject (System.Object data, System.Boolean copy) [0x00000] in <74221ab25db54b76800a8d2a7149b899>:0
at System.Windows.Forms.Clipboard.SetDataOb ject (System.Object data) [0x00000] in <74221ab25db54b76800a8d2a7149b899>:0
at System.Windows.Forms.Clipboard.SetData (System.String format, System.Object data) [0x00019] in <74221ab25db54b76800a8d2a7149b899>:0
at System.Windows.Forms.Clipboard.SetImage (System.Drawing.Image image) [0x00011] in <74221ab25db54b76800a8d2a7149b899>:0
at ClipboardTest.Update () [0x0006e] in D:\Proj\Assets\ClipboardTest.cs:53

Пробовал разные способы (например, Image.FromHbitmap(bitmap.GetHbitmap())), которые смог найти. Везде: в редакторе работает, в сборке - нет.
0
1152 / 860 / 263
Регистрация: 30.04.2009
Сообщений: 3,603
10.07.2019, 12:53
Цитата Сообщение от Nikita_Nikita Посмотреть сообщение
Unity
C этого надо было и начинать.
0
70 / 71 / 19
Регистрация: 01.05.2013
Сообщений: 279
10.07.2019, 12:55  [ТС]
Цитата Сообщение от nicolas2008 Посмотреть сообщение
C этого надо было и начинать.
(уточнение на всякий случай)
Т. к. PInvoke работают так же, как в в обычном шарпе, код из первого поста тестировался не (только) в Unity, а в обычном Windows Form приложении.
0
1152 / 860 / 263
Регистрация: 30.04.2009
Сообщений: 3,603
10.07.2019, 16:04
Цитата Сообщение от Nikita_Nikita Посмотреть сообщение
проблема связана с тем, что формат CF_BITMAP не будет распознан как картинка
Если использовать Clipboard.SetImage, то добавляется как раз CF_BITMAP в буфер обмена.
Возможно paint требует именно OLE обьект, а не raw bitmap, непонятно...

Добавлено через 1 минуту
И еще в вашем коде нет копирования обьекта в unmanaged память, без этого точно не будет работать корректно. Но я пробовал с копированием - тоже не работает.
0
70 / 71 / 19
Регистрация: 01.05.2013
Сообщений: 279
10.07.2019, 17:12  [ТС]
Цитата Сообщение от nicolas2008 Посмотреть сообщение
Если использовать Clipboard.SetImage, то добавляется как раз CF_BITMAP в буфер обмена.
Возможно paint требует именно OLE обьект, а не raw bitmap, непонятно...
Paint.net так же не может вставить картинку, но он выдает ошибку, которая, вряд ли будет понятна (т. к. это Paint.net), но вдруг:
Кликните здесь для просмотра всего текста
Application version: paint.net версия 4.1.6

System.Exception: GetClipboardData() returned NULL (0, ERROR_SUCCESS) ---> System.ComponentModel.Win32Exception: GetClipboardData() returned NULL (0, ERROR_SUCCESS)
в PaintDotNet.SystemLayer.NativeUtilities. ThrowOnWin32Error(String message, Int32 lastWin32Error, Boolean alwaysThrow) в D:\src\pdn\src\SystemLayer\NativeUtiliti es.cs:строка 88
в PaintDotNet.SystemLayer.ClipboardTransac tion.TryGetRawNativeData(UInt32 formatID, Action`1 readDataCallback) в D:\src\pdn\src\SystemLayer\ClipboardTran saction.cs:строка 241
в PaintDotNet.ClipboardImageHelper.DibImag eRetriever.OnTryGetDataT(IClipboardTrans action clipTx) в D:\src\pdn\src\PaintDotNet\ClipboardImag eHelper.cs:строка 270
в PaintDotNet.ClipboardDataRetriever`1.Try GetData(IClipboardTransaction clipTx) в D:\src\pdn\src\PaintDotNet\ClipboardData Retriever`1.cs:строка 29
в PaintDotNet.ClipboardUtil.TryGetData[T](IClipboardTransaction clipTx, IReadOnlyList`1 retrievers) в D:\src\pdn\src\PaintDotNet\ClipboardUtil .cs:строка 58
--- Конец трассировки внутреннего стека исключений ---
в PaintDotNet.ClipboardUtil.TryGetData[T](IClipboardTransaction clipTx, IReadOnlyList`1 retrievers) в D:\src\pdn\src\PaintDotNet\ClipboardUtil .cs:строка 113
в PaintDotNet.ClipboardImageHelper.TryGetI mage(IClipboardTransaction clipTx) в D:\src\pdn\src\PaintDotNet\ClipboardImag eHelper.cs:строка 74
в PaintDotNet.Actions.PasteImageAction.<Pe rformActionImpl>b__6_0() в D:\src\pdn\src\PaintDotNet\Actions\Paste ImageAction.cs:строка 103
в PaintDotNet.Runtime.RetryManager.<>c__Di splayClass7_0`1.<RunMemorySensitiveOpera tion>b__0() в D:\src\pdn\src\Base\Runtime\RetryManager .cs:строка 139
в PaintDotNet.Runtime.RetryManager.RunMemo rySensitiveOperation(Int32 maxAttempts, Action action) в D:\src\pdn\src\Base\Runtime\RetryManager .cs:строка 168
в PaintDotNet.Runtime.RetryManager.RunMemo rySensitiveOperation[T](Int32 maxAttempts, Func`1 func) в D:\src\pdn\src\Base\Runtime\RetryManager .cs:строка 144
в PaintDotNet.Actions.PasteImageAction.Per formActionImpl() в D:\src\pdn\src\PaintDotNet\Actions\Paste ImageAction.cs:строка 81

Код:
C#
1
2
3
4
5
6
7
            Bitmap bitmap = new Bitmap(@"D:\NGD\Icons\HNY.png");
       button1.BackgroundImage = bitmap;
   OpenClipboard(IntPtr.Zero);
           EmptyClipboard();
            var ptr = bitmap.GetHbitmap();
          button1.Text = SetClipboardData(2, ptr).ToString(); 
            CloseClipboard();
Цитата Сообщение от nicolas2008 Посмотреть сообщение
И еще в вашем коде нет копирования объекта в unmanaged память, без этого точно не будет работать корректно. Но я пробовал с копированием - тоже не работает.
К сожалению, я немного в другой области (где управление памятью в основном идет другими командами, и т. п.), и могу что-то не до конца понять. Я нашел всего 2-3 примера на C# для этой функции, с примерно одинаковым кодом (и 1 тему с тем советом про DIB). Намного больше примеров на C++, и там все проблемы решались преобразованием из Bitmap в другие типы/форматы (DIB, DDB...).
0
1152 / 860 / 263
Регистрация: 30.04.2009
Сообщений: 3,603
10.07.2019, 17:48
Извините ошибся, GetHbitmap как раз создает обьект в unmanaged памяти.
Но структура обьекта не та которая должна быть.
Я бы поискал какой нибудь опенсорсный графический редактор на C++ и посмотрел бы какие api там используются для добавления изображения в буфер обмена
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
10.07.2019, 17:48
Помогаю со студенческими работами здесь

SendInput() (user32.dll) работает с разными приложениями по разному
В приложения: блокнот, калькулятор и тому подобное с помощью метода SendInput из user32.dll у меня получается передавать все нужные...

User32.dll FindWindow откуда взять первый аргумент?
FindWindow(className, windowTitle) Видел пример работы где первым аргументом было &quot;calcFrame&quot; , вторым - название окна, на русской...

Не работает GetLastInputInfo из user32.dll: время увеличивается несмотря на активность устройств ввода
Добрый день. Подскажите пожалуйста почему функция GetLastInputInfo из user32.dll не работает так, как написано в описании. Время...

Найти окно стороннего приложения зная его id и нажать 1 кнопку, но без использования user32.dll
Доброго времени суток, форумчане. Возникла следующая трудность. Есть консольное приложение написанное на C# но работающее не из под...

Нарисовать прошлый Bitmap на новом так, чтобы небыл растянут рисунок, если новый Bitmap больше размером
Короче пытался сделать такое дело: Рисую фигуры на форме, когда отпускаю левую кнопку мыши (когда кнопка зажата, то растягивается например...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Новые блоги и статьи
My Business CRM
MaGz GoLd 16.04.2026
Всем привет, недавно возникла потребность создать CRM, для личных нужд. Собственно программа предоставляет из себя базу данных клиентов, в которой можно фиксировать звонки, стадии сделки, а также. . .
Знаешь почему 90% людей редко бывают счастливыми?
kumehtar 14.04.2026
Потому что они ждут. Ждут выходных, ждут отпуска, ждут удачного момента. . . а удачный момент так и не приходит.
Фиксация колонок в отчете СКД
Maks 14.04.2026
Фиксация колонок в СКД отчета типа Таблица. Задача: зафиксировать три левых колонки в отчете. Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка) / / . . .
Настройки VS Code
Loafer 13.04.2026
{ "cmake. configureOnOpen": false, "diffEditor. ignoreTrimWhitespace": true, "editor. guides. bracketPairs": "active", "extensions. ignoreRecommendations": true, . . .
Оптимизация кода на разграничение прав доступа к элементам формы
Maks 13.04.2026
Алгоритм из решения ниже реализован на нетиповом документе, разработанного в конфигурации КА2. Задачи, как таковой, поставлено не было, проделанное ниже исключительно моя инициатива. Было так:. . .
Контроль заполнения и очистка дат в зависимости от значения перечислений
Maks 12.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: реализовать контроль корректности заполнения дат назначения. . .
Архитектура слоя интернета для сервера-слоя.
Hrethgir 11.04.2026
В продолжение https:/ / www. cyberforum. ru/ blogs/ 223907/ 10860. html Знаешь что я подумал? Раз мы все источники пишем в голове ветки, то ничего не мешает добавить в голову такой источник, который сам. . .
Подстановка значения реквизита справочника в табличную часть документа
Maks 10.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача №1: при указании работ (справочник РаботыПоРемонтуСпецтехники),. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru