Category Archives: Software

Converting Microsoft Error Numbers into Something Useful

For whatever reason sometimes when I’m using OLEDB or ADODB error numbers are given as longs rather than as the more useful HEX numbers. More often than not these days when OLEDB or ADODB errors are thrown there’s no accompanying description so having the error number in a useful format is vital so I can work out what the heck the error actually is. The long format is not useful but the HEX format is because that’s the number Microsoft use in all their documentation. So how do you convert an error like this to something useful:

Error Number:-2147467259
Error Description:

Turns out it’s fairly simple. Just fire up the Windows calculator and put it into programmer mode, choose the Dec number format and enter the error code. It should look something like this:

Error in Decimal Format

Error in Decimal Format

Once you’ve done that convert the long to a HEX number and it should look like this:

Error in HEX Format

Error in HEX Format

The vital thing we see her is the last 8 digits. The error number is 80004005 which is then easily Googled. It turns out that it’s some sort of error establishing a connection to a database using OLEDB.

Compiled HTML Help and Online Help Documents

All my products ship with documentation in the form of a compiled HTML (CHM) file. I also provide the same content online. Maintaining the two different HTML projects was always a pain which I could have solved through the use of a third party tool like Help and Manual. But I am cheap and a few years ago I hit on a solution that allows me to maintain a single copy of my documentation and build it to a compiled help file or upload it as HTML to a website.

Tag the HTML

My individual help files (which are all just HTML files) are littered with custom tags encapsulated within HTML comment tags. So, for example when my help files are displayed online I like to display a simple menu at the top of each page, but I do not want this appearing in the CHM version. So the top of the HTML body in all my documentation HTML files looks something like this:

<body> 
<table width='100%' border=0 bgcolor=#6699cc> 
  <tr> 
    <td width='100%'> 
    <h1>Help Topic Name Goes Here</h1> 
  </td> 
  </tr>
<!--insert php here-->
</table>

Note the “insert php here” tag in the HTML comments.

Search and Replace at Build Time

When I am ready to build a new version of the software (and compile a new CHM file and upload documentation in HTML form) I just need to search and replace the HTML using the free tool FART (Find And Replace Tool). Here’s some of the relevant lines out of my build script (which is just a DOS batch file).

@ECHO BUILDING HELP FILE
"d:\Program Files (x86)\HTML Help Workshop\hhc" "d:\Path\To\HTML\HelpProject\help.hhp"
ECHO Deleting old online help files
delete "d:\Path\To\Online\Help\Files\*.htm"
ECHO Copying help files to online help directory
copy "d:\Path\To\HTML\HelpProject\html" "d:\Path\To\Online\Help\Files\"
ECHO Replacing place holders with PHP
fart -q "d:\Path\To\Online\Help\Files\*.htm" "<!--insert php here-->" "<?php include('inc/header.php');?>"
fart -q "d:\Path\To\Online\Help\Files\*.htm" "</head>" "<?php include('inc/google-tracking.php');?>"
fart -q "d:\Path\To\Online\Help\Files\*.htm" "<script src='scripts/footer.js'></script>" "<?php include('inc/footer.php');?>"
@ECHO FTPing FILES TO WEB SERVER
"d:\Path\To\WinSCP\winscp.exe" /console /script=winscp-ftp-help-file.txt ftp_login:ftp_password@ftp.somesite.com

Line 1 compiles the CHM file. I use good old HTML Help Workshop from Microsoft to do this. It works well and but I maintain all of the project files in a text editor because the GUI is awful.
Line 4 deletes the old temporary copy of the online HTML files.
Line 6 makes a copy of the HTML files into the temporary online HTML location.
Lines 8-10 uses the FART tool to do the search and replaces. Note that I’ve replaced a custom tag with a php_include, replaced the </head> tag with a php include that generates Google Analytics code (and puts the </head> back), and finally replaced a js footer with a PHP equivalent.
Line 12 uses the very neat WINSCP command line SFTP tool to upload the files.

So, there you have it. One set of HTML files can be used to generate a CHM file using HTML Help Workshop and to generate online HTML files. It works very well and automating the process using tools like FART and WINSCP have made my build and release process a snap.

Checking and Setting an INI Entry in Innosetup

Here’s a handy bit of code I wrote today for checking and setting an INI entry using the free setup compiler, Innosetup.

procedure CurStepChanged(CurStep: TSetupStep);
  var 
    sFirstRun: string;
begin
    if CurStep = ssDone then
      begin
          sFirstRun:=GetIniString('FirstRun','FirstRun','0',ExpandConstant('{commonappdata}')+'\AppName\appname.ini');
          if sFirstRun<>'1' then //we are doing a clean install of version 5 set version 5 database updates to 1 to stop upgrade prompt.
            begin
              SetIniString('IniSection','KeyName','1',ExpandConstant('{commonappdata}')+'\AppName\appname.ini');
            end;
      end;
end;

A key thing to note here are that the code is living in the CurStepChanged event and I’m checking that CurStep=ssDone. ssDone represents the successful completion of the installation process. Another item of interest is the ExpandConstant function which is used to access the in-built constants that Innosetup offers.

The reason I’m using this code is to differentiate between a clean install of a program and an install over the top of an existing installation. When any of my programs runs for the first time I write a key (usually FirstRun into section FirstRun) into an ini file. If this key is present then the software has been run at least once. If it’s not present then the installation is a clean one. I can then write an ini entry if it’s a clean install.

C# MD5 File Hash and PHP Comparison

Further to my recent formless multi-threaded C# application blog post I’ve just implemented a simple MD5 hashing system to ensure that files are uploaded without the contents being changed. I’ve created a new method in my File Uploader class to calculate the MD5 hash of the files I’m uploading. You wouldn’t want to do this on the fly for larger files because of the time taken but the XML files I’m dealing with are less than 2kb in size so it’s not an issue. Here’s the MD5 method for my uploader class.

        private string md5Hash
        {
            get
            {
                using (var md5 = MD5.Create())
                {
                    using (var stream = File.OpenRead(WebExtensionsService.XMLFolder + "\\" + this.Filename))
                    {
                        byte[] md5_bytes=md5.ComputeHash(stream);
                        return BitConverter.ToString(md5_bytes).Replace("-","");
                    }
                }
            }
        }

Note that you need to convert the byte stream to a string and you’re going to have to strip out all the “-” characters to make the MD5 string look normal.

Once I had the MD5 hash I simply appended it to the URL I’m uploading the file to. Like this:

    byte[] byte_response = wClient.UploadFile(WebExtensionsService.UploadLocation+"?md5="+md5, "POST", WebExtensionsService.XMLFolder + "\\" + this.Filename);

The final step is to calculate the MD5 of the uploaded file in PHP and then compare this with the passed MD5 hash. I do this in the code below as well as a couple of other checks to make sure the file is of the correct type and isn’t too big.

	if (isset($_GET['md5']))
	{
		$md5=$_GET['md5'];
	}
	else
	{
		echo "Error : No md5 hash";
		die();		
	}

	if (substr($_FILES["file"]["name"],strlen($_FILES["file"]["name"])-4)=="xml")
	{
		echo "Error : Invalid file type";
		die();
	}
        if ($_FILES["file"]["size"]/1024>1000)
	{
		echo "Error : File too large";
		die();		
	}
	
	$tmp_name=$_FILES["file"]["tmp_name"];
	
	$calculated_md5=md5_file($tmp_name);
	
	if (strtoupper($md5)!=strtoupper($calculated_md5))
	{
		echo "Error : MD5 File Hash Mismatch";
		die();
	}

C# Formless Application with Multi Threading

I’ve been having a bit of fun in the last few weeks developing the next major release of Time Clock MTS. Part of this release includes a system that sends out emails based on certain events occurring within the software. To accomplish this I could have included some POP email fields and asked users to enter their mail account details. Or I could have used MAPI email. But both of these approaches are ugly as they require input from the user and don’t work for web mail.

So I decided on an approach that goes something like this:

1. The existing application generates an XML file when an event email is required and saves it into the appropriate application data folder.
2. A process monitors the data folder and uploads the files to a web server as it finds them. Each upload process is executed on its’ own thread.
3. The web server processes the XML file and sends emails as required.

Step 1 was easy enough even in Visual Basic 6 (which Time Clock MTS is developed in). However step 2 was always going to be tough so I decided to build a small application in c# to perform this role. The VB6 application would start the C# app on startup and the C# app would shut itself down when the VB6 application closed. Step 3 would be accomplished easily enough with PHP. The key advantage (as I see it) with this approach is that the only requirement for a client computer is an internet connection. It doesn’t require an email client to be installed (like MAPI does) and doesn’t require the user to know and enter some arcane email server settings when they first install the program.

I won’t bore you with Step 1 or 3 but Step 2 had some interesting code that I thought I might share. The C# app is a standard Windows Forms app but I hide the form (except when the debugger is running). I could have made this a windows service but that seemed to introduce a level of complexity (and difficulty in debugging) that was unwarranted. Here’s how I hide the form in the form constructor:

            InitializeComponent();
            if (!Debugger.IsAttached)
            {
                // Prevent the window from showing up in the task bar AND when Alt-tabbing
                ShowInTaskbar = false;
                FormBorderStyle = FormBorderStyle.FixedToolWindow;

                // Move it off-screen
                StartPosition = FormStartPosition.Manual;
                Location = new Point(SystemInformation.VirtualScreen.Right + 10, SystemInformation.VirtualScreen.Bottom + 10);
                Size = new System.Drawing.Size(1, 1);
            }

The work that the form does is handled by a WebExtensionsService class that includes a couple of timers. The class is initialized in the form constructor and the timers are started at the same time. The first timer checks for the existence the parent VB6 program process. I’m sure there’s better ways of doing this but the method I used below works fairly well with little or no CPU overhead and raises an event.

        private void timCheckForClose_Elapsed(object sender, ElapsedEventArgs e)
        {
            //writeLog("timCheckForClose update");
            Process[] adminProcesses = Process.GetProcessesByName("appname");

            if (adminProcesses.Count() == 0)
            {
                if (_bAppRunning == true)
                {
                    _bAppRunning = false;
                    OnAppNotRunning(EventArgs.Empty);
                }
            }
            else
            {
                if (!_bAppRunning )
                {
                    _bAppRunning = true;
                    OnAppNotRunning(EventArgs.Empty);

                }

            }
            

        }

Then I could consume this event in the C# form with this:


        private void WebExtensionsService_AppStopped(object sender, EventArgs e)
        {
            Application.Exit();
        }

I used the Command Line Parser Library to read in a range of command line options that were passed to the C# application when it was started by the parent VB6 application. These settings were used by the second timer to do the real work of this C# forms app. Namely scanning a folder looking for XML files and then uploading them to a server. The second timer in the WebExtensionsService class does this:


        private void timCheckFiles_Elapsed(object sender, ElapsedEventArgs e)
        {
            this.checkForXMLFiles();
        }

        public void checkForXMLFiles()
        {
            Classes.Uploader uploader;

            if (uploaderThreads.Count < this.MaxThreads)
            {
                if (bDirectoryExists(this.XMLFolder))
                {
                    DirectoryInfo info = new DirectoryInfo(this.XMLFolder);
                    FileInfo[] files = info.GetFiles().OrderBy(p => p.CreationTime).ToArray();
                    writeLog("checkForXMLFile:: " + files.Count().ToString() + " files found");
                    foreach (FileInfo file in files)
                    {
                        if (!uploaderThreads.ContainsKey(file.Name))
                        {
                            uploader = new Classes.Uploader();
                            uploader.Filename = file.Name;
                            Thread workerThread = new Thread(uploader.DoWork);
                            uploaderThreads.Add(file.Name, workerThread);
                            workerThread.Start();
                            writeLog("Starting uploader thread " + uploaderThreads.Count + " of " + this.MaxThreads);
                        }
                        if (uploaderThreads.Count >= this.MaxThreads)
                        {
                            writeLog("checkForXMLFile:: MaxThreads " + this.MaxThreads.ToString() + " are busy");
                            break;
                        }
                    }

                }
                else
                {
                    writeLog("checkForXMLFile::"+this.XMLFolder+" doesn't exist");
                }
            }
            else
            {
                writeLog("checkForXMLFile:: MaxThreads " + this.MaxThreads.ToString() + " are busy");
            }
        }

The Uploader class is my worker class that is used to upload a file in it’s own thread. Note that I have a MaxThreads setting and maintain a collection of UploadedThreads to make sure I don’t try to upload the same file twice.

And for interests sake here’s the method from the Uploader class that does the actual work. It’s worth noting that the WebExtensionsService class is a singleton and contains all of the global settings I need. I’m sure this isn’t the most elegant way of doing things but it’s always worked extremely well for me in the past.

        private bool uploadFile()
        {
            bool bReturn = false;
            string sResponse = "No Response";
            WebClient wClient = new WebClient();


            try
            {
                byte[] byte_response = wClient.UploadFile(WebExtensionsService.UploadLocation, "POST", WebExtensionsService.XMLFolder + "\\" + this.Filename);
                if (byte_response != null)
                {
                    sResponse = System.Text.ASCIIEncoding.ASCII.GetString(byte_response);
                    WebExtensionsService.writeLog("Upload " + this.Filename + " Reponse :: " + sResponse);
                    if (sResponse == "1")
                    {
                        bReturn = true;
                    }
                }

            }
            catch (Exception e)
            {
                WebExtensionsService.writeError(e);
            }
            if (bReturn)
            {
                sResult += " UPLOAD SUCCESSFUL";
            }
            else
            {
                sResult += " UPLOAD FAILED RESPONSE " + sResponse;
            }
            

            return bReturn;

        }

Right now the uploadFile method waits for the correct response from the web server. I am thinking about not just uploading the file but also uploading a checksum of the file contents so that the web server can check that the file has not been corrupted in the upload process. But that’s something for another day.

The final step in the application is how to close it out cleanly. I showed earlier how the Application.exit() method was called when the parent VB6 program process was no longer present. Here’s the code that makes sure that all the uploader threads are closed out before the application exits.

        private static void OnApplicationExit(object sender, EventArgs e)
        {
            Classes.WebExtensionsService WebExtensionsService;
            WebExtensionsService = Classes.WebExtensionsService.Instance;
            WebExtensionsService.writeLog("Closing TimeClockMTSWebExtensions");

            foreach (KeyValuePair<string, System.Threading.Thread> entry in WebExtensionsService.UploaderThreads) //wait for uploaded threads to finish
            {
                System.Threading.Thread thread = entry.Value;
                thread.Join();
                WebExtensionsService.writeLog("Waiting for " + entry.Key + " uploader thread to finish");
            }
            WebExtensionsService.writeLog("Closed TimeClockMTSWebExtensions");
        }

The key here is the thread.Join() call. This blocks the main C# program thread until the child threads (stored in my UploaderThreads collection) have completed their work.

Doing this work in C# is far easier than trying to do the same thing in VB6. The C# network code is about a million times easier and more robust. Part of me would LOVE to port the entire VB6 application to .NET but there’s three things stopping me. Firstly, the sheer amount of work. We’re talking about 80,000 lines of code that need porting. Not a trivial task. Second, ADO code in .NET simply isn’t as good as it is in VB6. It’s slower, handles connection pooling very poorly in comparison with VB6, and file sharing of a simple database like MS Access just doesn’t work as well. In the past I’ve had to perform tricky pre-caching of ADO data in .NET to get it performing even remotely as quickly as VB6 code. And finally, it scares me witless mainly because of all the reasons discussed in this great article by Joel Spolsky.

That being said stepping back to VB6 to do development work instead of using C# is like owning a 2013 model car and being forced to drive a leaky 1969 Volkswagen Beetle every second day. It works but it’s not fun. As a result I’m trying to build new features and move older non database reliant features (such as web camera image capture and network time checking code) into COM visible .NET code. However, because of the problems with database handling in .NET I don’t think I’ll ever get rid of VB6 altogether unless Windows drops compatibility for it.

Building a Garage Door Sensor with an Arduino Nano

The Problem

Our two car garage has a roller door on the front and back. The one on the front of the house is motorised and activated with a remote control. You cannot see if the front roller door is open from anywhere within our house so the only way to check if it is open is to walk outside and look. If you remember that is. The problem is that we do not want to go to bed and leave the front roller door on the garage open and we have done so a few times.

The Solution

Create some sort of sensor and indicator letting us know that the front roller door is open. The sensor should be reliable and the indicator should be obvious (especially when night has fallen) and not require us to walk outside to check on the status of the door. I’ve had an Arduino starter kit sitting on my desk for a while so (of course) I thought that the solution had to include an Arduino.

The Sensors

I wanted to detect if the door was up or down so this would require two sensors. Initially I was thinking along the lines of an ultrasonic detector but the cost of this was prohibitive as I needed two of them. In the end I settled on simple magnetic reed switches of the type you see in home security systems. One would be mounted to the door frame at the bottom and one at the top. A magnet would be fixed to the door to trigger the switches as the door moved up and down. The two door sensors with paired magnets were $5.

The Indicator

Initially I had thoughts of a two unit system. One sender unit mounted on the garage door and a receiver unit that sat inside with an indicator light with RF comms using one of the many different types of Arduino RF shields. But this was complete overkil so in the end I settled on 2 colour high intensity 3 watt LED that could be mounted outside our kitchen window and be driven by a cable. The LED module would need to be driven by a decent constant current power supply so I bought a couple of 330mA units at the same time. These PSU’s could be driven by a 0-5V PWM (pulse width modulated) signal to adjust the intensity of the driven LED. The LED module was $3, a heatsink to mount the LED on was $3, and the PSU’s were $9 each. A transparent poly-carbonate box to install the LED in was $9. The cable ended up being some 8 core alarm cable that cost about a dollar a meter and I used some 6 pin audio plugs for each end. Total cost for the cable was around $20 or so.

The Arduino

My Arduino kit contains a Arduino UNO clone. This was bigger than I wanted so I settled on a cloned Arduino Nano from eBay which was about $10. This had the digital inputs I wanted, more than enough memory to hold the simple sketch I’d write, could be run from a 12V DC plug pack, and the PWM outputs I’d need.

Enclosure and Breadboard

The enclosure would need to hold the Arduino Nano, the two LED PSU’s, and a small breadboard. It would also need to take the wires from the door sensors, have a female socket to take 12V and a female connector to plug our LED cable into. The breadboard was used to make a circuit that would ground out the sensor signals and route 3.3V to the sensors and 12V to the LED power supplies. All connections from the circuit to the Arduino and the Arduino to the power supply were done via connectors and cables I had laying around from old PC builds. Total cost of the enclosure and assorted components (and a 2A 12V DC plug pack) ran out to about $40.

Build Problems

One of the LED PSU’s was DOA so I settled on running just one of the LED colours. I chose to indicate different door states by flashing the LED at different rates. A second problem was that the roller door frame was significantly out of square and the magnets supplied with the reed switches were not strong enough to trigger the switches. I solved this by purchasing a rare earth magnet and gluing it to the roller door (cost was $12).

Arduino Code

I decided on a simple state engine for the code to run my indicator light. The first state was door down. In this state the Arduino was in a “door closed sleep” state waiting for an interrupt from the bottom door sensor. When the state of this sensor changed the Arduino would wake and enter a “door in transition” state and flash the LED rapidly. When the top sensor triggered the door would enter a third “door up” state and pulse the light slowly. When the roller door was lowered the Arduino would enter the “door in transition” state again and stay that way until the door closed and the bottom sensor was triggered. The Arduino would now enter a “door closed indicator” state and leave the LED on for 10 seconds before entering the “door closed sleep” state. Here’s the Arduino sketch I came up with to accomplish this:

#include <avr/interrupt.h>
#include <avr/power.h>
#include <avr/sleep.h>


const int blueLED = 3;
const int ledBrightness=50;
const int doorDownSensor=2;
const int doorUpSensor=4;
int doorDownSensorState=0;
int doorUpSensorState=0;
int oldDoorUpSensorState=0;
int oldDoorDownSensorState=0;
int tmpState=0;
int i=0;
int pulseStep=1;
int pulseBrightness=0;
unsigned long blueLEDStartTime;
String tmpString;

unsigned long endLastPulse;
unsigned long pulseDelay=3000;

void setup() {
  // put your setup code here, to run once:
  pinMode(blueLED,OUTPUT);
  pinMode(doorDownSensor,INPUT);
  pinMode(doorUpSensor,INPUT);
  
  Serial.begin(9600);
}

void loop() {
  tmpState=digitalRead(doorDownSensor);
  
  
  if (tmpState==HIGH)
    tmpString="HIGH ";
  else
    tmpString="LOW ";  

  if (tmpState != oldDoorDownSensorState)
  {
    doorDownSensorState=1-doorDownSensorState;
    delay(50);
    if (doorDownSensorState==1)
    {
      blueLEDStartTime=millis();  
    }
  }
  oldDoorDownSensorState=doorDownSensorState;
  
  tmpState=digitalRead(doorUpSensor);

  if (tmpState==HIGH)
    tmpString+="HIGH ";
  else
    tmpString+="LOW "; 
    
  if (tmpState != oldDoorUpSensorState)
  {
    doorUpSensorState=1-doorUpSensorState;
    delay(50);
  }
  oldDoorUpSensorState=doorUpSensorState;  
  
  tmpString+="DOWN_STATE::";
  tmpString+=doorDownSensorState;
  tmpString+=" UP_STATE::";
  tmpString+=doorUpSensorState; 
  Serial.println(tmpString); 
    
  if (doorDownSensorState==1)
  {
    if ((millis()-blueLEDStartTime)<=10000)
      analogWrite(blueLED,ledBrightness); 
    else
    {
      analogWrite(blueLED,0);
      sleepNow();
    }
  }

  
  if (doorUpSensorState==1)
  {
    if (endLastPulse==0 || (millis()-endLastPulse)>pulseDelay)
    {
      pulseBrightness+=pulseStep;
      if (pulseBrightness<0)
      {
        pulseBrightness=0;
        pulseStep=-1*pulseStep; 
        endLastPulse=millis();
      }
      if (pulseBrightness>ledBrightness)
      {
        pulseBrightness=ledBrightness;
        pulseStep=-1*pulseStep; 
      }      
      analogWrite(blueLED,pulseBrightness);
      delay(25);
    }

  }
  else
  {
    endLastPulse=0; 
  }

  
  if (doorDownSensorState!=1 && doorUpSensorState!=1)
  {
    if ((millis() % 1000)<500)
      analogWrite(blueLED,ledBrightness);    
    else
      analogWrite(blueLED,0);        
  }

  
}

void sleepNow()
{
    // Set pin 2 as interrupt and attach handler:
    attachInterrupt(0, pinInterrupt, LOW);
    delay(100);
    //
    // Choose our preferred sleep mode:
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    //
    // Set sleep enable (SE) bit:
    sleep_enable();
    //
    // Put the device to sleep:
    sleep_mode();
    //
    // Upon waking up, sketch continues from this point.
    sleep_disable();
}

void pinInterrupt(void)
{
  detachInterrupt(0);
}

There’s a couple of things to note here. First, the Nano only has interrupts on IO pins 2 and 3 so the bottom door sensor had to be on one of these pins. I used pin 2 which is interrupt 0. Also, I wanted to drive the LED power supply with a PWM signal so I had to use one of the PWM capable outputs, in my case I used pin 3.

I developed this code on my Arduino UNO with the circuit mocked up on a spring breadboard that came with my starters kit. Flashing the code to the Nano was troublesome because it turns out that the Nano I bought had a problem with the serial chip (UART) and just wouldn’t talk to my computer. After much googling I just needed to download and install an older driver for the USB/Serial driver on my PC and suddenly I could talk to the Nano.

Installation

The hardware mounted up easily enough. The reed switches included adhesive and stuck well enough to the door frame once I had cleaned the metal with some acetone. The door magnet was put in place with some cyano acrylate glue. Cabling from the sensors to the control box was cheap two core cable and the control box was mounted to the wall with some wall plugs I had lying around. A friend of mine helped me route the LED cable through my roof cavity and the LED box was stuck to one of the beams of the verandah outside our kitchen window.

Here’s one of the reed switches mounted to the top of the door frame. You can see the rare earth magnet (the silver disk) on the door itself.

Reed Sensor and Magnet

Reed Sensor and Magnet

And here’s the control box containing the Arduino Nano, home made circuit, and one of the constant current power supplies that drive the LED. The 12V power goes in via the plug at the bottom left while the cable coming out the top right goes into the roof cavity and drives the LED.

Arduino Enclosure

Arduino Enclosure

Finally, here’s the LED box mounted to a beam on our verandah. It’s the blue thing in the middle of the picture. You can see the cable running across to the top of the beam it’s mounted on.

LED Enclosure

LED Enclosure

Here’s what it looks like in operation:

innosetup and .NET 4.0

My simple timesheet software, Timesheets Lite is a a C# program based on Winforms and the DXperience library for WinForms. It is installed with an innosetup script. Up until yesterday the software required the .NET 2.0 library and the installer could detect if .NET 2.0 was installed and download and install it if it wasn’t. Windows 8 was an exception to this rule as .NET 2.0 (actually .NET 3.5) is a Windows feature that needs to be enabled rather than something that needed to be installed. This wasn’t too difficult to get around because you (used) to be able to use DISM to enable Windows features.

Previously my innosetup script detected if Windows 8 was the target OS and then could simply enable the .NET 3.5 feature using this:

Exec('Dism', ' /online /enable-feature /featurename:NetFx3 /All /NoRestart', '', SW_SHOW, ewWaitUntilTerminated, ResultCode);

This had worked fine previously because Windows went away (presumably to the Windows Update site) and downloaded what it needed from there. But it doesn’t work any longer and to get DISM to enable .NET 3.5 the /source parameter must be specified pointing to a local copy of the Windows 8 installation media or an ISO. Clearly this isn’t acceptable for my purposes. Hence I decided to update Timesheets Lite to require the .NET 4.0 library (which is installed on W8 by default). This threw up some other problems though because now I needed to detect .NET 4.0 on earlier versions of Windows, and download and install it during the Timesheets Lite installation process.

This was (surprisingly) easy. I made use of the innosetup .NET detection function from this page and modified the inno script I’d written years ago to download and install .NET 2.0. Here’s some code from my innosetup script for giggles. Firstly, the InitializeSetup function which determines what version of Windows is the target and uses the IsDotNetDetected function to check for the .NET 4.0 client or full installation.

function InitializeSetup(): Boolean;
begin
    dotNetNeeded := false;
    Windows8 := false;
    Result := true;

    if (Version.Major=6) and (Version.Minor=2) then
      begin
        Windows8:=true;

      end;


    if (not IsDotNetDetected('v4\Client', 0)) and (not Windows8) then 
      begin
        if not IsDotNetDetected('v4\Full', 0) then
          begin
              dotNetNeeded := true;
          end
      end 

     if dotNetNeeded then
      begin
            if (not IsAdminLoggedOn()) then
                begin
                    MsgBox('This program needs the Microsoft .NET 4.0 Framework to be installed by an Administrator', mbInformation, MB_OK);
                    Result := false;
                end
            else
                begin

                    
                    dotnetRedistPath := ExpandConstant('{src}\dotnetfx.exe');
                    if not FileExists(dotnetRedistPath) then
                        begin
                            dotnetRedistPath := ExpandConstant('{tmp}\dotnetfx.exe');
                            if not FileExists(dotnetRedistPath) then
                                begin
                                    isxdl_AddFile(dotnetRedistURL, dotnetRedistPath);
                                    downloadNeeded := true;
                                end
                        end

                    SetIniString('install', 'dotnetRedist', dotnetRedistPath, ExpandConstant('{tmp}\dep.ini'));
                end
      end
end;

Next up I’ve added some code to the NextButtonClick function that runs when the current page is wpReady (read to install).


  dotnetRedistURL = 'http://download.microsoft.com/download/9/5/A/95A9616B-7A37-4AF6-BC36-D6EA96C8DAAE/dotNetFx40_Full_x86_x64.exe';

function NextButtonClick(CurPage: Integer): Boolean;

var
  hWnd: Integer;


begin

  Result := true;

  //*********************************************************************************            
  // Only run this at the "Ready To Install" wizard page.
  //*********************************************************************************
  if CurPage = wpReady then
    begin

        hWnd := StrToInt(ExpandConstant('{wizardhwnd}'));


        // don't try to init isxdl if it's not needed because it will error on < ie 3

        //*********************************************************************************
        // Download the .NET 4.0 redistribution file.
        //*********************************************************************************
        if downloadNeeded and (dotNetNeeded = true) and Windows8 = false then
            begin
                isxdl_SetOption('label', 'Downloading Microsoft .NET Framework 4.0');
                isxdl_SetOption('description', 'This program needs to install the Microsoft .NET Framework 4.0. Please wait while Setup is downloading extra files to your computer.');
                if isxdl_DownloadFiles(hWnd) = 0 then Result := false;
            end;

        //*********************************************************************************
        // Run the install file for .NET Framework 4.0. This is usually dotnetfx.exe
        //*********************************************************************************
            if ((dotNetNeeded = true)) then
            begin

                if Exec(ExpandConstant(dotnetRedistPath), '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
                    begin

                        // handle success if necessary; ResultCode contains the exit code
                        if not (ResultCode = 0) then
                            begin

                                Result := false;

                            end
                    end
                    else
                        begin

                            // handle failure if necessary; ResultCode contains the error code
                            Result := false;

                        end;
            end;


    end;

end;

I tested this script on XP, Vista, Windows 7 and Windows 8 and it works very well. The .NET 4.0 download is about 50MB so it’s not too big an impost for users. And I suspect most people will have .NET 4.0 installed anyway. Note that you’ll have to to be using the isxdl innosetup plugin for this installation procedure to work.

Having Trouble Viewing Media on Your Sony Bravia TV?

If you’ve got a latish model internet-enabled Sony TV (we have a Sony Bravia KDL40HX750 TV) then you may know it can display media streamed from a compliant DLNA server. If you know this you probably also know that the Sony TV’s can be very picky about what media formats (specifically movies) they will and wont play. I’ve had some luck converting movies to different file formats but even with this solution I’d pretty much given up on watching streamed movies on the TV because it was just all too hard. So I’d been resorting to using my five year old WD Live Media Player with an external HDD plugged into it.

However, I’ve hit on a solution that has allowed me to watch almost any movie in any format on our Sony TV. I’ve setup a DLNA media server and downloaded the great app Bubble UPNP to our Nexus 7 tablet. Once the app is installed it’s just a matter of connecting it to our media server, choosing a movie to play and selecting our Sony TV as a rendering device. Once that is done and I press PLAY in the app by the magic of smoke and mirrors the movie starts playing on the TV. Fabulous.

DatePickers on Excel MultiPage Controls

I’ve known this for a little while but I thought it worth posting here. You cannot get or assign the value of a DatePicker control on a MultiPage control if you’re on a different page of the MultiPage control. So if you’ve got a 5 page MultiPage control and the DatePicker Control is on page 1 of the MultiPage then this won’t work (and will indeed give an error):

  Me.MultiPage1.Value=4
'dtPicker is on MultiPage1 page 1, 
  Me.dtPicker.value=Now

And this wont work either:

  Dim datTmp as Date
  Me.MultiPage1.Value=4
'dtPicker is on MultiPage1 page 1, 
  datTmp=Me.dtPicker.value
 'this just sets datTmp to todays date and ignores the actual dtPicker value

So if you want to set or get the value of a DatePicker on a MultiPage control you need to be careful which page of the MultiPage is selected. You need to do something like this.

 'save the page we are on now
  iCurrentPage = Me.MultiPage1.Value
  
  'change to the page the DatePicker is on and set the value
  Me.MultiPage1.Value = 4
  Me.dtPicker.Value = Now
  'go back to the original page
  Me.MultiPage1.Value = iCurrentPage

IE9, radio buttons and DIVs

I’m just getting back into some development of Online Time Clock MTS and had the pleasure of squashing an annoying bug today that was only appearing on IE9. I used the prototype javascript library pretty heavily in the development of this online system and getting the value of a group of radio buttons is something of a pain but can be done like this:

var selected_value = Form.getInputs('form_name','radio','radio_group_name').find(function(radio) { return radio.checked; }).value;

This returns the value of the selected radio button of the group you’re interested in. Works perfectly until you go and put a <DIV> </DIV> in the middle of your HTML radio buttons. Then IE9 decides that the radio buttons AFTER the div are no longer part of the radio group. The above javascript will then throw an exception if one of the radio buttons after the offending DIV is selected. The simple fix (for me at least) was to change the <DIV> to a <SPAN>