Tag Archives: MFC

Article in Technical Magazine Programmez N° 219 – June 2018

May be in next June edition of french magazine Programmez, an article about creating a Windows Service. All the plumbing ! The second part will explain how to host a deamon inside and respond to external communication.

VSDemo App Version 1.1 January 2018

My light weight IDE is updated…  The download link is always: www.windowscpp.com/Appz/VSDemo.zip

The source code is on GitHub : https://github.com/ChristophePichaud/VSDemo

You can build the source code and run the program. The code is compiled using Roslyn compiler which is shipped into the package.

An IDE made with C++ and MFC – Part II

For the January 2018 edition of the french magazine Programmez, I have written an article about building an IDE with open-source project Scintilla and Roslyn, the Microsoft C# compiler. My goal is that my daughter Lisa, 12 ans, can begin learning software development on it. The code is available on GitHub: https://github.com/ChristophePichaud/VSDemo

 

VSDemo is now upgraded with many features…

“Open Folder” is the best feature of the IDE:

But if you want more comfort, check Enable Full-Screen :

All of the magic is done by the MFC framework. It’s beautiful and cool. :)

Open Folder feature done in my IDE

Look at that:

It’s an important feature to have software’s adoption.

 

Make your own IDE in C++

For the december edition of programmez n°213, I have written an article and developped an IDE using MFC and C++.

Mission at Sydev 21 Burgundy Area

This week, I will deliver 5 days about a hot session on C++ Windows Programming using MFC.

Goal: plan to migrate a Win32 C messages app to a MFC app with Ribbon, Properties Grid and more.

 

My IDE light is coming… hot !

I have made some improvments to the Visual Studio Demo App. The Scintilla MFC wrappers from naughter.com are used. Stay tuned…

 

Download UltraFluid modeler

You can download my application here:

http://www.windowscpp.com/Appz/UltraFluid_Modeler.zip

In the archive there are 2 main folders: bin and images. I have also created a shortcut. Adjust the shortcut to start the app located in bin but place the working directory on the upper folder.

I have a little bug on displaying images by setting the current folder. It will be fixed sooner.

To run the application, you must have vcredist from VS2015. These dll are not distributed in the zip archive.

ultrafluid_modeler_2

Updating Scintilla open-source project and Naughter’s wrappers and Boost 1.63

When I have updated Scintilla’s wrappers written by Naughter, I encountered compilation errors…
This the MFC class view that operates with the scintilla control. I need to update that class too. But first of all, I need to update Boost. Current version is 1.63. Just compile it with bjam. Classic stuff. Result is in stage\lib folder.

boost_stage_lib_163

For the moment I use Boost only for serialization stuff for XML stuff.

modeler1_saveasxml

Here is a XML file:

modeler1_data_xml

Boost serialization is not easy because it is designed that data has to be read by a Boost app…

Using open-source libraries for MyModeler C++ project

I will make some enhancements to my modeler project (http://ultrafluid.codeplex.com). I have moved to Visual Studio online.

image001

MyModeler

My project use three open-source projects:

– Scintilla (http://www.scintilla.org/)

– MFC Naughter classes to encapsulate Scintilla edit control with MFC (http://www.naughter.com/scintilla.html)

– Boost (http://www.boost.org/)

My project was primary built in the 2012′. It was an idea to make my daughter Lisa able to place elements with the mouse.
It is a family project. It was also an free-time occupation when I was consultant for the “Banque de France” to build Architecture diagrams.
The initial goal of the project is to build diagrams with individual shapes elements. These elements contains properties and everything is store in a database.
Then, it is possible to make requests to find things. For the moment, I have no database. I need to implement that part of the software.

First surprise when I rebuilt the project with the latest version of Scintilla, the Naughter classes produced C++ compilation errors.
I needed to get the latest classes but also make some minor corrections (hide the code of 2 methods).
For boost, I have a version 1.59 on my computer and I have no evidence to jump to the latest version because I just use serialization and XML stuff which belong to a very stable library : serialization.

I rebuilt the project and it just works. The project updated to MSVC140 build tools with Visual Studio 2015.
This is the magic of C++ : it works along all theses years… But my open-source libraries has evolved and most of the time, getting an updated version can bring some changes.
In my case, the Naughter MFC classes depends on Scintilla project so the GET operation must assure that the 2 projects are synced.

Upgrading my MFC project and Boost to Visual C++ 2013

First of all, my modeler project hosted at codeplex is compiled with Visual C++ 2012 and vc10 compiler toolset. Why the vc10 compiler ? I use Boost serialization library and sourceforge gives me a static lib called libboost_serialization-vc100-mt-gd-1_51.lib built using vc10. Switching to Visual Studio 2013, I decided to build every thing with Visual C++ 2013, even boost.

First step : building Boost

My project use Boost 1.51 and there are some issue with Boost latest version 1.55 with the serialization library and vc12 (Visual C++ 2013) so I stay with Boost 1.51. There are two commands to launch. The first is bootstrap.bat and the second one is:

> bjam toolset=msvc-12.0 variant=debug,release threading=multi link=shared

The result is in the boost \ stage \ lib folder.

Second step: updating MFC setup

Download the MFC120.dll regular dll from http://www.microsoft.com/en-us/download/details.aspx?id=40770. If your project is built with Unicode character set, it will go OK but if you use not set or multibyte, you can’t compile…

Third step: modify Boost includes to handle a proper link to vc12

Modify the boost_1_51_0\boost\config\auto_link.hpp to handle vc12 (Visual C++ 2013). Add this line 158.

#elif defined(BOOST_MSVC) && (BOOST_MSVC == 1800)
// vc12:
#  define BOOST_LIB_TOOLSET “vc120”

Fourth step: modify my project to use Boost as Dynamic Library for Serialization library

In the stdafx.h, I just add the following defines before including Boost headers:

#define BOOST_SERIALIZATION_DYN_LINK TRUE
#define BOOST_ALL_DYN_LINK TRUE

Implementing a full Ribbon in a native application (more)

Here is my ribbon in my application:

modeler1_ribbon

The first item to create is the circle button that acts as the file menu. It is done using CMFCRibbonMainPanel class.

Then you create a category called Home using CMFCRibbonCategory class.

After this step, you have to create panels using CMFCRibbonPanel class.

Inside your panel, you can create button, combo box and galley using CMFCRibbonButton class, CMFCRibbonComboBox class, CMFCRibbonGallery  class.

Here is the whole source code:


void CMainFrame::InitMainButton()
{
m_MainButton.SetImage(IDB_RIBBON_MAIN);
m_MainButton.SetToolTipText(_T("File"));
m_MainButton.SetText(_T("\nf"));

CreateDocumentColors();

m_wndRibbonBar.SetApplicationButton(&m_MainButton, CSize(45, 45));

CMFCRibbonMainPanel* pMainPanel = m_wndRibbonBar.AddMainCategory(_T("File"), IDB_RIBBON_FILESMALL, IDB_RIBBON_FILELARGE);
pMainPanel->Add(new CMFCRibbonButton(ID_FILE_NEW, _T("&New"), 0, 0));
pMainPanel->Add(new CMFCRibbonButton(ID_FILE_OPEN, _T("&Open..."), 1, 1));
pMainPanel->Add(new CMFCRibbonButton(ID_FILE_OPEN_AS_XML, _T("Open As XML..."), 1, 1));
pMainPanel->Add(new CMFCRibbonButton(ID_FILE_SAVE, _T("&Save"), 2, 2));
pMainPanel->Add(new CMFCRibbonButton(ID_FILE_SAVE_AS, _T("Save &As..."), 3, 3));
pMainPanel->Add(new CMFCRibbonButton(ID_FILE_SAVE_AS_XML, _T("Save As &XML..."), 3, 3));
pMainPanel->AddSeparator();
pMainPanel->Add(new CMFCRibbonButton(ID_FILE_CLOSE, _T("&Close"), 8, 8));
pMainPanel->AddRecentFilesList(_T("Recent Documents"));
pMainPanel->AddToBottom(new CMFCRibbonMainPanelButton(ID_APP_EXIT, _T("E&xit"), 27));

CMFCRibbonCategory* pCategory = m_wndRibbonBar.AddCategory(_T("&Home"), IDB_RIBBON_WRITESMALL, IDB_RIBBON_WRITELARGE);
// Create "Design" panel
CMFCRibbonPanel* pPanelDesign = pCategory->AddPanel(_T("Design\nzd"), m_PanelImages.ExtractIcon(2));
pPanelDesign->Add(new CMFCRibbonButton(ID_DESIGN_SELECT, _T("Select\nc"), 2));
//pPanelDesign->Add(new CMFCRibbonButton(ID_DESIGN_RECTANGLE, _T("Rectangle\ng"), 2));
//pPanelDesign->Add(new CMFCRibbonButton(ID_DESIGN_LINE, _T("Line\ng"), 2));
//pPanelDesign->Add(new CMFCRibbonButton(ID_DESIGN_ELLIPSE, _T("Ellipse\ng"), 2));

CMFCRibbonButton* pInsertPictureBtn = new CMFCRibbonButton(ID_DESIGN_IMAGE, _T("Picture"), 4, 4);
pPanelDesign->Add(pInsertPictureBtn);

CMFCRibbonGallery *pInsertShapesBtn = new CMFCRibbonGallery(ID_DESIGN_SHAPES, _T("Shapes"), 6, 6);
pInsertShapesBtn->SetButtonMode();
pInsertShapesBtn->SetIconsInRow(12);
pInsertShapesBtn->AddGroup(_T("Recently Used Shapes"), IDB_SHAPE1, 20);
pInsertShapesBtn->AddGroup(_T("Lines"), IDB_SHAPE2, 20);
pInsertShapesBtn->AddGroup(_T("Basic Shapes"), IDB_SHAPE3, 20);
pInsertShapesBtn->AddGroup(_T("Block Arrows"), IDB_SHAPE4, 20);
pInsertShapesBtn->AddGroup(_T("Flowchart"), IDB_SHAPE5, 20);
pInsertShapesBtn->AddGroup(_T("Callouts"), IDB_SHAPE6, 20);
pInsertShapesBtn->AddGroup(_T("Stars and Banners"), IDB_SHAPE7, 20);
pInsertShapesBtn->AddSubItem(new CMFCRibbonButton(ID_DESIGN_SHAPES_NEW, _T("&New Drawing Canvas"), 29, -1));
pPanelDesign->Add(pInsertShapesBtn);

CMFCRibbonButton* pBtnDrawText = new CMFCRibbonButton(ID_DESIGN_TEXTBOX, _T("Draw Text Box\nx"), 15, 15);
pBtnDrawText->SetMenu(IDR_DRAW_TEXT_MENU);
pPanelDesign->Add(pBtnDrawText);
// Add hidden button
pCategory->AddHidden(new CMFCRibbonButton(ID_TEXT_LEFT, _T("&Bottom Border"), 28));
pCategory->AddHidden(new CMFCRibbonButton(ID_TEXT_CENTER, _T("Paste Special"), 29));
pCategory->AddHidden(new CMFCRibbonButton(ID_TEXT_RIGHT, _T("Paste Special"), 30));
pCategory->AddHidden(new CMFCRibbonButton(ID_TEXT_JUSTIFY, _T("Paste Special"), 31));

CRibbonListButton *pListBtnInfra = new CRibbonListButton(ID_DESIGN_SHAPESINFRA, _T("Infrastructure\nti"), 20, -1, FALSE);
pListBtnInfra->AddGroup(_T("Built-In"), IDB_SHAPES_INFRA, 64, m_arInfraShapes);
pListBtnInfra->SetIconsInRow(4);
pListBtnInfra->EnableMenuResize();
pPanelDesign->Add(pListBtnInfra);

CRibbonListButton *pListBtnDev = new CRibbonListButton(ID_DESIGN_SHAPESDEV, _T("Development\ntd"), 35, -1, FALSE);
pListBtnDev->AddGroup(_T("Built-In"), IDB_SHAPES_DEV, 64, m_arInfraDev);
pListBtnDev->SetIconsInRow(4);
pListBtnDev->EnableMenuResize();
pPanelDesign->Add(pListBtnDev);

// Create "Debug" panel
CMFCRibbonPanel* pPanelDebug = pCategory->AddPanel(_T("Debug\nzd"), m_PanelImages.ExtractIcon(2));
pPanelDebug->Add(new CMFCRibbonButton(ID_DEBUG_DUMP_OBJECTS, _T("Dump Objects\nc"), 2));

CMFCRibbonButtonsGroup * apFontGroup = new CMFCRibbonButtonsGroup();
CMFCRibbonFontComboBox* pFontCombo = new CMFCRibbonFontComboBox(ID_FONT_FONT);
pFontCombo->SetWidth(55, TRUE); // Width in "floaty" mode
pFontCombo->SelectItem(10);
apFontGroup->AddButton(pFontCombo);

CMFCRibbonComboBox* pFontSizeCombo = new CMFCRibbonComboBox(ID_FONT_FONTSIZE, FALSE, 39);
pFontSizeCombo->AddItem(_T("8"));
pFontSizeCombo->AddItem(_T("9"));
pFontSizeCombo->AddItem(_T("10"));
pFontSizeCombo->AddItem(_T("11"));
pFontSizeCombo->AddItem(_T("12"));
pFontSizeCombo->AddItem(_T("14"));
pFontSizeCombo->AddItem(_T("16"));
pFontSizeCombo->AddItem(_T("18"));
pFontSizeCombo->AddItem(_T("20"));
pFontSizeCombo->AddItem(_T("22"));
pFontSizeCombo->AddItem(_T("24"));
pFontSizeCombo->AddItem(_T("26"));
pFontSizeCombo->AddItem(_T("28"));
pFontSizeCombo->AddItem(_T("36"));
pFontSizeCombo->AddItem(_T("48"));
pFontSizeCombo->AddItem(_T("72"));
pFontSizeCombo->SetWidth(20, TRUE); // Width in "floaty" mode
pFontSizeCombo->SelectItem(3);
apFontGroup->AddButton(pFontSizeCombo);

pPanelDebug->Add(apFontGroup);

// Create "Show/Hide" panel:
CMFCRibbonPanel* pPanelShow = pCategory->AddPanel(_T("Show/Hide\nzs"), m_PanelImages.ExtractIcon(4));
pPanelShow->Add(new CMFCRibbonCheckBox(ID_VIEW_FILE_VIEW, _T("Solution View\nc")));
pPanelShow->Add(new CMFCRibbonCheckBox(ID_VIEW_CLASS_VIEW, _T("Class View\nc")));
pPanelShow->Add(new CMFCRibbonCheckBox(ID_VIEW_PROPERTIES, _T("Properties View\np")));

// Create "Action" panel
CMFCRibbonPanel* pPanelAction = pCategory->AddPanel(_T("Action\nzd"), m_PanelImages.ExtractIcon(2));
pPanelAction->Add(new CMFCRibbonButton(ID_ACTION_REMOVE, _T("Remove\nc"), 12));
pPanelAction->Add(new CMFCRibbonButton(ID_ACTION_LOAD_MODULE, _T("Import .NET Module\nin"), 35));

// Create "Format" panel
CMFCRibbonPanel* pPanelFormat = pCategory->AddPanel(_T("Format and Style\nzd"), m_PanelImages.ExtractIcon(2));
CMFCRibbonColorButton * pBtnFillColor = new CMFCRibbonColorButton(ID_FORMAT_FILLCOLOR, _T("Fill Color\nsf"), FALSE, 1, -1);
pBtnFillColor->SetDefaultCommand(FALSE);
pBtnFillColor->EnableAutomaticButton(_T("&Automatic"), RGB(128, 128, 128));
pBtnFillColor->EnableOtherButton(_T("&More Fill Colors..."), _T("More Fill Colors"));
pBtnFillColor->SetColumns(10);
pBtnFillColor->SetColorBoxSize(CSize(17, 17));
pBtnFillColor->AddColorsGroup(_T("Theme Colors"), m_lstMainColors);
pBtnFillColor->AddColorsGroup(_T(""), m_lstAdditionalColors, TRUE);
pBtnFillColor->AddColorsGroup(_T("Standard Colors"), m_lstStandardColors);
pBtnFillColor->AddSubItem(new CMFCRibbonButton(ID_FORMAT_NOFILL, _T("&No Fill\nn"), -1));
pBtnFillColor->SetColor((COLORREF)-1);
pPanelFormat->Add(pBtnFillColor);

CMFCRibbonColorButton * pBtnLineColor = new CMFCRibbonColorButton(ID_FORMAT_LINECOLOR, _T("Line Color\nso"), FALSE, 3, -1);
pBtnLineColor->SetDefaultCommand(FALSE);
pBtnLineColor->EnableAutomaticButton(_T("&Automatic"), RGB(0, 0, 0));
pBtnLineColor->EnableOtherButton(_T("&More Line Colors..."), _T("More Line Colors"));
pBtnLineColor->SetColumns(10);
pBtnLineColor->SetColorBoxSize(CSize(17, 17));
pBtnLineColor->AddColorsGroup(_T("Theme Colors"), m_lstMainColors);
pBtnLineColor->AddColorsGroup(_T(""), m_lstAdditionalColors, TRUE);
pBtnLineColor->AddColorsGroup(_T("Standard Colors"), m_lstStandardColors);
pBtnLineColor->AddSubItem(new CMFCRibbonButton(ID_FORMAT_NOLINE, _T("&No Line\nn"), 2));
pBtnLineColor->SetColor((COLORREF)-1);
pPanelFormat->Add(pBtnLineColor);

CStringArray sa;
sa.Add(_T("1 pt"));
sa.Add(_T("2 pt"));
sa.Add(_T("3 pt"));
sa.Add(_T("4 pt"));
sa.Add(_T("5 pt"));
sa.Add(_T("6 pt"));
sa.Add(_T("7 pt"));

CRibbonListButton * pBtnLineWeight = new CRibbonListButton(ID_FORMAT_LINEWIDTH, _T("Line Width\nsw"), 4, -1, IDB_LINEWEIGHT, 96, sa);
pBtnLineWeight->AddSubItem(new CMFCRibbonButton(ID_FORMAT_LINEWIDTH_MORE, _T("More &Lines..."), 5, -1));
pBtnLineWeight->EnableMenuResize(TRUE, TRUE); // Vertical only
pPanelFormat->Add(pBtnLineWeight);

CMFCRibbonColorButton * pBtnPageColor = new CMFCRibbonColorButton(ID_FORMAT_PAGECOLOR, _T("Page Color\npo"), TRUE, -1, 26);
pBtnPageColor->SetDefaultCommand(FALSE);
pBtnPageColor->EnableAutomaticButton(_T("&Automatic"), RGB(0, 0, 0));
pBtnPageColor->EnableOtherButton(_T("&More Line Colors..."), _T("More Line Colors"));
pBtnPageColor->SetColumns(10);
pBtnPageColor->SetColorBoxSize(CSize(17, 17));
pBtnPageColor->AddColorsGroup(_T("Theme Colors"), m_lstMainColors);
pBtnPageColor->AddColorsGroup(_T(""), m_lstAdditionalColors, TRUE);
pBtnPageColor->AddColorsGroup(_T("Standard Colors"), m_lstStandardColors);
pPanelFormat->Add(pBtnPageColor);

pPanelFormat->Add(new CMFCRibbonButton(ID_FORMAT_ZOOM_IN, _T("Zoom In\ni"), -1));
pPanelFormat->Add(new CMFCRibbonButton(ID_FORMAT_ZOOM_OUT, _T("Zoom Out\no"), -1));
CMFCRibbonComboBox *pBtnZoom = new CMFCRibbonComboBox(ID_FORMAT_ZOOM, FALSE, 50, _T("Zoom: "), -1);
pBtnZoom->AddItem(_T("100 %"));
pBtnZoom->AddItem(_T("150 %"));
pBtnZoom->AddItem(_T("200 %"));
pBtnZoom->AddItem(_T("400 %"));
pBtnZoom->AddItem(_T("25 %"));
pBtnZoom->AddItem(_T("50 %"));
pBtnZoom->AddItem(_T("75 %"));
pBtnZoom->SelectItem(0);
pPanelFormat->Add(pBtnZoom);

// Create "Position" panel
CMFCRibbonPanel* pPanelPosition = pCategory->AddPanel(_T("Position\nzd"), m_PanelImages.ExtractIcon(2));
pPanelPosition->Add(new CMFCRibbonButton(ID_POSITION_MOVETOFRONT, _T("Move to Front\nc"), -1, 22));
pPanelPosition->Add(new CMFCRibbonButton(ID_POSITION_MOVEFORWARD, _T("Move Forward\nc"), -1, 24));
pPanelPosition->Add(new CMFCRibbonButton(ID_POSITION_MOVEBACKWARD, _T("Move Backward\nc"), -1, 25));
pPanelPosition->Add(new CMFCRibbonButton(ID_POSITION_MOVETOBACK, _T("Move to Back\nc"), -1, 23));
}
<pre>

See more on codeplex here : https://ultrafluid.codeplex.com/SourceControl/latest#Modeler1/MainFrm.cpp

Implementing a ribbon using C++ in native app

In my modeler, I have a Ribbon with pictures inside.

Ribbon_Infrastructure

To build it, you need some code.

        CRibbonListButton *pListBtnInfra = new CRibbonListButton(ID_DESIGN_SHAPESINFRA, _T("Infrastructure\nti"), 20, -1, FALSE);
	pListBtnInfra->AddGroup(_T("Built-In"), IDB_SHAPES_INFRA, 64, m_arInfraShapes);
	pListBtnInfra->SetIconsInRow(4);
	pListBtnInfra->EnableMenuResize();
	pPanelDesign->Add(pListBtnInfra);

The class CRibbonListButton  provides a simple way to load a full bitmap and display each part of it in a cell. IBD_SHAPES_INFRA is defined in the resource file as a PNG in res\ShapesInfra.png

ShapesInfra

To handle the click on the ribbon in your view, you just have to retrieve the ID of the clicked bitmap using CMFCRibbonGallery::GetLastSelectedItem().

void CModeler1View::OnModelingInfrastructure()
{
	// TODO: Add your command handler code here
	GetManager()->m_type = ElementType::type_shapes_infrastructure;
	int shapeId = CMFCRibbonGallery::GetLastSelectedItem(ID_DESIGN_SHAPESINFRA);
	GetManager()->m_shapeType = CShapeType::ToShapeType(OffsetShapes_Infrastructure + shapeId);

	//CString str;
	//str.Format("shapeId=%d m_shapeType=%d", shapeId, GetManager()->m_shapeType);
	//AfxMessageBox(str);
}

 

Compiling MFC from command line using NMAKE

One interesting point using Visual C++ 2010 samples is contained in the MFC folder. You can build mfc samples using a makefile using this command: nmake -a -f makefile. The makefile file just contains your obj files, and then the RC part. Then you #include mfcsamps.mak and that’s all.

Sample:

PROJ=MODELER1
OBJS=AppInit.obj CalendarBar.obj ChildFrm.obj ClassView.obj \
Data.obj \
DrawingContext.obj DrawingElements.obj \
Element.obj ElementContainer.obj ElementFactory.obj ElementManager.obj  \
FileView.obj MainFrm.obj Modeler1.obj Modeler1Doc.obj  \
Modeler1SourceView.obj Modeler1View.obj OutputWnd.obj PropertiesWnd.obj RibbonListButton.obj SourceCodeView.obj TabbedView.obj \
ScintillaCtrl.obj ScintillaDocView.obj

USES_OLE=1

!include <mfcsamps.mak>

# Update the resource if necessary
Modeler1.res: Modeler1.rc resource.h
    rc $(rcflags) $(rcvars) -r -fo Modeler1.res Modeler1.rc

The project is named Modeler1 and the first part of the makefile contains the obj files. You take your cpp files and you write them using the obj extension. Next, the RC part is dedicated for resources.

The MFCSAMPS.MAK file is include into Microsoft Visual Studio\VC\ATLMFC\INCLUDE folder.

OK, now enter the logging libraries area

In 1997, I made a web server for a regional bank using Visual C++ and MFC ISAPI. A great great great experience. You think than now you have ASP.NET but the real hardcore stuff are below, and ISAPI bring this. MFC ISAPI is a wonderfull technology. You have to respect every aspect of the web server. You have to provide your own mechanism for every thing from log to session stuff.

enum Mode

{

debug,

error

};

#define LogError(X,Y) Log(X,Y,__FILE__,__LINE__, error)

#define LogDebug(X,Y) Log(X,Y,__FILE__,__LINE__, debug)

class CInternetTrace

{

public:

static Mode m_Mode;

static int m_iCptRef;

static CString m_PathDirectory;

public:

_CERAPI_ CInternetTrace(CString strServiceName);

_CERAPI_ ~CInternetTrace();

_CERAPI_ void Log(LPCSTR szMethod,LPCSTR szMsg, LPCSTR szFile, int iLine, Mode modeAEcrire);

_CERAPI_ void Log2(LPCSTR szMethod,LPCSTR szMsg, LPCSTR szFile, int iLine, Mode modeAEcrire);

_CERAPI_ void Init(CString strServiceName);

};

#define INT_TRACE(x) \

{ \

CInternetTrace theTrace(&quot;Internet&quot;); \

theTrace.LogDebug(x,&quot;&quot;); \

} \

int CInternetTrace::m_iCptRef=0;

CString CInternetTrace::m_PathDirectory;

Mode CInternetTrace::m_Mode=debug;

static CInternetTrace theTrace(TRACE_INTERNET);

//////////////////////////////////////////////////////////////////

// CInternetTrace

//////////////////////////////////////////////////////////////////

BOOL GetRegValue(char *szChemin, char *szValeur, UCHAR *szBuffer)

{

CerRegKey RegKey(HKEY_LOCAL_MACHINE);

DWORD dwCount;

dwCount=256;

if(RegKey.OpenSubKey(szChemin,&amp;RegKey,KEY_READ) == FALSE)

return FALSE;

RegKey.GetValue(szValeur,(UCHAR *)szBuffer,&amp;dwCount);

RegKey.Close();

return TRUE;

}

CInternetTrace::CInternetTrace(CString strServiceName)

{

if( m_iCptRef==0 )

{

csTrace.Unlock();

Init(strServiceName);

}

m_iCptRef++;

}

CInternetTrace::~CInternetTrace()

{

m_iCptRef--;

}

void CInternetTrace::Init(CString strServiceName)

{

char szBuf[256];

if( GetRegValue(REG_TRACE, &quot;Path&quot;,(UCHAR *)szBuf) == FALSE)

m_PathDirectory = &quot;d:\\srv\\trace&quot;;

else

m_PathDirectory.Format(&quot;%s\\%s&quot;,szBuf,&quot;CI&quot;); //strServiceName);

if( GetRegValue(REG_TRACE, (LPSTR)(LPCSTR)strServiceName,(UCHAR *)szBuf) == FALSE)

m_Mode = debug;

else

{

CString Level;

Level = szBuf;

Level.MakeUpper();

if( Level == &quot;ERROR&quot; )

m_Mode = error;

else

m_Mode = debug;

}

}

void CInternetTrace::Log(LPCSTR szMethod,LPCSTR szMsg, LPCSTR szFile, int iLine, Mode modeAEcrire)

{

try

{

if( (modeAEcrire == debug) &amp;&amp; (m_Mode == error) )

return;

csTrace.Lock();

CTime t=CTime::GetCurrentTime();

CString str;

str.Format(&quot;%02d/%02d/%02d %02d:%02d:%02d, %s, %s, %s, %d\n&quot;, t.GetDay(), t.GetMonth(), t.GetYear()%100, t.GetHour(), t.GetMinute(), t.GetSecond(), szMethod, szMsg, szFile, iLine);

CString strFileName;

strFileName.Format(&quot;%s%02d%02d%02d.txt&quot;,m_PathDirectory,t.GetDay(), t.GetMonth(), t.GetYear()%100);

CStdioFile file;

HANDLE hFileExist;

WIN32_FIND_DATA data;

hFileExist=FindFirstFile( strFileName, &amp;data );

if( hFileExist==INVALID_HANDLE_VALUE )

{

if( file.Open(strFileName, CFile::modeWrite | CFile::modeCreate | CFile::typeText)==FALSE )

{

FindClose(hFileExist);

Log2(szMethod, szMsg, szFile, iLine, modeAEcrire);

csTrace.Unlock();

return;

}

}

else

{

if( file.Open(strFileName, CFile::modeReadWrite | CFile::typeText)==FALSE )

{

FindClose(hFileExist);

Log2(szMethod, szMsg, szFile, iLine, modeAEcrire);

csTrace.Unlock();

return;

}

}

//CStdioFile file;

//if( file.Open(strFileName, CFile::modeReadWrite | CFile::typeText)==FALSE )

// if( file.Open(strFileName, CFile::modeWrite | CFile::modeCreate | CFile::typeText)==FALSE )

// return;

FindClose(hFileExist);

file.Seek(0, CFile::end);

file.WriteString(str);

file.Close();

csTrace.Unlock();

}

catch( ... )

{

csTrace.Unlock();

Log2(&quot;CInternetTrace::Log&quot;,&quot;echec&quot;,&quot;techint.cpp&quot;,0,debug);

}

}

void CInternetTrace::Log2(LPCSTR szMethod,LPCSTR szMsg, LPCSTR szFile, int iLine, Mode modeAEcrire)

{

try

{

CTime t=CTime::GetCurrentTime();

CString str;

str.Format(&quot;%02d/%02d/%02d %02d:%02d:%02d, %s, %s, %s, %d\n&quot;, t.GetDay(), t.GetMonth(), t.GetYear()%100, t.GetHour(), t.GetMinute(), t.GetSecond(), szMethod, szMsg, szFile, iLine);

CString strFileName;

strFileName.Format(&quot;%sLocked.txt&quot;,m_PathDirectory);

CStdioFile file;

HANDLE hFileExist;

WIN32_FIND_DATA data;

hFileExist=FindFirstFile( strFileName, &amp;data );

if( hFileExist==INVALID_HANDLE_VALUE )

{

if( file.Open(strFileName, CFile::modeWrite | CFile::modeCreate | CFile::typeText)==FALSE )

{

FindClose(hFileExist);

return;

}

}

else

{

if( file.Open(strFileName, CFile::modeReadWrite | CFile::typeText)==FALSE )

{

FindClose(hFileExist);

return;

}

}

//CStdioFile file;

//if( file.Open(strFileName, CFile::modeReadWrite | CFile::typeText)==FALSE )

// if( file.Open(strFileName, CFile::modeWrite | CFile::modeCreate | CFile::typeText)==FALSE )

// return;

FindClose(hFileExist);

file.Seek(0, CFile::end);

file.WriteString(str);

file.Close();

}

catch( ... )

{

}

}

http://ultrafluid.codeplex.com

The entire application is available at http://ultrafluid.codeplex.com

2 new features : multiple selection and clipboard / and serialization !

Now, I can select multiple elements (with the SHIFT key) and make a right click to have clipboard support. The feature of copy/paste is very usefull.

Another feature is the XML serialization. I can load and save XML diagram with the boost::serialization.

Managing the Gdi+ drawing context

For drawing stuff, I rely on Gdi+ which is easier to use for advanced graphics rather than Gdi. Transformation and scaling operations are provided with appropriate methods.


#pragma once
#include "Element.h"

class CDrawingContext
{
public:
// Drawing Attributes are built in the ctor
CDrawingContext(std::shared_ptr<CElement> pElement);
virtual ~CDrawingContext(void);

public:
Graphics * GetGraphics() { return m_pGraphics; }
// Methods for Drawing Attributes
public:
Color & GetColorWhite() { return m_gdiColorWhite; }
Color & GetColorBlack() { return m_gdiColorBlack; }
Color & GetColorLine() { return m_gdiColorLine; }
Color & GetColorFill() {     return m_gdiColorFill; }
Pen & GetPenBlack() { return m_gdiPenBlack; }
Pen & GetPenColor() { return m_gdiPenColor; }
SolidBrush & GetBrushColor() { return m_gdiBrushColor; }
SolidBrush & GetBrushBlack() { return m_gdiBrushBlack; }
LinearGradientBrush & GetGradientBrushColor() { return m_gdiGradientBrush; }
CPoint GetTopLeft() { return m_pointTopLeft; }
CPoint GetBottomRight() { return m_pointBottomRight; }

public:
Graphics * m_pGraphics;

public:
// GDI+ Drawing objects
Color m_gdiColorWhite;
Color m_gdiColorBlack;
Color m_gdiColorLine;
Color m_gdiColorFill;
Pen m_gdiPenBlack;
Pen m_gdiPenColor;
SolidBrush m_gdiBrushColor;
SolidBrush m_gdiBrushBlack;
LinearGradientBrush m_gdiGradientBrush;

// MFC Drawing objects
CPoint m_pointTopLeft;
CPoint m_pointBottomRight;
};

#include "StdAfx.h"
#include "DrawingContext.h"

CDrawingContext::CDrawingContext(std::shared_ptr<CElement> pElement)
: m_gdiPenBlack(Color(255, 0, 0, 0)),
m_gdiPenColor(Color(255, 0, 0, 0)),
m_gdiBrushColor(m_gdiColorBlack),
m_gdiBrushBlack(m_gdiColorBlack),
m_gdiGradientBrush(
Point(pElement->m_rect.left, pElement->m_rect.top),
Point(pElement->m_rect.right, pElement->m_rect.bottom),
m_gdiColorBlack,
m_gdiColorBlack)
{
m_gdiColorWhite.SetFromCOLORREF(Color::White);
m_gdiColorBlack.SetFromCOLORREF(Color::Black);
m_gdiColorLine.SetValue(Color::MakeARGB(255, GetRValue(pElement->m_colorLine), GetGValue(pElement->m_colorLine), GetBValue(pElement->m_colorLine)));
m_gdiColorFill.SetValue(Color::MakeARGB(255, GetRValue(pElement->m_colorFill), GetGValue(pElement->m_colorFill), GetBValue(pElement->m_colorFill)));
m_gdiPenBlack.SetColor(m_gdiColorBlack);
m_gdiPenColor.SetColor(m_gdiColorLine);
m_gdiPenColor.SetWidth(pElement->m_lineWidth);
m_pointTopLeft = pElement->m_rect.TopLeft();
m_pointBottomRight = pElement->m_rect.BottomRight();
m_gdiBrushColor.SetColor(m_gdiColorFill);

Color color1(255, 241, 247, 255);
m_gdiGradientBrush.SetLinearColors(color1, m_gdiColorFill);

}

CDrawingContext::~CDrawingContext(void)
{
}