Miscellaneous notes

Get window size/position in parent client co-ordinates

To find the size and position of a child window relative to the parent window’s client area:

// Find out the area of this window in screen coordinates.
CRect rectWindow;
GetWindowRect(&rectWindow);

// Convert the area to client coordinates of the parent window.
GetParent()->ScreenToClient(&rectWindow);

String to/from numeric conversion functions

MSDN: see "Data Type Conversion APIs".

Use the family of API functions "Vartype2Fromtype1" to convert from type1 to type2. String conversions take into account the locale, i.e. regional settings on the user’s computer.

Specifying fonts in logical and point sizes

The API function CreateFont (and CreateFontIndirect, which uses the LOGFONT structure) specifies the size of the font in logical units. In the default mapping mode (MM_TEXT), one logical unit equals one device unit, i.e. one pixel.

The MFC class CFont provides methods CreatePointFont (and CreatePointFontIndirect) that specify the size of the font in tenths of a point.

Disable Size/Maximize/etc. commands

MSDN: see "HOWTO: Preventing an MDI Child Window from Changing Size", knowledge base ID Q71669.

  1. Provide a handler for the WM_SYSCOMMAND message, and prevent the relevant command from being handled. For example:
    void CMainFrame::OnSysCommand(UINT nID, LPARAM lParam)
    {
        // Disable the "Size" command, by trapping it then ignoring it.
        if ((nID & 0xFFF0) == SC_SIZE)
        {
            return;
        }
        
        // Default handling for all other system commands.
        CWnd::OnSysCommand(nID, lParam);
    }
      
  2. Grey out the relevant command on the application’s system menu, within a handler for the WM_INITMENU message. For example:
    void CMainFrame::OnInitMenu(CMenu* pMenu)
    {
        // Call the base class handler.
        CFrameWnd::OnInitMenu(pMenu);
        
        // Get a copy of the system menu.
        CMenu* pSystemMenu = GetSystemMenu(FALSE);
        
        // Grey out (and disable) the "Size" command.
        pSystemMenu->EnableMenuItem(SC_SIZE, MF_GRAYED|MF_BYCOMMAND);
    }
      

Focus

When a main frame window (or a dialogue box) loses the input focus, Windows sends it a WM_ACTIVATE message with WPARAM=WA_INACTIVE. The window should record which child window actually had the focus, using the GetFocus API function.

When a main frame window (or a dialogue box) gains the input focus, Windows sends it a WM_ACTIVATE message with WPARAM=WA_ACTIVE or WA_CLICKACTIVE. The window should set the focus to the child window which previously had the focus, using the SetFocus API function.

Add a COM interface to any old code

  1. Use GUIDGEN.EXE to get a new GUID for your interface.

  2. Create an IDL file defining your interface, and add it to the "Source Files" of your project. For example:
    // Include standard type definitions.
    import "wtypes.idl";
    
    // Definition of IUnknown.
    import "unknwn.idl";
    
    [ uuid(12345678-1234-1234-1234-123456789ABC), object ]
    interface IName : IUnknown
    {
        HRESULT CustomMethod();
    }
  3. Create a class implementing the required interface. Note that the class probably won’t need reference counting, since it doesn’t belong to a COM object: it probably has a static lifetime. For example:
    #include "idlfile_i.c"
    #include "idlfile.h"
    
    class CName : public IName
    {
        virtual ULONG STDMETHODCALLTYPE AddRef()
        {
            return 1;
        }
        
        virtual ULONG STDMETHODCALLTYPE Release()
        {
            return 1;
        }
        
        virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void FAR* FAR* ppvObj)
        {
            *ppvObj = this;
            return S_OK;
        }
        
        virtual HRESULT STDMETHODCALLTYPE CustomMethod()
        {
            // Switch the MFC context from the extension DLL back to the main application.
            AFX_MANAGE_STATE(NULL);
        
            // Implementation code.
            return S_OK;
        }
    };
        
    CName oName;
  4. The interface can be passed (to whoever requires it) as &oName.

  5. If the class implements (i.e. is derived from) more than one interface, casting will be required to get the right interface pointer. QueryInterface could be implemented like this:
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void FAR* FAR* ppvObj)
    {
        HRESULT hResult;
    
        if (riid == IID_IUnknown)
        {
            *ppvObject = static_cast<IUnknown*>(this);
            hResult = S_OK;
        }
        else if (riid == IID_IName)
        {
            *ppvObject = static_cast<IName*>(this);
            hResult = S_OK;
        }
        else
        {
            *ppvObject = NULL;
            hResult = E_NOINTERFACE;
        }
        
        return hResult;
    }