本文...
http://www.codeproject.com/Articles/4528/Use-IRichEditOle-from-C
...展示了如何在 C# 中获取 IRichEditOle COM 接口。到目前为止,一切都很好。
我一直在编写代码以在 C# 中获取 ITextDocument 接口。
(顺便说一句,我需要它来访问 Undo(tomSuspend,NULL) 所以如果存在解决方法,它同样受欢迎)
本文...
http://www.codeproject.com/Articles/4528/Use-IRichEditOle-from-C
...展示了如何在 C# 中获取 IRichEditOle COM 接口。到目前为止,一切都很好。
我一直在编写代码以在 C# 中获取 ITextDocument 接口。
(顺便说一句,我需要它来访问 Undo(tomSuspend,NULL) 所以如果存在解决方法,它同样受欢迎)
我发现大部分解决方案都隐藏在我上面链接的文章的评论中。
对于那些感兴趣的人,这是一个完整的解决方案的样子:
[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 接口代码。所有的错误都是我的。