/*++

Copyright (c) 1997  Microsoft Corporation

Module Name:

    iroot.cpp

Abstract:

    Internal implementation for the root subfolder.

Environment:

    WIN32 User Mode

Author:

    Darwin Ouyang (t-darouy) 30-Sept-1997

--*/ 

#include "StdAfx.h"

#include "inode.h"          // base class
#include "iroot.h"          // root folder

#include "idevices.h"       // devices folder
#include "ilogging.h"       // logging folder

#include "faxsnapin.h"      // snapin 
#include "faxdataobj.h"     // dataobject
#include "faxhelper.h"      // ole helper functions
#include "faxstrt.h"        // string table
#include "faxsecinfo.h"     // fax security info

#include "dgenprop.h"       // general property sheet
#include "droutpri.h"       // routing priority property sheet
#include <aclui.h>          // acl editor property sheet

#pragma hdrstop

// context menu command
#define RECONNECT_SERVER        101

extern CStringTable * GlobalStringTable;

// Generated with uuidgen. Each node must have a GUID associated with it.
// This one is for the main root node.
const GUID GUID_RootNode = /* 8f39b047-3071-11d1-9067-00a0c90ab504 */
{
    0x8f39b047,
    0x3071,
    0x11d1,
    {0x90, 0x67, 0x00, 0xa0, 0xc9, 0x0a, 0xb5, 0x04}
};

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// Constructor and destructor
//
//

CInternalRoot::CInternalRoot(
                            IN CInternalNode * pParent, 
                            IN CFaxComponentData * pCompData ) 
: CInternalNode( this, pCompData )
/*++

Routine Description:

    Constructor

Arguments:

    pParent - pointer to parent node, in this case unused
    pCompData - pointer to IComponentData implementation for snapin global data

Return Value:

    None.    

--*/
{
    iDevices    = NULL;
    iLogging    = NULL;   

    targetFaxServName = NULL;           
    m_pCompData->m_FaxHandle = NULL;
    localNodeName = NULL;
    pMyPropSheet = NULL;
    pMyPropSheet2 = NULL;
    m_myPropPage = NULL;
}

CInternalRoot::~CInternalRoot()
/*++

Routine Description:

    Destructor

Arguments:

    None.

Return Value:

    None.    

--*/
{
    if(iDevices != NULL ) {
        delete iDevices;
    }
    if(iLogging != NULL ) {
        delete iLogging;
    }
    if(m_pCompData->m_FaxHandle != NULL ) {
        FaxClose( m_pCompData->m_FaxHandle ); // close the connection
        m_pCompData->m_FaxHandle = NULL;     
    }
    if(targetFaxServName != NULL ) {
        delete targetFaxServName;
    }

}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// Mandatory CInternalNode implementations.
//
//

const GUID * CInternalRoot::GetNodeGUID()
/*++

Routine Description:

    Returns the node's associated GUID.

Arguments:

    None.

Return Value:

    A const pointer to a binary GUID.    

--*/
{
//    DebugPrint(( TEXT("Trace: CInternalRoot::GetNodeGUID") ));
    return &GUID_RootNode;
}

const LPTSTR 
CInternalRoot::GetNodeDisplayName()
/*++

Routine Description:

    Returns a const TSTR pointer to the node's display name.

Arguments:

    None.

Return Value:

    A const pointer to a TSTR.

--*/
{
//    DebugPrint(( TEXT("Trace: CInternalRoot::GetNodeDisplayName") ));
    if( localNodeName == NULL ) {
        if( targetFaxServName != NULL ) {
            // remote machine
            localNodeName = new TCHAR[  StringSize(  (::GlobalStringTable->GetString(IDS_ROOTNODENAME)) )
                                        + StringSize( targetFaxServName ) 
                                        + 1 ];

            assert( localNodeName != NULL );
            if (!localNodeName) {
                return NULL;
            }

            _tcscpy( localNodeName, ::GlobalStringTable->GetString(IDS_ROOTNODENAME) );
            _tcscat( localNodeName, targetFaxServName );
        } else {
            // local machine
            localNodeName = new TCHAR[  StringSize(  (::GlobalStringTable->GetString(IDS_ROOTNODENAME)) )
                                        + StringSize( ::GlobalStringTable->GetString(IDS_LOCALMACHINE) )
                                        + 1 ];

            assert( localNodeName != NULL );
            if (!localNodeName) {
                return NULL;
            }

            _tcscpy( localNodeName, ::GlobalStringTable->GetString(IDS_ROOTNODENAME) );
            _tcscat( localNodeName, ::GlobalStringTable->GetString(IDS_LOCALMACHINE) );
        }

    }

    return localNodeName;
}

const LONG_PTR
CInternalRoot::GetCookie()
/*++

Routine Description:

    Returns the cookie for this node.

Arguments:

    None.

Return Value:

    A const long containing the cookie for the pointer,
    in this case, a NULL, since the root node has no cookie.    

--*/
{
    DebugPrint(( TEXT("Root Node Cookie: NULL") ));
    return NULL; // root node has no cookie.
}

void         
CInternalRoot::SetMachine(
                         IN LPTSTR theName )
/*++

Routine Description:

    Sets the machine name for the root node. This is used by all other nodes
    to determine the target machine name.

Arguments:

    A LPTSTR pointing to the machine name. It will be string copied to an internal store.

Return Value:

    None.    

--*/
{
    if(theName != NULL ) {
        targetFaxServName = new TCHAR[ MAX_COMPUTERNAME_LENGTH + 1 ];
        if (!targetFaxServName) {
            return;
        }
        ZeroMemory( (PVOID) targetFaxServName, (MAX_COMPUTERNAME_LENGTH + 1) * sizeof( TCHAR ) );
        _tcsncpy( targetFaxServName, theName, MAX_COMPUTERNAME_LENGTH );
        targetFaxServName[MAX_COMPUTERNAME_LENGTH] = 0;
    } else {
        targetFaxServName = NULL;
    }
}

const LPTSTR
CInternalRoot::GetMachine()
/*++

Routine Description:

    Returns the machine name for the root node. This is used by all other
    nodes to determine the target machine name.

Arguments:

    None.

Return Value:

    A const LPTSTR pointing to the machine name. Do not free this string, it is an internal
    buffer.

--*/
{
    return targetFaxServName;
}    

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// 
// Internal Event Handlers
//
//

HRESULT
CInternalRoot::ScopeOnExpand(
                            IN CFaxComponentData * pCompData,
                            IN CFaxDataObject * pdo, 
                            IN LPARAM arg, 
                            IN LPARAM param )
/*++

Routine Description:

    Event handler for the MMCN_EXPAND message for the root node.

Arguments:

    pCompData - a pointer to the instance of IComponentData which this root node is associated with.
    pdo - a pointer to the data object associated with this node
    arg, param - the arguements of the message

Return Value:

    HRESULT which indicates SUCCEEDED() or FAILED()

--*/
{
    DebugPrint(( TEXT("Trace: CInternalRoot::ScopeOnExpand") ));

    INT             iResult;
    HRESULT         hr = S_OK;        
    LPCONSOLE       console = pCompData->m_pConsole;
    HANDLE          targetFaxServHandle = NULL;
    DWORD           descCount = 0;

    assert(console != NULL);    // make sure we QI'ed for the interface

    if(arg == TRUE) { // folder needs to be expanded
        DebugPrint(( TEXT("Trace: CInternalRoot::ScopeOnExpand - Expand folder") ));

        if(!pdo) {
            hr = console->MessageBox(::GlobalStringTable->GetString( IDS_CORRUPT_DATAOBJECT ), 
                                     ::GlobalStringTable->GetString( IDS_ERR_TITLE ), 
                                     MB_OK, 
                                     &iResult);
            hr = E_INVALIDARG;
            return hr;
        }

        // Make sure that what we are placing ourselves under is the root node!
        if(pdo->GetCookie() != NULL)
            return S_FALSE;

        assert(pdo->GetContext() == CCT_SCOPE);

        //
        // Open the fax server connection.
        //

        try {
            if( FaxConnectFaxServer( targetFaxServName, &targetFaxServHandle ) == FALSE ) {
                m_pCompData->NotifyRpcError( TRUE );
                hr = console->MessageBox(::GlobalStringTable->GetString( IDS_FAX_CONNECT_SERVER_FAIL ), 
                                         ::GlobalStringTable->GetString( IDS_ERR_TITLE ), 
                                         MB_OK, 
                                         &iResult);
                DebugPrint(( TEXT("Trace: CInternalRoot::ScopeOnExpand - open connection fail") ));        
                hr = E_UNEXPECTED;
            } else {
                // sucessful connect!
                m_pCompData->NotifyRpcError( FALSE );
            }            
        } catch( ... ) {
            m_pCompData->NotifyRpcError( TRUE );
            console->MessageBox(::GlobalStringTable->GetString( IDS_FAX_CONNECT_SERVER_FAIL ), 
                                     ::GlobalStringTable->GetString( IDS_ERR_TITLE ), 
                                     MB_OK, 
                                     &iResult);
            hr = E_UNEXPECTED;
            DebugPrint(( TEXT("Trace: CInternalRoot::ScopeOnExpand - open connection fail") ));        
        }

        //
        // short circuit if we failed to connect to faxsvc
        //
        if (FAILED(hr)) {
            return(hr);
        }

        m_pCompData->m_FaxHandle = targetFaxServHandle;

        //
        // Place our folder into the scope pane
        //

        // create a new internal representation of the devices folder.
        iDevices = new CInternalDevices( this, m_pCompData );        
        
        assert( iDevices != NULL );
        if (!iDevices) {
            return(E_OUTOFMEMORY);
        }
        
        // insert devices folder
        hr = InsertItem( iDevices, param );

        // create a new internal representation of the logging folder.
        iLogging = new CInternalLogging( this, m_pCompData );        
        
        assert( iLogging != NULL );
        if (!iLogging) {
            return(E_OUTOFMEMORY);
        }

        // insert logging folder
        hr = InsertItem( iLogging, param );
    } else if(arg == FALSE ) {
        DebugPrint(( TEXT("Trace: CInternalRoot::ScopeOnExpand - Contract folder") ));
    }

    return hr;    
}

HRESULT 
CInternalRoot::ResultOnShow(
                           IN CFaxComponent* pComp, 
                           IN CFaxDataObject * lpDataObject, 
                           IN LPARAM arg, 
                           IN LPARAM param)
/*++

Routine Description:

    Event handler for the MMCN_SHOW message for the root node.

Arguments:

    pCompData - a pointer to the instance of IComponentData which this root node is associated with.
    lpDataObject - a pointer to the data object containing context information for this node.
    pdo - a pointer to the data object associated with this node
    arg, param - the arguements of the message

Return Value:

    HRESULT which indicates SUCCEEDED() or FAILED()

--*/
{
    LPHEADERCTRL    pIHeaderCtrl = pComp->m_pHeaderCtrl;    
    HRESULT         hr = S_OK;

    DebugPrint(( TEXT("Trace: CInternalRoot::ResultOnShow") ));

    assert( pIHeaderCtrl != NULL );

    if( arg == TRUE ) {
        do {
            // insert the icons into the image list
            hr = pComp->InsertIconsIntoImageList();
            assert( SUCCEEDED( hr ) );
            if( FAILED( hr ) ) {
                break;
            }

            hr = pIHeaderCtrl->InsertColumn( 0,  
                                             ::GlobalStringTable->GetString( IDS_ROOT_NAME ), 
                                             LVCFMT_LEFT, 
                                             MMCLV_AUTO );
            if( FAILED( hr ) ) {
                break;
            }

            hr = pIHeaderCtrl->InsertColumn( 1, 
                                             ::GlobalStringTable->GetString( IDS_ROOT_DESC ),
                                             LVCFMT_LEFT, 
                                             MMCLV_AUTO );                                             
            if( FAILED( hr ) ) {
                break;
            }
        } while( 0 );
    }
    return hr;
}

HRESULT 
CInternalRoot::ResultOnSelect(
                             IN CFaxComponent* pComp, 
                             IN CFaxDataObject * lpDataObject, 
                             IN LPARAM arg, 
                             IN LPARAM param)
/*++

Routine Description:

    Event handler for the MMCN_SELECT message for the root node.

Arguments:

    pCompData - a pointer to the instance of IComponentData which this root node is associated with.
    pdo - a pointer to the data object associated with this node
    arg, param - the arguements of the message

Return Value:

    HRESULT which indicates SUCCEEDED() or FAILED()

--*/
{
    DebugPrint(( TEXT("Trace: CInternalRoot::ResultOnSelect") ));
    if( m_pCompData->QueryRpcError() == FALSE ) {
        pComp->m_pConsoleVerb->SetVerbState( MMC_VERB_PROPERTIES, ENABLED, TRUE );    
        pComp->m_pConsoleVerb->SetDefaultVerb( MMC_VERB_OPEN );
    } else {
        pComp->m_pConsoleVerb->SetVerbState( MMC_VERB_PROPERTIES, ENABLED, FALSE );        
        pComp->m_pConsoleVerb->SetDefaultVerb( MMC_VERB_NONE );
    }

    return S_OK;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// IExtendPropertySheet implementation
//
//

HRESULT 
STDMETHODCALLTYPE 
CInternalRoot::ComponentDataPropertySheetCreatePropertyPages(
                                                            IN CFaxComponentData * pCompData,
                                                            IN LPPROPERTYSHEETCALLBACK lpProvider,
                                                            IN LONG_PTR handle,
                                                            IN CFaxDataObject * lpIDataObject)
/*++

Routine Description:

    Event handler for the MMCN_EXPAND message for the root node.

Arguments:

    pCompData - a pointer to the instance of IComponentData which this root node is associated with.
    pdo - a pointer to the data object associated with this node
    arg, param - the arguements of the message

Return Value:

    HRESULT which indicates SUCCEEDED() or FAILED()

--*/
{
    DebugPrint(( TEXT("Trace: CInternalDevice::ComponentPropertySheetCreatePropertyPages") ));
    assert( lpIDataObject != NULL );
    assert( lpProvider != NULL );

    HRESULT                             hr;
    BOOL                                bResult = FALSE;
    PFAX_SECURITY_DESCRIPTOR            pSecurityDescriptor = NULL;
    CFaxSecurityInformation *           psi = NULL;
    DWORD                               descCount = 0;

    PFAX_GLOBAL_ROUTING_INFO            pRoutingMethod;    
    DWORD                               iRoutingMethodCount;
    DWORD                               i;
    WCHAR                               DllName[MAX_PATH];
    BOOL                                bUnknownMethod = FALSE;

    if( m_pCompData->QueryRpcError() == TRUE ) {
        assert( FALSE );
        return E_UNEXPECTED;   
    }

    if( lpIDataObject == NULL || lpProvider == NULL ) {
        assert(FALSE);
        return E_POINTER;
    }

    pMyPropSheet = new CFaxGeneralSettingsPropSheet( ::GlobalStringTable->GetInstance(), handle, this );
    if (!pMyPropSheet) {
        hr = E_OUTOFMEMORY;
        goto e0;
    }
    
    hr = lpProvider->AddPage( pMyPropSheet->GetHandle() );
    if (FAILED(hr)) {
        goto e1;        
    }

    try {
        //
        // do routing priority page
        //

        //
        // Check if we have non "default" extensions
        //
       

       if( !FaxEnumGlobalRoutingInfo( m_pCompData->m_FaxHandle, 
                                      &pRoutingMethod, 
                                      &iRoutingMethodCount ) ) {
           if (GetLastError() != ERROR_ACCESS_DENIED) {
               m_pCompData->NotifyRpcError( TRUE );
               assert(FALSE);
           }
           ::GlobalStringTable->SystemErrorMsg( GetLastError() );
           hr = E_UNEXPECTED;           
           goto e1;
       } else {

         // go through the routing methods ensuring that
         // we know of all of them
         DWORD retval;
         retval = ExpandEnvironmentStrings(MSFAX_EXTENSION,DllName,MAX_PATH);
         if (retval == 0 || retval > MAX_PATH) {
             hr = E_OUTOFMEMORY;
             goto e1;
         }

         for( i=0; i<iRoutingMethodCount; i++ ) {
            if(wcscmp( pRoutingMethod[i].ExtensionImageName, DllName ) != 0) {
               bUnknownMethod = TRUE;
               break;
            }
         }

         FaxFreeBuffer( (PVOID)pRoutingMethod );
         
         // if we bumped into a method we don't know
         // then we put up the routing property sheet
         if( bUnknownMethod == TRUE ) {       
            pMyPropSheet2 = new CFaxRoutePriPropSheet( ::GlobalStringTable->GetInstance(), handle, this, NULL );
            if (!pMyPropSheet2) {
                hr = E_OUTOFMEMORY;
                goto e1;
            }
            hr = lpProvider->AddPage( pMyPropSheet2->GetHandle() );
            if (FAILED(hr)) {
                goto e2;
            }
         }
         
       }       
    
       if( FaxGetSecurityDescriptorCount( m_pCompData->m_FaxHandle, &descCount ) ) {        
       // if there is only one descriptor we might as well just stick it in
       // the root node
            if( descCount == 1 ) {                
                psi = new CComObject<CFaxSecurityInformation>;
                if (!psi) {
                    hr = E_OUTOFMEMORY;
                    goto e2;
                }

                psi->SetOwner( this );
                if( SUCCEEDED( psi->SetSecurityDescriptor( 0 ) ) ) {
                    m_myPropPage = CreateSecurityPage( psi );
                    hr = lpProvider->AddPage( m_myPropPage );
                } else {
                    goto e3;                    
                }
    
                FaxFreeBuffer( (PVOID)pSecurityDescriptor );            
            }
        }
    } catch ( ... ) {
        assert( FALSE );
        DebugPrint(( TEXT("Trace: CInternalRoot::ComponentDataPropertySheetCreatePropertyPages - RPC connection fail") ));        
        m_pCompData->NotifyRpcError( TRUE );
        hr = E_UNEXPECTED;
    }

    return hr;

e3:
    if (psi) delete(psi);
e2: 
    if (pMyPropSheet2) delete(pMyPropSheet2);
e1:
    if (pMyPropSheet) delete(pMyPropSheet);
e0:
    return(hr);
}

HRESULT 
STDMETHODCALLTYPE 
CInternalRoot::ComponentDataPropertySheetQueryPagesFor(
                                                      IN CFaxComponentData * pCompData,
                                                      IN CFaxDataObject * lpDataObject)
/*++

Routine Description:

    Returns S_OK to indicated there are property pages for this node.

Arguments:

    pCompData - a pointer to the instance of IComponentData which this root node is associated with.
    lpDataObject - a pointer to the data object associated with this node    

Return Value:

    HRESULT which indicates SUCCEEDED() or FAILED()

--*/
{
    DebugPrint(( TEXT("Trace: CInternalDevice::ComponentPropertySheetQueryPagesFor") ));
    return S_OK;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// IExtendContextMenu implementation
//
//

HRESULT
STDMETHODCALLTYPE 
CInternalRoot::ComponentDataContextMenuAddMenuItems(
                                                   IN CFaxComponentData * pCompData,
                                                   IN CFaxDataObject * piDataObject,
                                                   IN LPCONTEXTMENUCALLBACK piCallback,
                                                   IN OUT long __RPC_FAR *pInsertionAllowed)
/*++

Routine Description:

    Adds the context menu items to the root node.

Arguments:

    pCompData - a pointer to the instance of IComponentData which this root node is associated with.
    piDataObject - a pointer to the data object associated with this node
    piCallback - a pointer the the IContextMenuCallback supplied by the MMC
    pInsertionAllowed - a set of flags to indicate whether context menu insertion is allows

Return Value:

    HRESULT which indicates SUCCEEDED() or FAILED()

--*/
{       
    DebugPrint(( TEXT("Trace: CInternalDevice::ComponentContextMenuAddMenuItems") ));

    CONTEXTMENUITEM menuItem;    
    HRESULT         hr = S_OK;

    if( !( *pInsertionAllowed | CCM_INSERTIONALLOWED_TOP ) ) {
        assert( FALSE );
        return E_UNEXPECTED;
    }

    if( m_pCompData->QueryRpcError() == TRUE ) {

        // build the submenu items

        ZeroMemory( ( void* )&menuItem, sizeof( menuItem ) );

        menuItem.strName = ::GlobalStringTable->GetString( IDS_RECONNECT );
        menuItem.strStatusBarText = ::GlobalStringTable->GetString( IDS_RECONNECT_DESC );
        menuItem.lCommandID = RECONNECT_SERVER;
        menuItem.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_TOP;
        menuItem.fFlags = MF_ENABLED;
        menuItem.fSpecialFlags = CCM_SPECIAL_DEFAULT_ITEM;

        hr = piCallback->AddItem( &menuItem );
        if( FAILED(hr) ) {
            assert(FALSE);
            return hr;
        }

    }

    return hr;
}


HRESULT 
STDMETHODCALLTYPE 
CInternalRoot::ComponentDataContextMenuCommand(
                                              IN CFaxComponentData * pCompData,
                                              IN long lCommandID,
                                              IN CFaxDataObject * piDataObject)
/*++

Routine Description:

    Handles the context menu events.

Arguments:

    pCompData - a pointer to the instance of IComponentData which this root node is associated with.
    lCommandID - the command ID.
    piDataObject - a pointer to the data object associated with this node

Return Value:

    HRESULT which indicates SUCCEEDED() or FAILED()

--*/
{
    DebugPrint(( TEXT("Trace: CInternalRoot::ComponentDataContextMenuCommand") ));

    HRESULT                 hr = S_OK;
    HANDLE                  targetFaxServHandle = NULL;
    int                     iResult;        

    do {
        switch( lCommandID ) {
            case RECONNECT_SERVER:
                //
                // Re-open the fax server connection.
                //

                try {

                    if( FaxConnectFaxServer( targetFaxServName, &targetFaxServHandle ) == FALSE ) {
                        m_pCompData->NotifyRpcError( TRUE );
                        hr = m_pCompData->m_pConsole->MessageBox(::GlobalStringTable->GetString( IDS_FAX_CONNECT_SERVER_FAIL ), 
                                                                 ::GlobalStringTable->GetString( IDS_ERR_TITLE ), 
                                                                 MB_OK, 
                                                                 &iResult);
                        DebugPrint(( TEXT("Trace: CInternalRoot::ComponentDataContextMenuCommand - RE-OPEN connection fail") ));
                    } else {
                        // sucessful connect!
                        m_pCompData->NotifyRpcError( FALSE );                        
                    }

                } catch( ... ) {
                    m_pCompData->NotifyRpcError( TRUE );
                    m_pCompData->m_pConsole->MessageBox(::GlobalStringTable->GetString( IDS_FAX_CONNECT_SERVER_FAIL ), 
                                                             ::GlobalStringTable->GetString( IDS_ERR_TITLE ), 
                                                             MB_OK, 
                                                             &iResult);
                    DebugPrint(( TEXT("Trace: CInternalRoot::ComponentDataContextMenuCommand - RE-OPEN connection fail") ));
                    hr = E_UNEXPECTED;
                    break;
                }
                m_pCompData->m_FaxHandle = targetFaxServHandle;
                break;

            default:
                assert(FALSE);
                hr = E_UNEXPECTED;
                break;

        }

    } while( 0 );

    return hr;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// Utility Function
// 
//

HRESULT 
CInternalRoot::InsertItem(
                         IN CInternalNode * iCookie, 
                         IN LPARAM param )
/*++

Routine Description:

    Wrapper that inserts an item into a scope view pane given a cookie.

Arguments:

    iCookie - the cookie of the node that needs to be inserted into the view
    param - the HRESULTITEM of the parent to the node being inserted

Return Value:

    HRESULT which indicates SUCCEEDED() or FAILED()

--*/
{
    SCOPEDATAITEM sdi;
    LPCONSOLENAMESPACE consoleNameSpace = m_pCompData->m_pConsoleNameSpace;
    assert(consoleNameSpace != NULL); // make sure we QI'ed for the interface

    ZeroMemory(&sdi, sizeof sdi);
    sdi.mask        = SDI_STR       | // displayname is valid
                      SDI_PARAM     | // lParam is valid
                      SDI_IMAGE     | // nImage is valid
                      SDI_OPENIMAGE | // nOpenImage is valid
                      SDI_CHILDREN  | // cChildren is valid
                      SDI_PARENT;
    sdi.relativeID  = (HSCOPEITEM) param;
    sdi.nImage      = iCookie->GetNodeDisplayImage();
    sdi.nOpenImage  = iCookie->GetNodeDisplayOpenImage();
    sdi.displayname = MMC_CALLBACK;
    sdi.cChildren = 0;
    sdi.lParam = (LPARAM) iCookie; // The cookie

    return consoleNameSpace->InsertItem(&sdi);   
}