简体   繁体   English

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

[英]How do I pass a C# interface to an external COM object for its use?

UPDATE: 更新:

I found that the IID for ITfDocumentMgr was in the registry, but the IID for ITextStoreACP was not. 我发现注册表中有ITfDocumentMgr的IID,但ITextStoreACP的IID没有。 When I removed the [Guid("28888....")] from my ITextStoreACP interface definition, the Push() method did not crash, I suspect because my class was not reporting it had that interface. 当我从ITextStoreACP接口定义中删除[Guid(“ 28888 ....”)]时,Push()方法没有崩溃,我怀疑是因为我的班级并未报告它具有该接口。 I then placed it back and made the assembly, class, and interface NOT COM visible. 然后,我将其放回原处,并使程序集,类和接口NOT COM可见。 Again, my AdviseSink method is not called. 同样,不调用我的AdviseSink方法。

Any thoughts on this would be appreciated. 任何想法,将不胜感激。


NEAR ORIGINAL POST: 原帖附近:

I am trying to integrate Text Services Framework into my C# application, with my C# application as the TSF client (as opposed to a TSF service). 我正在尝试将Text Services Framework集成到C#应用程序中,并将C#应用程序作为TSF客户端(而不是TSF服务)。 I can get the TSF COM interfaces to create a document manager okay. 我可以使用TSF COM接口来创建文档管理器。 I have created a text store that implements the ITextStoreACP. 我创建了一个实现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;
    }
....
}

After I create a context that uses my ITextStoreACP, I then use DocumentMgr.Push() to use the context that references my text store. 创建使用ITextStoreACP的上下文之后,然后使用DocumentMgr.Push()使用引用我的文本存储的上下文。 In turn, the TSF framework should then call my ITextStoreACP.AdviseSink() method with its sink interface so that I can notify the framework when changes occur to the text store contents. 反过来,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
        {
        }

    }

}

I am using the ITfDocumentMgr interface definition here: 我在这里使用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);
}

However, instead of receiving a call to my AdviseSink() method, the app crashes and closes from within the call to Push(). 但是,应用程序崩溃了,没有收到对我的AdviseSink()方法的调用,而是从对Push()的调用中关闭了。 If I do not pass an interface for a text store (which is legal), but rather a null when I call CreateContext, then Push() returns fine, as there is no ITextStoreACP.AdviseSink() to call. 如果我没有传递用于文本存储的接口(合法),而是在调用CreateContext时传递了null,则Push()会返回正常,因为没有ITextStoreACP.AdviseSink()可以调用。

I set the project property "Make Assembly COM-Visible" to true. 我将项目属性“ Make Assembly COM-Visible”设置为true。 I set the project property "Register for COM interop" to true, though I don't think this is necessary. 我将项目属性“ Register for COM interop”设置为true,尽管我认为这不是必需的。

Is there anything else I need to do to make my C# class object based upon the ITextStoreACP interface accessible to an external COM object's method for it to use correctly? 我还需要做其他事情来使基于ITextStoreACP接口的C#类对象可被外部COM对象的方法访问,以使其正确使用吗?

The interface I base my TextStore object from is shown next. 接下来显示我基于TextStore对象的接口。 All methods are implemented in the text store, with at least the default "Method not implemented" exception, so that I can run the code. 所有方法都在文本存储区中实现,至少具有默认的“未实现方法”例外,以便我可以运行代码。

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

It turns out that I needed the following signature: 事实证明,我需要以下签名:

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

But now I find a read access violation and it appears that the stack pointer is popping 0 on the way back, which seems to indicate that the call itself is still not quite right. 但是现在我发现一个读取访问冲突,并且看来堆栈指针在返回的途中弹出0,这似乎表明调用本身仍然不太正确。

And then I find that I simply need to add [PreserveSig] to the AdviseSink method declaration and all is good.... 然后我发现我只需要将[PreserveSig]添加到AdviseSink方法声明中,一切就很好了。

... or change the uint (HRESULT) to void (no return code). ...或将uint(HRESULT)更改为void(无返回码)。 See the links here: 在此处查看链接:

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 http://msdn.microsoft.com/zh-CN/library/system.runtime.interopservices.preservesigattribute%28v=VS.90%29.aspx http://social.msdn.microsoft.com/Forums/zh-CN / clr / thread / a8c2d872-a42e-441a-907b-62d4a05f75ea

Didn't need to hire anyone, just needed a little direction. 不需要雇用任何人,只需要一点指导。 Thanks all!!! 谢谢大家! You are awesome! 你真棒!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM