Monthly Archives: August 2002

Modifying the System Menu in MFC

Introduction

The system menu is a standard feature of every Windows application. It is managed by Windows so normally we don’t have to worry about it at all. However sometimes it is nice to be able to modify that menu according to our own program with things that Windows can’t automatically do for us.

As my main example I will be using a tool I’ve created called BabelOn. This is a C++/MFC program that accesses a web-service to translate text into foreign languages. It uses a toolbox window, so we don’t see the system menu icon in the upper-left corner, however the menu can still be accessed with Ctrl-Space or by right-clicking on the title bar. The menu has been modified to contain two extra commands: About BabelOn, and Exit. Exit is needed because the default action for Close (Alt-F4) has been overridden in the program to hide the window and allow tray access.

Adding Commands

First we need to define a unique variable to represent each menu item. This can be done in the Resource.h file, or in any standard header file. If the commands already exist as part of another standard or context menu, then this step can be skipped because the definitions already exist. However, it’s important to note that even if we use the pre-existing definitions, the message handlers for the commands on the regular menu will NOT be automatically called. System commands are routed differently. So, in the end, it doesn’t matter if we use the existing or define our own.

For our example, we’ll define two:

[code]
#define IDM_ABOUT 16
#define IDM_EXIT 17
[/code]

The IDM just means this is a menu-item ID.

We add these commands in our window’s initializing function ( OnInitDialog(), OnCreate() ). My example is in a dialog class, so this is what the function looks like:

[code lang=”cpp”]
BOOL CBabelOnDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add “About…” and “Exit” menu items to system menu.
// Command IDs must be in system range
// the ANDing is because of a bug in Windows 95
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
ASSERT((IDM_EXIT & 0xFFF0) == IDM_EXIT);
ASSERT(IDM_EXIT < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL) {
pSysMenu->AppendMenu(MF_STRING,IDM_EXIT,”E&xit Program”);
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, “A&bout BabelOn”);

}
. . .
//other initialization
[/code]

The first thing you should notice is a couple of ASSERT statements for each command. The first one deals with a bug present in Windows 95 and the second ensures the custom command is below the range used by pre-defined system commands. From the MFC documentation: “All predefined Control-menu items have ID numbers greater than 0xF000. If an application adds items to the Control menu, it should use ID numbers less than F000.”

Next we get a pointer to the system menu with the GetSystemMenu. We call it with an argument of FALSE to get the pointer. If we call it with TRUE, then it will reset the menu to its default state.

If the pointer is valid, we call some commands to add to the bottom of the menu, passing the IDs and the string we want to show up when the menu is viewed.

Simple, isn’t it?

Processing Custom Commands

In order to have those commands do anything, we can’t rely on the normal message-handling mechanism, even if we have handlers for the same items in other menus. We have to handle the WM_SYSCOMMAND message in our dialog/window class.

[code lang=”cpp”]
void CBabelOnDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
//trap our own system menu messages
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout; dlgAbout.DoModal();
} else if ((nID & 0xFFF0)==SC_CLOSE)
{
OnClose();
} else if ((nID & 0xFFF0)==IDM_EXIT)
{
::PostQuitMessage(0);
} else {
CDialog::OnSysCommand(nID, lParam);
}
}
[/code]

This is the height of simplicity herself. We compare the code that was passed in with the system to our commands, again ANDing them to account for the Windows 95 bug. Then call whatever code we want to handle it.

If we selected Exit, then we post a message to quit the application.

Take a look at the second test: SC_CLOSE is a predefined menu constant. It’s one normally handled by Windows, but we can still add custom processing to it if we want. In this application, I didn’t want it to exit, but to merely hide the application (with an icon in the tray). So I just call a handler that I wrote that does that. If the ID doesn’t equal anything we want to custom-process, we just pass it on up the hierarchy for default processing.

The IDs for the most common system commands are:

SC_CLOSE – Close the CWnd object.
SC_MAXIMIZE (or SC_ZOOM) – Maximize the CWnd object.
SC_MINIMIZE (or SC_ICON) – Minimize the CWnd object.
SC_MOVE – Move the CWnd object.
SC_RESTORE – Restore window to normal position and size.
SC_SIZE – Size the CWnd object.

There are others in special situations that you can learn about in the documentation for WM_SYSCOMMAND.

Modifying Existing Commands

We just saw that it’s possible to change the default handling of built-in system commands, but it’s also possible to modify existing menu items by changing their text, or to entirely remove them.

To modify the text of a command, use the ModifyMenu() function on pSysMenu in the above example. For example, to change “Close” to “Hide”, I could do this:
[code lang=”cpp”]
pSysMenu->ModifyMenu(SC_CLOSE, MF_BYCOMMAND,IDM_HIDE, “&Hide”);
[/code]

The MF_BYCOMMAND argument tells the function to interpret SC_CLOSE as a command ID. IDM_HIDE is a new command ID, and then comes the text we want to show.

Alternatively, we can call ModifyMenu() on the ith menu item:

[code lang=”cpp”]
pSysMenu->ModifyMenu(0,MF_BYPOSITION,IDM_HIDE,”&Hide”);
[/code]

This changes the first menu item to Hide.

Removing commands

Don’t want a close command at all on the window? Not sure if this is a good idea or not, but you can do it.

Use this method:

[code lang=”cpp”]
pSysMenu->RemoveMenu(SC_CLOSE,MF_BYCOMMMAND); pSysMenu->RemoveMenu(0,MF_BYPOSITION);
[/code]

The first one removes the command associated with SC_CLOSE, while the second removes the first item on the menu.

Conclusion

Modifying the system menu in this way has limited application but it is sometimes useful for small applications and utilities that have a limited menu structure otherwise. It can be useful for commands you want to be easily accessible from the task bar–when a program is is in the background or minimized, right-clicking on it’s icon on the task bar will bring up the system menu.

Something should be said, however, about the wisdom of certain modifications. Removing or modifying functionality that user expects is usually a bad idea. It makes your program less usable and friendly compared to other applications. UI guidelines and standard look and feel exist for a good reason!

Enjoy playing with this!

©2004 Ben Watson

Operator Overloading in C++

Definition

This can be a weird subject for some, especially those with a strong Java background, or another language that doesn’t support this feature. It can be confusing even for excellent programmers. But it is a strong feature of C++ that, if mastered, can yield some increased productivity in programming.

We all know that an operator can be used in mathematical expressions:

[code lang=”cpp”]
int z=x+y;
float g=3.14*g;
[/code]

Now wouldn’t it be nice to use operators on our own objects to do what we want? For example, a string class could use + to concatenate, or a Throttle class could use the ++ and — operators to increase or decrease throttle position. The operators can be programmed to do whatever we want them to.

However, some words of caution. Operator overloading provides NO additional functionality to your code. It just compiles to normal function calls. It’s even written out like normal function calls. It is mainly for aesthetics. There is, however, one extremely useful set of operators to overload that makes life much easier: the streaming operators, which I will cover at the end.

Second, you should NOT use operator overloading for unobvious relationships. Using + to concatenate two strings intuitively makes sense to most programmers, so it’s easy to use it like that. But how would you define string1*string2? or string1^string2? It isn’t very clear what that means. So use caution when considering adding operators to your objects.

Sample Object

For my sample object, I’m going to implement a matrix. This won’t be a full-scale implementation of every imaginable matrix operation, but it should be enough to cover the basics of operator overloading, and maybe whet your appetite to complete the implementation for other operations (dot product, inverse, determinant, etc.).

In order to completely encapsulate a matrix within a class, we actually need two classes: Row and Matrix.

So let’s start with Row:
[code lang=”cpp”]
template
class Row {
public:
Row(int cols=0):row(NULL) {SetRowSize(cols);}
~Row() {SetRowSize(0); }
Row(const Row &r):row(NULL) {
SetRowSize(r.numCols);
for (int i=0;i row[i]=r.row[i];
}

void SetRowSize(int n) {
if(row) delete[] row;
if (n>0) {
row=new T[n];
memset(row,0,sizeof(T)*n/sizeof(char));
}
else row=NULL;
numCols=n;
}

int size() { return numCols;}
private:
int numCols;
T* row;
};[/code]

Let’s look at this before continuing on. Notice that I’m making it a template class. This is so you can have a matrix of all the usual numerical types, as well as any type you want to define yourself. The only requirement for the type is that it must have the +, -, and * operators defined on it. We’ll get into how to do that. If you don’t understand templates, you can think of all of the T’s as ints for now.

SetRowSize() deletes any old data, and allocates space for new data, unless we set the number of columns to 0, in which case it merely deletes the data. This lets us use this function for construction, destruction, and dynamic modification in one method. Nifty, eh? The call to memset() just zeroes out the array after figuring out how many bytes the row uses and dividing this by the size of character, because memset() works in terms of chars.

I also defined a copy constructor, which will come in handy quite a bit, as we’ll see later on when we copy matrices.

Overloading []

OK, let’s overload our first operator: []

Yes, that’s one operator. The array-access operator. It makes perfect sense here, because we have a linear array of objects we would like to access. Let’s add this definition to our Row class:
[code lang=”cpp”]
T& operator[](int column) {
assert(column return row[column];
}
[/code]

The arguments to our brackets are going to be integers specifying the index of the item we want, so that will be the function’s arguments. Notice the syntax: [ReturnType] operator[Op]([argument list]). We do an assertion to make sure we’re accessing memory within the array’s bounds. If all is OK, we return a reference to the object. Why a reference instead of a value? It won’t make much of a difference in a case like this:

[code]
Row r(1);//1×1 matrix

int a=r[0];
[/code]

a will get the value of r[0] whether a reference or a value is returned. However, if we return a reference, we can then change the value in the row from outside the class, using the [] accessor operator, like so:
[code lang=”cpp”]
Row r(1);

r[0]=3.142;
float pi=r[0];
[/code]

Very cool, isn’t it.

Overloading =

The only other operator we need to overload is assignment (=). When overloading assignment, we must keep in mind that the object we’re assigning to must already exist, and it is that object’s operator= method which will be called.
[code lang=”cpp”]
Row& operator=(const Row& r) {
SetRowSize(r.numCols);
for (int i=0;i row[i]=r.row[i];
return *this;
}
[/code]

Again we return a reference, but this time it’s a reference to itself. First we set the size of the current row equal to that of the source row, then we copy its values. There is an important note here. Notice that I’m using [] on the primitive T array itself–NOT the overloaded []s of Row. Remember that Row’s [] returns a reference, thus if we had written row[i]=r[i], we would get a row that references the exact same data in memory, so that when we changed one the other would change–this isn’t what we want at all, so we need to access the raw data in the Row class.

Now we can write code like this:
[code lang=”cpp”]
Row r1(5);
Row r2;//creates an empty row
Row r3(2);
r2=r1;
r3=r1;//overwrites previous row information to contain same info as r1
[/code]

Matrices are Made of Many Rows

Now that we have a working Row, we can combine rows into a matrix. Let’s start with this basic definition:
[code lang=”cpp”]
template
class Matrix {
public:
Matrix(int rows=0, int cols=0): matrix(NULL) {
SetSize(rows,cols);
}
Matrix(const Matrix& m): matrix(NULL) {
SetSize(m.numRows,m.numCols);
for (int r=0;r matrix[r]=Row(m.matrix[r]);//assign to primitive array, NOT overloaded []–to get a copy
}
void SetSize(int rows, int cols) {
if (rows) delete[]matrix;
if (cols > 0 && rows >0) {
matrix=new Row[rows];
for (int i=0;i matrix[i].SetRowSize(cols);
}
else
rows=NULL;
numCols=cols;numRows=rows;
}
int GetCols() { return numCols;}
int GetRows() { return numRows;}

private:
int numCols, numRows;
Row* matrix;

};
[/code]

This follows very closely the basic form of the Row class. The only item of interest is when we declare and allocate a matrix: we must specify the type, T, after the class name.

First let’s implement the same operators we did on the Row class:
[code lang=”cpp”]
Row& operator[](int index) {
assert(index return matrix[index];
}

Matrix& operator=(const Matrix& m) {
SetSize(m.numRows,m.numCols);
for (int r=0;r matrix[r]=Row(m.matrix[r]);//assign to primitive array, NOT overloaded []–to get a copy
return *this;
}
[/code]

The most important part of this code is the return type of operator[]. It returns a reference to a Row of type T. This little fact allows us to use the Matrix class like this:
[code lang=”cpp”]
Matrix a(2,2);

a[0][0]=2;
a[0][1]=4;
a[1][0]=8;
a[1][1]=16;
[/code]

That is, we can refer to Matrix objects now with exactly the same notation as primitive 2-D arrays in C++: array[row][column]. Our operator overloading is faking it well enough to keep a consistent interface with analogous structures, but add much more functionality and safety. Isn’t this cool?

The = operator works the same way as in Row. It sets the size of the current Matrix to that of the source, and then copies all of the objects to the current Matrix. Now we can do the following:
[code lang=”cpp”]
Matrix<__int64> m(1000,1000);
Matrix<__int64> n=m;
[/code]

…and we have two very large matrices of 64-bit integers.

Overloading +

Let’s do some more interesting things with these matrices now. There are a number of mathematical operations that can be performed on a matrix, the simplest perhaps is addition. Addition of matrices requires that they both have the same dimensions. The resulting matrix is made by simply adding each number in the same position in each matrix and putting the answer in the same position as the two operands.
[code lang=”cpp”]
[1 0] [4 3] [5 3]
[2 1] + [-1 0] = [1 1]
[/code]

Since addition creates a new matrix, we don’t want to return a reference, but an actual matrix object. Here’s what the code looks like:
[code lang=”cpp”]
const Matrix operator+( const Matrix& m) {
assert(numCols==m.numCols && numRows==m.numRows);
Matrix theMatrix(numRows,numCols);
for (int r=0;r for (int c=0;c theMatrix[r][c]=matrix[r][c]+m.matrix[r][c];
return theMatrix;
}
[/code]

This adds the current matrix to the matrix in argument m. We first assure that the dimensions are equivalent, then create a new matrix with the same dimensions as the sources. It is then a simple matter of adding the two sources, and returning the new matrix. Notice that we perform the actual math on the types that make up each row.
[code lang=”cpp”]
Matrix a(2,2);
Matrix b(2,2);
Matrix c(2,3);
Matrix d=a+b;
Matrix e=a+c;//will fail assertion, abort program
[/code]

It is just as easy to define subtraction:
[code lang=”cpp”]
const Matrix operator-( const Matrix& m) {
assert(numCols==m.numCols && numRows==m.numRows);
Matrix theMatrix(numRows,numCols);
for (int r=0;r for (int c=0;c theMatrix[r][c]=matrix[r][c]-m.matrix[r][c];
return theMatrix;
}
[/code]

Overloading += and -=

+= and -= are operators that both add and change the current object, so the code to describe it is a combination of +/- and =. We’ll return a reference again because we don’t want to create a new object, but just modify the existing one, which called the function. We’ll just add whatever is currently in it to the other matrix, and return a reference to itself:
[code lang=”cpp”]
Matrix& operator+=(const Matrix& m) {
assert(numCols==m.numCols && numRows==m.numRows);
for (int r=0;r for (int c=0;c matrix[r][c]+=m.matrix[r][c];
return *this;
}

Matrix& operator-=( const Matrix& m) {
assert(numCols==m.numCols && numRows==m.numRows);
for (int r=0;r for (int c=0;c matrix[r][c]-=m.matrix[r][c];
return *this;
}
[/code]

We can now expand our repertoire to include the following possibilities:
[code lang=”cpp”]
Matrix a(2,1);
Matrix b(2,1);

a+=b;
a-=b;
[/code]

Scaling: Overloading *

Another useful operation we can perform on matrices is scaling. This just multiples every element in the matrix by a constant.
[code lang=”cpp”]
[1 2] [2 4]
[2 4] * 2 = [4 8]
[/code]

This operation returns a new matrix so we will return by value, not reference. The code should be trivial to read by now:
[code lang=”cpp”]
const Matrix operator*(const float s) {
Matrix theMatrix(numRows,numCols);
for (int r=0;r for (int c=0;c theMatrix[r][c]=matrix[r][c]*s;
return theMatrix;
}
[/code]

We use a float as the scalar, and multiply it by every value in the source matrix, and return a new matrix. It is left up to the reader to implement *=. (/ and /= could also be implemented as inverses of scaling, but since scaling allows a float, this is mostly redundant.)

Matrix Multiplication – Overloading * again

We can actually overload the same operator more than once if we would like. As long as the function’s signature (return type, name, and arguments) is different, we can define as many as we want. The * operator would be a likely candidate for implementing matrix multiplication as well as scaling. Both imply multiplication of some sort, so it should make sense.

Matrix multiplication has a requirement: the number of columns in the first matrix must be equal to the number of rows in the second. Matrix multiplication is NOT commutative. I won’t explain how to do matrix multiplcation–it’s easy enough to look up this topic on-line or in a math textbook. Or you can deduce the “by-hand” algorithm from the code.
[code lang=”cpp”]
const Matrix operator*(Matrix& m) {
assert(numCols==m.numRows);
Matrix theMatrix(numRows,m.numCols);
for (int r=0;r for (int c=0;c for (int i=0;i theMatrix[r][c]+=matrix[r][i]*m[i][c];
}
}
}
return theMatrix;
}
[/code]

Overloading < < and >>

There are only two more important operators that I will cover here. These are perhaps the operators that should be implemented for each and every class you create. The streaming operators < < and >> allow your object to be saved and restored from any stream, be it console, network, or file.

There is a slight additional challenge with these operators because we must allow the stream access to our object’s private data. Therefore, these functions must be declared as friends inside the Matrix class.

Let’s first look at outputting to a stream:
[code lang=”cpp”]
friend ostream& operator< <(ostream& os,const Matrix& m) {
os << m.numRows<<” “< Matrix a(2,2);

cout < <“Matrix a:”<

ofstream ofile(“output.dat”);
ofile << a << endl<<“End of File”;
[/code]

It is a quite similar technique to read in values from a stream:
[code lang=”cpp”]
friend istream& operator>>(istream& is, Matrix& m) {
int rows,cols;
is >> rows >> cols;
m.SetSize(rows,cols);
for (int r=0;r for (int c=0;c is >> m[r][c];
return is;
}
[/code]

Here we declare some local variables to hold our matrix dimensions, which we then pass to the referenced matrix object. Then it’s just a matter of reading in the next number and putting it in the appropriate location. We then return a reference to the stream in case the calling function wanted to continue getting data from it in the same command.

Putting it all together

To demonstrate the Matrix class and its overloaded operators, I’ve written a sample main() as well as some helper functions that will run the class through its paces:

[code lang=”cpp”]
//the functions fill in a matrix with random values–they are type-specific
void init_matrix(Matrix& m) {
for (int r=0;r for (int c=0;c m[r][c]=rand()%5+1;
}

void init_matrix(Matrix<__int64>& m) {
for (int r=0;r for (int c=0;c m[r][c]=rand()%100000+1;
}

void init_matrix(Matrix& m, int precision) {
for (int r=0;r for (int c=0;c float dec=float(rand()%precision)/precision;
m[r][c]=float(rand()%5)+1.0+dec;
}
}

int _tmain(int argc, _TCHAR* argv[])
{
srand((unsigned)time(NULL));

//save/load from file7
Matrix a(5,5);
init_matrix(a);
a[0][0]=-13;
a[1][1]=-13;
cout < < “Writing to file from Matrix a:” < cout << a< ofstream of;
of.open(“test.txt”);
of << a< of.close();
ifstream iff(“test.txt”);
if (!iff) {
cout << “Error opening file”< return 1;
}
Matrix b;
cout < < “Reading from file into Matrix b:”< iff >> b;
iff.close();
cout < cout << b<

cout <<“Press any key to continue…”< getchar();

//add two floating-point matrices
Matrix c(3,2);
init_matrix(c,100);
cout < <“Matrix c:”< Matrix d(3,2);
init_matrix(d,100);
cout < < “Matrix d:”< cout << “c+d:”<

cout <<“Press any key to continue…”< getchar();

//scale a floating-point matrix
Matrix e(10,10);
init_matrix(e,1);
float scalar=-1.5;
cout < < “Matrix e:” << endl< cout << “Scalar: “< cout << “e * scalar:”<

cout <<“Press any key to continue…”< getchar();

//matrix-product
Matrix<__int64> f(3,5);
Matrix<__int64> g(5,6);
init_matrix(f);
init_matrix(g);
cout < <“Matrix f:”< cout <<“Matrix g:”< cout <<“f*g:”<

cout <<“Press any key to continue…”< getchar();

return 0;
}
[/code]

Conclusion

Operator overloading can be a powerful programming tool when it increases usability and understandability of a class. In this case, it’s much nicer to write matrix[0][4] rather than matrix->GetRow(0)->GetCol(4). However, it must always be remembered that overloading serves to make programming easier–it doesn’t benefit the end user at all. Overloading an operator must make sense, as I hope all of the decisions I made in this class make sense. If it’s appropriate, go ahead and use it. If it will make people wonder what you meant, than it’s probably something to stay away from.

Also, because this is a template, you could possibly have a matrix of any object, including, for example strings. This will work perfectly in some situations, but not in others. Basically, if + is defined on strings, then you can do matrix addition on a string matrix. However, * is usually not defined for strings, so a statement with that would refuse to compile.
[code lang=”cpp”]
Matrix s(2,7);
Matrix t(2,7);

/*
will work fine–concatenates strings
at same locations in matrix
*/
Matrix u=s+t;

Matrix v(7,5);
/*
will not compile: error C2676: binary ‘*’ :
‘std::string’ does not define this operator or a conversion to a type
acceptable to the predefined operator
*/
Matrix w=s*v;
[/code]

I did not make use of the — and ++ unary operators in this tutorial because they don’t always make sense when used on a matrix. With these operators it is important to know that since they can be both prefix and postfix, each version has a slightly different function signature. With the understanding you have gained in this tutorial, you should be able to look up how to implement these operators without trouble.

Hope this helps somebody understand this subject better! Happy coding!