Saturday, July 9, 2011

The longest class name in Java

The first thing, that I noticed while working with Spring framework (right after its simplicity, purity, good performance, etc.) is that the designers of the framework didn't bother of creating short and simple names which resulted in a set of VeryLongSelfDescriptiveClassNames.

Curious enough, went throught the core Spring API and found two candidates for the title of "the longest class name in Java", and by the longes class name I mean a class name with no package prefix.

Those two candidates are:

AbstractInterruptibleBatchPreparedStatementSetter
AbstractTransactionalDataSourceSpringContextTests
both containing impressing 50 characters.

However, with Google's help found they're not the winners. The longes class name tends to be:
PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails
from Spring Security package, which is amazing 59 characters long.

Well self-described code or just a good sense of humor? Both, I guess.

Uninstalling devices and hardware reenumeration in Windows - C# in action

Recently I came across the following problem: how to re-install some device in MS Windows in the easiest possible way (assuming a target user has no knowledge of the system, whatsoever, maybe with exception of an Internet browser). The solution is to write a simple app, which does everything automatically. The idea was quite simple: uninstall the device and then rescan all hardware for changes, letting the PnP mechanism do the rest. Language: C# and SetupAPI (Windows Driver Kit) hidden behind fancy Windows Forms GUI. Here's the code.

Declarations:
using System.Runtime.InteropServices;
// ...
public const int CR_SUCCESS = 0x00000000;
public const int CM_LOCATE_DEVNODE_NORMAL = 0x00000000;
public const int DIGCF_PRESENT = 0x00000002;
public const int DIF_REMOVE = 0x00000005;

// devnode info struct
[StructLayout(LayoutKind.Sequential)]
public class SP_DEVINFO_DATA
{
    public int cbSize;
    public Guid ClassGuid;
    public int DevInst;

    public ulong Reserved;
}

// importing external SetupAPI methods
[DllImport("cfgmgr32.dll")]
public static extern UInt32 CM_Locate_DevNode(ref UInt32 DevInst, string pDeviceID, UInt32 Flags);

[DllImport("cfgmgr32.dll", SetLastError = true)]
public static extern UInt32 CM_Reenumerate_DevNode(UInt32 DevInst, UInt32 Flags);

[DllImport("setupapi.dll")]
public static extern Boolean SetupDiClassGuidsFromNameA(string ClassName, ref Guid Guids, UInt32 ClassNameSize, ref UInt32 RequiredSize);

[DllImport("setupapi.dll")]
public static extern IntPtr SetupDiGetClassDevsA(ref Guid ClassGuid, UInt32 Enumerator, IntPtr hwndPtr, UInt32 Flags);

[DllImport("setupapi.dll")]
public static extern Boolean SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet, UInt32 DeviceIndex, SP_DEVINFO_DATA DeviceInfoData);

[DllImport("setupapi.dll", SetLastError = true)]
public static extern Boolean SetupDiCallClassInstaller(UInt32 InstallFunction, IntPtr DeviceInfoSet, SP_DEVINFO_DATA DeviceInfoData);

[DllImport("setupapi.dll")]
public static extern Boolean SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);
Uninstalling all devices in class:
private Int32 RemoveAllDevicesInClassName(string ClassName)
    {
        IntPtr NewDeviceInfoSet;
        UInt32 RequiredSize = 0;
        SP_DEVINFO_DATA DeviceInfoData = new SP_DEVINFO_DATA();
        Guid[] Guids = new Guid[1];

  // getting required size to store Guids for given class name
        Boolean result = SetupDiClassGuidsFromNameA(
                                ClassName, ref Guids[0], RequiredSize, ref RequiredSize);
        if (RequiredSize == 0)
        {
            // incorrect class name
            return -4;
        }
        if (!result)
        {
            Guids = new Guid[RequiredSize];
   // getting the actual Guids
            result = SetupDiClassGuidsFromNameA(
                                ClassName, ref Guids[0], RequiredSize, ref RequiredSize);
        }
        if (!result)
        {
            // incorrect class name
            return -4;
        }
  // getting all present devnodes for given Guid
        NewDeviceInfoSet = SetupDiGetClassDevsA(ref Guids[0], 0, IntPtr.Zero, DIGCF_PRESENT);

        if (NewDeviceInfoSet.ToInt32() == -1)
        {
            // unavailable
            return -8;
        }

  // preparing device info struct
        DeviceInfoData.cbSize = 28;
        DeviceInfoData.ClassGuid = Guid.Empty;
        DeviceInfoData.DevInst = 0;
        DeviceInfoData.Reserved = 0;

        UInt32 i;
  // for each device in class (set of devnodes pointed by NewDeviceInfoSet)
        for (i = 0; SetupDiEnumDeviceInfo(NewDeviceInfoSet, i, DeviceInfoData); i++)
        {
   // invoke class installer method with DIF_REMOVE flag
            if (!SetupDiCallClassInstaller(DIF_REMOVE, NewDeviceInfoSet, DeviceInfoData))
            {
                // failed to uninstall device
    SetupDiDestroyDeviceInfoList(NewDeviceInfoSet);
                return -16;
            }
        }
  // perform cleanup
        SetupDiDestroyDeviceInfoList(NewDeviceInfoSet);
        return CR_SUCCESS;
    }
Forcing hardware reenumeration:
private Int32 ScanForHardwareChanges()
    {
        UInt32 DevInst = 0;
        UInt32 result = CM_Locate_DevNode(ref DevInst, null, CM_LOCATE_DEVNODE_NORMAL);
        if (result != CR_SUCCESS)
        {
            // failed to get devnode
            return -1;
        }
        result = CM_Reenumerate_DevNode(DevInst, 0);

        if (result != CR_SUCCESS)
        {
            // reenumeration failed
            return -2;
        }
        return CR_SUCCESS;
    }

Method invocation:
private void btnFixme_Click(object sender, EventArgs e)
    {
        // remove all devices of class "Image" (image capturing devices)
        Int32 status = RemoveAllDevicesInClassName("Image");
        if (status == CR_SUCCESS)
        {
            status = ScanForHardwareChanges();
        }
        lblStatus.Text = status==CR_SUCCESS ? "Done!" : "Error: " + status.ToString();
    }
I hope the code is commented well enough, and doesn't require further explanation.