COMP.CPP

///////////////////////////////////////////////////////////////////////////// 
// comp.cpp : IComponent Interface to communicate with MMC for the
// results pane. This implementation uses the
// default list view.
//
// This is a part of the MMC SDK.
// Copyright (C) 1997 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// MMC SDK Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// MMC Library product.
//

#include "stdafx.h"
#include "disk.h"
#include "globals.h"
#include "compdata.h" // Step2: Added for SetIComponetData
#include "comp.h"

/////////////////////////////////////////////////////////////////////////////
// CComponent - Several new interfaces are added in Step2:
//
// mostly a stub place holder and serves no real purpose. It will
// get filled in and used in later steps.

CComponent::CComponent()
{
m_ipConsole = NULL; // Step2: Adding support for a bunch
m_ipHeaderCtrl = NULL; // of new interfaces
m_ipResultData = NULL;
m_ipConsoleVerb = NULL;
m_ipImageResult = NULL;
m_pCompData = NULL;
m_cRefs = 0;

} // end Constructor()


CComponent::~CComponent()
{
}

/////////////////////////////////////////////////////////////////////////////
// IComponent implementation
//

//---------------------------------------------------------------------------
// IComponent::Initialize is called when a snap-in is being created and
// has items in the result pane to enumerate. The pointer to IConsole that
// is passed in is used to make QueryInterface calls to the console for
// interfaces such as IResultData.
// Step2: We add the basic interfaces from the console.
//
STDMETHODIMP
CComponent::Initialize
(
LPCONSOLE lpConsole // [in] Pointer to IConsole's IUnknown interface
)
{
HRESULT hr = S_OK;
_ASSERT( NULL != lpConsole );

// Save away all the interfaces we'll need.
// Fail if we can't QI the required interfaces.

m_ipConsole = lpConsole;
m_ipConsole->AddRef();
hr = m_ipConsole->QueryInterface( IID_IResultData,
(VOID**)&m_ipResultData
);
if( FAILED(hr) )
return hr;

hr = m_ipConsole->QueryInterface( IID_IHeaderCtrl,
(VOID**)&m_ipHeaderCtrl
);
if( FAILED(hr) )
return hr; // Console needs the header
else // control pointer
m_ipConsole->SetHeader( m_ipHeaderCtrl );

hr = m_ipConsole->QueryResultImageList( &m_ipImageResult);
if( FAILED(hr) )
return hr;

hr = m_ipConsole->QueryConsoleVerb( &m_ipConsoleVerb );
if( FAILED(hr) )
return hr;

// Load the bitmaps from the dll for the results pane
m_hbmp16x16 = LoadBitmap(g_hinst, MAKEINTRESOURCE(IDB_RESULT_16x16));
_ASSERT( m_hbmp16x16 );
m_hbmp32x32 = LoadBitmap(g_hinst, MAKEINTRESOURCE(IDB_RESULT_32x32));
_ASSERT( m_hbmp32x32 );

return hr;

} // end Initialize()


//---------------------------------------------------------------------------
// Step2: Add code to implment notifications. At this point we do not
// handle every notification, but we have handlers for the most
// important ones.
//
STDMETHODIMP
CComponent::Notify
(
LPDATAOBJECT pDataObject, // [in] Points to data object
MMC_NOTIFY_TYPE event, // [in] Identifies action taken by user
long arg, // [in] Depends on the notification type
long param // [in] Depends on the notification type
)
{
HRESULT hr = S_OK;

switch( event )
{
case MMCN_ADD_IMAGES:
ATLTRACE( L"CComponent::Notify: MMCN_ADD_IMAGES\n" );
hr = OnAddImages( pDataObject, arg, param );
break;

case MMCN_SHOW:
ATLTRACE( L"CComponent::Notify: MMCN_SHOW\n" );
hr = OnShow( pDataObject, arg, param );
break;

case MMCN_SELECT:
ATLTRACE( L"CComponent::Notify: MMCN_SELECT\n" );
hr = OnSelect( pDataObject, arg, param );
break;

case MMCN_REFRESH:
ATLTRACE( L"CComponent::Notify: MMCN_REFRESH\n" );
hr = OnRefresh( pDataObject, arg, param );
break;

case MMCN_VIEW_CHANGE:
ATLTRACE( L"CComponent::Notify: MMCN_VIEW_CHANGE unimplemented\n" );
break;

case MMCN_CLICK:
ATLTRACE( L"CComponent::Notify: MMCN_CLICK unimplemented\n" );
break;

case MMCN_DBLCLICK:
ATLTRACE( L"CComponent::Notify: MMCN_DBLCLICK unimplemented\n" );
break;

case MMCN_ACTIVATE:
ATLTRACE( L"CComponent::Notify: MMCN_ACTIVATE unimplemented\n" );
break;

case MMCN_MINIMIZED:
ATLTRACE( L"CComponent::Notify: MMCN_MINIMIZED unimplemented\n" );
break;

case MMCN_BTN_CLICK:
ATLTRACE( L"CComponent::Notify: MMCN_BTN_CLICK unimplemented\n" );
break;

default:
ATLTRACE( L"CComponent::Notify: unexpected event %x\n" , event );
hr = E_UNEXPECTED;
break;
}
return hr;

} // end Notify()


//---------------------------------------------------------------------------
// Releases all references to the console.
// Only the console should call this method.
// Step2: Added a bunch of new interfaces to release
//
STDMETHODIMP
CComponent::Destroy
(
long cookie // Reserved, not in use at this time
)
{
// Release the interfaces that we QI'ed
m_ipConsole->SetHeader(NULL);
if( NULL != m_ipHeaderCtrl )
{
m_ipHeaderCtrl->Release();
m_ipHeaderCtrl = NULL;
}

if( NULL != m_ipResultData )
{
m_ipResultData->Release();
m_ipResultData = NULL;
}

if( NULL != m_ipImageResult )
{
m_ipImageResult->Release();
m_ipImageResult = NULL;
}

if( NULL != m_ipConsoleVerb )
{
m_ipConsoleVerb->Release();
m_ipConsoleVerb= NULL;
}

if( NULL != m_ipConsole )
{
m_ipConsole->Release();
m_ipConsole = NULL;
}

if( NULL != m_pCompData )
{
m_pCompData->Release();
m_pCompData = NULL;
}

_ASSERT( DeleteObject(m_hbmp16x16) );
_ASSERT( DeleteObject(m_hbmp32x32) );

return S_OK;

} // end Destroy()


//---------------------------------------------------------------------------
// Returns a data object that can be used to retrieve context information
// for the specified cookie.
// Step2: Now we need to implement this method
//
STDMETHODIMP
CComponent::QueryDataObject
(
long cookie, // [in] Specifies the unique identifier
DATA_OBJECT_TYPES context, // [in] Type of data object
LPDATAOBJECT *ppDataObject // [out] Points to address of returned data
)
{
INT iResult;
HRESULT hr = S_OK;
CDataObject *pdoNew = NULL;

_ASSERT( CCT_SCOPE == context || // Must have a context
CCT_RESULT == context || // we understand
CCT_SNAPIN_MANAGER == context
);

do
{
pdoNew = new CDataObject;
*ppDataObject = pdoNew;

if( !pdoNew ) // Can't create object
{
hr = m_ipConsole->MessageBox( L"Out of memory",
L"CComponent::QueryDataObject",
MB_OK,
&iResult
);
break;
}

if( CCT_RESULT == context )
{
if( cookie )
{
// cookie is the lparam field that we passed in SCOPEDATAITEM
// used for the m_ipConsoleNameSpace->InsertItem(&sdi);
pdoNew->SetCookie( cookie, CCT_SCOPE, COOKIE_IS_STATUS );
}
else
{
// _ASSERT(FALSE); // Should never have NULL cookie
hr = E_UNEXPECTED; // with CCT_RESULT as the context
}
}
else
{
hr = E_UNEXPECTED; // Only handling CCT_RESULT
}
} while( 0 );

return S_FALSE;

} // end QueryDataObject()


//---------------------------------------------------------------------------
// This is where we provide strings for items we added to the the result
// pane. We only have one item, so this is easy. We get asked for a string
// for each column.
// Note that we still need to provide strings for items that are actually
// scope pane items. Notice that when the scope pane item was asked for a
// string for the scope pane we gave it. Here we actually have two columns
// of strings - "Name" and "Type".
// We also get asked for the icons for items in both panes.
//
STDMETHODIMP
CComponent::GetDisplayInfo
(
LPRESULTDATAITEM pResultItem // [in,out] Type of info required
)
{
static WCHAR* s_szSize = L"ABC";

_ASSERT( NULL != pResultItem );

if (pResultItem)
{
// Only responding for scope items for now.
if ( TRUE == pResultItem->bScopeItem )
{
if (pResultItem->mask & RDI_STR) // Looking for a string
{
if (0 == pResultItem->nCol )
pResultItem->str = (LPOLESTR)L"Geometry";
else if (1 == pResultItem->nCol )
pResultItem->str = (LPOLESTR)L"Child Folder";
else
pResultItem->str = (LPOLESTR)L"Error: Invalid Column";
}

if (pResultItem->mask & RDI_IMAGE)
{
pResultItem->nImage = 0;
}
}
else // Step2: Provide strings for Result Pane items
{ // See the comments in OnShow()
if( pResultItem->mask & RDI_STR )
{
if( pResultItem->nCol == 0 )
pResultItem->str = (LPOLESTR)L"Column 0";
else if( pResultItem->nCol == 1 )
pResultItem->str = (LPOLESTR)L"Column 1";
else
pResultItem->str = (LPOLESTR)L"Error: Unknown Column.";
}

if( pResultItem->mask & RDI_IMAGE ) // Looking for image
{
pResultItem->nImage = 2;
}
}
}

return S_OK;

} // end GetDisplayInfo()


//---------------------------------------------------------------------------
// Determines what the result pane view should be
//
STDMETHODIMP
CComponent::GetResultViewType
(
long cookie, // [in] Specifies the unique identifier
BSTR *ppViewType, // [out] Points to address of the returned view type
long *pViewOptions // [out] Pointer to the MMC_VIEW_OPTIONS enumeration
)
{
// Ask for default listview.
//
*pViewOptions = MMC_VIEW_OPTIONS_NONE;
return S_FALSE;

} // end GetResultViewType()


//---------------------------------------------------------------------------
// Not used in Step2
//
HRESULT
CComponent::CompareObjects
(
LPDATAOBJECT lpDataObjectA, // [in] First data object to compare
LPDATAOBJECT lpDataObjectB // [in] Second data object to compare
)
{
return S_FALSE;

} // end CompareObjects()


/////////////////////////////////////////////////////////////////////////////
// Support methods
//

//---------------------------------------------------------------------------
// Here is where we handle the MMCN_SHOW message. Insert the column
// headers, and then the rows of data into the result pane.
//
HRESULT
CComponent::OnShow
(
LPDATAOBJECT pDataObject, // [in] Points to data object
long arg, // [in]
long param // [in]
)
{
INT iResult;
CDataObject *pdo;
RESULTDATAITEM ResultItem;
HRESULT hr = S_OK;

_ASSERT( NULL != pDataObject );
_ASSERT( m_ipResultData ); // Must be first time

if( TRUE == arg )
{
pdo = ExtractOwnDataObject(pDataObject);

// If this is the root node, Let use the default mmc column headings
if( COOKIE_IS_ROOT == pdo->GetCookieType() )
{
return S_FALSE;
}

// Set the column headers in the results pane
//
hr = m_ipHeaderCtrl->InsertColumn( 0, L"One", 0, 100 );
_ASSERT( S_OK == hr );
hr = m_ipHeaderCtrl->InsertColumn( 1, L"Two", 0, 200 );
_ASSERT( S_OK == hr );

// Set the items in the results pane rows
//
if( !pdo )
{
hr = m_ipConsole->MessageBox( L"Unknown data object.\nNot set up to be an extension",
L"CComponent::OnShow",
MB_OK,
&iResult
);
return hr;
}

_ASSERT( CCT_SCOPE == pdo->GetContext() );
_ASSERT( COOKIE_IS_STATUS == pdo->GetCookieType() );


// Here we add the one item to the result pane.
// NOTE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The lParam is what we see in QueryDataObject as the cookie.
// In the upcomming steps we will actually create an object representing
// row data, so that the cookie knows what to display in the results pane,
// and when we get into GetDisplayInfo we cast the cookie to our object,
// and can get the data to display.
//
memset( &ResultItem, 0, sizeof(RESULTDATAITEM) );
ResultItem.mask = RDI_STR | // Displayname is valid
RDI_IMAGE | // nImage is valid
RDI_PARAM; // lParam is valid

ResultItem.str = MMC_CALLBACK; // Will get this from GetDisplayInfo
ResultItem.nImage = 2;
ResultItem.lParam = NULL;
m_ipResultData->InsertItem( &ResultItem );
}
return hr;

} // end OnShow()

//---------------------------------------------------------------------------
// Step2: New handler for the MMCN_ADD_IMAGES message
//
HRESULT
CComponent::OnAddImages
(
LPDATAOBJECT pDataObject, // [in] Points to the data object
long arg, // [in] Not used
long param // [in] Not used
)
{
HRESULT hr;
_ASSERT( NULL != m_ipImageResult );
hr = m_ipImageResult->ImageListSetStrip( (LONG *)m_hbmp16x16,
(LONG *)m_hbmp32x32,
0,
RGB(0,255,0)
);
_ASSERT( S_OK == hr );
return hr;

} // end OnAddImages()

//---------------------------------------------------------------------------
// Step2: This is a handler for the MMCN_SELECT notification. The user
// selected the node that populated the result pane. We have a
// chance to enable verbs. We will enable the REFRESH verb.
//
HRESULT
CComponent::OnSelect
(
LPDATAOBJECT pDataObject, // [in] Points to the data object
long arg, // [in] Contains flags about the selected item
long param // [in] Not used
)
{
BOOL fScopePane;
BOOL fSelected;
CDataObject *pdo;
HRESULT hr = S_OK;

fScopePane = LOWORD(arg);
fSelected = HIWORD(arg);

// Don't care about de-select notifications so just return
//
if( !fSelected )
{
return S_OK;
}

//
// Bail if we couldn't get the console verb interface, or if the
// selected item is the root;
//
pdo = ExtractOwnDataObject( pDataObject );
_ASSERT( NULL != pdo ); // Check object before using it

if( NULL == m_ipConsoleVerb || COOKIE_IS_ROOT == pdo->GetCookieType() )
{
return S_OK;
}

//
// Use selections and set which verbs are allowed
//

if( fScopePane ) // Selection in the scope pane
{
if( COOKIE_IS_STATUS == pdo->GetCookieType() )
{
hr = m_ipConsoleVerb->SetVerbState( MMC_VERB_REFRESH, ENABLED, TRUE );
_ASSERT( S_OK == hr );
}
}
else // Selection in the result pane
{
//
}
return S_OK;

} // end OnSelect()


//---------------------------------------------------------------------------
// Step2: Respond to the MMCN_REFRESH notification and refresh the rows.
//
HRESULT
CComponent::OnRefresh
(
LPDATAOBJECT pDataObject, // [in] Points to the data object
long arg, // [in]
long param // [in]
)
{
CDataObject *pdo;
RESULTDATAITEM ResultItem;
HRESULT hr = S_OK;

//
// Clear out and re-populate
//
hr = m_ipResultData->DeleteAllRsltItems();
_ASSERT( S_OK == hr );

_ASSERT( NULL != m_ipResultData );

pdo = ExtractOwnDataObject( pDataObject );
_ASSERT( NULL != pdo );

// If this is the root node, Let use the default mmc column headings
if( COOKIE_IS_ROOT == pdo->GetCookieType() )
{
return S_FALSE;
}

//
// Set the items in the results pane rows
//

_ASSERT( CCT_SCOPE == pdo->GetContext() );
_ASSERT( COOKIE_IS_STATUS == pdo->GetCookieType() );

memset( &ResultItem, 0, sizeof(RESULTDATAITEM) );
ResultItem.mask = RDI_STR | // displayname is valid
RDI_IMAGE | // nImage is valid
RDI_PARAM; // lParam is valid

ResultItem.str = MMC_CALLBACK;
ResultItem.nImage = 2;
ResultItem.lParam = NULL;
m_ipResultData->InsertItem( &ResultItem );

return S_OK;

} // end OnRefresh()


//---------------------------------------------------------------------------
// Store the parent IComponetData object.
//
VOID
CComponent::SetIComponentData
(
CComponentData* pData
)
{
_ASSERT( pData );
_ASSERT( NULL == m_pCompData ); // Can't do this twice
LPUNKNOWN pUnk = pData->GetUnknown(); // Get the object IUnknown

HRESULT hr;
hr = pUnk->QueryInterface( IID_IComponentData,
reinterpret_cast<void**>(&m_pCompData)
);
_ASSERT( S_OK == hr );

} // end SetIComponentData()