You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1507 lines
40 KiB
1507 lines
40 KiB
/*++
|
|
|
|
© 1998 Seagate Software, Inc. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
CSakSnap.cpp
|
|
|
|
Abstract:
|
|
|
|
This component implements the IComponent interface for
|
|
the snapin. Primarily it is responsible for handling the
|
|
result view panes.
|
|
|
|
Author:
|
|
|
|
Rohde Wakefield [rohde] 04-Mar-1997
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "stdafx.h"
|
|
#include "CSakSnap.h"
|
|
#include "CSakData.h"
|
|
#include "MsDatObj.h"
|
|
|
|
|
|
UINT CSakSnap::m_nImageArray[RS_RESULT_IMAGE_ARRAY_MAX];
|
|
INT CSakSnap::m_nImageCount = 0;
|
|
|
|
STDMETHODIMP
|
|
CSakSnap::GetResultViewType(
|
|
IN MMC_COOKIE Cookie,
|
|
OUT BSTR* ppViewType,
|
|
OUT long* pViewOptions
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine what the type of the result view will be:
|
|
|
|
Arguments:
|
|
|
|
pUnk - Base IUnknown of console
|
|
|
|
Return Value:
|
|
|
|
S_OK : either an OCX CLSID string or a URL path.
|
|
S_FALSE : default list view will be used.
|
|
|
|
--*/
|
|
{
|
|
WsbTraceIn( L"CSakSnap::GetResultViewType", L"Cookie = <0x%p>, ppViewType = <0x%p>, pViewOptions = <0x%p>", Cookie, ppViewType, pViewOptions );
|
|
|
|
HRESULT hr = S_FALSE;
|
|
|
|
try {
|
|
|
|
CComPtr<ISakNode> pSakNode;
|
|
WsbAffirmHr( m_pSakData->GetBaseHsmFromCookie( Cookie, &pSakNode ) );
|
|
|
|
|
|
//
|
|
// Use default view
|
|
//
|
|
|
|
*ppViewType = 0;
|
|
*pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT;
|
|
hr = S_FALSE;
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut( L"CSakSnap::GetResultViewType", L"hr = <%ls>, *ppViewType = <%ls>, *pViewOptions = <%ls>", WsbHrAsString( hr ), WsbPtrToStringAsString( ppViewType ), WsbPtrToPtrAsString( (void**)pViewOptions ) );
|
|
return( hr );
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CSakSnap::Initialize(
|
|
IN IConsole * lpConsole
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called when the user first clicks on node to show result pane.
|
|
|
|
Arguments:
|
|
|
|
pUnk - Base IUnknown of console
|
|
|
|
Return Value:
|
|
|
|
S_OK - Correctly initialized.
|
|
|
|
E_xxxxxxxxxxx - Unable to initialize.
|
|
|
|
--*/
|
|
{
|
|
WsbTraceIn( L"CSakSnap::Initialize", L"lpConsole = <0x%p>", lpConsole );
|
|
|
|
HRESULT hr = S_OK;
|
|
try {
|
|
|
|
//
|
|
// validity check on parameters
|
|
//
|
|
|
|
WsbAffirmPointer( lpConsole );
|
|
|
|
//
|
|
// Save the IConsole pointer
|
|
//
|
|
|
|
m_pConsole = lpConsole;
|
|
|
|
//
|
|
// Save the result image list
|
|
// MS seems to QI for this instead of call
|
|
// 'QueryResultImageList'
|
|
//
|
|
|
|
WsbAffirmHr( m_pConsole->QueryInterface( IID_IImageList, (void**)&m_pImageResult ) );
|
|
// WsbAffirmHr( m_pConsole->QueryResultImageList( &m_pImageResult ) );
|
|
|
|
//
|
|
// Save the result data pointer
|
|
//
|
|
WsbAffirmHr( m_pConsole->QueryInterface( IID_IResultData, (void**)&m_pResultData ) );
|
|
// Save the ConsolveVerb pointer
|
|
// WsbAffirmHr( m_pConsole->QueryInterface( IID_IConsoleVerb, (void **)&m_pConsoleVerb ) );
|
|
WsbAffirmHr (m_pConsole->QueryConsoleVerb(&m_pConsoleVerb));
|
|
|
|
|
|
//
|
|
// Get the header interface
|
|
//
|
|
|
|
WsbAffirmHr( m_pConsole->QueryInterface( IID_IHeaderCtrl, (void**)&m_pHeader ) );
|
|
|
|
//
|
|
// Give the console the header control interface pointer
|
|
//
|
|
|
|
WsbAffirmHr( m_pConsole->SetHeader( m_pHeader ) );
|
|
|
|
} WsbCatch( hr);
|
|
|
|
WsbTraceOut( L"CSakSnap::Initialize", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|
return( hr );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
CSakSnap::Notify(
|
|
IN IDataObject* pDataObject,
|
|
IN MMC_NOTIFY_TYPE event,
|
|
IN LPARAM arg,
|
|
IN LPARAM param
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle user clicks on nodes in the result view, along with other
|
|
MMC notices.
|
|
|
|
Arguments:
|
|
|
|
pDataObject - Data Object for which event occured
|
|
|
|
event - The event type
|
|
|
|
arg, param - Info for event (depend on type)
|
|
|
|
Return Value:
|
|
|
|
S_OK - Notification handled without error.
|
|
|
|
E_xxxxxxxxxxx - Unable to register server.
|
|
|
|
--*/
|
|
{
|
|
WsbTraceIn( L"CSakSnap::Notify", L"pDataObject = <0x%p>, event = <%ls>, arg = <%ld><0x%p>, param = <%ld><0x%p>", pDataObject, RsNotifyEventAsString( event ), arg, arg, param, param );
|
|
CComPtr <IDataObject> pTempDataObject;
|
|
HRESULT hr = S_OK;
|
|
|
|
try {
|
|
|
|
CComPtr<ISakNode> pBaseHsm;
|
|
CComPtr <ISakSnapAsk> pSakSnapAsk;
|
|
|
|
|
|
switch( event ) {
|
|
|
|
case MMCN_PROPERTY_CHANGE:
|
|
WsbAffirmHr( m_pSakData->GetDataObjectFromCookie( param, &pTempDataObject ) );
|
|
WsbAffirmHr( OnChange( pTempDataObject, arg, 0L ) );
|
|
break;
|
|
|
|
// This node was expanded or contracted in the scope pane (the user
|
|
// clicked on the actual node
|
|
case MMCN_SHOW:
|
|
WsbAffirmHr( OnShow(pDataObject, arg, param) );
|
|
break;
|
|
|
|
// Not implemented
|
|
case MMCN_SELECT:
|
|
WsbAffirmHr( OnSelect(pDataObject, arg, param) );
|
|
break;
|
|
|
|
// Not implemented
|
|
case MMCN_MINIMIZED:
|
|
WsbAffirmHr( OnMinimize(pDataObject, arg, param) );
|
|
break;
|
|
|
|
case MMCN_ADD_IMAGES:
|
|
WsbAffirmHr( OnAddImages() );
|
|
break;
|
|
|
|
case MMCN_VIEW_CHANGE:
|
|
WsbAffirmHr ( OnChange(pDataObject, arg, param) );
|
|
break;
|
|
|
|
case MMCN_CLICK:
|
|
break;
|
|
|
|
case MMCN_DBLCLICK:
|
|
//
|
|
// return S_FALSE so that auto-expansion takes place
|
|
//
|
|
hr = S_FALSE;
|
|
break;
|
|
|
|
case MMCN_DELETE:
|
|
WsbAffirmHr( OnDelete(pDataObject, arg, param) );
|
|
break;
|
|
|
|
case MMCN_REFRESH:
|
|
WsbAffirmHr( OnRefresh(pDataObject, arg, param) );
|
|
break;
|
|
|
|
case MMCN_CONTEXTHELP:
|
|
WsbAffirmHr( m_pSakData->OnContextHelp( pDataObject, arg, param ) );
|
|
break;
|
|
|
|
// Note - Future expansion of notify types possible
|
|
default:
|
|
// WsbThrow( S_FALSE ); // Handle new messages
|
|
break;
|
|
}
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut( L"CSakSnap::Notify", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|
return( hr );
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CSakSnap::Destroy(
|
|
MMC_COOKIE Cookie
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called to force the release of any owned objects and
|
|
to clear all views.
|
|
|
|
Arguments:
|
|
|
|
cookie - Not used.
|
|
|
|
Return Value:
|
|
|
|
S_OK - Correctly tore down.
|
|
|
|
E_xxxxxxxxxxx - Failure occurred (not meaningful).
|
|
|
|
--*/
|
|
{
|
|
WsbTraceIn( L"CSakSnap::Destroy", L"Cookie = <0x%p>", Cookie );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
try {
|
|
|
|
// This is a straight C++ pointer, so null it out
|
|
m_pSakData = 0;
|
|
|
|
|
|
// Release the interfaces that we QI'ed
|
|
if( m_pToolbar && m_pControlbar ) {
|
|
m_pControlbar->Detach( m_pToolbar );
|
|
}
|
|
if( m_pConsole ) {
|
|
m_pConsole->SetHeader( 0 );
|
|
}
|
|
|
|
m_pToolbar.Release();
|
|
m_pControlbar.Release();
|
|
m_pHeader.Release();
|
|
m_pResultData.Release();
|
|
m_pImageResult.Release();
|
|
m_pConsoleVerb.Release();
|
|
m_pConsole.Release( );
|
|
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut( L"CSakSnap::Destroy", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|
return( hr );
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CSakSnap::QueryDataObject(
|
|
IN MMC_COOKIE cookie,
|
|
IN DATA_OBJECT_TYPES type,
|
|
OUT IDataObject** ppDataObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by the console when it needs data for a particular node.
|
|
Since each node is a data object, its IDataObject interface is
|
|
simply returned. The console will later pass in this dataobject to
|
|
SakSnap help it establish the context under which it is being called.
|
|
|
|
Arguments:
|
|
|
|
cookie - Node which is being queried.
|
|
|
|
type - The context under which a dataobject is being requested.
|
|
|
|
ppDataObject - returned data object.
|
|
|
|
Return Value:
|
|
|
|
S_OK - Data Object found and returned.
|
|
|
|
E_xxxxxxxxxxx - Failure occurred.
|
|
|
|
--*/
|
|
{
|
|
|
|
WsbTraceIn( L"CSakSnap::QueryDataObject", L"cookie = <0x%p>, type = <%d>, ppDataObject = <0x%p>", cookie, type, ppDataObject );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
try {
|
|
//
|
|
// If multi select, we create and return a special data object
|
|
//
|
|
if( ( MMC_MULTI_SELECT_COOKIE == cookie ) ) {
|
|
HRESULT hrInternal = S_OK;
|
|
|
|
RESULTDATAITEM item;
|
|
item.mask = RDI_STATE;
|
|
item.nState = LVIS_SELECTED;
|
|
item.nIndex = -1;
|
|
|
|
// Create a Com object
|
|
CComObject <CMsDataObject> * pMsDataObject = new CComObject <CMsDataObject>;
|
|
pMsDataObject->FinalConstruct();
|
|
pMsDataObject->AddRef(); // zzzzz
|
|
|
|
// Get the IDataObject pointer to pass back to the caller
|
|
WsbAffirmHr (pMsDataObject->QueryInterface (IID_IDataObject, (void **) ppDataObject));
|
|
|
|
// Go through the selected nodes in the result pane and add their node pointers
|
|
// and GUIDs to the Data object.
|
|
while (hrInternal == S_OK) {
|
|
hrInternal = m_pResultData->GetNextItem (&item);
|
|
if (hrInternal == S_OK) {
|
|
CComPtr<ISakNode> pSakNode;
|
|
WsbAffirmHr( m_pSakData->GetBaseHsmFromCookie( item.lParam, &pSakNode ) );
|
|
WsbAffirmPointer( pSakNode );
|
|
WsbAffirmHr( pMsDataObject->AddNode( pSakNode ) );
|
|
}
|
|
} // while
|
|
|
|
} else {
|
|
|
|
//
|
|
// Delegate to SakData
|
|
//
|
|
|
|
WsbAffirmHr (m_pSakData->QueryDataObject( cookie, type, ppDataObject ));
|
|
}
|
|
} WsbCatch (hr);
|
|
|
|
WsbTraceOut( L"CSakSnap::QueryDataObject", L"hr = <%ls>, *ppDataObject = <%ls>", WsbHrAsString( hr ), WsbPtrToPtrAsString( (void**)ppDataObject ) );
|
|
return( hr );
|
|
}
|
|
|
|
void
|
|
CSakSnap::FinalRelease(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called on final release in order to clean up all members.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
WsbTraceIn( L"CSakSnap::FinalRelease", L"" );
|
|
WsbTraceOut( L"CSakSnap::FinalRelease", L"" );
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CSakSnap::FinalConstruct(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called during initial CSakSnap construction to initialize members.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
S_OK - Initialized correctly.
|
|
|
|
E_xxxxxxxxxxx - Failure occurred.
|
|
|
|
--*/
|
|
{
|
|
WsbTraceIn( L"CSakSnap::FinalConstruct", L"" );
|
|
|
|
HRESULT hr = CComObjectRoot::FinalConstruct( );
|
|
|
|
m_ActiveNodeCookie = 0;
|
|
m_pEnumeratedNode = NULL;
|
|
|
|
//
|
|
// Initialize column widths to 0
|
|
//
|
|
for( INT i = 0; i < BHSM_MAX_NODE_TYPES; i++ ) {
|
|
|
|
m_ChildPropWidths[ i ].nodeTypeId = GUID_NULL;
|
|
m_ChildPropWidths[ i ].colCount = 0;
|
|
|
|
for ( INT j = 0; j < BHSM_MAX_CHILD_PROPS; j++ ) {
|
|
|
|
m_ChildPropWidths[ i ].columnWidths[ j ] = 0;
|
|
|
|
}
|
|
}
|
|
m_cChildPropWidths = 0;
|
|
|
|
WsbTraceOut( L"CSakSnap::FinalConstruct", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|
return( hr );
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CSakSnap::InitResultPaneHeaders(
|
|
ISakNode* pNode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This functions sets up the result view header titles and widths.
|
|
It should be called immediately prior to populating the result view.
|
|
|
|
Arguments:
|
|
|
|
pNode - Node whose contents will be shown.
|
|
|
|
Return Value:
|
|
|
|
S_OK - Initialized correctly.
|
|
|
|
E_xxxxxxxxxxx - Failure occurred.
|
|
|
|
--*/
|
|
{
|
|
WsbTraceIn( L"CSakSnap::InitResultPaneHeaders", L"pNode = <0x%p>", pNode );
|
|
|
|
HRESULT hr = S_OK;
|
|
HRESULT hrInternal = S_OK;
|
|
BOOL bGotSavedWidths = FALSE;
|
|
CComPtr<IEnumString> pEnumStr;
|
|
|
|
try {
|
|
|
|
WsbAffirmPointer( m_pHeader );
|
|
WsbAffirmPointer( pNode );
|
|
|
|
// Clean out any old columns in the result pane
|
|
hrInternal = S_OK;
|
|
while ( hrInternal == S_OK ) {
|
|
hrInternal = m_pHeader->DeleteColumn( 0 );
|
|
}
|
|
|
|
// Get saved column widths (from CSakSnap) (they may not exist).
|
|
|
|
INT columnWidths [ BHSM_MAX_CHILD_PROPS ];
|
|
INT colCount;
|
|
hrInternal = GetSavedColumnWidths( pNode, &colCount, columnWidths );
|
|
if( hrInternal == S_OK ) {
|
|
|
|
bGotSavedWidths = TRUE;
|
|
|
|
}
|
|
|
|
// Enumerate child display property column widths and create the columns with the correct
|
|
// widths (but wrong titles).
|
|
WsbAffirmHr( pNode->EnumChildDisplayPropWidths( &pEnumStr ) );
|
|
if( pEnumStr ) {
|
|
|
|
OLECHAR* str;
|
|
|
|
// loop over the columns of display properties to get their widths.
|
|
INT nCol = 0;
|
|
while( pEnumStr->Next( 1, &str, NULL ) == S_OK ) {
|
|
|
|
// Set the the next column width. Sometimes we may display more columns
|
|
// than were saved - if so use the resource string for those columns. We
|
|
// don't throw errors because this function can get called when (I think)
|
|
// when the scope pane is displaying the nodes in the result pane and the
|
|
// header functions will fail.
|
|
|
|
if( bGotSavedWidths && ( nCol < colCount ) ) {
|
|
|
|
hrInternal = m_pHeader->InsertColumn( nCol, str, LVCFMT_LEFT, columnWidths[ nCol ] );
|
|
|
|
} else {
|
|
|
|
hrInternal = m_pHeader->InsertColumn( nCol, str, LVCFMT_LEFT, MMCLV_AUTO );
|
|
|
|
}
|
|
nCol++;
|
|
CoTaskMemFree( str );
|
|
str = 0;
|
|
}
|
|
|
|
} else {
|
|
|
|
hr = S_FALSE;
|
|
|
|
}
|
|
|
|
// Enumerate child display titles and use as correct column titles.
|
|
pEnumStr = NULL;
|
|
pNode->EnumChildDisplayTitles( &pEnumStr );
|
|
if( pEnumStr ) {
|
|
|
|
OLECHAR* str;
|
|
|
|
// loop over the columns of display properties to get their titles.
|
|
INT nCol = 0;
|
|
while( pEnumStr->Next( 1, &str, NULL ) == S_OK ) {
|
|
|
|
// Reset the strings in the titles of the headers. For some reason, it is NOW
|
|
// acting as if 0 based.
|
|
WsbAffirmHr( m_pHeader->SetColumnText( nCol, str ) );
|
|
nCol++;
|
|
|
|
CoTaskMemFree( str );
|
|
str = 0;
|
|
}
|
|
|
|
} else {
|
|
|
|
hr = S_FALSE;
|
|
|
|
}
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut( L"CSakSnap::InitResultPaneHeaders", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CSakSnap::GetDisplayInfo(
|
|
IN OUT RESULTDATAITEM * pResult
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
When MMC is told to call back concerning resultview items,
|
|
we receive a call here to fill in missing information (once per "cell"
|
|
in the columns and rows of a "listview" style of result view).
|
|
|
|
Note that the snapin manager automatically calls this method for the items
|
|
appearing in the scope pane to render them in the result pane, and then it is
|
|
called again for the items that appear only in the result pane as a result of
|
|
our establishing the callback in EnumResultView.
|
|
|
|
Arguments:
|
|
|
|
pResult - RESULTDATAITEM structure representing state of the node
|
|
in the result listview.
|
|
|
|
Return Value:
|
|
|
|
S_OK - Struct filled in.
|
|
|
|
E_xxxxxxxxxxx - Failure occurred.
|
|
|
|
--*/
|
|
{
|
|
static CWsbStringPtr tmpString;
|
|
|
|
WsbTraceIn( L"CSakSnap::GetDisplayInfo", L"cookie = <0x%p>, pScopeItem->mask = <0x%p>, pResult->nCol = <%d>", pResult->lParam, pResult->mask, pResult->nCol );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
try {
|
|
|
|
WsbAffirmPointer( pResult );
|
|
|
|
CComPtr<ISakNode> pNode; // basehsm interface for the node whose properties are being displayed.
|
|
WsbAffirmHr( m_pSakData->GetBaseHsmFromCookie( pResult->lParam, &pNode ) );
|
|
|
|
if( pResult->mask & RDI_IMAGE ) {
|
|
|
|
WsbAffirmHr( pNode->GetResultIcon( m_pSakData->m_State, &pResult->nImage ) );
|
|
|
|
}
|
|
//
|
|
// If the RESULTDATAITEM indicates that it needs a string...
|
|
//
|
|
if( pResult->mask & RDI_STR ) {
|
|
|
|
//
|
|
// Use the basehsm pointer to get the correct data to populate the listview.
|
|
//
|
|
|
|
DISPID dispid;
|
|
CComPtr<IDispatch> pDisp; // dispatch interface
|
|
CComPtr<ISakNode> pParentNode; // basehsm interface for the node's parent
|
|
|
|
CWsbVariant varRet;
|
|
CWsbStringPtr pPropString;
|
|
|
|
//
|
|
// Prepare an enumerator to look at each child property
|
|
// (i.e. - column of info). Need to get the list of child properties from
|
|
// the parent of this child.
|
|
//
|
|
|
|
CComPtr<IEnumString> pEnum;
|
|
WsbAffirmHr( pNode->GetParent( &pParentNode ));
|
|
|
|
//
|
|
// If parentNode == 0, we are displaying our root node in the result pane
|
|
// ( we are extending someone else ). Since the parent has determined the
|
|
// columns to be name, type and description, we show that.
|
|
//
|
|
|
|
if( ! pParentNode ) {
|
|
|
|
WsbAffirmHr( EnumRootDisplayProps( &pEnum ) );
|
|
|
|
} else {
|
|
|
|
WsbAffirmHr( pParentNode->EnumChildDisplayProps( &pEnum ) );
|
|
|
|
}
|
|
if( pEnum ) {
|
|
|
|
//
|
|
// Skip the correct number of columns to access
|
|
// the exact column that we need.
|
|
//
|
|
|
|
if( pResult->nCol > 0 ) {
|
|
|
|
WsbAffirmHr( pEnum->Skip( pResult->nCol ) );
|
|
|
|
}
|
|
WsbAffirmHr( pEnum->Next( 1, &pPropString, NULL ) );
|
|
|
|
//
|
|
// get the dispatch interface for this node
|
|
//
|
|
WsbAffirmHr( pNode->QueryInterface( IID_IDispatch, (void**)&pDisp ) );
|
|
|
|
DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
|
|
|
|
//
|
|
// convert the property name to a dispatch id that can be invoked.
|
|
// Invoke the interfaces to get the value of the cell.
|
|
//
|
|
|
|
WsbAffirmHr( pDisp->GetIDsOfNames( IID_NULL, &(pPropString), 1, LOCALE_USER_DEFAULT, &dispid ));
|
|
WsbAffirmHr( pDisp->Invoke( dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
|
|
&dispparamsNoArgs, &varRet, NULL, NULL) );
|
|
tmpString = (OLECHAR*)varRet;
|
|
}
|
|
|
|
pResult->str = tmpString;
|
|
}
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut( L"CSakSnap::GetDisplayInfo", L"hr = <%ls>, pResult->str = <%ls>, pResult->nImage = <%ls>", WsbHrAsString( hr ), (RDI_STR & pResult->mask) ? pResult->str : L"N/A", (RDI_IMAGE & pResult->mask) ? WsbLongAsString( pResult->nImage ) : L"N/A" );
|
|
return( hr );
|
|
}
|
|
|
|
HRESULT CSakSnap::EnumRootDisplayProps( IEnumString ** ppEnum )
|
|
{
|
|
WsbTraceIn( L"CSakSnap::EnumRootDisplayProps", L"ppEnum = <0x%p>", ppEnum );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
CEnumString * pEnum = 0;
|
|
BSTR rgszRootPropIds[] = {L"DisplayName", L"Type", L"Description"};
|
|
INT cRootPropsShow = 3;
|
|
try {
|
|
|
|
WsbAffirmPointer( ppEnum );
|
|
WsbAffirm( cRootPropsShow > 0, S_FALSE );
|
|
|
|
*ppEnum = 0;
|
|
|
|
//
|
|
// New an ATL enumerator
|
|
//
|
|
pEnum = new CEnumString;
|
|
WsbAffirm( pEnum, E_OUTOFMEMORY );
|
|
|
|
WsbAffirmHr( pEnum->FinalConstruct( ) );
|
|
WsbAffirmHr( pEnum->Init( &rgszRootPropIds[0], &rgszRootPropIds[cRootPropsShow], NULL, AtlFlagCopy ) );
|
|
WsbAffirmHr( pEnum->QueryInterface( IID_IEnumString, (void**)ppEnum ) );
|
|
|
|
} WsbCatchAndDo( hr,
|
|
|
|
if( pEnum ) delete pEnum;
|
|
|
|
);
|
|
|
|
WsbTraceOut( L"CSakSnap::EnumRootDisplayProps", L"hr = <%ls>, *ppEnum = <%ls>", WsbHrAsString( hr ), WsbPtrToPtrAsString( (void**)ppEnum ) );
|
|
return( hr );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IExtendPropertySheet Implementation.
|
|
//
|
|
|
|
STDMETHODIMP
|
|
CSakSnap::CreatePropertyPages(
|
|
IPropertySheetCallback* pPropSheetCallback,
|
|
RS_NOTIFY_HANDLE handle,
|
|
IDataObject* pDataObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Console calls this when it is building a property sheet to
|
|
show for a node. It is also called for the data object given
|
|
to represent the snapin to the snapin manager, and should
|
|
show the initial selection page at that point.
|
|
|
|
Arguments:
|
|
|
|
pPropSheetCallback - MMC interface to use to add page.
|
|
|
|
handle - Handle to MMC to use to add the page.
|
|
|
|
pDataObject - Data object refering to node.
|
|
|
|
Return Value:
|
|
|
|
S_OK - Pages added.
|
|
|
|
E_xxxxxxxxxxx - Failure occurred.
|
|
|
|
--*/
|
|
{
|
|
WsbTraceIn( L"CSakSnap::CreatePropertyPages", L"pPropSheetCallback = <0x%p>, handle = <0x%p>, pDataObject = <0x%p>", pPropSheetCallback, handle, pDataObject );
|
|
|
|
//
|
|
// Delegate to CSakData
|
|
//
|
|
|
|
HRESULT hr = m_pSakData->CreatePropertyPages( pPropSheetCallback, handle, pDataObject );
|
|
|
|
WsbTraceOut( L"CSakSnap::CreatePropertyPages", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|
return( hr );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CSakSnap::QueryPagesFor(
|
|
IDataObject* pDataObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This method is called by MMC when it wants to find out if this node
|
|
supports property pages. The answer is yes if:
|
|
|
|
1) The MMC context is either for the scope pane or result pane, AND
|
|
|
|
2) The node actually DOES have property pages.
|
|
|
|
OR
|
|
|
|
1) The Data Object is acquired by the snapin manager.
|
|
|
|
Return S_OK if it DOES have pages, and S_FALSE if it does NOT have pages.
|
|
|
|
Arguments:
|
|
|
|
pDataObject - Data object refering to node.
|
|
|
|
Return Value:
|
|
|
|
S_OK - Pages exist.
|
|
|
|
S_FALSE - No property pages.
|
|
|
|
E_xxxxxxxxxxx - Failure occurred.
|
|
|
|
--*/
|
|
{
|
|
WsbTraceIn( L"CSakSnap::QueryPagesFor", L"pDataObject = <0x%p>", pDataObject );
|
|
|
|
HRESULT hr = m_pSakData->QueryPagesFor( pDataObject );
|
|
|
|
WsbTraceOut( L"CSakSnap::QueryPagesFor", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|
return ( hr );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CSakSnap::CompareObjects(
|
|
IN IDataObject* pDataObjectA,
|
|
IN IDataObject* pDataObjectB
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compare data objects for MMC
|
|
|
|
Arguments:
|
|
|
|
pDataObjectA, - Data object refering to node.
|
|
pDataObjectB
|
|
|
|
Return Value:
|
|
|
|
S_OK - Objects represent the same node.
|
|
|
|
S_FALSE - Objects do not represent the same node.
|
|
|
|
E_xxxxxxxxxxx - Failure occurred.
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WsbTraceIn( L"CSakSnap::CompareObjects", L"pDataObjectA = <0x%p>, pDataObjectB = <0x%p>", pDataObjectA, pDataObjectB );
|
|
|
|
hr = m_pSakData->CompareObjects( pDataObjectA, pDataObjectB );
|
|
|
|
WsbTraceOut( L"CSakSnap::CompareObjects", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|
return ( hr );
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IPersistStream implementation
|
|
//
|
|
|
|
HRESULT
|
|
CSakSnap::Save(
|
|
IStream *pStm,
|
|
BOOL fClearDirty
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Save the information we need to reconstruct the root node in the
|
|
supplied stream.
|
|
|
|
Arguments:
|
|
|
|
pStm I: Console-supplied stream
|
|
fClearDirty I: The console tells us to clear our dirty flag
|
|
|
|
Return Value:
|
|
|
|
S_OK - Saved successfully.
|
|
E_* - Some error occurred.
|
|
|
|
--*/
|
|
{
|
|
WsbTraceIn( L"CSakSnap::Save", L"pStm = <0x%p>, fClearDirty", pStm, WsbBoolAsString( fClearDirty ) );
|
|
|
|
HRESULT hr = S_OK;
|
|
INT index;
|
|
INT jindex;
|
|
|
|
try {
|
|
ULONG version = HSMADMIN_CURRENT_VERSION;
|
|
WsbAffirmHr( WsbSaveToStream( pStm, version ) );
|
|
|
|
// Get the settings from the currently opened view
|
|
if ( m_pEnumeratedNode ) {
|
|
SaveColumnWidths( m_pEnumeratedNode );
|
|
}
|
|
|
|
// Save the number of different nodes
|
|
WsbAffirmHr( WsbSaveToStream ( pStm, m_cChildPropWidths ) );
|
|
|
|
// For each different node...
|
|
for ( index = 0; index < m_cChildPropWidths; index++ ) {
|
|
|
|
// Save the nodetype and column count
|
|
WsbAffirmHr( WsbSaveToStream ( pStm, m_ChildPropWidths[ index ].nodeTypeId ) );
|
|
WsbAffirmHr( WsbSaveToStream ( pStm, m_ChildPropWidths[ index ].colCount ) );
|
|
|
|
// Save the column widths
|
|
for ( jindex = 0; jindex < m_ChildPropWidths[ index ].colCount; jindex++ ) {
|
|
WsbAffirmHr( WsbSaveToStream ( pStm, m_ChildPropWidths[ index ].columnWidths[ jindex ] ) );
|
|
}
|
|
}
|
|
} WsbCatch ( hr );
|
|
|
|
WsbTraceOut( L"CSakSnap::Save", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|
return( hr );
|
|
}
|
|
|
|
HRESULT
|
|
CSakSnap::Load(
|
|
IStream *pStm
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Load the information we need to reconstruct the root node from the
|
|
supplied stream.
|
|
|
|
Arguments:
|
|
|
|
pStm IConsole-supplied stream
|
|
|
|
Return Value:
|
|
|
|
S_OK - Saved successfully.
|
|
E_* - Some error occurred.
|
|
|
|
--*/
|
|
{
|
|
WsbTraceIn( L"CSakSnap::Load", L"pStm = <0x%p>", pStm );
|
|
|
|
HRESULT hr = S_OK;
|
|
HRESULT hrInternal = S_OK;
|
|
USHORT nodeCount;
|
|
INT index;
|
|
INT jindex;
|
|
|
|
try {
|
|
ULONG version = 0;
|
|
WsbAffirmHr( WsbLoadFromStream( pStm, &version ) );
|
|
WsbAssert( ( version == 1 ), E_FAIL );
|
|
|
|
// Set to zero in case we fail part way through
|
|
m_cChildPropWidths = 0;
|
|
|
|
// If this fails, it probably means that nothing has been saved yet
|
|
hrInternal = WsbLoadFromStream (pStm, &nodeCount);
|
|
if ( hrInternal == S_OK ) {
|
|
|
|
for ( index = 0; index < nodeCount; index++ ) {
|
|
|
|
// Retrieve the nodetype and column count
|
|
WsbAffirmHr( WsbLoadFromStream ( pStm, &( m_ChildPropWidths[ index ].nodeTypeId ) ) );
|
|
WsbAffirmHr( WsbLoadFromStream ( pStm, &( m_ChildPropWidths[ index ].colCount ) ) );
|
|
|
|
// Retrieve the column widths
|
|
for ( jindex = 0; jindex < m_ChildPropWidths[ index ].colCount; jindex++ ) {
|
|
WsbAffirmHr( WsbLoadFromStream ( pStm, &( m_ChildPropWidths[ index ].columnWidths[ jindex ] ) ) );
|
|
}
|
|
}
|
|
m_cChildPropWidths = nodeCount;
|
|
}
|
|
WsbTraceOut( L"CSakSnap::Load", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|
} WsbCatch (hr);
|
|
return( hr );
|
|
}
|
|
|
|
HRESULT
|
|
CSakSnap::IsDirty(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The console asks us if we are dirty.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
S_OK - Dirty.
|
|
S_FALSE - Not Dirty.
|
|
|
|
--*/
|
|
{
|
|
WsbTraceIn( L"CSakSnap::IsDirty", L"" );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceOut( L"CSakSnap::IsDirty", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|
return( hr );
|
|
}
|
|
|
|
HRESULT
|
|
CSakSnap::GetSizeMax(
|
|
ULARGE_INTEGER *pcbSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Not currently used by the console
|
|
|
|
Arguments:
|
|
|
|
pcbSize
|
|
|
|
Return Value:
|
|
|
|
S_OK
|
|
|
|
--*/
|
|
{
|
|
WsbTraceIn( L"CSakSnap::GetSizeMax", L"" );
|
|
|
|
pcbSize->QuadPart = 256;
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceOut( L"CSakSnap::GetSizeMax", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|
return( hr );
|
|
}
|
|
|
|
HRESULT
|
|
CSakSnap::GetClassID(
|
|
CLSID *pClassID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Not currently used by the console
|
|
|
|
Arguments:
|
|
|
|
pClassID - The class ID for the snapin
|
|
|
|
Return Value:
|
|
|
|
S_OK
|
|
--*/
|
|
{
|
|
WsbTraceIn( L"CSakSnap::GetClassID", L"pClassID = <0x%p>", pClassID );
|
|
|
|
HRESULT hr = S_OK;
|
|
*pClassID = CLSID_HsmAdmin;
|
|
|
|
WsbTraceOut( L"CSakSnap::GetClassID", L"hr = <%ls>, *pClassID = <%ls>", WsbHrAsString( hr ), WsbPtrToGuidAsString( pClassID ) );
|
|
return( hr );
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Description: Add the supplied resource ID to the list of resource IDs for
|
|
// the scope pane. Returns the index into the array.
|
|
//
|
|
INT CSakSnap::AddImage( UINT rId )
|
|
{
|
|
INT nIndex = 1;
|
|
if (CSakSnap::m_nImageCount < RS_RESULT_IMAGE_ARRAY_MAX) {
|
|
|
|
CSakSnap::m_nImageArray[CSakSnap::m_nImageCount] = rId;
|
|
nIndex = CSakSnap::m_nImageCount;
|
|
CSakSnap::m_nImageCount++;
|
|
|
|
}
|
|
return nIndex;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Adds images to the consoles image list from the static array
|
|
//
|
|
HRESULT CSakSnap::OnAddImages()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HICON hIcon;
|
|
AFX_MANAGE_STATE( AfxGetStaticModuleState( ) );
|
|
try {
|
|
|
|
//
|
|
// References to the image list are now invalid
|
|
//
|
|
|
|
// Put the images from the static array into the image list
|
|
// for the result pane
|
|
|
|
for( INT i = 0; i < m_nImageCount; i++) {
|
|
// Load the icon using the resource Id stored in the
|
|
// static array and get the handle.
|
|
|
|
hIcon = LoadIcon( _Module.m_hInst,
|
|
MAKEINTRESOURCE( m_nImageArray [i] ) );
|
|
|
|
// Add to the Console's Image list
|
|
WsbAffirmHr( m_pImageResult->ImageListSetIcon( (RS_WIN32_HANDLE*)hIcon, i) );
|
|
}
|
|
} WsbCatch (hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CSakSnap::SaveColumnWidths( ISakNode *pNode )
|
|
{
|
|
WsbTraceIn( L"CSakSnap::SaveColumnWidths", L"pNode = <0x%p>", pNode );
|
|
|
|
HRESULT hr = S_OK;
|
|
HRESULT hrInternal;
|
|
INT columnWidth;
|
|
GUID nodeTypeGuid;
|
|
BOOL exists = FALSE;
|
|
INT updateIndex = -1;
|
|
INT col;
|
|
|
|
try {
|
|
WsbAssertPointer( pNode );
|
|
|
|
// Get the type of the supplied node
|
|
WsbAffirmHr( pNode->GetNodeType ( &nodeTypeGuid ) );
|
|
|
|
// Search to see if the GUID already has an entry
|
|
for ( INT index = 0; index < m_cChildPropWidths; index++ ) {
|
|
|
|
if ( m_ChildPropWidths[ index ].nodeTypeId == nodeTypeGuid ) {
|
|
|
|
updateIndex = index;
|
|
exists = TRUE;
|
|
|
|
}
|
|
}
|
|
if ( !exists ) {
|
|
|
|
// Create a new entry
|
|
WsbAssert( m_cChildPropWidths < BHSM_MAX_NODE_TYPES - 1, E_FAIL );
|
|
updateIndex = m_cChildPropWidths;
|
|
m_ChildPropWidths[ updateIndex ].nodeTypeId = nodeTypeGuid;
|
|
m_cChildPropWidths++;
|
|
}
|
|
|
|
// Now set the column widths
|
|
col = 0;
|
|
hrInternal = S_OK;
|
|
while ( hrInternal == S_OK ) {
|
|
hrInternal = m_pHeader->GetColumnWidth( col, &columnWidth );
|
|
if (hrInternal == S_OK) {
|
|
m_ChildPropWidths[ updateIndex ].columnWidths[ col ] = (USHORT)columnWidth;
|
|
col++;
|
|
}
|
|
}
|
|
// if we failed totally to get column widths, don't wipe out the previous value
|
|
if ( col > 0 ) {
|
|
m_ChildPropWidths[ updateIndex ].colCount = (USHORT)col;
|
|
}
|
|
} WsbCatch (hr);
|
|
WsbTraceOut( L"CSakSnap::SaveColumnWidths", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CSakSnap::GetSavedColumnWidths( ISakNode *pNode, INT *pColCount, INT *pColumnWidths )
|
|
{
|
|
WsbTraceIn( L"CSakSnap::SaveColumnWidths", L"pNode = <0x%p>", pNode );
|
|
|
|
HRESULT hr = S_OK;
|
|
GUID nodeTypeGuid;
|
|
BOOL exists = FALSE;
|
|
INT col;
|
|
|
|
try {
|
|
|
|
WsbAssertPointer( pNode );
|
|
|
|
// Get the type of the supplied node
|
|
WsbAffirmHr( pNode->GetNodeType ( &nodeTypeGuid ) );
|
|
|
|
// Search to see if the GUID already has an entry
|
|
for( INT index = 0; index < m_cChildPropWidths; index++ ) {
|
|
|
|
if ( m_ChildPropWidths[ index ].nodeTypeId == nodeTypeGuid ) {
|
|
|
|
for ( col = 0; col < m_ChildPropWidths[ index ].colCount; col++) {
|
|
|
|
// Return the column widths
|
|
pColumnWidths[ col ] = m_ChildPropWidths[ index ].columnWidths[ col ];
|
|
|
|
}
|
|
*pColCount = m_ChildPropWidths[ index ].colCount;
|
|
exists = TRUE;
|
|
}
|
|
}
|
|
if ( !exists ) {
|
|
return WSB_E_NOTFOUND;
|
|
}
|
|
} WsbCatch (hr);
|
|
WsbTraceOut( L"CSakSnap::SaveColumnWidths", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|
return hr;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// IExtendControlbar implementation
|
|
//
|
|
|
|
|
|
STDMETHODIMP CSakSnap::SetControlbar(LPCONTROLBAR pControlbar)
|
|
{
|
|
WsbTraceIn( L"CSakSnap::SetControlbar", L"pControlbar = <0x%p>", pControlbar );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
try {
|
|
|
|
//
|
|
// Clear out old controlbar
|
|
//
|
|
if( m_pControlbar && m_pToolbar ) {
|
|
|
|
m_pControlbar->Detach( m_pToolbar );
|
|
|
|
}
|
|
m_pToolbar.Release( );
|
|
m_pControlbar.Release( );
|
|
|
|
//
|
|
// Hold on to the controlbar interface.
|
|
//
|
|
m_pControlbar = pControlbar;
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut( L"CSakSnap::SetControlbar", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|
return( hr );
|
|
}
|
|
|
|
STDMETHODIMP CSakSnap::ControlbarNotify( MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param )
|
|
{
|
|
WsbTraceIn( L"CSakSnap::ControlbarNotify", L"" );
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
HRESULT hr = S_FALSE;
|
|
|
|
switch( event ) {
|
|
|
|
case MMCN_BTN_CLICK:
|
|
hr = OnToolbarButtonClick( arg, param );
|
|
break;
|
|
|
|
case MMCN_DESELECT_ALL:
|
|
break;
|
|
|
|
case MMCN_SELECT:
|
|
OnSelectToolbars( arg, param );
|
|
break;
|
|
|
|
case MMCN_MENU_BTNCLICK:
|
|
// HandleExtMenus(arg, param);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
WsbTraceOut( L"CSakSnap::ControlbarNotify", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|
return( hr );
|
|
}
|
|
|
|
HRESULT CSakSnap::OnToolbarButtonClick( LPARAM arg, LPARAM cmdId )
|
|
{
|
|
WsbTraceIn( L"CSakSnap::OnToolbarButtonClick", L"arg = <0x%p>, cmdId = <%ld>" );
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
try {
|
|
|
|
IDataObject* pDataObject = (IDataObject*)arg;
|
|
WsbAffirmPointer( pDataObject );
|
|
|
|
CComPtr<ISakNode> pNode;
|
|
WsbAffirmHr( m_pSakData->GetBaseHsmFromDataObject( pDataObject, &pNode ) );
|
|
|
|
// Delegate to the node
|
|
WsbAffirmHr( pNode->OnToolbarButtonClick( pDataObject, (LONG)cmdId ) );
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut( L"CSakSnap::OnToolbarButtonClick", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|
return( hr );
|
|
}
|
|
|
|
|
|
void CSakSnap::OnSelectToolbars(LPARAM arg, LPARAM param)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
try {
|
|
|
|
BOOL bScope = (BOOL) LOWORD( arg );
|
|
BOOL bSelect = (BOOL) HIWORD( arg );
|
|
|
|
IDataObject* pDataObject = (IDataObject*)param;
|
|
WsbAffirmPointer( pDataObject );
|
|
|
|
CComPtr<ISakNode> pNode;
|
|
WsbAffirmHr( m_pSakData->GetBaseHsmFromDataObject( pDataObject, &pNode ) );
|
|
|
|
if( bSelect ) {
|
|
|
|
//
|
|
// ATL detaches any existing toolbar before attaching new ones.
|
|
// This appears to fix issues of us adding toolbar upon toolbar
|
|
//
|
|
if( m_pToolbar ) {
|
|
|
|
m_pControlbar->Detach( m_pToolbar );
|
|
m_pToolbar.Release( );
|
|
|
|
}
|
|
|
|
//
|
|
// Does the node have a toolbar?
|
|
//
|
|
if( pNode->HasToolbar() == S_OK ) {
|
|
|
|
//
|
|
// Create the toolbar for the indicated node
|
|
//
|
|
WsbAffirmHr( m_pControlbar->Create( TOOLBAR, this, reinterpret_cast<LPUNKNOWN*>(&m_pToolbar) ) );
|
|
|
|
//
|
|
// Returns S_FALSE if there is no toolbar for the node
|
|
//
|
|
if( pNode->SetupToolbar( m_pToolbar ) == S_OK ) {
|
|
|
|
//
|
|
// Attach the toolbar
|
|
//
|
|
WsbAffirmHr( m_pControlbar->Attach( TOOLBAR, (IUnknown*) m_pToolbar ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Destroy the toolbar
|
|
// NOTE: Not done in ATL snapin classes
|
|
//
|
|
if( m_pToolbar ) {
|
|
|
|
m_pControlbar->Detach( m_pToolbar );
|
|
|
|
}
|
|
m_pToolbar.Release();
|
|
|
|
}
|
|
|
|
|
|
} WsbCatch( hr );
|
|
}
|
|
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
CSakSnap::Compare(
|
|
IN LPARAM /*lUserParam*/,
|
|
IN MMC_COOKIE CookieA,
|
|
IN MMC_COOKIE CookieB,
|
|
IN OUT int* pnResult
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
try {
|
|
|
|
//
|
|
// Store column and set result to 'equal' ASAP
|
|
//
|
|
WsbAffirmPointer( pnResult );
|
|
int col = *pnResult;
|
|
*pnResult = 0;
|
|
|
|
//
|
|
// And make sure we have a node we know we're showing
|
|
//
|
|
WsbAffirmPointer( m_pEnumeratedNode );
|
|
|
|
|
|
CComPtr<ISakNode> pNodeA, pNodeB;
|
|
CComPtr<IDispatch> pDispA, pDispB;
|
|
WsbAffirmHr( m_pSakData->GetBaseHsmFromCookie( CookieA, &pNodeA ) );
|
|
WsbAffirmHr( m_pSakData->GetBaseHsmFromCookie( CookieB, &pNodeB ) );
|
|
WsbAffirmHr( pNodeA.QueryInterface( &pDispA ) );
|
|
WsbAffirmHr( pNodeB.QueryInterface( &pDispB ) );
|
|
|
|
CComPtr<IEnumString> pEnum;
|
|
WsbAffirmHrOk( m_pEnumeratedNode->EnumChildDisplayProps( &pEnum ) );
|
|
|
|
//
|
|
// Skip the correct number of columns to access
|
|
// the exact column that we need.
|
|
//
|
|
if( col > 0 ) {
|
|
|
|
WsbAffirmHr( pEnum->Skip( col ) );
|
|
|
|
}
|
|
|
|
CWsbVariant varRetA, varRetB;
|
|
CWsbStringPtr pPropString;
|
|
WsbAffirmHrOk( pEnum->Next( 1, &pPropString, NULL ) );
|
|
WsbAffirmHr( pPropString.Append( L"_SortKey" ) );
|
|
|
|
|
|
//
|
|
// convert the property name to a dispatch id that can be invoked.
|
|
// Invoke the interfaces to get the value of the cell.
|
|
//
|
|
DISPID dispid;
|
|
DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
|
|
|
|
WsbAffirmHr( pDispA->GetIDsOfNames( IID_NULL, &(pPropString), 1, LOCALE_USER_DEFAULT, &dispid ));
|
|
WsbAffirmHr(
|
|
pDispA->Invoke(
|
|
dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
|
|
&dispparamsNoArgs, &varRetA, NULL, NULL ) );
|
|
WsbAffirmHr(
|
|
pDispB->Invoke(
|
|
dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
|
|
&dispparamsNoArgs, &varRetB, NULL, NULL ) );
|
|
|
|
WsbAffirmPointer( (WCHAR*)varRetA );
|
|
WsbAffirmPointer( (WCHAR*)varRetB );
|
|
*pnResult = _wcsicmp( (WCHAR*)varRetA, (WCHAR*)varRetB );
|
|
|
|
//
|
|
// If results are that they are the same (and not first column)
|
|
// than compare the first column (the Name)
|
|
//
|
|
if( ( 0 == *pnResult ) && ( col > 0 ) ) {
|
|
|
|
*pnResult = 0; // Compare first Column if same
|
|
WsbAffirmHr( Compare( 0, CookieA, CookieB, pnResult ) );
|
|
|
|
}
|
|
WsbTrace( L"CSakSnap::Compare: *pnResult = <%ls>, SortKeyA = <%ls>, SortKeyB = <%ls>\n", WsbPtrToLongAsString( (LONG*)pnResult ), (WCHAR*)varRetA, (WCHAR*)varRetB );
|
|
|
|
} WsbCatch( hr );
|
|
|
|
return( hr );
|
|
}
|
|
|
|
|
|
|
|
|