1

In C++, I want to load a image, and render it to a win32 window using winrt compositing. I'm just trying to build a simple test bed for my other app to test 2dtexture compositing.

I've tried many implementations at this point.

void CreateDesktopWindowTarget(HWND window)
{
    namespace abi = ABI::Windows::UI::Composition::Desktop;

    auto interop = m_compositor.as<abi::ICompositorDesktopInterop>();
    DesktopWindowTarget target{ nullptr };
    check_hresult(interop->CreateDesktopWindowTarget(window, false, reinterpret_cast<abi::IDesktopWindowTarget**>(put_abi(target))));
    m_target = target;
}

This is in most of their examples and sample code. It fails here:

    check_hresult(interop->CreateDesktopWindowTarget(window, false, reinterpret_cast<abi::IDesktopWindowTarget**>(put_abi(target))));

with:

C++: Exception thrown: read access violation. decoder.**ptr** was nullptr. (decoder.ptr was nullptr.)

I don't know or understand what any of this abi type reflection stuff is doing. Its hard to debug. The failures are just esoteric.

This scratch file is where I'm at:

#define NOMINMAX
#include <windows.h>
#include <windows.ui.composition.h>
#include <windows.ui.composition.desktop.h>
#include <windows.ui.composition.interop.h>
#include <unknwn.h>       // For IUnknown and related COM interfaces
#include <activation.h>   // For IActivationFactory
#include <roapi.h>        // For RoInitialize, RoUninitialize, RoGetActivationFactory
#include <wrl.h>          // For Microsoft::WRL::ComPtr
#include <d3d11.h>
#include <dxgi1_2.h>
#include <dxgidebug.h>
#include <cstdio>
#include <combaseapi.h>

// Link necessary libraries
#pragma comment(lib, "runtimeobject.lib")
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxguid.lib")

#include <wrl/client.h> // For Microsoft::WRL::ComPtr

// WIL (Windows Implementation Library)
#include <wil/cppwinrt.h> // Needs to come before C++/WinRT headers
#include <wil/resource.h>
#include <wil/cppwinrt_helpers.h>
#include <wil/coroutine.h>

// C++/WinRT headers
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Foundation.Metadata.h>
#include <winrt/Windows.Graphics.Capture.h>
#include <winrt/Windows.Graphics.DirectX.h>
#include <winrt/Windows.Graphics.DirectX.Direct3D11.h>
#include <winrt/Windows.Graphics.Imaging.h>
#include <winrt/Windows.Security.Authorization.AppCapabilityAccess.h>
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.Storage.Pickers.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.System.h>
#include <winrt/Windows.UI.h>
#include <winrt/Windows.UI.Composition.h>
#include <winrt/Windows.UI.Composition.Desktop.h>
#include <winrt/Windows.UI.Popups.h>
#include <winrt/Windows.Foundation.Numerics.h>
#include <winrt/Windows.UI.Composition.Interactions.h>

// STL headers
#include <atomic>
#include <memory>
#include <algorithm>
#include <unordered_set>
#include <vector>
#include <optional>
#include <future>
#include <mutex>

// D3D headers
#include <d3d11.h>
#include <d3d11_4.h>
#include <dxgi1_6.h>
#include <d2d1_3.h>
#include <wincodec.h>

// Helper headers
#include "ComPtr.hpp"
#include <robmikh.common/composition.interop.h>
#include <robmikh.common/composition.desktop.interop.h>
#include <robmikh.common/d3d11Helpers.h>
#include <robmikh.common/d3d11Helpers.desktop.h>
#include <robmikh.common/direct3d11.interop.h>
#include <robmikh.common/d2dHelpers.h>
#include <robmikh.common/capture.desktop.interop.h>
#include <robmikh.common/dispatcherqueue.desktop.interop.h>
#include <robmikh.common/stream.interop.h>
#include <robmikh.common/hwnd.interop.h>
#include <robmikh.common/ControlsHelper.h>



#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "windowscodecs.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "gdi32.lib")
#pragma comment(lib, "comctl32.lib")


using namespace winrt;

namespace winrt
{
    using namespace Windows::UI::Composition;
    using namespace Windows::UI::Composition::Desktop;
    using namespace Windows::Graphics::DirectX::Direct3D11;
    using namespace Windows::Foundation;
    using namespace Windows::Foundation::Numerics;

    using namespace Windows::Foundation;
    using namespace Windows::Foundation::Numerics;
    using namespace Windows::Graphics;
    using namespace Windows::Graphics::Capture;
    using namespace Windows::Graphics::DirectX;
    using namespace Windows::Graphics::DirectX::Direct3D11;
    using namespace Windows::System;
    using namespace Windows::UI;
    using namespace Windows::UI::Composition;
    using namespace Windows::System;
    using namespace Windows::UI::Composition::Desktop;
    using namespace Windows::Foundation::Numerics;
}

namespace util
{
    using namespace robmikh::common::uwp;
    using namespace robmikh::common::desktop;
}

winrt::Windows::UI::Composition::Compositor m_compositor{ nullptr };
winrt::Windows::UI::Composition::Desktop::DesktopWindowTarget m_target{ nullptr };
winrt::Windows::UI::Composition::ContainerVisual m_root{ nullptr };
winrt::Windows::UI::Composition::SpriteVisual m_content{ nullptr };
winrt::Windows::UI::Composition::CompositionSurfaceBrush m_brush{ nullptr };
winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice m_device{ nullptr };
winrt::com_ptr<IDXGISwapChain1> m_swapChain{ nullptr };
winrt::com_ptr<ID3D11Device> m_d3dDevice{ nullptr };
winrt::com_ptr<ID3D11DeviceContext> m_d3dContext{ nullptr };
winrt::Windows::System::DispatcherQueueController m_dispatcherQueueController{ nullptr };


void CreateDesktopWindowTarget(HWND window)
{
    namespace abi = ABI::Windows::UI::Composition::Desktop;

    auto interop = m_compositor.as<abi::ICompositorDesktopInterop>();
    DesktopWindowTarget target{ nullptr };
    check_hresult(interop->CreateDesktopWindowTarget(window, false, reinterpret_cast<abi::IDesktopWindowTarget**>(put_abi(target))));
    m_target = target;
}

void CreateCompositionRoot()
{
    auto root = m_compositor.CreateContainerVisual();
    root.RelativeSizeAdjustment({ 1.0f, 1.0f });
    root.Offset({ 124, 12, 0 });
    m_target.Root(root);
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if (uMsg == WM_DESTROY)
    {
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

void EnsureDispatcherQueue()
{
    namespace abi = ABI::Windows::System;

    if (m_dispatcherQueueController == nullptr)
    {
        DispatcherQueueOptions options
        {
            sizeof(DispatcherQueueOptions), /* dwSize */
            DQTYPE_THREAD_CURRENT,          /* threadType */
            DQTAT_COM_ASTA                  /* apartmentType */
        };

        winrt::Windows::System::DispatcherQueueController controller{ nullptr };
        check_hresult(CreateDispatcherQueueController(options, reinterpret_cast<abi::IDispatcherQueueController**>(put_abi(controller))));
        m_dispatcherQueueController = controller;
    }
}

int main()
{
    winrt::init_apartment(winrt::apartment_type::multi_threaded);
    EnsureDispatcherQueue();
    auto m_compositor = winrt::Compositor();

    const wchar_t CLASS_NAME[] = L"FrameShowWindowClass";

    WNDCLASS wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = GetModuleHandle(NULL);
    wc.lpszClassName = CLASS_NAME;
    wc.style = CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&wc);

    DWORD style = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
    DWORD exStyle = 0;

    RECT rect = { 0, 0, 1024, 1024 };
    AdjustWindowRectEx(&rect, style, FALSE, exStyle);
    HWND hwnd = CreateWindowEx(
        exStyle,
        CLASS_NAME,
        L"Frame Show",
        style,
        CW_USEDEFAULT, CW_USEDEFAULT,
        rect.right - rect.left,
        rect.bottom - rect.top,
        NULL,
        NULL,
        wc.hInstance,
        NULL
    );

    if (!hwnd)
    {
        return -1;
    }

    ShowWindow(hwnd, SW_SHOW);

    const wchar_t CHILD_CLASS_NAME[] = L"ChildWindowClass";

    WNDCLASS child_wc = {};
    child_wc.lpfnWndProc = WindowProc; 
    child_wc.hInstance = GetModuleHandle(NULL);
    child_wc.lpszClassName = CHILD_CLASS_NAME;
    child_wc.style = CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&child_wc);

    HWND hwndChild = CreateWindowEx(
        0,
        CHILD_CLASS_NAME,
        NULL,
        WS_CHILD | WS_VISIBLE,
        0, 0, 1024, 1024,
        hwnd,
        NULL,
        wc.hInstance,
        NULL
    );


    auto d3dDevice = util::CreateD3D11Device();
    auto dxgiDevice = d3dDevice.as<IDXGIDevice>();
    m_device = CreateDirect3DDevice(dxgiDevice.get());

    auto d2dFactory = util::CreateD2DFactory();
    auto d2dDevice = util::CreateD2DDevice(d2dFactory, d3dDevice);
    winrt::com_ptr<ID2D1DeviceContext> d2dContext;

    ComPtr<IWICImagingFactory> wicFactory;
    CoCreateInstance(
        CLSID_WICImagingFactory,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_PPV_ARGS(&wicFactory)
    );

    ComPtr<IWICBitmapDecoder> decoder;
    std::wstring imagePath = L"C:\\data\\train - Copy\\outpu21567151.bmp";
    wicFactory->CreateDecoderFromFilename(
        imagePath.c_str(),
        nullptr,
        GENERIC_READ,
        WICDecodeMetadataCacheOnLoad,
        &decoder
    );

    ComPtr<IWICBitmapFrameDecode> frame;
    decoder->GetFrame(0, &frame);

    ComPtr<IWICFormatConverter> converter;
    wicFactory->CreateFormatConverter(&converter);
    converter->Initialize(
        frame.Get(),
        GUID_WICPixelFormat32bppRGBA,
        WICBitmapDitherTypeNone,
        nullptr,
        0.f,
        WICBitmapPaletteTypeCustom
    );

    UINT width, height;
    converter->GetSize(&width, &height);
    UINT stride = width * 4;
    UINT imageSize = stride * height;
    std::unique_ptr<BYTE[]> pixels(new BYTE[imageSize]);
    converter->CopyPixels(NULL, stride, imageSize, pixels.get());

    D3D11_TEXTURE2D_DESC texDesc = {};
    texDesc.Width = 1024;
    texDesc.Height = 1024;
    texDesc.MipLevels = 1;
    texDesc.ArraySize = 1;
    texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    texDesc.SampleDesc.Count = 1;
    texDesc.Usage = D3D11_USAGE_DEFAULT;
    texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    texDesc.CPUAccessFlags = 0;
    texDesc.MiscFlags = 0;

    ComPtr<ID3D11Texture2D> texture;
    d3dDevice->CreateTexture2D(&texDesc, nullptr, &texture);
    d3dDevice->GetImmediateContext(m_d3dContext.put());
    m_d3dContext->UpdateSubresource(texture.Get(), 0, nullptr, pixels.get(), stride, 0);
    
    CreateDesktopWindowTarget(hwndChild);
    CreateCompositionRoot();
    auto compositionGraphicsDevice = util::CreateCompositionGraphicsDevice(m_compositor, d2dDevice.get());
    auto compositionSurface = util::CreateCompositionSurfaceForSwapChain(m_compositor, texture.Get());
    SpriteVisual spriteVisual = m_compositor.CreateSpriteVisual();
    CompositionSurfaceBrush surfaceBrush = m_compositor.CreateSurfaceBrush(compositionSurface);
    spriteVisual.Brush(surfaceBrush);
    spriteVisual.RelativeSizeAdjustment({ 1.0f, 1.0f });
    m_target.Root(spriteVisual);

    MSG msg = {};
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

This is just a scratch file. But I should be able to make this work. If you know, do I have to have a dispatch queue? With screen capture I just init a single thread apartment.

0

1 Answer 1

2

In your main() function, you are creating a new Compositor object and assigning it to a local variable named m_compositor, but your CreateDesktopWindowTarget() function is using a global variable of the same name, which is initialized to nullptr and never re-assigned, so your interop variable ends up as nullptr when casting the global m_compositor variable.

Change this statement in main():

auto m_compositor = winrt::Compositor();

To this instead:

m_compositor = winrt::Compositor();
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.