While fooling this afternoon at work with IProcessInitializer, I found an interesting problem with the registration code in the .NET Framework v1.0. Consider the following snippet:

using System;
using System.Diagnostics;
using System.EnterpriseServices;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
[
assembly:
AssemblyVersion("1.0.0.0"),
AssemblyKeyFile("procint.snk"),
ApplicationActivation(ActivationOption.Server),
ApplicationID("797fb7f8-d223-4d33-8f6c-be6fa27d42a4"),
ApplicationName("ProcInitializerTest")
]
namespace Winterdom.Samples.ComPlus
{
[
ComImport(),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("1113f52d-dc7f-4943-aed6-88d04027e32a")
]
public interface IProcessInitializer
{
void Startup([MarshalAs(UnmanagedType.IUnknown)] object processControl);
void Shutdown();
}
[
ClassInterface(ClassInterfaceType.None),
Guid("9c9d323e-85fc-4122-a507-b0a74f2e7583")
]
public class ProcessInitializer
: ServicedComponent, IProcessInitializer
{
public void Startup(object processControl)
{
Debug.WriteLine("DLLHost is starting...");
}
public void Shutdown()
{
Debug.WriteLine("DLLHost is shutting down...");
}
} // class ProcessInitializer
public class SomeOtherSC : ServicedComponent
{
public void DoSomething()
{
}
};
} // namespace Winterdom.Samples.ComPlus

Nothing really weird about this, huh? Well, it turns out that the registration code is aware of IProcessInitializer, and will try to set the InitializesServerApplication value in the catalog for the component. Unfortunately, if you compile the code above and use regsvcs.exe to register it, you'll notice the application is no longer able to startup.

The cause? A bad registration. Instead of setting InitializesServerApplication to true for the ProcessInitializer class, as should be, it is set for the SomeOtherSC class. Huh? Now try this: Invert the order those two classes are defined in the source code and try again. Now it works as it should be.

It's easy to work around this by creating a script that uses the catalog to fix the registration, but annoying. Fortunately, it seems to be corrected for v1.1 (although I didn't try to hard...)

P.S. In case you're wondering how to easily check what I'm saying, here's a simple VBScript that given an Application ID, will print the value of the InitializesServerApplication property for each component of the application:


if WScript.Arguments.Count <> 1 Then
WScript.Echo "usage: CheckSCISA "
WScript.End
end if
Dim appID
appID = WScript.Arguments(0)
Dim catalog, root
set catalog = CreateObject("COMAdmin.COMAdminCatalog")
set root = catalog.Connect("localhost")
Dim appsCol
set appsCol = catalog.GetCollection("Applications")
appsCol.PopulateByKey Array(appID)
Dim components
set components = appsCol.GetCollection("Components", appID)
components.Populate
Dim obj
for each obj in components
WScript.Echo "Component: " & obj.Name
WScript.Echo " " & obj.Value("InitializesServerApplication")
next


Tomas Restrepo

Software developer located in Colombia. Sr. PFE at Microsoft.