Как использовать буфер обмена в утверждении сопрограммы WinRT - C ++ / WinRT! Is_sta () - PullRequest
0 голосов
/ 30 апреля 2020

Я хочу установить растровое изображение в буфер обмена. Но не удалось установить буфер обмена с помощью сопрограммы. Скажите, пожалуйста, правильный способ создания растрового объекта и установки его в буфер обмена.

У меня возникают следующие проблемы.

  • !is_sta() пойманное утверждение. Конечно, я понимаю использование модели STA, но я не знаю, как избежать метода.
  • Функция буфера обмена не работает при игнорировании вышеприведенной ошибки. (Имя ошибки WinRT originate error, но мне кажется, что это неправдивый ответ.)

И я не знаком с сопрограммой C ++ и моделью потоков WinRT. Так что моё мнение тоже может быть неправильным.

Следующий код работает в основной функции (можно вставить растровое изображение в Power Point 2013), но функция not_working не работает из-за некоторых проблем. Какая разница в каждом методе?

С уважением.

#include <winrt/base.h>
#include <iostream>
#include <cstdint>
#include <string>
#include <winrt/Windows.ApplicationModel.DataTransfer.h>
#include <winrt/Windows.Graphics.Imaging.h>
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.Storage.Streams.h>
#include <random>
#include <Windows.h>

using namespace winrt::Windows::Graphics::Imaging;
using namespace winrt::Windows::ApplicationModel::DataTransfer;
using namespace winrt::Windows::Storage::Streams;
using namespace winrt::Windows::Foundation;

#pragma comment(lib, "WindowsApp")

IAsyncAction not_working()
{
  std::random_device seed_gen;
  std::mt19937 engine(seed_gen());

  std::vector<uint8_t> data(100 * 100 * 4);
  for (std::size_t i = 0; i < std::size(data); ++i)
  {
    data[i] = static_cast<std::uint8_t>(engine() * 255);
  }

  auto stream = InMemoryRandomAccessStream();
  auto encoder = co_await BitmapEncoder::CreateAsync(
    BitmapEncoder::BmpEncoderId(), stream
  ); // Assertion !is_sta()
  encoder.SetPixelData(
    BitmapPixelFormat::Bgra8, BitmapAlphaMode::Straight,
    100, 100, 1.0, 1.0, data
  );
  co_await encoder.FlushAsync();

  auto package = DataPackage();
  package.SetBitmap(RandomAccessStreamReference::CreateFromStream(stream));

  Clipboard::Clipboard::Clear();
  Clipboard::SetContent(package);
  Clipboard::Flush(); // WinRT originate error 

}

int main() 
{
  SetConsoleOutputCP(CP_UTF8);
  //winrt::init_apartment(winrt::apartment_type::multi_threaded);
  winrt::init_apartment(winrt::apartment_type::single_threaded);

  try
  {
    std::random_device seed_gen;
    std::mt19937 engine(seed_gen());

    std::vector<uint8_t> data(100 * 100 * 4);
    for (std::size_t i = 0; i < std::size(data); ++i)
    {
      data[i] = static_cast<std::uint8_t>(engine() * 255);
    }

    auto stream = InMemoryRandomAccessStream();
    auto encoder = BitmapEncoder::CreateAsync(
      BitmapEncoder::BmpEncoderId(), stream
    ).get();
    encoder.SetPixelData(
      BitmapPixelFormat::Bgra8, BitmapAlphaMode::Straight,
      100, 100, 1.0, 1.0, data
    );
    encoder.FlushAsync().get();

    auto package = DataPackage();
    package.SetBitmap(RandomAccessStreamReference::CreateFromStream(stream));

    Clipboard::Clipboard::Clear();
    Clipboard::SetContent(package);
    Clipboard::Flush();
  }
  catch (winrt::hresult_error const& ex)
  {
    winrt::hresult hr = ex.to_abi(); // HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND).
    winrt::hstring message = ex.message(); // The system cannot find the file specified.
    std::cout << (int)hr << std::endl;
    std::cout << winrt::to_string(message) << std::endl;
  }
  return 0;
}

1 Ответ

0 голосов
/ 04 мая 2020

API Clipboard доступен только тогда, когда вызывающее приложение находится в фокусе потока UI, нам нужно вызывать его из потока UI. Вы можете co_await функцию winrt :: resume_foreground, чтобы переключиться на определенный c поток переднего плана. Теперь мы можем использовать DispatcherQueue для работы с функцией winrt :: resume_foreground. Например:

#include <winrt/Windows.UI.Core.h>
#include <winrt/Windows.System.h>

using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::System;

IAsyncAction not_working(DispatcherQueue queue)
{
    std::random_device seed_gen;
    std::mt19937 engine(seed_gen());

    std::vector<uint8_t> data(100 * 100 * 4);
    for (std::size_t i = 0; i < std::size(data); ++i)
    {
        data[i] = static_cast<std::uint8_t>(engine() * 255);
    }

    auto stream = InMemoryRandomAccessStream();

    auto encoder = co_await BitmapEncoder::CreateAsync(
        BitmapEncoder::BmpEncoderId(), stream
    ); // Assertion !is_sta()
    encoder.SetPixelData(
        BitmapPixelFormat::Bgra8, BitmapAlphaMode::Straight,
        100, 100, 1.0, 1.0, data
    );
    co_await encoder.FlushAsync();

    auto package = DataPackage();
    package.SetBitmap(RandomAccessStreamReference::CreateFromStream(stream));

    //add resume_foreground
    co_await winrt::resume_foreground(queue);

    Clipboard::Clipboard::Clear();
    Clipboard::SetContent(package);
    Clipboard::Flush(); // WinRT originate error 
}

int main()
{
    SetConsoleOutputCP(CP_UTF8);

    winrt::init_apartment();

    auto controller{ DispatcherQueueController::CreateOnDedicatedThread() };
    not_working(controller.DispatcherQueue()).get();

    return 0;
}

Для получения более подробной информации об этом вы можете обратиться к: Более расширенный параллелизм и асинхронность с C ++ / WinRT .

...