//
// Implementation file for the CListViews Class
//
#include <Windows.h>
#include "stdafx.h"
#include "CListViews.h"
#include "resource.h"
#include <wbemidl.h>
#include <comdef.h>
#include <Commctrl.h>
#include  <io.h>
#include <Math.h>
#include <commdlg.h>
#define   FILENAME_FIELD_WIDTH  10
#define   VERSION_FIELD_WIDTH    13
#define   DATE_FIELD_WIDTH   9
#define   CURRENT_FIELD_WIDTH 8
#define   PATH_FIELD_WIDTH   13

BOOL bUserAbort;
BOOL bSuccess;
HWND hDlgPrint;
#define BUFFER_SIZE 255
LRESULT CListViews::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled,HWND m_hWnd)
{
	LPNMHDR  lpnmh = (LPNMHDR) lParam;
	NM_LISTVIEW *pnm = (NM_LISTVIEW *)lParam;
	LPNMITEMACTIVATE lpnmia;
 HWND     hwndListView = ::GetDlgItem(m_hWnd, 1001);
_TCHAR  ItemName[255];
_TCHAR FileName[255];
_TCHAR TempProduct[255];
    if ( lpnmh->idFrom != 1001)
	{
	
			return 0;
	}
	

	switch(lpnmh->code)
	{

	case LVN_ITEMCHANGED:
			lpnmia = (LPNMITEMACTIVATE)lParam;
			switch (m_CurrentView) 
			{
			case VIEW_ALL_FILE:
				ListView_GetItemText(hwndListView, lpnmia->iItem,0,TempProduct,255);
				ListView_GetItemText(hwndListView, lpnmia->iItem,1,ItemName, 255);
				
				_tcscpy(CurrentProductName,TempProduct);
				_tcscpy(m_CurrentHotfix, ItemName);
				_tcscpy (m_ProductName,_T("\0"));

				AddItemsBottom();
				break;
			case VIEW_ALL_HOTFIX:
				ListView_GetItemText(hwndListView, lpnmia->iItem,0,TempProduct,255);
				ListView_GetItemText(hwndListView, lpnmia->iItem,1,ItemName, 255);
				_tcscpy(CurrentProductName,TempProduct);
					_tcscpy(m_CurrentHotfix, ItemName);
					_tcscpy (m_ProductName,_T("\0"));

					AddItemsBottom();

				break;
			case VIEW_BY_FILE:
				ListView_GetItemText(hwndListView, lpnmia->iItem,0,ItemName, 255);
					ListView_GetItemText(hwndListView, lpnmia->iItem,0,FileName, 255);
					_tcscpy(CurrentFile, FileName);
					_tcscpy(m_CurrentHotfix, ItemName);
					AddItemsBottom();
				break;
			case VIEW_BY_HOTFIX:
				ListView_GetItemText(hwndListView, lpnmia->iItem,0,ItemName, 255);
					_tcscpy(m_CurrentHotfix, ItemName);
					AddItemsBottom();
				break;
			} // end switch
		    //_tcscpy(m_CurrentHotfix, ItemName);
			 // Process LVN_COLUMNCLICK to sort items by column. 
			break;
        case LVN_COLUMNCLICK:
		{
			//Message(TEXT("NotifyListView: LVN_COLUMNCLICK"), -1, NULL);
            ListView_SortItemsEx(
				lpnmh->hwndFrom, 
				CompareFunc, 
				pnm->iSubItem);
			    m_SortOrder = !m_SortOrder;
            break;
		}
			

		break;
	
	} // end switch


				DWORD Status = GetState();
			
				::EnableWindow(m_WebButton,FALSE);
				::EnableWindow(m_UninstButton,FALSE);
				::EnableWindow(m_RptButton,FALSE);
			
				if (Status & UNINSTALL_OK)
					::EnableWindow(m_UninstButton,TRUE);
				if (Status & HOTFIX_SELECTED)
					::EnableWindow(m_WebButton,TRUE);
				if (Status & OK_TO_PRINT)
					::EnableWindow(m_RptButton,TRUE);
			
			//	SetFocus(m_WebButton);


	bHandled = TRUE;	
	return 0;
}

BOOL CListViews::Initialize( _TCHAR * ComputerName)
{
	LVCOLUMN Col;
	_TCHAR TempComputer[255];



	_tcscpy(m_ProductName,_T("\0"));
	EnableWindow(m_WebButton, FALSE);
	EnableWindow(m_UninstButton,FALSE);
	for (DWORD  i = 0; i< 3000000;i++) ;
	_tcscpy ( m_ComputerName, ComputerName);
	if (DataBase)
		FreeDatabase();
	DataBase = NULL;

	Col.mask = LVCF_WIDTH;
	SendMessage(TopList, LVM_DELETEALLITEMS, 0, 0);
  
	SendMessage(TopList, WM_SETREDRAW, FALSE, 0);
	while (ListView_GetColumn(TopList,0,&Col))
			ListView_DeleteColumn(TopList,0);

	
	// Clear the bottom list 
   
	SendMessage(BottomList, LVM_DELETEALLITEMS, 0, 0);
  
	SendMessage(BottomList, WM_SETREDRAW, FALSE, 0);
	while (ListView_GetColumn(BottomList,0,&Col))
			ListView_DeleteColumn(BottomList,0);

	SendMessage(BottomList, WM_SETREDRAW,TRUE, 0);
		
		
         Col.mask = LVCF_FMT | LVCF_TEXT;
         Col.fmt =  LVCFMT_LEFT;
		Col.pszText = _T("Hotfix Manager");
	
		ListView_InsertColumn(TopList,0,&Col);
		LVITEM LvItem;
		LvItem.mask = LVIF_TEXT;
		LvItem.iItem = 0;
		_TCHAR Message[255];
		_tcscpy(Message,_T("\0"));
		LoadString(m_hInst,IDS_RETRIEVE_DATA,Message,255);
		LvItem.pszText = Message;
	    LvItem.iSubItem = 0;
		ListView_InsertItem(TopList,&LvItem);
		SendMessage(TopList, WM_SETREDRAW,TRUE, 0);
	
	DataBase = BuildDatabase (ComputerName);

	DWORD dwLength = 255;
	GetComputerName(TempComputer, &dwLength);
	if (_tcscmp(ComputerName, TempComputer))
		m_bRemoted = TRUE;
	else
		m_bRemoted = FALSE;


	_tcscpy (m_ProductName,_T("\0"));
   	_tcscpy(m_CurrentHotfix, _T("\0"));
	
	AddItemsTop();
   AddItemsBottom();
	return TRUE;
}




BOOL CListViews::Initialize( HWND ParentWnd, HINSTANCE hInst,_TCHAR * ComputerName, 
							                  HWND WebButton, HWND UninstButton, HWND RptButton)
{
	m_bRemoted = FALSE;
	m_WebButton = WebButton;
	m_UninstButton = UninstButton;
	m_RptButton = RptButton;
	m_hInst = hInst;
	m_CurrentView = VIEW_ALL_HOTFIX;
	_tcscpy (m_ProductName,_T("\0"));
	DWORD dwStyle =  
            WS_CHILD | 
            WS_BORDER | 
            LVS_AUTOARRANGE |
		//	LVS_SORTDESCENDING|
            LVS_REPORT | 
            LVS_SHAREIMAGELISTS |
            WS_VISIBLE | LVS_SHOWSELALWAYS   ;

	
	
	TopList = CreateWindowEx(   WS_EX_CLIENTEDGE,          // ex style
                                 WC_LISTVIEW,               // class name - defined in commctrl.h
                                 NULL,                      // window text
                                 dwStyle,                   // style
                                 0,                         // x position
                                 0,                         // y position
                                 0,                         // width
                                 0,                         // height
                                 ParentWnd,                // parent
                                 (HMENU)1001,       // ID
                                 hInst,                   // instance
                                 NULL);                     // no extra data


	dwStyle |= LVS_NOSORTHEADER;
	BottomList = CreateWindowEx(   WS_EX_CLIENTEDGE,          // ex style
                                 WC_LISTVIEW,               // class name - defined in commctrl.h
                                 NULL,                      // window text
                                 dwStyle,                   // style
                                 0,                         // x position
                                 0,                         // y position
                                 0,                         // width
                                 0,                         // height
                                 ParentWnd,                // parent
                                 NULL,       // ID
                                 hInst,                   // instance
                                 NULL);                     // no extra data

		ListView_SetExtendedListViewStyle(TopList, LVS_EX_FULLROWSELECT);
		ListView_SetExtendedListViewStyle(BottomList, LVS_EX_FULLROWSELECT);
		_tcscpy (m_ProductName,_T("\0"));
		_tcscpy (m_CurrentHotfix,_T("\0"));
	return TRUE;
}

BOOL    CListViews::Resize(RECT *rc)
{
	MoveWindow( TopList, 
            rc->left,
            rc->top,
            rc->right - rc->left,
            (rc->bottom -50) /2 - 2,
            TRUE);

	MoveWindow( BottomList, 
            rc->left,
           ( rc->bottom-50) / 2 ,
            rc->right - rc->left,
           rc->bottom-50 - (rc->bottom -50) /2,
            TRUE);
	return TRUE;

}

BOOL    CListViews::ShowLists(RECT * rc)
{
	ShowWindow(TopList,TRUE);
	ShowWindow(BottomList, TRUE);
	Resize(rc);
	return TRUE;
}


BOOL CListViews::AddItemsTop()
{

		// Top View First
	LVITEM     LvItem;
	LVCOLUMN Col;
	_TCHAR      szBuffer[255];
	PHOTFIXLIST CurrentHotfix;
	PFILELIST       CurrentFile;
    int itemnum = 0;
//	int iSubItem = 0;
	PPRODUCT CurrentEntry; 
    
	LvItem.iItem = itemnum;
	LvItem.mask = LVIF_TEXT ;
    Col.mask = LVCF_WIDTH;
	SendMessage(TopList, LVM_DELETEALLITEMS, 0, 0);
  
	SendMessage(TopList, WM_SETREDRAW, FALSE, 0);
	while (ListView_GetColumn(TopList,0,&Col))
			ListView_DeleteColumn(TopList,0);

	
	 Col.cx =100;
  Col.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
   Col.fmt =  LVCFMT_LEFT;
    
	switch (m_CurrentView )
	{
	case VIEW_ALL_HOTFIX:			// default for primary node.
		{
		CurrentEntry = DataBase;
		
		
    	LoadString(m_hInst,IDS_PRODUCT_NAME,szBuffer ,255);
		Col.pszText = _T("Product Name");
		ListView_InsertColumn(TopList,0,&Col);

		LoadString(m_hInst,IDS_ARTICLE_NUMBER,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(TopList,1,&Col);

		LoadString(m_hInst,IDS_DESCRIPTION,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(TopList,2,&Col);
		
		LoadString(m_hInst,IDS_SERVICE_PACK,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(TopList,3,&Col);

		LoadString(m_hInst,IDS_INSTALLED_BY,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(TopList,4,&Col);
		
		LoadString(m_hInst,IDS_INSTALL_DATE,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(TopList,5,&Col);

		LoadString(m_hInst,IDS_UPDATE_TYPE,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(TopList,6,&Col);

		LvItem.mask = LVIF_TEXT ;
   
		if (CurrentEntry == NULL)
		{
			LoadString(m_hInst,IDS_NO_ITEMS,szBuffer, 255);
			LvItem.iSubItem = 0;
			LvItem.pszText = szBuffer;
			ListView_InsertItem(TopList,&LvItem);
			SendMessage(TopList, WM_SETREDRAW, TRUE, 0);
			return FALSE;
		}
		while (CurrentEntry != NULL)
		{
			// first insert the product name
		    	

			// Now walk down the hotfix list.
			CurrentHotfix = CurrentEntry->HotfixList;
			while (CurrentHotfix != NULL)
			{
				LvItem.mask |= LVIF_PARAM;
				LvItem.iItem = itemnum;
				
			
				LvItem.pszText = CurrentEntry->ProductName;
	    		LvItem.iSubItem = 0;
				ListView_InsertItem(TopList,&LvItem);
			
			
				ListView_SetItemText(TopList, itemnum, 1, CurrentHotfix->HotfixName);
				ListView_SetItemText(TopList, itemnum, 2 , CurrentHotfix->Description);
				ListView_SetItemText(TopList, itemnum, 3, CurrentHotfix->ServicePack);
			
				ListView_SetItemText(TopList, itemnum, 4, CurrentHotfix->InstalledBy);
					ListView_SetItemText(TopList, itemnum, 5, CurrentHotfix->InstalledDate);
				ListView_SetItemText(TopList, itemnum, 6, CurrentHotfix->Type);

				if (itemnum == 0)
				{
//					MessageBox(NULL,CurrentEntry->ProductName, _T("Selecting Product"),MB_OK);
					_tcscpy(CurrentProductName,CurrentEntry->ProductName);
					
					_tcscpy(m_CurrentHotfix, CurrentEntry->HotfixList->HotfixName );
					ListView_SetItemState(TopList, 0,LVIS_SELECTED,LVIS_STATEIMAGEMASK | LVIS_SELECTED);
					::EnableWindow(m_WebButton,FALSE);
					::EnableWindow(m_UninstButton,FALSE);
					::EnableWindow(m_RptButton,FALSE);
			        DWORD Status = GetState();
					if (Status & UNINSTALL_OK)
						::EnableWindow(m_UninstButton,TRUE);
					if (Status & HOTFIX_SELECTED)
						::EnableWindow(m_WebButton,TRUE);
					if (Status & OK_TO_PRINT)
						::EnableWindow(m_RptButton,TRUE);
			
					SetFocus(m_WebButton);
				}
			
				itemnum++;
			
				CurrentHotfix = CurrentHotfix->pNext;
			}
		
			CurrentEntry = CurrentEntry->pNext;
		}
		 
	
		}
	
	break;

	case VIEW_ALL_FILE:					// View all of the files updated by all products.
		CurrentEntry = DataBase;
		
//		MessageBox(NULL,_T("Viewing all by file"),NULL,MB_OK);
    LoadString(m_hInst,IDS_PRODUCT_NAME,szBuffer ,255);
	Col.pszText = szBuffer;
    ListView_InsertColumn(TopList,0,&Col);

	LoadString(m_hInst,IDS_ARTICLE_NUMBER,szBuffer ,255);
	Col.pszText = szBuffer;
    ListView_InsertColumn(TopList,1,&Col);

	LoadString(m_hInst,IDS_FILE_NAME,szBuffer ,255);
	Col.pszText = szBuffer;
	ListView_InsertColumn(TopList,2,&Col);
	
	LoadString(m_hInst,IDS_FILE_DATE,szBuffer ,255);
	Col.pszText = szBuffer;
	ListView_InsertColumn(TopList,3,&Col);

	LoadString(m_hInst,IDS_FILE_CURRENT,szBuffer ,255);
	Col.pszText = szBuffer;
	ListView_InsertColumn(TopList,4,&Col);

	LoadString(m_hInst,IDS_FILE_VERSION,szBuffer ,255);
	Col.pszText = szBuffer;
	ListView_InsertColumn(TopList,5,&Col);

	LoadString(m_hInst,IDS_FILE_LOCATION,szBuffer ,255);
	Col.pszText = szBuffer;
	ListView_InsertColumn(TopList,6,&Col);

	
	if (CurrentEntry == NULL)
		{
			LoadString(m_hInst,IDS_NO_ITEMS,szBuffer, 255);
			LvItem.iSubItem = 0;
			LvItem.pszText = szBuffer;
			ListView_InsertItem(TopList,&LvItem);
			SendMessage(TopList, WM_SETREDRAW, TRUE, 0);
//			MessageBox(NULL,_T("No Database"),NULL,MB_OK);
			return FALSE;
		}
	
    
		LvItem.mask = LVIF_TEXT;
		
		while (CurrentEntry != NULL)
		{
		
			// first insert the product name
		  	// Now walk down the hotfix list.
			CurrentHotfix = CurrentEntry->HotfixList;
			while (CurrentHotfix != NULL)
			{
				CurrentFile = CurrentHotfix->FileList;
				LvItem.iItem = itemnum;
			
				while (CurrentFile != NULL)
				{
					
				    LvItem.pszText = CurrentEntry->ProductName;
	    	    	LvItem.iSubItem = 0;
					ListView_InsertItem(TopList,&LvItem);
				
					ListView_SetItemText(TopList, itemnum, 1, CurrentHotfix->HotfixName);
					ListView_SetItemText(TopList, itemnum, 2 , CurrentFile->FileName);
					ListView_SetItemText(TopList, itemnum, 3, CurrentFile->FileDate);
					ListView_SetItemText(TopList, itemnum, 4, CurrentFile->IsCurrent);
					ListView_SetItemText(TopList, itemnum, 5, CurrentFile->FileVersion);
						ListView_SetItemText(TopList, itemnum, 6, CurrentFile->InstallPath);
					itemnum++;
					
					CurrentFile = CurrentFile->pNext;
					LvItem.iItem = itemnum;
				}	
				CurrentHotfix = CurrentHotfix->pNext;
			}
			CurrentEntry = CurrentEntry->pNext;
		}
		
	break;
    case VIEW_BY_HOTFIX:

		CurrentEntry = DataBase;
			if (CurrentEntry == NULL)
			{
				LoadString(m_hInst,IDS_NO_ITEMS,szBuffer, 255);
			LvItem.iSubItem = 0;
			LvItem.pszText = szBuffer;
			ListView_InsertItem(TopList,&LvItem);
				SendMessage(TopList, WM_SETREDRAW, TRUE, 0);
				return FALSE;
			}
		LoadString(m_hInst,IDS_ARTICLE_NUMBER,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(TopList,0,&Col);

		LoadString(m_hInst,IDS_DESCRIPTION,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(TopList,1,&Col);
		
		LoadString(m_hInst,IDS_SERVICE_PACK,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(TopList,2,&Col);

		LoadString(m_hInst,IDS_INSTALLED_BY,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(TopList,3,&Col);
		
		LoadString(m_hInst,IDS_INSTALL_DATE,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(TopList,4,&Col);

		LoadString(m_hInst,IDS_UPDATE_TYPE,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(TopList,5,&Col);

		LvItem.mask = LVIF_TEXT;
       
		while ( _tcscmp(CurrentEntry->ProductName, m_ProductName) && (CurrentEntry != NULL))
			CurrentEntry = CurrentEntry->pNext;
			// first insert the product name
		
			

			// Now walk down the hotfix list.
		if (CurrentEntry == NULL)
		{
			LoadString(m_hInst,IDS_NO_ITEMS,szBuffer, 255);
			LvItem.iSubItem = 0;
			LvItem.pszText = szBuffer;
			ListView_InsertItem(TopList,&LvItem);
				SendMessage(TopList, WM_SETREDRAW, TRUE, 0);
			return FALSE;
		}
		CurrentHotfix = CurrentEntry->HotfixList;
		while (CurrentHotfix != NULL)
		{
			LvItem.iItem = itemnum;
			LvItem.pszText = CurrentHotfix->HotfixName;
	    	LvItem.iSubItem = 0;
			ListView_InsertItem(TopList,&LvItem);
		
			ListView_SetItemText(TopList, itemnum, 1 , CurrentHotfix->Description);
			ListView_SetItemText(TopList, itemnum, 2, CurrentHotfix->ServicePack);
			ListView_SetItemText(TopList, itemnum, 4, CurrentHotfix->InstalledDate);
			ListView_SetItemText(TopList, itemnum, 3, CurrentHotfix->InstalledBy);
			ListView_SetItemText(TopList, itemnum, 5, CurrentHotfix->Type);

				if (itemnum == 0)
				{
//					MessageBox(NULL,CurrentEntry->ProductName, _T("Selecting Product"),MB_OK);
					_tcscpy(CurrentProductName,CurrentEntry->ProductName);
					
					_tcscpy(m_CurrentHotfix, CurrentEntry->HotfixList->HotfixName );
					ListView_SetItemState(TopList, 0,LVIS_SELECTED,LVIS_STATEIMAGEMASK | LVIS_SELECTED);
					::EnableWindow(m_WebButton,FALSE);
					::EnableWindow(m_UninstButton,FALSE);
					::EnableWindow(m_RptButton,FALSE);
			        DWORD Status = GetState();
					if (Status & UNINSTALL_OK)
						::EnableWindow(m_UninstButton,TRUE);
					if (Status & HOTFIX_SELECTED)
						::EnableWindow(m_WebButton,TRUE);
					if (Status & OK_TO_PRINT)
						::EnableWindow(m_RptButton,TRUE);
			
					SetFocus(m_WebButton);
				}
			itemnum++;
		
			CurrentHotfix = CurrentHotfix->pNext;
		}
		break;
	case VIEW_BY_FILE:				// Displays all files modified by all updates for the current product.
		CurrentEntry = DataBase;
		
		LoadString(m_hInst,IDS_ARTICLE_NUMBER,szBuffer ,255);
	Col.pszText = szBuffer;
    ListView_InsertColumn(TopList,1,&Col);

	LoadString(m_hInst,IDS_FILE_NAME,szBuffer ,255);
	Col.pszText = szBuffer;
	ListView_InsertColumn(TopList,2,&Col);
	
	LoadString(m_hInst,IDS_FILE_DATE,szBuffer ,255);
	Col.pszText = szBuffer;
	ListView_InsertColumn(TopList,3,&Col);

	LoadString(m_hInst,IDS_FILE_CURRENT,szBuffer ,255);
	Col.pszText = szBuffer;
	ListView_InsertColumn(TopList,4,&Col);

	LoadString(m_hInst,IDS_FILE_VERSION,szBuffer ,255);
	Col.pszText = szBuffer;
	ListView_InsertColumn(TopList,5,&Col);

	LoadString(m_hInst,IDS_FILE_LOCATION,szBuffer ,255);
	Col.pszText = szBuffer;
	ListView_InsertColumn(TopList,6,&Col);
	if (CurrentEntry == FALSE)
	{
			LoadString(m_hInst,IDS_NO_ITEMS,szBuffer, 255);
			LvItem.iSubItem = 0;
			LvItem.pszText = szBuffer;
			ListView_InsertItem(TopList,&LvItem);
				SendMessage(TopList, WM_SETREDRAW, TRUE, 0);
			return FALSE;
	}
    
		LvItem.mask = LVIF_TEXT;
		// first insert locate the product name
		while ( (_tcscmp(CurrentEntry->ProductName,m_ProductName) )&& (CurrentEntry != NULL))
				CurrentEntry = CurrentEntry->pNext;
		
		  	// Now walk down the hotfix list.
		if (CurrentEntry == NULL)
		{
			LoadString(m_hInst,IDS_NO_ITEMS,szBuffer, 255);
			LvItem.iSubItem = 0;
			LvItem.pszText = szBuffer;
			ListView_InsertItem(TopList,&LvItem);
				SendMessage(TopList, WM_SETREDRAW, TRUE, 0);
			return FALSE;
		}

		CurrentHotfix = CurrentEntry->HotfixList;
		while (CurrentHotfix != NULL)
		{
			LvItem.iItem = itemnum;
			CurrentFile = CurrentHotfix->FileList;
			
			while (CurrentFile != NULL)
			{
				LvItem.pszText = CurrentHotfix->HotfixName;
	    		LvItem.iSubItem = 0;
				ListView_InsertItem(TopList,&LvItem);
				ListView_SetItemText(TopList, itemnum, 1 , CurrentFile->FileName);
				ListView_SetItemText(TopList, itemnum, 2, CurrentFile->FileDate);
				ListView_SetItemText(TopList, itemnum, 3, CurrentFile->IsCurrent);
				ListView_SetItemText(TopList, itemnum, 4, CurrentFile->FileVersion);
					ListView_SetItemText(TopList, itemnum, 5, CurrentFile->InstallPath);
						if (itemnum == 0)
				{
//					MessageBox(NULL,CurrentEntry->ProductName, _T("Selecting Product"),MB_OK);
					_tcscpy(CurrentProductName,CurrentEntry->ProductName);
					
					_tcscpy(m_CurrentHotfix, CurrentEntry->HotfixList->HotfixName );
					ListView_SetItemState(TopList, 0,LVIS_SELECTED,LVIS_STATEIMAGEMASK | LVIS_SELECTED);
					::EnableWindow(m_WebButton,FALSE);
					::EnableWindow(m_UninstButton,FALSE);
					::EnableWindow(m_RptButton,FALSE);
			        DWORD Status = GetState();
					if (Status & UNINSTALL_OK)
						::EnableWindow(m_UninstButton,TRUE);
					if (Status & HOTFIX_SELECTED)
						::EnableWindow(m_WebButton,TRUE);
					if (Status & OK_TO_PRINT)
						::EnableWindow(m_RptButton,TRUE);
			
					SetFocus(m_WebButton);
				}
				itemnum++;
				LvItem.iItem = itemnum;
				CurrentFile = CurrentFile->pNext;
			}	
			CurrentHotfix = CurrentHotfix->pNext;
		}
	

	break;	
	} // end switch			
	SendMessage(TopList, WM_SETREDRAW, TRUE, 0);


	return TRUE;
}

BOOL CListViews::AddItemsBottom ()
{
	LVITEM     LvItem;
	LVCOLUMN Col;
	_TCHAR      szBuffer[255];
	PHOTFIXLIST CurrentHotfix;
	PFILELIST       CurrentFile;
    int itemnum = 0;
//	int iSubItem = 0;
//	int ItemCount = 0;
	BOOL Done = FALSE;


	LvItem.mask = LVIF_TEXT;
	LvItem.iItem = itemnum;
	PPRODUCT CurrentEntry; 
    // Clear the List View and prepare it for updating....
	SendMessage(BottomList, LVM_DELETEALLITEMS, 0, 0);
  	SendMessage(BottomList, WM_SETREDRAW, FALSE, 0);


	

	Col.mask =LVCF_WIDTH;
	while (ListView_GetColumn(BottomList,0,&Col))
			ListView_DeleteColumn(BottomList,0);

	Col.mask = LVCF_TEXT | LVCF_WIDTH;
	Col.cx = 100;

	
    switch (m_CurrentView)
	{
	case VIEW_ALL_FILE:
	case VIEW_BY_FILE:
		CurrentEntry = DataBase;
	
		LoadString(m_hInst,IDS_ARTICLE_NUMBER,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(BottomList,0,&Col);

		LoadString(m_hInst,IDS_DESCRIPTION,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(BottomList,1,&Col);
		
		LoadString(m_hInst,IDS_SERVICE_PACK,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(BottomList,2,&Col);

		LoadString(m_hInst,IDS_INSTALLED_BY,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(BottomList,3,&Col);
		
		LoadString(m_hInst,IDS_INSTALL_DATE,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(BottomList,4,&Col);

		LoadString(m_hInst,IDS_UPDATE_TYPE,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(BottomList,5,&Col);
	SendMessage(BottomList, WM_SETREDRAW, TRUE, 0);
		LvItem.mask = LVIF_TEXT;
       
		if (CurrentEntry == NULL)
		{
			LoadString(m_hInst,IDS_NO_ITEMS,szBuffer, 255);
			LvItem.iSubItem = 0;
			LvItem.pszText = szBuffer;
			ListView_InsertItem(BottomList,&LvItem);
			SendMessage(BottomList, WM_SETREDRAW, TRUE, 0);
//			MessageBox(NULL, _T("Database is NULL"),_T("No Items"), MB_OK);
			return FALSE;
		}
		Done = FALSE;
		
		if (_tcscmp (m_ProductName,_T("\0")))
		{
			while (  (!Done) && (CurrentEntry != NULL))
			{
			
				if (!_tcscmp(CurrentEntry->ProductName, m_ProductName))
					Done = TRUE;
				else
					CurrentEntry = CurrentEntry->pNext;
			}
		}
		else
		{
		
			while (  (!Done) && (CurrentEntry != NULL))
			{
		
				if (!_tcscmp(CurrentEntry->ProductName, CurrentProductName))
					Done = TRUE;
				else
					CurrentEntry = CurrentEntry->pNext;
			}
		}
				// Now walk down the hotfix list.
		if (CurrentEntry == NULL)
		{
			LoadString(m_hInst,IDS_NO_ITEMS,szBuffer, 255);
			LvItem.iSubItem = 0;
			LvItem.pszText = szBuffer;
			ListView_InsertItem(BottomList,&LvItem);
			SendMessage(BottomList, WM_SETREDRAW, TRUE, 0);
//			MessageBox(NULL, _T("Product Not found or not selected"), _T("No Items"),MB_OK);
			return FALSE;
		
		}
		CurrentHotfix = CurrentEntry->HotfixList;
		while ( (CurrentHotfix != NULL) && (_tcscmp(CurrentHotfix->HotfixName, m_CurrentHotfix)))
			CurrentHotfix = CurrentHotfix->pNext;

		if (CurrentHotfix != NULL)
		{
			LvItem.iItem = itemnum;
			LvItem.pszText = CurrentHotfix->HotfixName, 
	    	LvItem.iSubItem = 0;
			ListView_InsertItem(BottomList,&LvItem);
		
			ListView_SetItemText(BottomList, itemnum, 1 , CurrentHotfix->Description);
			ListView_SetItemText(BottomList, itemnum, 2, CurrentHotfix->ServicePack);
			ListView_SetItemText(BottomList, itemnum, 3, CurrentHotfix->InstalledBy);
			ListView_SetItemText(BottomList, itemnum, 4, CurrentHotfix->InstalledDate);
			ListView_SetItemText(BottomList, itemnum, 5, CurrentHotfix->Type);
			itemnum++;
		
			CurrentHotfix = CurrentHotfix->pNext;
		}
		else
		{
			LoadString(m_hInst,IDS_NO_ITEMS,szBuffer, 255);
			LvItem.iSubItem = 0;
			LvItem.pszText = szBuffer;
			ListView_InsertItem(BottomList,&LvItem);
			SendMessage(BottomList, WM_SETREDRAW, TRUE, 0);
//			MessageBox(NULL, _T("No Hotfix Found"), _T("No Items"),MB_OK);
			return FALSE;
		}
		break;

	case VIEW_ALL_HOTFIX:
	case VIEW_BY_HOTFIX:
		CurrentEntry = DataBase;
		
		LoadString(m_hInst,IDS_ARTICLE_NUMBER,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(BottomList,1,&Col);

		LoadString(m_hInst,IDS_FILE_NAME,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(BottomList,2,&Col);
		
		LoadString(m_hInst,IDS_FILE_DATE,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(BottomList,3,&Col);

		LoadString(m_hInst,IDS_FILE_CURRENT,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(BottomList,4,&Col);

		LoadString(m_hInst,IDS_FILE_VERSION,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(BottomList,5,&Col);

		LoadString(m_hInst,IDS_FILE_LOCATION,szBuffer ,255);
		Col.pszText = szBuffer;
		ListView_InsertColumn(BottomList,6,&Col);
    
		SendMessage(BottomList, WM_SETREDRAW, TRUE, 0);
		LvItem.mask = LVIF_TEXT ;
		// first insert locate the product name
/*		if (!_tcscmp(m_ProductName,_T("\0")))

		{	LoadString(m_hInst,IDS_NO_ITEMS,szBuffer, 255);
			LvItem.iSubItem = 0;
			LvItem.pszText = szBuffer;
			ListView_InsertItem(BottomList,&LvItem);
			SendMessage(BottomList, WM_SETREDRAW, TRUE, 0);
			return FALSE;
			
		}
		*/
		if (CurrentEntry == NULL)
		{
			LoadString(m_hInst,IDS_NO_ITEMS,szBuffer, 255);
			LvItem.iSubItem = 0;
			LvItem.pszText = szBuffer;
			LvItem.lParam = NULL;
			ListView_InsertItem(BottomList,&LvItem);
			SendMessage(BottomList, WM_SETREDRAW, TRUE, 0);
//			MessageBox(NULL, _T("No Database"), _T("No Items"),MB_OK);
			return FALSE;
		}

		
		
		if (_tcscmp (m_ProductName,_T("\0")))
		{
			
			while (  (!Done) && (CurrentEntry != NULL))
			{
		
				if (!_tcscmp(CurrentEntry->ProductName, m_ProductName))
					Done = TRUE;
				else
					CurrentEntry = CurrentEntry->pNext;
			}
		}
		else
		{
		
			while (  (!Done) && (CurrentEntry != NULL))
			{
			
				if (!_tcscmp(CurrentEntry->ProductName, CurrentProductName))
					Done = TRUE;
				else
					CurrentEntry = CurrentEntry->pNext;
			}
		}
		
		  	// Now walk down the hotfix list.
		if (CurrentEntry == NULL)
		{
			
			LoadString(m_hInst,IDS_NO_ITEMS,szBuffer, 255);
			LvItem.iSubItem = 0;
			LvItem.pszText = szBuffer;
			LvItem. lParam = NULL;
			ListView_InsertItem(BottomList,&LvItem);
		
			SendMessage(BottomList, WM_SETREDRAW, TRUE, 0);
//			MessageBox(NULL, _T("Product Not found or not selected"), _T("No Items"),MB_OK);
			return FALSE;
		}

		CurrentHotfix = CurrentEntry->HotfixList;
		while ((CurrentHotfix != NULL) && (_tcscmp(CurrentHotfix->HotfixName, m_CurrentHotfix)))
			CurrentHotfix = CurrentHotfix->pNext;

		if ( CurrentHotfix == NULL)
		{
			LoadString(m_hInst,IDS_NO_ITEMS,szBuffer, 255);
			LvItem.iSubItem = 0;
			LvItem.pszText = szBuffer;
			LvItem.lParam = NULL;
			ListView_InsertItem(BottomList,&LvItem);
			SendMessage(BottomList, WM_SETREDRAW, TRUE, 0);
//			MessageBox(NULL,_T("No Hotfix Found"), _T("No Items"), MB_OK);
			return FALSE;
		}
		if (CurrentHotfix != NULL)
		{
			LvItem.iItem = itemnum;
			
			CurrentFile = CurrentHotfix->FileList;
			if (CurrentFile == NULL)
			{
			LoadString(m_hInst,IDS_NO_ITEMS,szBuffer, 255);
			LvItem.iSubItem = 0;
			LvItem.pszText = szBuffer;
			LvItem.lParam = NULL;
			ListView_InsertItem(BottomList,&LvItem);
			SendMessage(BottomList, WM_SETREDRAW, TRUE, 0);
//			MessageBox (NULL, _T("No Files Found"), _T("No Items"), MB_OK);
			return FALSE;
			}
			while (CurrentFile != NULL)
			{
				LvItem.pszText = CurrentHotfix->HotfixName;
	    		LvItem.iSubItem = 0;
				ListView_InsertItem(BottomList,&LvItem);
				ListView_SetItemText(BottomList, itemnum, 1 , CurrentFile->FileName);
				ListView_SetItemText(BottomList, itemnum, 2, CurrentFile->FileDate);
				ListView_SetItemText(BottomList, itemnum, 3, CurrentFile->IsCurrent);
				ListView_SetItemText(BottomList, itemnum, 4, CurrentFile->FileVersion);
				ListView_SetItemText(BottomList, itemnum, 5, CurrentFile->InstallPath);
				itemnum++;
				LvItem.iItem = itemnum;
				CurrentFile = CurrentFile->pNext;
			}	
			CurrentHotfix = CurrentHotfix->pNext;
		}
		else
		{
			LoadString(m_hInst,IDS_NO_ITEMS,szBuffer, 255);
			LvItem.iSubItem = 0;
			LvItem.pszText = szBuffer;
			ListView_InsertItem(BottomList,&LvItem);
			SendMessage(BottomList, WM_SETREDRAW, TRUE, 0);
			return FALSE;
		}
		break;	
		default:
				LoadString(m_hInst,IDS_NO_ITEMS,szBuffer, 255);
			LvItem.iSubItem = 0;
			LvItem.pszText = szBuffer;
			ListView_InsertItem(BottomList,&LvItem);
			return FALSE;
		
	}	// end switch
	SendMessage(BottomList, WM_SETREDRAW, TRUE, 0);
	return TRUE;
}
PPRODUCT CListViews::BuildDatabase(_TCHAR * lpszComputerName)
{

	HKEY		 hPrimaryKey;						// Handle of the target system HKLM 
//	_TCHAR    szPrimaryPath;			 // Path to the update key;

	HKEY		hUpdatesKey;					  // Handle to the updates key.
	_TCHAR   szUpdatesPath[BUFFER_SIZE];				// Path to the udates key
	DWORD   dwUpdatesIndex;			  // index of current updates subkey
	DWORD   dwBufferSize;				  // Size of the product name buffer.



	_TCHAR	 szProductPath[BUFFER_SIZE];				// Path of the current product key
	_TCHAR  szProductName[BUFFER_SIZE];			  // Name of product; also path to product key

	PPRODUCT	pProductList = NULL;			// Pointer to the head of the product list.
	PPRODUCT    pNewProdNode;					// Pointer used to allocate new nodes in the product list.
	PPRODUCT    pCurrProdNode;					  // Used to walk the Products List;

    // Connect to the target registry
	RegConnectRegistry(lpszComputerName,HKEY_LOCAL_MACHINE, &hPrimaryKey);
	// insert error handling here......

	if (hPrimaryKey != NULL)
	{
		// Initialize the primary path not localized since registry keys are not localized.
	    _tcscpy (szUpdatesPath, _T("SOFTWARE\\Microsoft\\Updates"));
		// open the udates key
		RegOpenKeyEx(hPrimaryKey,szUpdatesPath, 0, KEY_READ ,&hUpdatesKey);
        if (hUpdatesKey != NULL)
		{
			// Enumerate the Updates key.
			dwUpdatesIndex = 0;
			while (	RegEnumKeyEx(hUpdatesKey,dwUpdatesIndex,szProductName, &dwBufferSize,0,NULL,NULL,NULL) != ERROR_NO_MORE_ITEMS)
			{
				// Create a node for the current product 
				pNewProdNode = (PPRODUCT) malloc(sizeof(PRODUCTLIST));
				_tcscpy(pNewProdNode->ProductName,szProductName);
				
				_tcscpy (szProductPath, szProductName);
				// now get the hotfix for the current product.
				pNewProdNode->HotfixList = GetHotfixInfo(szProductName, &hUpdatesKey);

				 // Insert the new node into the list.
				 pCurrProdNode=pProductList;
				 if (pCurrProdNode == NULL)						// Head of the list
				 {
					 pProductList = pNewProdNode;
					 pProductList->pPrev = NULL;
					 pProductList->pNext = NULL;
				 }
				 else
				 {
					 //Find the end of the list.
					 while (pCurrProdNode->pNext != NULL)
							pCurrProdNode = pCurrProdNode->pNext;
					 // Now insert the new node at the end of the list.
					 pCurrProdNode->pNext = pNewProdNode;
					 pNewProdNode->pPrev = pCurrProdNode;
					 pNewProdNode->pNext = NULL;
				 }

				// increment index and clear the szProducts name string for the next pass.
				
				dwUpdatesIndex++;
				_tcscpy (szProductName,_T("\0"));
				_tcscpy(szProductPath, _T("\0"));
				dwBufferSize = 255;					
			}
		}
		// close the open keys
		RegCloseKey(hUpdatesKey);
		RegCloseKey(hPrimaryKey);
	}
	// return a pointer to the head of our database.
	VerifyFiles(pProductList);
	return pProductList;
}


void BuildQuery (_TCHAR * Path, _TCHAR * FileName, _TCHAR * Result)
{

	_TCHAR * src;
	_TCHAR * dest;
	_TCHAR Temp[255];


	src = Path;
	dest = Temp;


	while (*src != _T('\0'))
	{
		if (*src == _T('\\'))  // if we hit a \ character we need to insert four of them in the dest string.
		{
			for (int i = 0; i < 4; i++)
			{
				*dest = *src;
				++dest;
			}
			++src;
		
		}
		else
		{
			*dest = *src;
			++src;
			++dest;
		}
	
	}
	*dest = _T('\0');

	_stprintf(Result,_T("SELECT * from CIM_DataFile WHERE Name = '%s\\\\\\\\%s'"), Temp, FileName);
	
}
	
BOOL VerifyVersion(_TCHAR * Ver1, _TCHAR * Ver2)
{
	_TCHAR *src1;
	_TCHAR *src2;
	_TCHAR *dest1, *dest2;
	_TCHAR temp[20];
	_TCHAR temp2[20];
	BOOL  Done = FALSE;
	BOOL  Status = TRUE;
	src1 =  Ver1;
	src2 = Ver2;
	dest1 = temp;
	dest2 = temp2;

	if ((!src1) || (!src2))
		return FALSE;

	if (!_tcscmp (src1, src2))
		return TRUE;
	  
	while ( (*src1 != _T('\0')) && (!Done) )
	{
		_tcscpy (temp, _T("\0"));
		_tcscpy (temp2, _T("\0"));
		dest1 = temp;
		dest2 = temp2;
		// Get the next field of the registry string
		while( (*src1 != _T('.')) && (*src1 != _T('\0')))
		{
			*dest1 = *src1;
			++dest1;
			++src1;
		}
		if ( *src1 != _T('\0'))
			++src1; // skip the .
		*dest1 = _T('\0');
		++dest1;
		*dest1= _T('\0');

		// Now get the next field from the WMI returned version.
		while ( (*src2 != _T('.') ) && (*src2 != _T('\0')) )
		{
			*dest2= *src2;
			++dest2;
			++src2;

		}
		if ( *src2 != _T('\0'))
			++src2; // skip the .
		*dest2 = _T('\0');
		++dest2;
		*dest2= _T('\0');
	
        // Now convert the strings to integers.

		if ( _ttol (temp) != _ttol (temp2) )
		{
			Status = FALSE;
			Done = TRUE;
		}
	
		if ( (*src1 == _T('\0')) && (*src2 != _T('\0')) )
		{
			Done = TRUE;
			Status = FALSE;
		}
		if ( ( *src1 != _T('\0')) && (*src2 == _T('\0')) )
		{
			Done = TRUE;
			Status = FALSE;
		}
	}
	return Status;
}

VOID CListViews::VerifyFiles(PPRODUCT Database)
{

	PPRODUCT CurrentProduct = NULL;
	PHOTFIXLIST CurrentHotfix    = NULL;
	PFILELIST CurrentFile        = NULL;
    HRESULT     hres;
	_TCHAR      ConnectString[255];
	_TCHAR     TempBuffer[255];
	 
	    
	    IWbemLocator *pLoc = 0;
		hres = CoCreateInstance(CLSID_WbemLocator, 0,CLSCTX_INPROC_SERVER,IID_IWbemLocator, (LPVOID *) &pLoc);
		if ( FAILED (hres))
		{
//			MessageBox(NULL, _T("Failed to create IWebmLocator Object"),NULL,MB_OK);
		}
		else
		{
			IWbemServices *pSvc = NULL;
			// Build the connection string.
			if (!_tcscmp(m_ComputerName,_T("\0")))
				_stprintf(ConnectString,_T("ROOT\\CIMV2"));
			else
				_stprintf(ConnectString,_T("\\\\%s\\ROOT\\CIMV2"), m_ComputerName);
			_TCHAR * ConnectString1;
			ConnectString1 = SysAllocString(ConnectString);
			// Connect to the default namespace 
			hres = pLoc->ConnectServer(
				ConnectString1,
				NULL,NULL,0,NULL,0,0,&pSvc);
			SysFreeString(ConnectString1);
			if ( FAILED (hres))
			{
				;				
			}
			else
			{
					CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT,RPC_C_AUTHZ_NONE,
					NULL,
					RPC_C_AUTHN_LEVEL_CALL,
					RPC_C_IMP_LEVEL_IMPERSONATE,
					NULL,
					EOAC_NONE);
				IEnumWbemClassObject *pEnum = NULL;
				IWbemClassObject *pObj = NULL;

                // Now Update the Current field of all of the File Entries.
				CurrentProduct = Database;
				_TCHAR Query[255];
				while (CurrentProduct != NULL)
				{
		
					CurrentHotfix = CurrentProduct->HotfixList;
				    while (CurrentHotfix != NULL)
					{
						CurrentFile = CurrentHotfix->FileList;
						while (CurrentFile != NULL)
						{
							_tcscpy (Query,_T("\0"));
							BuildQuery(CurrentFile->InstallPath, CurrentFile->FileName,  Query);

							_TCHAR * bstrQuery = SysAllocString(Query);
							_TCHAR * bstrType = SysAllocString(_T("WQL"));
							hres = pSvc->ExecQuery(bstrType,
								                                       bstrQuery,
																	   WBEM_FLAG_FORWARD_ONLY,
																	   NULL, 
																	   &pEnum);
							SysFreeString (bstrQuery);
							SysFreeString(bstrType);
							if (hres == WBEM_S_NO_ERROR)
							{
									ULONG uReturned = 1;
									while (uReturned == 1)
									{
										hres = pEnum->Next(WBEM_INFINITE ,1,&pObj, &uReturned);
										if ( (SUCCEEDED (hres))  && (uReturned == 1))
										{
												VARIANT pVal;
												VariantClear (&pVal);

												BSTR propName = SysAllocString(L"Version");
    											hres = pObj->Get(propName,
												0L,
												&pVal,
												NULL,
												NULL);


												if  (pVal.vt == VT_NULL)
													;
												else if (pVal.vt == VT_BSTR)
												{
													TCHAR  NewVal[255];
													    _tcscpy (NewVal, pVal.bstrVal);
														//_bstr_t NewVal(pVal.bstrVal,FALSE); 
														if (! _tcscmp(CurrentFile->FileVersion, _T("\0")))
															_tcscpy (CurrentFile->IsCurrent, _T("N\\A"));
														else
														{
															if (VerifyVersion ( CurrentFile->FileVersion, NewVal) )
															{
																LoadString(m_hInst, IDS_YES, TempBuffer, 255);
																_tcscpy(CurrentFile->IsCurrent, TempBuffer);
															}
															else 
															{
																LoadString(m_hInst, IDS_NO, TempBuffer, 255);
																_tcscpy(CurrentFile->IsCurrent,_T("\0"));
															}
														}

													
												}
												if (pObj) pObj->Release();
												
										}
										else
											;
									} // end while uReturned
								
							} 
							// Done with this enumerator
							if (pEnum) pEnum->Release();
							CurrentFile = CurrentFile->pNext;
						}// end while CurrentFile != NULL
						CurrentHotfix = CurrentHotfix->pNext;
					}// end while hotfix != NULL
					CurrentProduct = CurrentProduct->pNext;
				} // end while product != NULL
			}//end else
		} // end else
} // end


					
					
					
				
			
			



PHOTFIXLIST CListViews::GetHotfixInfo( _TCHAR * pszProductName, HKEY* hUpdateKey )
{
	HKEY			   hHotfixKey = NULL;						// Handle of the hotfix key being processed.
	HKEY			   hProduct = NULL ;				   // Handle to the current product key
    HKEY               hSPKey = NULL; 
	_TCHAR          szHotfixName[BUFFER_SIZE];    // Name of the current hotfix.
    _TCHAR          szValueName[BUFFER_SIZE];
	_TCHAR          szSPName[BUFFER_SIZE];


	PHOTFIXLIST	 pHotfixList = NULL; // Pointer to the head of the hotfix list.
	PHOTFIXLIST  pCurrNode = NULL;				  // Used to walk the list of hotfixes
	PHOTFIXLIST  pNewNode = NULL;				 // Used to create nodes to be added to the list.

	DWORD		   dwBufferSize;			// Size of the product name buffer.
	DWORD          dwValIndex;					  // index of current value.
	DWORD		   dwHotfixIndex = 0;
	BYTE				*Data = NULL;
	DWORD			dwDataSize = BUFFER_SIZE;
	DWORD			dwValType;
	DWORD           dwSPIndex = 0;


	Data = (BYTE *) malloc(BUFFER_SIZE);
    if (Data == NULL)
		return NULL;

	// Open the current product key
	if (*hUpdateKey != NULL)
	{
		RegOpenKeyEx(*hUpdateKey,pszProductName,0 , KEY_READ, &hProduct);
		if (hProduct != NULL)
		{
			dwHotfixIndex = 0;
			dwBufferSize = BUFFER_SIZE;
			dwSPIndex = 0;
			while (RegEnumKeyEx(hProduct,dwSPIndex, szSPName,&dwBufferSize, 0, NULL,NULL,NULL) != ERROR_NO_MORE_ITEMS)
			{
				 // Open the Service pack Key
				RegOpenKeyEx(hProduct,szSPName,0,KEY_READ,&hSPKey);
				if (hSPKey != NULL)
				{
					// Enumerate the Service Pack key to get the hotfix keys.
					dwBufferSize = BUFFER_SIZE;
					dwHotfixIndex = 0;
					while (RegEnumKeyEx(hSPKey,dwHotfixIndex, szHotfixName, &dwBufferSize,0,NULL,NULL,NULL) != ERROR_NO_MORE_ITEMS)
					{
						
						// now create a new node
							pNewNode = (PHOTFIXLIST) malloc (sizeof(HOTFIXLIST));
							pNewNode->pNext = NULL;
							pNewNode->FileList = NULL;
							_tcscpy(pNewNode->HotfixName,szHotfixName);
							_tcscpy(pNewNode->ServicePack,szSPName);
								_tcscpy(pNewNode->Uninstall,_T("\0"));
							// Open the Hotfix Key
							RegOpenKeyEx(hSPKey,szHotfixName, 0, KEY_READ,&hHotfixKey);
						
						
							if (hHotfixKey != NULL)
							{
								// Now enumerate the values of the current hotfix.
								dwValIndex = 0;
								dwBufferSize =BUFFER_SIZE;
								dwDataSize = BUFFER_SIZE;
								while (RegEnumValue(hHotfixKey,dwValIndex, szValueName,&dwBufferSize, 0,&dwValType, Data, &dwDataSize) != ERROR_NO_MORE_ITEMS)
								{
										// Fill in the hotfix data members.
										_tcslwr(szValueName);
										if (!_tcscmp(szValueName,_T("description")))
											_tcscpy(pNewNode->Description,(_TCHAR *) Data);

										if (!_tcscmp(szValueName,_T("installeddate")))
											_tcscpy(pNewNode->InstalledDate,(_TCHAR *) Data);

										if (!_tcscmp(szValueName,_T("type")))
											_tcscpy(pNewNode->Type,(_TCHAR*) Data);

										if (!_tcscmp(szValueName,_T("installedby")))
											_tcscpy(pNewNode->InstalledBy , (_TCHAR*) Data);

										if (!_tcscmp(szValueName,_T("uninstallcommand")))
											_tcscpy(pNewNode->Uninstall, (_TCHAR*)Data);
										++ dwValIndex;
										_tcscpy (szValueName, _T("\0"));
										ZeroMemory(Data,BUFFER_SIZE);
										dwValType = 0;
										dwBufferSize =BUFFER_SIZE;
										dwDataSize   = BUFFER_SIZE;
								}
								// Get the file list for the current hotfix.
								pNewNode->FileList = GetFileInfo(&hHotfixKey);
								//insert the new node at the end of the hotfix list.
							   pCurrNode = pHotfixList;
								if (pCurrNode == NULL)
								{
									pHotfixList = pNewNode;
									pHotfixList->pPrev = NULL;
									pHotfixList->pNext = NULL;


								}
								else
								{
									 pCurrNode = pHotfixList;
									 while (pCurrNode->pNext != NULL)
										 pCurrNode = pCurrNode->pNext;
									 pCurrNode->pNext = pNewNode;
									 pNewNode->pPrev = pCurrNode;
									 pNewNode->pNext = NULL;
								}
								// Close the current Hotfix Key
								RegCloseKey(hHotfixKey);

								// Clear the strings.
							 _tcscpy(szHotfixName,_T("\0"));

								// increment the current index
								++dwHotfixIndex;
								dwBufferSize = BUFFER_SIZE;
							}
					}
					RegCloseKey(hSPKey);
					_tcscpy (szSPName,_T("\0"));
					dwBufferSize = BUFFER_SIZE;
					dwSPIndex++;
				}
			}// end enum SP keys.
			// Close all open keys
			RegCloseKey(hProduct);
		}
		if (Data != NULL)
			free (Data);
	}
	return pHotfixList;
}
PFILELIST CListViews::GetFileInfo(HKEY* hHotfixKey)
{
		PFILELIST			   pFileList = NULL;				   // Pointer to the head of the file list.
//		_TCHAR				 szFilePath;				// Path to the files subkey.
		PFILELIST			   pNewNode = NULL;
		PFILELIST			   pCurrNode = NULL;;
		BYTE *					Data;
		DWORD				 dwBufferSize = BUFFER_SIZE;
		DWORD				 dwDataSize	  = BUFFER_SIZE;
		DWORD				 dwFileIndex	= 0;
		DWORD				 dwPrimeIndex = 0;
		DWORD				 dwValType = 0;
		HKEY					hPrimaryFile;
		HKEY					hFileKey;
		_TCHAR				 szFileSubKey[BUFFER_SIZE];
		_TCHAR				 szValueName[BUFFER_SIZE];
	
		Data = (BYTE *) malloc(BUFFER_SIZE);
			ZeroMemory(Data,BUFFER_SIZE);
		// Open the files subkey of the current hotfix
	   if (RegOpenKeyEx(*hHotfixKey, _T("FileList"),0,KEY_READ,&hPrimaryFile) != ERROR_SUCCESS)
	   {
		     
			return NULL;
	   }
		_tcscpy(szValueName,_T("\0"));
		while (RegEnumKeyEx(hPrimaryFile,dwPrimeIndex,szFileSubKey, &dwBufferSize,0,NULL,NULL,NULL) != ERROR_NO_MORE_ITEMS)
		{

			// open the subfile key
			RegOpenKeyEx(hPrimaryFile,szFileSubKey,0,KEY_READ,&hFileKey);
			dwFileIndex = 0;
		// Enumerate the file(x) subkeys of the file subkey
			dwDataSize	  = BUFFER_SIZE;
			dwBufferSize = BUFFER_SIZE;
			pNewNode = (PFILELIST) malloc (sizeof(FILELIST));
			pNewNode->pNext = NULL;
			pNewNode->pPrev = NULL;
			_tcscpy (pNewNode->IsCurrent,_T("\0"));
			_tcscpy(pNewNode->FileDate,_T("\0"));
		
			while (RegEnumValue(hFileKey,dwFileIndex,szValueName,&dwBufferSize,0,&dwValType,Data,&dwDataSize) != ERROR_NO_MORE_ITEMS)
			{
				
				_tcslwr(szValueName);

				// now find out which value we have and insert it into the node
				if (! _tcscmp(szValueName,_T("filename")))
				{
					_tcscpy(pNewNode->FileName,(_TCHAR *) Data);
				}
				if (! _tcscmp(szValueName,_T("version")))
				{
					_tcscpy(pNewNode->FileVersion,(_TCHAR*)Data);
				}
				if (!_tcscmp(szValueName,_T("builddate")))
				{		    
					_tcscpy(pNewNode->FileDate,(_TCHAR*) Data);
				}
				if (! _tcscmp(szValueName, _T("location")))
				{
					_tcscpy(pNewNode->InstallPath, (_TCHAR*) Data);
			
				}

				dwFileIndex ++;
				_tcscpy(szValueName,_T("\0"));
				ZeroMemory(Data,BUFFER_SIZE);
				dwValType = 0;
				dwBufferSize = BUFFER_SIZE;
				dwDataSize = BUFFER_SIZE;
			}
			RegCloseKey(hFileKey);
			    // add the current node to the list if not stored in dll cache
			_TCHAR TempString[255];
			_tcscpy (TempString, pNewNode->InstallPath);
			_tcslwr(TempString);
			if (  (_tcsstr (TempString, _T("dllcache")) == NULL ) && (_tcsstr (TempString, _T("driver cache") )== NULL))
			{
				pCurrNode = pFileList;
				if (pNewNode != NULL)
				{
					if (pFileList == NULL)
					{
						pFileList = pNewNode;
					}
					else
					{
						
						while (pCurrNode->pNext != NULL)
							pCurrNode = pCurrNode->pNext;
						pCurrNode->pNext = pNewNode;
						pNewNode->pPrev = pCurrNode;
					}
				}
			}
			else // otherwise free the node.
				free (pNewNode);
			++dwPrimeIndex;
		} // end enum of primary file key
		RegCloseKey(hPrimaryFile);
		if (Data != NULL)
			free (Data);
		return pFileList;
}

_TCHAR * CListViews::GetCurrentHotfix()
{
	return m_CurrentHotfix;
}


void CListViews::SetViewMode(DWORD ViewType) 
{
	m_CurrentView = ViewType;
    _tcscpy (m_CurrentHotfix,_T("\0"));
	EnableWindow(m_UninstButton,FALSE);
	EnableWindow(m_WebButton,FALSE);
	switch (ViewType)
	{
	case VIEW_BY_FILE:
			if (! _tcscmp(m_ProductName,_T("\0")))
				m_CurrentView = VIEW_ALL_FILE;
			else
				m_CurrentView = VIEW_BY_FILE;
		break;
	case VIEW_BY_HOTFIX:
	        if (! _tcscmp(m_ProductName,_T("\0")))
				m_CurrentView =VIEW_ALL_HOTFIX;
			else
				m_CurrentView = VIEW_BY_HOTFIX;
			
	    break;
	}
	AddItemsTop();
	AddItemsBottom();
	
}

void CListViews::SetProductName(_TCHAR * NewName) 
{ 
	_tcscpy (m_ProductName,NewName);
	 _tcscpy(m_ProductName, NewName);
	 EnableWindow(m_WebButton, FALSE);
	 EnableWindow(m_UninstButton,FALSE);
	_tcscpy(m_CurrentHotfix, _T("\0"));
	if (_tcscmp(NewName, _T("\0")))
	{
		switch (m_CurrentView)
		{
		case VIEW_ALL_FILE:
			m_CurrentView = VIEW_BY_FILE;
			break;
		case VIEW_ALL_HOTFIX:
			m_CurrentView = VIEW_BY_HOTFIX;
			break;
	
		}
	}
	if (!_tcscmp(NewName, _T("\0")))
	{
		switch (m_CurrentView)
		{
		case VIEW_BY_FILE:
			m_CurrentView = VIEW_ALL_FILE;
					break;
		case VIEW_BY_HOTFIX:
			m_CurrentView = VIEW_ALL_HOTFIX;
			break;
		default:
			m_CurrentView = VIEW_ALL_HOTFIX;
		}
			_tcscpy(m_ProductName,_T("\0"));
			_tcscpy(m_CurrentHotfix,_T("\0"));
	}

	
	AddItemsTop();
	AddItemsBottom();
}

BOOL CListViews::FreeFileList(PFILELIST CurrentFile)
{
	while (CurrentFile->pNext->pNext != NULL)
			CurrentFile = CurrentFile->pNext;

		//Remove the file list
	while ( (CurrentFile->pPrev != NULL) && (CurrentFile->pNext != NULL) )
	{
		free ( CurrentFile->pNext );
		CurrentFile = CurrentFile->pPrev ;
	}
	if (CurrentFile != NULL)
	free (CurrentFile);
	CurrentFile = NULL;
	return TRUE;
}

BOOL CListViews::FreeHotfixList (PHOTFIXLIST CurrentHotfix)
{
	PFILELIST CurrentFile;

	while (CurrentHotfix->pNext != NULL)
			CurrentHotfix = CurrentHotfix->pNext;

	if (CurrentHotfix->pPrev != NULL)
		CurrentHotfix = CurrentHotfix->pPrev;
		//Remove the Hotfix list
	while ( (CurrentHotfix->pPrev != NULL) && (CurrentHotfix->pNext != NULL) )
	{
		CurrentFile = CurrentHotfix->pNext->FileList ;
		FreeFileList (CurrentFile);
		free ( CurrentHotfix->pNext );
		CurrentHotfix = CurrentHotfix->pPrev ;
	}
	if (CurrentHotfix != NULL)
	free (CurrentHotfix);
	return TRUE;
}
BOOL CListViews::FreeDatabase()
{


	PPRODUCT CurrentProduct = DataBase;
	PHOTFIXLIST CurrentHotfix;
	PFILELIST   CurrentFile;

	while (CurrentProduct->pNext->pNext != NULL) 
			CurrentProduct = CurrentProduct->pNext;

	while (CurrentProduct->pPrev != NULL)
	{
	
		CurrentHotfix = CurrentProduct->HotfixList;
		FreeHotfixList(CurrentHotfix);
		CurrentProduct = CurrentProduct->pPrev ;
	}

	if (CurrentProduct != NULL)
		free(CurrentProduct);
	DataBase = NULL;
	return TRUE;
}

BOOL CListViews::Uninstall()
{
	char temp[255];
	
	PPRODUCT pProduct = NULL;
	PHOTFIXLIST pHotfix = NULL;
    
	
	pProduct = DataBase;
	BOOL Done = FALSE;

	if (_tcscmp  (m_ProductName,_T("\0")))
	{
		while (  (!Done) && (pProduct != NULL))
		{
		
			 if (!_tcscmp(pProduct->ProductName, m_ProductName))
				Done = TRUE;
			else
				pProduct = pProduct->pNext;
		}
	}
	else
	{
		while (  (!Done) && (pProduct != NULL))
		{
		
			 if (!_tcscmp(pProduct->ProductName, CurrentProductName))
				Done = TRUE;
			else
				pProduct = pProduct->pNext;
		}
	}


	if (pProduct != NULL)
		pHotfix = pProduct->HotfixList;

	if (pHotfix != NULL)
	{
		Done = FALSE;
		while( (!Done) && (pHotfix != NULL) )
		{ 
			if ( ! _tcscmp(pHotfix->HotfixName,m_CurrentHotfix)) 
				Done = TRUE;
			else
				pHotfix = pHotfix->pNext;
		}
		if (pHotfix != NULL)
		{
			if (_tcscmp(pHotfix->Uninstall, _T("\0")))
			{
				_TCHAR TempString[255];
				_TCHAR TempString2[255];
				LoadString(m_hInst,IDS_UNINSTAL_WRN,TempString,255);
				_tcscat (TempString, pHotfix->HotfixName);
				LoadString(m_hInst,IDS_UNINSTAL_WRN_TITLE,TempString2,255);
				if (::MessageBox(NULL,TempString,TempString2, MB_OKCANCEL) != IDCANCEL)
				{
					wcstombs(temp,pHotfix->Uninstall,255);
      				WinExec( (char*)temp, SW_SHOWNORMAL);
					// Free the database
					FreeDatabase();
					DataBase = NULL;
					BuildDatabase( m_ComputerName);
				}
			}
		}
	}
	return TRUE;
}


	void InitializeOfn(OPENFILENAME *ofn)
	{


		static _TCHAR szFilter[] =  _T("Text (Comma Delimited) (*.csv)\0*.csv\0\0") ;
													
											

		ofn->lStructSize = sizeof (OPENFILENAME);
		ofn->hwndOwner = NULL;
		ofn->hInstance = NULL;
		ofn->lpstrFilter = szFilter;
		ofn->lpstrCustomFilter = NULL;
		ofn->nMaxCustFilter = 0;
		ofn->lpstrFile = NULL;
		ofn->nMaxFile = MAX_PATH;
		ofn->lpstrFileTitle = NULL;
		ofn->Flags = OFN_OVERWRITEPROMPT;
		ofn->nFileOffset = 0;
		ofn->nFileExtension  = 0;
		ofn->lpstrDefExt = _T("csv");
		ofn->lCustData = 0L;
		ofn->lpfnHook = NULL;
		ofn->lpTemplateName = NULL;
	}
void CListViews::SaveToCSV()
{
	PPRODUCT    pProduct = NULL;
	PHOTFIXLIST pHotfix = NULL; 
	PFILELIST       pFileList = NULL;
	_TCHAR        *Buffer;
	DWORD        LineLength = 0;
	HANDLE		 hFile = NULL;
	DWORD		 BytesWritten = 0;
	DWORD LineSize = 0;

	char			  *Buffer2;


	static OPENFILENAME ofn;
	 _TCHAR FileName[MAX_PATH];
	_tcscpy (FileName,_T("\0"));
	 InitializeOfn (&ofn);
	 ofn.lpstrFile = FileName;
	 if ( !GetSaveFileName(&ofn) )
	 {
		 return;
	 }
	// open the file
    hFile = CreateFile( FileName, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

	
	if ( hFile == INVALID_HANDLE_VALUE)
	{
	
		LPVOID lpMsgBuf;
FormatMessage( 
    FORMAT_MESSAGE_ALLOCATE_BUFFER | 
    FORMAT_MESSAGE_FROM_SYSTEM | 
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    (LPTSTR) &lpMsgBuf,
    0,
    NULL 
);
// Process any inserts in lpMsgBuf.
// ...
// Display the string.
//	MessageBox( NULL, (LPCTSTR)lpMsgBuf,_T(" Error"), MB_OK | MB_ICONINFORMATION );
// Free the buffer.
LocalFree( lpMsgBuf );

		return;
	} 
	// Store Headers
	Buffer = (_TCHAR *) malloc (2000);
	Buffer2 = (char*) malloc(2000);
	LoadString(m_hInst,IDS_CSV_HEADER,Buffer,1000);
	//_stprintf(Buffer, _T("Product,Service Pack,Article,InstalledBy,InstalledDate,FileName,FileVersion,FileDate,InstallPath,Current\r"));
	wcstombs(Buffer2,Buffer, _msize(Buffer2) );
	WriteFile(hFile,Buffer2, strlen(Buffer2), &BytesWritten, NULL);

	if (Buffer)
		free (Buffer);
	if (Buffer2)
		free (Buffer2);

	Buffer = NULL;
	Buffer2 = NULL;



	// Run through the Data base and write the info to the file.
	pProduct = DataBase;
	while (pProduct != NULL)
	{
		pHotfix = pProduct->HotfixList;

		while (pHotfix != NULL)
		{
			pFileList = pHotfix->FileList;
			while (pFileList != NULL)
			{
				// Build the CSV output string
				// Product,Article,Description, ServicePack, By, Date, Type, FileName, Version, Date,Current,InstallPath
			
				// Add up the string lengths and allocata a large enough buffer.
				LineLength = _tcslen(pProduct->ProductName) + _tcslen(pHotfix->ServicePack)+
									   _tcslen(pHotfix->HotfixName) + _tcslen(pHotfix->Description )+ _tcslen(pHotfix->InstalledBy ) +
										_tcslen(pHotfix->InstalledDate)  +  _tcslen(pHotfix->Type) +
										_tcslen(pFileList->FileName ) + _tcslen(pFileList->FileVersion ) +
										_tcslen(pFileList->FileDate  ) + _tcslen(pFileList->InstallPath )+
										_tcslen(pFileList->IsCurrent  );
				Buffer = (_TCHAR *) malloc ( LineLength * sizeof (_TCHAR ) *2) ;
				Buffer2 = (char  *) malloc (LineLength *2);
				//ZeroMemory(Buffer, (LineLength * sizeof (_TCHAR)) +2);
				_tcscpy (Buffer,_T("\0"));
				strcpy(Buffer2,"\0");
				if (!Buffer)
					MessageBox (NULL,_T("NO Memory"),NULL, MB_OK);
				else
				{
				_stprintf(Buffer,_T("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\r\0\0"),pProduct->ProductName,
					pHotfix->ServicePack,pHotfix->HotfixName,pHotfix->Description ,pHotfix->InstalledBy, pHotfix->InstalledDate, 
					pHotfix->Type,pFileList->FileName,pFileList->FileVersion,pFileList->FileDate ,
					pFileList->InstallPath,pFileList->IsCurrent);
				
				// Write the line to the file
				LineSize = 0;
				LineSize = 	wcstombs(Buffer2,Buffer, _msize (Buffer2) );
				strcat(Buffer2,"\0");
				WriteFile(hFile, Buffer2, LineSize, &BytesWritten, NULL);
				}
				// Free the buffer and zero the line length for next pass.
				if (Buffer)
				{
					free (Buffer);
					free (Buffer2);
				}
				Buffer = NULL;
				Buffer2 = NULL;
				LineLength = 0;
				pFileList = pFileList->pNext;
			}
			pHotfix = pHotfix->pNext;
		}
		pProduct = pProduct->pNext;
	}
	CloseHandle(hFile);
}


DWORD CListViews::GetState()
{
	DWORD dwStatus =0;
    PPRODUCT CurrentProduct;
	PHOTFIXLIST CurrentHotfix;
	BOOL Done = FALSE;;


	switch (m_CurrentView)
	{
	case VIEW_ALL_FILE:
	case VIEW_BY_FILE:
		dwStatus |= STATE_VIEW_FILE;
		break;
	case VIEW_ALL_HOTFIX:
	case VIEW_BY_HOTFIX:
		dwStatus |= STATE_VIEW_HOTFIX;
		break;
	}

	// Do we have a database.
	if (DataBase == NULL)
		return dwStatus;

	// Does the database contain any data...
	    // A case can arise if a hotfix is installed and then uninstalled where the Registry keys 
	    // for the Product and Service Pack are not removed. We need to have at least 1 hotfix list.
     CurrentProduct = DataBase;
	 while ( (CurrentProduct != NULL) && (!Done))
	 {
		 if (CurrentProduct ->HotfixList != NULL)
			 Done = TRUE;
		 CurrentProduct = CurrentProduct->pNext;
	 }
	 if (!Done)
	 {
		//dwStatus = 0;
		 return dwStatus;
	 }
	 else 
	 {
		 // We do have data in the database so we can enable the Export list and Print options.
		 dwStatus |= DATA_TO_SAVE;
		 dwStatus |= OK_TO_PRINT;
	 }
	 	
	// Do we have a hotfix selected 
	if (_tcscmp(m_CurrentHotfix,_T("\0")))
		dwStatus |= HOTFIX_SELECTED;
    else
	{
		// If we don't have a selected hotfix we cant view the web or uninstall so 
		// Just return the current status

		return dwStatus;
	}

	// Now we need to see if we have an uninstall string for the current hotfix
	CurrentProduct = DataBase;
	// Find the selected product
	Done = FALSE;
	while ( (CurrentProduct != NULL) && (!Done))
	{
		if (!_tcscmp(CurrentProduct->ProductName ,m_ProductName))
		{
			// Find the selected hotfix
			CurrentHotfix = CurrentProduct->HotfixList;
			while ((CurrentHotfix != NULL) && (!Done))
			{
				if (! _tcscmp (CurrentHotfix->HotfixName, m_CurrentHotfix))
				{
						// Now verify the uninstall string exists
					    if (_tcscmp(CurrentHotfix->Uninstall, _T("\0")))
						{
							
							// Now verify the directory still exists
							_TCHAR TempString[255];
							_tcscpy (TempString,CurrentHotfix->Uninstall);
							PathRemoveArgs(TempString);
						    if (  PathFileExists( TempString  ))
							{
								// Yes it does we can enable uninstall
								dwStatus |=UNINSTALL_OK;
							}
							
						}
						Done = TRUE;
				}
				CurrentHotfix = CurrentHotfix->pNext;
				
			}
		}
		CurrentProduct = CurrentProduct->pNext;
	}

	

	return dwStatus;
}

_TCHAR * BuildDocument()
{


//	_TCHAR Document;
	return NULL;
}

BOOL CALLBACK AbortProc(HDC hPrinterDC, int iCode)
{
	MSG msg;
	while (!bUserAbort && PeekMessage (&msg, NULL,0,0,PM_REMOVE))
	{
		if (!hDlgPrint || !IsDialogMessage (hDlgPrint, &msg))
		{
			TranslateMessage (&msg);
			DispatchMessage (&msg);
		}
	}
	return !bUserAbort;
}

BOOL CALLBACK PrintDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{

	switch (msg)
	{
	case WM_INITDIALOG :
		EnableMenuItem (GetSystemMenu (hDlg,FALSE), SC_CLOSE, MF_GRAYED);
		return TRUE;
	case WM_COMMAND:
		bUserAbort = TRUE;
		EnableWindow (GetParent (hDlg), TRUE);
		DestroyWindow (hDlg);
	    hDlgPrint = NULL;
		return TRUE;
	}
	return FALSE;
}

BOOL JustifyString( _TCHAR* String, int FieldLength, BOOL Left)
{
	_TCHAR TempString[255];
    int   i= 0;
	int   NumSpaces = 0;
	_TCHAR Message[100];
	_TCHAR *src, *dest;



	if (String == NULL)
	{
		return FALSE;
	}

	if (Left)
	{
			// String leading spaces.
		src = String;
		dest = TempString;
		while (*src == _T(' '))
			++src;

		while (*src != _T('\0'))
		{
			*dest = *src;
			++src;
			++dest;
		}
		*dest = _T('\0');
		++dest;
		*dest = _T('\0');
		NumSpaces = (FieldLength - _tcslen(TempString) );
		_stprintf(Message,_T("FieldSize: %d, String Length: %d"),FieldLength, _tcslen(TempString));
	//	MessageBox(NULL,Message,_T("Justify"),MB_OK);
		while (NumSpaces >0)
		{
			_tcscat(TempString,_T(" "));
			--NumSpaces;
		}
	    _tcscpy (String, TempString);
		_stprintf(Message,_T("NewString Length: %d"),_tcslen(String));
	//	MessageBox(NULL,Message,_T("New String Length"),MB_OK);
		
	}
	else
	{

		_tcscpy(TempString,_T("\0"));

		NumSpaces = FieldLength - _tcslen(String);
		if (NumSpaces > 0 )
		{
			for (i = 0 ; i < NumSpaces;i++)
				TempString[i] = _T(' ');
			TempString[i] = _T('\0');
			_tcscat(TempString,String);
			_tcscpy(String,TempString);
		}
	}
	return TRUE;
}

void GetFont ( int PointSize, BOOL Bold, BOOL Underlined, LOGFONT * lf, HDC hDC)
{
	POINT pt;

	lf->lfHeight = PointSize * 10;
	pt.y = GetDeviceCaps(hDC, LOGPIXELSY) * lf->lfHeight;
	pt.y /= 720;    // 72 points/inch, 10 decipoints/point
	DPtoLP(hDC, &pt, 1);
	POINT ptOrg = { 0, 0 };
	DPtoLP(hDC, &ptOrg, 1);
	lf->lfHeight = -abs(pt.y - ptOrg.y);
	if (Underlined)
		lf->lfUnderline = TRUE;
	else
		lf->lfUnderline = FALSE;
	if (Bold)
		lf->lfWeight = FW_BOLD;
	else
		lf->lfWeight = FW_NORMAL;
	

}


void NewPage (HDC hDC, _TCHAR *Header1, _TCHAR * Header2, DWORD * CurrentLine, LOGFONT * lf)
{
	TEXTMETRIC tm;
	SIZE size;
	DWORD xStart;
	DWORD yChar;
	RECT  rect;


	rect.left = (LONG) (0 + GetDeviceCaps(hDC, LOGPIXELSX) * 0.5);
	rect.right =  (LONG) (GetDeviceCaps(hDC, PHYSICALWIDTH) -(1+ (GetDeviceCaps(hDC, LOGPIXELSX) / 2)));
	rect.top =  (LONG) (1 + GetDeviceCaps(hDC, LOGPIXELSY) * 0.5);
	rect.bottom =  (LONG) (GetDeviceCaps(hDC, PHYSICALHEIGHT) - GetDeviceCaps(hDC, LOGPIXELSX) * 0.5);
	if (StartPage(hDC) > 0)
	{
		*CurrentLine = 1;
		GetFont (12,TRUE,TRUE,lf,hDC);
		SelectObject(hDC, CreateFontIndirect(lf));
		GetTextMetrics(hDC,&tm);
		yChar = tm.tmHeight + tm.tmExternalLeading ;
		GetTextExtentPoint32(hDC, Header1,_tcslen(Header1),&size);

		xStart = (rect.right - rect.left)/2 - size.cx/2 ;
		TextOut (hDC, xStart,(*CurrentLine)* yChar ,Header1, _tcslen(Header1) );

		GetFont (10,FALSE, FALSE, lf, hDC);
		SelectObject(hDC, CreateFontIndirect (lf));
		GetTextMetrics (hDC, &tm);
		yChar = tm.tmHeight + tm.tmExternalLeading ;
		xStart = rect.right - ((_tcslen(Header2) +2) * tm.tmAveCharWidth);
		TextOut(hDC, xStart,(*CurrentLine) * yChar, Header2, _tcslen(Header2));

		(*CurrentLine) += 4;
	}
	


}
void CListViews::PrintReport()
{
	static DOCINFO	di = {sizeof (DOCINFO)  } ;
	static PRINTDLG pd;
	BOOL			bSuccess;
	int				yChar, iCharsPerLine, iLinesPerPage;


	_TCHAR			Header1[255];
	_TCHAR			Header2[255];
	TEXTMETRIC		tm;

	_TCHAR			Line [255];
	PPRODUCT		CurrentProduct;
	PHOTFIXLIST		CurrentHotfix;
	PFILELIST		CurrentFile;
	DWORD			CurrentLine = 0;
	DWORD			yStart = 0;
	_TCHAR			TempBuffer[255];
	RECT			rect;
    SIZE			size;
	_TCHAR *		src;
	DWORD			xStart;
	static LOGFONT	lf;
	SYSTEMTIME		systime;
	BOOL			Done = FALSE;
	_TCHAR			SystemDate[255];
	_TCHAR			SystemTime[255];

	_TCHAR			TempBuffer1[255];
	_TCHAR			TempBuffer2[255];
	// invoke Print common dialog box

	GetLocalTime(&systime);
	GetDateFormatW (LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systime,NULL, SystemDate,255);
	GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systime,NULL,SystemTime,255);
	CurrentProduct = DataBase;
	pd.lStructSize = sizeof (PRINTDLG);
	pd.hwndOwner = TopList; //m_hWnd;
	pd.hDevMode = NULL;
	pd.hDevNames= NULL;
	pd.hDC= NULL;
	pd.Flags = PD_ALLPAGES | PD_COLLATE |
					   PD_RETURNDC | PD_NOSELECTION ;
	pd.nFromPage = 0;
	pd.nToPage = 0;
	pd.nMinPage = 0;
	pd.nMaxPage = 0;
	pd.nCopies = 1;
	pd.hInstance = NULL;
	pd.lCustData = 0L;
	pd.lpfnPrintHook = NULL;
	pd.lpfnSetupHook = NULL;
	pd.lpPrintTemplateName = NULL;
	pd.lpSetupTemplateName = NULL;
	pd.hPrintTemplate = NULL;
	pd.hSetupTemplate = NULL;
 	
	if (!PrintDlg (&pd) )
			return; //TRUE;

	else
	{
		
		// Setup the printer dimensions.
		
		rect.left = (LONG) (0 + GetDeviceCaps(pd.hDC, LOGPIXELSX) * 0.5);
		rect.right =  (LONG) (GetDeviceCaps(pd.hDC, PHYSICALWIDTH) - GetDeviceCaps(pd.hDC, LOGPIXELSX) * 0.5);
		rect.top =  (LONG) (1 + GetDeviceCaps(pd.hDC, LOGPIXELSY) * 0.5);
		rect.bottom = (LONG) ( GetDeviceCaps(pd.hDC, PHYSICALHEIGHT) - GetDeviceCaps(pd.hDC, LOGPIXELSX) * 0.5);
		rect.bottom -= 100;


		bSuccess = TRUE;
		bUserAbort = TRUE;
		hDlgPrint = CreateDialog(m_hInst, _T("PrintDlgBox"),
		TopList, PrintDlgProc );
	   
		di.lpszDocName = _T("Hotfix Manager"); 
		SetAbortProc(pd.hDC, AbortProc);

		LOGFONT logFont;
		memset(&logFont, 0, sizeof(LOGFONT));
		logFont.lfCharSet = DEFAULT_CHARSET;
		_tcscpy(logFont.lfFaceName, _T("Dlg Shell Font"));
		
		LoadString(m_hInst, IDS_UPDATE_REPORT, TempBuffer, 255);
		_stprintf(Header1,_T("%s %s"), TempBuffer,m_ComputerName);
		_stprintf(Header2, _T("%s %s"),SystemDate,SystemTime);

		StartDoc(pd.hDC,&di);
			
			
					_tcscpy (Line,_T("\0"));
							
					NewPage (pd.hDC, Header1,Header2, &CurrentLine, &logFont);
					GetTextMetrics(pd.hDC,&tm);
					yChar = tm.tmHeight + tm.tmExternalLeading ;
    				iCharsPerLine = GetDeviceCaps (pd.hDC, HORZRES) / tm.tmAveCharWidth ;
					iLinesPerPage = GetDeviceCaps (pd.hDC, VERTRES) / yChar ;
					_tcscpy (Line,_T("\0"));
					xStart = rect.left;
					while ( (CurrentProduct != NULL) && (!Done))
					{
						
						_tcscpy (Line,_T("\0"));
						LoadString(m_hInst,IDS_PRODUCT_NAME, TempBuffer,255);
						logFont.lfWeight = FW_BOLD;
						SelectObject(pd.hDC,CreateFontIndirect (&logFont));
						GetTextMetrics (pd.hDC, &tm);
					
						_stprintf (Line, _T("%s: "), TempBuffer);
						yStart = CurrentLine * yChar;
						if (yStart >=  (UINT) rect.bottom)
						{
							EndPage(pd.hDC);
							NewPage(pd.hDC, Header1,Header2, &CurrentLine, &logFont);
							yStart = CurrentLine * yChar;
						}
					
						TextOut (pd.hDC, xStart,yStart ,Line, _tcslen(Line) );
						xStart = rect.left + ((_tcslen(Line) + 4 )* tm.tmAveCharWidth);
						logFont.lfWeight = FW_NORMAL;
						SelectObject(pd.hDC,CreateFontIndirect (&logFont));
						GetTextMetrics (pd.hDC, &tm);
					
						_tcscpy (Line, CurrentProduct->ProductName);
					
						TextOut(pd.hDC, xStart, yStart , Line, _tcslen(Line) );
						CurrentLine ++;
						yStart = CurrentLine * yChar;
						if (yStart >=   (UINT)rect.bottom)
						{
							EndPage(pd.hDC);
							NewPage(pd.hDC, Header1,Header2, &CurrentLine, &logFont);
							yStart = CurrentLine * yChar;
						}
						xStart = rect.left; 
						CurrentHotfix = CurrentProduct->HotfixList;
						while ( (CurrentHotfix != NULL ) && (!Done))
						{
							
							_stprintf (Line, _T("%s \t%s"),CurrentHotfix->HotfixName,CurrentHotfix->Description );
							TabbedTextOut (pd.hDC, xStart,yStart ,Line, _tcslen(Line),0,NULL,0 );
							++CurrentLine;
							yStart = CurrentLine * yChar;
							if (yStart >=   (UINT)rect.bottom)
							{
								EndPage(pd.hDC);
								NewPage(pd.hDC, Header1,Header2, &CurrentLine, &logFont);
								yStart = CurrentLine * yChar;
							}
							LoadString (m_hInst,IDS_SERVICE_PACK, TempBuffer, 255);
							LoadString (m_hInst,IDS_INSTALL_DATE, TempBuffer1, 255);
							LoadString (m_hInst,IDS_INSTALLED_BY, TempBuffer2, 255);
						
							_stprintf(Line, _T("\t\t%s: %s \t%s: %s \t%s: %s"), TempBuffer,   CurrentHotfix->ServicePack,
																		TempBuffer1, CurrentHotfix->InstalledDate,
																		TempBuffer2, CurrentHotfix->InstalledBy);
						//	_stprintf (Line, _T("\t\tService Pack: %s\tInstall Date: %s\tInstalled By %s"),
							//	CurrentHotfix->ServicePack,CurrentHotfix->InstalledDate, CurrentHotfix->InstalledBy);
							TabbedTextOut (pd.hDC, xStart,yStart ,Line, _tcslen(Line),0,NULL,0 );

							CurrentLine +=2;
							yStart = CurrentLine * yChar;
							if (yStart >=   (UINT)rect.bottom)
							{
								EndPage(pd.hDC);
								NewPage(pd.hDC, Header1,Header2, &CurrentLine, &logFont);
								yStart = CurrentLine * yChar;
							} 
							CurrentFile = CurrentHotfix->FileList ;
							if (CurrentFile == NULL)
							{
								_tcscpy (Line, _T("\0"));
								LoadString(m_hInst,IDS_NO_FILES,Line,255);
								TextOut (pd.hDC, xStart,yStart ,Line, _tcslen(Line) );
								CurrentLine += 2;
								if (yStart >=  (UINT) rect.bottom)
								{
									EndPage(pd.hDC);
									NewPage(pd.hDC, Header1,Header2, &CurrentLine, &logFont);
									yStart = CurrentLine * yChar;
								} 
							}
							else
							{
								logFont.lfUnderline = TRUE;
								logFont.lfWeight = FW_BOLD;
								SelectObject(pd.hDC, CreateFontIndirect (&logFont));
								_tcscpy (Line, _T("\0"));
								LoadString (m_hInst, IDS_FILE,TempBuffer,255);
							    JustifyString(TempBuffer,FILENAME_FIELD_WIDTH,TRUE);
								TextOut( pd.hDC, xStart,yStart ,TempBuffer, _tcslen(TempBuffer) );

								LoadString (m_hInst, IDS_FILEDATE,TempBuffer,255);
							    JustifyString(TempBuffer,DATE_FIELD_WIDTH,TRUE);
								TextOut( pd.hDC, xStart + 29 * tm.tmAveCharWidth ,yStart ,TempBuffer, _tcslen(TempBuffer) );
								
								LoadString (m_hInst, IDS_FILEVERSION,TempBuffer,255);
							    JustifyString(TempBuffer,VERSION_FIELD_WIDTH,TRUE);
								TextOut( pd.hDC, xStart + 45 * tm.tmAveCharWidth ,yStart ,TempBuffer, _tcslen(TempBuffer) );

								LoadString (m_hInst, IDS_FILECURRENT,TempBuffer,255);
							    JustifyString(TempBuffer,CURRENT_FIELD_WIDTH,TRUE);
								TextOut( pd.hDC, xStart + 61* tm.tmAveCharWidth,yStart ,TempBuffer, _tcslen(TempBuffer) );

								LoadString (m_hInst, IDS_FILEPATH,TempBuffer,255);
							    JustifyString(TempBuffer,PATH_FIELD_WIDTH,TRUE);
								TextOut( pd.hDC, xStart+72 * tm.tmAveCharWidth ,yStart ,TempBuffer, _tcslen(TempBuffer) );
								++ CurrentLine;
								yStart = CurrentLine * yChar;
								if (yStart >=   (UINT)rect.bottom)
								{
									EndPage(pd.hDC);
									NewPage(pd.hDC, Header1,Header2, &CurrentLine, &logFont);
									yStart = CurrentLine * yChar;
								} 
							}
							while ( (CurrentFile != NULL) && (!Done) )
							{
								logFont.lfWeight = FW_NORMAL;
								logFont.lfUnderline = FALSE;
								SelectObject(pd.hDC, CreateFontIndirect (&logFont));
								_tcscpy (Line, _T("\0"));

								_tcscpy (Line, CurrentFile->FileName);
							//	JustifyString(Line,40, TRUE);
								TextOut (pd.hDC, xStart,yStart ,Line, _tcslen(Line) );
							//_tcscat (Line,TempBuffer);

								_tcscpy (Line, CurrentFile->FileDate);
							//	JustifyString(Line,20, TRUE);
								TextOut (pd.hDC, xStart + 29 * tm.tmAveCharWidth,yStart ,Line, _tcslen(Line) );

								_tcscpy (Line, CurrentFile->FileVersion );
							//	JustifyString(Line,18, TRUE);
								TextOut (pd.hDC, xStart + 45 * tm.tmAveCharWidth,yStart ,Line, _tcslen(Line) );

								_tcscpy (Line, CurrentFile->IsCurrent);
							//	JustifyString(Line,12, TRUE);
								TextOut (pd.hDC, xStart + 61 * tm.tmAveCharWidth,yStart ,Line, _tcslen(Line) );

								_tcscpy (Line,CurrentFile->InstallPath);
								TextOut (pd.hDC, xStart + 72 * tm.tmAveCharWidth,yStart ,Line, _tcslen(Line) );
								++CurrentLine;

								yStart = CurrentLine * yChar;
								if (yStart >=   (UINT)rect.bottom)
								{
//									MessageBox (NULL,_T("Hit Page Break Code"),NULL,MB_OK);
									EndPage(pd.hDC);
									NewPage(pd.hDC, Header1,Header2, &CurrentLine, &logFont);
									yStart = CurrentLine * yChar;
								} 
								CurrentFile = CurrentFile->pNext;
								if (!bUserAbort)
									Done = TRUE;
								
							} // End While Current File
							++CurrentLine;

							yStart = CurrentLine * yChar;
							if (yStart >=   (UINT)rect.bottom)
							{
								EndPage(pd.hDC);
								NewPage(pd.hDC, Header1,Header2, &CurrentLine, &logFont);
								yStart = CurrentLine * yChar;
							} 
							CurrentHotfix = CurrentHotfix->pNext;
							if (!bUserAbort)
								Done = TRUE;
						}
						++CurrentLine;
						yStart = CurrentLine * yChar;
						if (yStart >=   (UINT)rect.bottom)
						{
							EndPage(pd.hDC);
							NewPage(pd.hDC, Header1,Header2, &CurrentLine, &logFont);
							yStart = CurrentLine * yChar;
						} 
						CurrentProduct = CurrentProduct->pNext;
						if (!bUserAbort)
							Done = TRUE;
					}

					if (EndPage(pd.hDC) > 0)
						EndDoc(pd.hDC);
					DeleteDC(pd.hDC);
					DestroyWindow(hDlgPrint);
				
				
			
		

		
	}
	return; //FALSE;
}


int CALLBACK CListViews::CompareFunc (LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
	int Result = -1;
	int SubItemIndex = (INT) lParamSort;
	
	_TCHAR String1[1000];
	_TCHAR String2 [1000];


	ListView_GetItemText( TopList, lParam1, SubItemIndex, String1, 1000);
	ListView_GetItemText( TopList, lParam2, SubItemIndex, String2, 1000);
	if (! (String1 && String2) )
		return 1;
	if (m_SortOrder)   // Sort Acending
	{
		Result = _tcscmp(String1,String2);
	}
	else						// Sort Decending
	{
		Result = -_tcscmp(String1,String2);
	}
	if (Result == 0)
		Result = -1;
	return Result; 
}