2

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):

enter image description here (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:

enter image description here (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.

enter image description here

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.

Radium Zheng
  • 203
  • 1
  • 9
  • That is a normal and expected mishap. UWP apps run in a security sandbox that aggressively inhibits DLL injection. COM activation is very different, components must be included in the appx package and listed in the manifest. Only OS components can be activated the legacy way, identified by a certificate that only Microsoft owns. How to enable a custom IME in a UWP app is an open question, I don't see any decent Google hits about it when i google "uwp use custom ime". – Hans Passant Jun 02 '18 at 22:25
  • @HansPassant That's not true. UWP apps can, of course, use third-party IMEs and I am using a lot of them, on a daily basis. https://imgur.com/a/fEI3KO3 (Most are DLLs written in C++, All of them works except for the one written in .NET) I guess you don't see any google hits because a) TSF is poorly documented in the English world b) most IMEs using TSF load and work just fine in UWP without modifications. – Radium Zheng Jun 03 '18 at 03:49
  • Again, in this case the UWP application code is not loading the external DLLs. Some of its text controls (the TSF aware ones), via the TSF framework, cause the external DLLs to load. TSF APIs are partially supported in UWP. (Search for the keyword `ITfRange` at https://learn.microsoft.com/en-us/uwp/win32-and-com/win32-extension-apis) – Radium Zheng Jun 03 '18 at 03:54
  • Here is a pull request of a C++ based, opensource 3rd party Chinese IME, Weasel, that fixes its IPC issues on UWP. https://github.com/rime/weasel/pull/106/files The actual bug they were trying to fix were irrelavant to my question. But point is, its DLL, although third party, can be loaded and used in UWP (via the TSF framework). – Radium Zheng Jun 03 '18 at 03:57

1 Answers1

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++.

Xie Steven
  • 8,544
  • 1
  • 9
  • 23
  • Ah! That's kind of disappointing... but it makes sense to me. If you may clarify further: the "only allow a single version of the .net runtime" rule applies to both .NET full framework and the .NET Core runtime in UWP? – Radium Zheng Jun 26 '18 at 06:41
  • And as an implication of this: does it mean that **any** in-proc COM server implemented using [.NET interops](https://learn.microsoft.com/en-us/dotnet/framework/interop/exposing-dotnet-components-to-com) will the risk of not being able to be loaded? It appears that this restriction is not limited to IMEs only, since IMEs (under TSF) are just COM servers. – Radium Zheng Jun 26 '18 at 06:46
  • @RadiumZheng If you know ahead of time the versions of .net that will be targeted you can use the compiler’s multi-target support. This isn’t perfect and requires support from the project level to work as expected. https://weblogs.asp.net/scottgu/multi-targeting-support-vs-2010-and-net-4-series – Xie Steven Jul 02 '18 at 01:42
  • @xavier-xie-msft I failed to see how this is relevant to my question. – Radium Zheng Jul 13 '18 at 03:02