如何将C#接口传递给外部COM对象供其使用?

时间:2011-02-02 21:56:49

标签: c# com interface

更新:

我发现ITfDocumentMgr的IID在注册表中,但ITextStoreACP的IID却没有。当我从我的ITextStoreACP接口定义中删除[Guid(“28888 ....”)]时,Push()方法没有崩溃,我怀疑是因为我的类没有报告它有该接口。然后我把它放回去,使组件,类和接口NOT COM可见。同样,我的AdviseSink方法没有被调用。

对此的任何想法都将不胜感激。


NEAR ORIGINAL POST:

我正在尝试将Text Services Framework集成到我的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);
}

然而,应用程序在调用Push()时崩溃并关闭,而不是接收对我的AdviseSink()方法的调用。如果我没有传递文本存储的接口(这是合法的),而是在调用CreateContext时为null,则Push()返回正常,因为没有要调用的ITextStoreACP.AdviseSink()。

我将项目属性“Make Assembly COM-Visible”设置为true。 我将项目属性“Register for COM interop”设置为true,但我不认为这是必要的。

我需要做些什么才能使我的C#类对象基于外部COM对象可以正确使用的方法访问的ITextStoreACP接口?

接下来显示我的TextStore对象的接口。所有方法都在文本存储中实现,至少具有默认的“Method not implemented”异常,以便我可以运行代码。

    [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
        );
}

1 个答案:

答案 0 :(得分:0)

事实证明我需要以下签名:

[ComVisible(true)]
[Guid("28888fe3-c2a0-483a-a3ea-8cb1ce51ff3d")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ITextStoreACP 
{
    uint AdviseSink(
        ref Guid Iid, 
        [MarshalAs(UnmanagedType.IUnknown)] object pUnknown, 
        uint Mask
        );
    .......
}


public class TextStore : ITextStoreACP
{
    #region ITextStoreACP Members

    public uint AdviseSink(ref Guid Iid, object pUnknown, uint Mask)
    {
        throw new NotImplementedException();
    }
    .....
}

但是现在我发现了一个读取访问冲突,看起来堆栈指针在回来的路上弹出0,这似乎表明调用本身仍然不太正确。

然后我发现我只需要将[PreserveSig]添加到AdviseSink方法声明中,一切都很好....

...或将uint(HRESULT)更改为void(无返回码)。请参阅此处的链接:

http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.preservesigattribute%28v=VS.90%29.aspx http://social.msdn.microsoft.com/Forums/en-US/clr/thread/a8c2d872-a42e-441a-907b-62d4a05f75ea

不需要雇佣任何人,只需要一点方向。谢谢大家!你太棒了!