0

I'm working on a C++ app and I need to be able to add a bitmap to the Windows Runtime clipboard. My options were to use WRL or WinRT, so I chose WRL as it seemed to have (slightly) more documentation. After a bit of fiddling I had some code to add text to the clipboard:

    RoInitializeWrapper initialise(RO_INIT_SINGLETHREADED);
    if (FAILED(initialise))
    {
        return 1;
    }

    ComPtr<IClipboardStatics> clipboard;
    HRESULT hr2 = GetActivationFactory(HStringReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_Clipboard).Get(), &clipboard);

    ComPtr<IDataPackage> dataPackage;
    hr2 = ActivateInstance(HStringReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_DataPackage).Get(), &dataPackage);

    hr2 = dataPackage.Get()->SetText(HStringReference(L"Testing 1 2 3 4").Get());

    hr2 = clipboard.Get()->SetContent(dataPackage.Get());

Adding a bitmap proved to be much harder, however. I spend a lot of time looking at source code, reading docs and writing test code, and eventually ended up with the following (note I read a BMP file from HD for testing purposes):

    HRESULT hr2;

    ComPtr<IDataWriter> imageDataWriter;
    ComPtr<IRandomAccessStream> imageStream;
    ComPtr<IRandomAccessStreamReference> imageStreamReference;
 
    RoInitializeWrapper initialise(RO_INIT_SINGLETHREADED);
    if (FAILED(initialise))
    {
         return 1;
    }

    hr2 = ActivateInstance(HStringReference(RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream).Get(), imageStream.GetAddressOf());


    ComPtr<IOutputStream> outputStream;
    hr2 = imageStream.As(&outputStream);

    ComPtr<IDataWriterFactory> dataWriterFactory;
    hr2 = GetActivationFactory(HStringReference(RuntimeClass_Windows_Storage_Streams_DataWriter).Get(), dataWriterFactory.GetAddressOf());

    hr2 = dataWriterFactory->CreateDataWriter(outputStream.Get(), imageDataWriter.GetAddressOf());

    BYTE* data = nullptr;

    std::streampos size;
    std::ifstream in(L"c:\\temp\\background.bmp", std::ios::in|std::ios::binary|std::ios::ate);
    if (in.is_open())
    {
        size = in.tellg();

        data = new BYTE[size];
        in.seekg(0, std::ios::beg);
        in.read((char*) data, size);
        in.close();
    }

    hr2 = imageDataWriter->WriteBytes(size, data);

    ComPtr<IDataPackage> dataPackage;
    hr2 = ActivateInstance(HStringReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_DataPackage).Get(), &dataPackage);

    ComPtr<IRandomAccessStreamReferenceStatics> streamRefFactory;
    hr2 = GetActivationFactory(HStringReference(RuntimeClass_Windows_Storage_Streams_RandomAccessStreamReference).Get(), streamRefFactory.GetAddressOf());

    hr2 = streamRefFactory->CreateFromStream(imageStream.Get(), imageStreamReference.GetAddressOf());

    hr2 = dataPackage.Get()->SetBitmap(imageStreamReference.Get());

    hr2 = dataPackage->put_RequestedOperation(DataPackageOperation::DataPackageOperation_Copy);

    ComPtr<IClipboardStatics> clipboard;
    hr2 = GetActivationFactory(HStringReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_Clipboard).Get(), &clipboard);

    hr2 = clipboard.Get()->SetContent(dataPackage.Get());

    clipboard->Flush();

All the WRL functions return S_OK but nothing actually appears in the clipboard. I do get an exception when the IRandomAccessStreamReference goes out of scope, so that might be a clue.

Any clues as to what I'm doing wrong? This is my first experience with Windows Runtime and to be honest I'm finding it very frustrating to work with.

Ðаn
  • 10,934
  • 11
  • 59
  • 95
JonB
  • 1
  • "*I do get an exception when the IRandomAccessStreamReference goes out of scope*" - probably because your `RoInitializeWrapper` is going out of scope first. Your `imageDataWriter`, `imageStream`, and `imageStreamReference` variables are going out of scope and being released *after* the `RoInitializeWrapper` has called `::Windows::Foundation::Uninitialize()`. Order of Declaration matters in C++. Local variables are destroyed in the reverse order that they are declared. – Remy Lebeau Jul 26 '21 at 18:14
  • On a side note: if your `std::ifstream` fails to open the file, your `size` variable is left *uninitialized* when `imageDataWriter->WriteBytes()` is called. In fact, most of your code lacks adequate error handling – Remy Lebeau Jul 26 '21 at 18:16
  • @RemyLebeau Thanks for your comments. Good point about the order of destruction - it's now fixed, but I still don't get a bitmap in the clipboard. Note that this code is from a scratch app, so I see any errors when I single step though it. The final version will trap and log any errors it comes across - I've just got to get it to work first :) – JonB Jul 27 '21 at 09:04

0 Answers0