none
C# 如何正确使用CreateTextServices、ITextHost、ITextServices? RRS feed

  • 问题

  • 1、如何查找对应接口的GUID呢?在TextServ.h中的ITextHost中我只看到一个声明EXTERN_C const IID IID_ITextHost;

    2、调用CreateTextServices总是出现错误

    

    以下是我代码中的所有定义及调用方法:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    using System.ComponentModel;
    using System.Drawing;
    
    using WfUIL.NativeMethods;
    
    namespace WfUIL.Forms
    {
        public class RichEdit : Control, ITextHost
        {
            protected override void OnHandleCreated(EventArgs e)
            {
                base.OnHandleCreated(e);
                try
                {
                    IntPtr pUnk = IntPtr.Zero;
                    if (WinAPI.CreateTextServices(IntPtr.Zero, this, out pUnk) < 0)
                        throw new Win32Exception();
    
                    //Guid iid = typeof(WinInterface.ITextServices).GUID;
                    //Marshal.QueryInterface(pUnk, ref iid, out ppv);
                    //services = (WinInterface.ITextServices)
                    //    Marshal.GetTypedObjectForIUnknown(ppv, typeof(WinInterface.ITextServices));
    
                }
                finally
                {
                    //Marshal.Release(pUnk);
                }
            }
    
    
            public IntPtr TxGetDC()
            {
                return WinAPI.GetDC(new HandleRef(this, Handle);
            }
    
            public int TxReleaseDC(IntPtr hdc)
            {
                return WinAPI.ReleaseDC(new HandleRef(this, Handle), new HandleRef(null, hdc));
            }
    
            public bool TxShowScrollBar(int fnBar, bool fShow)
            {
                return false;
            }
    
            public bool TxEnableScrollBar(int fuSBFlags, int fuArrowflags)
            {
                return false;
            }
    
            public bool TxSetScrollRange(int fnBar, int nMinPos, int nMaxPos, bool fRedraw)
            {
                return false;
            }
    
            public bool TxSetScrollPos(int fnBar, int nPos, bool fRedraw)
            {
                return false;
            }
    
            public void TxInvalidateRect(WinStruct.P_RECT prc, bool fMode)
            {
    
            }
    
            public void TxViewChange(bool fUpdate)
            {
    
            }
    
            public bool TxCreateCaret(IntPtr hbmp, int xWidth, int yHeight)
            {
                return false;
            }
    
            public bool TxShowCaret(bool fShow)
            {
                return false;
            }
    
            public bool TxSetCaretPos(int x, int y)
            {
                return false;
            }
    
            public bool TxSetTimer(int idTimer, int uTimeout)
            {
                return false;
            }
    
            public void TxKillTimer(int idTimer)
            {
    
            }
    
            public void TxScrollWindowEx(int dx, int dy, WinStruct.P_RECT lprcScroll, WinStruct.P_RECT lprcClip, IntPtr hrgnUpdate, WinStruct.P_RECT lprcUpdate, int fuScroll)
            {
    
            }
    
            public void TxSetCapture(bool fCapture)
            {
    
            }
    
            public void TxSetFocus()
            {
    
            }
    
            public void TxSetCursor(IntPtr hcur, bool fText)
            {
    
            }
    
            public bool TxScreenToClient(WinStruct.P_POINT lppt)
            {
    
                return false;
            }
    
            public bool TxClientToScreen(WinStruct.P_POINT lppt)
            {
    
                return false;
            }
    
            public int TxActivate(ref int plOldState)
            {
                return 0;//S_OK
                //return unchecked((int)0x80004005);
            }
    
            public int TxDeactivate(int lNewState)
            {
                return 0;//S_OK
                //return unchecked((int)0x80004005);
            }
    
            public int TxGetClientRect(WinStruct.P_RECT prc)
            {
                //prc = new WinStruct.P_RECT(ClientRectangle);
                return 0;//S_OK
                //return unchecked((int)0x80004005);
            }
    
            public int TxGetViewInset(WinStruct.P_RECT prc)
            {
    
                //prc = new WinStruct.P_RECT(0, 0, 0, 0);
                return 0;//S_OK
            }
    
            public int TxGetCharFormat(ref WinStruct.P_CHARFORMATW ppCF)
            {
                Font font = SystemFonts.DefaultFont;
                WinStruct.P_LOGFONT logFont = new WinStruct.P_LOGFONT();
                WinStruct.P_CHARFORMATW format = new WinStruct.P_CHARFORMATW();
                font.ToLogFont(logFont);
    
                format.dwMask = WinEnum.CFM_FLAGS.CFM_FACE | WinEnum.CFM_FLAGS.CFM_SIZE | WinEnum.CFM_FLAGS.CFM_BOLD |
                    WinEnum.CFM_FLAGS.CFM_ITALIC | WinEnum.CFM_FLAGS.CFM_STRIKEOUT | WinEnum.CFM_FLAGS.CFM_UNDERLINE |
                    WinEnum.CFM_FLAGS.CFM_CHARSET | WinEnum.CFM_FLAGS.CFM_COLOR;
    
                format.dwEffects = 0;
                if (font.Bold)
                    format.dwEffects |= WinEnum.CFE_FLAGS.CFE_BOLD;
    
                if (font.Italic)
                    format.dwEffects |= WinEnum.CFE_FLAGS.CFE_ITALIC;
    
                if (font.Strikeout)
                    format.dwEffects |= WinEnum.CFE_FLAGS.CFE_STRIKEOUT;
    
                if (font.Underline)
                    format.dwEffects |= WinEnum.CFE_FLAGS.CFE_UNDERLINE;
    
                format.yHeight = (int)(font.SizeInPoints * 20);
                format.bCharSet = logFont.lfCharSet;
                format.bPitchAndFamily = logFont.lfPitchAndFamily;
                format.crTextColor = ColorTranslator.ToWin32(Color.Black);
    
                byte[] byteFaceName = Encoding.Default.GetBytes(logFont.lfFaceName);
                for (int i = 0; i < byteFaceName.Length; i++)
                {
                    format.szFaceName[i] = byteFaceName[i];
                }
    
                ppCF = format;
                return 0;//S_OK
            }
    
            public int TxGetParaFormat(ref WinStruct.P_PARAFORMAT ppPF)
            {
                //m_ParaFormat.cbSize = sizeof m_ParaFormat;
                //m_ParaFormat.dwMask = PFM_ALIGNMENT|PFM_NUMBERING|PFM_OFFSET|PFM_OFFSETINDENT|
                //PFM_RIGHTINDENT|PFM_RTLPARA|PFM_STARTINDENT|PFM_TABSTOPS;
                //m_ParaFormat.wAlignment = PFA_LEFT;
                WinStruct.P_PARAFORMAT format = new WinStruct.P_PARAFORMAT();
                format.dwMask = WinEnum.PFM_FLAGS.PFM_ALIGNMENT | WinEnum.PFM_FLAGS.PFM_NUMBERING
                    | WinEnum.PFM_FLAGS.PFM_OFFSET | WinEnum.PFM_FLAGS.PFM_OFFSETINDENT
                    | WinEnum.PFM_FLAGS.PFM_RIGHTINDENT | WinEnum.PFM_FLAGS.PFM_STARTINDENT
                    | WinEnum.PFM_FLAGS.PFM_TABSTOPS | WinEnum.PFM_FLAGS.PFM_RTLPARA;
    
                format.wAlignment = WinEnum.PFA_TYPE.PFA_LEFT;
                ppPF = format;
                return 0;//S_OK
            }
    
            public int TxGetSysColor(int nIndex)
            {
                return WinAPI.GetSysColor(nIndex);
            }
    
            public int TxGetBackStyle(ref WinEnum.TXTBACKSTYLE pstyle)
            {
                pstyle = WinEnum.TXTBACKSTYLE.TXTBACK_TRANSPARENT;
                return 0;//S_OK
            }
    
            public int TxGetMaxLength(ref int plength)
            {
                plength = int.MaxValue;
                return 0;//S_OK
            }
    
            public int TxGetScrollBars(ref int pdwScrollBar)//滚动条样式
            {
                pdwScrollBar = 0;
                return 0;//S_OK
            }
    
            public int TxGetPasswordChar(ref char pch)
            {
                return 1;//S_FLASE
            }
    
            public int TxGetAcceleratorPos(ref int pcp)
            {
                pcp = -1;
                return 0;//S_OK
    
            }
    
            public int TxGetExtent(WinStruct.P_SIZE lpExtent)
            {
                return unchecked((int)0x80004001L);//E_NOTIMPL
            }
    
            public int OnTxCharFormatChange(WinStruct.P_CHARFORMATW pCF_readonly)
            {
                return unchecked((int)0x80004005L);//E_FAIL
            }
    
            public int OnTxParaFormatChange(WinStruct.P_PARAFORMAT pPF_readonly)
            {
                return unchecked((int)0x80004005L);//E_FAIL
            }
    
            public int TxGetPropertyBits(WinEnum.TXTBIT_FLAGS dwMask, ref WinEnum.TXTBIT_FLAGS pdwBits)
            {
                // Set the windowless control as being multiple lines of wrapping rich text
    
                pdwBits = (WinEnum.TXTBIT_FLAGS.TXTBIT_MULTILINE | WinEnum.TXTBIT_FLAGS.TXTBIT_RICHTEXT
                    | WinEnum.TXTBIT_FLAGS.TXTBIT_WORDWRAP)
                    & dwMask;
                return 0;//S_OK
            }
    
            public int TxNotify(int iNotify, IntPtr pv)// void* pv)
            {
                return 0;//S_OK
            }
    
            public IntPtr TxImmGetContext()
            {
                return IntPtr.Zero;
            }
    
            public void TxImmReleaseContext(IntPtr himc)
            {
    
            }
    
            public int TxGetSelectionBarWidth(ref int lSelBarWidth)
            {
                lSelBarWidth = 0;
                return 0;//S_OK
            }
        }
    
        [ComImport(), Guid("C5BDD8D0-D26E-11CE-A89E-00AA006CADC5"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface ITextHost
        {
            /// <summary>
            /// 请求文本主机窗口的设备上下文。
            /// Requests the device context for the text host window.
            /// </summary>
            [PreserveSig]
            IntPtr TxGetDC();
    
            /// <summary>
            /// 释放由TxGetDC方法获取的设备上下文。
            /// Releases the device context obtained by the ITextHost::TxGetDC method.
            /// </summary>
            [PreserveSig]
            int TxReleaseDC(IntPtr hdc);
    
            // Show the scroll bar
            /// <summary>
            /// 显示或隐藏滚动条。
            /// Show the scroll bar
            /// </summary>
            [PreserveSig]
            bool TxShowScrollBar(int fnBar, bool fShow);
    
            /// <summary>
            /// 启用或禁用滚动条箭头。
            /// Enable or disable scroll bar
            /// </summary>
            [PreserveSig]
            bool TxEnableScrollBar(int fuSBFlags, int fuArrowflags);
    
    
            /// <summary>
            /// 设置指定滚动条的最小和最大位置值。
            /// Sets the minimum and maximum position values for the specified scroll bar in the text host window.
            /// </summary>
            [PreserveSig]
            bool TxSetScrollRange(int fnBar, int nMinPos, int nMaxPos, bool fRedraw);
    
            /// <summary>
            /// 设置指定滚动条中滚动框(滑块)的位置,如果需要,重绘滚动条以反映滚动框的新位置。
            /// Sets the position of the scroll box (thumb) in the specified scroll bar and, 
            /// if requested, redraws the scroll bar to reflect the new position of the scroll box.
            /// </summary>
            [PreserveSig]
            bool TxSetScrollPos(int fnBar, int nPos, bool fRedraw);
    
            /// <summary>
            /// 指定需要更新的区域。
            /// Specifies a rectangle for the text host to add to the update region of the text host window.
            /// </summary>
            [PreserveSig]
            void TxInvalidateRect(WinStruct.P_RECT prc, bool fMode);
    
            /// <summary>
            /// 向文本主机指示更新区域已更改。
            /// Indicates to the text host that the update region has changed.
            /// </summary>
            [PreserveSig]
            void TxViewChange(bool fUpdate);
    
            // Create the caret
            /// <summary>
            /// 为无窗口富文本框的插入符创建一个新形状。
            /// Creates a new shape for windowless rich edit control's caret.
            /// </summary>
            [PreserveSig]
            bool TxCreateCaret(IntPtr hbmp, int xWidth, int yHeight);
    
            /// <summary>
            /// 显示或隐藏插入符
            /// Shows or hides the caret at the caret position in the text host window.
            /// </summary>
            [PreserveSig]
            bool TxShowCaret(bool fShow);
    
            /// <summary>
            /// 将插入符位置移动到文本主机窗口中的指定坐标。
            /// Moves the caret position to the specified coordinates in the text host window.
            /// </summary>
            [PreserveSig]
            bool TxSetCaretPos(int x, int y);
    
            /// <summary>
            /// 使用指定的超时创建计时器
            /// Requests the text host to create a timer with a specified time-out.
            /// </summary>
            [PreserveSig]
            bool TxSetTimer(int idTimer, int uTimeout);
    
            /// <summary>
            /// 请求文本主机销毁指定的计时器。
            /// </summary>
            [PreserveSig]
            void TxKillTimer(int idTimer);
    
            /// <summary>
            /// 滚动指定客户区的内容。
            /// Requests the text host to scroll the content of the specified client area.
            /// </summary>
            [PreserveSig]
            void TxScrollWindowEx(int dx, int dy, WinStruct.P_RECT lprcScroll, WinStruct.P_RECT lprcClip, IntPtr hrgnUpdate, WinStruct.P_RECT lprcUpdate, int fuScroll);
    
            /// </summary>
            /// Get mouse capture
            /// </summary>
            [PreserveSig]
            void TxSetCapture(bool fCapture);
    
            /// </summary>
            /// Set the focus to the text window
            /// </summary>
            [PreserveSig]
            void TxSetFocus();
    
            /// </summary>
            /// Establish a new cursor shape
            /// </summary>
            [PreserveSig]
            void TxSetCursor(IntPtr hcur, bool fText);
    
            /// </summary>
            /// Converts screen coordinates of a specified point to the client coordinates 
            /// </summary>
            [PreserveSig]
            bool TxScreenToClient(WinStruct.P_POINT lppt);
    
            /// </summary>
            /// Converts the client coordinates of a specified point to screen coordinates
            /// </summary>
            [PreserveSig]
            bool TxClientToScreen(WinStruct.P_POINT lppt);
    
            /// </summary>
            /// Request host to activate text services
            /// </summary>
            [PreserveSig]
            int TxActivate(ref int plOldState);
    
            /// </summary>
            /// Request host to deactivate text services
            /// </summary>
            [PreserveSig]
            int TxDeactivate(int lNewState);
    
            /// </summary>
            /// Retrieves the coordinates of a window's client area
            /// </summary>
            [PreserveSig]
            int TxGetClientRect(WinStruct.P_RECT prc);
    
            /// </summary>
            /// Get the view rectangle relative to the inset
            /// </summary>
            [PreserveSig]
            int TxGetViewInset(WinStruct.P_RECT prc);
    
            /// </summary>
            /// Get the default character format for the text
            /// </summary>
            [PreserveSig]
            int TxGetCharFormat(ref WinStruct.P_CHARFORMATW ppCF);
    
            ////@cmember Get the default character format for the text
            //virtual HRESULT		TxGetCharFormat(const CHARFORMATW **ppCF ) = 0;
    
            ////@cmember Get the default paragraph format for the text
            //virtual HRESULT		TxGetParaFormat(const PARAFORMAT **ppPF) = 0;
    
            /// <summary>
            /// 获取文本的默认段落格式
            /// Get the default paragraph format for the text
            /// <summary>
            [PreserveSig]
            int TxGetParaFormat(ref WinStruct.P_PARAFORMAT ppPF);
    
            /// </summary>
            /// Get the background color for the window
            /// </summary>
            [PreserveSig]
            int TxGetSysColor(int nIndex);
    
            /// <summary>
            /// 获取背景(不透明或透明)
            /// Get the background (either opaque or transparent)
            /// </summary>
            [PreserveSig]
            int TxGetBackStyle(ref WinEnum.TXTBACKSTYLE pstyle);
    
            /// </summary>
            /// Get the maximum length for the text
            /// </summary>
            [PreserveSig]
            int TxGetMaxLength(ref int plength);
    
            /// </summary>
            /// Get the bits representing requested scroll bars for the window
            /// </summary>
            [PreserveSig]
            int TxGetScrollBars(ref int pdwScrollBar);
    
            /// <summary>
            /// 获取要显示密码输入的字符
            /// Get the character to display for password input
            /// </summary>
            [PreserveSig]
            int TxGetPasswordChar(ref char pch);
    
            /// </summary>
            /// Get the accelerator character
            /// </summary>
            [PreserveSig]
            int TxGetAcceleratorPos(ref int pcp);
    
            /// <summary>
            /// 获取控件的原始大小。
            /// Requests the native size of the control in HIMETRIC.
            /// </summary>
            [PreserveSig]
            int TxGetExtent(WinStruct.P_SIZE lpExtent);
    
            /// </summary>
            /// Notify host that default character format has changed
            /// </summary>
            [PreserveSig]
            int OnTxCharFormatChange(WinStruct.P_CHARFORMATW pCF_readonly);
    
            /// </summary>
            /// Notify host that default paragraph format has changed
            /// </summary>
            [PreserveSig]
            int OnTxParaFormatChange(WinStruct.P_PARAFORMAT pPF_readonly);
    
            ////@cmember Notify host that default character format has changed
            //virtual HRESULT		OnTxCharFormatChange (const CHARFORMATW * pCF) = 0;
    
            ////@cmember Notify host that default paragraph format has changed
            //virtual HRESULT		OnTxParaFormatChange (const PARAFORMAT * pPF) = 0;
    
            /// <summary>
            /// 请求文本主机的位属性设置。
            /// Requests the bit property settings for the text host.
            /// </summary>
            [PreserveSig]
            int TxGetPropertyBits(WinEnum.TXTBIT_FLAGS dwMask, ref WinEnum.TXTBIT_FLAGS pdwBits);
    
            /// <summary>
            /// 通知各种事件到主机。
            /// Notify host of events
            /// </summary>
            [PreserveSig]
            int TxNotify(int iNotify, IntPtr pv);//void* pv);
    
            /// </summary>
            // East Asia Methods for getting the Input Context
            /// </summary>
            [PreserveSig]
            IntPtr TxImmGetContext();
    
            [PreserveSig]
            void TxImmReleaseContext(IntPtr himc);
    
            /// </summary>
            // Returns HIMETRIC size of the control bar.
            /// </summary>
            [PreserveSig]
            int TxGetSelectionBarWidth(ref int lSelBarWidth);
        }
    }
    

    2019年3月27日 7:57

答案

  • 除了这个,我发现还有很多对指针和对象的混淆操作,既然win32代码可以运行的话,不妨可以用win32的代码生成一个DLL库,将这个类封装。然后通过C#来导入并间接调用。这样会比修改整个代码效率高。

    • 已标记为答案 Troy_Zhang 2019年4月11日 2:00
    2019年4月8日 9:52

全部回复

  • [DllImport(ExternDll.Msftedit, SetLastError = true, CharSet = CharSet.Auto)]
            public static extern int CreateTextServices(
                IntPtr punkOuter,
                WinInterface.ITextHost pITextHost,
                out IntPtr ppUnk
                );
    API定义
    2019年3月27日 7:58
  • Hi,

    1. EXTERN_C const IID IID_ITextHost; 值初始化和接口函数的实现通常被放在lib文件中(以隐藏),系统.h文件通常只会存放一些声明。要动态获取GUID,可以用你注释掉的方法:

    Guid iid = typeof(type).GUID;

    2. 0xc0000005通常表示写入位置没有访问的权限,CreateTextServices()最后一个参数是指向接收指向文本服务对象的私有IUnknown的指针的变量的指针,会有对这个指针指向的地址的写入操作,而你传的值是空指针,尝试在0地址上执行写入操作是非法的。你需要先申请一段空间。

    IntPtr pUnk = Marshal.AllocHGlobal(size);

    然后在用完的时候释放:

    Marshal.FreeHGlobal(pUnk);


    Best regards,

    Drake


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    2019年3月29日 8:08
  • HRESULT CFormattedTextDraw::CreateTextServicesObject()
    {
    IUnknown *spUnk;
    HMODULE hmod = ::LoadLibrary("Msftedit.dll");
    if (hmod == NULL)
    throw "LoadLibrary";
    
    CreateTextServicesFunc func = (CreateTextServicesFunc)::GetProcAddress(hmod, "CreateTextServices");
    
    HRESULT hr = func(NULL, static_cast<ITextHost*>(this), &spUnk);
    if (hr == S_OK) {
    hr = spUnk->QueryInterface(IID_ITextServices, (void**)&m_spTextServices);
    hr = spUnk->QueryInterface(IID_ITextDocument, (void**)&m_spTextDocument);
    spUnk->Release();
    }
    
    return hr;
    }

    你好,这是Win32代码,请注意spUnk也是一个未初始化的空指针,这个代码运行的话没有任何问题。

    还有一个问题没有说明:问题描述的代码在Win10x64也没有问题,在Win7x86就有问题了。

    不管是否在Win7编译,到Win10上就正常了


    2019年3月29日 10:41
  • 是的,win32的话这样写是对的,注意,虽然spUnk虽然是未初始化的指针(可能为空可能为随机值),但是你传的是&spUnk,代表的是spUnk的地址,这个值肯定是有效的值。这个"spUnk"跟你在C#中传的"pUnk"的类型是不一样的,spUnk是"IUnknown* ",而"pUnk"是"IUnknow** "(指针等级差一级),"&spUnk"的类型才跟"pUnk"一样。这是C/C++的语法,这个符号(&)+变量作为参数的话,通常是表示这个变量是个out的值。也可以申请一段空间给一个"IUnknow**"对象,然后传进去,这样也是有效值。C#中没有取地址符号(&),所以可以用第二种方法。你可以先试试我说的方法。
    2019年4月2日 0:42
  • pUnk = Marshal.AllocHGlobal(IntPtr.Size);

    还是依旧的错误的

    2019年4月6日 5:47
  • 除了这个,我发现还有很多对指针和对象的混淆操作,既然win32代码可以运行的话,不妨可以用win32的代码生成一个DLL库,将这个类封装。然后通过C#来导入并间接调用。这样会比修改整个代码效率高。

    • 已标记为答案 Troy_Zhang 2019年4月11日 2:00
    2019年4月8日 9:52