Rss Feed
Tweeter button
Facebook button
Technorati button
Reddit button
Myspace button
Linkedin button
Webonews button
Delicious button
Digg button
Flickr button
Stumbleupon button
Newsvine button

Posts tagged: MFC

How to output to stdout from an MFC program

By , January 31, 2017 1:00 pm

If you’ve ever developed an MFC program with a graphical user interface and then later thought that it would be really nice to also provide a command line version with output to stdout you’ve probably bumped into the problem that there is no stdout for these programs. The program isn’t attached to a console.

So how do you do it?

The secret to this is a Win32 API “AttachConsole” which is available from Windows XP onwards.
AttachConsole takes one argument, a DWORD identifying the process to which to attach. In our case we want to attach to the parent process, so we pass ATTACH_PARENT_PROCESS which is defined as (DWORD)-1.

AllocConsole(ATTACH_PARENT_PROCESS);

When you need to print to this console use _cprintf(), which is defined in conio.h.

But we’re still working with legacy systems!

If you need your code to work on old systems as well as modern systems you’ll need to use GetProcAddress() as shown below.

#ifndef ATTACH_PARENT_PROCESS
#define ATTACH_PARENT_PROCESS	((DWORD)-1)
#endif	//ATTACH_PARENT_PROCESS

typedef BOOL (WINAPI *AttachConsole_FUNC)(DWORD);

//-NAME---------------------------------
//.DESCRIPTION..........................
//.PARAMETERS...........................
//.RETURN.CODES.........................
//--------------------------------------

BOOL attachToProcessConsole(DWORD	processId)
{
	HMODULE				hMod;

	hMod = GetModuleHandle(_T("Kernel32.dll"));
	if (hMod != NULL)
	{
		AttachConsole_FUNC	func;

		func = (AttachConsole_FUNC)GetProcAddress(hMod, "AttachConsole");
		if (func != NULL)
		{
			// valid for Windows XP onwards

			return (*func)(processId);
		}
	}

	return FALSE;
}
Share

Improving MFC memory performance

By , January 2, 2012 12:16 pm

If you are using MFC arrays it is possible in quite a few cases to improve the speed and memory performance of these arrays. This applies to the standard CStringArray, CUIntArray and similar classes and also to template classes based upon the CArray template.

If you are not using MFC but using another framework or set of classes that provide similar functionality you can often find similar functions in those classes that will allow you to get a similar benefit to what I will describe in this article.

The Problem

The problem is the typical use of populating the array is by calling the Add() method to add something to the array. No actual problem with that, its simple and straightforward enough. However, under the hood, each time you call Add() the array class has to reallocate more memory of the data stored in the class.

This reallocation has a cost. The cost is increased CPU usage as suitable memory space is searched for by the memory allocator and memory is copied and reassigned inside the class. For small arrays this is not really a problem.

However for larger arrays this becomes quite a noticeable issue. In addition you also run into potential memory fragmentation issues, where memory "holes" of an unusuable size are left in the memory managed by the memory allocator. Should enough of these holes occur you can suffer out of memory conditions even when Task Manager tells you you have available memory. Frustrating! I’ll cover Memory Fragmentation in a different article.

Here is a (simplified) example of the type of problem:

// read data from the serialization archive and store in an array

DWORD i, n;

ar >> n; 
for(i = 0; i < n; i++)
{
    someClass *sc;

    sc = new someClass();
    if (sc != NULL)
    {
        sc->load(ar);
        array.Add(sc);
    }
}

The Solution

In the case shown above we know how many objects we require storage for beforehand. This means we can tell the array how many objects to store and only perform one memory allocation to set aside storage for the array. This has CPU benefits and also because there are no repeated calls to reallocate the memory the likelihood of fragmentation occurring diminishes dramatically. In many cases, completely removed from the scenario.

To set the size beforehand we need to call SetSize(size); and to place data in the array we no longer use Add();, but use SetAt(index, data); instead.

Here is the reworked example:

// read data from the serialization archive and store in an array

DWORD i, n;

ar >> n; 
array.SetSize(n);
for(i = 0; i < n; i++)
{
    someClass *sc;

    sc = new someClass();
    if (sc != NULL)
    {
        sc->load(ar);
        array.SetAt(i, sc);
    }
}

For large volumes of data the above implementation can be noticeably faster.

Caveats

When you preallocate memory like this you must be aware that if you don’t fill all locations in the array using SetAt() you may get errors when you call GetSize() to get the array size and GetAt(i) to retrieve data.

// read data from the serialization archive and store in an array
// we won't store all data, leaving some unused memory at the end of
// the array

DWORD i, n, c;

ar >> n; 
c = 0;
array.SetSize(n);
for(i = 0; i < n; i++)
{
    someClass *sc;

    sc = new someClass();
    if (sc != NULL)
    {
        sc->load(ar);
        if (sc->IsEmpty())
        {
            // discard
 
            delete sc;
        }
        else
        {
            array.SetAt(c, sc);
            c++;
        }
    }
}

GetSize() will return the size of the array you set when you called SetSize(), this is not necessarily the number of items in the array – this will come as a surprise to people used to adding data by calling Add().

To fix this, use FreeExtra() to remove any unused items from the end of the array. You can also use GetUpperBound() to find the largest index that is used by the array. The example below shows this.

// read data from the serialization archive and store in an array
// we won't store all data, leaving some unused memory at the end of
// the array

DWORD i, n, c;

ar >> n; 
c = 0;
array.SetSize(n);
for(i = 0; i < n; i++)
{
    someClass *sc;

    sc = new someClass();
    if (sc != NULL)
    {
        sc->load(ar);
        if (sc->IsEmpty())
        {
            // discard
 
            delete sc;
        }
        else
        {
            array.SetAt(c, sc);
            c++;
        }
    }
}

// make sure array.GetSize() returns the max number of items used

array.FreeExtra();
Share

Problems when subclassing controls

By , November 19, 2010 2:56 pm

I’m developing a graph control for use in our Memory Validator software tool.

Graph custom control

Tracking a mouse
One of the requirements was that we need to monitor mouse move messages on the control so that we can update some on-the-fly statistics related to where the mouse cursor is in the graph. No problem, add a ON_WM_MOUSEMOVE() message map entry and an OnMouseMove() method to the class (I’m using MFC) and that should be it. Easy.

Transparent hit tests
That’s what I thought until it didn’t work. Very confusing. Checked some other controls we’ve written and they all work OK. What is different about this control? After some head scratching and testing I decided to run Spy++ to monitor the windows messages being sent to our custom control. What a surprise that was. The only messages the custom control was generating were WM_NCHITTEST messages to see if the mouse cursor was in the control. Rather than return HTCLIENT or something similar the control was returning HTTRANSPARENT. Why would it do that?

Why is it transparent?
The reason the control is returning HTTRANSPARENT is because I’ve used a CStatic frame control to place my control in the resource editor and then I subclass that CStatic with my custom control. If I don’t override OnNcHitTest() method and add WM_ON_NCHITTEST() to the message map then I get the hit testing functionality from the CStatic. The CStatic’s job is to display a frame and let other control be displayed inside it (even though they are not child controls). For CStatic to do that it needs to return HTTRANSPARENT.

Getting mouse move messages
To fix this problem is straightforward.

  • Add a WM_ON_NCHITTEST() entry to the custom control message map.
  • Add a OnNcHitTest() method to the custom control and make it return HTCLIENT;

Once these are in place, the hit test works and then mouse move messages are sent to the custom control.

Conclusion
Sometimes the reason you are not getting messages is because something else is setup incorrectly. In this case the lack of correct hit testing was affecting many other messages, of which the mouse move message was one. I hope this article will help prevent you wasting any time on a bug like this.

Share

Don’t try this at home – custom control time sink

By , November 16, 2010 11:44 am

There are time when writing a custom control will waste your time like nothing on earth.

I’m going to share with you a particularly painful timewaster than bit my behind last night.

The custom control
I’m writing a custom control that will take data from an arbitrary data source via a data provider and then display this data as a graph. The screenshots in this article are not from the finished control, just some mockups to test various ideas I am experimenting with. As you can see it is a graph with a pastel block colour and a harder solid outline. All configurable of course.

Graph custom control

The problem
The problem was first noticed when I wanted to change some settings in the host program. I clicked on the toolbar button to open the settings dialog and nothing happened. Button depressed, but nothing. Clicking elsewhere on the screen and I get a beep – hmmm, not allowed. GUI is totally frozen.

It felt like a deadlock. But all the code I’d written had its multithreading code locked down and everything I’m doing is on the GUI thread. No chance of a deadlock. Still I go investigating, several times in the debugger, use Thread Validator and Thread Status Monitor. No sign of a deadlock. Thats odd.

Try a different tack. Comment out the subclassing of the graph controls – effectively disabling them. Does the settings dialog display? Yes it does. OK, so it is something to do with the custom control. But what? Identify by process of elimination. Comment out all message map handlers except erase background and paint. Do I still get the problem? Yes, OK, so the problem is with erase background or paint. Turns out the problem is in paint. I’ll show you the code below.

void CSvlGraphCtrl::OnPaint()
{
    if (GetSafeHwnd() == 0)
        return;

    CRect    rCl;

    GetClientRect(&rCl);

    CClientDC    dc(this);
    CMemDC     dcMem(&dc, rCl);

    OnDraw(&dcMem);
}

Can you spot the problem? I’ve forgotten to call CWnd::OnPaint() which sets the I’ve been drawn bits inside the class and causes various other drawing related operations to happen. Without this call, the settings dialog I’ve been trying interact with (which is displayed on top of this graph custom control in this case) does not get drawn properly – or at all. So the settings dialog which is nothing to do with the custom control is displayed but doesn’t get drawn due to an incorrect cascade of events caused by failing to call CWnd::OnPaint() from the custom control’s OnPaint() handler.

The code should look like this (added line in bold)

void CSvlGraphCtrl::OnPaint()
{
    CWnd::OnPaint();

    if (GetSafeHwnd() == 0)
        return;

    CRect    rCl;

    GetClientRect(&rCl);

    CClientDC    dc(this);
    CMemDC     dcMem(&dc, rCl);

    OnDraw(&dcMem);
}

Conclusion
Sometimes the bug isn’t what you think it is. I started thinking this was a deadlock as the GUI appeared to freeze (pressing ALT caused the display to fix itself, but I found that by accident several hours later) but the fix was a missing call to a base class method. I’ve been writing MFC for years and yet this trivial bug eluded me for some time.

Hopefully sharing this with you will help prevent you from making the same mistake.

Share

Speed up your MFC program without a profiler!

By , February 13, 2010 3:35 pm

I’m going to explain how to potentially improve the performance of MFC programs using CMap<> and related containers (CMapStringToPtr, etc) by a substantial amount.

We use MFC for quite a lot of our software. We also use STL and also some custom containers. It is easy to fall into certain programming habits of using a particular container for a particular task. Sometimes the result is not what you expected!

During the Christmas break I decided to write some software to analyse the Software Verification website log files. Initially I wanted to do keyword mining, but it soon blossomed into a stats package calculating different statistics for keywords, referrers, domains, URLs, favourite domains, bounce rates, evaluation download rates, etc.

I was also reading the wonderful "Web Analytics an Hour a Day" book by Avinash Kauschik. And to top it all, I was ill. I’ve since been told by various people that I had Swine Flu.

The initial version didn’t calculate much and was quite fast, but when I wanted to scale up to calculating monthly data as well as yearly, that was 13 times as much calculation and the inefficiencies in container choice started to show. I’d been lazy, this was a hobby project, nothing serious, so I’d chosen the MFC class CMap.

I wanted to map keyword strings to countData objects which would hold all the data on that keyword. Later we could discard the map and just use an array of keyword objects for random access and sorting.  I wanted data for unique keywords, so during processing of the data it seemed natural to want to map the keyword to the keyword data. I was doing similar things for referrers, referring domains, requested URLs, etc.

A CMap<> is an MFC hash table. A declaration would look like this:

CMap<CString, LPCTSTR, countData *, countData *&> mfcData;

The data processing would be something like this (simplified)

	BOOL	b;

	while(TRUE)
	{
		CString	s;
			
		b = file.ReadString(s);
		if (!b)
			break;

		// lookup string

		countData	*cd = NULL;

		if (mfcData.Lookup(s, cd))
		{
			// if we know about the string update the count

			cd->addCount(1);
		}
		else
		{
			// otherwise create the string and update the count

			cd = new countData(s, 1);
			mfcData.SetAt(s, cd);
		}
	}

The problem with the CMap<> class is that its hash key calculation isn’t very sophisticated, so you get collisions reasonably quickly, which forces the CMap to start making linked lists for the non-identical collisions, and walking the linked lists for subsequent searches is linear time. That gets slower as you add more data.

After processing for one particlularly large set of data for 2009 took 36 hours I thought a better solution was required. Why did I let it run so long? Partly because once it got past a few hours I was curious to see how long it would take. By this time I was ill, so it didn’t really matter, I was spending much of this time in bed alternately too hot or too cold 🙁

The STL has a non-standard hash table, so we didn’t want to use that, so we opted to use the STL <map> class. The declaration would look like this

map<CString, countData *> stlData;

The data processing would be something like this (simplified)

	BOOL	b;

	while(TRUE)
	{
		if (stopScan)
			break;

		CString	s;
			
		b = file.ReadString(s);
		if (!b)
			break;

		// lookup string

		MAP_STL::iterator	iter;

		iter = stlData.find(s);
		if (iter != stlData.end())
		{
			// if we know about the string update the count

			iter->second->addCount(1);
		}
		else
		{
			// otherwise create the string and update the count

			countData	*cd;

			cd = new countData(s, 1);
			stlData[s] = cd;
		}
	}

This is not a hash table, its a B-tree, so it will use more memory than the hash map, and unique entries should be slower than the hash table, but colliding entries should be faster. With this new style of map substituted all over the program, for all the many unique datatypes being calculated, the processing time dropped from 36 hours to 1 hour.

In other words, the STL version processed the data in 2.77% of the time the MFC version processed the data. That is a 97% improvement in processing time.

I am not saying that you will get this improvement. This improvement was acheived partly because of the type of statistics being calculated and partly due to the input data having so many collisions. The dataset for the above test was 17.1GB of Apache log files.

I have created an example MFC program that shows a trivial example of reading in lines from a file, testing them for uniqueness and storing them and updating the counts for them. The program also does the same using STL. Some sample times shown below:

Size (MB) MFC STL Improvement
34 00:00:12 00:00:06 50%
2048 00:22:46 00:05:21 76%

Time comparison of reading a 34MB file with MFC and STL
For a sample 34MB input file, the MFC program processes the data in 12+ seconds and the STL program processes the same data in 6+ seconds. An approximately 50% improvement.

Time comparison of reading a 2GB file with MFC and STL
For a sample 2GB input file, the MFC program processes the data in 22 minutes 46 seconds seconds and the STL program processes the same data in 5 minutes 21 seconds. An approximately 76% improvement.

The larger the dataset, or the more different CMap<> you are using calculating the data, the chances are that changing them to STL <map> would be highly effective in speeding up that part of your application. Note that if you are only loading a few tens of items into the map, it will not be worth making the change.

You can download the executable and the source code with project files so that you can test this yourself.

I don’t recommend changing all occurrences of CMap<> for STL <map>, but changing a the right ones should make some easy and worthwhile gains for you.

Share

Panorama Theme by Themocracy