IISAdmin – multiple sites on Windows XP

The inability to run multiple concurrent websites from IIS under Windows XP is a pain. I need to run Server 2003 and IIS 6 to do that, and live with the resulting slowdown

IISAdmin Screenshot

There is a handy free utility, IISAdmin, which mitigates the worst aspect of the IIS 5 limitation: the need to reconfigure the Default Web Site each time I want to work with a different site. IISAdmin allows you to create new websites, each permanently pointing to a different set of files on disk. The limitation (probably in IIS 5 on XP) is that only a single site can be started at a time.

Work around limitations of VS 2005 Deployment Projects with Windows Services

I needed to deploy a Windows Service using an MSI. The project was built in VS 2005 using .Net 2.0; so far, so good.

The problem arose when I wanted to have the Service write to its own Event Log, rather than the default Application log. The standard Installer class from System.Configuration.Install, which otherwise does a fine job of installing the Windows Service, proved less than ideal because it automatically creates an EventLogSource with the same name as the Service executable, and sets its event log to be Application.

The solution lies in the way in which the Installer class contains a series of other installers in the Installer.Installers collection, which in turn contain other installer objects.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Diagnostics;

namespace MyService
{
  [RunInstaller(true)]
  public partial class ProjectInstaller : Installer
  {
    public ProjectInstaller()
    {
      InitializeComponent();

      //
      // ProjectInstaller
      //
      this.Installers.AddRange(new System.Configuration.Install.Installer[] {
            this.serviceProcessInstaller1,
            this.serviceInstaller1});
    }

    private void serviceInstaller1_BeforeInstall(object sender, InstallEventArgs e)
    {
      RemoveEventLogInstallers(this, 0);
    }

    ///
    /// Recursive method to remove EventLogInstaller Installers from the Installers collection.
    /// This is needed to avoid automatic setting up of the event logs
    private static void RemoveEventLogInstallers(Installer installer, int depth)
    {
      Console.Out.WriteLine(String.Format("Number of installers at depth {0}: {1}", installer.Installers.Count, depth));
      for (int i = installer.Installers.Count - 1; i >= 0; --i)
      {
        Installer childInstaller = installer.Installers[i];
        Console.Out.WriteLine(String.Format("Installer {0} at depth {1} is of type: {2}", i, depth, installer.GetType().Name));

        RemoveEventLogInstallers(childInstaller, depth + 1); //recurse

        if (childInstaller is EventLogInstaller)
        {
          Console.Out.WriteLine(String.Format("Removing Installer {0} at depth {1} because it is of type: {2}", i, depth, childInstaller.GetType().Name));
          installer.Installers.Remove(childInstaller);
        }

      }
    }

    private void serviceInstaller1_BeforeUninstall(object sender, InstallEventArgs e)
    {
      RemoveEventLogInstallers(this, 0);
    }
  }
}

Search recursively through the entire tree of Installer objects and remove any installer whose type is EventLogInstaller, and the problem is solved! Make sure to do this before Install and before Uninstall, otherwise the (un)installation does not complete successfully.

Calling Javascript from C#

Call JavaScript from C# code, passing parameters and returning results.

I came across a need to call JavaScript methods on HTML code inside a web page from a C# WinForms application. How could that language gap be bridged?

It turns out that Type.InvokeMember() does the trick when using a [Internet Explorer] WebBrowser control to load a web page.

using mshtml;
...
private AxSHDocVw.AxWebBrowser axWebBrowser1;
...
///
 /// Retrieves a reference to the HTML element containing a DIV. /// JavaScript methods are implemented on this element itself. /// 

/// A reference to the HTML element holding the JavaScript methods
private HTMLDivElementClass GetContainer()
{
 HTMLDivElementClass container = null;
 IHTMLDocument2 doc = axWebBrowser1.Document as IHTMLDocument2;

 if (null != doc)
 {
  foreach (IHTMLElement element in doc.all)
  {
   if (element.id == "My_Container")
   {
    container = element as HTMLDivElementClass;
    break;
   }
  }
 }

 return container;
}

///
 /// Gets the text from the container /// 

/// A string containing the text of the container
private string GetText()
{
 string result = null;
 HTMLDivElementClass div = GetContainer();
 if (null != div)
 {
  Type type = div.GetType();
  result = (string) type.InvokeMember(
    "GetText",
    BindingFlags.InvokeMethod,
    null,
    div,
    null);
 }   

 return result;
}

The HTML page loaded in the WebBrowser control has a DIV element with an id of “My_Container”, attached to which is a method called GetText(), which returns some arbitrary text.

Having acquired a reference to the DIV on which the JavaScript method is declared (using GetContainer()), the JavaScript method is called using the InvokeMember() method of the Type class instance; the return value is cast to a string.

Discussion

There is every reason why this should NOT work, but the implementers of the WebBrowser control decided that JavaScript methods living within the DOM should be accessible as first class object members at runtime (in this case, via IDispatch). Nice!

Result

C# code can call arbitrary JavaScript within an HTML page! The only limitation is that the return types of the JavaScript methods can be only simple types (even DateTime is too complex).

Integrating Blogger and PHP

As part of my ’10 pages or less’ website framework, I needed to integrate Blogger with PHP. Blogger can publish to an FTP server (instead of BlogSpot, and so news and blog content can be included within a ‘real’ site, but the management overhead solved by Blogger.

Here is how to get Blogger working with PHP:

  1. Set up your blog to publish via FTP (on Publishing tab)
  2. Change the ‘Blog Filename’ to index.php
  3. Change ‘Archive Filename’ to archive.php (on Archiving tab)
  4. Finally, delete the old index.html file from the blog directory (otherwise it will probably take precedence over the new index.php)

You can then edit the blog Template to include all the standard PHP includes to match the rest of the site.

Asymmetry in PHP’s array_diff()

I have been working on my ueber-basic PHP-driven website engine, and ran into a really odd ‘feature’ of the array_diff() function in PHP 5.1.2: its results seem inconsistent.

Take two arrays, each with the same number of elements (say n). One of the arrays contains some string values, but the other contains all null/empty strings. array_diff($array1, $array2) returns all the elements in $array1, as expected; however, array_diff($array2, $array1) returns an array containing n empty elements. It should return just a single (empty) element.

This code demonstrates the behaviour:

// array_diff() weirdness
echo 'DEBUG - testing array_diff()';
$array1 = array('a', 'b', 'c'); // 3 entries, non-null
$array2 = array('', 'b', '');   // 3 entries, 1 non-null
$array3 = array('', '', '');    // 3 entries, all null
echo '$array1: ' . implode(',', $array1) . '.';
echo '$array2: ' . implode(',', $array2) . '.';
echo '$array3: ' . implode(',', $array3) . '.';
$diff12 = array_diff($array1, $array2); // diff array1 against array2
$diff21 = array_diff($array2, $array1); // diff array2 against array1
$diff13 = array_diff($array1, $array3); // etc.
$diff31 = array_diff($array3, $array1);
$diff23 = array_diff($array2, $array3);
$diff32 = array_diff($array3, $array2);
echo '$diff12: ' . implode(',', $diff12) . '.';
echo '$diff21: ' . implode(',', $diff21) . '.';
echo '$diff13: ' . implode(',', $diff13) . '.';
echo '$diff31: ' . implode(',', $diff31) . '.';
echo '$diff23: ' . implode(',', $diff23) . '.';
echo '$diff32: ' . implode(',', $diff32) . '.';

This returns the following:

DEBUG - testing array_diff()
$array1: a,b,c.
$array2: ,b,.
$array3: ,,.
$diff12: a,c.
$diff21: ,.
$diff13: a,b,c.
$diff31: ,,.
$diff23: b.
$diff32: .

Notice the result for $diff31, compared to that for $diff21. Why are there three elements in the result for $diff31? array_diff() should return an array of unique elements which exist in one array and not another. It seems that there are ‘special cases’ which depend on (what?) array size? nullness? element ordering? The documentation for array_diff() states:

Multiple occurrences in $array1 are all treated the same way.

The crucial question: Why are multiple occurances in $array2 not treated in the same way?

The context for this is here: html_simple_tidy()

What a shame there is no decent interactive PHP shell, like those for Python and Ruby.