//+---------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1992-2001.
//
//  File:       V I R T U A L . C P P
//
//  Contents:   Virtual miniport class definition.
//
//  Notes:
//
//  Author:     Alok Sinha
//----------------------------------------------------------------------------

#include "virtual.h"
#include "common.h"

//+---------------------------------------------------------------------------
//
// Function:  CMuxVirtualMiniport::CMuxVirtualMiniport
//
// Purpose:   Constructor for class CMuxVirtualMiniport
//
// Arguments: None
//
// Returns:
//
// Notes:
//

CMuxVirtualMiniport::CMuxVirtualMiniport(INetCfg *pnc,
                                         GUID    *pguidMiniport,
                                         GUID    *pguidAdapter)
{
    TraceMsg( L"-->CMuxVirtualMiniport::CMuxVirtualMiniport(Constructor).\n" );

    m_pnc = pnc;
    m_pnc->AddRef();

    CopyMemory( &m_guidAdapter,
                pguidAdapter,
                sizeof(GUID) );

    if ( pguidMiniport ) {

        CopyMemory( &m_guidMiniport,
                    pguidMiniport,
                    sizeof(GUID) );

    }
    else {

        ZeroMemory( &m_guidMiniport,
                    sizeof(GUID) );
    }

    TraceMsg( L"<--CMuxVirtualMiniport::CMuxVirtualMiniport(Constructor).\n" );
}

//+---------------------------------------------------------------------------
//
// Function:  CMuxVirtualMiniport::~CMuxVirtualMiniport
//
// Purpose:   Destructor for class CMuxVirtualMiniport
//
// Arguments: None
//
// Returns:
//
// Notes:
//

CMuxVirtualMiniport::~CMuxVirtualMiniport(VOID)
{
    TraceMsg( L"-->CMuxVirtualMiniport::~CMuxVirtualMiniport(Destructor).\n" );

    ReleaseObj( m_pnc );

    TraceMsg( L"<--CMuxVirtualMiniport::~CMuxVirtualMiniport(Destructor).\n" );

}

//+---------------------------------------------------------------------------
//
// Function:  CMuxVirtualMiniport::LoadConfiguration
//
// Purpose:   Load miniport configuration from the registry.
//
// Arguments: None
//
// Returns: S_OK on success, otherwise an error code.
//
// Notes:
//

HRESULT CMuxVirtualMiniport::LoadConfiguration(VOID)
{
    TraceMsg( L"-->CMuxVirtualMiniport::LoadConfiguration.\n" );

    TraceMsg( L"<--CMuxVirtualMiniport::LoadConfiguration(HRESULT = %x).\n",
            S_OK );

    return S_OK;
}

//+---------------------------------------------------------------------------
//
// Function:  CMuxVirtualMiniport::GetAdapterGUID
//
// Purpose:   Returns the adapter GUID.
//
// Arguments:
//          OUT pguidAdapter: GUID of the adapter returned.
//
// Returns: None.
//
// Notes:
//

VOID CMuxVirtualMiniport::GetAdapterGUID (GUID *pguidAdapter)
{
    TraceMsg( L"-->CMuxVirtualMiniport::GetAdapterGUID.\n" );

    CopyMemory( pguidAdapter,
                &m_guidAdapter,
                sizeof(GUID) );

    TraceMsg( L"<--CMuxVirtualMiniport::GetAdapterGUID.\n" );
}

//+---------------------------------------------------------------------------
//
// Function:  CMuxVirtualMiniport::GetMiniportGUID
//
// Purpose:   Returns the miniport GUID.
//
// Arguments:
//          OUT pguidMiniport: GUID of the miniport returned.
//
// Returns: None.
//
// Notes:
//

VOID CMuxVirtualMiniport::GetMiniportGUID (GUID *pguidMiniport)
{
    TraceMsg( L"-->CMuxVirtualMiniport::GetMiniportGUID.\n" );

    CopyMemory( pguidMiniport,
              &m_guidMiniport,
              sizeof(GUID) );

    TraceMsg( L"<--CMuxVirtualMiniport::GetMiniportGUID.\n" );
}

//+---------------------------------------------------------------------------
//
// Function:  CMuxVirtualMiniport::Install
//
// Purpose:   Installs a virtual miniport.
//
// Arguments: None
//
// Returns: S_OK on success, otherwise an error code.
//
// Notes:
//

HRESULT CMuxVirtualMiniport::Install (VOID)
{
    INetCfgClass       *pncClass;
    INetCfgClassSetup  *pncClassSetup;
    INetCfgComponent   *pnccMiniport;
    HRESULT            hr;

    TraceMsg( L"-->CMuxVirtualMiniport::Install.\n" );

    hr = m_pnc->QueryNetCfgClass( &GUID_DEVCLASS_NET,
                                  IID_INetCfgClass,
                                  (void **)&pncClass );
    if ( hr == S_OK ) {

        hr = pncClass->QueryInterface( IID_INetCfgClassSetup,
                                       (void **)&pncClassSetup );
        if ( hr == S_OK ) {

            hr = pncClassSetup->Install( c_szMuxMiniport,
                                         NULL,
                                         0,
                                         0,
                                         NULL,
                                         NULL,
                                         &pnccMiniport );
            if ( hr == S_OK ) {

                hr = pnccMiniport->GetInstanceGuid( &m_guidMiniport );

                if ( hr != S_OK ) {

                    TraceMsg( L"   Failed to get the instance guid, uninstalling "
                              L" the miniport.\n" );

                    pncClassSetup->DeInstall( pnccMiniport,
                                              NULL,
                                              NULL );
                }

                ReleaseObj( pnccMiniport );
            }
            else {

                TraceMsg( L"   Failed to install the miniport.\n" );
            }

            ReleaseObj( pncClassSetup );
        }
        else {

            TraceMsg( L"   QueryInterface failed.\n" );
        }

        ReleaseObj( pncClass );
    }
    else {

     TraceMsg( L"   QueryNetCfgClass failed.\n" );
    }

    TraceMsg( L"<--CMuxVirtualMiniport::Install(HRESULT = %x).\n",
            hr );

    return hr;
}

//+---------------------------------------------------------------------------
//
// Function:  CMuxVirtualMiniport::DeInstall
//
// Purpose:   Uninstalls the virtual miniport.
//
// Arguments: None
//
// Returns: S_OK on success, otherwise an error code.
//
// Notes:
//

HRESULT CMuxVirtualMiniport::DeInstall (VOID)
{
    INetCfgClass       *pncClass;
    INetCfgClassSetup  *pncClassSetup;
    INetCfgComponent   *pnccMiniport;
    HRESULT            hr;

    TraceMsg( L"-->CMuxVirtualMiniport::DeInstall.\n" );

    hr = m_pnc->QueryNetCfgClass( &GUID_DEVCLASS_NET,
                                  IID_INetCfgClass,
                                  (void **)&pncClass );
    if ( hr == S_OK ) {

        hr = pncClass->QueryInterface( IID_INetCfgClassSetup,
                                       (void **)&pncClassSetup );
        if ( hr == S_OK ) {

            hr = HrFindInstance( m_pnc,
                                 m_guidMiniport,
                                 &pnccMiniport );

            if ( hr == S_OK ) {

                TraceMsg( L"   Found the miniport instance to uninstall.\n" );

                hr = pncClassSetup->DeInstall( pnccMiniport,
                                               NULL,
                                               NULL );
                ReleaseObj( pnccMiniport );
            }
            else {
                TraceMsg( L"   Didn't find the miniport instance to uninstall.\n" );
            }

            ReleaseObj( pncClassSetup );
        }
        else {

            TraceMsg( L"   QueryInterface failed.\n" );
        }

        ReleaseObj( pncClass );
    }
    else {

        TraceMsg( L"   QueryNetCfgClass failed.\n" );
    }

    TraceMsg( L"<--CMuxVirtualMiniport::DeInstall(HRESULT = %x).\n",
              hr );

    return hr;
}

//+---------------------------------------------------------------------------
//
// Function:  CMuxVirtualMiniport::ApplyRegistryChanges
//
// Purpose:   Store the changes in the registry.
//
// Arguments:
//            IN eApplyAction: Action performed.
//
// Returns: S_OK on success, otherwise an error code.
//
// Notes:
//

HRESULT CMuxVirtualMiniport::ApplyRegistryChanges(ConfigAction eApplyAction)
{
    HKEY                    hkeyAdapterGuid;
    WCHAR                   szAdapterGuid[MAX_PATH+1];
    WCHAR                   szAdapterGuidKey[MAX_PATH+1];
    WCHAR                   szMiniportGuid[MAX_PATH+1];
    LPWSTR                  lpDevice;
    LONG                    lResult = 0;

    TraceMsg( L"-->CMuxVirtualMiniport::ApplyRegistryChanges.\n" );

    switch( eApplyAction ) {

        case eActAdd:         // Virtual miniport added.

            StringFromGUID2( m_guidAdapter,
                             szAdapterGuid,
                             MAX_PATH+1 );

            swprintf( szAdapterGuidKey,
                      L"%s\\%s",
                      c_szAdapterList,
                      szAdapterGuid );

            lResult = RegCreateKeyExW( HKEY_LOCAL_MACHINE,
                                       szAdapterGuidKey,
                                       0,
                                       NULL,
                                       REG_OPTION_NON_VOLATILE,
                                       KEY_ALL_ACCESS,
                                       NULL,
                                       &hkeyAdapterGuid,
                                       NULL);


            if ( lResult == ERROR_SUCCESS ) {

                StringFromGUID2( m_guidMiniport,
                                 szMiniportGuid,
                                 MAX_PATH+1 );

                lpDevice = AddDevicePrefix( szMiniportGuid );

                if ( lpDevice ) {

#ifndef PASSTHRU_NOTIFY

                    lResult = AddToMultiSzValue( hkeyAdapterGuid,
                                                 lpDevice );
#else

                    lResult = RegSetValueExW( hkeyAdapterGuid,
                                              c_szUpperBindings,
                                              0,
                                              REG_SZ,
                                              (LPBYTE)lpDevice,
                                              (wcslen(lpDevice) + 1) *
                                              sizeof(WCHAR) );


#endif

                    if ( lResult != ERROR_SUCCESS ) {

                        TraceMsg( L"   Failed to save %s at %s\\%s.\n",
                                  lpDevice,
                                  szAdapterGuidKey,
                                  c_szUpperBindings );

                    }

                    free( lpDevice );
                }
                else {
                    lResult = ERROR_NOT_ENOUGH_MEMORY;
                }

                RegCloseKey( hkeyAdapterGuid );
            }
            else {
                TraceMsg( L"   Failed to open the registry key: %s.\n",
                          szAdapterGuidKey );
            }
            break;

        case eActRemove:                  // Virtual miniport removed.

            StringFromGUID2( m_guidAdapter,
                             szAdapterGuid,
                             MAX_PATH+1 );

            swprintf( szAdapterGuidKey,
                      L"%s\\%s",
                      c_szAdapterList,
                      szAdapterGuid );

            lResult = RegCreateKeyExW( HKEY_LOCAL_MACHINE,
                                        szAdapterGuidKey,
                                        0,
                                        NULL,
                                        REG_OPTION_NON_VOLATILE,
                                        KEY_ALL_ACCESS,
                                        NULL,
                                        &hkeyAdapterGuid,
                                        NULL);


            if ( lResult == ERROR_SUCCESS ) {

                StringFromGUID2( m_guidMiniport,
                                 szMiniportGuid,
                                 MAX_PATH+1 );

                lpDevice = AddDevicePrefix( szMiniportGuid );
                TraceMsg( L"   Deleting %s at %s.\n",
                          lpDevice,
                          szAdapterGuidKey );

                if ( lpDevice ) {

#ifndef PASSTHRU_NOTIFY

                    lResult = DeleteFromMultiSzValue( hkeyAdapterGuid,
                                                      lpDevice );
#else

                    lResult = RegDeleteValueW( hkeyAdapterGuid,
                                               c_szUpperBindings );
#endif

                    if ( lResult != ERROR_SUCCESS ) {

                        TraceMsg( L"   Failed to delete %s at %s\\%s.\n",
                                  lpDevice,
                                  szAdapterGuidKey,
                                  c_szUpperBindings );

                    }

                    free( lpDevice );
                }

                RegCloseKey( hkeyAdapterGuid );
            }
            else {
                TraceMsg( L"   Failed to open the registry key: %s.\n",
                          szAdapterGuidKey );
            }
    }

    TraceMsg( L"<--CMuxVirtualMiniport::ApplyRegistryChanges(HRESULT = %x).\n",
              HRESULT_FROM_WIN32(lResult) );

    return HRESULT_FROM_WIN32(lResult);
}

//+---------------------------------------------------------------------------
//
// Function:  CMuxVirtualMiniport::ApplyPnpChanges
//
// Purpose:   
//
// Arguments:
//            IN eApplyAction: Action performed.
//
// Returns: S_OK on success, otherwise an error code.
//
// Notes:
//

HRESULT CMuxVirtualMiniport::ApplyPnpChanges
                                 (INetCfgPnpReconfigCallback *pfCallback,
                                  ConfigAction eApplyAction)
{
    TraceMsg( L"-->CMuxVirtualMiniport::ApplyPnpChanges.\n" );

    TraceMsg( L"<--CMuxVirtualMiniport::ApplyPnpChanges(HRESULT = %x).\n",
            S_OK );

    return S_OK;
}