Как передать интерфейс C # внешнему COM-объекту для его использования? - PullRequest
2 голосов
/ 03 февраля 2011

UPDATE:

Я обнаружил, что IID для ITfDocumentMgr был в реестре, но IID для ITextStoreACP не было. Когда я удалил [Guid ("28888 ....")] из определения интерфейса ITextStoreACP, метод Push () не завершился сбоем, я подозреваю, потому что мой класс не сообщал, что у него был этот интерфейс. Затем я поместил его обратно и сделал сборку, класс и интерфейс НЕ COM видимыми. Опять же, мой метод AdviseSink не вызывается.

Любые мысли по этому поводу будут оценены.


РЯДОМ ОРИГИНАЛЬНОЙ ПОЧТЫ:

Я пытаюсь интегрировать Text Services Framework в мое приложение C #, используя мое приложение C # в качестве клиента TSF (в отличие от службы TSF). Я могу получить COM-интерфейсы TSF для создания менеджера документов. Я создал текстовое хранилище, которое реализует 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, то Push () возвращает нормально, поскольку нет ITextStoreACP.AdviseSink () для вызова.

Я установил для свойства проекта «Сделать сборку видимым» значение true. Я установил для свойства проекта «Регистрация для COM-взаимодействия» значение true, хотя я не думаю, что это необходимо.

Есть ли что-то еще, что мне нужно сделать, чтобы сделать мой объект класса C # на основе интерфейса ITextStoreACP доступным для метода внешнего 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
        );
}

1 Ответ

0 голосов
/ 03 февраля 2011

Оказывается, мне нужна была следующая подпись:

[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

Не нужно было никого нанимать, просто нужно небольшое руководство. Спасибо всем!!! Вы великолепны!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...