Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

two concurrent CanvasBitmap.LoadAsync will generate "The component cannot be found. (Exception from HRESULT: 0x88982F50)" #805

Closed
jtorjo opened this issue Feb 9, 2021 · 5 comments

Comments

@jtorjo
Copy link

jtorjo commented Feb 9, 2021

This will happen even if I'm using a different canvas devices on each thread.
Why is this, and is there a workaround?
Can this be fixed?

@benstevens48
Copy link

@jtorjo - what overload did you use? If you used the file name overload, try the stream overload.

The error is a WIC error which usually occurs if it can't find a suitable decoder for the image (I think). If there's noting wrong with the image, then this usually indicates some sort of corruption with the input stream, or perhaps you are using the same stream simultaneously?

I also found that actually Win2D's WIC factory initialization is not thread-safe - see https://github.com/microsoft/Win2D/blob/0ac546bca974b9b454b99d9d31935071966537ea/winrt/lib/images/WicAdapter.h. It's difficult to see how this could cause the error you are seeing, but I could submit a PR to fix this (basically it would be better just to initialize the factory in the constructor).

@jtorjo
Copy link
Author

jtorjo commented Feb 16, 2021

@benstevens48 Thanks!

I am using the stream overload:

using (var stream = new InMemoryRandomAccessStream()) {
	await stream.WriteAsync(buffer);
	stream.Seek(0); // Just to be sure.
	var bmp = await CanvasBitmap.LoadAsync(canvas_device, stream, 96, CanvasAlphaMode.Premultiplied);
	return bmp;
}

The images are correct, since using them in a single threaded fashion works. The input stream is always correct, since everything happens in memory -- I preload what I need in memory, and then convert each image to a stream.

Not sure if the initialization is the issue, since the call above is not the first call to LoadAsync (thus, the WIC factory should already be initialized).

but I could submit a PR to fix this (basically it would be better just to initialize the factory in the constructor).

That makes sense regardless of whether it fixes my issue or not. Thanks!

@benstevens48
Copy link

I've submitted a PR - #807 - to ensure thread safety. Maybe you can check if it fixes the problem (you will have to build a local copy of Win2D) but I doubt this was the problem though. I couldn't reproduce the issue using the unfixed version so I can't really say for sure.

With regards to it not being the first call to LoadAsync - actually, one thing I didn't realize until recently is that you shouldn't store a reference to a COM object in a global/static variable in a C++ app, because it will be destructed after COM has shut down and cause an access violation. See https://devblogs.microsoft.com/oldnewthing/20210208-00/?p=104812. Therefore in fact Win2D uses the method of only keeping a weak reference in the static variable, so if there are no in-use copies of the WIC factory (or the wrapping singleton instance) then it will actually be destroyed and then re-created again later if needed. (Why does everything have to be so complicated!!)

@jtorjo
Copy link
Author

jtorjo commented Mar 3, 2021

@benstevens48 Many thanks! My apologies for the late reply!
I'm more than swamped with work - I will get to this ASAP, but it will very likely be a few days -- I know just testing this will take a few hours, and at this point, I simply can't afford to do this.

@jtorjo
Copy link
Author

jtorjo commented Sep 24, 2021

@benstevens48 I finally figured this out. Sorry for the late reply, I've had a few shots at this in the last few months, but never got to the root of the issue.

Finally, I really got pissed a few days ago, and said I'll investigate, and debug within win2d. After quite a few hours of testing and googling this STUPID error, I figured it out: it was a bug in my code, namely I was using a file stream from several threads - and sometimes clearly some of the memory bytes were filled incorrectly. And CreateDecoderFromStream will simply dump that idiotic error code when that happened. Of course, it happened completely at random times. Never came to me to look at how I'm filling the stream buffer.

Long story short, with my internal fix, it works 100% correctly. This was a really weird one!

@jtorjo jtorjo closed this as completed Sep 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants