Click here to Skip to main content
15,891,905 members
Articles / Mobile Apps / Windows Mobile

Using the Connection Manager

Rate me:
Please Sign up or sign in to vote.
4.78/5 (8 votes)
30 Jul 2010CPOL5 min read 65.2K   5K   24  
How to effectively use the Connection Manager API to connect to an arbitrary network.
// MainFrm.cpp : implmentation of the CMainFrame class
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "resource.h"
#include "MainFrm.h"
#include <atlctrlx.h>
#include <vector>
#include <sstream>
#include <WinSock2.h>
#include "ConnectionManager.h"

#pragma comment( lib, "ws2.lib" )

/// functor to find the status of a particular item by name and description
struct IsStatus
{
    /// locate a status by name and description
    IsStatus( const std::wstring& name, const std::wstring& description )
        : name_( name ),
          description_( description )
    {
    };

    /// return true if the name and description match the one in the given status
    bool operator()( const CONNMGR_CONNECTION_DETAILED_STATUS& status )
    {
        bool name_match = ( NULL == status.szAdapterName ) ? 
            ( name_.length() == 0 ) : ( name_ == status.szAdapterName );
        if( name_match )
        {
            return ( NULL == status.szDescription ) ? 
                ( description_.length() == 0 ) : ( description_ == status.szDescription );
        }
        return false;
    };

private:
    std::wstring name_;
    std::wstring description_;
}; // struct IsStatus

/// populate the given buffer with the current status of all adapters registered
/// with connection manager.
/// returns NULL on failure.
const CONNMGR_CONNECTION_DETAILED_STATUS* GetAdaptersStatus( std::vector< BYTE >* buffer )
{
    std::vector< BYTE > int_buffer( sizeof( CONNMGR_CONNECTION_DETAILED_STATUS ) );
    DWORD buffer_size = int_buffer.size();

    CONNMGR_CONNECTION_DETAILED_STATUS* status = 
        reinterpret_cast< CONNMGR_CONNECTION_DETAILED_STATUS* >( &int_buffer.front() );

    HRESULT hr = ::ConnMgrQueryDetailedStatus( status, &buffer_size );
    if( HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) == hr )
    {
        int_buffer.resize( buffer_size );
        status = reinterpret_cast< CONNMGR_CONNECTION_DETAILED_STATUS* >( &int_buffer.front() );
        hr = ::ConnMgrQueryDetailedStatus( status, &buffer_size );
    }

    if( S_OK == hr )
    {
        buffer->swap( int_buffer );
        return status;
    }
    return NULL;
}

/// Get the status for the adapter matching the given name and description
/// returns NULL if no adapter is found.
const CONNMGR_CONNECTION_DETAILED_STATUS* GetAdapterStatus( 
    std::vector< BYTE >* buffer, 
    const std::wstring& name, 
    const std::wstring& description )
{
    // get the current status for all ConnMgr adapters
    const CONNMGR_CONNECTION_DETAILED_STATUS* status = 
        GetAdaptersStatus( buffer );
    if( NULL != status )
    {
        // locate the selected adapter in the list
        return std::find_if( ConnectionManager::StatusIterator( status ), 
            ConnectionManager::StatusIterator(),
            IsStatus( name, description ) );
    }
    return NULL;
}

/// wait a maximum of max_wait_time ms for the ConnMgr API to be ready
BOOL WaitForAPIReady( DWORD max_wait_time )
{
    HANDLE ready = ::ConnMgrApiReadyEvent();
    DWORD res = ::WaitForSingleObject( ready, max_wait_time );
    ::CloseHandle( ready );
    return ( WAIT_OBJECT_0 == res );
}

BOOL CMainFrame::PreTranslateMessage( MSG* pMsg )
{
    if( CFrameWindowImpl< CMainFrame >::PreTranslateMessage( pMsg ) )
        return TRUE;

    return view_.PreTranslateMessage( pMsg );
}

BOOL CMainFrame::OnIdle()
{
    return FALSE;
}

LRESULT CMainFrame::OnCreate( UINT /*uMsg*/, 
                              WPARAM /*wParam*/, 
                              LPARAM /*lParam*/, 
                              BOOL& bHandled )
{
    bHandled = FALSE;
    CreateSimpleCEMenuBar( IDR_MAINFRAME, TBSTYLE_AUTOSIZE | SHCMBF_HMENU );

    m_hWndClient = view_.Create( m_hWnd );

    // register object for message filtering and idle updates
    CMessageLoop* pLoop = _Module.GetMessageLoop();
    ATLASSERT( pLoop != NULL );
    pLoop->AddMessageFilter( this );
    pLoop->AddIdleHandler( this );

    CWaitCursor wait_cursor;
    if( !WaitForAPIReady( 5000 ) )
    {
        MessageBox( L"Connection Manager API is not ready.", 
                    L"CM Test", 
                    MB_ICONERROR );
    }
    else
    {
        PopulateAdapterList();
    }

    return 0;
}

LRESULT CMainFrame::OnAction( WORD /*wNotifyCode*/, 
                              WORD /*wID*/, 
                              HWND /*hWndCtl*/, 
                              BOOL& /*bHandled*/ )
{
    CWaitCursor wait_cursor;
    std::wstring selected_name, selected_description;
    if( view_.GetSelectedAdapter( &selected_name, &selected_description ) )
    {
        std::vector< BYTE > buffer;
        const CONNMGR_CONNECTION_DETAILED_STATUS* status =
            GetAdapterStatus( &buffer, selected_name, selected_description );
        if( NULL != status )
        {
            CONNMGR_CONNECTIONINFO info = { 0 };
            info.cbSize = sizeof( CONNMGR_CONNECTIONINFO );
            info.dwParams = CONNMGR_PARAM_GUIDDESTNET;
            info.dwPriority = CONNMGR_PRIORITY_USERINTERACTIVE;

            // allow connection manager to use any proxy it needs to make the connection
            info.dwFlags = CONNMGR_FLAG_PROXY_HTTP | 
                           CONNMGR_FLAG_PROXY_SOCKS4 | 
                           CONNMGR_FLAG_PROXY_SOCKS5 | 
                           CONNMGR_FLAG_PROXY_WAP;

            // Get the destination meta-network GUID for the adapter with the given name. If the
            // adapter doesn't have a name, the description usually works. If the adapter is a proxy,
            // be sure to set the correct reference type.
            if( S_OK == ::ConnMgrMapConRef( 
                ( CM_CONNTYPE_PROXY == status->dwType ) ? ConRefType_PROXY : ConRefType_NAP, 
                ( NULL != status->szAdapterName ) ? status->szAdapterName : status->szDescription, 
                &info.guidDestNet ) )
            {
                DWORD status = 0;
                HANDLE connection = NULL;

                // Establish the connection. hr will either be E_FAIL or S_OK. Extended error 
                // information is stored in the status variable.
                HRESULT hr = ::ConnMgrEstablishConnectionSync( &info, 
                                                               &connection, 
                                                               30000, 
                                                               &status );

                // show the extended error information
                ShowAdapterState( status );

                if( S_OK == hr )
                {
                    // use the connection wisely, then release it when you are finished
                    ::ConnMgrReleaseConnection( connection, 1 );
                }
            }
        }
    }
    return 0;
}

void CMainFrame::PopulateAdapterList()
{
    std::vector< BYTE > buffer;
    const CONNMGR_CONNECTION_DETAILED_STATUS* status = 
        GetAdaptersStatus( &buffer );
    for( const CONNMGR_CONNECTION_DETAILED_STATUS* item = status; 
         item != NULL; 
         item = item->pNext )
    {
        view_.AddAdapter( item->szAdapterName, item->szDescription );
    }
}

void CMainFrame::ShowAdapterState( DWORD status )
{
    // found the adapter, now print the status (locates the correct status
    // message with a binary search).
    ConnectionManager::StatusItem* it = 
        std::lower_bound( ConnectionManager::status_items, 
            ConnectionManager::status_items + ConnectionManager::status_item_max, 
            status );
    if( NULL != it )
        view_.SetAdapterState( it->status_name );
    else
        view_.SetAdapterState( L"Unknown State" );
}

void CMainFrame::ShowAdapterDestination( const GUID& destination )
{
    // if there's a destination GUID, show the string representation. If not, 
    // show an empty string.
    ConnectionManager::DestGuidItem* dgi = 
        std::find( ConnectionManager::dest_guid_items, 
            ConnectionManager::dest_guid_items + ConnectionManager::dest_guid_item_max, 
            destination );
    if( NULL != dgi )
    {
        view_.SetAdapterDestination( dgi->guid_name );
    }
    else
    {
        view_.SetAdapterDestination( L"" );
    }
}

void CMainFrame::ShowAdapterType( DWORD type, DWORD subtype )
{
    // locate the adapter type
    ConnectionManager::ConnectionTypeItem* cti = 
        std::lower_bound( ConnectionManager::connection_types,
            ConnectionManager::connection_types + ConnectionManager::connection_type_max,
            type );
    if( NULL != cti )
    {
        // locate the adapter subtype and show its string representation
        ConnectionManager::ConnectionSubtypeItem* csti = cti->subtype;
        for( csti; csti->subtype != subtype && csti->subtype_name != NULL; ++csti );
        if( NULL != csti->subtype_name )
            view_.SetAdapterType( csti->subtype_name );
        else
            view_.SetAdapterType( L"" );
    }
    else
    {
        view_.SetAdapterType( L"" );
    }
}

void CMainFrame::UpdateAdapterStatus( const std::wstring& name, 
                                      const std::wstring& description )
{
    // get an updated adapter status list
    std::vector< BYTE > buffer;
    const CONNMGR_CONNECTION_DETAILED_STATUS* status = 
        GetAdapterStatus( &buffer, name, description );
    if( NULL != status )
    {
        // show the connection status of the adapter
        ShowAdapterState( status->dwConnectionStatus );

        // show the ip address of the adapter
        if( NULL != status->pIPAddr && status->pIPAddr->cIPAddr > 0 )
        {
            std::wstringstream addrW;
            std::string addrA = inet_ntoa( 
                reinterpret_cast< const sockaddr_in* >( status->pIPAddr->IPAddr )->sin_addr );
            addrW << addrA.c_str();
            view_.SetAdapterAddress( addrW.str() );
        }
        else
            view_.SetAdapterAddress( L"" );

        // show the destination
        ShowAdapterDestination( status->guidDestNet );

        // show the adapter type
        ShowAdapterType( status->dwType, status->dwSubtype );

    }
    else
    {
        view_.SetAdapterState( L"Unable to get adapter state" );
    }
}

LRESULT CMainFrame::OnSelectedAdapter( int /*idCtrl*/, 
                                       LPNMHDR pnmh, 
                                       BOOL& /*bHandled*/ )
{
    NMADAPTERSELECTED* selected = reinterpret_cast< NMADAPTERSELECTED* >( pnmh );
    UpdateAdapterStatus( selected->name, selected->description );
    return 0;
}

LRESULT CMainFrame::OnAppExit( WORD /*wNotifyCode*/, 
                               WORD /*wID*/, 
                               HWND /*hWndCtl*/, 
                               BOOL& /*bHandled*/ )
{
    PostMessage( WM_CLOSE );
    return 0;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) An engineering firm in Cedar Rapids, Iowa
United States United States
I'm also on the MSDN forums
http://social.msdn.microsoft.com/profile/paulh79

Comments and Discussions