mike-obrien.net Resume Blog Labs
Friday, March 23, 2007

I have been working with the new custom configuration classes in .NET 2.0 and they really make creating custom xml configuration a snap. They are a little quirky to use at first but once you get past the initial learning curve they really make the job a lot easier.

One thing I really wanted to figure out is how to use these new classes to read files other than the default app/web.config. For example if you have one config file that might be shared between exes or if a config file is pulled from a URL. Its actually pretty easy to do.

First create your custom configuration file. It will look exactly the same as a web/app.config file except it will only contain your custom section(s). Create a section handler element identifying the custom section handler and the name of the section. Again, nothing different from doing this in the app/web.config.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <configSections>
  <section name="mySettings" type="CustomConfigHandler.MySettingSection, CustomConfigHandler"/>
 </configSections>
 <mySettings>
  <someSetting someAttribute="This is an attribute value from Settings1.config"/>
 </mySettings>
</configuration>

Next create a Configuration object that points to your file by passing in an ExeConfigurationFileMap with the ExeConfigFilename set.

// Create an exe file map containing the path to your config file
ExeConfigurationFileMap FileMap = new ExeConfigurationFileMap();
FileMap.ExeConfigFilename = "MySystem.config";

// Create a configuration object that is tied to your custom config file.
Configuration Config = ConfigurationManager.OpenMappedExeConfiguration(FileMap, ConfigurationUserLevel.None);

// Create the custom config section handler
MySettingSection MySettings = (MySettingSection)Config.GetSection("mySettings");

Console.WriteLine(MySettings.SomeSetting.SomeAttribute);


The entire source can be downloaded here:

ExternalConfigFile.zip (40.24 KB)
.NET | C# | Configuration | VB.NET
Friday, March 23, 2007 8:30:17 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
Friday, March 16, 2007

This is a very moving photo essay on the after effects of Chernobyl. Very sad to see how children were affected.

http://inmotion.magnumphotos.com/essays/chernobyl.aspx

Friday, March 16, 2007 7:23:32 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [2]  | 
Tuesday, February 27, 2007

Nice little util to extract the boot sector from an ISO or disk. The home page is located here or you can download from the link below:

bbie.zip (18.83 KB)

Here are boot sectors for a couple of OS's:

WIN_ME.zip (717.94 KB)
WIN_XP_PRO.zip (1.09 KB)
WIN_SVR_2003.zip (1.1 KB)

OS
Tuesday, February 27, 2007 6:24:15 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
Wednesday, February 14, 2007

I had a baffling problem arise today. Here is the scenario; I have a .NET WinForms app with a WebBrowser control. The WebBrowser control loads a web page that contains an embedded Flash movie. I need to send keystrokes to the Flash movie from the WinForms app. Now MS provides the SendKeys class under the Windows.Forms namespace for this very purpose, but in this instance it doesent pass them on to the Flash movie (Although it does pass them to HTML elements in the page). Hmmmmmm... A little digging in Reflector uncovers the reason. The SendKeys class internally calls the SetKeyboardState() native method to send the keyboard input. Here is what MSDN says about that call:

The SetKeyboardState function copies a 256-byte array of keyboard key states into the calling thread's keyboard input-state table. This is the same table accessed by the GetKeyboardState and GetKeyState functions. Changes made to this table do not affect keyboard input to any other thread.

I'm no expert on how embedded ActiveX controls work within a web page in IE but I bet the Flash control is not running in the same thread as the browser UI. And in the case of using the WebBrowser control, not in the UI thread of the WinForms app. So SendKeys will not be able to send keystrokes to embedded Flash in a WebBrowser control. Just a guess, but it seems that is what is happening here. Well, scratch that, I just checked Spy++ and everything is running under the WinForm UI thread including the Flash ActiveX control. So at this point I have no idea why SendInput() works but SetKeyboardState() doesent (And thus the SendKeys class), very strange indeed! If anyone knows for sure, please leave a comment! :)

So the other option is calling the SendInput method. FYI, this method supersedes the keybd_event method. Here is a sample of the code required to send keystrokes to the foreground window. Remember, you must make sure that the WebBrowser control has focus for it to receive the keystrokes (As does the Flash control in the web page, see further down for more info).

private void Main_Load(object sender, EventArgs e)
{
    WebBrowserControl.Navigate(@"file://C:\Temp\Flash.html");
    Timer.Enabled = true;
}

private int Index = 0;

private void Timer_Tick(object sender, EventArgs e)
{
    Index++;

    NativeMethods.INPUT[] structInput = new NativeMethods.INPUT[1];

    structInput[0] = new NativeMethods.INPUT();
    structInput[0].type = NativeMethods.INPUT_KEYBOARD;
    structInput[0].ki.wScan = 0;
    structInput[0].ki.time = 0;
    structInput[0].ki.dwFlags = 0;
    structInput[0].ki.dwExtraInfo = NativeMethods.GetMessageExtraInfo();
    structInput[0].ki.wVk = NativeMethods.VK_RIGHT;

    // Key up every other pass
    if (Index % 2 == 0)
    {
        structInput[0].ki.dwFlags = NativeMethods.KEYUP;
    }

    NativeMethods.SendInput(1, structInput, Marshal.SizeOf(structInput[0]));
}

The basic native method & struct declarations are as follows. PInvoke.NET has a nice definition of all of these.

public const int INPUT_KEYBOARD = 1;
public const int KEYUP = 2;

public const int VK_LEFT = 0x25;
public const int VK_UP = 0x26;
public const int VK_RIGHT = 0x27;
public const int VK_DOWN = 0x28;


[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
    int dx;
    int dy;
    int mouseData;
    int dwFlags;
    int time;
    IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
    public short wVk;
    public short wScan;
    public int dwFlags;
    public int time;
    public IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
public struct HARDWAREINPUT
{
    int uMsg;
    short wParamL;
    short wParamH;
}

[StructLayout(LayoutKind.Explicit)]
public struct INPUT
{
    [FieldOffset(0)]
    public int type;
    [FieldOffset(4)]
    public MOUSEINPUT mi;
    [FieldOffset(4)]
    public KEYBDINPUT ki;
    [FieldOffset(4)]
    public HARDWAREINPUT hi;
}

[DllImport("user32.dll", SetLastError = true)]
public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);

[DllImport("user32.dll", SetLastError = false)]
public static extern IntPtr GetMessageExtraInfo();

The only other thing you need to do to make this completely automated is to set focus on the Flash movie in the web page using JavaScript. Simply call the focus method of the Flash control as follows:

window.document.MyFlash.focus();

The entire project can be downloaded here.

.NET | C# | Flash | Win32 API
Wednesday, February 14, 2007 10:31:15 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [4]  | 
Tuesday, February 06, 2007

Zipped source files are getting really lame! I found a hosted Subversion solution (wush.net) for about 7 bucks a month and am hosting all the source code for the Labs there. The setup was very simple and I was up and running in about 15 minutes. The starter package gives you 1 repository and 100mb of space, plenty for personal use. You can browse the repository here with a web browser, but the best way to access it is using a Subversion client such as TortoiseSVN.

Tuesday, February 06, 2007 5:58:42 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 

For those of you who still use SMS Installer the following script enables you to detect if a certian version of the .NET Framework is installed on the machine. Just switch over to the "Script Editor", copy the text from the following file and paste it where you want it. Basically it only extracts and runs the redist if the desired version is not installed. This makes the setup run a lot faster for users who will already have a particular version of the framework installed.

DOTNETSMS.txt (6.23 KB)
Tuesday, February 06, 2007 5:49:33 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
Monday, January 29, 2007

There is a new version of the Hid Library in the labs. It has been converted to .NET 2.0 and includes a bug fix. This bug fix involved how the vendor and product id were cast in the structure consumed by the Hid API. So some devices like Logitec's gamepads would not be recognized by their product and vendor id's. Now that issue is resolved. N-joy!

USB Hid Device Library

.NET | C# | USB HID | VB.NET
Monday, January 29, 2007 10:36:12 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [27]  | 
Wednesday, January 10, 2007

The question came up regarding the scheduling of SQL Server jobs and whether multiple instances of a job could run at the same time. So for example if I have a job that is scheduled to run every 15 minutes and for some reason the job runs 30 minutes, will a new instance of the job be started so now I will have 2 instances of the job running at the same time? The answer is no. SQL Server will not allow multiple instances of a job to run at any given time (See the note). I did some testing and the behavior of the SQL Server Agent is this; the Agent will run the job, if the job runs longer than the interval the Agent will wait the interval after the previous job had completed before running the job again, if it runs less than the interval it will allow the interval to completely pass (From the time the job was started) before running it again. For example if you have a job that is scheduled to run every 15 minutes the activity might look something like this:

01:00 PM - Agent runs the job

01:45 PM - Job stops after running 45 minutes

02:00 PM - Agent runs the job after waiting 15 minutes from when the job stopped

02:14 PM - Job stops running after 14 minutes

02:15 PM - Agent runs the job after waiting 15 minutes from when the job started

This could be problematic if the job runs every 5 hours and you are expecting the job to run like clockwork:

12:00 PM - Agent runs the job

05:01 PM - Job stops running after 5 hours and 1 minute

10:00 PM - Agent runs the job after waiting 5 hours from when the job stopped

This essentially skips the 5:00 PM instance of the job because the 12:00 PM instance ran a minute longer than the interval. In most cases this will not be a problem but could throw you off if you are expecting it to be run at that time.

Wednesday, January 10, 2007 6:54:43 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 

Very cool, MIT is publishing all of their couse materials under a CC license. Great resource for self-study!

Wednesday, January 10, 2007 4:13:41 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
Tuesday, January 09, 2007

I was looking over a peice of my code today and noticed I had some finalization code in a try-finally block but there was a code path that had a return statement. So I thought, "thats a bug because I'm jumping out of the method before the finally block is called!". Silly me! MSDN says "Control is always passed to the finally block regardless of how the try block exits". For some reason I always thought that the finally block was bypassed when you exited a method via the return statement... :-S

.NET | C# | VB.NET
Tuesday, January 09, 2007 5:02:49 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |