directxc++-cxhresultuwp-mapsdirectxtk

0x88982F50: "The component cannot be found" When using DirectXTK's CreateWICTextureFromMemory()


I'm working on a (Universal Windows) c++/cx Directx project, which builds to a dll used in a c# UWP project.

I'm using the DirectX Toolkit to load textures.

I already use it to create a texture from file, but now I need it to create a texture from a byte array that was send from the UWP project. But when trying to use CreateWICTextureFromMemory(), the HRESULT says 0x88982F50:"The component cannot be found"

All I can find about this problem indicates the bytes are not a correct image, but I tested it in the UWP project, there I get the byte array from bingmaps (it's a static map image), and I could make a working image from these bytes.

Does annyone know what I'm doing wrong?

UWP c# download code (to get the bytes):

private async Task DownloadTexture()
    {
        byte[] buffer = null;
        try
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_url);
            WebResponse response = await request.GetResponseAsync();
            using (Stream stream = response.GetResponseStream())
            using (MemoryStream ms = new MemoryStream())
            {
                stream.CopyTo(ms);
                buffer = ms.ToArray();
            }
        }
        catch (Exception exception)
        {
            Logger.Error($"Could not Download Texture: {exception}");
        }

        _track3D.SetImage(out buffer[0], (ulong)buffer.Length);
    }

Directx C++ code (that fails):

void Track3D::SetImage(uint8_t* ddsData, size_t ddsDataSize)
{
    HRESULT result = CreateWICTextureFromMemory(_d3dDevice.Get(), _d3dContext.Get(), ddsData, ddsDataSize, nullptr, _Terrain.ReleaseAndGetAddressOf());
    //here it goes wrong
    //TODO: use the texture
}

UWP C# test code that works (displays image):

private async void setImage(byte[] buffer) //test
    {
        try
        {
            BitmapImage bmpImage = new BitmapImage();
            using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
            {
                await stream.WriteAsync(buffer.AsBuffer());
                stream.Seek(0);
                await bmpImage.SetSourceAsync(stream);
            }

            Image image = new Image();
            image.Source = bmpImage;

            ((Grid)Content).Children.Add(image);
        }
        catch (Exception exception)
        {
            Logger.Error($"{exception}");
        }
    }

EDIT:

OK, turns out the first byte in the buffer is different in the C++ code, than it was when sent from UWP. When I change that first byte to the correct value in the C++ code (as a test), the texture is correctly created.

Which raises the question, why did the value of the first byte change? (Or what did I do wrong?)

As requested, The function setImage() looks like this in c#:

[MethodImpl]
public void __ITrack3DPublicNonVirtuals.SetImage(out byte ddsData, [In] ulong ddsDataSize);

(also, I just realised the parameter names still have 'dds' in their name, sorry about that, will change that in my code as it is misleading)


Solution

  • 0x88982F50: “The component cannot be found”

    This is WINCODEC_ERR_COMPONENTNOTFOUND which happens whenever WIC can't determine what format codec to use for a file/binary. Your problem is your transfer of the data from managed to native code is wrong.

    Your interop method is set to:

    [MethodImpl]
    public void __ITrack3DPublicNonVirtuals.SetImage(out byte ddsData, [In] ulong ddsDataSize);
    

    With the C++ method signature being:

    void Track3D::SetImage(uint8_t* ddsData, size_t ddsDataSize)
    

    Because of the out your first parameter is being passed as a safe array with the length in the first element.

    Instead you should use:

    SetImage([In] byte ddsData, [In] ulong ddsDataSize); // C#
    
    void Track3D::SetImage(const uint8_t* ddsData, size_t ddsDataSize); // C++.