Monday, December 10, 2007

BIRT: Dynamic Images

There was a question on the BIRT newsgroup about how to put a dynamic image into a report file. This is typically done in multi-company sites, where a different header or logo will appear based on some environmental parameter. In the following example I will show how to do this with a report parameter, although the same thing can be done based on a URL.

The following example will show one of two logos, depending on the value of a report parameter. If the value is equal to 0, we will show the Eclipse logo at

http://www.eclipse.org/eclipse.org-common/themes/Phoenix/images/eclipse_home_header.jpg

If the value is 1, we will show the BIRT Exchange logo:

http://www.birt-exchange.com/themes/birt/images/homep_r1_c1.gif

This image will reside in the Master Page of the report. So lets take a look at how to do this.

  1. First, create a new report called DynamicImage.rptDesign

Figure 1. Create new Report

  1. In the new report design, open up the Master Page tab.
  2. Drag over a grid, and make it 2 column, 1 row.
  3. In the 1st column, drag over an Image component.
  4. For the URL, put in “http://www.eclipse.org/eclipse.org-common/themes/Phoenix/images/eclipse_home_header.jpg”. Be sure to keep the quotes. This is more as a place holder than anything else.

Figure 2. Master Page with Image

  1. Create a new report parameter called imageSelector. It needs to be an Integer type. In the following screen shot, I am using a List Box and a List of Values for this purpose.

Figure 3. Create new Parameter

  1. Select the Image.
  2. Open the Script tab in the Report Designer
  3. Change the Event to onRender.
  4. Use the following BIRT Script
if (params["imageSelector"] == 0)
{
this.setURL("http://www.eclipse.org/eclipse.org-common/themes/Phoenix/images/eclipse_home_header.jpg");
}
else
{
this.setURL("http://www.birt-exchange.com/themes/birt/images/homep_r1_c1.gif");
}

  1. Save and run.

When you set the value to Eclipse, it will show the Eclipse logo. When set to the BIRT Exchange, it will show that logo.

Figure 4. The Final Report

Saturday, December 08, 2007

BIRT: Passing Serialized Objects as Parameters

Recently I had a question about being able to serialize Java Objects and use them as the data source. I have a few possible solutions, but I wanted to look at one of the options a little deeper.

In this scenario, the Java Objects are actually generated outside of the report application, and need to be passed to the report as a parameter. The easiest way was to create a Java class that extends the java.io.Serializable class. In additional to using the Serializable class, I also want to URL encode the serialized class. What this means is that I need to Decode and Deserialize the class inside of the report.

The following is a walkthrough of the classes that I built, and an external Java Event Handler for a Report Design that will handle the object.

To demonstrate this, I used the following Java class.

package com.digiassn.blogspot;

import java.io.Serializable;

public class EmployeeParameter implements Serializable {
static final long serialVersionUID = 11111112;

private int employeeNumber;
private String date;
public int getEmployeeNumber() {
return employeeNumber;
}
public void setEmployeeNumber(int employeeNumber) {
this.employeeNumber = employeeNumber;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}


}



Not much to this class. The serialVersionUID was defined to avoid issues with the URLEncode and URLDecode process, which if not implicitly defined, causes the URLDecode of the object to fail. This is also the same reason I used String as my Date type instead of the java.util.Date. For some reason there were errors with the Date and its use of the serialVersionUID (yet, String, and a few other classes didn’t have any issues).

I wanted to test to see if the whole serialize and URLEncode process would work, so I created the following Unit test.

package com.digiassn.blogspot.tests;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

import junit.framework.TestCase;

import com.digiassn.blogspot.EmployeeParameter;

public class TestEmployeeParameter extends TestCase {
private EmployeeParameter param;

protected void setUp() throws Exception {
super.setUp();

param = new EmployeeParameter();

param.setEmployeeNumber(1);
param.setDate("01-01-2005");
}

protected void tearDown() throws Exception {
super.tearDown();
}

public void testGetEmployeeNumber() {
assertEquals(1, param.getEmployeeNumber());
}

public void testGetDate() {
assertEquals("01-01-2005", param.getDate());
}

public void testSerialize()
{
ByteArrayOutputStream bos = null;
try {
bos = new ByteArrayOutputStream();
ObjectOutputStream obj_out = new ObjectOutputStream (bos);
obj_out.writeObject ( param );
} catch (IOException e) {
e.printStackTrace();
fail("Error with serialization\n\n");
}

String encoded = bos.toString();
try {
encoded = URLEncoder.encode(encoded, "UTF-8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();

fail("Unsupported formatting");
}
System.out.print("The serialized output is: " + encoded);

try {
String toDecode = URLDecoder.decode(encoded, "UTF-8");
ByteArrayInputStream bis = new ByteArrayInputStream(toDecode.getBytes());
ObjectInputStream obj_in = new ObjectInputStream (bis);

Object obj = obj_in.readObject();

if (obj instanceof EmployeeParameter)
{
assertEquals(1, ((EmployeeParameter)obj).getEmployeeNumber());
assertEquals("01-01-2005", ((EmployeeParameter)obj).getDate());
}
} catch (IOException e) {
e.printStackTrace();
fail("Error with deserialization");
} catch (ClassNotFoundException e) {
e.printStackTrace();
fail("Error with deserialization");
}

}

}


So, my next task is to create the Event Handler. In BIRT, event handlers need to extend their appropriate event handler type. Since this is a Scripted Data Source, I need to extend the org.eclipse.birt.report.engine.api.script.eventadapter.ScriptedDataSetEventAdapter type.

package com.digiassn.blogspot.handlers;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

import org.eclipse.birt.report.engine.api.script.IReportContext;
import org.eclipse.birt.report.engine.api.script.IUpdatableDataSetRow;
import org.eclipse.birt.report.engine.api.script.ScriptException;
import org.eclipse.birt.report.engine.api.script.eventadapter.ScriptedDataSetEventAdapter;
import org.eclipse.birt.report.engine.api.script.instance.IDataSetInstance;

import com.digiassn.blogspot.EmployeeParameter;

public class EmployeeEventHandler extends ScriptedDataSetEventAdapter {
private EmployeeParameter param;
int count = 0;

@Override
public boolean fetch(IDataSetInstance dataSet, IUpdatableDataSetRow row) {

if (count < 1)
{
try {
if (param == null)
{
row.setColumnValue("employeeNumber", -1);
row.setColumnValue("setDate", "Error, param is null");
}
else
{
row.setColumnValue("employeeNumber", param.getEmployeeNumber());
row.setColumnValue("setDate", param.getDate());
}
count++;

return true;
} catch (ScriptException e) {
e.printStackTrace();
}
}


return false;
}

@Override
public void beforeOpen(IDataSetInstance dataSet,
IReportContext reportContext) {

String myParam = null;

try {
myParam = URLDecoder.decode((String) reportContext.getParameterValue("employeeParam"), "UTF-8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
System.out.println("Got parameters");
ByteArrayInputStream bis = new ByteArrayInputStream(myParam.getBytes());

try {
ObjectInputStream obj_in = new ObjectInputStream(bis);

param = (EmployeeParameter)obj_in.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}




So, now I have the event handler made, I need to create the report. To create the report I use the following steps:
1: Create a new report.
2: Create a Scripted Data Source.
3: Create a data set.
4: Add in the following two fields into the data set
-employeeNumber
-setDate
5: Add a report parameter called employeeParam.
6: Drag the data set over to the report design window.
7: Select the new data set in the Data Explorer.
8: In the Property Editor. Select the Event Handler tab.
9: Under the Event Hander, browse and select the Java Object Event handler.

Now, when I run the report, my report will use the external object. I need to pass in the serialized version of the object. In my case, I used the following test string.

%C2%AC%C3%AD%05sr5com.digiassn.blogspot.EmployeeParameter%C2%A9%C5%A0%C3%88%02%02I%0EemployeeNumberL%04datet%12Ljava%2Flang%2FString%3Bxp%01t%0A01-01-2005



I would recommend that you use the Unit test and copy the serialized object from the standard output device.

And that’s it. Now, I deployed this to an Apache Tomcat server using the BIRT Web Viewer to view my report. I had to copy the .class files for EmployeeParameter and the event handler into the shared class folder under Tomcat. I also needed copy all the JAR files in the Web Viewer into the shared lib folder to get around some silly bug in the Web Viewer (note: this was not a problem prior to version 2.2.1).

I still ran into one outstanding issue with this approach. If I tried to use the serialized object in a URL parameter in a browser, I would get a SaxParser error. This wasn’t a problem if I passed the parameter using the dialog in the web viewer, or if I assigned the parameter using the Report Engine API, so it must have something to do with the way the Viewer app handles its SOAP requests.

Monday, November 26, 2007

BIRT: Dynamic Adding Tables and Columns

I had a request from a co-worker the other day wanting to know how Columns could be Dynamically added to Tables in BIRT. The following example is a Initialize Event Handler used in a BIRT report to dynamically create a table, add a few columns, and a single row. Once added to the report, the script then finds the Table in the report, and adds a single column to the report.


//get a reference to the ElementFactory
elementFactory = reportContext.getReportRunnable().designHandle.getElementFactory();

//create a new table with 3 columns
dynamicTable = elementFactory.newTableItem("myNewTable", 3);
dynamicTable.setWidth("100%");

//set reference to the first detail row
myNewRow = dynamicTable.getDetail().get(0);

//get references to the first 3 cells
firstCell = myNewRow.getCells().get(0);
secondCell = myNewRow.getCells().get(1);
thirdCell = myNewRow.getCells().get(2);

//create the cells and add
label = elementFactory.newLabel("firstCellLabel");
label.setText("First Cell");
firstCell.getContent().add(label);

label = elementFactory.newLabel("secondCellLabel");
label.setText("Second Cell");
secondCell.getContent().add(label);

label = elementFactory.newLabel("thirdCellLabel");
label.setText("Third Cell");
thirdCell.getContent().add(label);

//although it is not in the autocomplete, getBody is a method of the ReportDesignHandle class
reportContext.getReportRunnable().designHandle.getBody().add(dynamicTable);

//now, to demonstrate, get a reference to the table fromt he report design, this automatically cast
//to a TableHandel type
dynamicTable = reportContext.getReportRunnable().designHandle.findElement("myNewTable");

//now insert the column to the right of the indicated column position. Column number is 1 based, not 0 based
dynamicTable.insertColumn(3, 1);

//get the first detail row and the 4th column. This is 0 based
myNewRow = dynamicTable.getDetail().get(0);
forthCell = myNewRow.getCells().get(3);

//create a new label
label = elementFactory.newLabel("forthCell");
label.setText("dynamic cell");
forthCell.getContent().add(label);

Saturday, October 20, 2007

BIRT: Parameterized Page Break Interval

A useful trick to know with BIRT is how to control the pagination for report output. It would be nice if you could present the user with a parameter to control the number of rows displayed per page and let them decide. While there is the page_break_interval property in a table, it is not easily exposable. Thanks to Jason Weathersbys of BirtWorlds help, I have a simply answer on how to create a parameter and assign the page_break_interval the value I need.

What I did was create a user parameter called NewParameter. I know, clever name, but this was just at test scenario. I have a table called counTable that will output the results of a dataset. Then, I used the following script in the tables onPrepare event handler (although this could be done in the reports Initialize event handler also):

tableContext = reportContext.getReportRunnable().designHandle.getDesignHandle().findElement("countTable");

tableContext.setPageBreakInterval(params["NewParameter"]);


That’s it. Now, when the report is displayed, a parameter will prompt the user to enter the number of rows to break each page on. This is useful when used with the Progressive Viewing feature to allow the user to really control pagination when embedding BIRT into an application. The completed report is below in XML.

<?xml version="1.0" encoding="UTF-8"?>
<report xmlns="http://www.eclipse.org/birt/2005/design" version="3.2.14" id="1">
<property name="author">John Ward</property>
<property name="createdBy">Eclipse BIRT Designer Version 2.2.0.v20070620 Build &lt;2.2.0.v20070626-1003></property>
<property name="units">in</property>
<text-property name="title">Page Break Interval</text-property>
<property name="comments">Copyright (c) 2007 &lt;&lt;Your Company Name here>></property>
<html-property name="description">A test report that will generate a data set with 6000 numbers, then assign the tables page break interval using a parameter.</html-property>
<text-property name="displayName">Blank Report</text-property>
<property name="iconFile">/templates/blank_report.gif</property>
<parameters>
<scalar-parameter name="NewParameter" id="6">
<property name="valueType">static</property>
<property name="dataType">string</property>
<text-property name="promptText">Page Break Interval</text-property>
<property name="controlType">text-box</property>
<property name="defaultValue">5</property>
<structure name="format">
<property name="category">Unformatted</property>
</structure>
</scalar-parameter>
</parameters>
<data-sources>
<script-data-source name="Data Source" id="23"/>
</data-sources>
<data-sets>
<script-data-set name="Data Set" id="24">
<list-property name="resultSetHints">
<structure>
<property name="position">0</property>
<property name="name">count</property>
<property name="dataType">any</property>
</structure>
</list-property>
<list-property name="columnHints">
<structure>
<property name="columnName">count</property>
</structure>
</list-property>
<structure name="cachedMetaData">
<list-property name="resultSet">
<structure>
<property name="position">1</property>
<property name="name">count</property>
<property name="dataType">any</property>
</structure>
</list-property>
</structure>
<property name="dataSource">Data Source</property>
<method name="open"><![CDATA[x = 0;]]></method>
<method name="fetch"><![CDATA[if (x < 6000)
{
x++;
row["count"] = x;

for (y = 0; y < 6000; y++);

return true;
}

return false;]]></method>
</script-data-set>
</data-sets>
<page-setup>
<simple-master-page name="Simple MasterPage" id="2">
<page-footer>
<text id="3">
<property name="contentType">html</property>
<text-property name="content"><![CDATA[<value-of>new Date()</value-of>]]></text-property>
</text>
</page-footer>
</simple-master-page>
</page-setup>
<body>
<table name="countTable" id="27">
<property name="width">100%</property>
<property name="dataSet">Data Set</property>
<list-property name="boundDataColumns">
<structure>
<property name="name">count</property>
<expression name="expression">dataSetRow["count"]</expression>
<property name="dataType">any</property>
</structure>
</list-property>
<method name="onPrepare"><![CDATA[tableContext = reportContext.getReportRunnable().designHandle.getDesignHandle().findElement("countTable");

tableContext.setPageBreakInterval(params["NewParameter"]);]]></method>
<column id="36"/>
<header>
<row id="28">
<cell id="29">
<label id="30">
<text-property name="text">count</text-property>
</label>
</cell>
</row>
</header>
<detail>
<row id="31">
<cell id="32">
<data id="33">
<property name="resultSetColumn">count</property>
</data>
</cell>
</row>
</detail>
<footer>
<row id="34">
<cell id="35"/>
</row>
</footer>
</table>
</body>
</report>

Sunday, October 07, 2007

BIRT: Progressive Viewing during Render

A coworker and I recently engaged is a discussion about the requirements for a client of ours. Although this ultimately wasn’t the solutions we ended up going with, one of the possible options for this client was to do what is called Progressive Viewing in BIRT. Progressive Viewing is the ability for BIRT to view a particular page out of a report document while the Report Document itself is still rendering. If you have ever used the commercial versions of Actuate IServer or ERD Pro, this is familiar. Page 1 gets displayed, while pages 2 – 10 are still being rendered, then when pages 2 – 10 are renders, the next range of pages gets rendered, and the user can view what is ready to view. Since I wanted to know how to do this for an unrelated project, I decided to research how this is done for future reference.

Surprisingly, this was much easier to implement than I would have thought, with BIRT defining an Interface that acts as a Callback when pages are ready. The way it works is for each page event, a callback method is called with the page number, a checkpoint status of either true or false, which means all pages before this page are ready for viewing, and a checkpoint has been reached, and a reference to the Report Document being rendered so you do not need to create a separate Report Document interface. In the OnPage method, you define what you want to do with it. In the case of an interactive viewer, you would simply notify the parent process that the next batch of pages are ready for the user to navigate forward. In the following example, I am rendering out the “Checkpoint” pages when they are ready, and informating the user via the standard console that the next page range is ready. The following bit is a JUnit Test I used for testing the rendering of a custom emitter I was using for a client, slightly modified to do Progressive Viewing rendering. In addition, it also demonstrates doing a Run then Render task in BIRT to allow for pagination.



package test;

import static org.junit.Assert.fail;

import java.util.logging.Level;

import org.eclipse.birt.core.exception.BirtException;
import org.eclipse.birt.core.framework.Platform;
import org.eclipse.birt.report.engine.api.EngineConfig;
import org.eclipse.birt.report.engine.api.EngineException;
import org.eclipse.birt.report.engine.api.IPageHandler;
import org.eclipse.birt.report.engine.api.IRenderTask;
import org.eclipse.birt.report.engine.api.IReportDocument;
import org.eclipse.birt.report.engine.api.IReportDocumentInfo;
import org.eclipse.birt.report.engine.api.IReportEngine;
import org.eclipse.birt.report.engine.api.IReportEngineFactory;
import org.eclipse.birt.report.engine.api.IReportRunnable;
import org.eclipse.birt.report.engine.api.IRunTask;
import org.eclipse.birt.report.engine.api.RenderOption;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestXMLEmitter {
private String BIRT_HOME = "C:/BIRT_RUNTIME_2_2/birt-runtime-2_2_0/ReportEngine/";
private String REPORT_DESIGN_FILE = "C:/Workbench/pageBreakInterval.rptdesign";
private String OUTPUT_FILE_LOCATION_RENDER = "C:/temp/myReportOutputRender.xml";
private String OUTPUT_FILE_LOCATION_RUN_RENDER = "C:/temp/myReportOutputRunRender.xml";
private IReportEngine engine;

@Before
public void setUp() throws Exception {
EngineConfig config = new EngineConfig();
config.setBIRTHome(BIRT_HOME);
config.setLogConfig("C:/TEMP/", Level.ALL);

try {
Platform.startup( config );
IReportEngineFactory factory = (IReportEngineFactory) Platform.createFactoryObject( IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY);
engine = factory.createReportEngine(config);
engine.changeLogLevel(Level.ALL);
} catch (RuntimeException e) {
e.printStackTrace();
}
}

@After
public void tearDown()
{
engine.shutdown();
Platform.shutdown();
}

/*@Test
//Removed, for our purposes, we do not need to do a run and render task
public void testReportRun() throws Exception {
try {
//once the engine is started, create the report task
IReportRunnable design = engine.openReportDesign(REPORT_DESIGN_FILE);

IRunAndRenderTask task = engine.createRunAndRenderTask(design);

//RenderOption renderOption = new RenderOption();
RenderOption renderOption = new RenderOption();

renderOption.setOutputFormat("MyXMLEmitter");
renderOption.setOutputFileName(this.OUTPUT_FILE_LOCATION_RUN_RENDER);

renderOption.setOutputStream(System.out);
task.setRenderOption(renderOption);

task.setParameterValue("NewParameter", 5);

task.run();

task.close();

} catch (RuntimeException e) {
engine.getLogger().log(Level.SEVERE, e.getMessage(), e);
fail(e.getMessage());
}
} */

@Test
public void testReportRender() throws Exception {
try {
//create the report task and open the report design file
IReportRunnable design = engine.openReportDesign(REPORT_DESIGN_FILE);
IRunTask runTask = engine.createRunTask(design);

//For our test report, we have a parameter called NewParameter, that
//is actually setting the pageBreakInterval property. We need to set this
//before running our report
runTask.setParameterValue("NewParameter", 5);

//Define the callback handler for new page events
runTask.setPageHandler(new MyPageHandler());

//run and close the report run task
runTask.run("C:/temp/tempDoc.rptDocument");
runTask.close();

//Inform the user running is complete
System.out.println("Done running");
} catch (RuntimeException e) {
engine.getLogger().log(Level.SEVERE, e.getMessage(), e);
fail(e.getMessage());
}
}

/**
* Class MyPageHandler
*
* This class will handle new page events for the Report Run Task
*/
public class MyPageHandler implements IPageHandler {

//Define local variables for the callback class
private String OUTPUT_FILE_LOCATION_RUN_RENDER = "C:/temp/myReportOutputRunRender";
private int lastCheckpoint = 0;

/**
* void onPage
*
* @param pageNumber - the page number that is currently be called for event
* @param readyForViewing - is this event a Check POint event
* @param reportDocument - instance to the report document
*/
public void onPage(int pageNumber, boolean readyForViewing, IReportDocumentInfo reportDocument) {
//we only want to do something if this is a checkpoint event
if (readyForViewing)
{
//Just let the user know that the next page ranges are ready, then set the last check point to the
//current page
System.out.println("Pages " + lastCheckpoint + " through " + pageNumber + " are ready for viewing");
lastCheckpoint = pageNumber;

try {
//open the report document then create the render task from it
IReportDocument iReportDocument = reportDocument.openReportDocument();
IRenderTask task = engine.createRenderTask(iReportDocument);

//Set Render context to handle url and image locataions
RenderOption renderOption = new RenderOption();

//set the output file format and the emitter output in the render options
renderOption.setOutputFileName(OUTPUT_FILE_LOCATION_RENDER + pageNumber + ".xml");
renderOption.setOutputFormat("MyXMLEmitter");
task.setRenderOption(renderOption);

//Render Page and close the render task
task.setPageNumber(pageNumber);
task.render();
task.close();

System.out.println("Page " + pageNumber + " is ready for viewing");
} catch (EngineException e) {
e.printStackTrace();
} catch (BirtException e) {
e.printStackTrace();
}
}
}
}
}

Wednesday, September 19, 2007

Repair: USB Device Refuses to Initialize

The past few days have been PC hell for me. Some strange behavior has cropped up my my system that has earned it the right to be re-formatted. Since I am traveling however, I don’t have access to my backup drives or my install CD’s for my new system. So in the meantime, I needed to work around the issues I was having.

A few months ago I wrote about Hacking my Motorola Razr to use as a broadband modem while I travel. This has been working great for the past few months, up until about 3 days ago. Now my system has been behaving odd for the past few days. Things like the “Safely remove this Device” icon disappearing. To resolve that I had to go under Device Manager, right-mouse click on any of the USB disks I had (in my case it was my IPod), go to Policies, and manually click on the Safetly Remove Hardware link in the description text. Ever since that issue has not appeared.

However, the issue that has been driving me nuts is the fact that my Razr stopped working. Everytime I would connect it to my machine, I would get the New Hardware Found wizard and an error stating “An error occured during the installation of this device Fatal Error during installation…”. Now I searched and searched for a few days and found nothing but garbage advice. Things like totally remove all USB devices under Device Manager did not resolve this problem (nor do I think they are the correct solution). I cleared every USB device entry under the registry to reinitialize the know USB device catalog (not something I recommend, and even if you do, backup backup backup). This also didn’t fix the issue. I reinstalled the drivers, updated the drivers, yet nothing would get this device to work. I could plug it into another machine and it would work fine. I could even plug it in running VMWare and set VMWare to use it, with VMWare recognizing the device and it working correctly. So that narrows it down to something software related.

So how did I fix the problem? Well, I went back to good old fasion detective work to figure it out, and worked on blind faith and a prayer. I did a search for any files modified within the past day hoping that some sort of log was laying around. What I came across was 2 log files, setupapi.log and setupact.log (information about these files can be found here). When I opened the file I came across the following entry in the setupapi.log:

#-019 Searching for hardware ID(s): usb\vid_22b8&pid_2a62&rev_0001,usb\vid_22b8&pid_2a62
#-018 Searching for compatible ID(s): usb\class_02&subclass_02&prot_01,usb\class_02&subclass_02,usb\class_02
#-198 Command line processed: C:\WINDOWS\system32\services.exe
#I022 Found "USB\VID_22B8&PID_2A62" in C:\WINDOWS\inf\oem44.inf; Device: "Motorola USB Modem"; Driver: "Motorola USB Modem"; Provider: "Motorola"; Mfg: "Motorola"; Section name: "USB1XCDMA".
#I023 Actual install section: [USB1XCDMA.NT]. Rank: 0x00000001. Effective driver date: 06/18/2007.
#-166 Device install function: DIF_SELECTBESTCOMPATDRV.
#I063 Selected driver installs from section [USB1XCDMA] in "c:\windows\inf\oem44.inf".
#I320 Class GUID of device remains: {4D36E96D-E325-11CE-BFC1-08002BE10318}.
#I060 Set selected driver.
#I058 Selected best compatible driver.
#-166 Device install function: DIF_INSTALLDEVICEFILES.
#I124 Doing copy-only install of "USB\VID_22B8&PID_2A62\5&B4DCBF&0&2".
#-166 Device install function: DIF_REGISTER_COINSTALLERS.
#I056 Coinstallers registered.
#-166 Device install function: DIF_INSTALLINTERFACES.
#-011 Installing section [USB1XCDMA.NT.Interfaces] from "c:\windows\inf\oem44.inf".
#I054 Interfaces installed.
#-166 Device install function: DIF_INSTALLDEVICE.
#E151 Coinstaller 3 of 3 failed. Error 1603: Fatal error during installation.

Huh… what is the CoInstaller? I checked the next file hoping to find another clue:

WdfCoInstaller: [09/18/2007 16:38.06.531] Update process returned error code :error(1603) Fatal error during installation.
. Possible causes are running free version of coinstaller on checked version of OS or vice versa. Look at the Kmdf documentation as to what steps need to be followed to install the correct versionof the coinstaller

What is this? Another clue. So there is definitely a problem with this WdfCoInstaller. A nother search on my system turned up the final clue, a log file called Wdf01005Inst.log. I took a look inside of that:

0.047: 2007/09/18 16:38:06.312 (local)
0.047: c:\6cdccf09bac8c0c517fbc0e694\update\update.exe (version 6.3.4.0)
0.047: Hotfix started with following command line: /quiet
0.047: In Function GetBuildType, line 1170, RegQueryValueEx failed with error 0x2
0.047: C:\WINDOWS\system32\DRIVERS\wdf01000.sys is Present
0.047: FileVersion of C:\WINDOWS\system32\DRIVERS\wdf01000.sys is Greater Than 1.5.5600.0
0.047: Condition Check for Line 1 of PreRequisite returned FALSE
0.047: ReadStringFromInf: UpdSpGetLineText failed: 0xe0000102
0.047: Wdf01005 Setup encountered an error: Setup cannot continue because one or more prerequisites required to install Wdf01005 failed. For More details check the Log File c:\windows\Wdf01005Inst.log
0.062: ReadStringFromInf: UpdSpGetLineText failed: 0xe0000102
0.062: Setup cannot continue because one or more prerequisites required to install Wdf01005 failed. For More details check the Log File c:\windows\Wdf01005Inst.log
0.062: Update.exe extended error code = 0xf0f4
0.062: Update.exe return code was masked to 0x643 for MSI custom action compliance.


This solidifies it, I had tracked down the problem. I made a backup copy of the C:\Windows\system32\Drivers\wdf01000.sys and deleted it. When I re-ran the install, it worked fine. Thanks to logs I was able to track down the issue, not the fall back street level tech resolution of reformat and reinstall OS.

Although I fixed my issues, I am still going to reformat my system. I haven’t installed anything or changed anything that would cause this previously working setup to change, especially something that relies on Kernel Mode drivers. So without any relevant changes to my system, with yet changing behavior, it would leave me to believe something else is afoot. So better safe than sorry. time, unfortunately, is not something I have the luxury of having at the moment to track down issues.