CSNAPIN.CPP

// This is a part of the Microsoft Management Console. 
// Copyright 1995 - 1997 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Management Console and related
// electronic documentation provided with the interfaces.



#include "stdafx.h"
#include "Service.h"
#include "CSnapin.h"
#include "DataObj.h"
#include "afxdlgs.h"
#include "resource.h"
#include "genpage.h" // Step 3

#include <atlimpl.cpp>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


// All data is static for the sample
FOLDER_DATA FolderData[NUM_FOLDERS] =
{
{L"User Data", L"1111", L"Info about users", USER},
{L"Company Data", L"2222", L"Info about Companies", COMPANY},
{L"Virtual Data", L"3333", L"Info about virtual items", VIRTUAL},
{L"", L"", L"",STATIC}
};

FOLDER_DATA ExtFolderData[NUM_FOLDERS] =
{
{L"1:", L"1111", L"Info about users", EXT_USER},
{L"2:", L"2222", L"Info about Companies", EXT_COMPANY},
{L"3:", L"3333", L"Infor about virtual items", EXT_VIRTUAL},
{L"", L"", L"",STATIC}
};

static MMCBUTTON SnapinButtons[] =
{
{ 0, 1, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Folder", L"New Folder" },
{ 1, 2, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Inbox", L"Mail Inbox"},
{ 2, 3, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Outbox", L"Mail Outbox" },
{ 3, 4, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Send", L"Send Message" },
{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, L" ", L"" },
{ 4, 5, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Trash", L"Trash" },
{ 5, 6, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Open", L"Open Folder"},
{ 6, 7, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"News", L"Today's News" },
{ 7, 8, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"INews", L"Internet News" },

};

static MMCBUTTON SnapinButtons2[] =
{
{ 0, 10, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Compose", L"Compose Message" },
{ 1, 20, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Print", L"Print Message" },
{ 2, 30, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Find", L"Find Message" },
{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, L" ", L"" },
{ 3, 40, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Inbox", L"Inbox" },
{ 4, 50, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Smile", L"Smile :-)" },
{ 5, 60, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Reply", L"Reply" },
{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP , L" ", L"" },
{ 6, 70, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Reply All", L"Reply All" },

};

enum
{
// Identifiers for each of the commands/views to be inserted into the context menu.
IDM_COMMAND1,
IDM_COMMAND2,
IDM_SAMPLE_OCX_VIEW,
IDM_SAMPLE_WEB_VIEW
};

static int n_count = 0;

//#define ODS OutputDebugString
#define ODS OutputDebugString

#ifdef DBX
void DbxPrint(LPTSTR pszFmt, ...)
{
va_list va;
va_start (va, pszFmt);
TCHAR buf[250];
wsprintf(buf, pszFmt, va);
OutputDebugString(buf);
va_end(va);
}
//#define DBX_PRINT DbxPrint
inline void __DummyTrace(LPTSTR, ...) { }
#define DBX_PRINT 1 ? (void)0 : ::__DummyTrace
#else
inline void __DummyTrace(LPTSTR, ...) { }
#define DBX_PRINT 1 ? (void)0 : ::__DummyTrace
#endif

//
// The sample snap-in only has 1 property type and it's the workstation name
//

//
// Extracts the coclass guid format from the data object
//
template <class TYPE>
TYPE* Extract(LPDATAOBJECT lpDataObject, unsigned int cf)
{
ASSERT(lpDataObject != NULL);

TYPE* p = NULL;

STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL };
FORMATETC formatetc = { cf, NULL,
DVASPECT_CONTENT, -1, TYMED_HGLOBAL
};

// Allocate memory for the stream
int len = (cf == CDataObject::m_cfWorkstation) ?
((MAX_COMPUTERNAME_LENGTH+1) * sizeof(TYPE)) : sizeof(TYPE);

stgmedium.hGlobal = GlobalAlloc(GMEM_SHARE, len);

// Get the workstation name from the data object
do
{
if (stgmedium.hGlobal == NULL)
break;

if (FAILED(lpDataObject->GetDataHere(&formatetc, &stgmedium)))
break;

p = reinterpret_cast<TYPE*>(stgmedium.hGlobal);

if (p == NULL)
break;

} while (FALSE);

return p;
}

BOOL IsMMCMultiSelectDataObject(IDataObject* pDataObject)
{
if (pDataObject == NULL)
return FALSE;

static UINT s_cf = 0;
if (s_cf == 0)
{
USES_CONVERSION;
s_cf = RegisterClipboardFormat(W2T(CCF_MMC_MULTISELECT_DATAOBJECT));
}

FORMATETC fmt = {s_cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};

return (pDataObject->QueryGetData(&fmt) == S_OK);
}

// Data object extraction helpers
CLSID* ExtractClassID(LPDATAOBJECT lpDataObject)
{
return Extract<CLSID>(lpDataObject, CDataObject::m_cfCoClass);
}

GUID* ExtractNodeType(LPDATAOBJECT lpDataObject)
{
return Extract<GUID>(lpDataObject, CDataObject::m_cfNodeType);
}

wchar_t* ExtractWorkstation(LPDATAOBJECT lpDataObject)
{
return Extract<wchar_t>(lpDataObject, CDataObject::m_cfWorkstation);
}

INTERNAL* ExtractInternalFormat(LPDATAOBJECT lpDataObject)
{
return Extract<INTERNAL>(lpDataObject, CDataObject::m_cfInternal);
}


HRESULT _QueryDataObject(long cookie, DATA_OBJECT_TYPES type,
CComponentDataImpl* pImpl, LPDATAOBJECT* ppDataObject)
{
ASSERT(ppDataObject != NULL);
ASSERT(pImpl != NULL);

CComObject<CDataObject>* pObject;

CComObject<CDataObject>::CreateInstance(&pObject);
ASSERT(pObject != NULL);

// Save cookie and type for delayed rendering
pObject->SetType(type);
pObject->SetCookie(cookie);

#ifdef _DEBUG
pObject->SetComponentData(pImpl);
#endif

// Store the coclass with the data object
pObject->SetClsid(pImpl->GetCoClassID());

return pObject->QueryInterface(IID_IDataObject,
reinterpret_cast<void**>(ppDataObject));
}

DWORD GetItemType(long cookie)
{
// folder = CFoder* is cookie
// result = RESULT_DATA* is the cookie

return (*reinterpret_cast<DWORD*>(cookie));
}

/////////////////////////////////////////////////////////////////////////////
// Return TRUE if we are enumerating our main folder

BOOL CSnapin::IsEnumerating(LPDATAOBJECT lpDataObject)
{
BOOL bResult = FALSE;

ASSERT(lpDataObject);
GUID* nodeType = ExtractNodeType(lpDataObject);

// Is this my main node (static folder node type)
if (::IsEqualGUID(*nodeType, cNodeTypeStatic) == TRUE)
bResult = TRUE;

// Free resources
::GlobalFree(reinterpret_cast<HANDLE>(nodeType));

return bResult;
}


/////////////////////////////////////////////////////////////////////////////
// CSnapin's IComponent implementation

STDMETHODIMP CSnapin::GetResultViewType(long cookie, LPOLESTR* ppViewType, long* pViewOptions)
{

// guid for custom view
static WCHAR* szCalendarGUID = L"{8E27C92B-1264-101C-8A2F-040224009C02}";
static WCHAR* szMicrosoftURL = L"www.microsoft.com";

*pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT;

// if list view
if (m_CustomViewID == VIEW_DEFAULT_LV)
{
m_bVirtualView = FALSE;

// if static folder not selected
if (cookie != NULL)
{
// See if virtual data folder is selected
CFolder* pFolder = reinterpret_cast<CFolder*>(cookie);
ASSERT(pFolder->itemType == SCOPE_ITEM);
FOLDER_TYPES ftype = pFolder->GetType();

m_bVirtualView = (ftype == VIRTUAL || ftype == EXT_VIRTUAL);

if (m_bVirtualView)
*pViewOptions |= MMC_VIEW_OPTIONS_OWNERDATALIST;
}

return S_FALSE;
}

WCHAR* pszView = (m_CustomViewID == VIEW_CALENDAR_OCX) ? szCalendarGUID :
szMicrosoftURL;
UINT uiByteLen = (wcslen(pszView) + 1) * sizeof(WCHAR);
LPOLESTR psz = (LPOLESTR)::CoTaskMemAlloc(uiByteLen);

USES_CONVERSION;

if (psz != NULL)
{
wcscpy(psz, pszView);
*ppViewType = psz;
return S_OK;
}

return S_FALSE;
}

STDMETHODIMP CSnapin::Initialize(LPCONSOLE lpConsole)
{
DBX_PRINT(_T(" ---------- CSnapin::Initialize<0x08x>\n"), this);
ASSERT(lpConsole != NULL);
m_bInitializedC = true;

AFX_MANAGE_STATE(AfxGetStaticModuleState());

// Save the IConsole pointer
m_pConsole = lpConsole;
m_pConsole->AddRef();

// Load resource strings
LoadResources();

// QI for a IHeaderCtrl
HRESULT hr = m_pConsole->QueryInterface(IID_IHeaderCtrl,
reinterpret_cast<void**>(&m_pHeader));

// Give the console the header control interface pointer
if (SUCCEEDED(hr))
m_pConsole->SetHeader(m_pHeader);

m_pConsole->QueryInterface(IID_IResultData,
reinterpret_cast<void**>(&m_pResult));

hr = m_pConsole->QueryResultImageList(&m_pImageResult);
ASSERT(hr == S_OK);

hr = m_pConsole->QueryConsoleVerb(&m_pConsoleVerb);
ASSERT(hr == S_OK);

return S_OK;
}

STDMETHODIMP CSnapin::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, long arg, long param)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

if (IS_SPECIAL_DATAOBJECT(lpDataObject))
{
if (event == MMCN_BTN_CLICK)
{
if (m_CustomViewID != VIEW_DEFAULT_LV)
{
switch (param)
{
case MMC_VERB_REFRESH:
::AfxMessageBox(_T("MMCN_BTN_CLICK::MMC_VERB_REFRESH"));
_OnRefresh(lpDataObject);
break;

case MMC_VERB_PROPERTIES:
::AfxMessageBox(_T("MMCN_BTN_CLICK::MMC_VERB_PROPERTIES"));
break;

default:
::AfxMessageBox(_T("MMCN_BTN_CLICK::param unknown"));
break;
}
}
}
else
{
switch (event)
{
case MMCN_REFRESH:
::AfxMessageBox(_T("MMCN_BTN_CLICK::MMCN_REFRESH"));
_OnRefresh(lpDataObject);
break;
}
}

return S_OK;
}

HRESULT hr = S_OK;
long cookie;

if (event == MMCN_PROPERTY_CHANGE)
{
hr = OnPropertyChange(lpDataObject);
}
else if (event == MMCN_VIEW_CHANGE)
{
hr = OnUpdateView(lpDataObject);
}
else if (event == MMCN_DESELECT_ALL)
{
DBX_PRINT(_T("CSnapin::Notify -> MMCN_DESELECT_ALL \n"));
}
else if (event == MMCN_COLUMN_CLICK)
{
DBX_PRINT(_T("CSnapin::Notify -> MMCN_COLUMN_CLICK \n"));
}
else if (event == MMCN_SNAPINHELP)
{
AfxMessageBox(_T("CSnapin::Notify ->MMCN_SNAPINHELP"));
}
else
{
INTERNAL* pInternal = NULL;

if (IsMMCMultiSelectDataObject(lpDataObject) == FALSE)
{
pInternal = ExtractInternalFormat(lpDataObject);

if (pInternal == NULL)
{
ASSERT(FALSE);
return S_OK;
}

if (pInternal)
cookie = pInternal->m_cookie;
}

switch(event)
{
case MMCN_ACTIVATE:
break;

case MMCN_CLICK:
hr = OnResultItemClk(pInternal->m_type, cookie);
break;

case MMCN_DBLCLICK:
if (pInternal->m_type == CCT_RESULT)
Command(IDM_COMMAND1, lpDataObject);
else
hr = S_FALSE;

break;

case MMCN_ADD_IMAGES:
OnAddImages(cookie, arg, param);
break;

case MMCN_SHOW:
hr = OnShow(cookie, arg, param);
break;

case MMCN_MINIMIZED:
hr = OnMinimize(cookie, arg, param);
break;

case MMCN_INITOCX:
::MessageBox(NULL, _T("MMCN_INITOCX"), _T("TRACE"), MB_OK);
ASSERT(param != 0);
break;

case MMCN_DESELECT_ALL:
case MMCN_SELECT:
HandleStandardVerbs((event == MMCN_DESELECT_ALL),
arg, lpDataObject);
break;

case MMCN_PASTE:
AfxMessageBox(_T("CSnapin::MMCN_PASTE"));
break;

case MMCN_DELETE:
AfxMessageBox(_T("CSnapin::MMCN_DELETE"));
break;

case MMCN_CONTEXTHELP:
hr = OnContextHelp(lpDataObject);
break;

case MMCN_REFRESH:
AfxMessageBox(_T("CSnapin::MMCN_REFRESH"));
_OnRefresh(lpDataObject);
break;

case MMCN_RENAME:
ODS(_T("\n\n\t\tCSnapin::MMCN_RENAME\n\n"));
break;

// Note - Future expansion of notify types possible
default:
hr = E_UNEXPECTED;
break;
}

if (pInternal != NULL)
{
::GlobalFree(reinterpret_cast<HANDLE>(pInternal));
}
}

if (m_pResult)
m_pResult->SetDescBarText(L"hello world");

return hr;
}

void CSnapin::_OnRefresh(LPDATAOBJECT pDataObject)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
INTERNAL* pInternal = ExtractInternalFormat(pDataObject);
if (pInternal == NULL)
return;

if (pInternal->m_type == CCT_SCOPE)
{
CComponentDataImpl* pData = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
CFolder* pFolder = pData->FindObject(pInternal->m_cookie);
::AfxMessageBox(pInternal->m_cookie ? pFolder->m_pszName : _T("Files"));
}
else
{
RESULT_DATA* pData = reinterpret_cast<RESULT_DATA*>(pInternal->m_cookie);
::AfxMessageBox(pData->szName);
}
}

HRESULT CSnapin::OnContextHelp(LPDATAOBJECT pdtobj)
{
TCHAR name[128];
GetItemName(pdtobj, name);

TCHAR buf[200];
wsprintf(buf, _T("Context help requested for item: %s"), name);
::MessageBox(NULL, buf, _T("TRACE"), MB_OK);

return S_OK;
}


STDMETHODIMP CSnapin::Destroy(long cookie)
{
DBX_PRINT(_T(" ---------- CSnapin::Destroy<0x08x>\n"), this);
ASSERT(m_bInitializedC);
m_bDestroyedC = true;

AFX_MANAGE_STATE(AfxGetStaticModuleState());

// Release the interfaces that we QI'ed
if (m_pConsole != NULL)
{
// Tell the console to release the header control interface
m_pConsole->SetHeader(NULL);
SAFE_RELEASE(m_pHeader);

SAFE_RELEASE(m_pResult);
SAFE_RELEASE(m_pImageResult);

// Release the IConsole interface last
SAFE_RELEASE(m_pConsole);
SAFE_RELEASE(m_pComponentData); // QI'ed in IComponentDataImpl::CreateComponent

SAFE_RELEASE(m_pConsoleVerb);
}

return S_OK;
}

typedef CArray<GUID, const GUID&> CGUIDArray;

void GuidArray_Add(CGUIDArray& rgGuids, const GUID& guid)
{
for (int i=rgGuids.GetUpperBound(); i >= 0; --i)
{
if (rgGuids[i] == guid)
break;
}

if (i < 0)
rgGuids.Add(guid);
}

HRESULT CSnapin::QueryMultiSelectDataObject(long cookie, DATA_OBJECT_TYPES type,
LPDATAOBJECT* ppDataObject)
{
ASSERT(ppDataObject != NULL);
if (ppDataObject == NULL)
return E_POINTER;

CGUIDArray rgGuids;

if (m_bVirtualView == TRUE)
{
GuidArray_Add(rgGuids, cNodeTypeCompany);
}
else
{
// Determine the items selected
ASSERT(m_pResult != NULL);
RESULTDATAITEM rdi;
ZeroMemory(&rdi, sizeof(rdi));
rdi.mask = RDI_STATE;
rdi.nIndex = -1;
rdi.nState = TVIS_SELECTED;

while (m_pResult->GetNextItem(&rdi) == S_OK)
{
FOLDER_TYPES fType;
DWORD* pdw = reinterpret_cast<DWORD*>(rdi.lParam);


if (*pdw == SCOPE_ITEM)
{
CFolder* pFolder = reinterpret_cast<CFolder*>(rdi.lParam);
fType = pFolder->m_type;
}
else
{
ASSERT(*pdw == RESULT_ITEM);
RESULT_DATA* pData = reinterpret_cast<RESULT_DATA*>(rdi.lParam);
fType = pData->parentType;
}

const GUID* pguid;
switch (fType)
{
case STATIC:
pguid = &cNodeTypeStatic;
break;

case COMPANY:
pguid = &cNodeTypeCompany;
break;

case USER:
pguid = &cNodeTypeUser;
break;

case EXT_COMPANY:
pguid = &cNodeTypeExtCompany;
break;

case EXT_USER:
pguid = &cNodeTypeExtUser;
break;

case VIRTUAL:
case EXT_VIRTUAL:
pguid = &cNodeTypeVirtual;
break;

default:
return E_FAIL;
}

GuidArray_Add(rgGuids, *pguid);
}
}

CComObject<CDataObject>* pObject;
CComObject<CDataObject>::CreateInstance(&pObject);
ASSERT(pObject != NULL);

// Save cookie and type for delayed rendering
pObject->SetType(type);
pObject->SetCookie(cookie);
pObject->SetMultiSelDobj();

CComponentDataImpl* pImpl = dynamic_cast<CComponentDataImpl*>(m_pComponentData);

#ifdef _DEBUG
pObject->SetComponentData(pImpl);
#endif

// Store the coclass with the data object
pObject->SetClsid(pImpl->GetCoClassID());
UINT cb = rgGuids.GetSize() * sizeof(GUID);
GUID* pGuid = new GUID[rgGuids.GetSize()];
CopyMemory(pGuid, rgGuids.GetData(), cb);
pObject->SetMultiSelData((BYTE*)pGuid, cb);

return pObject->QueryInterface(IID_IDataObject,
reinterpret_cast<void**>(ppDataObject));
return S_OK;
}

STDMETHODIMP CSnapin::QueryDataObject(long cookie, DATA_OBJECT_TYPES type,
LPDATAOBJECT* ppDataObject)
{
if (cookie == MMC_MULTI_SELECT_COOKIE)
return QueryMultiSelectDataObject(cookie, type, ppDataObject);

ASSERT(type == CCT_RESULT);

#ifdef _DEBUG
if (cookie != MMC_MULTI_SELECT_COOKIE &&
m_bVirtualView == FALSE)
{
DWORD dwItemType = GetItemType(cookie);
ASSERT(dwItemType == RESULT_ITEM);
}
#endif

// Delegate it to the IComponentData
ASSERT(m_pComponentData != NULL);
CComponentDataImpl* pImpl = dynamic_cast<CComponentDataImpl*>(m_pComponentData);
ASSERT(pImpl != NULL);
return _QueryDataObject(cookie, type, pImpl, ppDataObject);
}

/////////////////////////////////////////////////////////////////////////////
// CSnapin's implementation specific members

DEBUG_DECLARE_INSTANCE_COUNTER(CSnapin);

CSnapin::CSnapin()
: m_bIsDirty(TRUE), m_bInitializedC(false), m_bDestroyedC(false)
{
DEBUG_INCREMENT_INSTANCE_COUNTER(CSnapin);
Construct();
}

CSnapin::~CSnapin()
{
#if DBG==1
ASSERT(dbg_cRef == 0);
#endif

DEBUG_DECREMENT_INSTANCE_COUNTER(CSnapin);

SAFE_RELEASE(m_pToolbar1);
SAFE_RELEASE(m_pToolbar2);

SAFE_RELEASE(m_pMenuButton1);

SAFE_RELEASE(m_pControlbar);

// Make sure the interfaces have been released
ASSERT(m_pConsole == NULL);
ASSERT(m_pHeader == NULL);
ASSERT(m_pToolbar1 == NULL);
ASSERT(m_pToolbar2 == NULL);


delete m_pbmpToolbar1;
delete m_pbmpToolbar2;

ASSERT(!m_bInitializedC || m_bDestroyedC);

Construct();
}

void CSnapin::Construct()
{
#if DBG==1
dbg_cRef = 0;
#endif

m_pConsole = NULL;
m_pHeader = NULL;

m_pResult = NULL;
m_pImageResult = NULL;
m_pComponentData = NULL;
m_pToolbar1 = NULL;
m_pToolbar2 = NULL;
m_pControlbar = NULL;

m_pMenuButton1 = NULL;

m_pbmpToolbar1 = NULL;
m_pbmpToolbar2 = NULL;

m_pConsoleVerb = NULL;

m_CustomViewID = VIEW_DEFAULT_LV;
m_bVirtualView = FALSE;
m_dwVirtualSortOptions = 0;
}

void CSnapin::LoadResources()
{
// Load strings from resources
m_column1.LoadString(IDS_NAME);
m_column2.LoadString(IDS_SIZE);
m_column3.LoadString(IDS_TYPE);
}

HRESULT CSnapin::InitializeHeaders(long cookie)
{
HRESULT hr = S_OK;

ASSERT(m_pHeader);

USES_CONVERSION;

// Put the correct headers depending on the cookie
// Note - cookie ignored for this sample
m_pHeader->InsertColumn(0, T2COLE(m_column1), LVCFMT_LEFT, 180); // Name
m_pHeader->InsertColumn(1, T2COLE(m_column2), LVCFMT_RIGHT, 90); // Size
m_pHeader->InsertColumn(2, T2COLE(m_column3), LVCFMT_LEFT, 160); // Type

return hr;
}

HRESULT CSnapin::InitializeBitmaps(long cookie)
{
ASSERT(m_pImageResult != NULL);

::CBitmap bmp16x16;
::CBitmap bmp32x32;

// Load the bitmaps from the dll
bmp16x16.LoadBitmap(IDB_16x16);
bmp32x32.LoadBitmap(IDB_32x32);

// Set the images
m_pImageResult->ImageListSetStrip(reinterpret_cast<long*>(static_cast<HBITMAP>(bmp16x16)),
reinterpret_cast<long*>(static_cast<HBITMAP>(bmp32x32)),
0, RGB(255, 0, 255));

return S_OK;
}

WCHAR* StringFromFolderType(FOLDER_TYPES type)
{
static WCHAR* s_szStatic = L"Static";
static WCHAR* s_szCompany = L"Company";
static WCHAR* s_szUser = L"User";
static WCHAR* s_szVirtual = L"Virtual";
static WCHAR* s_szUnknown = L"Unknown";

switch (type)
{
case STATIC: return s_szStatic;
case COMPANY: return s_szCompany;
case USER: return s_szUser;
case VIRTUAL: return s_szVirtual;
default: return s_szUnknown;
}
}

STDMETHODIMP CSnapin::GetDisplayInfo(LPRESULTDATAITEM pResult)
{
static WCHAR* s_szSize = L"200";

ASSERT(pResult != NULL);

if (pResult)
{
if (pResult->bScopeItem == TRUE)
{
CFolder* pFolder = reinterpret_cast<CFolder*>(pResult->lParam);
if (pResult->mask & RDI_STR)
{
if (pResult->nCol == 0)
pResult->str = pFolder->m_pszName;
else if (pResult->nCol == 1)
pResult->str = (LPOLESTR)s_szSize;
else
pResult->str = (LPOLESTR)StringFromFolderType(pFolder->m_type);

ASSERT(pResult->str != NULL);

if (pResult->str == NULL)
pResult->str = (LPOLESTR)L"";
}
}
else
{
RESULT_DATA* pData;

// if virtual, derive result item from index
// else lParam is the item pointer
if (m_bVirtualView)
pData = GetVirtualResultItem(pResult->nIndex);
else
pData= reinterpret_cast<RESULT_DATA*>(pResult->lParam);

if (pResult->mask & RDI_STR)
{
if (pResult->nCol == 0)
pResult->str = (LPOLESTR)pData->szName;
else if(pResult->nCol == 1)
pResult->str = (LPOLESTR)pData->szSize;
else
pResult->str = (LPOLESTR)pData->szType;

ASSERT(pResult->str != NULL);

if (pResult->str == NULL)
pResult->str = (LPOLESTR)L"";
}

// MMC can request image and indent for virtual data
if (pResult->mask & RDI_IMAGE)
pResult->nImage = 4;
}
}

return S_OK;
}


/////////////////////////////////////////////////////////////////////////////
// IExtendContextMenu Implementation


// Array of menu item commands to be inserted into the contest menu.
// Note - the first item is the menu text, // CCM_SPECIAL_DEFAULT_ITEM
// the second item is the status string
static CONTEXTMENUITEM menuItems[] =
{
{
L"Command 1", L"Sample extension menu added by snapin (Command 1)",
IDM_COMMAND1, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, 0
},
{
L"Command 2", L"Sample extension menu added by snapin (Command 2)",
IDM_COMMAND2, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, 0
},
{ NULL, NULL, 0, 0, 0 }
};

// Array of view items to be inserted into the context menu.
static CONTEXTMENUITEM viewItems[] =
{
{
L"Calendar", L"Sample OCX custom view",
IDM_SAMPLE_OCX_VIEW, CCM_INSERTIONPOINTID_PRIMARY_VIEW, 0, 0
},
{
L"Microsoft", L"Sample WEB custom view",
IDM_SAMPLE_WEB_VIEW, CCM_INSERTIONPOINTID_PRIMARY_VIEW, 0, 0
},
{ NULL, NULL, 0, 0, 0 },
};

// guid for custom view
static GUID CLSID_SmGraphControl =
{0xC4D2D8E0L,0xD1DD,0x11CE,0x94,0x0F,0x00,0x80,0x29,0x00,0x43,0x47};

STDMETHODIMP CSnapin::AddMenuItems(LPDATAOBJECT pDataObject,
LPCONTEXTMENUCALLBACK pContextMenuCallback,
long *pInsertionAllowed)
{
viewItems[0].fFlags = (m_CustomViewID == VIEW_CALENDAR_OCX) ? MF_CHECKED : 0;
viewItems[1].fFlags = (m_CustomViewID == VIEW_MICROSOFT_URL) ? MF_CHECKED : 0;

return dynamic_cast<CComponentDataImpl*>(m_pComponentData)->
AddMenuItems(pDataObject, pContextMenuCallback, pInsertionAllowed);
}


STDMETHODIMP CSnapin::Command(long nCommandID, LPDATAOBJECT pDataObject)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
INTERNAL* pInternal = ExtractInternalFormat(pDataObject);
if (pInternal == NULL)
return E_FAIL;

if (pInternal->m_type == CCT_SCOPE)
{
// Handle view specific commands here
switch (nCommandID)
{
case IDM_SAMPLE_WEB_VIEW:
case IDM_SAMPLE_OCX_VIEW:
m_CustomViewID = (nCommandID == IDM_SAMPLE_OCX_VIEW) ?
VIEW_CALENDAR_OCX : VIEW_MICROSOFT_URL;

// Ask console to reslelect the node to force a new view
if (pInternal->m_cookie == 0)
{
CComponentDataImpl* pCCDI =
dynamic_cast<CComponentDataImpl*>(m_pComponentData);

ASSERT(pCCDI != NULL);

m_pConsole->SelectScopeItem(pCCDI->m_pStaticRoot);
}
else
{
CFolder* pFolder = reinterpret_cast<CFolder*>(pInternal->m_cookie);
m_pConsole->SelectScopeItem(pFolder->m_pScopeItem->ID);
}
break;

case MMCC_STANDARD_VIEW_SELECT:
m_CustomViewID = VIEW_DEFAULT_LV;
break;

default:
// Pass non-view specific commands to ComponentData
return dynamic_cast<CComponentDataImpl*>(m_pComponentData)->
Command(nCommandID, pDataObject);
}
}
else if (pInternal->m_type == CCT_RESULT)
{

// Handle each of the commands.
switch (nCommandID)
{
case IDM_COMMAND1:
case IDM_COMMAND2:
{
m_pResult->ModifyViewStyle(MMC_SINGLESEL, (MMC_RESULT_VIEW_STYLE)0);

RESULTDATAITEM rdi;
ZeroMemory(&rdi, sizeof(rdi));

rdi.mask = RDI_STATE;
rdi.nState = LVIS_SELECTED;
rdi.nIndex = -1;
m_pResult->GetNextItem(&rdi);

int iSel = rdi.nIndex;

RESULT_DATA* pData;

// if virtual view, derive result item from the index
if (m_bVirtualView)
{
pData = GetVirtualResultItem(iSel);
}
// else get the cookie (which is result item ptr)
else

{ 
ZeroMemory(&rdi, sizeof(rdi));
rdi.mask = RDI_PARAM;
rdi.nIndex = iSel;
HRESULT hr = m_pResult->GetItem(&rdi);
ASSERT(SUCCEEDED(hr));
ASSERT(rdi.lParam != 0);

pData = reinterpret_cast<RESULT_DATA*>(rdi.lParam);
}

CString strBuf = (nCommandID == IDM_COMMAND1) ?
_T("\t Command 1 executed.\n\n") : _T("\t Command 2 executed.\n\n");

strBuf += pData->szName;
strBuf += _T(" is the currently selected item.");

AfxMessageBox(strBuf);

// change image in list
if (!m_bVirtualView)
{
ZeroMemory(&rdi, sizeof(rdi));
rdi.mask = RDI_IMAGE;
rdi.nIndex = iSel;
rdi.nImage = 3;
HRESULT hr = m_pResult->SetItem(&rdi);
ASSERT(SUCCEEDED(hr));
}
}
break;

default:
ASSERT(FALSE); // Unknown command!
break;
}
}
else
{
ASSERT(0);
}

::GlobalFree(reinterpret_cast<HANDLE>(pInternal));

return S_OK;
}

STDMETHODIMP CSnapin::GetClassID(CLSID *pClassID)
{
ASSERT(pClassID != NULL);

// Copy the CLSID for this snapin
*pClassID = CLSID_Snapin;

return E_NOTIMPL;
}

STDMETHODIMP CSnapin::IsDirty()
{
// Always save / Always dirty.
return ThisIsDirty() ? S_OK : S_FALSE;
}

STDMETHODIMP CSnapin::Load(IStream *pStm)
{
DBX_PRINT(_T(" ---------- CSnapin::Load<0x08x>\n"), this);
ASSERT(m_bInitializedC);

ASSERT(pStm);
// Read the string
char psz[10];
ULONG nBytesRead;
HRESULT hr = pStm->Read(psz, 10, &nBytesRead);

// Verify that the read succeeded
ASSERT(SUCCEEDED(hr) && nBytesRead == 10);

// check to see if the string is the correct string
ASSERT(strcmp("987654321", psz) == 0);

ClearDirty();

return SUCCEEDED(hr) ? S_OK : E_FAIL;
}

STDMETHODIMP CSnapin::Save(IStream *pStm, BOOL fClearDirty)
{
DBX_PRINT(_T(" ---------- CSnapin::Save<0x08x>\n"), this);
ASSERT(m_bInitializedC);

ASSERT(pStm);

// Write the string
ULONG nBytesWritten;
HRESULT hr = pStm->Write("987654321", 10, &nBytesWritten);

// Verify that the write operation succeeded
ASSERT(SUCCEEDED(hr) && nBytesWritten == 10);
if (FAILED(hr))
return STG_E_CANTSAVE;

if (fClearDirty)
ClearDirty();
return S_OK;
}

STDMETHODIMP CSnapin::GetSizeMax(ULARGE_INTEGER *pcbSize)
{
ASSERT(pcbSize);

// Set the size of the string to be saved
ULISet32(*pcbSize, 10);

return S_OK;
}

///////////////////////////////////////////////////////////////////////////////
// IComponentData implementation

DEBUG_DECLARE_INSTANCE_COUNTER(CComponentDataImpl);

CComponentDataImpl::CComponentDataImpl()
: m_bIsDirty(TRUE), m_pScope(NULL), m_pConsole(NULL),
m_bInitializedCD(false), m_bDestroyedCD(false)
{
DEBUG_INCREMENT_INSTANCE_COUNTER(CComponentDataImpl);

#ifdef _DEBUG
m_cDataObjects = 0;
#endif
}

CComponentDataImpl::~CComponentDataImpl()
{
DEBUG_DECREMENT_INSTANCE_COUNTER(CComponentDataImpl);

ASSERT(m_pScope == NULL);

ASSERT(!m_bInitializedCD || m_bDestroyedCD);

// Some snap-in is hanging on to data objects.
// If they access, it will crash!!!
ASSERT(m_cDataObjects <= 1);
}

STDMETHODIMP CComponentDataImpl::Initialize(LPUNKNOWN pUnknown)
{
DBX_PRINT(_T(" ---------- CComponentDataImpl::Initialize<0x08x>\n"), this);
m_bInitializedCD = true;

ASSERT(pUnknown != NULL);
HRESULT hr;

AFX_MANAGE_STATE(AfxGetStaticModuleState());

// MMC should only call ::Initialize once!
ASSERT(m_pScope == NULL);
pUnknown->QueryInterface(IID_IConsoleNameSpace,
reinterpret_cast<void**>(&m_pScope));

// add the images for the scope tree
::CBitmap bmp16x16;
LPIMAGELIST lpScopeImage;

hr = pUnknown->QueryInterface(IID_IConsole, reinterpret_cast<void**>(&m_pConsole));
ASSERT(hr == S_OK);

hr = m_pConsole->QueryScopeImageList(&lpScopeImage);

ASSERT(hr == S_OK);

// Load the bitmaps from the dll
bmp16x16.LoadBitmap(IDB_16x16);

// Set the images
lpScopeImage->ImageListSetStrip(reinterpret_cast<long*>(static_cast<HBITMAP>(bmp16x16)),
reinterpret_cast<long*>(static_cast<HBITMAP>(bmp16x16)),
0, RGB(255, 0, 255));

lpScopeImage->Release();

return S_OK;
}

STDMETHODIMP CComponentDataImpl::CreateComponent(LPCOMPONENT* ppComponent)
{
ASSERT(ppComponent != NULL);

CComObject<CSnapin>* pObject;
CComObject<CSnapin>::CreateInstance(&pObject);
ASSERT(pObject != NULL);

// Store IComponentData
pObject->SetIComponentData(this);

return pObject->QueryInterface(IID_IComponent,
reinterpret_cast<void**>(ppComponent));
}

STDMETHODIMP CComponentDataImpl::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, long arg, long param)
{
ASSERT(m_pScope != NULL);
HRESULT hr;

// Since it's my folder it has an internal format.
// Design Note: for extension. I can use the fact, that the data object doesn't have
// my internal format and I should look at the node type and see how to extend it.
if (event == MMCN_PROPERTY_CHANGE)
{
hr = OnProperties(param);
}
else
{

INTERNAL* pInternal = ExtractInternalFormat(lpDataObject);

if (pInternal == NULL)
{
return S_OK;
}

long cookie = pInternal->m_cookie;
::GlobalFree(reinterpret_cast<HANDLE>(pInternal));

switch(event)
{
case MMCN_PASTE:
AfxMessageBox(_T("CSnapin::MMCN_PASTE"));
break;

case MMCN_DELETE:
hr = OnDelete(cookie);
break;

case MMCN_REMOVE_CHILDREN:
hr = OnRemoveChildren(arg);
break;

case MMCN_RENAME:
hr = OnRename(cookie, arg, param);
break;

case MMCN_EXPAND:
hr = OnExpand(lpDataObject, arg, param);
break;

default:
break;
}

}

return hr;
}

STDMETHODIMP CComponentDataImpl::Destroy()
{
DBX_PRINT(_T(" ---------- CComponentDataImpl::Destroy<0x08x>\n"), this);
ASSERT(m_bInitializedCD);
m_bDestroyedCD = true;

// Delete enumerated scope items
DeleteList();

SAFE_RELEASE(m_pScope);
SAFE_RELEASE(m_pConsole);

return S_OK;
}

STDMETHODIMP CComponentDataImpl::QueryDataObject(long cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject)
{
#ifdef _DEBUG
if (cookie == 0)
{
ASSERT(type != CCT_RESULT);
}
else
{
ASSERT(type == CCT_SCOPE);

DWORD dwItemType = GetItemType(cookie);
ASSERT(dwItemType == SCOPE_ITEM);
}
#endif

return _QueryDataObject(cookie, type, this, ppDataObject);
}

///////////////////////////////////////////////////////////////////////////////
//// IPersistStream interface members

STDMETHODIMP CComponentDataImpl::GetClassID(CLSID *pClassID)
{
ASSERT(pClassID != NULL);

// Copy the CLSID for this snapin
*pClassID = CLSID_Snapin;

return E_NOTIMPL;
}

STDMETHODIMP CComponentDataImpl::IsDirty()
{
// Always save / Always dirty.
return ThisIsDirty() ? S_OK : S_FALSE;
}

STDMETHODIMP CComponentDataImpl::Load(IStream *pStm)
{
DBX_PRINT(_T(" ---------- CComponentDataImpl::Load<0x08x>\n"), this);

ASSERT(pStm);
ASSERT(m_bInitializedCD);

// Read the string
char psz[10];
ULONG nBytesRead;
HRESULT hr = pStm->Read(psz, 10, &nBytesRead);

// Verify that the read succeeded
ASSERT(SUCCEEDED(hr) && nBytesRead == 10);

// check to see if the string is the correct string
ASSERT(strcmp("123456789", psz) == 0);

ClearDirty();

return SUCCEEDED(hr) ? S_OK : E_FAIL;
}

STDMETHODIMP CComponentDataImpl::Save(IStream *pStm, BOOL fClearDirty)
{
DBX_PRINT(_T(" ---------- CComponentDataImpl::Save<0x08x>\n"), this);

ASSERT(pStm);
ASSERT(m_bInitializedCD);

// Write the string
ULONG nBytesWritten;
HRESULT hr = pStm->Write("123456789", 10, &nBytesWritten);

// Verify that the write operation succeeded
ASSERT(SUCCEEDED(hr) && nBytesWritten == 10);
if (FAILED(hr))
return STG_E_CANTSAVE;

if (fClearDirty)
ClearDirty();
return S_OK;
}

STDMETHODIMP CComponentDataImpl::GetSizeMax(ULARGE_INTEGER *pcbSize)
{
ASSERT(pcbSize);

// Set the size of the string to be saved
ULISet32(*pcbSize, 10);

return S_OK;
}


///////////////////////////////////////////////////////////////////////////////
//// Notify handlers for IComponentData

HRESULT CComponentDataImpl::OnDelete(long cookie)
{
return S_OK;
}

HRESULT CComponentDataImpl::OnRemoveChildren(long arg)
{
return S_OK;
}

HRESULT CComponentDataImpl::OnRename(long cookie, long arg, long param)
{
if (arg == 0)
return S_OK;

LPOLESTR pszNewName = reinterpret_cast<LPOLESTR>(param);
if (pszNewName == NULL)
return E_INVALIDARG;

CFolder* pFolder = reinterpret_cast<CFolder*>(cookie);
ASSERT(pFolder != NULL);
if (pFolder == NULL)
return E_INVALIDARG;

pFolder->SetName(pszNewName);

return S_OK;
}

HRESULT CComponentDataImpl::OnExpand(LPDATAOBJECT lpDataObject, long arg, long param)
{
if (arg == TRUE)
{
// Did Initialize get called?
ASSERT(m_pScope != NULL);
EnumerateScopePane(lpDataObject, param);
}

return S_OK;
}

HRESULT CComponentDataImpl::OnSelect(long cookie, long arg, long param)
{
return E_UNEXPECTED;
}

HRESULT CComponentDataImpl::OnProperties(long param)
{
if (param == NULL)
{
return S_OK;
}

ASSERT(param != NULL);
CFolder* pFolder = new CFolder();

// Create a new folder object
pFolder->Create( reinterpret_cast<LPOLESTR>(param), 0, 0, STATIC, FALSE);

// The static folder in the last item in the list
POSITION pos = m_scopeItemList.GetTailPosition();
if (pos == 0)
{
// CreateFolderList();
pos = m_scopeItemList.GetTailPosition();
}

ASSERT(pos);

// Add it to the internal list
if (pos)
{
CFolder* pItem = m_scopeItemList.GetAt(pos);
m_scopeItemList.InsertBefore(pos, pFolder);

pFolder->m_pScopeItem->relativeID = pItem->m_pScopeItem->relativeID;

// Set the folder as the cookie
pFolder->m_pScopeItem->mask |= SDI_PARAM;
pFolder->m_pScopeItem->lParam = reinterpret_cast<LPARAM>(pFolder);
pFolder->SetCookie(reinterpret_cast<long>(pFolder));
m_pScope->InsertItem(pFolder->m_pScopeItem);
}

::GlobalFree(reinterpret_cast<void*>(param));

return S_OK;
}


void CComponentDataImpl::CreateFolderList(LPDATAOBJECT lpDataObject)
{
CFolder* pFolder;

ASSERT(lpDataObject != NULL);

wchar_t* pWkStation = ExtractWorkstation(lpDataObject);
ASSERT(pWkStation != NULL);

CLSID* pCoClassID = ExtractClassID(lpDataObject);
ASSERT(pCoClassID != NULL);

// Determine which folder set to use based on context information
FOLDER_DATA* pFolderSet = FolderData;
BOOL bExtend = FALSE;

if (!IsEqualCLSID(*pCoClassID, GetCoClassID()))
{
pFolderSet = ExtFolderData;
bExtend = TRUE;
TRACE(_T("Using Extension Data\n"));
}

ASSERT(m_scopeItemList.GetCount() == 0);
wchar_t buf[100];

for (int i=0; i < NUM_FOLDERS; i++)
{
pFolder = new CFolder();
buf[0] = NULL;

USES_CONVERSION;

wcscpy(buf, pFolderSet[i].szName);

// Add context info to the folder name
if (bExtend)
wcscat(buf, pWkStation);

// Create the folder objects with static data
pFolder->Create(buf, FOLDER_IMAGE_IDX, OPEN_FOLDER_IMAGE_IDX,
pFolderSet[i].type, FALSE);

m_scopeItemList.AddTail(pFolder);
}

// mark cookie for last item
pFolder->SetCookie(NULL);

// Free memory from data object extraction
::GlobalFree(reinterpret_cast<HGLOBAL>(pWkStation));
::GlobalFree(reinterpret_cast<HGLOBAL>(pCoClassID));
}

void CComponentDataImpl::EnumerateScopePane(LPDATAOBJECT lpDataObject, HSCOPEITEM pParent)
{
int i;

ASSERT(m_pScope != NULL); // make sure we QI'ed for the interface
ASSERT(lpDataObject != NULL);

INTERNAL* pInternal = ExtractInternalFormat(lpDataObject);

if (pInternal == NULL)
return ;

long cookie = pInternal->m_cookie;

// Only the static node has enumerated children
if (cookie != NULL)
return ;

::GlobalFree(reinterpret_cast<HANDLE>(pInternal));

// Initialize folder list if empty
if (m_scopeItemList.GetCount() == 0)
CreateFolderList(lpDataObject);

// Enumerate the scope pane
// return the folder object that represents the cookie
// Note - for large list, use dictionary
CFolder* pStatic = FindObject(cookie);

ASSERT(!pStatic->IsEnumerated());
// Note - Each cookie in the scope pane represents a folder.
// A released product may have more then one level of children.
// This sample assumes the parent node is one level deep.

ASSERT(pParent != NULL);

// Cache the HSCOPEITEM of the static root.
if (cookie == NULL)
m_pStaticRoot = pParent;

POSITION pos = m_scopeItemList.GetHeadPosition();
CFolder* pFolder;

for (i=0; (i < (NUM_FOLDERS - 1)) && (pos != NULL); i++)
{
pFolder = m_scopeItemList.GetNext(pos);
ASSERT(pFolder);

// Set the parent
pFolder->m_pScopeItem->relativeID = pParent;

// Set the folder as the cookie
pFolder->m_pScopeItem->mask |= SDI_PARAM;
pFolder->m_pScopeItem->lParam = reinterpret_cast<LPARAM>(pFolder);
pFolder->SetCookie(reinterpret_cast<long>(pFolder));
m_pScope->InsertItem(pFolder->m_pScopeItem);

// Note - On return, the ID member of 'm_pScopeItem'
// contains the handle to the newly inserted item!
ASSERT(pFolder->m_pScopeItem->ID != NULL);
}

// Last folder added is the static folder
pStatic->Set(TRUE); // folder has been enumerated
pStatic->m_pScopeItem->relativeID = pParent;
}

void CComponentDataImpl::DeleteList()
{
POSITION pos = m_scopeItemList.GetHeadPosition();

while (pos)
delete m_scopeItemList.GetNext(pos);
}

CFolder* CComponentDataImpl::FindObject(long cookie)
{
POSITION pos = m_scopeItemList.GetHeadPosition();
CFolder* pFolder = NULL;

while(pos)
{
pFolder = m_scopeItemList.GetNext(pos);

if (*pFolder == cookie)
return pFolder;
}

return NULL;
}

STDMETHODIMP CComponentDataImpl::GetDisplayInfo(SCOPEDATAITEM* pScopeDataItem)
{
ASSERT(pScopeDataItem != NULL);
if (pScopeDataItem == NULL)
return E_POINTER;

CFolder* pFolder = reinterpret_cast<CFolder*>(pScopeDataItem->lParam);

ASSERT(pScopeDataItem->mask & SDI_STR);
pScopeDataItem->displayname = pFolder->m_pszName;

//ASSERT(pScopeDataItem->displayname != NULL);

return S_OK;
}

STDMETHODIMP CComponentDataImpl::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB)
{
if (lpDataObjectA == NULL || lpDataObjectB == NULL)
return E_POINTER;

// Make sure both data object are mine
INTERNAL* pA;
INTERNAL* pB;
HRESULT hr = S_FALSE;

pA = ExtractInternalFormat(lpDataObjectA);
pB = ExtractInternalFormat(lpDataObjectA);

if (pA != NULL && pB != NULL)
hr = (*pA == *pB) ? S_OK : S_FALSE;

::GlobalFree(reinterpret_cast<HANDLE>(pA));
::GlobalFree(reinterpret_cast<HANDLE>(pB));

return hr;
}

/////////////////////////////////////////////////////////////////////////////
// IExtendPropertySheet2 Implementation

HRESULT CComponentDataImpl::DoInsertWizard(LPPROPERTYSHEETCALLBACK lpProvider)
{
CStartUpWizard* pWizard = new CStartUpWizard;
CStartupWizard1* pWizard1 = new CStartupWizard1;

MMCPropPageCallback(&pWizard->m_psp97);
MMCPropPageCallback(&pWizard1->m_psp97);

HPROPSHEETPAGE hPage = CreatePropertySheetPage(&pWizard->m_psp97);

if (hPage == NULL)
return E_UNEXPECTED;

lpProvider->AddPage(hPage);

hPage = CreatePropertySheetPage(&pWizard1->m_psp97);

if (hPage == NULL)
return E_UNEXPECTED;

lpProvider->AddPage(hPage);

return S_OK;
}

STDMETHODIMP CComponentDataImpl::GetWatermarks(HBITMAP* lphWatermark, HBITMAP* lphHeader,
HPALETTE* lphPalette, BOOL* pbStretch)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

*lphHeader = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BANNER));
*lphWatermark = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_WATERMARK));
*pbStretch = TRUE; // force the watermark bitmap to stretch

return S_OK;
}

STDMETHODIMP CComponentDataImpl::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider,
long handle,
LPDATAOBJECT lpIDataObject)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

// Look at the data object and determine if this an extension or a primary
ASSERT(lpIDataObject != NULL);


// Look at the data object and see if the snap-in manager is asking for pages
INTERNAL* pInternal= ExtractInternalFormat(lpIDataObject);

if (pInternal != NULL)
{
DATA_OBJECT_TYPES type = pInternal->m_type;
FREE_DATA(pInternal);

if (type == CCT_SNAPIN_MANAGER)
{
HRESULT hr = DoInsertWizard(lpProvider);
return hr;
}
}

CLSID* pCoClassID = ExtractClassID(lpIDataObject);

if(pCoClassID == NULL)
{
ASSERT(FALSE);
return E_UNEXPECTED;
}

CPropertyPage* pBasePage;

// Determine which
// Note: Should check the node type, but the sample only has 1
if (IsEqualCLSID(*pCoClassID, GetCoClassID()))
{
// Create the primary property page
CGeneralPage* pPage = new CGeneralPage();
pPage->m_hConsoleHandle = handle;
pBasePage = pPage;
}
else
{

// Create the extension property page
CExtensionPage* pPage = new CExtensionPage();
pBasePage = pPage;

wchar_t* pWkStation = ExtractWorkstation(lpIDataObject);

if (pWkStation == NULL)
{
ASSERT(FALSE);
return E_FAIL;
}

// Save the workstation name
pPage->m_szText = pWkStation;
FREE_DATA(pWkStation);

}

FREE_DATA(pCoClassID);

// Object gets deleted when the page is destroyed
ASSERT(lpProvider != NULL);

HRESULT hr = MMCPropPageCallback(&pBasePage->m_psp);

if (SUCCEEDED(hr))
{

HPROPSHEETPAGE hPage = CreatePropertySheetPage(&pBasePage->m_psp);

if (hPage == NULL)
return E_UNEXPECTED;

lpProvider->AddPage(hPage);
}

return hr;
}

STDMETHODIMP CComponentDataImpl::QueryPagesFor(LPDATAOBJECT lpDataObject)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

// Get the node type and see if it's one of mine

// if (nodetype == one of mine)
// do this
// else
// see which node type it is and answer the question

return S_OK;
}

BOOL CComponentDataImpl::IsScopePaneNode(LPDATAOBJECT lpDataObject)
{
BOOL bResult = FALSE;
INTERNAL* pInternal = ExtractInternalFormat(lpDataObject);

if (pInternal->m_cookie == NULL &&
(pInternal->m_type == CCT_SCOPE || pInternal->m_type == CCT_RESULT))
bResult = TRUE;

FREE_DATA(pInternal);

return bResult;
}

///////////////////////////////////////////////////////////////////////////////
// IExtendContextMenu implementation
//
STDMETHODIMP CComponentDataImpl::AddMenuItems(LPDATAOBJECT pDataObject,
LPCONTEXTMENUCALLBACK pContextMenuCallback,
long *pInsertionAllowed)
{
HRESULT hr = S_OK;

// Note - snap-ins need to look at the data object and determine
// in what context, menu items need to be added. They must also
// observe the insertion allowed flags to see what items can be
// added.

if (IsMMCMultiSelectDataObject(pDataObject) == TRUE)
return S_FALSE;

INTERNAL* pInternal = ExtractInternalFormat(pDataObject);
BOOL bCmd1IsDefault = (pInternal->m_type == CCT_RESULT);

if (bCmd1IsDefault)
menuItems[0].fSpecialFlags = CCM_SPECIAL_DEFAULT_ITEM;
else
menuItems[0].fSpecialFlags = 0;

// Loop through and add each of the menu items
if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP)
{
for (LPCONTEXTMENUITEM m = menuItems; m->strName; m++)
{
hr = pContextMenuCallback->AddItem(m);

if (FAILED(hr))
break;
}
}

// Loop through and add each of the view items
if (*pInsertionAllowed & CCM_INSERTIONALLOWED_VIEW)
{
for (LPCONTEXTMENUITEM m = viewItems; m->strName; m++)
{
hr = pContextMenuCallback->AddItem(m);

if (FAILED(hr))
break;
}
}

return hr;
}


STDMETHODIMP CComponentDataImpl::Command(long nCommandID, LPDATAOBJECT pDataObject)
{
// Note - snap-ins need to look at the data object and determine
// in what context the command is being called.

// Handle each of the commands.
switch (nCommandID)
{
case IDM_COMMAND1:
{
INTERNAL* pi = ExtractInternalFormat(pDataObject);
ASSERT(pi);
ASSERT(pi->m_type != CCT_RESULT);
CFolder* pFolder = reinterpret_cast<CFolder*>(pi->m_cookie);
if (pFolder)
m_pConsole->SelectScopeItem(pFolder->m_pScopeItem->ID);
break;
}
case IDM_COMMAND2:
ASSERT(m_pConsole);
m_pConsole->MessageBox(L"Snapin Menu Comand Selected",
menuItems[nCommandID].strName, MB_OK, NULL);
break;

default:
ASSERT(FALSE); // Unknown command!
break;
}

return S_OK;
}


///////////////////////////////////////////////////////////////////////////////
// IExtendControlbar implementation
//


STDMETHODIMP CSnapin::SetControlbar(LPCONTROLBAR pControlbar)
{
TRACE(_T("CSnapin::SetControlbar(%ld)\n"),pControlbar);

// Please don't delete this. Required to make sure we pick up the bitmap
AFX_MANAGE_STATE(AfxGetStaticModuleState());

if (pControlbar != NULL)
{

// Hold on to the controlbar interface.
if (m_pControlbar)
{
m_pControlbar->Release();
}

m_pControlbar = pControlbar;
m_pControlbar->AddRef();

HRESULT hr=S_FALSE;

if (!m_pMenuButton1)
{
hr = m_pControlbar->Create(MENUBUTTON, this,
reinterpret_cast<LPUNKNOWN*>(&m_pMenuButton1));
ASSERT(SUCCEEDED(hr));
}

if (m_pMenuButton1)
{
// Unlike toolbar buttons, menu buttons need to be added every time.
hr = m_pMenuButton1->AddButton(FOLDEREX_MENU, L"FolderEx", L"Extended Folder Menu");
ASSERT(SUCCEEDED(hr));
hr = m_pMenuButton1->AddButton(FILEEX_MENU, L"FileEx", L"Extended File Menu");
ASSERT(SUCCEEDED(hr));
}


// Create the Toolbar 1
if (!m_pToolbar1)
{
hr = m_pControlbar->Create(TOOLBAR, this, reinterpret_cast<LPUNKNOWN*>(&m_pToolbar1));
ASSERT(SUCCEEDED(hr));


// Add the bitmap
m_pbmpToolbar1 = new ::CBitmap;
m_pbmpToolbar1->LoadBitmap(IDB_TOOLBAR1);
hr = m_pToolbar1->AddBitmap(11, *m_pbmpToolbar1, 16, 16, RGB(255, 0, 255));
ASSERT(SUCCEEDED(hr));

// Add the buttons to the toolbar
hr = m_pToolbar1->AddButtons(ARRAYLEN(SnapinButtons), SnapinButtons);
ASSERT(SUCCEEDED(hr));

}


// TOOLBAR 2

// Create the Toolbar 2
if (!m_pToolbar2)
{
hr = m_pControlbar->Create(TOOLBAR, this, reinterpret_cast<LPUNKNOWN*>(&m_pToolbar2));
ASSERT(SUCCEEDED(hr));

// Add the bitmap
m_pbmpToolbar2 = new ::CBitmap;
m_pbmpToolbar2->LoadBitmap(IDB_TOOLBAR2);
hr = m_pToolbar2->AddBitmap(36, *m_pbmpToolbar2, 16, 16, RGB(192,192,192));
ASSERT(SUCCEEDED(hr));

// Add the buttons to the toolbar
hr = m_pToolbar2->AddButtons(ARRAYLEN(SnapinButtons2), SnapinButtons2);
ASSERT(SUCCEEDED(hr));

}


}
else
{
SAFE_RELEASE(m_pControlbar);
}


return S_OK;
}


void CSnapin::OnButtonClick(LPDATAOBJECT pdtobj, int idBtn)
{
TCHAR name[128];
GetItemName(pdtobj, name);

TCHAR buf[200];
wsprintf(buf, _T("Toolbar button<%d> was clicked. \nThe currently selected result item is <%s>"), idBtn, name);
::MessageBox(NULL, buf, _T("TRACE"), MB_OK);
}


STDMETHODIMP CSnapin::ControlbarNotify(MMC_NOTIFY_TYPE event, long arg, long param)
{
HRESULT hr=S_FALSE;

AFX_MANAGE_STATE(AfxGetStaticModuleState());

switch (event)
{
case MMCN_BTN_CLICK:
//TCHAR szMessage[MAX_PATH];
//wsprintf(szMessage, _T("CommandID %ld"),param);
//AfxMessageBox(szMessage);
OnButtonClick(reinterpret_cast<LPDATAOBJECT>(arg), param);
break;

case MMCN_DESELECT_ALL:
case MMCN_SELECT:
HandleExtToolbars((event == MMCN_DESELECT_ALL), arg, param);
break;

case MMCN_MENU_BTNCLICK:
HandleExtMenus(arg, param);
break;

default:
break;
}


return S_OK;
}

// This compares two data objects to see if they are the same object.
// return
// S_OK if equal otherwise S_FALSE
//
// Note: check to make sure both objects belong to the snap-in.
//

STDMETHODIMP CSnapin::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB)
{
return S_FALSE;
}


// This compare is used to sort the item's in the listview
//
// Parameters:
//
// lUserParam - user param passed in when IResultData::Sort() was called
// cookieA - first item to compare
// cookieB - second item to compare
// pnResult [in, out]- contains the col on entry,
// -1, 0, 1 based on comparison for return value.
//
// Note: Assum sort is ascending when comparing.


STDMETHODIMP CSnapin::Compare(long lUserParam, long cookieA, long cookieB, int* pnResult)
{
if (pnResult == NULL)
{
ASSERT(FALSE);
return E_POINTER;
}

// check col range
int nCol = *pnResult;
ASSERT(nCol >=0 && nCol< 3);

*pnResult = 0;

USES_CONVERSION;

LPTSTR szStringA;
LPTSTR szStringB;

RESULT_DATA* pDataA = reinterpret_cast<RESULT_DATA*>(cookieA);
RESULT_DATA* pDataB = reinterpret_cast<RESULT_DATA*>(cookieB);


ASSERT(pDataA != NULL && pDataB != NULL);

if (nCol == 0)
{
szStringA = OLE2T(pDataA->szName);
szStringB = OLE2T(pDataB->szName);
}
else if(nCol == 1)
{
szStringA = OLE2T(pDataA->szSize);
szStringB = OLE2T(pDataB->szSize);
}
else
{

szStringA = OLE2T(pDataA->szType); 
szStringB = OLE2T(pDataB->szType) ;
}

ASSERT(szStringA != NULL);
ASSERT(szStringB != NULL);

*pnResult = _tcscmp(szStringA, szStringB);


return S_OK;
}


///////////////////////////////////////////////////////////////////////////////
// IResultOwnerData implementation
//
STDMETHODIMP CSnapin::FindItem (LPRESULTFINDINFO pFindInfo, int* pnFoundIndex)
{
// find next item that matches the string (exact or partial)
// if matched found, set FoundIndex and return S_OK

// For the sample all items are named by their index number
// so we don't do a real string search. Also, to simplify the code
// the routine assumes a partial match search with wrap, which is what
// keyboard navigation calls use.
ASSERT((pFindInfo->dwOptions & (RFI_PARTIAL | RFI_WRAP)) == (RFI_PARTIAL | RFI_WRAP));

USES_CONVERSION;

TCHAR* lpszFind = OLE2T(pFindInfo->psz);

TRACE(_T("CSnapin::FindItem(\"%s\")"), lpszFind);

// convert search string to number
int nMatchVal = 0;
TCHAR* pch = lpszFind;
while (*pch >= _T('0') && *pch <= _T('9') && nMatchVal < NUM_VIRTUAL_ITEMS)
nMatchVal = nMatchVal * 10 + (*pch++ - _T('0'));

// if string has a non-decimal char or is too large, it won't match anything
if (*pch != 0 || nMatchVal >= NUM_VIRTUAL_ITEMS)
return S_FALSE;

// if ascending sequence
if (!(m_dwVirtualSortOptions & RSI_DESCENDING))
{
int nStartVal = pFindInfo->nStart;

// if match is less than start (but not zero), locate first value above start that matches
// otherwise the match number itself it the answer
if (nMatchVal < nStartVal && nMatchVal != 0)
{
// find scale factor to reach value >= start value
int nScale = 1;
while (nMatchVal * nScale < nStartVal)
nScale *= 10;

// check special case of start value beginning with the match digits
int nTestVal = (nStartVal * 10 - nMatchVal * nScale) < nScale ? nStartVal : nMatchVal * nScale;

// if not too big it's the match, else the match value is the match
if (nTestVal < NUM_VIRTUAL_ITEMS)
nMatchVal = nTestVal;
}
}
else // descending sequence
{
// convert start index to start value
int nStartVal = (NUM_VIRTUAL_ITEMS - 1) - pFindInfo->nStart;

if (nMatchVal != 0)
{
// if match number > start, we will have to wrap to find a match
// so use max index as our target
int nTargetVal = (nMatchVal > nStartVal) ? NUM_VIRTUAL_ITEMS - 1 : nStartVal;

// find scale factor that gets closest without going over target
int nScale = 1;
while (nMatchVal * nScale * 10 < nTargetVal)
nScale *= 10;

// check special case of target value beginning with the match digits
nMatchVal = (nTargetVal - nMatchVal * nScale) < nScale ? nTargetVal : (nMatchVal + 1) * nScale - 1;
}

// convert match value back to an item index
nMatchVal = (NUM_VIRTUAL_ITEMS - 1) - nMatchVal;
}

*pnFoundIndex = nMatchVal;

return S_OK;

}


STDMETHODIMP CSnapin::CacheHint (int nStartIndex, int nEndIndex)
{
// If advantageous, use this hint to pre-fetch the result item info that
// is about to be requested.
TRACE(_T("CSnapin::CacheHint(%d,%d)\n"), nStartIndex, nEndIndex);

return S_OK;

}

STDMETHODIMP CSnapin::SortItems (int nColumn, DWORD dwSortOptions, long lUserParam)
{
// sort request for user owned result items
// if item order changed return S_OK, else S_FALSE

// Sample only sorts on the first column (item name)

if ((nColumn == 0) && (m_dwVirtualSortOptions != dwSortOptions))
{
m_dwVirtualSortOptions = dwSortOptions;
return S_OK;
}

return S_FALSE;

}


void CSnapin::HandleStandardVerbs(bool bDeselectAll, long arg,
LPDATAOBJECT lpDataObject)
{
if (m_CustomViewID != VIEW_DEFAULT_LV)
{
m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, HIDDEN, FALSE);
m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, ENABLED, TRUE);

m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, HIDDEN, FALSE);
m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, TRUE);

return;
}

if (!bDeselectAll && lpDataObject == NULL)
return;

// You should crack the data object and enable/disable/hide standard
// commands appropriately. The standard commands are reset everytime you get
// called. So you must reset them back.

WORD bScope = LOWORD(arg);
WORD bSelect = HIWORD(arg);

#if 0
TCHAR buf[40];
wsprintf(buf, _T(" %4d - CSnapin::OnSelect<%d, %d>\n"), ++n_count, bScope, bSelect);
ODS(buf);
#else
DBX_PRINT(_T(" %4d - CSnapin::OnSelect<%d, %d>\n"), ++n_count, bScope, bSelect);
#endif


if (!bDeselectAll && IsMMCMultiSelectDataObject(lpDataObject) == TRUE)
{
m_pConsoleVerb->SetVerbState(MMC_VERB_DELETE, HIDDEN, FALSE);
m_pConsoleVerb->SetVerbState(MMC_VERB_DELETE, ENABLED, TRUE);
return;
}

INTERNAL* pInternal = lpDataObject ? ExtractInternalFormat(lpDataObject) : NULL;

if (bDeselectAll || !bSelect)
{
if (bScope)
{
m_pConsoleVerb->SetVerbState(MMC_VERB_OPEN, ENABLED, FALSE);
m_pConsoleVerb->SetVerbState(MMC_VERB_COPY, ENABLED, FALSE);
m_pConsoleVerb->SetVerbState(MMC_VERB_PASTE, ENABLED, FALSE);
m_pConsoleVerb->SetVerbState(MMC_VERB_DELETE, ENABLED, FALSE);
m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, FALSE);
m_pConsoleVerb->SetVerbState(MMC_VERB_RENAME, ENABLED, FALSE);

m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, HIDDEN, FALSE);
m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, ENABLED, TRUE);
}
else
{
// Result pane background
m_pConsoleVerb->SetVerbState(MMC_VERB_PASTE, HIDDEN, FALSE);
m_pConsoleVerb->SetVerbState(MMC_VERB_PASTE, ENABLED, TRUE);

if (pInternal && pInternal->m_cookie == 0)
{
m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, HIDDEN, FALSE);
m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, TRUE);
}

m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, HIDDEN, FALSE);
m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, ENABLED, TRUE);
}

return;
}


if (m_pConsoleVerb && pInternal)
{
if (pInternal->m_type == CCT_SCOPE)
{
// Standard funcitonality support by scope items
m_pConsoleVerb->SetVerbState(MMC_VERB_OPEN, HIDDEN, FALSE);
m_pConsoleVerb->SetVerbState(MMC_VERB_OPEN, ENABLED, TRUE);

m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, HIDDEN, FALSE);
m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, ENABLED, TRUE);

// Enable properties for static node only.
if (pInternal->m_cookie == 0)
{
m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, TRUE);
//m_pConsoleVerb->SetDefaultVerb(MMC_VERB_PROPERTIES);
m_pConsoleVerb->SetDefaultVerb(MMC_VERB_OPEN);
}
else
{
m_pConsoleVerb->SetDefaultVerb(MMC_VERB_OPEN);
}

// Standard funcitonality NOT support by scope items
m_pConsoleVerb->SetVerbState(MMC_VERB_DELETE, HIDDEN, TRUE);

}
else
{
// Standard funcitonality support by result items
m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, HIDDEN, FALSE);
m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, ENABLED, TRUE);
m_pConsoleVerb->SetVerbState(MMC_VERB_DELETE, HIDDEN, FALSE);
m_pConsoleVerb->SetVerbState(MMC_VERB_DELETE, ENABLED, TRUE);
m_pConsoleVerb->SetDefaultVerb(MMC_VERB_NONE);

// Standard funcitonality NOT support by result items
}

m_pConsoleVerb->SetVerbState(MMC_VERB_RENAME, ENABLED, TRUE);

// Standard funcitonality NOT support by all items
m_pConsoleVerb->SetVerbState(MMC_VERB_COPY, HIDDEN, TRUE);
m_pConsoleVerb->SetVerbState(MMC_VERB_PASTE, HIDDEN, TRUE);
}
}

void EnableToolbar(LPTOOLBAR pToolbar, MMCBUTTON rgSnapinButtons[], int nRgSize,
BOOL bEnable)
{
for (int i=0; i < nRgSize; ++i)
{
if (rgSnapinButtons[i].idCommand != 0)
pToolbar->SetButtonState(rgSnapinButtons[i].idCommand, ENABLED,
bEnable);
}
}


void EnableMenuBtns(LPMENUBUTTON pMenuBtn, MMCBUTTON rgSnapinButtons[], int nRgSize,
BOOL bEnable)
{
for (int i=0; i < nRgSize; ++i)
{
if (rgSnapinButtons[i].idCommand != 0)
pMenuBtn->SetButtonState(rgSnapinButtons[i].idCommand, ENABLED,
bEnable);
}
}

void CSnapin::HandleExtToolbars(bool bDeselectAll, long arg, long param)
{
INTERNAL* pInternal = NULL;
HRESULT hr;

BOOL bScope = (BOOL) LOWORD(arg);
BOOL bSelect = (BOOL) HIWORD(arg);

#if 1
{
if (param)
{
LPDATAOBJECT pDataObject = reinterpret_cast<LPDATAOBJECT>(param);
pInternal = ExtractInternalFormat(pDataObject);
}

TCHAR buf[200];
wsprintf(buf, _T(" %4d - CExtendControlbar::OnSelect<%d, %d> = %d\n"),
++n_count, bScope, bSelect, pInternal ? pInternal->m_cookie : 0);
ODS(buf);
}
#else
DBX_PRINT(_T(" %4d - CExtendControlbar::OnSelect<%d, %d>\n"), ++n_count, bScope, bSelect);
#endif

if (bDeselectAll || bSelect == FALSE)
{
ASSERT(m_pToolbar1);
EnableToolbar(m_pToolbar1, SnapinButtons,
ARRAYLEN(SnapinButtons), FALSE);

ASSERT(m_pToolbar2);
EnableToolbar(m_pToolbar2, SnapinButtons2,
ARRAYLEN(SnapinButtons2), FALSE);

ASSERT(m_pMenuButton1 != NULL);
m_pMenuButton1->SetButtonState(FOLDEREX_MENU, ENABLED, FALSE);
m_pMenuButton1->SetButtonState(FILEEX_MENU, ENABLED, FALSE);

return;
}

ASSERT(bSelect == TRUE);
bool bFileExBtn = false;
if (bScope == TRUE)
{
LPDATAOBJECT pDataObject = reinterpret_cast<LPDATAOBJECT>(param);

pInternal = ExtractInternalFormat(pDataObject);
if (pInternal == NULL)
return;

CFolder* pFolder = reinterpret_cast<CFolder*>(pInternal->m_cookie);

if (pInternal->m_cookie == 0)
{
if (IsPrimaryImpl() == TRUE)
{
// Attach the toolbars to the window
hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pToolbar1);
ASSERT(SUCCEEDED(hr));

hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pToolbar2);
ASSERT(SUCCEEDED(hr));
}
}
else if ((IsPrimaryImpl() == TRUE && pFolder->GetType() == COMPANY) ||
(IsPrimaryImpl() == FALSE && pFolder->GetType() == EXT_COMPANY))
{
// Detach the toolbar2 from the window
hr = m_pControlbar->Detach((LPUNKNOWN)m_pToolbar2);
ASSERT(SUCCEEDED(hr));

// Attach the toolbar1 to the window
hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pToolbar1);
ASSERT(SUCCEEDED(hr));
}
else if ((IsPrimaryImpl() == TRUE && pFolder->GetType() == USER) ||
(IsPrimaryImpl() == FALSE && pFolder->GetType() == EXT_USER))
{
// Detach the toolbar1 from the window
hr = m_pControlbar->Detach((LPUNKNOWN)m_pToolbar1);
ASSERT(SUCCEEDED(hr));

// Attach the toolbar2 to the window
hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pToolbar2);
ASSERT(SUCCEEDED(hr));
}
else
{
// Detach the toolbars from the window
hr = m_pControlbar->Detach((LPUNKNOWN)m_pToolbar1);
ASSERT(SUCCEEDED(hr));

hr = m_pControlbar->Detach((LPUNKNOWN)m_pToolbar2);
ASSERT(SUCCEEDED(hr));
}

FREE_DATA(pInternal);

EnableToolbar(m_pToolbar1, SnapinButtons,
ARRAYLEN(SnapinButtons), FALSE);

EnableToolbar(m_pToolbar2, SnapinButtons2,
ARRAYLEN(SnapinButtons2), FALSE);
}
else // result item selected.
{
LPDATAOBJECT pDataObject = reinterpret_cast<LPDATAOBJECT>(param);

if (pDataObject != NULL)
pInternal = ExtractInternalFormat(pDataObject);

if (pInternal == NULL)
return;

if (pInternal->m_type == CCT_RESULT)
{
bFileExBtn = true;

ASSERT(m_pToolbar1);
EnableToolbar(m_pToolbar1, SnapinButtons,
ARRAYLEN(SnapinButtons), TRUE);

m_pToolbar1->SetButtonState(1, ENABLED, FALSE);
m_pToolbar1->SetButtonState(2, CHECKED, TRUE);
m_pToolbar1->SetButtonState(3, HIDDEN, TRUE);
m_pToolbar1->SetButtonState(4, INDETERMINATE, TRUE);
m_pToolbar1->SetButtonState(5, BUTTONPRESSED, TRUE);

// Above is the correct way
ASSERT(m_pToolbar2);
m_pToolbar2->SetButtonState(20, CHECKED, TRUE);
m_pToolbar2->SetButtonState(30, HIDDEN, TRUE);
m_pToolbar2->SetButtonState(40, INDETERMINATE, TRUE);
m_pToolbar2->SetButtonState(50, BUTTONPRESSED, TRUE);

EnableToolbar(m_pToolbar2, SnapinButtons2,
ARRAYLEN(SnapinButtons2), TRUE);
}
else // sub folder slected
{
CFolder* pFolder = reinterpret_cast<CFolder*>(pInternal->m_cookie);

ASSERT(m_pControlbar);

if (pInternal->m_cookie == 0)
{
if (IsPrimaryImpl() == TRUE)
{
// Attach the toolbars to the window
hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pToolbar1);
ASSERT(SUCCEEDED(hr));

hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pToolbar2);
ASSERT(SUCCEEDED(hr));
}
}
else if ((IsPrimaryImpl() == TRUE && pFolder->GetType() == COMPANY) ||
(IsPrimaryImpl() == FALSE && pFolder->GetType() == EXT_COMPANY))
{
// Detach the toolbar2 from the window
hr = m_pControlbar->Detach((LPUNKNOWN)m_pToolbar2);
ASSERT(SUCCEEDED(hr));

// Attach the toolbar1 to the window
hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pToolbar1);
ASSERT(SUCCEEDED(hr));
}
else if ((IsPrimaryImpl() == TRUE && pFolder->GetType() == USER) ||
(IsPrimaryImpl() == FALSE && pFolder->GetType() == EXT_USER))
{
// Detach the toolbar1 from the window
hr = m_pControlbar->Detach((LPUNKNOWN)m_pToolbar1);
ASSERT(SUCCEEDED(hr));

// Attach the toolbar2 to the window
hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pToolbar2);
ASSERT(SUCCEEDED(hr));
}
else
{
// Detach the toolbars from the window
hr = m_pControlbar->Detach((LPUNKNOWN)m_pToolbar1);
ASSERT(SUCCEEDED(hr));

hr = m_pControlbar->Detach((LPUNKNOWN)m_pToolbar2);
ASSERT(SUCCEEDED(hr));
}

ASSERT(m_pToolbar1);
EnableToolbar(m_pToolbar1, SnapinButtons,
ARRAYLEN(SnapinButtons), TRUE);

m_pToolbar1->SetButtonState(1, ENABLED, FALSE);
m_pToolbar1->SetButtonState(2, CHECKED, TRUE);
m_pToolbar1->SetButtonState(3, ENABLED, TRUE);
m_pToolbar1->SetButtonState(4, INDETERMINATE, TRUE);
m_pToolbar1->SetButtonState(5, BUTTONPRESSED, TRUE);


ASSERT(m_pToolbar2);
EnableToolbar(m_pToolbar2, SnapinButtons2,
ARRAYLEN(SnapinButtons2), TRUE);

// Above is the correct way
m_pToolbar2->SetButtonState(20, CHECKED, FALSE);
m_pToolbar2->SetButtonState(30, ENABLED, TRUE);
m_pToolbar2->SetButtonState(40, INDETERMINATE, FALSE);
m_pToolbar2->SetButtonState(50, BUTTONPRESSED, TRUE);
}
}

if (m_pMenuButton1)
{
// Always make sure the menuButton is attached
m_pControlbar->Attach(MENUBUTTON, m_pMenuButton1);

if (bFileExBtn)
{
m_pMenuButton1->SetButtonState(FILEEX_MENU, HIDDEN, FALSE);
m_pMenuButton1->SetButtonState(FOLDEREX_MENU, HIDDEN, TRUE);
m_pMenuButton1->SetButtonState(FILEEX_MENU, ENABLED, TRUE);
}
else
{
m_pMenuButton1->SetButtonState(FOLDEREX_MENU, HIDDEN, FALSE);
m_pMenuButton1->SetButtonState(FILEEX_MENU, HIDDEN, TRUE);
m_pMenuButton1->SetButtonState(FOLDEREX_MENU, ENABLED, TRUE);
}
}
}


void CSnapin::HandleExtMenus(long arg, long param)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

LPDATAOBJECT* ppDataObject = reinterpret_cast<LPDATAOBJECT*>(arg);
LPMENUBUTTONDATA pMenuData = reinterpret_cast<LPMENUBUTTONDATA>(param);

if (ppDataObject == NULL || pMenuData == NULL)
{
ASSERT(FALSE);
return;
}


::CMenu menu;
::CMenu* pMenu = NULL;

switch (pMenuData->idCommand)
{
case FOLDEREX_MENU:
menu.LoadMenu(FOLDEREX_MENU);
pMenu = menu.GetSubMenu(0);
break;

case FILEEX_MENU:
menu.LoadMenu(FILEEX_MENU);
pMenu = menu.GetSubMenu(0);
break;

default:
ASSERT(FALSE);
}

if (pMenu == NULL)
return;

pMenu->TrackPopupMenu(TPM_RETURNCMD | TPM_NONOTIFY, pMenuData->x, pMenuData->y, AfxGetMainWnd());

}


void CSnapin::GetItemName(LPDATAOBJECT pdtobj, LPTSTR pszName)
{
ASSERT(pszName != NULL);
pszName[0] = 0;

INTERNAL* pInternal = ExtractInternalFormat(pdtobj);
ASSERT(pInternal != NULL);
if (pInternal == NULL)
return;

OLECHAR *pszTemp;

if (pInternal->m_type == CCT_RESULT)
{
RESULT_DATA* pData;
// if virtual, derive result item from index
// else cookie is the item pointer
if (m_bVirtualView)
pData = GetVirtualResultItem(pInternal->m_cookie);
else
pData = reinterpret_cast<RESULT_DATA*>(pInternal->m_cookie);

ASSERT(pData != NULL);
pszTemp = pData->szName;
}
else
{
CFolder* pFolder = reinterpret_cast<CFolder*>(pInternal->m_cookie);
if (pFolder == 0)
pszTemp = L"Static folder";
else
pszTemp = OLE2T(pFolder->m_pszName);
}

USES_CONVERSION;

lstrcpy(pszName, OLE2T(pszTemp));
}