Эй, у меня та же проблема, я оцениваю, действительно ли мне нужно использовать C ++ для выполнения этой работы. Конечно, вы можете создать COM-сервер в любой COM-совместимой среде, а также в .NET.
Я далеко не в каком-либо пригодном для использования состоянии, но я могу сказать вам, что я сделал до сих пор.
Во-первых, msctf.dll имеет только заголовок и файл IDL (в Windows SDK 7.0), который необходимо изменить так, чтобы вы получили библиотеку типов (tlb). Я использовал tlbimp2 из codeplex, у него есть механизм переписывания на основе xml (который облегчает интенсивное использование указателей в библиотеке типов:
Вот мой командный файл
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
А вот и мой XML-файл правил (будет расширен, конечно)
http://clrinterop.codeplex.com/
<Rules>
<Rule Name="addlangprofile string 1" Category="Signature">
<Condition>
<And>
<NativeParentFunctionName Operator="Equal" Value="AddLanguageProfile" />
<NativeParameterIndex Operator="Equal" Value="4" />
</And>
</Condition>
<Action Name="ConvertTo">
<Parameter Key="Direction" Value="[In]" />
<Parameter Key="ByRef" Value="False" />
<Parameter Key="ManagedType" Value="LPArray" />
<Parameter Key="MarshalAs" Value="(default)" />
<Parameter Key="Attributes" Value="[SizeParamIndexOffset=+1]" />
</Action>
</Rule>
<Rule Name="addlanguageprofile string2" Category="Signature">
<Condition>
<And>
<NativeParentFunctionName Operator="Equal" Value="AddLanguageProfile" />
<NativeParameterIndex Operator="Equal" Value="6" />
</And>
</Condition>
<Action Name="ConvertTo">
<Parameter Key="Direction" Value="[In]" />
<Parameter Key="ByRef" Value="False" />
<Parameter Key="ManagedType" Value="LPArray" />
<Parameter Key="MarshalAs" Value="(default)" />
<Parameter Key="Attributes" Value="[SizeParamIndexOffset=+1]" />
</Action>
</Rule>
<Rule Name="GUID" Category="Type">
<Condition>
<And>
<NativeName Operator="Equal" Value="GUID" />
</And>
</Condition>
<Action Name="ResolveTo">
<Parameter Key="AssemblyName" Value="mscorlib" />
<Parameter Key="ManagedTypeFullName" Value="System.Guid" />
</Action>
</Rule>
</Rules>
Затем я пытался обернуть интерфейсы, чтобы они были более дружественными к .NET:
с использованием Системы;
using System.Collections.Generic;
использование System.Linq;
используя System.Text;
используя System.Globalization;
using MSCTF;
using System.Runtime.InteropServices;
namespace TextService
{
public class LanguageProfiles
{
private ITfInputProcessorProfiles instance;
public LanguageProfiles()
{
instance = new COMIFace<ITfInputProcessorProfiles>().CreateInstance();
}
public CultureInfo CurrentLanguage
{
get
{
ushort plangid;
instance.GetCurrentLanguage(out plangid);
return CultureInfo.GetCultureInfo(plangid);
}
set
{
instance.ChangeCurrentLanguage((ushort) value.LCID);
}
}
public IEnumerable<TF_LANGUAGEPROFILE> 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 && 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);
}
}
}
Класс COMIFace является всего лишь помощником для извлечения IID из реестра, поскольку я нашел их только в файле .c, созданном с помощью компилятора IDL. Думаю, лучше было бы разобрать этот файл, но он тоже работает нормально.
Данный класс работает нормально, я могу зарегистрировать сервис в следующем пакете (проверьте, включен ли regasm в настройках проекта C #)
set outtype=Debug
set asmname=TextService
cd bin\%outtype%
gacutil /u %asmname%
gacutil /i %asmname%.dll
cd ..\..
Проблема, с которой я столкнулся, заключается в том, что это огромное усилие, и есть много проблем, которые не стоят той боли, которую я думаю. Я не уверен и желаю, чтобы у кого-то было какое-то руководство.
Суть в том, что всегда нужно следить за каким-нибудь замечательным сайтом, подобным этому: Блог TSF Aware
но тогда вы можете написать это на C ++ в любом случае.
Одним из вариантов может быть C ++ / CLR, выполнение всех вещей COM и регистрация в C ++ и логика в C #, возможно, я думаю
А вот некоторый тестовый код, который показывает, что он в основном работает:
var profile = new LanguageProfiles ();
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;
}