Click here to Skip to main content
15,867,686 members
Articles / Web Development / HTML
Article

A GUI Front-End for Microsoft's Hotfix Checker Utility

Rate me:
Please Sign up or sign in to vote.
4.67/5 (3 votes)
6 Dec 20018 min read 217K   3.9K   41   39
This article demonstrates redirecting output of a child process, and displaying a web browser UI using DHTML.

 [WHotfixCheck dialog - 28K]

Introduction

Microsoft recently released a tool called Hfnetchk that checks NT 4 and Windows 2000 systems and generates a report of which service packs and hotfixes need to be installed. While this is a great idea, the tool is a console-mode program and only prints out a list of Knowledge Base article numbers; it doesn't list URLs or take you to the Knowledge Base articles about the hotfixes. Fortunately, Hfnetchk has a switch to produce tab-delimited output, which makes it rather simple to parse the output and show it in a more friendly UI. This article describes WHotfixCheck, a tool I wrote to provide just such a friendly UI, and touches on some interesting programming topics that I encountered while writing it.

Updates:

  • Sept. 23, 2001 - Added ability to scan remote computers. Added code to save and load last-used settings to/from the registry. Thanks to Uwe Keim for adding these new features!
  • Oct. 11, 2001 - Added Save Results button to save the scan results to an HTML file.
  • Oct 18, 2001 - Added support for more Hfnetchk switches: show missing or installed hotfixes, skip registry checks, verbose output. Made the HTML output a bit nicer-looking.
  • Nov. 7, 2001 - Improved handling of errors and messages from Hfnetchk. If Hfnetchk outputs a message (such as "no hotfixes available"), WHotfixCheck now shows that in a message box. Added XP theme support.

Using WHotfixCheck

To use WHotfixCheck, you must first download and install Hfnetchk from Microsoft. Browse to the Knowledge Base article on the tool and follow the download link in that article. Once it's installed, run WHotfixCheck and enter the path to hfnetchk.exe in the top edit box. If you have never run Hfnetchk before, leave the other edit box empty and Hfnetchk will download the necessary data file. If you have run it, there will be a file called mssecure.xml in the same directory as hfnetchk.exe; enter the path to that file in the second edit box.

In the Hotfixes to show combo box, select which hotfixes you want to see. The default is Necessary hotfixes, which shows hotfixes you have not installed. Select Installed hotfixes to see hotfixes you have already installed. Missing hotfixes is similar to Necessary hotfixes but also shows hotfixes that have been superseded by later hotfixes.

If you are viewing installed hotfixes, and WHotfixCheck reports that a hotfix that you have already installed is missing, check the Skip registry checks checkbox. Not all hotfixes are recorded in the registry, so they are always reported as not being installed. Checking Skip registry checks makes Hfnetchk ignore such hotfixes and not report them.

Check Verbose output if you want to see additional details in the hotfix list. This will show the status for each hotfix (found, not found, etc.) and an explanation of how Hfnetchk determined the status.

In the What to Scan combo box is a list of options relating to what computers should be scanned. Hfnetchk can remotely scan any computer on which you have administrator privileges. You can choose to scan just your local computer, a remote computer (identified by its name or IP address), a range of IP addresses, or an entire domain.

Once you have provided the locations of the needed files, click Run to begin the scan. If everything goes well, you will see a list of available hotfixes that are not installed on your computer. See the screen shot above for an idea of what the list looks like. Each line of the table lists the computer name, product name, Microsoft security bulletin number, and Knowledge Base article number. The latter two columns are linked to the corresponding web pages at Microsoft's site, so you can use those links to quickly get to Microsoft's descriptions of the hotfixes.

After running a scan, you can save the results to an HTML file by clicking the Save Results button.

Implementation Details

In this section I'll describe some of the more interesting parts of the code. You can safely skip this section if you aren't concerned with the internal workings of the program.

Running Hfnetchk and capturing its output

If WHotfixCheck were a console program, we could use the CRT function _popen() to run Hfnetchk and read its output. However, _popen() doesn't work when called from a GUI program, so we must create a pipe ourselves and attach it to Hfnetchk's standard output.

The first step is to set up security attributes for the pipe handles. The SECURITY_ATTRIBUTES struct contains a flag that determines whether the child process we'll launch can inherit handles from our process. This flag must be set to TRUE.

LRESULT CMainDlg::OnRun(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
// ...
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES) };
 
    sa.bInheritHandle = TRUE;

Next, we create the pipe. We get back two handles, one to the read end and one to the write end.

HANDLE hStdoutRd, hStdoutWr;
 
    if ( !CreatePipe ( &hStdoutRd, &hStdoutWr, &sa, 0 ))
        return 0;

Next, we set up the structures used by CreateProcess(). The important part here is that we set the child process's standard output to be the write end of the pipe.

STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi;
 
    si.dwFlags = STARTF_USESTDHANDLES;
    si.hStdOutput = hStdoutWr;

Next, we launch Hfnetchk.

if ( !CreateProcess ( NULL, szCommandLine, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS,
                      NULL, NULL, &si, &pi ))
    {
    // error handling omitted
    return 0;
    }

The fifth parameter is a flag that indicates whether the child process inherits our handles. This must be TRUE for Hfnetchk to be able to use the pipe handle we're passing it.

Once Hfnetchk has been launched, we can start reading its output. To make parsing easier, we dump the output to a temp file first. The first step is to close our handle to the write end of the pipe. If we don't do this, the write end will not close when Hfnetchk is done with it, because the pipe won't close when there are open handles to it.

CloseHandle ( hStdoutWr );

Next, we create a temp file to store Hfnetchk's output.

HANDLE hTempFile;
 
    hTempFile = CreateFile ( szTempFile, GENERIC_WRITE, 0, NULL, 
                             CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
 
    if ( INVALID_HANDLE_VALUE == hTempFile )
        return 0;

Now we can enter a loop and read the data from the pipe.

BYTE buff[1024];
DWORD dwRead, dwWritten;
 
    while ( ReadFile ( hStdoutRd, buff, countof(buff), &dwRead, NULL ) && dwRead != 0 )
        {
        WriteFile ( hTempFile, buff, dwRead, &dwWritten, NULL );
        }

ReadFile() will return FALSE when Hfnetchk has written all its data into the pipe and terminated, thus closing the write end of the pipe.

After that, it's a simple matter of parsing the lines with strtok(). Each line contains details about one hotfix. We pull out the computer name, product name, security bulletin number, and Knowledge Base article number and store them in a struct:

struct CPatchInfo
{
    CString sComputer, sProduct, sBulletin, sKBNumber;
};

OnRun() builds an array of structs and passes it to ShowPatchList(), which handles the UI.

Displaying the results

WHotfixCheck hosts a WebBrowser control and uses the IE DHTML object model to display HTML in the browser. The starting point it to get an IWebBrowser2 pointer on the control.

void CMainDlg::ShowPatchList ( CSimpleArray<CPatchInfo>& aPatchInfo )
{
CComPtr<IUnknown>       punkIE;
CComQIPtr<IWebBrowser2> pWB2;
 
    // Get an IWebBrowser2 interface to control the browser.
    AtlAxGetControl ( GetDlgItem(IDC_IE), &punkIE );
    pWB2 = punkIE;

Now, we can get a pointer to the HTML document, and then the <body> element. Once we have access to the body, we can insert any HTML we want. (There's actually a lot more code involved, but I've omitted it here for clarity.)

CComPtr<IDispatch>        pdispDoc;
CComQIPtr<IHTMLDocument2> pDoc;
CComPtr<IHTMLElement>     peltBody;
 
    // Get a pointer to the <body> element so we can insert a table.
    pWB2->get_Document ( &pdispDoc );
    pDoc = pdispDoc;
    pDoc->get_body ( &peltBody );

Now we can insert HTML into the body. The first step is to create a <table> with one row that contains the column headings.

// Replace the body with the beginnings of our table.
peltBody->put_innerHTML ( CComBSTR("<table width=100% id=\"patches\" cols=3><tr>...</tr></table>"));

The <table> has an id field so we can modify it with the DHTML object model. The next step is to get a IHTMLTable interface on the table. There are two ways to do this. To maintain compatibility with IE 4, WHotfixCheck accesses the all collection of the document and gets the table from that collection. A simpler way is to use IHTMLDocument3::getElementById() to get an interface on the table by passing its id, but this method requires IE 5.

CComPtr<IHTMLElementCollection> pColl;
CComPtr<IDispatch>    pdispTable;
CComQIPtr<IHTMLTable> pTable;
 
    pDoc->get_all ( &pColl );
 
    pColl->item ( CComVariant("patches"), CComVariant(0), &pdispTable );
    pTable = pdispTable;

Now we can start adding rows to the table. We loop through the array of CPatchInfo structs and for each one, assemble either a string or an HTML fragment to go in the table. Adding to the table involves first adding a row, then adding cells to the row. Here's how we add a new row:

for ( int i = 0; i < aPatchInfo.GetSize(); i++ )
    {
    CComPtr<IDispatch> pdispRow;
    CComQIPtr<IHTMLTableRow> pRow;

    // Add a new row to the end of the table.
    pTable->insertRow ( -1, &pdispRow );
    pRow = pdispRow;

Passing a row index of -1 puts the new row at the end of the table. With the IHTMLTableRow interface, we can add cells to the row. Here is the code to add column 1, a plain string listing the computer name:

CComPtr<IDispatch> pdispCell;
CComQIPtr<IHTMLElement> peltCell;
 
        // Col 1 - computer name
        pRow->insertCell ( -1, &pdispCell );
        peltCell = pdispCell;
 
        peltCell->put_innerText ( CComBSTR(aPatchInfo[i].sComputer) );
 
        pdispCell.Release();
        peltCell.Release();

IHTMLElement::put_innerText() sets the text of the element. The word "inner" indicates that the text being changed is inside the HTML tags (<td> and </td> in this case). Column 2 is created similarly, and shows the product name.

For column 3, we create an HTML fragment containing an <a> tag, which makes a hyperlink.

        // Col 3 - security bulletin name/URL
CString sText;
 
        pRow->insertCell ( -1, &pdispCell );
        peltCell = pdispCell;
 
        sText.Format ( _T("<a href=\"http://www.microsoft.com/technet/security/bulletin/%s.asp\" target=_blank>%s</a>"),
                       (LPCTSTR) aPatchInfo[i].sBulletin, (LPCTSTR) aPatchInfo[i].sBulletin );

        peltCell->put_innerHTML ( CComBSTR(sText) );
 
        pdispCell.Release();
        peltCell.Release();

This time we use IHTMLElement::put_innerHTML() to insert an HTML fragment into the cell. Column 4 is created similarly to column 3, and links to the Knowledge Base article.

As you can see, accessing the DHTML object model from C++ is a bit cumbersome, since many methods return IDispatch interfaces, which you then have to query for the interface you really need. The documentation is also lacking in some areas, most notably the fact that the Web Workshop pages that have the object model reference do not appear in the Contents pane, so you can't use the Locate button in the help viewer. I would normally use the Locate button to jump right to the list of methods in an interface.

Room for Improvement

The code in ShowPatchList() that gets a pointer to the <body> is rather ugly, since it has to handle the special case of the first call, where there is no document or body in the WebBrowser yet. I threw together something that creates a dummy body, since I found no IHTMLDocument method that looked like it could do the job.

Links

Find out more about Hfnetchk in these Knowledge Base articles:

WHotfixCheck and Hfnetchk require Microsoft's XML parser. Download version 3 here.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior) VMware
United States United States
Michael lives in sunny Mountain View, California. He started programming with an Apple //e in 4th grade, graduated from UCLA with a math degree in 1994, and immediately landed a job as a QA engineer at Symantec, working on the Norton AntiVirus team. He pretty much taught himself Windows and MFC programming, and in 1999 he designed and coded a new interface for Norton AntiVirus 2000.
Mike has been a a developer at Napster and at his own lil' startup, Zabersoft, a development company he co-founded with offices in Los Angeles and Odense, Denmark. Mike is now a senior engineer at VMware.

He also enjoys his hobbies of playing pinball, bike riding, photography, and Domion on Friday nights (current favorite combo: Village + double Pirate Ship). He would get his own snooker table too if they weren't so darn big! He is also sad that he's forgotten the languages he's studied: French, Mandarin Chinese, and Japanese.

Mike was a VC MVP from 2005 to 2009.

Comments and Discussions

 
GeneralThank you! Pin
Parchandri18-Apr-04 21:33
Parchandri18-Apr-04 21:33 
GeneralRe: Thank you! Pin
Michael Dunn19-Apr-04 4:54
sitebuilderMichael Dunn19-Apr-04 4:54 
QuestionPotential Security Concerns? Pin
John Aldrich7-Jul-03 15:13
John Aldrich7-Jul-03 15:13 
AnswerRe: Potential Security Concerns? Pin
Michael Dunn7-Jul-03 15:57
sitebuilderMichael Dunn7-Jul-03 15:57 
QuestionFuture Release? Pin
Bard16-Jul-02 2:11
Bard16-Jul-02 2:11 
AnswerRe: Future Release? Pin
Michael Dunn16-Jul-02 17:53
sitebuilderMichael Dunn16-Jul-02 17:53 
GeneralRe: Future Release? Pin
Bard21-Aug-02 22:34
Bard21-Aug-02 22:34 
GeneralStop working on support for 3.2, 3.3 is released Pin
Thomas Freudenberg28-Feb-02 2:03
Thomas Freudenberg28-Feb-02 2:03 
QuestionPlanning to support 3.2? Pin
Matt Philmon25-Nov-01 16:50
Matt Philmon25-Nov-01 16:50 
AnswerRe: Planning to support 3.2? Pin
Michael Dunn25-Nov-01 17:14
sitebuilderMichael Dunn25-Nov-01 17:14 
GeneralHotfix reporter Pin
Simon Hughes14-Nov-01 22:33
Simon Hughes14-Nov-01 22:33 
GeneralRe: Hotfix reporter Pin
Michael Dunn15-Nov-01 19:42
sitebuilderMichael Dunn15-Nov-01 19:42 
GeneralRe: Hotfix reporter Pin
Chris Maunder15-Nov-01 20:01
cofounderChris Maunder15-Nov-01 20:01 
GeneralWindow XP fun Pin
Darren Schroeder5-Nov-01 15:25
Darren Schroeder5-Nov-01 15:25 
GeneralRe: Window XP fun Pin
Michael Dunn5-Nov-01 20:38
sitebuilderMichael Dunn5-Nov-01 20:38 
GeneralRe: Window XP fun Pin
Michael Dunn7-Nov-01 9:47
sitebuilderMichael Dunn7-Nov-01 9:47 
GeneralIf WHC is crashing for you, download Hfnetchk using the link at the top of this article. Pin
Michael Dunn25-Oct-01 10:39
sitebuilderMichael Dunn25-Oct-01 10:39 
GeneralHelp for newbie Pin
25-Oct-01 6:38
suss25-Oct-01 6:38 
I can't get this to work on my Win2K SP2 laptop. I've installed both WHotfixCheck.exe and hfnetcheck.exe to C:\HotFixChecker.

The command line tool works fine, but when I click the "Run" button of WHotfixCheck, I get an access violation (instruction 0x40137f tries to access location 0). Feh.

I tried to download and compile the project using VC6 SP5 so that I can debug it, but the project is missing ATLRES.H, so it won't compile. Feh.

Any ideas?

Doug SchmidtConfused | :confused:
GeneralRe: Help for newbie Pin
Michael Dunn25-Oct-01 7:00
sitebuilderMichael Dunn25-Oct-01 7:00 
GeneralRe: Help for newbie Pin
26-Oct-01 12:49
suss26-Oct-01 12:49 
GeneralFYI: HFNetChk 3.2 released Pin
Thomas Freudenberg25-Oct-01 5:26
Thomas Freudenberg25-Oct-01 5:26 
GeneralRe: FYI: HFNetChk 3.2 released Pin
Michael Dunn25-Oct-01 10:32
sitebuilderMichael Dunn25-Oct-01 10:32 
GeneralExcellent work :) Pin
14-Oct-01 23:46
suss14-Oct-01 23:46 
GeneralFoo ?!! Pin
Andrew Peace11-Oct-01 10:42
Andrew Peace11-Oct-01 10:42 
GeneralRe: Foo ?!! Pin
Michael Dunn11-Oct-01 16:06
sitebuilderMichael Dunn11-Oct-01 16:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.