/******************************************************************************
*                                                                             *
*  RichEdit example program. Demonstrates some basics of a RichEdit control.  *
*     Allows you to change the text color on the fly, save and load RTF data  *
*     using stream callbacks.                                                 *
*                                                                             *
******************************************************************************/

#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#include "commdlg.h"
#include "richedit.h"

// === Function Prototypes ====================================================

BOOL WINAPI MainDlgProc( HWND, UINT, WPARAM, LPARAM );
BOOL SaveEditAsStream( HWND );
DWORD CALLBACK RTFSaveStreamCallback( DWORD, LPBYTE, LONG, LONG * );
BOOL LoadEditAsStream( HWND );
DWORD CALLBACK RTFLoadStreamCallback( DWORD, LPBYTE, LONG, LONG * );
BOOL GetNewTextColor( HWND );

// === Global Variables =======================================================

HINSTANCE hInst;                                    //  Program instance handle
HANDLE hRichEdit;                                       //  RICHED32.DLL handle
DWORD dwTextColor;                                       //  Current text color

// === Program Entry Points ===================================================

int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmd,
                     int nShow )
{
  hInst = hInstance;                       //  Save program instance in global
  hRichEdit = LoadLibrary( "RICHED32.DLL" );        //  Load Rich Edit control
  if( ! hRichEdit )
  {                                      //  If Rich Edit DLL load fails, exit
     MessageBox( NULL, "Unable to load the Rich Edit control!",
                 "RETest", MB_OK | MB_ICONEXCLAMATION );
     return( FALSE );
  }
                                                      //  Call main dialog box
  DialogBox( hInst, MAKEINTRESOURCE( 10000 ), NULL, MainDlgProc );

  FreeLibrary( hRichEdit );           //  Release Rich Edit DLL before leaving
  return( FALSE );
}

// === Main Dialog Proc =======================================================

BOOL WINAPI MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
  switch( msg )
  {
     case WM_INITDIALOG:
     {
        CHARFORMAT cf;

        if( GetDlgItem( hDlg, 100 ) )                         //  Sanity Check
        {
           dwTextColor = 0x0000FF00;

           memset( &cf, 0, sizeof(CHARFORMAT) );      //  Initialize structure

           cf.cbSize = sizeof(CHARFORMAT);             //  Initialize RichEdit
           cf.dwMask = CFM_COLOR | CFM_FACE | CFM_SIZE;  //  control structure
           cf.crTextColor = dwTextColor;
           cf.yHeight = 32;
           strcpy( cf.szFaceName, "Courier" );
                             //  Set character formatting and background color
           SendDlgItemMessage( hDlg, 100, EM_SETCHARFORMAT, 4, (LPARAM)&cf );
           SendDlgItemMessage( hDlg, 100, EM_SETBKGNDCOLOR, FALSE, 0 );
        }
        return( TRUE );                  //  End of dialog initialization code
     }

     case WM_COMMAND:
        if( wParam == 101 )                         //  "Color" button pressed
        {
           GetNewTextColor( hDlg );                 //  Get new color for text
           SetFocus( GetDlgItem( hDlg, 100 ) );       //  Back to edit control
           break;
        }
        if( wParam == 102 )                          //  "Save" button pressed
        {
           SaveEditAsStream( hDlg );       //  Save rich edit contents to file
           SetFocus( GetDlgItem( hDlg, 100 ) );       //  Back to edit control
           break;
        }
        if( wParam == 103 )                          //  "Load" button pressed
        {
           LoadEditAsStream( hDlg );           //  Load RTF file into richedit
           SetFocus( GetDlgItem( hDlg, 100 ) );       //  Back to edit control
           break;
        }
        if( wParam == IDCANCEL )               //  Close dialog if Esc pressed
        {
           EndDialog( hDlg, TRUE );
           return( TRUE );
        }
        break;
  }
  return( FALSE );
}                                                        //  End of MainDlgProc

// === Read RTF Data as a Rich Edit stream ====================================

BOOL SaveEditAsStream( HWND hDlg )
{
  EDITSTREAM es;
  LONG lOut;
  OPENFILENAME ofn;
  HANDLE hFile;
  char szFilename[ 256 ];


  memset( &ofn, 0, sizeof(OPENFILENAME) );            //  Initialize structure
  strcpy( szFilename, "*.rtf" );                 //  Initialize filename field

  ofn.lStructSize = sizeof(OPENFILENAME);      //  Fill in OPENFILENAME struct
  ofn.hwndOwner = hDlg;
  ofn.lpstrFilter = "RTF File\0*.rtf\0All Files\0*.*\0\0";
  ofn.lpstrFile = szFilename;
  ofn.nMaxFile = 256;
  ofn.lpstrTitle = "Save RTF File";
  ofn.Flags = OFN_OVERWRITEPROMPT;
  if( ! GetSaveFileName( &ofn ) )                   //  Get a filename or quit
     return( FALSE );
                                                 //  Create the specified file
  hFile = CreateFile( szFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
                      CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  if( hFile == INVALID_HANDLE_VALUE )
     return( FALSE );                          //  Quit if file creation fails

  es.dwCookie = (DWORD)hFile;                 //  Pass file handle to callback
  es.dwError = 0;                    //  so the callback can do the file write
  es.pfnCallback = (EDITSTREAMCALLBACK)RTFSaveStreamCallback;
                                                   //  Start the callback proc
  lOut = SendDlgItemMessage( hDlg, 100, EM_STREAMOUT, SF_RTF, (LPARAM)&es );

  CloseHandle( hFile );                         //  Close file handle and exit
  return( TRUE );
}                                                   //  End of SaveEditAsStream

// === RichEdit RTF Output Stream Handler =====================================

DWORD CALLBACK RTFSaveStreamCallback( DWORD dwCookie, LPBYTE lpBuffer,
                                     LONG lSize, LONG *plRead )
{
  if( ! lSize )                      //  Sanity check...exit if nothing passed
     return( 1 );

  *plRead = 0;           //  Initialize "amount read" variable for WriteFile()
                                               //  dwCookie is the file handle
  WriteFile( (HANDLE)dwCookie, lpBuffer, lSize, plRead, NULL );
  return( 0 );                                         //  Continue, if needed
}

// === Load RTF File into Rich Edit Control ===================================

BOOL LoadEditAsStream( HWND hDlg )
{
  EDITSTREAM es;
  LONG lOut;
  OPENFILENAME ofn;
  HANDLE hFile;
  char szFilename[ 256 ];


  memset( &ofn, 0, sizeof(OPENFILENAME) );  //  Initialize OPENFILENAME struct
  strcpy( szFilename, "*.rtf" );                 //  Initialize filename field

  ofn.lStructSize = sizeof(OPENFILENAME);                //  Fill in structure
  ofn.hwndOwner = hDlg;
  ofn.lpstrFilter = "RTF File\0*.rtf\0All Files\0*.*\0\0";
  ofn.lpstrFile = szFilename;
  ofn.nMaxFile = 256;
  ofn.lpstrTitle = "Open RTF File";
  ofn.Flags = OFN_FILEMUSTEXIST;
  if( ! GetOpenFileName( &ofn ) )                    //  Get file name or exit
     return( FALSE );
                                             // Attempt to open specified file
  hFile = CreateFile( szFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
                      OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  if( hFile == INVALID_HANDLE_VALUE )
     return( FALSE );                                   //  Exit if open fails

  es.dwCookie = (DWORD)hFile;                 //  Pass file handle to callback
  es.dwError = 0;
  es.pfnCallback = (EDITSTREAMCALLBACK)RTFLoadStreamCallback;
                                                   //  Start the callback proc
  lOut = SendDlgItemMessage( hDlg, 100, EM_STREAMIN, SF_RTF, (LPARAM)&es );

  CloseHandle( hFile );                   //  Close file handle before leaving
  return( TRUE );
}

// === RichEdit RTF Input Stream Handler ======================================

DWORD CALLBACK RTFLoadStreamCallback( DWORD dwCookie, LPBYTE lpBuffer,
                                     LONG lSize, LONG *plRead )
{
  if( ! lSize )                      //  Sanity check...exit if nothing passed
     return( 1 );

  *plRead = 0;                             //  Initialize amount read variable
                                               //  dwCookie is the file handle
  ReadFile( (HANDLE)dwCookie, lpBuffer, lSize, plRead, NULL );
  return( 0 );
}

// === Specify New Text Color =================================================

BOOL GetNewTextColor( HWND hDlg )
{
  CHOOSECOLOR cc;
  CHARFORMAT cf;
  DWORD dwColors[ 16 ];


  memset( &cc, 0, sizeof(CHOOSECOLOR) );
  cc.lStructSize = sizeof(CHOOSECOLOR);
  cc.hwndOwner = hDlg;
  cc.lpCustColors = dwColors;
  cc.Flags = CC_RGBINIT;
  cc.rgbResult = dwTextColor;

  if( ! ChooseColor( &cc ) )
     return( FALSE );

  dwTextColor = cc.rgbResult;

  memset( &cf, 0, sizeof(CHARFORMAT) );
  cf.cbSize = sizeof(CHARFORMAT);
  cf.dwMask = CFM_COLOR;
  cf.crTextColor = dwTextColor;

  SendDlgItemMessage( hDlg, 100, EM_SETCHARFORMAT,
                      SCF_SELECTION, (LPARAM)&cf );

  return( TRUE );
}

// ============================================================================