Create Richedit Controls
//=============================================================================
//RICHEDIT CONTROLS - Copyright © 2000,2005 Ken Fitlike
//=============================================================================
//API functions used: CreateWindowEx,DefWindowProc,DispatchMessage,GetMessage,
//GetSystemMetrics,GetVersionEx,LoadImage,LoadLibrary,MessageBox,
//PostQuitMessage,RegisterClassEx,ShowWindow,UpdateWindow,TranslateMessage,
//WinMain.
//=============================================================================
//Demonstrates the creation of a richedit control.
//=============================================================================
#include <windows.h>  //include all the basics
#include <tchar.h>    //string and other mapping macros
#include <richedit.h> //to use richedit control
#include <string>

//define an unicode string type alias
typedef std::basic_string<TCHAR> ustring;
//=============================================================================
//define v4.1 richedit control class name if necessary
#if !defined MSFTEDIT_CLASS
#define MSFTEDIT_CLASS L"RICHEDIT50W"
#endif
//=============================================================================
//message processing function declarartions
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int OnCreate(const HWND,CREATESTRUCT*);

//non-message function declarations
HWND CreateRichedit(const HWND,const HINSTANCE,DWORD,const RECT&,const int,
                    const ustring&,const ustring&);                    
inline int ErrMsg(const ustring&);          
bool IsWinxpSp1Min();
ustring GetRicheditClassName();

//setup some edit control id's
enum {
  IDCRE_RICHEDIT=200
};
//=============================================================================
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE,LPSTR pStr,int nCmd)
{
ustring classname=_T("SIMPLEWND");
WNDCLASSEX wcx={0};  //used for storing information about the wnd 'class'

wcx.cbSize         = sizeof(WNDCLASSEX);           
wcx.lpfnWndProc    = WndProc;             //wnd procedure pointer
wcx.hInstance      = hInst;               //app instance
//use 'LoadImage' to load wnd class icon and cursor as it supersedes the 
//obsolete functions 'LoadIcon' and 'LoadCursor', although these functions will 
//still work. Because the icon and cursor are loaded from system resources ie 
//they are shared, it is not necessary to free the image resources with either 
//'DestroyIcon' or 'DestroyCursor'.
wcx.hIcon         = reinterpret_cast<HICON>(LoadImage(0,IDI_APPLICATION,
                                            IMAGE_ICON,0,0,LR_SHARED));
wcx.hCursor       = reinterpret_cast<HCURSOR>(LoadImage(0,IDC_ARROW,
                                              IMAGE_CURSOR,0,0,LR_SHARED));
wcx.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BTNFACE+1);   
wcx.lpszClassName = classname.c_str(); 
//the window 'class' (not c++ class) has to be registered with the system
//before windows of that 'class' can be created
if (!RegisterClassEx(&wcx))
  {
  ErrMsg(_T("Failed to register wnd class"));
  return -1;
  }

int desktopwidth=GetSystemMetrics(SM_CXSCREEN);
int desktopheight=GetSystemMetrics(SM_CYSCREEN);

HWND hwnd=CreateWindowEx(0,                      //extended styles
                         classname.c_str(),      //name: wnd 'class'
                         _T("Richedit Controls"),//wnd title
                         WS_OVERLAPPEDWINDOW,    //wnd style
                         desktopwidth/4,         //position:left
                         desktopheight/4,        //position: top
                         desktopwidth/2,         //width
                         desktopheight/2,        //height
                         0,                      //parent wnd handle
                         0,                      //menu handle/wnd id
                         hInst,                  //app instance
                         0);                     //user defined info
if (!hwnd)
  {
  ErrMsg(_T("Failed to create wnd"));
  return -1;
  }

ShowWindow(hwnd,nCmd); 
UpdateWindow(hwnd);
//start message loop - windows applications are 'event driven' waiting on user,
//application or system signals to determine what action, if any, to take. Note 
//that an error may cause GetMessage to return a negative value so, ideally,  
//this result should be tested for and appropriate action taken to deal with 
//it(the approach taken here is to simply quit the application).
MSG msg;
while (GetMessage(&msg,0,0,0)>0)
  {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
  }
return static_cast<int>(msg.wParam);
}
//=============================================================================
LRESULT CALLBACK WndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch (uMsg)
  {
  case WM_CREATE:
    return OnCreate(hwnd,reinterpret_cast<CREATESTRUCT*>(lParam));
  case WM_DESTROY:
    PostQuitMessage(0);    //signal end of application
    return 0;
  default:
    //let system deal with msg
    return DefWindowProc(hwnd,uMsg,wParam,lParam);  
  }
}
//=============================================================================
int OnCreate(const HWND hwnd,CREATESTRUCT *cs)
{
//handles the WM_CREATE message of the main, parent window; return -1 to fail
//window creation
RECT rc={10,10,220,200};

CreateRichedit(hwnd,cs->hInstance,0,rc,IDCRE_RICHEDIT,_T("Richedit control"),
               GetRicheditClassName());

return 0;
}
//=============================================================================
HWND CreateRichedit(const HWND hParent,const HINSTANCE hInst,DWORD dwStyle,
                    const RECT& rc,const int id,const ustring& caption,
                    const ustring& classname)
{
dwStyle|=WS_CHILD|WS_VISIBLE;
ustring cap=caption + _T(" - ") + classname;
return CreateWindowEx(WS_EX_CLIENTEDGE,             //extended styles
                      classname.c_str(),            //control 'class' name
                      cap.c_str(),                  //control caption
                      dwStyle,                      //control style 
                      rc.left,                      //position: left
                      rc.top,                       //position: top
                      rc.right,                     //width
                      rc.bottom,                    //height
                      hParent,                      //parent window handle
                      //control's ID
                      reinterpret_cast<HMENU>(static_cast<INT_PTR>(id)),
                      hInst,                        //application instance
                      0);                           //user defined info
}
//=============================================================================
inline int ErrMsg(const ustring& s)
{
return MessageBox(0,s.c_str(),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
}
//=============================================================================
bool IsWinxpSp1Min()
{
//return true if operating sytem is winxpsp1(windows xp, service pack 1) or 
//later. Winxpsp1 is the minimum system required to use a richedit v4.1 but 
//only when UNICODE is defined. Use GetVersionEx rather than later system
//determining or verification functions to ensure backward compatibility with
//win9x.
OSVERSIONINFO osvi={0};
osvi.dwOSVersionInfoSize=sizeof(osvi);

if (!GetVersionEx(&osvi))
  {
  ErrMsg(_T("GetVersionEx failed"));
  return false;
  }
//determine if system is winxp minimum
if (osvi.dwMajorVersion>=5 && osvi.dwMinorVersion>=1)
  {
  //now check if system is specifically winxp and, if so, what service
  //pack version
  if (osvi.dwMajorVersion==5 && osvi.dwMinorVersion==1)
    {
    //The following test assumes that the szCSDVersion member of the 
    //OSVERSIONINFO struct's format will always be a string like 
    //"Service Pack x", where 'x' is a number >=1. This is fine for sp1 and 
    //sp2 but future service packs may have a different string descriptor.
    ustring test=_T("Service Pack 1");
    if (osvi.szCSDVersion>=test)
      {
      return true;
      }
    else
      {
      return false; //pre-winxpsp1
      }
    }
  return true;
  }

return false;
}
//=============================================================================
ustring GetRicheditClassName()
{
HINSTANCE hLib;

//try to load latest version of rich edit control. Since v4.1 is available only 
//as an UNICODE control on a minimum of winxp with service pack 1 (sp1) 
//installed, use ugly preprocessor conditional to ensure that an attempt to 
//load Msftedit.dll is only made if UNICODE is defined.
#if defined UNICODE
if (IsWinxpSp1Min())
  {
  //try to get richedit v4.1, explicitly use wide character string as this is 
  //UNICODE only
  hLib=LoadLibrary(L"Msftedit.dll"); 
  if (hLib)
    {
    return MSFTEDIT_CLASS;
    }
  }
#endif

//can't get latest version (v4.1) so try to get earlier one
hLib=LoadLibrary(_T("Riched20.dll")); //Rich Edit Version 2.0/3.0
if (!hLib)
  {
  hLib=LoadLibrary(_T("Riched32.dll")); //Rich Edit Version 1.0
  if (!hLib)
    {
    //can't get this version so inform user
    ErrMsg(_T("Failed to load any richedit library"));
    return _T("");
    }
  else    //version 1.0 is good
    {
    return _T("RichEdit");
    }
  }
//version 2.0/3.0 is good
return RICHEDIT_CLASS;
}
//=============================================================================