简体   繁体   中英

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. 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. I then placed it back and made the assembly, class, and interface NOT COM visible. Again, my AdviseSink method is not called.

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). I can get the TSF COM interfaces to create a document manager okay. I have created a text store that implements the 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. 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.

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:

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

I set the project property "Make Assembly COM-Visible" to true. I set the project property "Register for COM interop" to true, though I don't think this is necessary.

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?

The interface I base my TextStore object from is shown next. 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.

And then I find that I simply need to add [PreserveSig] to the AdviseSink method declaration and all is good....

... or change the uint (HRESULT) to void (no return code). 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

Didn't need to hire anyone, just needed a little direction. Thanks all!!! You are awesome!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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