// obj_vw.cpp
//
// Implementation of the CObjTreeView class
//

// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1995 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#include "stdafx.h"
#include "OleView.h"
#include "shadow.h"
#include "obj_vw.h"
#include <winnls.h>

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CObjectData

IMPLEMENT_DYNCREATE(CObjectData, CObject)

CObjectData::CObjectData()
{
    m_nType = typeUnknown ;
    m_pcf = NULL ;
    m_punk = NULL ;
    m_uiBitmap = NULL ;

}

CObjectData::~CObjectData()
{
}

BOOL CObjectData::Release()
{
    if (m_pcf)
        m_pcf->Release() ;

    if (m_punk)
        m_punk->Release() ;

    m_pcf = NULL ;
    m_punk = NULL ;
    
    CoFreeUnusedLibraries();

    return TRUE ;
}

HRESULT CObjectData::CreateInstance( DWORD clsctx )
{
    Release() ;

    HRESULT hr = NOERROR ;
    CString strError ;
    IUnknown* punk = NULL ;
    TRY
    {
        hr = CoGetClassObject( m_clsid, clsctx, NULL, IID_IUnknown, (void**)&punk ) ;
        if (FAILED(hr))
        {
            strError = "CoGetClassObject failed." ;
            AfxThrowOleException(hr) ;
        }
        ASSERT(punk) ;

        hr = punk->QueryInterface( IID_IClassFactory, (void**)&m_pcf ) ;
        if (FAILED(hr))
        {
            strError = "QueryInterface on class factory for IClassFactory failed." ;
            AfxThrowOleException(hr) ;
        }
        ASSERT(m_pcf) ;

        punk->Release() ;
        punk = NULL ;

        hr = m_pcf->CreateInstance( NULL, IID_IUnknown, (void**)&m_punk ) ;
        if (FAILED(hr))
        {
            strError = "IClassFactory::CreateInstance failed." ;
            AfxThrowOleException(hr) ;
        }

        m_pcf->Release() ;
        m_pcf = NULL ;
    }
    CATCH(COleException, pException)
    {
        if (punk)
            punk->Release() ;
        Release() ;

        ErrorMessage( strError, hr ) ;
    }
    END_CATCH ;

    return hr ;
}

/////////////////////////////////////////////////////////////////////////////
// CObjTreeView

IMPLEMENT_DYNCREATE(CObjTreeView, CTreeView)

BEGIN_MESSAGE_MAP(CObjTreeView, CTreeView)
    //{{AFX_MSG_MAP(CObjTreeView)
    ON_WM_CREATE()
    ON_WM_DESTROY()
	ON_WM_LBUTTONDBLCLK()
	ON_COMMAND(ID_OBJECT_DELETE, OnObjectDelete)
	ON_COMMAND(ID_OBJECT_VERIFY, OnObjectVerify)
	//}}AFX_MSG_MAP
	ON_NOTIFY_REFLECT(TVN_SELCHANGED,OnTreeSelchanged)
	ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnTreeItemExpanding)
	ON_NOTIFY_REFLECT(TVN_ITEMEXPANDED,OnTreeItemExpanded)
    ON_NOTIFY_REFLECT(TVN_DELETEITEM,OnTreeDeleteItem)
    ON_MESSAGE( WM_COMMANDHELP, OnCommandHelp)
	ON_NOTIFY_REFLECT(NM_RETURN, OnTreeReturn)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CObjTreeView construction/destruction

CObjTreeView::CObjTreeView()
{
    m_hObjects = NULL ;
    m_hTypeLibs= NULL ;
    m_hInterfaces = NULL ;

    m_hInsertable = NULL ;
    m_hControls= NULL ;
    m_hInternal= NULL ;
#ifdef SHOW_CONTAINERS
    m_hContainers= NULL ;
#endif
    m_hOLE1= NULL ;
    m_hUnclassified= NULL ;
}

CObjTreeView::~CObjTreeView()
{
}

LRESULT CObjTreeView::OnCommandHelp(WPARAM, LPARAM lParam)
{
    theApp.WinHelp( lParam, HELP_CONTEXT ) ;
    return TRUE ;
}

BOOL CObjTreeView::PreCreateWindow(CREATESTRUCT& cs)
{
	if (!CTreeView::PreCreateWindow(cs))
		return FALSE;

	cs.style = WS_CHILD | WS_VISIBLE | WS_BORDER | TVS_LINESATROOT |
		TVS_HASLINES | TVS_HASBUTTONS |	TVS_DISABLEDRAGDROP;
	return TRUE;
}


int CObjTreeView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CTreeView::OnCreate(lpCreateStruct) == -1)
        return -1;
#ifdef _MARCOC_OLD
    RECT rect ;
    rect.top = lpCreateStruct->y ;
    rect.left = lpCreateStruct->x ;
    rect.bottom = lpCreateStruct->cy ;
    rect.right = lpCreateStruct->cx ;

    if (!GetTreeCtrl().Create( WS_CHILD | WS_VISIBLE |
                                WS_BORDER | 
                                TVS_LINESATROOT |
                                TVS_HASLINES | 
//                                TVS_SHOWSELALWAYS |
                                TVS_HASBUTTONS |
                                TVS_DISABLEDRAGDROP,
                                rect, this, ID_TREEVIEW ))
    {
        TRACE( _T("Tree control failed to create!") ) ;
        return -1 ;
    }
#endif
    return 0;
}

void CObjTreeView::OnInitialUpdate()
{
    GetTreeCtrl().SetImageList( &theApp.m_images, TVSIL_NORMAL ) ;

    TV_INSERTSTRUCT tvis ;
    tvis.hParent = TVI_ROOT ;
    tvis.hInsertAfter = TVI_LAST ;
    tvis.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN ;
    tvis.item.lParam = 0 ;
    tvis.item.cChildren = 1 ;

    tvis.item.pszText = "Objects" ;
    tvis.item.iImage = BMINDEX(IDB_OBJECTFOLDER) ;
    tvis.item.iSelectedImage = BMINDEX(IDB_OBJECTFOLDER) ;
    m_hObjects = GetTreeCtrl().InsertItem( &tvis ) ;

    tvis.hParent = m_hObjects ;
    tvis.item.pszText = "OLE Document Objects" ;
    tvis.item.iImage = BMINDEX(IDB_OBJECT_INSERTABLE) ;
    tvis.item.iSelectedImage = BMINDEX(IDB_OBJECT_INSERTABLE) ;
    m_hInsertable = GetTreeCtrl().InsertItem( &tvis ) ;

    tvis.item.pszText = "OLE Controls" ;
    tvis.item.iImage = BMINDEX(IDB_OBJECT_CONTROL) ;
    tvis.item.iSelectedImage = BMINDEX(IDB_OBJECT_CONTROL) ;
    m_hControls = GetTreeCtrl().InsertItem( &tvis ) ;

    tvis.item.pszText = "Unclassified Objects" ;
    tvis.item.iImage = BMINDEX(IDB_OBJECT) ;
    tvis.item.iSelectedImage = BMINDEX(IDB_OBJECT) ;
    m_hUnclassified = GetTreeCtrl().InsertItem( &tvis ) ;

#ifdef SHOW_CONTAINERS
    tvis.item.pszText = "Containers" ;
    tvis.item.iImage = BMINDEX(IDB_CONTAINER) ;
    tvis.item.iSelectedImage = BMINDEX(IDB_CONTAINER) ;
    m_hContainers = GetTreeCtrl().InsertItem( &tvis ) ;
#endif

    tvis.item.pszText = "OLE 1.0 Objects" ;
    tvis.item.iImage = BMINDEX(IDB_OBJECT_INSERTABLE10) ;
    tvis.item.iSelectedImage = BMINDEX(IDB_OBJECT_INSERTABLE10) ;
    m_hOLE1 = GetTreeCtrl().InsertItem( &tvis ) ;

    tvis.item.pszText = "Internal OLE Objects" ;
    tvis.item.iImage = BMINDEX(IDB_QUESTION) ;
    tvis.item.iSelectedImage = BMINDEX(IDB_QUESTION) ;
    m_hInternal = GetTreeCtrl().InsertItem( &tvis ) ;

    GetTreeCtrl().Expand( m_hObjects, TVE_EXPAND ) ;

    tvis.hParent = TVI_ROOT ;
    tvis.item.pszText = "Type Libraries" ;
    tvis.item.iImage = BMINDEX(IDB_TYPELIBFOLDER) ;
    tvis.item.iSelectedImage = BMINDEX(IDB_TYPELIBFOLDER) ;
    m_hTypeLibs = GetTreeCtrl().InsertItem( &tvis ) ;

    tvis.item.pszText = "Interfaces" ;
    tvis.item.iImage = BMINDEX(IDB_IFACEFOLDER) ;
    tvis.item.iSelectedImage = BMINDEX(IDB_IFACEFOLDER) ;
    m_hInterfaces = GetTreeCtrl().InsertItem( &tvis ) ;
}

void CObjTreeView::OnDestroy()
{
    DeleteTreeContents() ;
    CTreeView::OnDestroy();
}


void CObjTreeView::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
    UINT hitflags ;
    HTREEITEM hitem ;

    hitem = GetTreeCtrl().HitTest( point, &hitflags ) ;
    if (hitflags & (TVHT_ONITEM | TVHT_ONITEMBUTTON))
    {
        NM_TREEVIEW nm ;
        nm.itemNew.mask = TVIF_PARAM  ;
        nm.itemNew.hItem = hitem ;
        if (GetTreeCtrl().GetItem( &nm.itemNew ))
        {
			CObjectData* pObjectData = (CObjectData*)nm.itemNew.lParam;
			CallInterfaceViewer(pObjectData, nm.itemNew.hItem);
        }
    }
	CTreeView::OnLButtonDblClk(nFlags, point);
}


/////////////////////////////////////////////////////////////////////////////
// CObjTreeView drawing

BOOL HasServer32( HKEY hkCLSID )
{
    HKEY hkTemp ;
    if ((RegOpenKey( hkCLSID, _T("InprocServer32"), &hkTemp ) == ERROR_SUCCESS) ||
        (RegOpenKey( hkCLSID, _T("InprocHandler32"), &hkTemp ) == ERROR_SUCCESS) ||
        (RegOpenKey( hkCLSID, _T("LocalServer32"), &hkTemp ) == ERROR_SUCCESS))
    {
        RegCloseKey( hkTemp ) ;
        return TRUE ;
    }

    return FALSE ;
}

BOOL HasServer16( HKEY hkCLSID )
{
    HKEY hkTemp ;
    if ((RegOpenKey( hkCLSID, _T("InprocServer"), &hkTemp ) == ERROR_SUCCESS) ||
        (RegOpenKey( hkCLSID, _T("InprocHandler"), &hkTemp ) == ERROR_SUCCESS) ||
        (RegOpenKey( hkCLSID, _T("LocalServer"), &hkTemp ) == ERROR_SUCCESS))
    {
        RegCloseKey( hkTemp ) ;
        return TRUE ;
    }

    return FALSE ;
}

void CObjTreeView::DeleteTreeItems( HTREEITEM htree )
{
    HTREEITEM       hItem, hItemNext ;

    hItem = GetTreeCtrl().GetChildItem( htree ) ;
    while( hItem )
    {
        hItemNext = GetTreeCtrl().GetNextSiblingItem( hItem ) ;
        GetTreeCtrl().DeleteItem( hItem ) ;
        hItem = hItemNext ;
    }
}

void CObjTreeView::DeleteTreeContents() 
{
    // Delete current contents
    //
    if ((int)GetTreeCtrl().GetCount() > 0)
    {
        DeleteTreeItems( m_hInsertable ) ;
        DeleteTreeItems( m_hControls ) ;
        DeleteTreeItems( m_hInternal ) ;
#ifdef SHOW_CONTAINERS
        DeleteTreeItems( m_hContainers ) ;
#endif
        DeleteTreeItems( m_hOLE1 ) ;
        DeleteTreeItems( m_hUnclassified ) ;
        
        DeleteTreeItems( m_hTypeLibs ) ;
        DeleteTreeItems( m_hInterfaces ) ;
    }
}

void CObjTreeView::OnDraw( CDC* /*pdc */ )
{
}

void CObjTreeView::OnUpdate( CView* pSender, LPARAM lHint, CObject* pHint )
{
    pSender; pHint ;
    if (lHint & UPD_NOOBJECTVIEW)
        return ;

    BeginWaitCursor() ;
    GetTreeCtrl().SetRedraw( FALSE ) ;
    GetTreeCtrl().SelectItem( NULL ) ;

    if ((int)GetTreeCtrl().GetCount() > 0)
    {
        BOOL fExpanded = FALSE ;
        TV_ITEM tvi ;
        tvi.mask = TVIF_STATE ;

        tvi.hItem = m_hInsertable ;
        if (GetTreeCtrl().GetItem( &tvi ))
        {
            fExpanded = (tvi.state & TVIS_EXPANDED) ;
            GetTreeCtrl().Expand( tvi.hItem, TVE_COLLAPSE ) ;
            DeleteTreeItems( tvi.hItem ) ;
            tvi.state &= ~TVIS_EXPANDEDONCE ;
            GetTreeCtrl().SetItem( &tvi ) ;
            if (fExpanded)
                GetTreeCtrl().Expand( tvi.hItem, TVE_EXPAND ) ;
        }

        tvi.hItem = m_hControls ;
        if (GetTreeCtrl().GetItem( &tvi ))
        {
            fExpanded = (tvi.state & TVIS_EXPANDED) ;
            GetTreeCtrl().Expand( tvi.hItem, TVE_COLLAPSE ) ;
            DeleteTreeItems( tvi.hItem ) ;
            tvi.state &= ~TVIS_EXPANDEDONCE ;
            GetTreeCtrl().SetItem( &tvi ) ;
            if (fExpanded)
                GetTreeCtrl().Expand( tvi.hItem, TVE_EXPAND ) ;
        }

        tvi.hItem = m_hInternal ;
        if (GetTreeCtrl().GetItem( &tvi ))
        {
            fExpanded = (tvi.state & TVIS_EXPANDED) ;
            GetTreeCtrl().Expand( tvi.hItem, TVE_COLLAPSE ) ;
            DeleteTreeItems( tvi.hItem ) ;
            tvi.state &= ~TVIS_EXPANDEDONCE ;
            GetTreeCtrl().SetItem( &tvi ) ;
            if (fExpanded)
                GetTreeCtrl().Expand( tvi.hItem, TVE_EXPAND ) ;
        }

        tvi.hItem = m_hOLE1 ;
        if (GetTreeCtrl().GetItem( &tvi ))
        {
            fExpanded = (tvi.state & TVIS_EXPANDED) ;
            GetTreeCtrl().Expand( tvi.hItem, TVE_COLLAPSE ) ;
            DeleteTreeItems( tvi.hItem ) ;
            tvi.state &= ~TVIS_EXPANDEDONCE ;
            GetTreeCtrl().SetItem( &tvi ) ;
            if (fExpanded)
                GetTreeCtrl().Expand( tvi.hItem, TVE_EXPAND ) ;
        }

        tvi.hItem = m_hUnclassified ;
        if (GetTreeCtrl().GetItem( &tvi ))
        {
            fExpanded = (tvi.state & TVIS_EXPANDED) ;
            GetTreeCtrl().Expand( tvi.hItem, TVE_COLLAPSE ) ;
            DeleteTreeItems( tvi.hItem ) ;
            tvi.state &= ~TVIS_EXPANDEDONCE ;
            GetTreeCtrl().SetItem( &tvi ) ;
            if (fExpanded)
                GetTreeCtrl().Expand( tvi.hItem, TVE_EXPAND ) ;
        }
        
        tvi.hItem = m_hTypeLibs ;
        if (GetTreeCtrl().GetItem( &tvi ))
        {
            fExpanded = (tvi.state & TVIS_EXPANDED) ;
            GetTreeCtrl().Expand( tvi.hItem, TVE_COLLAPSE ) ;
            DeleteTreeItems( tvi.hItem ) ;
            tvi.state &= ~TVIS_EXPANDEDONCE ;
            GetTreeCtrl().SetItem( &tvi ) ;
            if (fExpanded)
                GetTreeCtrl().Expand( tvi.hItem, TVE_EXPAND ) ;
        }

        tvi.hItem = m_hInterfaces ;
        if (GetTreeCtrl().GetItem( &tvi ))
        {
            fExpanded = (tvi.state & TVIS_EXPANDED) ;
            GetTreeCtrl().Expand( tvi.hItem, TVE_COLLAPSE ) ;
            DeleteTreeItems( tvi.hItem ) ;
            tvi.state &= ~TVIS_EXPANDEDONCE ;
            GetTreeCtrl().SetItem( &tvi ) ;
            if (fExpanded)
                GetTreeCtrl().Expand( tvi.hItem, TVE_EXPAND ) ;
        }
    }

    GetTreeCtrl().SetRedraw( TRUE ) ;
    EndWaitCursor() ;
}


/////////////////////////////////////////////////////////////////////////////
// CObjTreeView diagnostics

#ifdef _DEBUG
void CObjTreeView::AssertValid() const
{
    CTreeView::AssertValid();
}

void CObjTreeView::Dump(CDumpContext& dc) const
{
    CTreeView::Dump(dc);
}

#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CObjTreeView message handlers

void CObjTreeView::OnTreeSelchanged(NMHDR* pNMHDR, LRESULT* pResult) 
{
    COle2ViewDoc*   pDoc = GetDocument() ;
	NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pNMHDR;
    CObjectData*    lpOD ;

    lpOD = (CObjectData*)pnmtv->itemNew.lParam ;

    // special case typelibs because there may be multiple entries (versions)
    // for a given TYPELIBID
    //
    if (lpOD && (!IsEqualCLSID( lpOD->m_clsid, pDoc->m_clsidCur ) || pDoc->m_fTypeLib))
    {
        pDoc->m_fTypeLib = (lpOD->m_uiBitmap == BMINDEX(IDB_AUTOMATION)) ;
        pDoc->m_fInterface = (lpOD->m_uiBitmap == BMINDEX(IDB_INTERFACE)) ;
        pDoc->m_clsidCur = lpOD->m_clsid ;

        TV_ITEM tvi ;
        tvi.hItem = pnmtv->itemNew.hItem ;
        tvi.mask = TVIF_TEXT ;
        tvi.cchTextMax = 256 ;
        tvi.pszText = new TCHAR[256] ;
        if (GetTreeCtrl().GetItem( &tvi ))
        {
            pDoc->m_szObjectCur = tvi.pszText ;
        }
        else
            pDoc->m_szObjectCur = "ERROR" ;
        delete tvi.pszText ;
    }
    else
    {
        pDoc->m_fTypeLib = FALSE ;
        pDoc->m_fInterface = FALSE ;
        pDoc->m_clsidCur =  GUID_NULL;
        pDoc->m_szObjectCur = "" ;
    }
    pDoc->UpdateAllViews( this, UPD_NOOBJECTVIEW ) ;
	*pResult = 0;
}

void CObjTreeView::OnTreeItemExpanding(NMHDR* pNMHDR, LRESULT* pResult) 
{
	*pResult = 0;
    COle2ViewDoc*   pDoc = GetDocument() ;
	NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pNMHDR;
    if (pnmtv->action == TVE_EXPAND && pnmtv->itemNew.hItem != m_hObjects)
    {
        if (pnmtv->itemNew.state & TVIS_EXPANDEDONCE)
            return ;

        BeginWaitCursor() ;
        GetTreeCtrl().SetRedraw( FALSE ) ;

        if (pnmtv->itemNew.hItem == m_hInterfaces)
            ExpandInterfaces( pnmtv ) ;
        else if (pnmtv->itemNew.hItem == m_hTypeLibs)
            ExpandTypeLibs( pnmtv ) ;
        else if (pnmtv->itemNew.lParam != NULL)
            ExpandObject( pnmtv ) ;
        else 
            ExpandClassification( pnmtv ) ;

        GetTreeCtrl().SetRedraw( TRUE ) ;
        EndWaitCursor() ;
    }
}

void CObjTreeView::ExpandClassification( NM_TREEVIEW* pnmtv )
{
	USES_CONVERSION;
    HKEY    hkCLSID ;
    COle2ViewDoc* pDoc = GetDocument();

    if (RegOpenKey( HKEY_CLASSES_ROOT, _T("CLSID"), &hkCLSID) == ERROR_SUCCESS)
    {
        CObjectData* lpOD ;
        LONG     cb ;
        TCHAR    szBuf[_MAX_PATH] ;
        TCHAR    szName[64] ;
        TCHAR    szCLSID[64] ;
        DWORD   dwIndex ;

        for ( dwIndex = 0 ;
              RegEnumKey( hkCLSID, dwIndex, szCLSID, sizeof(szCLSID)) == ERROR_SUCCESS ;
              ++dwIndex )
        {
            lpOD = NULL ;
            cb = sizeof(szName);
            if (RegQueryValue( hkCLSID, (LPTSTR)szCLSID, szName, &cb) == ERROR_SUCCESS)
            {
                lpOD = new CObjectData ;
                lpOD->m_nType = CObjectData::typeObject ;
                ASSERT(lpOD) ;
                ::CLSIDFromString( T2OLE(szCLSID), &lpOD->m_clsid);
                lpOD->m_szProgID[0] = '\0' ;

                // Assume it's an object
                lpOD->m_uiBitmap = BMINDEX(IDB_OBJECT) ;


                // Now find out more about it.
                //
                // #1 Look in CLSID\{clsid} for the \Control key
                // #2 Assume it is an 'non-embeddable' OLE 2.0 object
                // #3 If \<progid>\NotInsertable exists we're done
                // #4 if !#2 then if \<progid>\Insertable it's an insertable OLE 2.0 object
                //    and we're done
                // #5 if !#3 see if it's an OLE 1.0 object by checking Ole1Class
                //
                HKEY    hkClass, hkTemp ;

                if (RegOpenKey( hkCLSID, szCLSID, &hkClass ) == ERROR_SUCCESS)
                {
                    BOOL    fHasServer32 = HasServer32( hkClass ) ;

                    if (fHasServer32)
                        lpOD->m_uiBitmap = BMINDEX(IDB_OBJECT32) ;
                    else
                        lpOD->m_uiBitmap = BMINDEX(IDB_OBJECT) ;

                    // First determine if it is a system component
                    //
                    cb = sizeof(szBuf) ;
                    if (RegQueryValue( hkClass, (LPTSTR)_T("InprocServer32"), szBuf, &cb ) == ERROR_SUCCESS)
                    {
                        if ((0 == lstrcmpi( szBuf, _T("ole32.dll") )) ||
                            (0 == lstrcmpi( szBuf, _T("oleprx32.dll") )) ||
                            (0 == lstrcmpi( szBuf, _T("ole2pr32.dll") )) ||
                            (0 == lstrcmpi( szBuf, _T("olecnv32.dll") )) ||
                            (0 == lstrcmpi( szBuf, _T("oleaut32.dll") )))
                        {
                            lpOD->m_uiBitmap = BMINDEX(IDB_QUESTION32) ;
                        }
                    } // Query InprocServer
                    else if (RegQueryValue( hkClass, (LPTSTR)_T("InprocServer"), szBuf, &cb ) == ERROR_SUCCESS)
                    {
                        if ((0 == lstrcmpi( szBuf, _T("ole2prox.dll") )) ||
                            (0 == lstrcmpi( szBuf, _T("ole2.dll") )) ||
                            (0 == lstrcmpi( szBuf, _T("ole2disp.dll") )))
                        {
                            lpOD->m_uiBitmap = BMINDEX(IDB_QUESTION) ;
                        }
                    } 

                    // If it has "Ole1Class" then it's an OLE 1.0 object
                    //
                    wsprintf( szBuf, _T("CLSID\\%s\\Ole1Class"), (LPTSTR)szCLSID) ;
                    if (RegOpenKey( HKEY_CLASSES_ROOT, szBuf, &hkTemp ) == ERROR_SUCCESS)
                    {
                        // Is it 32 bit or 16 bit?
                        if (fHasServer32)
                            lpOD->m_uiBitmap = BMINDEX(IDB_OBJECT_INSERTABLE1032) ;   // that succeeded.  This means we're insertable
                        else
                            lpOD->m_uiBitmap = BMINDEX(IDB_OBJECT_INSERTABLE10) ;   // that succeeded.  This means we're insertable
                        RegCloseKey( hkTemp ) ;
                        goto lblInsertInList ;
                    }
                                        // We now recognize the "Control" key which indicates it's
                    // an OLE Custom Control.
                    //
                    wsprintf( szBuf, _T("CLSID\\%s\\Control"), (LPTSTR)szCLSID) ;
                    if (RegOpenKey( HKEY_CLASSES_ROOT, szBuf, &hkTemp ) == ERROR_SUCCESS)
                    {
                        // Is it 32 bit or 16 bit?
                        if (fHasServer32)
                            lpOD->m_uiBitmap = BMINDEX(IDB_OBJECT_CONTROL32) ;
                        else
                            lpOD->m_uiBitmap = BMINDEX(IDB_OBJECT_CONTROL) ;
                        RegCloseKey( hkTemp ) ;
                        goto lblInsertInList ;
                    }

                    // If it's not a control, but it's insertable it must be a CD object
                    //
                    wsprintf( szBuf, _T("CLSID\\%s\\Insertable"), (LPTSTR)szCLSID) ;
                    if (RegOpenKey( HKEY_CLASSES_ROOT, szBuf, &hkTemp ) == ERROR_SUCCESS)
                    {
                        // Is it 32 bit or 16 bit?
                        if (fHasServer32)
                            lpOD->m_uiBitmap = BMINDEX(IDB_OBJECT_INSERTABLE32) ;   // that succeeded.  This means we're insertable
                        else
                            lpOD->m_uiBitmap = BMINDEX(IDB_OBJECT_INSERTABLE) ;   // that succeeded.  This means we're insertable
                        RegCloseKey( hkTemp ) ;
                        goto lblInsertInList ;
                    }


                    cb = sizeof(lpOD->m_szProgID) ;
                    if (RegQueryValue( hkClass, (LPTSTR)_T("ProgID"), lpOD->m_szProgID, &cb) == ERROR_SUCCESS)
                    {
                        HKEY    hkInsertable ;

                        // Is it an OLE 1.0 object?
                        //
                        cb = 64 ;
                        if (RegQueryValue( hkClass, (LPTSTR)"Ole1Class", szBuf, &cb ) == ERROR_SUCCESS)
                        {
                            if (fHasServer32)
                                lpOD->m_uiBitmap = BMINDEX( IDB_OBJECT_INSERTABLE1032 ) ;
                            else
                                lpOD->m_uiBitmap = BMINDEX( IDB_OBJECT_INSERTABLE10 ) ;
                            goto lblInsertInList ;
                        }

                        // Does the object force "NotInsertable"?
                        //
                        wsprintf( szBuf, _T("%s\\NotInsertable"), (LPTSTR)lpOD->m_szProgID ) ;
                        if (RegOpenKey( HKEY_CLASSES_ROOT, szBuf, &hkInsertable ) == ERROR_SUCCESS)
                        {
                            if (fHasServer32)
                                lpOD->m_uiBitmap = BMINDEX(IDB_OBJECT32) ;
                            else
                                lpOD->m_uiBitmap = BMINDEX(IDB_OBJECT) ;

                            RegCloseKey( hkInsertable ) ;
                            goto lblInsertInList ;
                        }

                        // Is it insertable?
                        //
                        wsprintf( szBuf, _T("%s\\Insertable"), (LPTSTR)lpOD->m_szProgID ) ;
                        if (RegOpenKey( HKEY_CLASSES_ROOT, szBuf, &hkInsertable ) == ERROR_SUCCESS)
                        {
                            if (fHasServer32)
                                lpOD->m_uiBitmap = BMINDEX(IDB_OBJECT_INSERTABLE32) ;   // that succeeded.  This means we're insertable
                            else
                                lpOD->m_uiBitmap = BMINDEX(IDB_OBJECT_INSERTABLE) ;   // that succeeded.  This means we're insertable
                            RegCloseKey( hkInsertable ) ;
                            goto lblInsertInList ;
                        }

#ifdef SHOW_CONTAINERS
                        // Try HKEY_CLASSES_ROOT\szProgID\shell\open to see if it's
                        // a container.
                        //
                        wsprintf( szBuf, _T("%s\\shell\\open"), (LPTSTR)lpOD->m_szProgID ) ;
                        if (RegOpenKey( HKEY_CLASSES_ROOT, szBuf, &hkInsertable ) == ERROR_SUCCESS)
                        {
                            if (fHasServer32)
                                lpOD->m_uiBitmap = BMINDEX(IDB_CONTAINER32) ;
                            else
                                lpOD->m_uiBitmap = BMINDEX(IDB_CONTAINER) ;
                            RegCloseKey( hkInsertable ) ;
                            goto lblInsertInList ;
                        }
#endif
                    }
                    RegCloseKey( hkClass ) ;

                }  // if RegOpenKey( ... &hkClass )

lblInsertInList:
                HTREEITEM htree = NULL ;
                switch( lpOD->m_uiBitmap )
                {
                    case BMINDEX(IDB_QUESTION):
                    case BMINDEX(IDB_QUESTION32):
                        htree = m_hInternal ;
                    break ;
                            
                    case BMINDEX(IDB_OBJECT_INSERTABLE10):
                    case BMINDEX(IDB_OBJECT_INSERTABLE1032):
                        htree = m_hOLE1 ;
                    break ;

                    case BMINDEX(IDB_OBJECT_INSERTABLE):
                    case BMINDEX(IDB_OBJECT_INSERTABLE32):
                        htree = m_hInsertable ;
                    break ;

#ifdef SHOW_CONTAINERS
                    case BMINDEX(IDB_CONTAINER):
                    case BMINDEX(IDB_CONTAINER32):
                        htree = m_hContainers ;
                    break ;
#endif

                    case BMINDEX(IDB_OBJECT_CONTROL):
                    case BMINDEX(IDB_OBJECT_CONTROL32):
                        htree = m_hControls ;
                    break ;

                    case BMINDEX(IDB_OBJECT):
                    case BMINDEX(IDB_OBJECT32):
                    default:
                        htree = m_hUnclassified ;
                    break ;

                }

                if (htree && htree == pnmtv->itemNew.hItem)
                {
                    RegOpenKey( hkCLSID, szCLSID, &hkClass ) ;
                    cb = sizeof(szBuf) ;
                    if (RegQueryValue( hkClass, (LPTSTR)"ToolboxBitmap32", szBuf, &cb ) == ERROR_SUCCESS ||
                        RegQueryValue( hkClass, (LPTSTR)"ToolboxBitmap", szBuf, &cb ) == ERROR_SUCCESS)
                    {
                        TCHAR * pszBitmapModule = _tcstok(szBuf, _T(","));
                        TCHAR * pszBitmapId = _tcstok(NULL, _T(","));
                        HINSTANCE hinstBitmap;
                        int nBitmapId;
                        if ((pszBitmapModule != NULL) && (pszBitmapId != NULL))
                        {
                            LPTSTR p ;
                            if (*pszBitmapModule == '"')
                            {
                                lstrcpy( pszBitmapModule, pszBitmapModule+1 ) ;
                                p = strrchr( pszBitmapModule, '"' ) ;
                                if (p) *p = '\0' ;
                            }
							nBitmapId = _ttoi(pszBitmapId);
							hinstBitmap = LoadLibraryEx(pszBitmapModule, NULL, LOAD_LIBRARY_AS_DATAFILE);
                            if (hinstBitmap && (nBitmapId > 0))
                            {
                                HBITMAP hbmGlyph = ::LoadBitmap(hinstBitmap, MAKEINTRESOURCE(nBitmapId));
                                if (hbmGlyph)
                                {                                     
                                    lpOD->m_uiBitmap = theApp.m_images.Add( CBitmap::FromHandle(hbmGlyph), RGBLTGRAY ) ;
                                    ::DeleteObject(hbmGlyph) ;
                                }
                                FreeLibrary( hinstBitmap ) ;
                            }
                        }
                    }
                    RegCloseKey( hkClass ) ;
                    ASSERT(lpOD) ;
  
                    TV_INSERTSTRUCT tvis ;
                    tvis.hParent = htree ;
                    tvis.hInsertAfter = TVI_SORT ;
                    tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE |TVIF_CHILDREN ;
                    tvis.item.cChildren = 1 ;
                    tvis.item.lParam = (LPARAM)(LPVOID)lpOD ;
                    tvis.item.pszText = szName ;
                    tvis.item.iImage = tvis.item.iSelectedImage = lpOD->m_uiBitmap ;
                    GetTreeCtrl().InsertItem( &tvis ) ;
                }
                else
                    delete lpOD ;
            }
        }
        RegCloseKey( hkCLSID ) ;
    }
}

void CObjTreeView::ExpandTypeLibs( NM_TREEVIEW* /* pnmtv */ )
{
	USES_CONVERSION;
    HKEY    hkTypeLib ;
    if (RegOpenKey( HKEY_CLASSES_ROOT, _T("TypeLib"), &hkTypeLib) == ERROR_SUCCESS)
    {
        LONG    cb ;
        TCHAR    szVer[64] ;
        TCHAR    szName[64] ;
        TCHAR    szGUID[64] ;
        TCHAR    szBuf[256] ;
        DWORD   dwIndex, dwIndex2 ;
        HKEY    hkGUID ;

        // Enum \TypeInfo
        for ( dwIndex = 0 ;
              RegEnumKey( hkTypeLib, dwIndex, szGUID, sizeof(szGUID)) == ERROR_SUCCESS ;
              ++dwIndex )
        {
            // Gotta open \TypeInfo\szGUID
            if (RegOpenKey( hkTypeLib, szGUID, &hkGUID ) == ERROR_SUCCESS)
            {
                // Enum all at this level (major.minor = name)
                for (dwIndex2 = 0 ;
                    RegEnumKey( hkGUID, dwIndex2, szVer, sizeof(szVer)) == ERROR_SUCCESS ;
                    ++dwIndex2 )
                {
                    cb = sizeof(szName);
                    if (RegQueryValue( hkGUID, (LPTSTR)szVer, szName, &cb) == ERROR_SUCCESS)
                    {
                        wsprintf( szBuf, _T("%s (Ver %s)"), (LPTSTR)szName, (LPTSTR)szVer ) ;

                        CObjectData* lpOD = new CObjectData ;
                        lpOD->m_nType = CObjectData::typeTypeLib ;
                        ::CLSIDFromString(T2OLE(szGUID), &lpOD->m_clsid);
                        lpOD->m_szProgID[0] = '\0' ;

                        lpOD->m_uiBitmap = BMINDEX(IDB_AUTOMATION) ;
                        lpOD->m_wMajorVer = (WORD)atoi( szVer ) ;
                        PTSTR p = strrchr( szVer, '.' ) ;
                        if (p)
                            lpOD->m_wMinorVer = (WORD)atoi( p+1 ) ;
                        else
                            lpOD->m_wMinorVer = 0 ;

                        TV_INSERTSTRUCT tvis ;
                        tvis.hParent = m_hTypeLibs ;
                        tvis.hInsertAfter = TVI_SORT ;
                        tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
                        tvis.item.iImage = tvis.item.iSelectedImage = lpOD->m_uiBitmap ;
                        tvis.item.lParam = (LPARAM)(LPVOID)lpOD ;
                        tvis.item.pszText = szBuf ;
                        GetTreeCtrl().InsertItem( &tvis ) ;
                    }
                }
                RegCloseKey( hkGUID ) ;
            }
        }
        RegCloseKey( hkTypeLib ) ;
    }
}

void CObjTreeView::ExpandObject( NM_TREEVIEW* pnmtv )
{
	USES_CONVERSION;
    COle2ViewDoc*   pDoc = GetDocument() ;
    TV_INSERTSTRUCT tvis ;
    CObjectData* pod = (CObjectData*)pnmtv->itemNew.lParam ;

    if (pod->m_nType == CObjectData::typeObject)
    {
        HRESULT hr = pod->CreateInstance( pDoc->m_dwClsCtx ) ;
        if (FAILED(hr))
            return ;

        tvis.hParent = pnmtv->itemNew.hItem  ;
        tvis.hInsertAfter = TVI_SORT ;
        tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE ;
        tvis.item.iImage = tvis.item.iSelectedImage = BMINDEX(IDB_INTERFACE) ;

        HKEY hk ;
        TCHAR szIID[80] ;
        IID  iid ;
        IUnknown* pfoo = NULL ;
        TCHAR szValue[256] ;
        if (RegOpenKey( HKEY_CLASSES_ROOT, _T("Interface"), &hk) == ERROR_SUCCESS)
        {
            for ( DWORD dwIndex = 0 ;
                  RegEnumKey( hk, dwIndex, szIID, sizeof(szIID)) == ERROR_SUCCESS ;
                  ++dwIndex )
            {
                LONG cb = sizeof(szValue);
                if (RegQueryValue( hk, (LPTSTR)szIID, szValue, &cb) == ERROR_SUCCESS)
                {
                    ::CLSIDFromString(T2OLE(szIID), &iid ) ;
                    if (SUCCEEDED(pod->m_punk->QueryInterface( iid, (void**)&pfoo )))
                    {
                        pfoo->Release() ;
                        pfoo = NULL ;

                        CObjectData* lpOD = new CObjectData ;
                        lpOD->m_nType = CObjectData::typeInterface ;
                        lpOD->m_clsid = iid ;
                        lpOD->m_szProgID[0] = '\0' ;
                        lpOD->m_uiBitmap = BMINDEX(IDB_INTERFACE) ;
                        lpOD->m_wMajorVer =  lpOD->m_wMajorVer  = 0 ;
                        tvis.item.lParam = (LPARAM)(LPVOID)lpOD ;
                        tvis.item.pszText = szValue ;
                        GetTreeCtrl().InsertItem( &tvis ) ;
                    }
                }
            }
            RegCloseKey( hk ) ;
        }
    }
}

void CObjTreeView::ExpandInterfaces( NM_TREEVIEW* pnmtv )
{
	USES_CONVERSION;
    if (pnmtv->itemNew.hItem == m_hInterfaces)
    {
        TV_INSERTSTRUCT tvis ;
        tvis.hParent = pnmtv->itemNew.hItem  ;
        tvis.hInsertAfter = TVI_SORT ;
        tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE ;
        tvis.item.iImage = tvis.item.iSelectedImage = BMINDEX(IDB_INTERFACE) ;

        HKEY hk ;
        TCHAR szTypeLibID[80] ;
        TCHAR szValue[256] ;
        if (RegOpenKey( HKEY_CLASSES_ROOT, _T("Interface"), &hk) == ERROR_SUCCESS)
        {
            for ( DWORD dwIndex = 0 ;
                  RegEnumKey( hk, dwIndex, szTypeLibID, sizeof(szTypeLibID)) == ERROR_SUCCESS ;
                  ++dwIndex )
            {
                LONG cb = sizeof(szValue);
                if (RegQueryValue( hk, (LPTSTR)szTypeLibID, szValue, &cb) == ERROR_SUCCESS)
                {
                    CObjectData* lpOD = new CObjectData ;
                    lpOD->m_nType = CObjectData::typeStaticInterface ;
                    ::CLSIDFromString(T2OLE(szTypeLibID), &lpOD->m_clsid );
                    lpOD->m_szProgID[0] = '\0' ;
                    lpOD->m_uiBitmap = BMINDEX(IDB_INTERFACE) ;
                    lpOD->m_wMajorVer =  lpOD->m_wMajorVer  = 0 ;
    
                    tvis.item.lParam = (LPARAM)(LPVOID)lpOD ;
                    tvis.item.pszText = szValue ;
                    GetTreeCtrl().InsertItem( &tvis ) ;
                }
            }
            RegCloseKey( hk ) ;
        }
        return ;
    }
}

void CObjTreeView::OnTreeItemExpanded(NMHDR* pNMHDR, LRESULT* pResult) 
{
	*pResult = 0;
    COle2ViewDoc*   pDoc = GetDocument() ;
	NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pNMHDR;
    if ( pnmtv->itemNew.lParam != NULL && 
         pnmtv->action == TVE_COLLAPSE)
    {
//        TV_INSERTSTRUCT tvis ;
        CObjectData* pod = (CObjectData*)pnmtv->itemNew.lParam ;

        switch(pod->m_nType)
        {
        case CObjectData::typeObject:
        {
            pod->Release() ;
            GetTreeCtrl().Expand( pnmtv->itemNew.hItem, TVE_COLLAPSERESET ) ;
        }
        break ;
        }
    }
 }

void CObjTreeView::CallInterfaceViewer(CObjectData* pObjectData, HTREEITEM hItem)
{
	COle2ViewDoc*   pDoc = GetDocument() ;

    if (pObjectData != NULL)
    {
		ASSERT_KINDOF(CObjectData,pObjectData);

        switch(pObjectData->m_nType)
        {
        case CObjectData::typeInterface:
        {
            CObjectData* podParent = NULL ;
            TV_ITEM tviParent ;
            tviParent.hItem = GetTreeCtrl().GetParentItem(hItem);
            ASSERT(tviParent.hItem) ;
            tviParent.mask = TVIF_PARAM ;
            GetTreeCtrl().GetItem( &tviParent ) ;
            if (tviParent.lParam)
            {
                podParent = (CObjectData*)tviParent.lParam ;

                ASSERT(podParent->m_punk) ;
                if (podParent->m_punk)
                    ViewInterface( theApp.m_pMainWnd->GetSafeHwnd(), pObjectData->m_clsid, podParent->m_punk ) ;
            }
        }            
        break ;

        case CObjectData::typeTypeLib:
        {
            ITypeLib* pTypeLib ;
            LCID      lcid = GetUserDefaultLCID() ;
            HRESULT hr = ::LoadRegTypeLib( pObjectData->m_clsid, pObjectData->m_wMajorVer,
                               pObjectData->m_wMinorVer, lcid, &pTypeLib ) ;
            if (FAILED(hr))
            {
				USES_CONVERSION;
                TCHAR szTemp[256] ;
				LPOLESTR lpStr;
				StringFromCLSID(pObjectData->m_clsid, &lpStr);
                wsprintf(szTemp, _T("LoadRegTypeLib(%s, %u, %u, %lu, ...) failed."),
                        OLE2CT(lpStr), pObjectData->m_wMajorVer, pObjectData->m_wMinorVer,
                        lcid);
				CoTaskMemFree(lpStr);
                ErrorMessage( szTemp, hr ) ;
            }
            else
            {
                ViewInterface( theApp.m_pMainWnd->GetSafeHwnd(), IID_ITypeLib, pTypeLib ) ;
                #ifdef _DEBUG
                ASSERT( 0 == pTypeLib->Release() ) ;
                #else
                pTypeLib->Release() ;
                #endif
            }
        }    
        break ;
        }
    }
}

void CObjTreeView::OnTreeReturn(NMHDR* /*pNMHDR */, LRESULT* pResult) 
{
	*pResult = (LRESULT)TRUE ;
    HTREEITEM hTreeItemSel = GetTreeCtrl().GetSelectedItem() ;

    if (hTreeItemSel)
        GetTreeCtrl().Expand( hTreeItemSel, TVE_TOGGLE ) ;
}

void CObjTreeView::OnTreeDeleteItem(NMHDR* pNMHDR, LRESULT*) 
{
	NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pNMHDR;

    if (pnmtv->itemOld.lParam)
    {
        CObjectData* pod = (CObjectData*)pnmtv->itemOld.lParam ;
        ASSERT(pod->IsKindOf(RUNTIME_CLASS(CObjectData)));
        delete (CObjectData*)pnmtv->itemOld.lParam ;
        pnmtv->itemOld.lParam = NULL ;
    }
}

void CObjTreeView::OnObjectDelete() 
{
	AfxMessageBox("Not implemented yet" ) ;
	
}

void CObjTreeView::OnObjectVerify() 
{
	AfxMessageBox("Not implemented yet" ) ;
	
}

BOOL CObjTreeView::IsValidSel()
{
    return (GetTreeCtrl().GetSelectedItem() != NULL) ;
}

#ifdef _DEBUG

COle2ViewDoc* CObjTreeView::GetDocument() // non-debug version is inline
{
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(COle2ViewDoc)));
    return (COle2ViewDoc*) m_pDocument;
}

#endif //_DEBUG

void CObjTreeView::OnUseInProcServer()
{
    COle2ViewDoc*   pDoc = GetDocument() ;

    if (pDoc->m_dwClsCtx & CLSCTX_INPROC_SERVER)
        pDoc->m_dwClsCtx &= ~CLSCTX_INPROC_SERVER ;
    else
        pDoc->m_dwClsCtx |= CLSCTX_INPROC_SERVER ;
    if (pDoc->m_dwClsCtx == NULL)
        pDoc->m_dwClsCtx = CLSCTX_INPROC_SERVER ;
//    OnUpdate( this, NULL, NULL ) ;
}

void CObjTreeView::OnUpdateUseInProcServer(CCmdUI* pCmdUI)
{
    COle2ViewDoc*   pDoc = GetDocument() ;
    pCmdUI->SetCheck( pDoc->m_dwClsCtx & CLSCTX_INPROC_SERVER ? TRUE : FALSE  ) ;
}

void CObjTreeView::OnUseInProcHandler()
{
    COle2ViewDoc*   pDoc = GetDocument() ;
    if (pDoc->m_dwClsCtx & CLSCTX_INPROC_HANDLER)
        pDoc->m_dwClsCtx &= ~CLSCTX_INPROC_HANDLER ;
    else
        pDoc->m_dwClsCtx |= CLSCTX_INPROC_HANDLER ;
    if (pDoc->m_dwClsCtx == NULL)
        pDoc->m_dwClsCtx = CLSCTX_INPROC_HANDLER ;
//    OnUpdate( this, NULL, NULL ) ;
}

void CObjTreeView::OnUpdateUseInProcHandler(CCmdUI* pCmdUI)
{
    COle2ViewDoc*   pDoc = GetDocument() ;
    pCmdUI->SetCheck( pDoc->m_dwClsCtx & CLSCTX_INPROC_HANDLER ? TRUE : FALSE ) ;
}

void CObjTreeView::OnUseLocalServer()
{
    COle2ViewDoc*   pDoc = GetDocument() ;
    if (pDoc->m_dwClsCtx & CLSCTX_LOCAL_SERVER)
        pDoc->m_dwClsCtx &= ~CLSCTX_LOCAL_SERVER ;
    else
        pDoc->m_dwClsCtx |= CLSCTX_LOCAL_SERVER ;

    if (pDoc->m_dwClsCtx == NULL)
        pDoc->m_dwClsCtx = CLSCTX_LOCAL_SERVER ;

//    OnUpdate( this, NULL, NULL ) ;
}

void CObjTreeView::OnUpdateUseLocalServer(CCmdUI* pCmdUI)
{
    COle2ViewDoc*   pDoc = GetDocument() ;
    pCmdUI->SetCheck( pDoc->m_dwClsCtx & CLSCTX_LOCAL_SERVER ? TRUE : FALSE ) ;
}


void CObjTreeView::OnFileBind()
{
}
