Tag Archives: mfc

GetTextExtent vs. DrawText (with DT_CALCRECT)

Working on an MFC app that has just been converted to Unicode (finally!), I noticed that one button (which is created dynamically) is too small to fit the text in Korean (and Russian and a few other languages).

The code was calling something like:

CSize sz = m_btAdjustColors.GetDC()->GetTextExtent(sCaption);

It seems correct, but these script languages are throwing it for a loop–the measured size is much smaller than it should be. The GetTextExtent documentation doesn’t shed any explicit light on this subject, but may hint at it.

The solution? DrawText. There is a flag you can pass to tell it to calculate the rectangle needed instead of drawing.

CRect rect(0,0,0,0);
m_btAdjustColors.GetDC()->DrawText(sCaption, &rect, DT_CALCRECT);

It’s important to initialize the rectangle to zeroes because, as the docs say, it only modifies the right and bottom members of the rectangle.

Serial Port Code Library

Need to interact with some hardware via serial port? I’m having to do some serial port communications in a project at work, and it is officially Not Fun. There was some original code that was doing only reads from the port, and I needed to some significant functionality that would not be possible with the existing code. So rather than writing a ton of code from scratch (well, other than what I will have to do anyway), I tried to find some open-source, commercial-friendly serial port libraries on the Internet.

The only one I could find that seemed to be perfectly suited to the task at hand was Serial Library for C++ by Ramon de Klein. It has a number of classes for various ways of accessing the serial port and handling events, interacting with Windows. It also supports MFC.

The license is LGPL, which makes it’s ok for me to use in the project. As Ramon’s article notes, doing serial port communications from scratch is hard. So reuse what is out there.

If you’re in .Net, you already have some nice classes in the form of System.IO.Ports.SerialPort, which was added in 2.0.

Technorati Tags: , , ,

UnitTest++

I’ve got a great process using NUnit in all my .Net projects. However, at work we have a large MFC/C++ application that has NO automated testing. I’ve been planing on getting unit testing into it for quite a while, but finally decided this is the week to do it.

It turns out that C++ unit testing is nowhere near as standardized or easy as .Net or Java. Partly, it’s the lack of reflection/introspection, but I think it’s also because the language itself just doesn’t lend itself to it.

There are a few very good resources for C++ unit testing. I first came across Noel Llopis’ Exploring the C++ Unit Testing Framework Jungle. I was just about set on using CxxTest, just as he had decided, but realizing that the post was written at the end of 2004, I continued my research. Sure, something must have improved since then! I came across UnitTest++: The New choice for C++ Unit Testing. It turns out to be partially written by Noel Llopis, so I thought this must be good since he gave such good reviews of the earlier solutions. You can read more about it here.

UnitTest++ seems to be the best of all possible worlds. It’s extremely simple to add test cases. I won’t include examples here, because the previous links have plenty.

The only thing I wish I could find is an open source code coverage C++ tool. I couldn’t survive without NUnit/NCover in C#.

Setting the minimum Windows version supported (C++)

Recently, I was trying to use the Shell function SHGetFolderPath. Despite including the correct header file (shlobj.h), the compiler wasn’t recognizing it. My code looked like this:

CString strPath; HRESULT hResult = SHGetFolderPath( NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, strPath.GetBufferSetLength(MAX_PATH)); strPath.ReleaseBuffer();

What I did was lookup the definition of SHGFP_TYPE_CURRENT in shlobj.h, and found this:

#if (NTDDI_VERSION >= NTDDI_WIN2K) SHSTDAPI_(void) SHFlushSFCache(void); typedef enum { SHGFP_TYPE_CURRENT = 0, // current value for user, verify it exists SHGFP_TYPE_DEFAULT = 1, // default value, may not exist } SHGFP_TYPE; SHFOLDERAPI SHGetFolderPathA(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, __out_ecount(MAX_PATH) LPSTR pszPath); SHFOLDERAPI SHGetFolderPathW(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, __out_ecount(MAX_PATH) LPWSTR pszPath); //etc...

It’s that first line that got me. My DDI version wasn’t >= that of Win2k’s. The solution is to modify the stdafx.h file. Before, it read:

#ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0400 #endif

That 0x0400 defines Windows 95 as the minimum supported OS. I don’t really care about 9x support, so I changed it to read like this:

#ifndef _WIN32_WINNT //define Windows 2000 as minimum necessary OS #define _WIN32_WINNT 0x0500 #endif

Don’t use CArchive with native C++ type bool

I recently ran into an issue where I was trying to serialize a bool variable from a CArchive object.

Archiving it out, with this code, works fine:

//CArchive ar;
bool bFill;
ar << bFill;

But this code:

ar >> bFill

has problems. It compiles fine under Visual Studio 2003, but errors out under Visual C++ 6 with this error:

C2679: binary ‘>>’
: no operator defined which takes a right-hand operand of type ‘bool’
(or there is no acceptable conversion)

Very weird. There is some explanation here.

My resolution? Use BOOL instead. Sure, it’s actually an int and takes 4 bytes, not 1, but that’s a not a big deal in this case. And it’s more clear than using BYTE.

Getting the real view under a CPreviewView (MFC)

I had an interesting problem at work the other day. In this MFC application, there are a number of views that can be printed and we support the Print Preview function.

However, in one of these views we rely on getting the view from the frame window in order to handle command updates. This is accomplished with code like this:

 pWnd = reinterpret_cast< CBaseView*>(GetActiveView());

However, when you’re in print preview mode, GetActiveView() returns a CPreviewView, not the underlying view (CBaseView). If you look in the source of CPreviewView, you’ll notice that it has a protected member m_pOrigView, which is indeed the one I want. However, there is no way of accessing that value. (I briefly toyed with the idea of directly accessing the memory via its offset from the beginning of the object, but as this software has to run in unpredictable environments, and it’s a horrible idea anyway, I let that go…)

 If you try this:

pWnd=(CBaseView*)pWnd->GetDescendantWindow(MAP_WINDOW);

Where MAP_WINDOW is the ID of the real view that I want, it won’t work (it may work in the general case, but it doesn’t work in my case).

I had two options, just return NULL and tell the higher-level functions to not do those certain command updates when the returned view is NULL. This should be done anyway, so I implemented those checks.

However, it still bugged me that I couldn’t get access to the real view. At last I hit on the idea of going through the document (this uses the Doc/View framework).

 I used this code and it did exactly what I needed:

CDocument* pDoc = GetActiveDocument();
if (pDoc!=NULL) {
    
POSITION pos = pDoc->GetFirstViewPosition();
    
CView* pView = NULL;
    
do {
            
pView = pDoc->GetNextView(pos);
            
if (pView != NULL && pView->IsKindOf(RUNTIME_CLASS(CBaseView)))
                        
return (CBaseView*)pView;     } while (pos!=NULL);
}

 

Unsupported Frameworks…

Programming with a framework that you’ve developed can be annoying, when you compare it to the ease of IDE-supported frameworks. MFC is a nice framework primarily because Visual C++ has so much built-in support for it.

My little framework has no such support (and I have no ambitions to build in IDE support for it) and that can make it frustrating to do all the repetitive stuff (making the initial window, message handling, for examples).

Another thing that MFC does that I want to avoid is make extensive use of macros. Macros are evil in my book. I’ve been bitten. I know they can be useful in limited circumstances, but MFC accomplishes a lot of its magic with macros. And unfortunately, that’s why it can sometimes be a problem–it becomes magic instead of straightforward code.

What’s Wrong with this code? – 2 – Answer

In the last post, I showed some code that had a very simple problem.

The problem is that when you call HIWORD, it converts the 16 bits into an unsigned short, which then gets passed as an int padded with zeros–not sign extended (it’s not signed). It will NEVER be less than zero. The solution is to cast it to a signed short before calling the function or change the function parameters to be signed short instead of int.

 

Macros are evil

I’m innocently developing a device context class for my LFC framework and I want a method called SelectPen. All of a sudden I’m getting very weird linker errors about how SelectPen is not defined.

It turns out that SelectPen is a macro defined in windowsx.h as an alias for SelectObject.

#define SelectPen(hdc, hpen) ((HPEN)SelectObject((hdc), (HGDIOBJ)(HPEN)(hpen))) Very annoying.Very annoying.Very annoying.