【发布时间】:2011-02-05 04:46:25
【问题描述】:
更新:
我发现 ITfDocumentMgr 的 IID 在注册表中,但 ITextStoreACP 的 IID 不在。当我从 ITextStoreACP 接口定义中删除 [Guid("28888....")] 时,Push() 方法没有崩溃,我怀疑是因为我的类没有报告它具有该接口。然后我把它放回去,使程序集、类和接口不是 COM 可见的。同样,我的 AdviseSink 方法没有被调用。
对此的任何想法将不胜感激。
接近原帖:
我正在尝试将文本服务框架集成到我的 C# 应用程序中,并将我的 C# 应用程序作为 TSF 客户端(而不是 TSF 服务)。我可以得到 TSF COM 接口来创建一个文档管理器好吗。我创建了一个实现 ITextStoreACP 的文本存储。
[ComVisible(true)]
public class TextStore : ITextStoreACP
{
public uint AdviseSink(
[MarshalAs(UnmanagedType.Struct)] ref IID Iid,
[MarshalAs(UnmanagedType.IUnknown)] Object pUnknown,
uint Mask
)
{
ITextStoreAcpSink Sink = pUnknown as ITextStoreAcpSink;
return 0;
}
....
}
创建使用 ITextStoreACP 的上下文后,我使用 DocumentMgr.Push() 来使用引用我的文本存储的上下文。反过来,TSF 框架应该调用我的 ITextStoreACP.AdviseSink() 方法及其接收器接口,以便我可以在文本存储内容发生更改时通知框架。
public partial class Form1 : Form
{
static ITextStoreACP pStore = new TextStore();
static Object pIunknown;
static ITfContext Context;
static ITfDocumentMgr DocMgr;
static IThreadMgr ThreadMgr;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
TfClientId Tid = new TfClientId();
TfEditCookie Cookie = new TfEditCookie();
uint hr;
// Get a new thread manager...
ThreadMgr = TsfInterfaces.CreateManager();
// Activate the thread manager and get our cookie back...
hr = ThreadMgr.Activate(out Tid);
// Create a document manager for our use...
hr = ThreadMgr.CreateDocumentMgr(out DocMgr);
// Get the IUnknown interface to pass to CreateContext()...
pIunknown = pStore as Object;
// Create a context to work in, designating our text store for our use...
hr = DocMgr.CreateContext(Tid, 0, pIunknown, out Context, out Cookie);
try
{
// Select our context to work in now. With a text store as part of
// the context, the Text services framework should call into our
// text store object with its sink interface.
//
// But it crashes instead.
//
hr = DocMgr.Push(Context);
}
catch
{
}
}
}
我在这里使用 ITfDocumentMgr 接口定义:
[Guid("aa80e7f4-2021-11d2-93e0-0060b067b86e")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ITfDocumentMgr
{
uint CreateContext(
TfClientId Tid,
uint Flags,
[MarshalAs(UnmanagedType.IUnknown)] Object pUnkUnique,
[MarshalAs(UnmanagedType.Interface)] out ITfContext pContext,
out TfEditCookie pCookie
);
uint Push([MarshalAs(UnmanagedType.Interface)] ITfContext pContext);
uint Pop(uint Flags);
uint GetTop(out ITfContext Context);
uint GetBase(out ITfContext Context);
uint EnumContexts(out IEnumITfContexts EnumContexts);
}
但是,应用程序没有收到对我的 AdviseSink() 方法的调用,而是在对 Push() 的调用中崩溃并关闭。如果我没有传递文本存储的接口(这是合法的),而是在调用 CreateContext 时传递一个 null,那么 Push() 会返回正常,因为没有 ITextStoreACP.AdviseSink() 可以调用。
我将项目属性“Make Assembly COM-Visible”设置为 true。 我将项目属性“Register for COM interop”设置为 true,但我认为这没有必要。
我还需要做些什么来使基于 ITextStoreACP 接口的 C# 类对象可供外部 COM 对象的方法访问以使其正确使用吗?
下面显示了我基于 TextStore 对象的接口。所有方法都在文本存储中实现,至少有默认的“方法未实现”异常,这样我就可以运行代码了。
[Guid("28888fe3-c2a0-483a-a3ea-8cb1ce51ff3d")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ITextStoreACP
{
uint AdviseSink(
[MarshalAs(UnmanagedType.Struct)] ref IID Iid,
[MarshalAs(UnmanagedType.IUnknown)] object pUnknown,
uint Mask
);
uint UnadviseSink([MarshalAs(UnmanagedType.IUnknown)] object pUnknown);
uint RequestLock(uint LockFlags, out uint hrSession);
uint GetStatus([MarshalAs(UnmanagedType.Struct)] out TS_STATUS TSS);
uint QueryInsert(long TestStart, long TestEnd, ulong Count, out long ResultStart, out long ResultEnd);
uint GetSelection(
ulong Index,
ulong Count,
[MarshalAs(UnmanagedType.Struct)] out TS_SELECTION_ACP Selection,
out ulong Fetched
);
uint SetSelection(
ulong Count,
[MarshalAs(UnmanagedType.Struct)] ref TS_SELECTION_ACP Selection
);
uint GetText(
long Start,
long End,
out string Plain,
ulong PlainReq,
out ulong PlainRet,
[MarshalAs(UnmanagedType.Struct)] out TS_RUNINFO RunInfo,
ulong RunInfoReq,
out ulong RunInfoRet,
out long Next
);
uint SetText(
uint Flags,
long Start,
long End,
string Text, // What kind of marshaling should I specify here for "in WCHAR *" types?
ulong Count,
[MarshalAs(UnmanagedType.Struct)] out TS_TEXTCHANCE Change
);
uint GetFormattedText(
long Start,
long End,
[MarshalAs(UnmanagedType.Interface)] out IDataObject DataObject
);
uint GetEmbedded(
long Pos,
[MarshalAs(UnmanagedType.Struct)] ref IID GUID_Service,
[MarshalAs(UnmanagedType.Struct)] ref IID IID_Service,
[MarshalAs(UnmanagedType.IUnknown)] out object pUnk
);
uint QueryInsertEmbedded(
[MarshalAs(UnmanagedType.Struct)] ref IID GUID_Service,
[MarshalAs(UnmanagedType.Struct)] ref FORMATETC FormatEtc,
[MarshalAs(UnmanagedType.Bool)] out bool IsInsertable
);
uint InsertEmbedded(
uint Flags,
long Start,
long End,
[MarshalAs(UnmanagedType.Interface)] IDataObject DataObject,
[MarshalAs(UnmanagedType.Struct)] out TS_TEXTCHANCE Change
);
uint InsertTextAtSelection(
uint Flags,
string Text,
ulong Count,
out long Start,
out long End,
[MarshalAs(UnmanagedType.Struct)] out TS_TEXTCHANCE Change
);
uint InsertEmbeddedAtSelection(
uint Flags,
[MarshalAs(UnmanagedType.Interface)] IDataObject DataObject,
out long Start,
out long End,
[MarshalAs(UnmanagedType.Struct)] out TS_TEXTCHANCE Change
);
uint RequestSupportedAttrs(
uint Flags,
ulong FilterAttrs,
[MarshalAs(UnmanagedType.Struct)] ref TS_ATTRID AttrId
);
uint RequestAttrsAtPosition(
long Pos,
ulong FilterAttrs,
[MarshalAs(UnmanagedType.Struct)] ref TS_ATTRID AttrId,
uint Flags
);
uint RequestAttrsTransitioningAtPosition(
long Pos,
ulong FilterAttrs,
[MarshalAs(UnmanagedType.Struct)] ref TS_ATTRID AttrId,
uint Flags
);
uint FindNextAttrTransition(
long Start,
long Halt,
ulong FilterAttrs,
[MarshalAs(UnmanagedType.Struct)] ref TS_ATTRID AttrId,
uint Flags,
out long Next,
out bool Found,
out long FoundOffset
);
uint RetrieveRequestedAttrs(
ulong Count,
[MarshalAs(UnmanagedType.Struct)] ref TS_ATTRVAL Vals,
out ulong Fetched
);
uint GetEndACP(out long Acp);
uint GetActiveView(out TsViewCookie Cookie);
uint GetACPFromPoint(
TsViewCookie Cookie,
[MarshalAs(UnmanagedType.Struct)] ref POINT Point,
uint Flags,
out long Acp
);
uint GetTextExt(
TsViewCookie Cookie,
long Start,
long End,
[MarshalAs(UnmanagedType.Struct)] out RECT Rect,
out bool IsClipped
);
uint GetScreenExt(
TsViewCookie Cookie,
[MarshalAs(UnmanagedType.Struct)] out RECT Rect
);
uint GetWnd(
TsViewCookie Cookie,
[MarshalAs(UnmanagedType.I4)] IntPtr hWnd
);
}
【问题讨论】:
-
不,如果你只需要一个接口,这就是你需要做的!
-
您是否为定义您需要实现的接口的 com dll(或 tlb)创建了互操作文件?您是否在 C# 项目中引用了上述互操作并从中继承了您的对象?