FAQ

Win32++

Frequently Asked Questions (FAQ)

How do I install Win32++? How do I start a project of my own?
Why does Win32++ use a map for HWNDs and CWnd*s?
Why does Win32++ use TLS (Thread Local Storage) during window creation?
How do I create a window that is initially hidden?
How do I create a window that is initially minimised or maximised?
How should I end an application?
How do I access one CWnd from within another?
How do I avoid automatically adding the Win32++ namespace to the global namespace?
How can I tell what type of window a CWnd or HWND is?
Should I use PostMessage or SendMessage, and what is the difference?
How do I get a WM_LBUTTONDBLCLK message for left button double clicks?
How do add icons to menu items?
How do I theme my popup menu?
How do I create a Wizard?
How do I avoid memory leaks?
How do I test for memory leaks?
How do I avoid GDI resource leaks?
How do I check if my program is leaking memory or GDI resources?
Why does my program assert?
Why does my program throw an exception?
Why are none of my resources working?
How do I avoid flicker in my program?
Why does the desktop flicker when I run my program?

How do I get the Desktop's window handle?
When are pointers from FromHandle deleted, and how do I use them safely?
How do I do Idle processing?
When do I need to use detach for a CDC?
How do I use XP themes?
How do I override the CToolBar or CStatusBar class for frames?
How do I implement a wait cursor?
How do I create a vertical ToolBar?

How do I install Win32++ ?

Obtain a copy of Win32++ from sourceforge, and extract the zip file into a directory of your choosing. The directory you choose might be within your documents folder. Be sure to retain the directory structure of Win32++ when extracting files from the zip archive. To download a copy of  Win32++ proceed to the project's hosting at SourceForge here.

How do I start a project of my own?

Win32++ contains a set of "NewProject" files in the "new projects" folder for this purpose. It might prove easier though to make a copy of one of the samples that ship with Win32++, and use that as your starting point.

Why does Win32++ use a map for HWNDs and CWnd*s rather than CreateWindow's lpParam when creating the window?

It would be possible to store the CWnd pointer in the lpParam during window creation, but this has its limitations. MDI windows, for example, use lpParam for its own purpose during window creation.

Using a map to store the CWnd pointer and HWND also support the framework's use of FromHandle to retrieve the CWnd pointer associated with a HWND.

Why does Win32++ use TLS (Thread Local Storage) during window creation?

Win32++ supports the creation of windows in different threads. When several windows are created in different threads simultaneously, TLS keeps the code thread safe.

How do I create a window that is initially hidden?

Windows created by Win32++ are visible by default. To create a window that is initially hidden, override PreCreate and specify a windows style that does not include WS_VISIBLE style as follows:

void CMyWin::PreCreate(CREATESTRUCT &cs)
{
// Sets the CREATESTRUCT parameters prior to window creation
cs.style = 0; // No WS_VISIBLE style is set }

Use ShowWindow when you are ready to display the window.

How do I create a window that is initially minimised or maximised?

Create a window that is initially hidden, and then use ShowWindow to display it as minimised or maximised by specifying the appropriate value for nCmdShow e.g SW_SHOWMAXIMIZED or SW_SHOWMINIMIZED.

There are window styles called WS_MAXIMIZE and WS_ICONIC which can be specified when creating windows, but these don't apply to top level windows. They can be used for MDI child windows.

How should I end an application?

In general, the best way to end an application is to post a WM_CLOSE to the top level window. This gives the application an opportunity to save any settings and clean up objects before destroying the main window and ending the program. The main window should then issue a PostQuitMessage when its window is destroyed. Win32++ issues the PostQuitMessage for us when a window inherited from CFrame is destroyed.

How do I access one CWnd object from within another?

Child windows for the CWnd are normally Class members of the CWnd. We should access the CWnd of child windows through these class members.

If the HWND of the window is known, we can use FromHandle to get the CWnd associated with it. If the relationship between the windows are known, we can use functions like GetParent and GetAncestor to access other windows.

Finally, we can use GetApp to get a pointer to our CWinApp class. The class you inherit from CWinApp could have a member that returns a pointer to the top level window it created. You could use that to step to the window you need.

For example.
Suppose CFrameApp inherits from CWinApp, and has CMainFrame as one of its class members. CFrameApp could have a member function that returns a pointer to CMainFrame. To access the frames status bar from anywhere we could use:

CFrameApp* pApp = (CFrameApp*)GetApp();
CStatusBar* pStatus = pApp->GetMainFrame()->GetStatusBar();

Note that a child window wouldn't normally call the functions of a parent CWnd directly. In most circumstance this represents poor program design. It is usually more appropriate for the child CWnd to send a message or notification to the parent and let the parent decide what to do with it. The message could be a user defined message or notification.

How do I avoid automatically adding the Win32xx namespace to the global namespace?

If the NO_USING_NAMESPACE macro is defined, the Win32xx namespace will not be added to the global namespace.

How can I tell what type of window a CWnd or HWND is?

We can use dynamic cast to identify the type of CWnd our CWnd* points to. For example:

if ( dynamic_cast<CToolBar*>(pWnd) )
{
  TRACE( _T("pWnd is a CToolBar*\n") );
}
We can also look at the class name of the window to identify its type.
if (lstrcmp(GetParent()->GetClassName(), _T("ReBarWindow32")) == 0)
{
  TRACE( _T("The Parent window is a ReBar control\n") );
}

Should I use PostMessage or SendMessage, and what is the difference?

The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message. The PostMessage function places (posts) a message in the message queue associated with the thread that created the window and returns without waiting for the thread to process the message.

Normally we would use SendMessage for windows in the current thread, and PostMessage for windows in a different thread. In multi-threaded applications it is usually undesirable to hold up a thread with a window, waiting for a window in a different thread to respond.

How do I get a WM_LBUTTONDBLCLK message for left button double clicks?

The CS_DBLCLKS class style allows the window to send the WM_LBUTTONDBLCLK message in response to a double left button click. Use the PreRegisterClass to register a window class with the CS_DBLCLKS style.

How do I add icons to menu items?

There are two functions used to add icons to menu items. The AddMenuIcons functions adds a group of icons to menu items from a bitmap, and AddMenuIcon adds an individual icon.

How do I theme my popup menu?

The CWnd we specify in TrackPopupMenu or TrackPopupMenuEx receives notifications from the menu. When we specify CFrame's CWnd in these functions, CFrame will perform the drawing of the menu for us.

How do I create a Wizard?

A wizard is a type of property sheet. Wizards are designed to present pages one at a time in a sequence that is controlled by the application. Refer to the propertysheet sample for a demonstration of how to create a wizard..

How do I avoid memory leaks?

Memory leaks are generated when memory is allocated from the heap, and not returned properly. C++ code we should always allocate dynamic memory by using new, and delete it with delete, or delete[] for arrays.

It is wise to store the pointer returned by new in a smart pointer. Shared_Ptr is a smart pointer provided by the Win32++ framework for this purpose. It can be safely stored in a vector. Storing the pointer in a smart pointer like Shared_Ptr eliminates the need for delete. The Shared_Ptr deletes the pointer for us when it goes out of scope. Storing the pointer in a smart pointer also helps ensure the code doesn't leak memory in the event of an exception, without additional of try catch blocks.

How do I test for memory leaks?

If you are using a Microsoft compiler, Visual Leak Detector can be used to identify memory leaks. Visual Leak Detector is a free utility. It can be downloaded from https://vld.codeplex.com/.

How do I avoid GDI resource leaks?

GDI resources are limited. If the code leaks GDI resources, it will ultimately fail when no more GDI resources are available. The best way to avoid GDI leaks is to use the CDC and GDI object classes provided with Win32++. These automatically release the device contexts and GDI resources.

How do I check if my program is leaking memory or GDI resources?

The window's taskmgr.exe is a very useful tool for identifying memory leaks and GDI resource leaks. It ships with windows and can be configured to display extra columns including GDI objects and working set memory.

If the amount of memory used or number of GDI objects increase without limit when we do things like resize the window, we have a leak.

Why does my program assert?

Asserts are only triggered in debug mode. They are always caused by programming errors, so the cause of the assert should be identified and fixed.

Win32++ will assert to warn that the library has been used improperly. The following sorts of things will cause Win32++ to assert.

  • A CWnd creating a window, when it already has a window assigned to it. If this is intended, the current window should be destroyed first.
  • A CWnd performing a window operation (such as ShowWindow) before the window is created.
  • Attaching a GDI handle (e.g. a HPEN) to a CGDIObject when it already has a handle attached. If this is intended, the current handle should be deleted or detached first.

Remember asserts our our friend. They give us early warning of bugs that might otherwise go unnoticed or be difficult to track down. They help us build robust, reliable code. For this reason, they should be used liberally in the code we write.

Why does my program throw an exception?

Exceptions should indicate that an unexpected error occurred. They may not necessarily indicate a programming error, but programming errors can certainly cause exceptions. If the exception is "handled", the program will continue to run. If the exception is unhandled, the program will abort. For example, C++ will generate an exception if an attempt to allocate memory dynamically using "new" fails.

Win32++ generates an exception when an attempt to create a window fails (in which case it will attempt to indicate why). It will also generate and handle an exception if an attempt to save values in the registry fails.

You may choose to generate and handle exceptions in your own code. As the name suggests though, the generation of exceptions should be the exception, not the rule.

Why are none of my resources working?

Resources are defined in a resource script file, often called "resource.rc" This file needs to be added to the set of files compiled by our compiler.

How do I avoid flicker in my program?

Flicker is an annoying visual effect caused when a window is rapidly redrawn differently. It may show up when we resize the window. Depending on the cause of the flicker, these techniques might help.

  • Use double buffering. With this technique we do all the drawing on a memory device context. When the drawing is complete, copy this to the window with BitBlt so we only draw to the window once.
  • Suppress the redrawing of the window background by handling OnEraseBkgnd.
  • Use DeferWindowPos to reposition a set of windows simultaneously.
  • Avoid invalidating the window unnecessarily.
  • Use of SetRedraw to turn window drawing off and on.

Why does the desktop flicker when I run my program?

Some functions, including InvalidateRect can use NULL as the handle for the desktop's window. If we perform an InvalidateRect on a NULL HWND, this will invalidate the desktop, forcing it to redraw.

How do I get the Desktop's window handle?

There are a few functions, such as GetDC and InvalidateRect that can use NULL as the HWND for the desktop. NULL isn't a real window handle however, and IsWindow(NULL) will return FALSE. The Windows API function ::GetDesktopWindow returns the handle to the desktop window, and Win32++'s GetDesktopWindow function returns a CWnd pointer to the desktop window.

When are the pointers from FromHandle deleted, and how do I use these function safely?

The FromHandle functions can return pointers to CWnd, CMenu, CDC, CImageList and CGDIObject when provided with the handle. If we use FromHandle to get the CWnd* from a HWND, for example, the framework checks the CWnd map to see if a CWnd for the HWND already exists. If the CWnd already exists, its pointer is returned. If the CWnd doesn't already exist, a temporary CWnd is created and its pointer is returned. Pointers for other types of objects behave in the same way.

The pointer returned by FromHandle might point to a temporary object. Temporary objects are deleted automatically some time after this current message is processed, and shouldn't be saved for later use. We should assume the pointer will be deleted when the framework fetches the next message from the message queue and processes it.

In practical terms, it is quite safe to copy the pointer returned by FromHandle and store it in a local variable in a function and use it there. The pointer will not be deleted until after the function completes. It would NOT be safe to store the pointer returned by FromHandle in a global variable, or a class member variable and expect to be able to use it sometime later.

How do I do Idle processing?

OnIdle will be called repetitively until it returns FALSE while there are no messages queued, incrementing lcount each time it is called. To implement idle processing, override CWinApp::OnIdle. Larger tasks will need to be split into chunks to allow the application to respond promptly to keyboard and mouse input. For tasks that have been split into chunks, do the first chunk when lcount is 0 and return TRUE, the second when lcount is 1 and return TRUE etc. When all chunks are done, OnIdle should return FALSE. The framework doesn't use OnIdle internally, so there is no need to call CWinApp::OnIdle when when overriding OnIdle.

OnIdle is not suitable for tasks that need to be performed at regular intervals. Use a timer for those.

Its important to remember that idle processing was introduced for 16 bit windows because it wasn't capable of running multiple threads. In 32 bit and 64 bit windows, worker threads provide a better way of performing background tasks without affecting the user's interaction with the application. Having said that, idle processing can prove simpler than threads for very small tasks. While larger idle tasks can be split up into chunks and performed during different cycles of the OnIdle processing, a worker thread would do this more efficiently, and would probably be simpler to implement.

When do I need to use detach for a CDC?

There are some HDCs we shouldn't destroy. These are the HDCs that windows operating creates for us, and provides them in messages such as WM_PAINT, WM_ERASEBKGND, NM_CUSTOMDRAW etc. If we choose to attach those HDCs to one of our CDCs we need to detach them before the CDC goes out of scope. In general, if we create the HDC, we are responsible for destroying it, but if the operating system creates the HDC for us, it is responsible for destroying it.

It can be be more convenient to use FromHandle to assign a temporary CDC for those HDCs provided to us by the operating system. Temporary CDCs don't destroy the HDC they manage when their destructor is called, so this eliminates the need to detach the HDC. For example, the Win32++ framework uses FromHandle to assign a temporary CDC to the HDC provided by the NM_CUSTOMDRAW notification when performing custom drawing.

How do I use XP themes?

In order to use XP themes, our application must contain a manifest. We can specify a manifest section in our resource script (resource.rc) as follows:

/////////////////////////////////////////////////////////////////////////////
//
// RT_MANIFEST
//

1                       RT_MANIFEST             "res/Win32++.manifest"

The manifest file supplied with the samples is compatible with both 32 bit and 64 bit windows.

Older compilers such as visual studio 6 and Borlands C++ compiler version 5.5 may not have a definition for RT_MANIFEST. RT_MANIFEST is defined as MAKEINTRESOURCE(24).

How do I override the CToolBar or CStatusBar class for frames?

If you should need to modify the CToolBar class that CFrame uses, you can do the following.

1) Inherit your new ToolBar from the CToolBar class. We will call the new ToolBar class CMyToolBar.
2) Add a CMyToolBar member variable to CMainFrame called MyToolBar.
3) Override CFrame's GetToolBar function in CMainFrame as follows:

virtual CToolBar* GetToolBar() const
{
  return const_cast<CMyToolBar*>(&m;_MyToolBar);
}

CMainFrame will now use your CMyToolBar class in place of CToolBar. You could use the same technique for overriding CStatusBar.

How do I implement a wait cursor?

SetCurser is the Windows API function which sets the cursor. By default, windows will set the cursor back to the one defined in the window class each time the mouse is moved. We can handle the WM_SETCURSOR message to determine which cursor should be displayed when the mouse is moved.

We can implement a wait cursor like this:

void CView::DoWaitCursor(BOOL bWait)
{
  m_bWait = bWait;	// m_bWait is a member variable

  if (m_bWait)
    SetCursor(LoadCursor(NULL, IDC_WAIT));
  else
    SetCursor(LoadCursor(NULL, IDC_ARROW));
}

	
LRESULT CView::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  switch (uMsg)
  {
  case WM_SETCURSOR:
    if (m_bWait)
    {
        SetCursor(LoadCursor(NULL, IDC_WAIT));
			
        // Prevent setting the cursor back to default
        return 0L;
    }
    else
      SetCursor(LoadCursor(NULL, IDC_ARROW));
		
    break;
  }
	
  // Do default processing for other messages
  return WndProcDefault(uMsg, wParam, lParam);
}

How do I create a vertical ToolBar?

There are two rather similar methods for achieving this:

Method 1:

  • Define a toolbar as you would for a horizontal toolbar
  • Add the CCS_LEFT (or CCS_VERT or CCS_RIGHT styles)
  • Add the TBSTATE_WRAP style to each ToolBar button.

The ToolBar will be automatically placed on the side of the parent window, specified by the style (e.g CCS_LEFT).

Method 2:

  • Define a toolbar as you would for a horizontal toolbar
  • Add the CCS_LEFT (or CCS_VERT or CCS_RIGHT styles)
  • Add the TBSTATE_WRAP style to each ToolBar button.
  • Position the ToolBar manually using SetWindowPos

Note:

  • Method 2 is required for vertical ToolBars within ReBars
  • CCS_NODIVIDER can be added to suppress the drawing of the ToolBar's divider
  • Use DeferWindowPos to reposition a group of windows simultaneously.