#include "pch.hxx"
#pragma hdrstop

#include "resource.h"
#include "infprod.h"
#include "addopt.h"
#include "setupapi.h"



BOOL CAddListView::OnClick()
{
    BOOL fEnable;
    CAddOptionDialog* pParent = GetParentObject(CAddOptionDialog, m_list);
    int sel =  GetCurrentSelection();
    fEnable = (sel != -1);

    if (sel != -1)
    {
        // Get the item data and see if it is the message string
            LV_ITEM lvi;
            lvi.mask = LVIF_PARAM;
            lvi.iSubItem = 0;
            lvi.iItem = sel;
            ListView_GetItem(*this, &lvi);
            if (lvi.lParam == -1)
                return FALSE;
    }

    EnableWindow(GetDlgItem(*pParent, IDOK), fEnable);
    return fEnable;
}

BOOL CAddListView::OnDoubleClick()
{
    CAddOptionDialog* pParent = GetParentObject(CAddOptionDialog, m_list);

    ASSERT(pParent != NULL);

    if (OnClick())
    {
        pParent->OnOk();
    }
    return CListView::OnDoubleClick();
}

CAddOptionDialog::CAddOptionDialog(OptionTypes eType, NCP* pNcp, CPtrList* pList)
{
    m_eType = eType;    
    m_tid = 0;
    m_mainThread = 0;
    m_hEvent = 0;
    m_nImage = 0;    
    m_hImage = 0;
    m_bWaitCursor = FALSE;
    m_hThread = 0;
    m_pInfProduct = 0;
    m_pNcp = pNcp;

    m_bHaveDisk = FALSE;        
    m_hHaveDiskThread = 0;

    if (pList == NULL)
    {
        m_optionList = new CPtrList;
        m_bDeleteList = TRUE;
    }
    else
    {
        m_optionList = pList;
        m_bDeleteList = FALSE;
    }
}

CAddOptionDialog::~CAddOptionDialog()
{
}

BOOL CAddOptionDialog::OnInitDialog()
{
    HWND hDlg = *this;

    // Attach list view and set images
    m_list.Create(hDlg, IDC_LISTVIEW, LVS_SHOWSELALWAYS);
    m_hImage = ImageList_LoadBitmap(g_hinst, MAKEINTRESOURCE(IDB_IMAGELIST), 16, 0,RGB(0,128,128));
    ListView_SetImageList(m_list, m_hImage, LVSIL_SMALL);

    // Changes the style of the static control so it displays
    HWND hLine = GetDlgItem(hDlg, IDC_STATIC_LINE);
    SetWindowLong(hLine, GWL_EXSTYLE, WS_EX_STATICEDGE |GetWindowLong(hLine, GWL_EXSTYLE));
    SetWindowPos(hLine, 0, 0,0,0,0, SWP_FRAMECHANGED|SWP_NOMOVE|
                            SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE);

    RECT rect;

    if (m_bDeleteList == FALSE)
    {
        CenterDialogToScreen(hDlg); // wizard mode
    }
    else
    {
        CascadeDialogToWindow( hDlg, DialogParent(), FALSE );
    }   

    // Load correct icon for add option, service by default
    UINT nIcon = IDI_CLIENT;
    UINT nDialogTitle = IDS_SELECT_SERVICE;
    UINT nString = IDS_SELECT_OPTION_SERVICE;
    m_nImage = ILI_CLIENT;
    
    if (m_eType == ADAPTER)
    {
        m_nImage = ILI_NETCARD;
        nIcon = IDI_ADAPTER;  
        nDialogTitle = IDS_SELECT_ADAPTER;  
        nString = IDS_SELECT_OPTION_ADAPTER;
    }
    else if (m_eType == PROTOCOL)
    {
        m_nImage = ILI_PROTOCOL;
        nIcon = IDI_PROTOCOL;
        nDialogTitle = IDS_SELECT_PROTOCOL; 
        nString = IDS_SELECT_OPTION_PROTOCOL;
    }

    // Set Icon
    HICON hIcon = LoadIcon(g_hinst, MAKEINTRESOURCE(nIcon));
    ASSERT(hIcon);

    if (hIcon)
        SendDlgItemMessage(hDlg, IDC_SELECT_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);

    // Build display strings
    String fmt;
    String type, data;
    String text, text2;

    // Dialog Title
    fmt.LoadString(g_hinst, IDS_SELECT_TITLE);
    type.LoadString(g_hinst, nDialogTitle);
    text.Format(fmt, (LPCTSTR)type);
    SetWindowText(hDlg, (LPCTSTR)text);


    // Set static text to the correct context
    fmt.LoadString(g_hinst, nString);
    data.LoadString(g_hinst, nDialogTitle);  // used later, don't modify
    text.Format(fmt, (LPCTSTR)data);
    fmt.LoadString(g_hinst, IDS_SELECT_OPTION_FMT);
    text2.Format(fmt, (LPCTSTR)text);
    SetDlgItemText(hDlg, IDC_DESCRIPTION, text2);

    // Listview title
    fmt.LoadString(g_hinst, IDS_SELECT_LV_TITLE);
    text.Format(fmt, (LPCTSTR)data);
    SetDlgItemText(hDlg, IDC_DESCRIPTIONSTATIC, text);

    // Prepare Listview
    m_list.InsertColumn(0, _T(" "));
    GetClientRect(m_list, &rect);
    rect.right -= GetSystemMetrics(SM_CXVSCROLL);
    m_list.SetColumnWidth(0, rect.right);

    m_list.DeleteAllItems();
    fmt.LoadString(g_hinst, IDS_SELECT_LV_MESSAGE);
    text.Format(fmt, (LPCTSTR)data);

    // Building ... wait message
    m_list.InsertItem(0, (LPCTSTR)text, m_nImage, (void*)-1);      

    // turn off ok button
    EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);

    // Sync the message queue creation and creat the worker thread
    m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    m_mainThread = GetCurrentThreadId();


    // Disable HaveDisk button until the list is populated and reenable it in
    // OnPrivateMessage
    EnableWindow(GetDlgItem(hDlg, IDC_HAVEDISK), FALSE);

    // If I create the list, start the thread
    if (m_bDeleteList == TRUE)
    {
        m_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)BuildList, this, 0, &m_tid); 

        WaitForSingleObject(m_hEvent, INFINITE);
        ResetEvent(m_hEvent);   // reset event object to a known state
        m_bWaitCursor = TRUE;  // start wait cursor
    }
    else
        OnPrivateMessage();  // list was provided, populate the listview
       
    return TRUE;
}

BOOL CAddOptionDialog::SetSelectedItem(int nListItem)
{
    int nCount = m_list.GetItemCount();

    if (nCount == 0)
        return FALSE;

    delete m_pInfProduct;
    m_pInfProduct = NULL;

    if (nListItem < 0 || nListItem >= nCount)
    {
        ASSERT(FALSE);
        return FALSE;
    }

    POSITION pos = m_optionList->GetHeadPosition();
    InfProduct* pItem = NULL;

    if (pos == NULL)
    {
        ASSERT(FALSE);
        return FALSE;
    }

    // get the selected text from the list view and find it in the internal list
    // Note: the items in the listview are sorted compared to the internal list

    TCHAR buf[256]={0};
    BOOL bMatch = FALSE;

    m_list.GetItem(nListItem, 0, buf, _countof(buf)-1);

    while(pos)
    {
        pItem = (InfProduct*)m_optionList->GetNext(pos);
        ASSERT(pItem != NULL);

        if(_tcscmp(buf, pItem->QueryDescription()) == 0)
        {
            bMatch = TRUE;
            break;
        }
    }
    
    ASSERT(bMatch == TRUE);
    m_pInfProduct = new InfProduct(*pItem);

    return TRUE;
}

BOOL CAddOptionDialog::GetSelectedItem(InfProduct* pItem)
{
    ASSERT(pItem != NULL);

    if (m_pInfProduct == NULL)
        return FALSE;

    *pItem = *m_pInfProduct;

    return TRUE;
}

BOOL CAddOptionDialog::OnCommand(WPARAM wParam, LPARAM lParam)
{
    if (wParam == IDC_HAVEDISK)
    {
        OnHaveDisk();
        return TRUE;
    }

    return CDialog::OnCommand(wParam, lParam);
}

BOOL CAddOptionDialog::OnNotify(WPARAM wParam, LPARAM lParam)
{
    return m_list.OnNotify(wParam, lParam);
}

DWORD HaveDisk(LPDWORD lpdwParam) 
{
    CAddOptionDialog* dlg = (CAddOptionDialog*)lpdwParam;
    HWND hDlg = *dlg;

    ASSERT(dlg);

    DWORD dwType = QIFT_SERVICES;

    if (dlg->m_eType == ADAPTER)
    {
        dwType =  QIFT_ADAPTERS;
    }
    else if(dlg->m_eType == PROTOCOL)
    {
        dwType =  QIFT_PROTOCOLS;
    }

    SetEvent(dlg->m_hEvent);

    ASSERT(dlg->m_pNcp != NULL);
    dlg->m_pNcp->HaveDisk(hDlg, dwType);

    PostMessage(*dlg, CDialog::PRIVATE_MSG, 0,0);

    return 0;
}

void CAddOptionDialog::OnHaveDisk()
{
    UINT tid;
    m_hHaveDiskThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)HaveDisk, this, 0, &m_tid); 

    if (m_hHaveDiskThread)
    {
        m_bHaveDisk = TRUE;        
        ASSERT(m_hEvent);
        WaitForSingleObject(m_hEvent, INFINITE);
        ResetEvent(m_hEvent);
    }

   
    // REVIEW Disable Parent
    EnableWindow(*this, FALSE);
}

BOOL CAddOptionDialog::OnSetCursor(WPARAM wParam, LPARAM lParam)
{
    if (HTCLIENT == LOWORD(lParam))
        SetWaitCursor(m_bWaitCursor, IDC_APPSTARTING);

    return m_bWaitCursor;
}

static const DWORD BUF_LEN= 512;

void CAddOptionDialog::OnPrivateMessage()
{
    EnableWindow(GetDlgItem(*this, IDC_HAVEDISK), TRUE);

    if (m_bHaveDisk == FALSE)
    {
        TRACE(_T("BuildList is done\n"));

        m_list.DeleteAllItems();    // remove message from the list
        POSITION pos;

        m_bWaitCursor = FALSE;
        pos = m_optionList->GetHeadPosition();
        InfProduct* option;

        EnableWindow(GetDlgItem(*this, IDOK), pos != NULL);
        while(pos)
        {
            option = (InfProduct*)m_optionList->GetNext(pos);
            m_list.InsertItem(m_list.GetItemCount(), option->QueryDescription(), m_nImage, 0);
        }

        // force 1 item to be selected
        if(m_list.GetItemCount())
        {
            m_list.SetItemState(0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
        }
    }
    else
    {
        TRACE(_T("Have Disk is done\n"));
        m_bHaveDisk = FALSE;    // have disk operation is done
        EnableWindow(*this, TRUE);

        // parse data from registry, fill in InfProduct item
        TCHAR* buf = new TCHAR[BUF_LEN];

        if (ReadSetupNetErrorKey(buf, BUF_LEN))
        {
            // if the key has the value STATUS_???????, the copied was canceled or failed
            if (_tcsncmp(buf, _T("STATUS_"), 7) != 0)
            {
                // create a new InfProduct and populate it
                InfProduct* inf = new InfProduct;
                int nLen = 0;
                LPTSTR ptr[4] = {NULL, NULL, NULL, NULL};
                TCHAR  tmp[BUF_LEN] = {NULL};
                LPTSTR pTmp = tmp;

                // get tokens and match order needed for InitFromBuffer                
                ptr[2] = _tcstok(buf , _T(","));    // filename
                ASSERT(ptr[2] != NULL);
                ptr[3] = _tcstok(NULL ,  _T(","));  // path
                ptr[0] = _tcstok(NULL ,  _T(","));   // option
                ptr[1] = _tcstok(NULL ,  _T(","));  // description

                for (int i=0; i < 4; i++)
                {
                    if (ptr[i] == NULL)
                        continue;

                    nLen = _tcslen(ptr[i]);
                    _tcsncpy(pTmp, ptr[i], nLen);
                    pTmp[nLen] = NULL;

                    pTmp += (nLen + 1);
                }

                inf->InitFromBuffer(tmp);
                if (ptr[3] )
                {
                    inf->AddOEMPath(ptr[3]);
                    
                }
                TRACE(_T("FileName:%s Option:%s Description:%s Path: %s\n"), inf->QueryFileName(), inf->QueryOption(),
                    inf->QueryDescription(), inf->QueryPathInfo());

                m_pInfProduct = inf;
                CDialog::OnOk();    // we're done
            }
            else
            {
                SetActiveWindow(*this);
            }
        }

        delete [] buf;
    }

    return;
}
 
void CAddOptionDialog::OnOk()
{
    // see if there is an item selected
    int nItem = m_list.GetCurrentSelection();

    VERIFY(SetSelectedItem(nItem));

    CDialog::OnOk();
}

void CAddOptionDialog::OnCancel()
{
    CDialog::OnCancel();
}

void CAddOptionDialog::TerminateThread()
{
    if (m_tid)
    {
        PostThreadMessage(m_tid, TERMINATE_THREAD, 0, 0); 
        WaitForSingleObject(m_hThread, INFINITE); 
    }
}

void CAddOptionDialog::OnDestroy()
{
    TerminateThread();

    if (m_hThread)
    {
        CloseHandle(m_hThread);
        m_hThread = 0;
    }

    if (m_hEvent)
    {
        CloseHandle(m_hEvent);
        m_hEvent = 0;
    }

    if (m_hHaveDiskThread)
    {
        CloseHandle(m_hHaveDiskThread);
        m_hHaveDiskThread = 0;
    }

    if (m_bDeleteList == TRUE)
    {
        POSITION pos = m_optionList->GetHeadPosition();
        InfProduct* pItem;

        while(pos)
        {
            pItem = (InfProduct*)m_optionList->GetNext(pos);
            delete pItem;
        }

        if (m_optionList->GetCount())
            m_optionList->RemoveAll();
    }

    if (m_hImage)
        ImageList_Destroy(m_hImage);
}

DWORD BuildList(LPDWORD lpdwParam) 
{ 
    BOOL bListDone = FALSE;
    CAddOptionDialog* dlg = (CAddOptionDialog*)lpdwParam;

    ASSERT(dlg != NULL);
    ASSERT(dlg->m_mainThread);
    ASSERT(dlg->m_hEvent);

    MSG msg;
    TRACE(_T("BuildList thread Started\n"));

    // Create the queue and signal the main thread
    PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
    SetEvent(dlg->m_hEvent);

    // Determine which options are needed
    DWORD dwType = QIFT_SERVICES;

    if (dlg->m_eType == ADAPTER)
    {
        dwType =  QIFT_ADAPTERS;
    }
    else if(dlg->m_eType == PROTOCOL)
    {
        dwType =  QIFT_PROTOCOLS;
    }

    // Launch setup and read options
    LPTSTR pszBuff;
    LPTSTR pchBuff;
    InfProduct* pinfp;
    InfProduct* pinfpPrev;


    // Are we told to terminate
    if (PeekMessage(&msg, NULL, TERMINATE_THREAD, TERMINATE_THREAD, PM_REMOVE))
        return 0;

    ASSERT(dlg->m_pNcp != NULL);

    dlg->m_pNcp->RunUpdateRegOemInfs(NULL, dwType);

    // retrieve buffer of services
    pszBuff =  dlg->m_pNcp->GetAllOptionsText(dwType);
    pchBuff = pszBuff;
    POSITION poslist;
    POSITION posCurrent;

    if (NULL != pszBuff)
    {
        // append buffer items onto our list
        do 
        {
            pinfp = new InfProduct;
            pchBuff += pinfp->InitFromBuffer(pchBuff);

            // check if option/filename matches a previous entry,
            // if so, remove the previous entry before append to list
            // NOTE:  Only one previous entry could be present, so break
            // out when one is found and removed.
            //
            poslist = dlg->m_optionList->GetTailPosition();
            while (NULL != poslist)
            {
                posCurrent = poslist;

                pinfpPrev = (InfProduct*)dlg->m_optionList->GetPrev( poslist );

                if (0 == lstrcmp(pinfpPrev->QueryOption(), pinfp->QueryOption() ) )
                {
                    // remove the dup
                    dlg->m_optionList->RemoveAt( posCurrent );
                    break;
                }            
            }
            dlg->m_optionList->AddTail(pinfp);

        } while (*pchBuff!= NULL);

        delete [] pszBuff;
    }

    // tell the main thread that the list is complete
    PostMessage(*dlg, CDialog::PRIVATE_MSG, 0,0);
    
    return 0; 
}

BOOL SelectComponent(HWND hParent, 
        OptionTypes eType, 
        DLIST_OF_InfProduct* pdlinfProduct, 
        InfProduct& infpSelected,
        NCP* pncp,
        DLIST_OF_InfProduct* pdlinfUIProduct )
{
    BOOL frt = FALSE;
    ASSERT(IsWindow(hParent));
    CPtrList* pcplList = NULL;
    CPtrList cplList;

    // did they supply a list to use
    //
    if (pdlinfProduct != NULL)
    {
        InfProduct* pinf;

        //
        // BUGBUG: We are converting lists here, we should use one list
        //    class 
        //
        ITER_DL_OF(InfProduct) iterInf( * pdlinfProduct );

        for ( ; pinf = iterInf.Next() ; )
        {
            BOOL fAppend = TRUE;

            if (NULL != pdlinfUIProduct)
            {
                InfProduct* pinfUI;
                ITER_DL_OF(InfProduct) iterUIInf( * pdlinfUIProduct );
                // don't add it if it is present in the UI already
                //
                while ( pinfUI = iterUIInf.Next() )
                {
                    if (0 == lstrcmpi( pinf->QueryOption(), pinfUI->QueryOption() ))
                    {
                        fAppend = FALSE;
                        break;
                    }
                }
            }
            if (fAppend)
            {
                cplList.AddTail(pinf);
            }
        }

        pcplList = &cplList;
    }

    CAddOptionDialog dlg(eType, pncp, pcplList);

    dlg.Create(hParent, g_hinst, IDD_SELECTNEW, PSZ_NETWORKHELP, (PDWORD)amhidsSelection);
    if (dlg.DoModal() == IDOK)
    {
        
        if (dlg.GetSelectedItem(&infpSelected) == TRUE)
        {
            frt = TRUE;
            TRACE(_T("Component Selected %s\n"), (LPCTSTR)infpSelected.QueryDescription());
        }
    }

    if (cplList.GetCount())
        cplList.RemoveAll();

    return( frt );
}

BOOL CreateWSTR(LPWSTR* ppszWStr, LPWSTR pszStr)
{
    int cchConv;
    LPWSTR pszConv;
    BOOL frt = FALSE;
    
    if (NULL == pszStr)
    {
        *ppszWStr = NULL;
        frt = TRUE;
    }
    else
    {
        cchConv = lstrlen( pszStr ) + 1;

        pszConv = new WCHAR[cchConv];
        if (NULL != pszConv)
        {
            lstrcpy( pszConv, pszStr );
            *ppszWStr = pszConv;
            frt = TRUE;
        }
    }
    return( frt );
}

InfProduct::InfProduct() 
{
    Initialize();
}

InfProduct::InfProduct(const InfProduct& inf)
{
    Initialize();
    CopyItem(inf);
}

InfProduct::InfProduct(LPTSTR szInfName, 
            LPTSTR szInfOption,
            LPTSTR szTitle, 
            LPTSTR szDetectInfo, 
            LPTSTR szPath, 
            LPTSTR szRegBase,
            LPTSTR szSection)
{
    Initialize();
    if (szInfOption)
    {
        _pszOption = new TCHAR[_tcslen(szInfOption) + 1];
        _tcscpy(_pszOption, szInfOption);
    }
    if (szTitle)
    {
        _pszDescription = new TCHAR[_tcslen(szTitle) + 1];
        _tcscpy(_pszDescription, szTitle);
    }

    if (szPath)
    {
        _pszPath = new TCHAR[_tcslen(szPath) + 1];
        _tcscpy(_pszPath, szPath);
    }

    if (szInfName)
    {
        _pszFileName = new TCHAR[_tcslen(szInfName) + 1];
        _tcscpy(_pszFileName, szInfName);
    }

    if (szDetectInfo)
    {
        _pszDetectInfo = new TCHAR[_tcslen(szDetectInfo) + 1];
        _tcscpy(_pszDetectInfo, szDetectInfo);
    }
    if (szRegBase)
    {
        _pszRegBase = new TCHAR[_tcslen(szRegBase) + 1];
        _tcscpy(_pszRegBase, szRegBase);
    }
    if (szSection)
    {
        _pszSection = new TCHAR[_tcslen(szSection) + 1];
        _tcscpy(_pszSection, szSection);
    }

}

InfProduct& InfProduct::operator = (const InfProduct& inf)
{
    if (this == &inf)
        return *this;

    this->~InfProduct();  
    
    CopyItem(inf); 
    return *this;
}

void InfProduct::CopyItem(const InfProduct& inf)
{
    ASSERT(inf._pszOption != NULL);
    ASSERT(inf._pszDescription != NULL);
    ASSERT(inf._pszFileName != NULL);

    _fState = inf._fState;

    if (inf._pszOption)
    {
        _pszOption = new TCHAR[_tcslen(inf._pszOption) + 1];
        _tcscpy(_pszOption, inf._pszOption);
    }

    if (inf._pszDescription)
    {
        _pszDescription = new TCHAR[_tcslen(inf._pszDescription) + 1];
        _tcscpy(_pszDescription, inf._pszDescription);
    }

    if (inf._pszPath)
    {
        _pszPath = new TCHAR[_tcslen(inf._pszPath) + 1];
        _tcscpy(_pszPath, inf._pszPath);
    }

    if (inf._pszFileName)
    {
        _pszFileName = new TCHAR[_tcslen(inf._pszFileName) + 1];
        _tcscpy(_pszFileName, inf._pszFileName);
    }

    if (inf._pszDetectInfo)
    {
        _pszDetectInfo = new TCHAR[_tcslen(inf._pszDetectInfo) + 1];
        _tcscpy(_pszDetectInfo, inf._pszDetectInfo);
    }
    if (inf._pszRegBase)
    {
        _pszRegBase = new TCHAR[_tcslen(inf._pszRegBase) + 1];
        _tcscpy(_pszRegBase, inf._pszRegBase);
    }
    if (inf._pszSection)
    {
        _pszSection = new TCHAR[_tcslen(inf._pszSection) + 1];
        _tcscpy(_pszSection, inf._pszSection);
    }
}

InfProduct::~InfProduct()
{
    delete [] _pszFileName;
    delete [] _pszOption;
    delete [] _pszDescription;
    delete [] _pszPath;
    delete [] _pszDetectInfo;
    delete [] _pszRegBase;
    delete [] _pszSection;
    Initialize();
}

void InfProduct::Initialize()
{
    _pszFileName =  NULL;
    _pszOption = NULL,
    _pszDescription = NULL;
    _pszPath = NULL;
    _pszDetectInfo = NULL;
    _pszRegBase = NULL;
    _pszSection = NULL;
    _fState = 0;
    _crefForce = 0;
}

void InfProduct::ResetRegBase( LPCTSTR pszRegBase )
{
    // note that it is valid to pass a null pszRegBase
    delete [] _pszRegBase;
    _pszRegBase = NULL;

    if (pszRegBase)
    {
        _pszRegBase = new TCHAR[_tcslen(pszRegBase) + 1];
        _tcscpy(_pszRegBase, pszRegBase);
    }
}

void InfProduct::ResetUnattendSection( LPCTSTR lpszSection )
{
    // note that it is valid to pass a null lpszSection
    delete [] _pszSection;
    _pszSection = NULL;

    if (lpszSection)
    {
        _pszSection = new TCHAR[_tcslen(lpszSection) + 1];
        _tcscpy(_pszSection, lpszSection);
    }
}

void InfProduct::ResetFileName( LPCTSTR pszFileName )
{
    ASSERT(_pszFileName != NULL);

    delete [] _pszFileName;
    _pszFileName = NULL;

    if (pszFileName)
    {
        _pszFileName = new TCHAR[_tcslen(pszFileName) + 1];
        _tcscpy(_pszFileName, pszFileName);
    }
}

/* BUGBUG: Because InitFromBuffer() does not know how to deal with the oem path
 * a separate, this member is needed.  The way the list of infproducts is built
 * has to be revamped
 */

void InfProduct::AddOEMPath(TCHAR* lpszPath)
{
    ASSERT(lpszPath != NULL);
    int cchSize = _tcslen(lpszPath);
    delete [] _pszPath;

    
    // add trailing \ if not present
    if (lpszPath[cchSize-1] != _T('\\'))
    {
        cchSize++;
    }
    
    _pszPath = new TCHAR[cchSize + 1];
    _tcscpy(_pszPath, lpszPath);
    
    _pszPath[cchSize-1] = _T('\\');
    _pszPath[cchSize] = _T('\0');
    
}

int InfProduct::InitFromBuffer(LPTSTR pszBuff)
{
    int cchSize;
    int cchTotal = 0;
    
    if (NULL != pszBuff)
    {
        // buffer points to option
        cchSize = lstrlen( pszBuff ) + 1;
        CreateWSTR(&_pszOption, pszBuff);
    
        cchTotal += cchSize;

        pszBuff += cchSize;

        // buffer points to description
        cchSize = lstrlen( pszBuff ) + 1;
        CreateWSTR(&_pszDescription, pszBuff);

        cchTotal += cchSize;

        pszBuff += cchSize;
        // buffer points to filename
        cchSize = lstrlen( pszBuff ) + 1;
        CreateWSTR( &_pszFileName, pszBuff );

        cchTotal += cchSize;
    }
    return(cchTotal);
};

//-------------------------------------------------------------------
//
//  Function:
//
//  Synopsis:
//
//  Arguments:
//
//  Return;
//
//  Notes: creates a INF list type { "", "", ... }
//
//  History:
//      Sept 21, 1995 MikeMi - Created
//
//
//-------------------------------------------------------------------

static const INT MAX_INFO = 1024;

static void appendstring( PWSTR pszBuff, PCWSTR pszStr )
{
    
    // because this item is in a list that will be included in anther list,
    // all items must have extra quotes for each depth of containment into a list
    //
    lstrcat( pszBuff, PSZ_QUOTE );
    lstrcat( pszBuff, PSZ_QUOTE );
    lstrcat( pszBuff, pszStr );
    lstrcat( pszBuff, PSZ_QUOTE );
    lstrcat( pszBuff, PSZ_QUOTE );
    
}

static void appendnumber( PWSTR pszBuff, INT nValue )
{
    WCHAR pszTemp[32];
    
    wsprintf( pszTemp, L"%i", nValue );
    appendstring( pszBuff, pszTemp );
}

INT InfProduct::SetDetectInfo( CARD_REFERENCE* pCardRef, INT iCard )
{
    WCHAR pszInfo[MAX_INFO];

    lstrcpy( pszInfo, PSZ_BEGINBRACE );
    appendstring( pszInfo, pCardRef->QueryCardType()->QueryOptionName() );
    lstrcat( pszInfo, PSZ_COMMA );

    appendnumber( pszInfo, iCard );
    lstrcat( pszInfo, PSZ_COMMA );

    appendnumber( pszInfo, pCardRef->QueryCardType()->QueryType() );
    lstrcat( pszInfo, PSZ_COMMA );

    appendnumber( pszInfo, pCardRef->QueryConfidence() );
    lstrcat( pszInfo, PSZ_COMMA );

    appendnumber( pszInfo, (INT) pCardRef->QueryIfType() );
    lstrcat( pszInfo, PSZ_COMMA );
   
    appendnumber( pszInfo, pCardRef->QueryBus() );

    lstrcat( pszInfo, PSZ_ENDBRACE );

    int cch = lstrlen( pszInfo );
    _pszDetectInfo = new WCHAR[cch+1];
    lstrcpy( _pszDetectInfo, pszInfo );

    return( cch );
}

const WCHAR PSZ_SETUPKEYNAME[] = L"SOFTWARE\\Microsoft\\Ncpa";
const WCHAR PSZ_NETERRORNAME[] = L"InfReturn";

BOOL ReadSetupNetErrorKey(PWSTR pszBuf, DWORD cchLen)
{
    ASSERT(pszBuf != NULL);
    ASSERT(cchLen);

    HKEY hkeySetup;
    DWORD cbSize;
    DWORD dwType;

    LONG lrt;
    
    // open the keys we need
    lrt = RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
            PSZ_SETUPKEYNAME,
            0,
            KEY_ALL_ACCESS,
            &hkeySetup );
    if (ERROR_SUCCESS == lrt)
    {
        cbSize = sizeof( WCHAR ) * cchLen;
        lrt = RegQueryValueEx( hkeySetup, 
                    PSZ_NETERRORNAME,
                    NULL,
                    &dwType,
                    (LPBYTE)pszBuf,
                    &cbSize );
        RegCloseKey( hkeySetup );
    }
    return (ERROR_SUCCESS == lrt);
}