CLR cannot create .NET-based COM objects in UWP

2020-07-27 15:47发布

问题:

I have created a Class Library (.NET Framework 4.7.1) that implements a Text Service (ITfTextInputProcessorEx etc.) in TSF, using ComVisible attribute. I registered it using RegistrationServices and it can be successfully recognised by the system as an Input Method (IME) and can be used in most applications, except UWP apps.

Using in Win32 app

In a Win32 app (the 32-bit notepad.exe for example), here is what happens when I activate my .NET-based TextService (by switching to the IME in the language bar):

(The circled YngPing.TSF.dll is the .NET assembly that contains the implementation of the COM object. The loading caused by COM object creation starts at #56.)

Basically, upon switching to my IME, the TSF framework (not the application code, but running in the same process) will try to create/request a COM object of my TextService by calling CoCreateObject. Because this not a native COM object, mscoree.dll is actually the "real" COM DLL that is in the registry. mscoree.dll first gets loaded, then it loads mscoreei.dll, clr.dll etc., before finally loading the actual .NET dll.

Using in AppContainer (UWP app)

Now these all works as expected in normal Desktop apps, but in an UWP app, the same process will stop after mscoree.dll and mscoreei.dll are loaded (i.e. clr.dll and my .NET assembly are not loaded). The call stack looks like this:

(The UWP app tested here is just an blank app with a textbox. All these COM loading are all initiated by the TSF.)

Another observation: after the calls to mscoree.dll quits, one of the pointers inside combase.dll is set to E_NOTIMPL.

In the same UWP app, DLLs of other 3rd party IMEs (like this one https://github.com/rime/weasel written in C++) can be loaded and used without problem. I am yet to test the official example, https://github.com/Microsoft/Windows-classic-samples/tree/master/Samples/IME but I am pretty confident it will work too.


I have a rough idea of what's going on, but I lack the expertise to dive deeper into the root cause: what happens is for .NET-based COM objects, the CLR is loaded first when the COM object is requested; but in this case for UWP, the CLR somehow failed to load and subsequently the COM object cannot be initiated.

I also used Fusion Log (with immersive mode for UWP) but did not see any related messages. I guess it is because even clr.dll is not loaded in my case.

Can anyone offer some ideas as to how to solve this problem? Thanks!

Update: When I say "IME" in this post, I mean "a Text Service using the Text Service Framework API", not the legacy "Input Method Manager (IMM)" API-based IMEs.

回答1:

You shouldn’t be using .net to write an IME. We only allow a single version of the .net runtime to be loaded into a process. When you build an IME with .net we cannot guarantee that we will be able to load the correct version of the runtime. Because of this the IME may fail. You should always write your IME components using unmanaged C++.