Hyperlinks     Hyperlinks Reference     Hyperlinks    
Web Workshop (Miscellaneous)

Hyperlinks Overview


One of the most compelling ease-of-use features of World Wide Web applications is the navigation-based user interface model that includes point-and-click hyperlink navigation, a History list (with commands such as Back and Forward), and a Favorites list. Like other Microsoft® ActiveX®-based technologies, ActiveX Hyperlinks enable you to add this hyperlink functionality to your documents and applications, allowing you to integrate them seamlessly with other hyperlinking applications, including Web browsers. ActiveX Hyperlinks allow you to:

This section provides an overview of hyperlinks, a description of the ActiveX Hyperlinking architecture (including the interfaces required to add hyperlink support to an application), and examples. Applications can choose to support various degrees of integration with the ActiveX Hyperlinking architecture. Where applicable, this document describes how to provide minimal or simple hyperlinking support, and also how to extend this support for more complete hyperlinking integration.

What Is a Hyperlink?

A hyperlink is a COM object provided by the system that implements the IHlink interface and acts as a link to an object at another location (the target). This target can be a reference to a location in the same document/object that contains the hyperlink, a different (top-level or embedded) document/object of the same class, or a different document/object of a different class. A hyperlink is made up of four main parts:

The data of the document/object can be stored in file system files, computers on the Internet (referred to by Uniform Resource Locators, or URLs), or any arbitrary location that can be referenced through monikers. Navigation to the location can be done by binding to the target and then asking it to jump to the location. How a hyperlink is presented to the user is up to the hyperlink container and the context of the hyperlink. While there are no user interface requirements limiting the presentation of hyperlinks, guidelines suggest that the hyperlinks should be made clear through coloring and/or underlining the hyperlink text, or by changing the cursor when selecting the hyperlink with the mouse.

What Is Hyperlink Navigation?

Hyperlink navigation involves a transition from one document, object, or application (the hyperlink container) to another document, object, or application (the hyperlink target). Usually both the hyperlink container and target remain running, but the hyperlink target is displayed over the hyperlink container. Hyperlink containers and targets can be top-level documents or Active Document objects in a browser application. Because of this variation, there are many possible forms of navigation. These include navigating from:

In the third and fifth cases above, the window is reused. In the other cases, the hyperlink target appears in a new window. The ActiveX Hyperlinks architecture suggests a mechanism for creating the illusion of window reuse in such cases: the hyperlink container passes its current window position to the hyperlink target, and the hyperlink target positions its window in the exact same location. Upon successful navigation, the hyperlink container hides its window.

What Is a Browse Context?

By looking at the possible forms of navigation, it is clear that multiple objects/documents (perhaps from different processes) share some global context. This context knows the order in which documents have been visited. All jumps are recorded with this context, and this context chains them together in a stack that can be navigated using Back and Forward buttons. This global context is called the hyperlink browse context.

Though a browse context is global and spans multiple processes, it need not be global per user, such as History and Favorites lists. There can be multiple browse contexts active at once. For example, in certain Web browsers you can start a new browse context by right-clicking and then selecting Open In New Window. ActiveX Hyperlinking defines the interface for the standard system browse context. This allows hyperlink-aware documents and applications to integrate the browse context's navigation stack through the standard hyperlinking interfaces and their methods.

The Simple Hyperlinking API

There are two methods of dealing with hyperlinks, depending on the needed complexity of the hyperlink operation. The simple hyperlink navigation model is a helper API aimed at common navigation scenarios such as a control (like a command button) embedded on a Web page that allows the user to jump to another page when it is clicked. The simple hyperlink functions are implemented by the Urlmon.dll dynamic-link library, and require that the Urlmon.h header file and the Urlmon.lib library file be in the include and library directories, respectively, of the C/C++ compiler you use.

The simple hyperlink functions are an encapsulation of the more complex full hyperlinking interfaces. These full hyperlinking interfaces offer a much richer set of navigation operations. For example, you can use these interfaces for operations such as supporting navigation to a location within a new document type, or allowing the cutting and pasting or dragging and dropping of hyperlinks. The simple hyperlink navigation API allows hyperlink navigation without knowledge of any other hyperlink interfaces or objects. This API includes the following functions:

These functions work within any ActiveX hyperlink frame application. A hyperlink frame is the outer container of the document processing the user's request to navigate (when a navigation action occurs). An application must expose the IHlinkFrame interface to be a hyperlink frame application. For example, Microsoft® Internet Explorer 3.0 is a hyperlink frame application that knows the user's current location in the navigation stack and goes to the correct location when the user clicks the Back or Forward button.

The programmer is shielded from the architectural details of figuring out the History list to navigate forward and backward. An ActiveX control or document hosted in a frame simply calls these functions to figure out where to go.

The calling object needs to know where in the navigation stack the user currently is so the user can go forward or backward properly. To do this, all that the calling object must pass in is the interface pointer to itself. In reality, this is the IUnknown pointer to the document or object that is initiating the hyperlink. (Note that this must be the pUnkOuter parameter for an aggregated COM object.) Using this object pointer, the API travels through the interface hierarchy of that object to locate its outer container to calculate navigation history and do the in-frame navigation. If, however, the pointer is NULL, the hyperlink is assumed to originate from an ActiveX-unaware application (an application that does not expose the IHlinkFrame interface), and the navigation history list will not be updated. In these instances, Internet Explorer will usually be launched to attempt the navigation.

The Hyperlink Architecture

The following sections describe the various components in the ActiveX Hyperlinks architecture and the interfaces they implement. Some of the components are standard, system-provided objects; the others are user-defined components that participate in ActiveX hyperlinking because they implement the appropriate interface(s).

The hyperlink target

A hyperlink target is a COM object that implements the IHlinkTarget interface and supplies its moniker, friendly name, and other information that other hyperlink objects will use to navigate to it. This can be a persisted ActiveX object that exposes IHlinkTarget, a persisted ActiveX object that exposes IOleObject, or any file that is viewed when its viewer application is launched through ShellExecute. An object (document) that wants to be targeted by hyperlinks can choose to implement all or part of the IHlinkTarget interface to integrate tightly with ActiveX Hyperlinks. If the object does not support IHlinkTarget, it can still act as a hyperlink target, but it won't be able to support internal navigation, and it will not have access to the common browse context that holds the navigation stack. A hyperlink target can be a top-level container document, an embedded object of arbitrary nesting, or, in general, any object that can be referenced through a moniker.

How to implement IHlinkTarget

An existing application that supports COM linking need only implement the IHlinkTarget interface on the same object that implements IPersistFile and IOleItemContainer. The application can also implement IPersistMoniker to support incremental rendering or asynchronous download as a persistence mechanism, rather than IPersistFile. Supporting IHlinkTarget from an Active Document object is the recommended way to make sure your document is viewable by browsers and participates in hyperlinking smoothly.

The hyperlink object

A hyperlink object implements the IHlink interface and encapsulates four pieces of reference information: a moniker to the hyperlink target; a string for the location within the target; a friendly name for the target; and additional parameters.

The hyperlink object completely encapsulates the behavior of navigating to a referenced location. It also supports the ability to save and load itself through the IPersistStream interface, and the ability to be transferred through the clipboard or through drag-and-drop operations by means of IDataObject. A standard hyperlink object implementation is provided with the system, and it is not advisable to implement another version. A document can use the standard hyperlink object to represent hyperlinks within itself, thus encapsulating the work of navigating, saving, loading, dragging, dropping, cutting, and pasting hyperlinks. Standard hyperlink objects are created through the HlinkCreateFromData, HlinkCreateFromMoniker, HlinkCreateFromString, and OleLoadFromStream functions. The standard hyperlink object implements the IHlink, IPersistStream, and IDataObject interfaces.

The hyperlink container

A hyperlink container is a document or application that contains hyperlinks. The container supports hyperlinks by implementing the IHlinkSite interface and, if the container's objects can be targets of other hyperlinks, the IHlinkTarget interface.

Note Generally, an object that acts as a hyperlink container can also act as a hyperlink target. An HTML page, for example, can contain a number of hyperlinks to other pages, while at the same time it can be the target of hyperlinks from other HTML pages.

The hyperlink site

A hyperlink site is a COM object that implements the IHlinkSite interface and supplies either the moniker or interface identifier of its hyperlink container. One hyperlink site can serve multiple hyperlinks. The moniker supplied by the hyperlink site is used to evaluate relative monikers to the hyperlink target. If the relative moniker is NULL, the target of the link is in the same container object, and IHlink::Navigate can result in an efficient internal jump

Note The standard hyperlink object performs internal jumps by retrieving the container's IHlinkTarget moniker using IHlinkSite::GetMoniker (which avoids an unnecessary moniker bind). The object then asks the container to navigate directly through the IHlinkTarget::Navigate method.

The hyperlink frame

A hyperlink frame is a COM object that implements the IHlinkFrame interface and controls the top-level navigation and display of hyperlinks for the frame's container and the hyperlink target's server. Browser applications such as Internet Explorer are examples of hyperlink frames. Ideally, a hyperlink frame also serves as an Active Document object frame, allowing it to support browsing and hyperlinking between various document objects.

The hyperlink browse context

The hyperlink browse context maintains the navigation stack that is passed during navigation from one document or application to another. As with the hyperlink object, the browse context is a standard object provided with the system.

In addition to maintaining the navigation stack, the browse context knows whether or not to enable Back and Forward commands. For example, if you navigate from A to B, A would create an instance of the browse context object (if it had not been given one before) and pass it to B. Next, if you navigate to C, B would pass the same browse context pointer to C. At this moment, the navigation stack of the browse context contains A, B, and C. Back is enabled but Forward is disabled. Now if you do click Back, you will navigate to B and the navigation stack still contains the same three items. Now both Back and Forward are enabled. If you click Back again, you will navigate to A, and again the navigation stack contains the same three elements. But now Back is disabled and only Forward is enabled.

In addition to maintaining the navigation stack, the browse context object manages the hyperlink frame window and hyperlink target object's window. This window position information allows hyperlinking from one top-level window to another while giving the illusion of window reuse (by positioning the windows on top of each other). Each hyperlink target is passed a browse context (through IHlinkTarget::SetBrowseContext) the first time it is navigated to. The hyperlink target registers with the browse context (through IHlinkBrowseContext::Register) and holds a reference to it. The target must also notify the browse context each time it is navigated to through IHlinkBrowseContext::OnNavigateHlink. The browse context uses this information to maintain the navigation stack, to remember the current item in the stack, and to manage the lifetimes of registered hyperlink target applications.

An Example of Simple Hyperlinking

The navigation in this example takes place between simple hyperlink containers and simple hyperlink targets, none of which understand how to use the hyperlinking browse context. For ActiveX Controls or Active Document objects hosted within a browser such as Internet Explorer, this is the only hyperlinking support that is necessary to integrate fully in the navigation stack and history list. The following example code outlines the order of execution of methods among the various objects during navigation.

Note Simple hyperlinking is simple mainly for the hyperlink container and the hyperlink target, particularly if both are document objects hosted in a document object frame. In these cases, the frame takes over all responsibility for providing a navigation stack and integrated history/favorites. There is no definition of simple hyperlinking for hyperlink frames.

Starting with a hyperlink container

The hyperlink container (for example, a document or an ActiveX control embedded within a document) initiates the hyperlink navigation using one of the simple hyperlinking functions.

// do the navigation
HlinkSimpleNavigateToString(L"http://www.microsoft.com/example.asp",
    NULL,  NULL, punkMe, pbc, pbsc, 0, 0);

The hyperlink frame (for example, Internet Explorer) is called from within the simple navigation API (which packages up the call into a full call to HlinkNavigate). This is the frame's chance to provide an integrated user interface, progress feedback, cancellation options, and so forth. Often the hyperlink frame simply sets some flags and defers to the IHlink::Navigate method. Other frames might choose to do more work. For instance, a frame might decide to provide its own IBindStatusCallback in order to listen in on progress notifications during navigation.

Calling the hyperlink target

Usually, the system-provided hyperlink object gains control to do the navigation on behalf of the container or frame, resulting in a call to the hyperlink target. The hyperlink target then receives control to navigate to the specific location within the target. Notice that support for "sublocations" is optional. Also, the interpretation of location strings is left to the interpretation of the target object.

STDMETHODIMP
IHlinkTarget::Navigate(DWORD grfHLNF, LPCWSTR szLocation)
{
    IHlinkFrame* phlFrame = NULL;
    IServiceProvider* pSP = NULL;
    HRESULT hr;

    // If szLocation is not visible show it (scroll to it).

    // If this hyperlink target is an Active Document object,
    // try to retrieve the hyperlink frame pointer using 
    // IServiceProvider.
    if (m_poleclientsite)
        m_poleclientsite->QueryInterface(IID_IServiceProvider,
            (void**)&pSP);
    if (pSP)
        pSP->QueryService(SID_SHlinkFrame, IID_IHlinkFrame,
            (void**)&phlFrame);
    
    // Notify the hlink frame and the browse context that the
    // navigation is complete. Note: either phlFrame or m_phlbc
    // may be NULL.

    hr = HlinkOnNavigate(phlFrame, m_phlbc, grfHLNF, m_pmk,
        wzLocation, wzFriendlyName);

    if(FAILED(hr))
        return hr;

    // Set document flag and global application flag to hide
    // document and application main window.
    m_fHide = FALSE;
    g_fHideAppFrame = FALSE; 

    return S_OK;
}  // IHlinkTarget::Navigate

Receiving success notification

The hyperlink frame next receives notification of a successful navigation from IHlinkTarget::Navigate in order to reposition its windows and update its windows' visibility. If this is the same frame that hosted the hyperlink container that initiated the navigation, the flags set will ensure that the frame remains visible.

An Example of Complex Hyperlinking

The navigation in this example takes place between hyperlink containers and hyperlink targets that understand how to use the hyperlinking browse context. The following example code outlines the order of execution of methods among the various objects during navigation.

Starting with a hyperlink container

Before any navigation occurs, the container starts with a hyperlink object that has either been created (using HlinkCreateFromData, HlinkCreateFromMoniker, or HlinkCreateFromString) or loaded from persistent data (using OleLoadFromStream). The hyperlink container might initialize the hyperlink through the IHlink::SetHlinkSite method by passing in an IHlinkSite interface and hyperlink-specific data (dwSiteData), which allows the hyperlink container to use the same hyperlink site to service multiple hyperlinks.

When the container decides to navigate the link as a result of user action, it does the following:

// Retrieve the hyperlink frame pointer.
// If this hyperlink target is an Active Document object, try to
// retrieve the hyperlink frame pointer using IServiceProvider.
if (m_poleclientsite)
    m_poleclientsite->QueryInterface(IID_IServiceProvider,
        (void**)&pSP);
if (pSP)
    pSP->QueryService(SID_SHlinkFrame, IID_IHlinkFrame,
        (void**)&phlFrame);

// If we don't have a current hyperlink browse context, create
// one or ask the hyperlink frame for one and then add this 
// hyperlink target at the top of the navigation stack.
if (m_phlbc == NULL)
{
    // get the browse context pointer
    if (phlFrame)
        phlFrame->GetBrowseContext(&m_phlbc);

    if (m_phlbc == NULL)
        HlinkCreateBrowseContext(NULL, IID_IHlinkBrowseContext,
            &m_phlbc);

    // Must have a hyperlink browse context to activate a
    // hyperlink object.
    if (m_phlbc == NULL)
        return E_FAIL;

    // Register the hyperlink site for this container and a
    // moniker to the container document/object with the
    // browse context.
    m_phlbc->Register(0, m_phls, pmkThis, &m_dwRegister);

    // Because we want the user to be able to come back to this
    // object via GoBack functionality, add self to the 
    // navigation stack. This effectively tells the browse context
    // that the current hyperlink container referred to by
    // m_pmk. This is a member (at the top) of the navigation stack.
    m_phlbc->OnNavigateHlink(0, pmkThis, wzLocation,
        wzFriendlyName);
    }

    if (phlFrame == NULL)
    {
        HLBWINFO hlbwinfo;

        // Initialize hlbwinfo with window locations and flags.

        // Register the browse window info in the browse context 
        // so it is later available to the hyperlink target and
        // set the flag indicating that this window should be
        // hidden after navigation. But this flag is cleared
        // in the IHlinkTarget::Navigate and
        // IHlinkFrame::OnNavigate methods.
        m_phlbc->SetBrowseWindowInfo(&hlbwinfo)
          
        m_fHide = TRUE;
        g_fHideAppFrame = TRUE;  // only the MDI applications
                                 // need this separate flag
    }
    else
    {
        m_fHide = FALSE;
        g_fHideAppFrame = FALSE; 
    }

// phlink is the hyperlink object we want to navigate to.
// This could have been created with one of the HlinkCreate
// functions, loaded from a stream, or pulled from the
// navigation stack using IHlinkBrowseContext::GetHlink
hr = HlinkNavigate(phlink, phlFrame, NULL, pbc, pbsc, m_phlbc);
    
if (hr == NOERROR)
{
    if (m_fHide)
        // Hide this document
    if (g_fHideAppFrame)
        // Hide/Minimize application's frame window
}

Calling the hyperlink frame

The hyperlink frame is called from within HlinkNavigate. This is the frame's chance to provide an integrated user interface, progress feedback, cancellation ability, and so forth. Often the hyperlink frame simply sets some flags and defers to the IHlink::Navigate method. Here is a theoretical implementation of a hyperlink frame's IHlinkFrame::Navigate function:

STDMETHODIMP
IHlinkFrame::Navigate(DWORD grfHLNF, IBindCtx* pbc,  
    IBindStatusCallback* pbsc,  IHlink* phlDest)
{
    // This flag gets cleared in IHlinkFrame::OnNavigate().
    // Thus if the Navigation is within the same frame window, 
    // then we will get the right behavior as this flag gets
    // cleared in the OnNavigate() method.
    m_gfHideAppFrame = TRUE;  

    // Some frames need only the following function so that 
    // they can properly show and hide themselves.
    // Others may hook themselves into the IBindStatusCallback
    // for progress notification
    hr = phlDest->Navigate(NULL, pbc, pbsc, m_phlbc);
    if (SUCCEEDED(hr) && m_gfHideAppFrame)
        // Hide the frame window
}  // IHlinkFrame::Navigate

Other frames might choose to do more work. For instance, a frame may decide to provide its own IBindStatusCallback in order to listen in on progress notifications during navigation.

Jumping to the hyperlink target

When called by the hyperlink frame, the system hyperlink object gains control to do most of the navigation work and to integrate the results with the browse context. The following code is a theoretical implementation of a hyperlink object. The system-provided hyperlink object uses similar code.

STDMETHODIMP
IHlink::Navigate(DWORD grfHLNF, IBindCtx* pbc,  IBindStatusCallback* 
    pbsc, IHlinkBrowseContext* phlbc)
{
    IHlinkTarget* phlTarget = NULL;
    IMoniker* pmkLeft = NULL;

    if (grfHLNF & HLNF_USEBROWSECONTEXTCLONE) {
        grfHLNF &= ~HLNF_USEBROWSECONTEXTCLONE;
        phlbc->Clone(NULL, IID_IHlinkBrowseContext, &phlbc);
        }
    else {
        hr = m_phlSite->GetMoniker(m_dwSiteData, 
        OLEGETMONIKER_ONLYIFTHERE, OLEWHICHMK_CONTAINER, &pmkLeft);
        if (FAILED(hr) || m_pmkTarget->IsEqual(pmkLeft)) {
            hr = m_phlSite->GetInterface(dwSiteData, 0, IID_IHlinkTarget,
                (void**)&phlTarget);
            if (FAILED(hr))
                phlbc->GetObject(m_pmkTarget, &phlTarget);
            }
        
    if (phlTarget == NULL) {
        // Set the pbsc in the pbc to get asynch and notification
        // binding behavior requested by caller.
        m_pmkTarget->BindToObject(pmkLeft, IID_IHlinkTarget, &phlTarget);
        phlTarget->SetBrowseContext(phlbc);
        }
        
    phlTarget->Navigate(grfHLNF, m_wzLocation);
}  // IHlink::Navigate

Setting the browse context

During the execution of the previous code, the hyperlink target receives the browse context for the navigation. This provides information about the hyperlink navigation stack and window positions for the hyperlinking.

Note This function is not called in all hyperlinking circumstances. A simple hyperlink target, as in the Simple Hyperlinking example above, need not implement this function.

STDMETHODIMP
CHlinkTarget::SetBrowseContext(IHlinkBrowseContext* phlbc)
{
    if (m_phlbc != NULL) {
        m_phlbc->Revoke(m_dwRegister);
        m_phlbc->Release();
        }
    m_phlbc = phlbc;
    if (m_phlbc != NULL) {
        m_phlbc->AddRef();
        m_phlbc->Register(0, (IUnknown*)this, m_pmk, &m_dwRegister);
        }

    return S_OK;
}  // CHlinkTarget::SetBrowseContext

The hyperlink target then receives control to navigate to the specific location within the target.

STDMETHODIMP
IHlinkTarget::Navigate(DWORD grfHLNF, LPCWSTR wzLocation)
{
    IHlinkFrame* phlFrame = NULL;
    IServiceProvider* pSP;

    // If the object is not visible, activate it and show it.
    // Jump to the location indicated by wzLocation.

    // If this hyperlink target is an Active Document object,
    // try to retrieve the hyperlink frame pointer using
    // IServiceProvider.

    if (m_poleclientsite)
        m_poleclientsite->QueryInterface(IID_IServiceProvider,
            (void**)&pSP);
    if(pSP)
        pSP->QueryService(SID_SHlinkFrame, IID_IHlinkFrame,
            (void**)&phlFrame);

    // Notify the hlink frame and the browse context that 
    // the navigation is complete.
    // Note: phlFrame may be NULL.
    HlinkOnNavigate(phlFrame, m_phlbc, grfHLNF, pmkThis,
        wzLocation, wzFriendlyName);

    if (phlFrame == NULL && !(grfHLNF & HLNF_INTERNALJUMP))
    {
        HLBWINFO hlbwi;
        phlbc->GetBrowseWindowInfo(&hlbwi);

        // Adjust the document and frame windows according 
        // to the dimensions in HLBWI.
    }

    // Adjust flags so that if we navigated to the same
// document or a document in the same application frame,
// they won't get hidden.
    m_fHide = FALSE;    
    m_gfHideAppFrame = FALSE; 
}  // IHlinkTarget::Navigate

Receiving notifications

The hyperlink frame next receives notification of a successful navigation from within IHlinkTarget::Navigate in order to reposition its windows and update their visibility. If this is the same frame that hosted the hyperlink container that initiated the navigation, the m_gfHideAppFrame flag set in the following example will ensure that the frame remains visible.

STDMETHODIMP
IHlinkFrame::OnNavigate(DWORD grfHLNF)
{
    if (!(grfHLNF & HLNF_INTERNALJUMP)) {
        HLBWINFO hlbwi;
        m_phlbc->GetBrowseWindowInfo(&hlbwi);
        // Adjust document/frame windows according to the
        // dimensions in hlbwi.
    }    
    m_gfHideAppFrame = FALSE;    
}  // IHlinkFrame::OnNavigate

Finally, the browse context receives notification of a successful navigation from IHlinkTarget::Navigate in order to update the navigation stack.

STDMETHODIMP
IHlinkBrowseContext::OnNavigateHlink(DWORD grfHLNF, IMoniker* 
    pmkTarget, LPCWSTR szLocation, LPCWSTR szFriendlyName)
{
    // If CreateNoHistory or NavigatingToStackItem, return immediately
    // unless NavigatingBack or NavigatingForward is also set.
    if (grfHLNF & (HLNF_CREATENOHISTORY | HLNF_NAVIGATINGTOSTACKITEM)) {
        if (!(grfHLNF & (HLNF_NAVIGATINGBACK | HLNF_NAVIGATINGFORWARD)))
            return NOERROR;
        }
    if (grfHLNF & HLNF_NAVIGATINGBACK)
        --m_iCurrent;
    else if (grfHLNF & HLNF_NAVIGATINGFORWARD)
        ++m_iCurrent;
    else {
        // Add this hyperlink to the navigation stack at m_iCurrent+1;
        // remove all items greater than m_iCurrent+1.

        ++m_iCurrent;
        }
}  // IHlinkBrowseContext::OnNavigateHlink


Back to topBack to top

Did you find this topic useful? Suggestions for other topics? Write us!

© 1999 Microsoft Corporation. All rights reserved. Terms of use.