Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Hey I have the same problem, I am evaluating if i really have to use C++ for doing the job. You can of course create a COM Server in any COM compatible environment, so also in .NET. I am by far not in any usable state, but I can tell you what I did so far. First, the msctf.dll only has a header and an IDL file (in Windows SDK 7.0), which has to be modified such that you get a type library (tlb). I used the tlbimp2 from codeplex, it has an xml based rewriting mechanism (that eases the heavy use of pointers in the type library: Here is my batch file</p> <pre><code>set sdk7=C:\Program Files\Microsoft SDKs\Windows\v7.0 set imported=msctf rem call "%sdk7%\Bin\SetEnv.cmd" midl "%sdk7%\Include\%imported%.idl" rem i copied the tlbimp2 into the sdk bin tlbimp2 /keyfile:TextService.snk %imported%.tlb /config:msctf.xml rem tlbimp /keyfile:TextService.snk %imported%.tlb rem not sure about this gacutil /u %imported% gacutil /i %imported%.dll </code></pre> <p>And here my XML rule file (to be expanded of course) <a href="http://clrinterop.codeplex.com/" rel="nofollow noreferrer">http://clrinterop.codeplex.com/</a></p> <pre class="lang-XML prettyprint-override"><code>&lt;Rules&gt; &lt;Rule Name="addlangprofile string 1" Category="Signature"&gt; &lt;Condition&gt; &lt;And&gt; &lt;NativeParentFunctionName Operator="Equal" Value="AddLanguageProfile" /&gt; &lt;NativeParameterIndex Operator="Equal" Value="4" /&gt; &lt;/And&gt; &lt;/Condition&gt; &lt;Action Name="ConvertTo"&gt; &lt;Parameter Key="Direction" Value="[In]" /&gt; &lt;Parameter Key="ByRef" Value="False" /&gt; &lt;Parameter Key="ManagedType" Value="LPArray" /&gt; &lt;Parameter Key="MarshalAs" Value="(default)" /&gt; &lt;Parameter Key="Attributes" Value="[SizeParamIndexOffset=+1]" /&gt; &lt;/Action&gt; &lt;/Rule&gt; &lt;Rule Name="addlanguageprofile string2" Category="Signature"&gt; &lt;Condition&gt; &lt;And&gt; &lt;NativeParentFunctionName Operator="Equal" Value="AddLanguageProfile" /&gt; &lt;NativeParameterIndex Operator="Equal" Value="6" /&gt; &lt;/And&gt; &lt;/Condition&gt; &lt;Action Name="ConvertTo"&gt; &lt;Parameter Key="Direction" Value="[In]" /&gt; &lt;Parameter Key="ByRef" Value="False" /&gt; &lt;Parameter Key="ManagedType" Value="LPArray" /&gt; &lt;Parameter Key="MarshalAs" Value="(default)" /&gt; &lt;Parameter Key="Attributes" Value="[SizeParamIndexOffset=+1]" /&gt; &lt;/Action&gt; &lt;/Rule&gt; &lt;Rule Name="GUID" Category="Type"&gt; &lt;Condition&gt; &lt;And&gt; &lt;NativeName Operator="Equal" Value="GUID" /&gt; &lt;/And&gt; &lt;/Condition&gt; &lt;Action Name="ResolveTo"&gt; &lt;Parameter Key="AssemblyName" Value="mscorlib" /&gt; &lt;Parameter Key="ManagedTypeFullName" Value="System.Guid" /&gt; &lt;/Action&gt; &lt;/Rule&gt; &lt;/Rules&gt; </code></pre> <p>Then I was trying to wrap the interfaces to be more .NET friendly:</p> <p>using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Globalization;</p> <pre><code>using MSCTF; using System.Runtime.InteropServices; namespace TextService { public class LanguageProfiles { private ITfInputProcessorProfiles instance; public LanguageProfiles() { instance = new COMIFace&lt;ITfInputProcessorProfiles&gt;().CreateInstance(); } public CultureInfo CurrentLanguage { get { ushort plangid; instance.GetCurrentLanguage(out plangid); return CultureInfo.GetCultureInfo(plangid); } set { instance.ChangeCurrentLanguage((ushort) value.LCID); } } public IEnumerable&lt;TF_LANGUAGEPROFILE&gt; ProfilesOfLanguage(CultureInfo culture) { IEnumTfLanguageProfiles ppenum; instance.EnumLanguageProfiles( (ushort) culture.LCID, out ppenum); TF_LANGUAGEPROFILE profile; uint fetch; do { ppenum.Next(1, out profile, out fetch); yield return profile; } while (fetch == 1 &amp;&amp; profile.fActive != -1); } public void Register(ref Guid rclsid) { instance.Register(ref rclsid); } public void Unregister(ref Guid rclsid) { instance.Unregister(ref rclsid); } public void Add(ref Guid rclsid, CultureInfo info, string name, string icon) { var empty = Guid.Empty; instance.AddLanguageProfile(ref empty, (ushort)info.LCID, ref rclsid, name.ToUShortArray(), name.ULength(), icon.ToUShortArray(), icon.ULength(), 0); } public void Remove(ref Guid rclsid, CultureInfo info) { instance.RemoveLanguageProfile(ref rclsid, (ushort)info.LCID, ref rclsid); } } } </code></pre> <p>The COMIFace class is just a helper to fetch the IIDs from registry, as I only found them in the .c file generated with the IDL compiler. Better would be to parse that file I think, but this works fine too. The given class works fine, I can register the service with following batch (check if regasm enabled in the C# project Options)</p> <pre><code>set outtype=Debug set asmname=TextService cd bin\%outtype% gacutil /u %asmname% gacutil /i %asmname%.dll cd ..\.. </code></pre> <p>The problem I had is with all this that its a huge effort and there are many issues that are not worth the pain i think. I am not sure and wish anybody had some guidance. A point is, one always needs to follow some great site like this: <a href="http://blogs.msdn.com/tsfaware/default.aspx" rel="nofollow noreferrer">TSF Aware blog</a> but then u can write it in C++ anyways. One option might be C++/CLR, doing all the COM stuff and registration in C++ and the logic in C#, possible I guess</p> <p>A here is some test code which shows it basically works:</p> <p>var profiles = new LanguageProfiles();</p> <pre><code>var ko_KR = CultureInfo.GetCultureInfo("ko-KR"); foreach (var profile in profiles.ProfilesOfLanguage(ko_KR)) { Console.WriteLine("clsid: " + profile.clsid + " lid: " + CultureInfo.GetCultureInfo(profile.langid) + " catid: " + profile.catid + " active: " + profile.fActive + " guidProf: " + profile.guidProfile); var id = profile.clsid; } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload