4

本文...

http://www.codeproject.com/Articles/4528/Use-IRichEditOle-from-C

...展示了如何在 C# 中获取 IRichEditOle COM 接口。到目前为止,一切都很好。

我一直在编写代码以在 C# 中获取 ITextDocument 接口。

(顺便说一句,我需要它来访问 Undo(tomSuspend,NULL) 所以如果存在解决方法,它同样受欢迎)

4

1 回答 1

8

我发现大部分解决方案都隐藏在我上面链接的文章的评论中。

对于那些感兴趣的人,这是一个完整的解决方案的样子:

[ComImport]
[InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
[Guid( "00020D00-0000-0000-c000-000000000046" )]
public interface IRichEditOle
{
    int GetClientSite( IntPtr lplpolesite );
    int GetObjectCount();
    int GetLinkCount();
    int GetObject( int iob, REOBJECT lpreobject, [MarshalAs( UnmanagedType.U4 )] GetObjectOptions flags );
    int InsertObject( REOBJECT lpreobject );
    int ConvertObject( int iob, CLSID rclsidNew, string lpstrUserTypeNew );
    int ActivateAs( CLSID rclsid, CLSID rclsidAs );
    int SetHostNames( string lpstrContainerApp, string lpstrContainerObj );
    int SetLinkAvailable( int iob, int fAvailable );
    int SetDvaspect( int iob, uint dvaspect );
    int HandsOffStorage( int iob );
    int SaveCompleted( int iob, IntPtr lpstg );
    int InPlaceDeactivate();
    int ContextSensitiveHelp( int fEnterMode );
    //int GetClipboardData(CHARRANGE FAR * lpchrg, uint reco, IntPtr lplpdataobj);
    //int ImportDataObject(IntPtr lpdataobj, CLIPFORMAT cf, HGLOBAL hMetaPict);
}

public enum GetObjectOptions
{
    REO_GETOBJ_NO_INTERFACES    = 0x00000000,
    REO_GETOBJ_POLEOBJ          = 0x00000001,
    REO_GETOBJ_PSTG             = 0x00000002,
    REO_GETOBJ_POLESITE         = 0x00000004,
    REO_GETOBJ_ALL_INTERFACES   = 0x00000007,
}

[StructLayout( LayoutKind.Sequential )]
public struct CLSID
{
    public int      a;
    public short    b;
    public short    c;
    public byte     d;
    public byte     e;
    public byte     f;
    public byte     g;
    public byte     h;
    public byte     i;
    public byte     j;
    public byte     k;
}

[StructLayout( LayoutKind.Sequential )]
public struct SIZEL
{
    public int  x;
    public int  y;
}

[StructLayout( LayoutKind.Sequential )]
public class REOBJECT
{
    public REOBJECT()
    {
    }

    public int      cbStruct    = Marshal.SizeOf( typeof( REOBJECT ) );     // Size of structure
    public int      cp          = 0;                                        // Character position of object
    public CLSID    clsid       = new CLSID();                              // Class ID of object
    public IntPtr   poleobj     = IntPtr.Zero;                              // OLE object interface
    public IntPtr   pstg        = IntPtr.Zero;                              // Associated storage interface
    public IntPtr   polesite    = IntPtr.Zero;                              // Associated client site interface
    public SIZEL    sizel       = new SIZEL();                              // Size of object (may be 0,0)
    public uint     dvaspect    = 0;                                        // Display aspect to use
    public uint     dwFlags     = 0;                                        // Object status flags
    public uint     dwUser      = 0;                                        // Dword for user's use
}

public class API
{
    [DllImport( "User32.dll", CharSet = CharSet.Auto )]
    public static extern int SendMessage( IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam );
}

public class Messages
{
    public const int    WM_USER             = 0x0400;
    public const int    EM_GETOLEINTERFACE  = WM_USER + 60;
}


protected IRichEditOle  IRichEditOleValue   = null;
protected IntPtr        IRichEditOlePtr     = IntPtr.Zero;

[ComImport]
[InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
[Guid( "8CC497C0-A1DF-11ce-8098-00AA0047BE5D" )]
public interface ITextDocument
{
// IDispath methods (We never use them)
int GetIDsOfNames( Guid riid, IntPtr rgszNames, uint cNames, uint lcid, ref int rgDispId );
int GetTypeInfo( uint iTInfo, uint lcid, IntPtr ppTInfo );
int GetTypeInfoCount( ref uint pctinfo );
int Invoke( uint dispIdMember, Guid riid, uint lcid, uint wFlags, IntPtr pDispParams, IntPtr pvarResult, IntPtr pExcepInfo, ref uint puArgErr );

// ITextDocument methods
int GetName( /* [retval][out] BSTR* */ [In, Out, MarshalAs( UnmanagedType.BStr )] ref string pName );
int GetSelection( /* [retval][out] ITextSelection** */ IntPtr ppSel );
int GetStoryCount( /* [retval][out] */ ref int pCount );
int GetStoryRanges( /* [retval][out] ITextStoryRanges** */ IntPtr ppStories );
int GetSaved( /* [retval][out] */ ref int pValue );
int SetSaved( /* [in] */ int Value );
int GetDefaultTabStop( /* [retval][out] */ ref float pValue );
int SetDefaultTabStop( /* [in] */ float Value );
int New();
int Open( /* [in] VARIANT **/ IntPtr pVar, /* [in] */ int Flags, /* [in] */ int CodePage );
int Save( /* [in] VARIANT * */ IntPtr pVar, /* [in] */ int Flags, /* [in] */ int CodePage );
int Freeze( /* [retval][out] */ ref int pCount );
int Unfreeze( /* [retval][out] */ ref int pCount );
int BeginEditCollection();
int EndEditCollection();
int Undo( /* [in] */ int Count, /* [retval][out] */ ref IntPtr prop );
int Redo( /* [in] */ int Count, /* [retval][out] */ ref IntPtr prop );
int Range( /* [in] */ int cp1, /* [in] */ int cp2, /* [retval][out] ITextRange** */ IntPtr ppRange );
int RangeFromPoint( /* [in] */ int x, /* [in] */ int y, /* [retval][out] ITextRange** */ IntPtr ppRange );
}

public class TomConstants
{
public const int    tomSuspend  = -9999995;
public const int    tomResume   = -9999994;
}

protected ITextDocument ITextDocumentValue  = null;
protected IntPtr        ITextDocumentPtr    = IntPtr.Zero;

然后

public IRichEditOle GetRichEditOleInterface()
{
    if( this.IRichEditOleValue == null )
    {
        // Allocate the ptr that EM_GETOLEINTERFACE will fill in
        IntPtr ptr = Marshal.AllocCoTaskMem( Marshal.SizeOf( typeof( IntPtr ) ) );  // Alloc the ptr.
        Marshal.WriteIntPtr( ptr, IntPtr.Zero );                                    // Clear it.
        try
        {
            if( 0 != API.SendMessage( this.Handle, Messages.EM_GETOLEINTERFACE, IntPtr.Zero, ptr ) )
            {
                // Read the returned pointer
                IntPtr pRichEdit = Marshal.ReadIntPtr( ptr );
                try
                {
                    if( pRichEdit != IntPtr.Zero )
                    {
                        // Query for the IRichEditOle interface
                        Guid guid = new Guid( "00020D00-0000-0000-c000-000000000046" );
                        Marshal.QueryInterface( pRichEdit, ref guid, out this.IRichEditOlePtr );

                        // Wrap it in the C# interface for IRichEditOle
                        this.IRichEditOleValue = (IRichEditOle)Marshal.GetTypedObjectForIUnknown( this.IRichEditOlePtr, typeof( IRichEditOle ) );

                        if( this.IRichEditOleValue == null )
                        {
                            throw new Exception( "Failed to get the object wrapper for the IRichEditOle interface." );
                        }

                        // IID_ITextDocument
                        guid = new Guid( "8CC497C0-A1DF-11CE-8098-00AA0047BE5D" );
                        Marshal.QueryInterface( pRichEdit, ref guid, out this.ITextDocumentPtr );

                        // Wrap it in the C# interface for IRichEditOle
                        this.ITextDocumentValue = (ITextDocument)Marshal.GetTypedObjectForIUnknown( this.ITextDocumentPtr, typeof( ITextDocument ) );

                        if( this.ITextDocumentValue == null )
                        {
                            throw new Exception( "Failed to get the object wrapper for the ITextDocument interface." );
                        }
                    }
                    else
                    {
                        throw new Exception( "Failed to get the pointer." );
                    }
                }
                finally
                {
                    Marshal.Release( pRichEdit );
                }
            }
            else
            {
                throw new Exception( "EM_GETOLEINTERFACE failed." );
            }
        }
        catch( Exception err )
        {
            Trace.WriteLine( err.ToString() );
            this.ReleaseRichEditOleInterface();
        }
        finally
        {
            // Free the ptr memory
            Marshal.FreeCoTaskMem( ptr );
        }
    }

    return this.IRichEditOleValue;
}

public void ReleaseRichEditOleInterface()
{
    if( this.IRichEditOlePtr != IntPtr.Zero )
    {
        Marshal.Release( this.IRichEditOlePtr );
    }

    this.IRichEditOlePtr    = IntPtr.Zero;
    this.IRichEditOleValue  = null;
}

暂停/恢复撤消的调用可能如下所示:

public void EnableUndo( bool enable )
{
    if( IRichEditOleValue == null )
    {
        GetRichEditOleInterface();
    }

    IntPtr ptr = IntPtr.Zero;

    ITextDocumentValue.Undo( ( enable == true ) ? TomConstants.tomResume : TomConstants.tomSuspend, ptr );
}

此解决方案的功劳归功于 John Fisher 撰写了原始文章,并感谢 Chris Woodall 在评论中提供了 ITextDocument 接口代码。所有的错误都是我的。

于 2015-02-15T18:39:55.817 回答