The University of Queensland Homepage
School of ITEE ITEE Main Website

 Windows development tips

The CDialogBar class comes in handy at times. However, by default, it does not have the focus set to any button. I tried everything to get the focus to the toolbar, but nothing seemed to work. So you can't use the dialog bar without a mouse. If only you can set the focus to one button, them all the keyboard shortcuts work.

It dawned on me that the Print Preview dialog bar gets the focus correctly, and Microsoft publishes the source code to most of MFC. So in fact, all I had to do was to find the CPreviewView::OnActivateView function, and copy that functionality. (They have a pointer to what they call the toolbar as a member function; I embed the dialog bar in the Frame class, so I had to add access functions to my frame class to get a CWnd of the dialog bar). On my old copy of MSVC, I found this function in the viewprev.cpp file.

To pop up a complete new View, create a document template in Application::InitInstance, but don't call AddDocTemplate(pDocTemplate).  Usually, you will need classes for the frame, document and view that are different from the main window's classes. When the time comes to pop up the new View, first create a new document with this code:

    // Create a plot document at runtime
    CMyApp* pApp = (CMyApp*)AfxGetApp();
    CRuntimeClass* pRuntimeClass = RUNTIME_CLASS(CPopupDoc);
    CPopupDoc* pPopupDoc = (CPopupDoc*)pRuntimeClass->CreateObject();
    ASSERT( pPopupDoc->IsKindOf( RUNTIME_CLASS(CPopupDoc)));

Use the pointer to initialise the document - unserialise from a file, or however you want. Then instantiate the new frame and view with this code:

    CFrameWnd* pFrame = pApp->m_pPopupTemplate->CreateNewFrame(pPopupDoc, NULL);
    pApp->m_pPopupTemplate->InitialUpdateFrame(pFrame, NULL);

This view can be derived from CScrollView if desired, and it can use print preview code if desired. (Pinch code from your main class if needed). If you don't want a menu, give it a dummy menu in the nIDResource parameter to the template constructor, and in the frame class override OnCreate() and call SetMenu(NULL);

I find I often want to support more than one file extension for a document. For example, you might want to be able to load and save a binary or a text version of the data (.dat for the binary form, and .txt for the text form). This can be accomplished by deriving a class from CSingleDocTemplate or CMultiDocTemplate. Code to do this is available here:
http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/Q141/9/21.ASP&NoWebContent=1

When creating a modeless dialog box, don't create it as a child window (Styles tab of Properties in the dialog editor). Do set the visible style. If you set the "Center" style, it will centre in the screen, not its parent window. To centre it in its parent's window, don't use that "Center" style, and just use MoveWindow to centre it. (Do everything in screen coordinates, so use GetWindowRect instead of GetClientRect.) To make a dialog modeless, you just need to call CDialog::Create in its constructor, or soon after it is constructed (and set the Visible style with the dialog editor).

With MSVC, if you don't call SetRegistryKey in the App's InitInstance function, WriteProfileInt/String writes to the registry key HKEY_CURRENT_USER\Software\Local AppWizard-Generated Applications\appname\entry .

To prevent an MFC MDI application from generating an empty initial document, add the following code before the call to ProcessShellCommand in the App's InitInstance:
    // Prevent an empty document being initially generated
    if (cmdInfo.m_nShellCommand == CCommandLineInfo::FileNew)
        cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;

To support serial port I/O on all Win32 platforms, I found the best way was to use overlapped I/O. You need to use the FILE_FLAG_OVERLAPPED flag in
CreateFile, pass a pointer to an OVERLAPPED structure to ReadFile and WriteFile, and you need to create an event with CreateEvent. Wait for the event to become signalled with MsgWaitForMultipleObjects (you wait for only 1 event, but WaitForSingleObject doesn't allow you to wait for ordinary messages like mouse movement and paint messages). Check the return value; if it was not due to a timeout or the event, do a PeekMessage / TranslateMessage / DispatchMessage loop. That allows for normal operation of cancel buttons, etc. (You may need other PeekMessage loops to get paint messages to work properly).

Occasionally, it seems necessary to add message handlers by hand. If you do, remember to use the correct signature (e.g.
UINT, LONG for ON_MESSAGE handlers), even if you don't use all the parameters. Remember: Windows procedures are (mostly) Pascal calling convention; the callee has to pop the number of arguments put there by the caller. For C calling convention, the caller pushes and pops the arguments; it doesn't matter if you don't declare all the parameters in the callee. I had a repeatable crash which only showed up some of the time, and only in the release build; it took several days to track it down.


Visual Studio Projects

This section is not strictly about Windows development, however the Visual Studio IDE from Microsoft is quite popular. I found to my cost that is is a bad idea to copy project files. They have embedded in them a unique identifier (search for GUID=), and if these are not unique as expected, strange problems result. For example, I would modify the project dependencies, close the dialog, re-open the project dependencies, and they would be different. When the GUIDs were manually corrected (make sure that solution and project files match, and remove dependencies with identical GUIDs), the problem vanished. Note that dependencies are silently used for more than the order of building projects within a solution; they imply .lib files that if will cause unresolved symbol errors at link time.

I also found that I had .lib files specified under "Module Definition File" (Linker Input). It's amazing the abuse that the compiler will put up with in there, causing many warnings, and possibly subtle problems. Usually, you will not need a definition file (.def).

Some of the hardest problem to track down are the multiple definitionsi in implicitly linked library files. This can sometimes happen when some inputs to a program are linked with debug versions of the runtime libraries, and some with release. A possible aid would be to look at the "command line" section under "link" in project properties. Check for access to release objects or libraries in debug mode, and vice versa. You can click on a different project when this dialog is open, and it will show the information for that project. So you can flip between projects that are supposed to be similar, looking for major differences.

Last modified: 08/Sep/06: Visual Studio projects.