Blog Archives

Adding HTML Content to the WebBrowser Control Dynamically

A common problem in dealing with the Microsoft’s WebBrowser control seems to be making it display HTML content.  The usual way of doing this is creating a HTML file, and using the IWebBrowser2::Navigate( ) or IWebBrowser2::Navigate2( ) methods.  It works perfectly, but it has some limitations.  You need to specify a URL or path to the HTML file.  It means that you should either have an external file, and distribute it with your application (which is not desirable, because the user would be able to directly edit it), or putting the HTML file into a resource in your module.  The downside with this is that you can’t make the WebBrowser control show dynamic data, which is generated by your application at runtime.  To overcome this problem, some people try to create a temporary HTML file, and Navigate( )-ing to that file, and some other people might develop a COM object and use it so that the application could talk to the web page, and vice versa, and hence transfer dynamic data.

Both of the above methods work, but are not perfect solutions, because they would have a lot of overhead (creating a file, doing unnecessary I/O, writing a COM object, and appropriate script in the page itself, and so on).  You would wish that you create a normal string containing some HTML code, and getting the WebBrowser to show that content.  I’ll show you how to do this here.  Also, for some applications (to name one, Yahoo Messenger), you would need to add some HTML content to the document currently loaded at runtime, without changing the old stuff that are being displayed.  This is also possible.

In the ZIP file found at the bottom of the article, you’ll find two files HTMLWriter.h and HTMLWriter.cpp which define the class CHTMLWriter as well as two sample applications.  Here is the description of the CHTMLWriter public member functions:

  • CHTMLWriter::CHTMLWriter( IUnknown * pUnk );
    CHTMLWriter::CHTMLWriter( IWebBrowser2 * pWB );

    The first constructor is used when you want to use this class with a ClassWizard-generated CWebBrowser2 class (for example, when you insert a WebBrowser control in a MFC dialog application).  The second constructor is used when you want to use this class with a MFC CHtmlView-derived class.  For the first case, you always pass CWnd::GetControlUnknown( ) to the constructor, and for the second case, you should pass m_pBrowserApp to the constructor.  (See the sample code to see how to do this).
  • CHTMLWriter::Write( LPCTSTR pszHTMLContent );
    This method writes the HTML content specified by pszHTMLContent to the WebBrowser control.  The pszHTMLContent should be a string containing raw HTML code, like "<html><head></head><body>My HTML file</body></html>".
  • CHTMLWriter::Add( LPCTSTR pszHTMLContent );
    This method appends the HTML content specified by pszHTMLContent to the WebBrowser control, leaving the rest of the document being displayed unchanged.  The pszHTMLContent should be a string containing raw HTML code, like "<p>New HTML content</p>".

Using the class couldn’t be any simpler.  You just construct an instance on the stack with the appropriate constructor, and call the Write( ) or Add( ) method, passing the string containing the HTML content to them.  The sample application MFCWebBrowserDemo demonstrates how to use this class in a dialog-based MFC application in which I’ve inserted the WebBrowser control from the Registered ActiveX Controls accessible from Project > Add To Project > Components and Controls menu item.  The sample application DocVwWebBrowserDemo demonstrates how to use this class in a MFC document/view application whose view class is derived from CHtmlView.

If you look at the source code for the class, you’ll figure out how I’ve done it, and then you can add your own methods to the class to customize it further.

 Download source code for the article

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++

Resource-only DLL AppWizard

As you know, Win32 DLLs can contain both code and resources.  They can also contain only code, and only resource.  A DLL with no code and only resources is called a resource-only DLL.  Resource-only DLLs are used for many purposes, like building multilingual applications, in which each resource-only DLL contains the resources specific to a language, and at runtime, depending on the user’s choice, you load one appropriate DLL using the LoadLibrary( ) function.

Creating a resource-only DLL is not a complicated task.  You should create an empty Win32 DLL project, add a resource script (RC) file to the project, and adding the "/noentry" switch to the linker’s options.  Although it’s an easy task, my being lazy caused me to create a custom AppWizard for creating these kind of DLLs.  The AppWizard does not have any steps (it doesn’t need to!), and once you create a resource-only DLL using it, you can add resources to the RC file, and build the DLL without any change to the project’s settings.  Download the source and binary files for this custom AppWizard at the bottom of the article.  You should copy the AWX file in the C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Template directory to see it in the New Project dialog box.  Please note that this AppWizard has been built for Visual C++ 6.

 Download source code and the AppWizard for the article

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++

Non-pushbutton Controls in Toolbars

Several Windows application use toolbars, and I’m sure you have noticed that many of them place non-push-button items inside their toolbars.  A good example is WordPad which for instance has a combo box for selecting the font family inside its formatting toolbar.  Have you ever wondered how this is done?  This article explains the steps you need to place some kind of control inside a toolbar.  The control I have chosen here is a combo box, but you can perform similar steps to place any kind of control inside your toolbars.

  1. Create a toolbar (if you don’t have one already) inside the MSVC resource editor, and add any buttons to it, as you would make a normal toolbar.  Then, close the MSVC workspace, and open the .rc file containing the toolbar definition in some text editor capable of saving documents in plain text, NotePad being a good example.  Add a placeholder SEPARATOR item to the toolbar definition, so that the toolbar definition would look like this:

    IDR_MAINFRAME TOOLBAR DISCARDABLE  16, 15
    BEGIN
        BUTTON      ID_FILE_NEW
        BUTTON      ID_FILE_OPEN
        BUTTON      ID_FILE_SAVE
    	SEPARATOR
        BUTTON      ID_EDIT_CUT
        BUTTON      ID_EDIT_COPY
        BUTTON      ID_EDIT_PASTE
    	SEPARATOR
    	SEPARATOR  /* Place holder for the combo box */
    	SEPARATOR
        BUTTON      ID_FILE_PRINT
    	SEPARATOR
        BUTTON      ID_APP_ABOUT
    END
  2. Go to the Resource View, right click on the "MyApp resources" tree item, choose Resource Symbols, click the New button, and add a new resource symbol with an appropriate name, like IDC_COMBO.
  3. Derive a class from CToolBar using the Class Wizard, give it a reasonable name (like CExtendedToolBar) and add a CComboBox member variable to that class.  Then, override the CreateEx( ) member function of the class like this:
    BOOL CExtendedToolBar::CreateEx(CWnd* pParentWnd,
    DWORD dwCtrlStyle /* = TBSTYLE_FLAT*/,
    DWORD dwStyle /* = WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP*/,
    CRect rcBorders /* = CRect(0, 0, 0, 0)*/,
    UINT nID /* = AFX_IDW_TOOLBAR*/,
    UINT nResourceID /* = IDR_MAINFRAME */)
    {
    if (!CToolBar::CreateEx( pParentWnd, dwCtrlStyle,
    dwStyle, rcBorders, nID ) ||
    !CToolBar::LoadToolBar( nResourceID ))
    return FALSE;

    const int nWidth = 150;
    const int nHeight = 200;

    const UINT nItemIndex = 8;

    SetButtonInfo( nItemIndex, IDC_COMBO, TBBS_SEPARATOR, nWidth );

    CRect rcItem;
    GetItemRect( nItemIndex, &rcItem );
    rcItem.bottom = rcItem.top + nHeight;

    if (!m_ComboBox.Create( WS_CHILD | WS_VISIBLE | WS_VSCROLL | CBS_DROPDOWNLIST,
    rcItem, this, IDC_COMBO ))
    {
    DestroyWindow();
    return FALSE;
    }

    return TRUE;
    }
  4. Make sure that the creation code for the toolbar is like this (no LoadToolbar( ) call is necessary):
        if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
    | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC))
    {
    TRACE0("Failed to create toolbar\n");
    return -1; // fail to create

    }
  5. Add a small member function to the CExtendedToolBar class that allows access to the member combo box object:
    CComboBox & CExtendedToolBar::GetComboBox()
    {
    return m_ComboBox;
    }
  6. Add a resource string in the form of "Status Text\nTooltip String" like a normal toolbar button.  The "Tooltip String" will appear as a tooltip when the mouse is over the combo box, and the "Status Text" will appear in the status bar.
  7. Handle any combo box notifications like normal.  These notifications should be handled inside the derived toolbar class.

Note that if you want to update the combo box contents according to your application’s state, the process is different from updating a normal toolbar button.  You need to override the virtual function OnUpdateCmdUI( ) inside the derived toolbar class, and first call the base class version, and then add any logic for updating the combo box.  This function will be called from CWinApp::OnIdle( ) and it’s the root of all ON_UPDATE_COMMAND_UI update handlers.  If you forget to call the base class version, then all the other update handlers will stop working, so watch out!

The sample application at the bottom of the article contains a working sample using the steps above.  Download it, and investigate it, it’s pretty easy!  So now you too can start having custom toolbars, happy toolbar-ing!

 Download source code for the article

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++

Modeless Dialogs

Creating a modeless dialog in MFC is very easy, however, many MFC programmers seem to have problems with it.  Here I demonstrate the steps needed to be taken to create an MFC modeless dialog:

  1. Like creating any other dialog, first you need to insert a dialog resource into your project, and derive a class from CDialog, as you would do for a normal modal dialog.  I won’t describe this step more because I assume that every basic MFC text describes it well.
  2. Add a function named Create( ) to your dialog class, like this:
    // inside the .h file:

    class CMyDialog : public CDialog
    {
    // ...
    BOOL Create(CWnd * pParent = NULL);
    };

    // inside the .cpp file:

    BOOL CMyDialog::Create(CWnd * pParent)
    {
    return CDialog::Create( CMyDialog::IDD, pParent );
    }
  3. Make sure the CMyDialog constructor calls the default constructor of CDialog:

    CMyDialog::CMyDialog(CWnd * /*pParent*/)
    : CDialog()
    {
    // ...
    }

It’s that easy!  Now, to use your modeless dialog, you’ll need to consider the following points:

  1. You should call CMyDialog::Create( ) instead of CMyDialog::DoModal( ) to create a modeless dialog.
  2. When using a normal modal dialog, you create an instance of the dialog class on the stack, and call DoModal( ).  DoModal( ) would not return until the dialog is dismissed, and the dialog object can be safely destroyed.  But this is not the case with modeless dialogs.  Modeless dialogs should be created on the heap, because the Create( ) functions returns immediately after creating the dialog, and does not wait for the dialog to be dismissed, so if you call the dialog object on the stack, when the object goes out of scope, the destructor is called, and suddenly the dialog disappears!  Not what you would want of course.
  3. To dismiss a modeless dialog, CDialog::DestroyWindow( ) should be called.  Note that the default CDialog::OnOK( ) and CDialog::OnCancel( ) functions shouldn’t be called for a modeless dialog.
  4. Typically, a modeless dialog should be a "manager" object, which would be a class derived from CWnd or CView.  The manager object is responsible for creating and destroying the dialog object.  One usual way to do this is to register a custom window message, and make OnOK and OnCancel functions post that message to the manager window, and then the manager window is responsible for calling DestroyWindow.  If you are unclear with this, please download the demo application at the bottom of the article which demonstrates this technique.

 Download source code for this article

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++

Single Instance Applications

To limit your application to a single instance, the most common way is creating a named Mutex using CreateMutex, and checking to see if that Mutex already existed or not.  If that Mutex already existed, it means that your application is the second instance on the system, so you can kill it right away.

Some applications do more than this, when you attempt to open a second instance, not only they don’t let you do that, but also they bring the older instance to front.  How do they do it?  It’s simple.  They register a WNDCLASS with a specific name, and every time they call FindWindow to find windows of that class.  Once they found such windows, they simply call SetForegroundWindow to bring the other window to front, and exit themselves.

To simplify things a bit, I wrote a C++ class named CSingleInstance (found in singinst.h and singinst.cpp files in the ZIP file at the bottom of the article).  To use this class, you add it to your CWinApp-derived class’s base class list as public, like this:

class CSingleInstanceApp : public CWinApp, public CSingleInstance
{
// ...
}

Then, you call the constructor with appropriate parameters:

CSingleInstanceApp::CSingleInstanceApp()
: CSingleInstance( false, _T("SingleInstanceApplication") )
{
// ...
}

The first parameter is a bool indicating whether you want to activate the older instances of the class if you’re being the second instance.  Passing true to this parameter causes the second instance to bring the previous instance to front.  The second parameter is an optional string, which specifies the name of the Mutex and window class.  This string should not be longer than MAX_PATH.  If you don’t specify this parameter, or pass NULL to it, a default name would be used ("Single Instance Application — ExeFileName.exe").

The next step is overriding CWinApp::InitInstance (if it’s not already overridden) and adding the following lines at the beginning of the code for that function:

BOOL CSingleInstanceApp::InitInstance()
{
if (!IsFirstInstance())
return FALSE;

// ...
}

That’s it if you don’t want to bring the older instance of the application to front.  If you wish to do so, you would need to make two changes.  First, you should change the first parameter passed to the CSingleInstance’s constructor to true, and also you need to override the PreCreateWindow in your CMainFrame class, and change it like this:

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
cs.lpszClass = ((CSingleInstanceApp *) ::AfxGetApp())->GetWndClassName();

return CMDIFrameWnd::PreCreateWindow( cs );
}

This will make the main frame window be created with the window class that CSingleInstance has registered.

 Download source code for this article

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++

System Standby and Hibernation

Some time back, I wrote a small utility for putting the system on standby mode, or hibernate it.  I created a C++ class named CPowerState, and encapsulated all the actions needed to do this inside that class.  My class is not dependent on anything else, and is not an MFC class, but you can use it in MFC applications as well as SDK applications.

Using CPowerState couldn’t be any simpler.  You just construct an object of this class on the stack, and call Standby( ) or Hibernate( ) methods, and check the bool return value.  Here is how to do it:

CPowerState ps;
bool bSuccess = ps.Standby();
if (!bSuccess)
::MessageBox( NULL, TEXT("Standby operation failed."), TEXT("Error"), MB_OK | MB_ICONSTOP );

Or to hibernate the system:

CPowerState ps;
bool bSuccess = ps.Hibernate();
if (!bSuccess)
::MessageBox( NULL, TEXT("Hibernate operation failed."), TEXT("Error"), MB_OK | MB_ICONSTOP );

That’s it.  Just one very important point to consider.  Both the Standby( ) and Hibernate( ) methods, if successful, will return only when the system is activated again (in case of standby) or when it’s started again (in case of hibernation), so you should only check for the false return, because your operation may succeed, but you may receive no true result.  Consider this case.  You hibernate the system using this class, and the next time the user turns on the power of the system, he presses F8 at system boot screen, and chooses "Delete restoration data and proceed to system boot menu" for some reason.  This way, your process is terminated (as well as any other processes running when the system fell into hibernation mode) and the Hibernate( ) function will *never* return, so you will *never* get back the true result.

I’ve tested this code on Windows 2000 Professional and Windows XP Professional, and it works on both systems.  Download the sample application at the bottom of the article and use PowerState.h and PowerState.cpp files in your application.  Also, you can take a look at Power.cpp to see a sample of using this class.

 Download source code for this article

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++

Super TRACE

One of the nice utilities that MFC provides the developers with is the "tracing" utility.  This allows you to mark up any section of the code so that it would print a string message to the debug output window using the OutputDebugString API function.  You can use trace in your application like this:

void my_function( void )
{
TRACE( _T("entering my_function( )") );
// do some work here
TRACE( _T("exiting my_function( )") );
}

Also, it’s possible to use the TRACE macro in a more advanced way to use the printf-like string formatting:

void my_param_function( LPCTSTR string, int number, float flt )
{
TRACE( _T("my_param_function( %s, %d, %f );"), string, number, flt );
// ...
}

The TRACE macro is especially useful when debugging multithreaded code, in which setting breakpoints or using MessageBox’s or other means of checking some value inside a function would change the normal flow of the threads in the program.

There are four varieties of the TRACE macro, names TRACE0, TRACE1, TRACE2, and TRACE3.  They’re the same as TRACE, where as TRACE0 only takes a string parameter, TRACE1 takes one parameter other than the format string parameter, and so on.  So, as an example, the above my_param_function( ) can be written with TRACE3 as well.  Of course, because TRACE0, TRACE1, TRACE2, and TRACE3 wrap the first string parameters inside a _T macro for Unicode compatibility, you should not put the first strings inside a _T, but the other possible strings should be wrapped inside a _T macro.  So, here’s another version of my_param_function:

void my_param_function( LPCTSTR string, int number, float flt )
{
TRACE3( "my_param_function( %s, %d, %f );", string, number, flt );
// ...
}

Now, we’ll come to a negative point in the TRACE macros.  When you watch the debug output window, you see the trace messages, but the only way you have to recognize exactly which part of the code is generating a certain message is to do a "Find in Files" in Visual C++.  This problem shows itself more when you consider you’re debugging a project with, let’s say, 1000 TRACE statements.  Here the Super TRACE macros come in handy.  To use the Super TRACE macros, all you need is to include the header file supertrc.h after including either afx.h or afxwin.h.  Now, all of your normal TRACE, TRACE0, TRACE1, TRACE2, and TRACE3 macros will be changed to Super TRACE macros, which let’s you easily double-click on the trace message in the debug output window to navigate to the exact file and line of the code that has generated the trace messages.  The download link to supertrc.h header file can be found at the end of the article.

MFC itself uses trace macros internally a lot.  A nice feature of Super TRACE is you can force MFC also to print the file names and line numbers of the code that generates the trace message.  But unfortunately, to obtain such a feature, the only way is recompiling the MFC source code (distributed with Visual C++).  In case you’re interested in having Super TRACE in the MFC library itself (and I encourage you to do so) open the stdafx.h file inside the MFC source directory, and add an #include statement for supertrc.h after the include line for afx.h like this:

// ...
// core headers
#include "afx.h"
/*** Super TRACE ***/
#include "supertrc.h"
#include "afxplex_.h"
#include "afxcoll.h"
// ...

And then build the MFC library using the make files provided.

 Download source code for this article

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++

Winsock Error Translator

When writing an application which uses the Winsock library, error checking and handling is a must, because of the unreliable nature of Winsock (you can’t guarantee that a machine is always connected to the network, for example).  Some error situations are recoverable, and some are not.  According to this fact, you must choose to report the occurred error to the user, write a system Event Log entry, append information to a log file, or discard the error.  You can report the error code, but probably a message box stating that "Error 10015" occurred will not mean much to the user.  You need some method to convert the error message to a human readable string, and then use that string when reporting, either with or without the error code number.

You would expect to be able to call FormatMessage( ) passing the error code returned from WSAGetLastError( ) to retrieve a textual representation of the error message.  Unfortunately, life is not always that easy.  Some implementations of Winsock provide this facility, while some do not.  In other words, you can’t rely on FormatMessage( ) returning anything useful when it comes to a Winsock error.

The easiest solution for this case is to write your own DLL which does the translation job for you.  If you don’t want to reinvent the wheel, you can use the NetErr.dll written by me.  You can download the source code with a test application as well as a pre-built and ready to use version of the DLL plus its corresponding NetErr.lib file.

The DLL is simple enough.  It exports some C-style functions, and stores the text for the error messages as a string table resource.  Each entry in the string table has an ID equal to the error code.  The DLL supports both Unicode and ANSI, and the NetErr.h header file defines some generic macros that are mapped to the correct version of each function in the usual way the Windows header files are organized.  To use the DLL, you simply include neterr_lib.h and link with NetErr.lib.  You should also make sure that at run time, the DLL can be found, and loaded by your application.  Because the usage of the string table resource, you can easily replace it with another string table resource containing the translated version of the texts if you plan for internationalization of your application.

Here I am going to describe each of the exported functions.  They are easy to call, only you should get familiar with the syntax:

  • BOOL __stdcall neterrIsDescriptionAvailable( int nErrorCode );

Checks to see if the DLL can translate a specific error code number.
nErrorCode is the error code number to be checked.  The function returns TRUE if the error can be translated, and FALSE otherwise.

  • int __stdcall neterrGetLastError( VOID );

Returns the last Winsock error code number.

  • VOID __stdcall neterrSetLastError( int nErrorCode );

Sets the last Winsock error code number.
nErrorCode is the error code number to be set.

  • BOOL __stdcall neterrGetDescriptionComplete( int nErrorCode, LPTSTR pszDescription, DWORD cchDescription );

Returns the complete error description text for a particular error code number.
nErrorCode specifies the error code number.  pszDescription is a pointer to the memory buffer to be filled with the error code description.  This buffer should contain at least 1024 characters.  cchDescription is the length of the buffer, in characters.  This function returns TRUE if it’s successful, and FALSE otherwise.

The error text translation returned by this function contains both a title, and descriptive error description.

  • BOOL __stdcall neterrGetDescriptionTitle( int nErrorCode, LPTSTR pszTitle, DWORD cchTitle );

Returns a short error description text for a particular error code number.
nErrorCode specifies the error code number.  pszTitle is a pointer to the memory buffer to be filled with the error code description.  This buffer should contain at least 1024 characters.  cchTitle is the length of the buffer, in characters.  This function returns TRUE if it’s successful, and FALSE otherwise.

The error text translation returned by this function is a short message indicating the error, and is useful for small user interfaces.

  • BOOL __stdcall neterrGetDescriptionShort( int nErrorCode, LPTSTR pszShort, DWORD cchShort );

Returns a descriptive error description text for a particular error code number.
nErrorCode specifies the error code number.  pszShort is a pointer to the memory buffer to be filled with the error code description.  This buffer should contain at least 1024 characters.  cchShort is the length of the buffer, in characters.  This function returns TRUE if it’s successful, and FALSE otherwise.

The error text translation returned by this function is a descriptive message indicating the error, and is useful for normal user interfaces.

A short point to be noted if you plan to change the string table resource strings.  The strings are in the following format: "TITLE – DESCRIPTION", where TITLE is the error title, retrieved by the neterrGetDescriptionTitle( ) function, and DESCRIPTION is a descriptive piece of text explaining the error in detail, which is retrieved by the neterrGetDescriptionShort( ) function.  The neterrGetDescriptionComplete( ) function retrieves the whole string, containing both the title and the description of the error message.

You can also compile and run the test application which retrieves the error description for the WSAEWOULDBLOCK Winsock error code.

 Download source code for this article

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++

Smart COM

This article can be considered the second part for my Client COM article.  It’s targeted to those who have just starting writing applications which use COM objects.  If you have never worked with COM before, please read the Client COM article before going on.


Writing COM client code can be cumbersome.  Why, you ask?  Because of having to check for the return value of each and every method, querying interfaces for other interfaces, matching up calls to IUnknown::AddRef( ) and IUnknown::QueryInterface( ) (which internally ends up calling AddRef( ) or some similar function) with calls to IUnknown::Release( ) is just not what you want to do manually.

There are numerous classes and libraries designed to solve this very problem.  In this article, we’ll explore some of the most widely used options proficient COM developers use every day to figure out what tasks can be automated for this kind of COM bookkeeping.

ATL Smart Pointers

ATL is a C++ library shipped with VC++.  It’s mostly targeted to those writing COM servers, providing numerous services for dealing with COM object implementations.  However, there are some smaller parts in this library which fit other purposes as well.  Two such smaller parts are ATL Conversion Macros (which I have described in my Unicode article) and ATL Smart Pointers.

Smart pointers are C++ classes which look like and act like pointers, but implement certain facilities which automate some tasks.  They are described in nearly every good C++ book, so check out your favorite C++ text to see just how many cool stuff can be done with smart pointers.  ATL Smart pointers are capable of automating the following tasks:

  • Reference counting COM interfaces
  • Managing calls to QueryInterface( )
  • Determining if two COM interface pointers belong to the same instance of COM object
  • A more elegant way of creating COM objects
  • Attach/Detach semantics
  • Copying interface pointers
  • Providing special services for IDispatch pointers (which are beyond the scope of this article, yet curious readers can consult the CComPtr< IDispatch > specialization)
  • Some connection point services (which are beyond the scope of this article, curious readers can consult CComPtr< >::Advise( )

We explore each of these services in detail here.

CComPtr and CComQIPtr are the heart of ATL Smart Pointer support.  They are both template classes, with a single parameter which should be the name of the COM interface they should point to.  They are both located in namespace ATL.  CComQIPtr is derived from CComPtr, and provides services for managing QueryInterface( ) calls.  So, any facility discussed for CComPtr applies just as well for CComQIPtr.

Reference counting services

CComPtr pointer takes care when the COM pointer should be Release( )-ed.   The destructor of this class checks to see if the internal pointer is non-NULL.  If it’s non-NULL, then the destructor calls Release( ) on the COM pointer.  Typically, you initialize an object of type CComPtr with an interface pointer obtained from somewhere and then forget about releasing it, since the destructor automatically does the right thing.

IMyInterface * GetMyInterface();

void foo()
{
CComPtr< IMyInterface > pInterface( GetMyInterface() );
// use the interface pointer
pInterface->MyMethod();
} // the destructor takes care of releasing the pointer

Managing calls to QueryInterface( )

This support is provided in two levels: inside CComPtr and inside CComQIPtr.  CComPtr has a template member function QueryInterface( ) which allows you to QueryInterface( ) a COM interface in a type safe manner.  This way, you don’t have to worry about passing the necessary IID to QueryInterface( ).

IMyInterface * GetMyInterface();

void foo()
{
CComPtr< IMyInterface > pInterface( GetMyInterface() );
CComPtr< IMyOtherInterface > pOther; // not containing any pointer yet
if (SUCCEEDED(pInterface.QueryInterface( &pOther )))
{
// use pOther
}
} // both pInterface and pOther will be correctly released by the destructors

Note the "&pOther" in the code.  As you see, CComPtr acts like a normal C++ pointer, in this manner that you can get its address using the normal & operator.  Nifty, isn’t it?

But things can be further simplified.  CComQIPtr’s constructor does the necessary QueryInterface( ) call, so if pOther is a CComQIPtr, you can simply initialize it with pInterface and get the QueryInterface( ) call automagically.  Note that you still need to check to make sure the QueryInterface( ) call has succeeded.

IMyInterface * GetMyInterface();

void foo()
{
CComPtr< IMyInterface > pInterface( GetMyInterface() );
CComQIPtr< IMyOtherInterface > pOther( pInterface ); // implicit QI
if (pOther)
{
// use pOther
}
} // both pInterface and pOther will be correctly released by the destructors

You clearly see how much this simplifies the code.  In general, there is little reason why you would want to use CComPtr::QueryInterface( ).  Always prefer CComQIPtr instead.

One thing is worth mentioning here.  CComQIPtr accepts a second template parameter which specifies the IID used in QI call.  Most of the times, the compiler detects it on its own using the __uuidof( ) extension (see the MSDN to find out how it works).  On rare cases where this does not work, you will get a compiler error, and you will have to pass a pointer to the IID which is usually named in the form of IID_InterfaceName yourself.  CComPtr::QueryInterface( ) does not provide this facility.

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++

Windows Target Version Macros

The Win32 SDK does not come in different versions for different platforms.  For example, if you choose to develop for Windows 98, you should work with the same SDK as you would when developing for Windows XP.  The solution Microsoft offers to enforce a minimum system requirement for a particular application works through a set of preprocessor macros used widely in the Windows header files.  These macros are WINVER, _WIN32_WINDOWS, _WIN32_WINNT, and _WIN32_IE.  You should define these macros to a hexadecimal number that varies for each platform.  Here’s a table that indicates which macros need to be defined for developing for a particular platform, and what number should they be defined to.

System Requirement WINVER _WIN32_WINDOWS _WIN32_WINNT _WIN32_IE
Windows 95 and NT 4.0 0×0400 n/a n/a n/a
Windows 98 and NT 4.0 0×0400 0×0410 n/a n/a
Windows NT 4.0 0×0400 n/a 0×0400 n/a
Windows 98 n/a 0×0410 n/a n/a
Windows Me n/a 0×0490 n/a n/a
Windows 2000 0×0500 n/a 0×0500 n/a
Windows XP and Windows .NET Server 0×0501 n/a 0×0501 n/a
Internet Explorer 3.0, 3.01, 3.02 n/a n/a n/a 0×0300
Internet Explorer 4.0 n/a n/a n/a 0×0400
Internet Explorer 4.01 n/a n/a n/a 0×0401
Internet Explorer 5.0, 5.0a, 5.0b n/a n/a n/a 0×0500
Internet Explorer 5.01, 5.5 n/a n/a n/a 0×0501
Internet Explorer 6.0 n/a n/a n/a 0×0560
or
0×0600

In order to use the above macros, you should define them before including any other header files.  For example, if you want to develop an application targeting Windows 98, Me, NT 4.0, 2000, XP, with a minimum of Internet Explorer 5.0 installed, you should include Windows headers like this:

#define WINVER         0x0400
#define _WIN32_WINDOWS 0x0410
#define _WIN32_IE 0x0500

#include <windows.h>
// include other necessary headers as well...

You should find the minimum system requirement, and define the macros dependently.  In the above example, the minimum system requirement is Windows 98 and NT 4.0 with Internet Explorer 5.0 installed.  In other words, any application developed with regard to those requirements is compatible with higher system versions.

Note that this is only a compile-time check.  You should perform run-time checks as well.  By being strict in defining the above macros as necessary, you ensure that you won’t use any features that are not present in the target platform.

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++