我想在我的 .net 应用程序中使用 Com 接口,但这与文本服务框架有关,我对此进行了研究,就像它只支持 COM 服务器一样,任何人都可以帮助我解决这个问题,我可以在我的 .NET 应用程序中使用 TSF 接口吗? net 应用程序,如果是,请告诉我该怎么做 plzzzzzz :) 谢谢
1 回答
嘿,我有同样的问题,我正在评估我是否真的必须使用 C++ 来完成这项工作。当然,您可以在任何兼容 COM 的环境中创建 COM 服务器,在 .NET 中也是如此。到目前为止,我还没有处于任何可用状态,但我可以告诉你我到目前为止做了什么。首先,msctf.dll 只有一个头文件和一个 IDL 文件(在 Windows SDK 7.0 中),必须对其进行修改以获得类型库 (tlb)。我使用了 codeplex 的 tlbimp2,它有一个基于 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 更友好:
使用系统;使用 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 的助手,因为我只在 IDL 编译器生成的 .c 文件中找到了它们。我认为最好解析那个文件,但这也很好。给定的类工作正常,我可以使用以下批次注册服务(检查是否在 C# 项目选项中启用了 regasm)
set outtype=Debug
set asmname=TextService
cd bin\%outtype%
gacutil /u %asmname%
gacutil /i %asmname%.dll
cd ..\..
我遇到的问题是这一切都是一项巨大的努力,而且有很多问题不值得我认为的痛苦。我不确定,希望有人能得到一些指导。有一点是,一个人总是需要关注一些像这样的伟大网站:TSF Aware blog ,但无论如何你都可以用 C++ 编写它。一种选择可能是 C++/CLR,在 C++ 中完成所有 COM 的东西和注册以及在 C# 中的逻辑,我猜可能
这里是一些测试代码,表明它基本上可以工作:
var 配置文件 = 新 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;
}