// 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;
}