0

调用时: pTextServices->TxSendMessage( EM_STREAMIN, ( WPARAM ) SF_RTF, ( LPARAM ) &editStream, &lResult )

没有调用 editSteam.EditStreamInCallback,但如果使用 SF_TEXT 而不是 SF_RTF,则调用 editSteam.EditStreamInCallback。

根据 MS 文档: https ://docs.microsoft.com/en-us/windows/win32/api/richedit/nc-richedit-editstreamcallback

发生错误,阻止富编辑控件将数据传入或传出自身。例如内存不足、系统功能故障或读取缓冲区中的无效字符。

在这些情况下,editStream.dwError 应该包含与零不同的值,但它是零。

这是使用的 RTF:代码中的“{\rtf1\ansi\pard test \par}”转义为:

"{\\rtf1\\ansi\\pard test \\par}"

谢谢

4

1 回答 1

0

感谢我的朋友 Bruno Cantero 先生 (C3),修复并正常工作

#include <Richedit.h>
#include <textserv.h>

typedef struct
{
   char * szText;
   LONG lSize;
   LONG lCount;
} RTFTEXTINFO;

typedef HRESULT ( _stdcall * PCREATETEXTSERVICES ) ( IUnknown *, ITextHost *, IUnknown ** );

const IID IID_ITextServices = { 0x8d33f740, 0xcf58, 0x11ce, { 0xa8, 0x9d, 0x00, 0xaa, 0x00, 0x6c, 0xad, 0xc5 } };

class TTextHost : public ITextHost
{
   public:
      /* IUnknown */
      STDMETHOD( QueryInterface )( REFIID, PVOID * ppvObject ) { * ppvObject = NULL; return S_FALSE; };
      STDMETHOD_( ULONG, AddRef )( void ) { return 0; };
      STDMETHOD_( ULONG, Release )( void ) { return 0; };

      /* ITextHost */
      HDC TxGetDC( void ) { return NULL; };
      INT TxReleaseDC( HDC ) { return 1; };
      BOOL TxShowScrollBar( INT, BOOL ) { return FALSE; };
      BOOL TxEnableScrollBar( INT, INT ) { return FALSE; };
      BOOL TxSetScrollRange( INT, LONG, INT, BOOL ) { return FALSE; };
      BOOL TxSetScrollPos( INT, INT, BOOL ) { return FALSE; };
      void TxInvalidateRect( LPCRECT, BOOL ) {};
      void TxViewChange( BOOL ) {};
      BOOL TxCreateCaret( HBITMAP, INT, INT ) { return FALSE; };
      BOOL TxShowCaret( BOOL ) { return FALSE; };
      BOOL TxSetCaretPos( INT, INT ) { return FALSE; };
      BOOL TxSetTimer( UINT, UINT ) { return FALSE; };
      void TxKillTimer( UINT ) {};
      void TxScrollWindowEx( INT, INT, LPCRECT, LPCRECT, HRGN, LPRECT, UINT ) {};
      void TxSetCapture( BOOL ) {};
      void TxSetFocus( void ) {};
      void TxSetCursor( HCURSOR, BOOL ) {};
      BOOL TxScreenToClient( LPPOINT ) { return FALSE; };
      BOOL TxClientToScreen( LPPOINT ) { return FALSE; };
      HRESULT TxActivate( LONG * ) { return S_OK; };
      HRESULT TxDeactivate( LONG ) { return S_OK; };
      HRESULT TxGetClientRect( LPRECT prc ) { SetRectEmpty( prc ); return S_OK; };
      HRESULT TxGetViewInset( LPRECT prc ) { SetRectEmpty( prc ); return S_OK; };
      HRESULT TxGetCharFormat( const CHARFORMATW ** ppCF ) { * ppCF = FCharFormat; return S_OK; };
      HRESULT TxGetParaFormat( const PARAFORMAT ** ppPF ) { * ppPF = FParaFormat; return S_OK; };
      COLORREF TxGetSysColor( int iIndex ) { return GetSysColor( iIndex ); };
      HRESULT TxGetBackStyle( TXTBACKSTYLE * pstyle ) { * pstyle = TXTBACK_TRANSPARENT; return S_OK; };
      HRESULT TxGetMaxLength( DWORD * plength ) { * plength = INFINITE; return S_OK; };
      HRESULT TxGetScrollBars( DWORD * pdwScrollBar ) { * pdwScrollBar = 0; return S_OK; };
      HRESULT TxGetPasswordChar( _Out_ TCHAR * pch ) { return S_FALSE; };
      HRESULT TxGetAcceleratorPos( LONG * pcp ) { * pcp = -1; return S_OK; };
      HRESULT TxGetExtent( LPSIZEL ) { return E_NOTIMPL; };
      HRESULT OnTxCharFormatChange( const CHARFORMATW * pCF ) { _bcopy( FCharFormat, ( void * ) pCF, pCF->cbSize ); return S_OK; };
      HRESULT OnTxParaFormatChange( const PARAFORMAT * pPF ) { _bcopy( FParaFormat, ( void * ) pPF, pPF->cbSize ); return S_OK; };
      HRESULT TxGetPropertyBits( DWORD, DWORD * pdwBits ) { * pdwBits = TXTBIT_RICHTEXT | TXTBIT_MULTILINE | TXTBIT_WORDWRAP | TXTBIT_USECURRENTBKG; return S_OK; };
      HRESULT TxNotify( DWORD, void * ) { return S_OK; };
      HIMC TxImmGetContext( void ) { return NULL; };
      void TxImmReleaseContext( HIMC ) {};
      HRESULT TxGetSelectionBarWidth( LONG * lSelBarWidth ) { * lSelBarWidth = 100; return S_OK; };

      CHARFORMATW * FCharFormat;
      PARAFORMAT * FParaFormat;
};

static DWORD CALLBACK EditStreamCallback( DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb )
{
   RTFTEXTINFO * pRtfTextInfo;

   pRtfTextInfo = ( RTFTEXTINFO * ) dwCookie;

   if( pRtfTextInfo->lSize - pRtfTextInfo->lCount < cb )
      * pcb = pRtfTextInfo->lSize - pRtfTextInfo->lCount;
   else
      * pcb = cb;

   memcpy( pbBuff, pRtfTextInfo->szText, * pcb );
   pRtfTextInfo->lCount += * pcb;

   return 0;
}

extern "C" void SayRTF( void )
{
   LRESULT lResult;
   HDC hDC;
   HFONT hFont;
   HMODULE hDLL;
   RECT stRect;
   LOGFONT stLogFont;
   EDITSTREAM stEditStream;
   PCREATETEXTSERVICES pCreateTextServices;
   CHARFORMATW stCharFormat;
   PARAFORMAT stParaFormat;
   RTFTEXTINFO sRtfTextInfo;
   IUnknown * pUnknown;
   ITextServices * pTextServices;
   TTextHost * pTextHost;

   /* HDC donde dibujar. */
   hDC = ( HDC ) hb_parnl( 1 ); // the hDC where you want to show the RTF

   // Comentamos para probar la transperencia Rectangle( hDC, 9, 9, 202, 202 );

   stRect = { 10, 10, 200, 200 };
   hDLL = LoadLibrary( "Riched20.dll" );

   if( hDLL == NULL )
      return;

   pCreateTextServices = ( PCREATETEXTSERVICES ) GetProcAddress( hDLL, "CreateTextServices" );

   if( pCreateTextServices == NULL )
   {
      FreeLibrary( hDLL );

      return;
   }

   /* Obtenemos las características de la fuente del HDC. */
   hFont = ( HFONT ) SelectObject( hDC, GetStockObject( SYSTEM_FONT ) );
   GetObject( hFont, sizeof( LOGFONT ), &stLogFont );
   SelectObject( hDC, hFont );

   /* Creamos el formato de la fuente por defecto. */
   memset( &stCharFormat, 0, sizeof( CHARFORMATW ) );
   stCharFormat.cbSize = sizeof( CHARFORMATW );
   stCharFormat.dwEffects = CFM_EFFECTS | CFE_AUTOBACKCOLOR;
   stCharFormat.dwEffects &= ~( CFE_PROTECTED | CFE_LINK | CFE_AUTOCOLOR );

   if( stLogFont.lfWeight < FW_BOLD )
      stCharFormat.dwEffects &= ~CFE_BOLD;

   if( !stLogFont.lfItalic )
      stCharFormat.dwEffects &= ~CFE_ITALIC;

   if( !stLogFont.lfUnderline )
      stCharFormat.dwEffects &= ~CFE_UNDERLINE;

   if( !stLogFont.lfStrikeOut )
      stCharFormat.dwEffects &= ~CFE_STRIKEOUT;

   stCharFormat.dwMask = CFM_ALL | CFM_BACKCOLOR | CFM_STYLE;
   stCharFormat.bCharSet = stLogFont.lfCharSet;
   stCharFormat.bPitchAndFamily = stLogFont.lfPitchAndFamily;
   stCharFormat.yHeight = -stLogFont.lfHeight * 1440 / GetDeviceCaps( hDC, LOGPIXELSY );
   MultiByteToWideChar( CP_ACP, 0, stLogFont.lfFaceName, LF_FACESIZE, stCharFormat.szFaceName, LF_FACESIZE );

   /* Creamos el formato de párrafo por defecto. */
   memset( &stParaFormat, 0, sizeof( PARAFORMAT ) );
   stParaFormat.cbSize = sizeof( PARAFORMAT );
   stParaFormat.dwMask = PFM_ALL;
    stParaFormat.wAlignment = PFA_LEFT;
    stParaFormat.cTabCount = 1;
    stParaFormat.rgxTabs[ 0 ] = lDefaultTab;

   /* Instanciamos nuestro objeto host. */
   pTextHost = new TTextHost;
   pTextHost->FCharFormat = &stCharFormat;
   pTextHost->FParaFormat = &stParaFormat;

   /* Creamos el objeto IUnknown y lo asociamos a nuestro objeto TTextHost. */
   if( pCreateTextServices( NULL, pTextHost, &pUnknown ) != S_OK )
   {
      delete pTextHost;
      FreeLibrary( hDLL );

      return;
   }

   /* Obtenemos el interface ITextServices. */
   pTextServices = NULL;
   pUnknown->QueryInterface( IID_ITextServices, ( void ** ) &pTextServices );
   
   /* Liberamos el objeto IUnknown. */
   pUnknown->Release();

   if( pTextServices != NULL )
   {
//      sRtfTextInfo.szText = "Plaint Text";
      sRtfTextInfo.szText = "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Tahoma;}{\\f1\\fswiss\\fcharset0 Arial;}}{\\colortbl ;\\red128\\green0\\blue0;\\red0\\green0\\blue128;\\red0\\green128\\blue0;}\\viewkind4\\uc1\\pard\\f0\\fs20 H\\fs24 E\\b L\\ul\\fs20 L\\i O\\ulnone\\b0\\i0   \\cf1 W\\b\\fs22 O\\cf2\\ul\\b0 R\\i\\fs28 L\\cf3\\ulnone\\b\\i0\\fs20 D\\cf0\\b0\\f1\\par}";
      sRtfTextInfo.lSize = lstrlen( sRtfTextInfo.szText );
      sRtfTextInfo.lCount = 0;
      stEditStream.dwCookie = ( DWORD_PTR ) &sRtfTextInfo;
      stEditStream.pfnCallback = EditStreamCallback;

//      if( pTextServices->TxSendMessage( EM_STREAMIN, SF_TEXT, ( LPARAM ) &stEditStream, &lResult ) == S_OK )
      if( pTextServices->TxSendMessage( EM_STREAMIN, SF_RTF, ( LPARAM ) &stEditStream, &lResult ) == S_OK )
         pTextServices->TxDraw( DVASPECT_CONTENT, 0, NULL, NULL, hDC, NULL, ( RECTL * ) &stRect, NULL, NULL, NULL, 0, TXTVIEW_INACTIVE );

      /* Liberamos el objeto ITextServices. */
      pTextServices->Release();
   }

   delete pTextHost;
   FreeLibrary( hDLL );
}
于 2022-02-12T19:13:21.923 回答