Cory Foy

Saturday, April 30, 2005

MSDN Code Camp a success!

Today was the MSDN Code Camp here in Charlotte. I got to see some great presentations on things like SOA, Mobile Speech Server, and Reflection. I also presented on Test Driving ASP.NET Development (ppt). I felt like the presentation was quite a success. It ran an hour and 10 minutes, and I had a lot of really good questions from developers.

One of the fascinating parts was the comments I got during and after. About 3/4 had never used NUnit before (I didn't even ask about NUnitAsp - though a lot of people liked it). Even more interesting was when I asked how many had ever used mock objects to which exactly one developer in the very back raised his hand on.

But all in all I had an awesome time, got to be some great people, and hang out for the day on the Microsoft campus. And with the great feedback I got from the TDD mailing list, the NUnit Mailing list and the NUnitAsp lists, I feel I was able to get some people really thinking about getting their code under unit tests, and just what this whole XP/TDD thing is all about.

For those interested in the presentation:
Presentation
Code

Wednesday, April 27, 2005

Test-Driving ASP.NET Development - MSDN Code Camp Presentation

This Saturday (April 30th) I have the pleasure of speaking at the MSDN Code Camp here in Charlotte, NC. I am going to be speaking on Test-Driving ASP.NET Development.

In preparation for that, I've put up a copy of my PowerPoint presentation (675k) for comments. What do you all think? Anything that should be added, taken away, made more clear? Email me at Cory.Foy at mobilehwy dot com.

Friday, April 22, 2005

browserCaps file and ASP.NET MobileControls

To follow up from my earlier post, I found that Microsoft does indeed offer updates for the Machine.Config file browserCaps section. They call it a Device Update, and by us installing Device Update 4 we were able to fix the issue we were having with Nextel's new phone header information.

Now that's how I like to enter the weekend. :)

Microsoft and Config files

Config files can be nice. They can help set settings so that you can tweak things on the fly without having to recompile your code. Or so that non-techies can modify things without having to know your code.

Microsoft uses several config files for .NET. The biggie is Machine.Config. And today I had the pleasure of one of our apps breaking because Nextel changed the phone header information, so .NET didn't recgonize it anymore. First, when I went into the config file, Microsoft provides a link to a company that is supposed to maintain the browserCaps section. But, of course, that company doesn't. I'm sure they'd be happy to sell it to you, but the free page .NET links to says "Under Construction". Nice.

So knowing I was going to have to modify it myself, I start looking for the mobile headers section. I found it, but to give you an idea of what not to do in a config file, I'll post a *small* snippet of it here:

<!-- Phone.com 3.x, 4.x and 5.x -->
<filter>
<case match="((?'deviceID'\S*) UP/\S* UP\.Browser/(?'version'\S*) UP\.Link/(?'gatewayVersion'\S*))|((?'deviceID'\S*)/\S* UP(\.Browser)*/(?'version'\S*))|(UP\.Browser/(?'version'\S*)-(?'deviceID'\S*) UP\.Link/(?'gatewayVersion'\S*))|((?'deviceID'\S*) UP\.Browser/(?'version'\S*) UP\.Link/(?'gatewayVersion'\S*))|((?'deviceID'\S*)/(?'DeviceVersion'\S*) UP/(?'version'\S*))|((?'deviceID'\S*)/(?'DeviceVersion'\S*) UP.Browser/(?'version'\S*))">
<filter with="${version}" match="(?'browserMajorVersion'\d*)(?'browserMinorVersion'\.\d*).*">
majorVersion = ${browserMajorVersion}
minorVersion = ${browserMinorVersion}
</filter>

<filter>
<case match="[45]" with="%{majorVersion}">
type = "Phone.com %{majorVersion}.x Browser"
preferredImageMime = "image/vnd.wap.wbmp"
requiresUniqueFilePathSuffix = "true"
</case>
<case match="3" with="%{majorVersion}">
type = "Phone.com 3.x Browser"
preferredImageMime = "image/bmp"
requiresUrlEncodedPostfieldValues = "true"
requiresUniqueFilePathSuffix = "true"
canRenderInputAndSelectElementsTogether = "false"
</case>
</filter>

version = %{majorVersion}%{minorVersion}
</filter>


etc, etc. Let me just say that you should not have code and variables and regex strings all slammed together in a XML Config file. Ugh.

Last night's CharJUG presentation from Andy Hunt

Last night CharJUG had the priviledge of having Pragmatic Programmer Andy Hunt speak. Though I was sorely disappointed in the turnout (19 people of 60 some odd who I had talked or had expressed interest in going) I was not in the presentation.

The talk started at 6:45pm and went until nearly 9:45pm. I took lots of notes, and I'm hoping he sends me the powerpoint so I can put it up on the site, but here are some highlights:

- The "Broken Windows" theory. The story is that these researchers put a nice car (Jaguar or similar) in the South Bronx and left it for four days. Nothing happened to the car at all. So they went over and broke one window. Within four hours the car had been stripped, burned and flipped. The moral? Don't let little things like broken builds pile up - fix them immediately. If you build up too much "technical debt" you may not be able to get back out.

- Processes have to be easy. In 2000 Romaine lettuce consumption went up 162%. Why? Because American's started eating healthier ("No", says Andy, "American's still eat crap")? Because McDonald's started selling salads? Nope! Because that was the year they introduced "Salad in a bag" making it a no brainer for people to get some pretty, prewashed lettue and shake it on their plate. Even though it is much more expensive, people want things to be easy.

- Stand up meetings should answer three questions, and three questions only. What have you accomplished? What are you working on? What is in your way? And the answers should be in term of that day. Saying that you are working on getting validation working for your login page is good. Saying you are working on "your app" without specifics is bad.

- Don't let any of your apps have a Bus number of "1". Your bus number is not your position in the computer as an ISA card, it is how many people can get hit by a bus before you are in trouble because no one else understands the app.

- The worst words you can hear from a team are "We'll try." That means that they know that they are subject to failure, and that they also know they aren't going to make it, so they are just going to march%2

Tuesday, April 19, 2005

Upcoming CharJUG meeting with Andy Hunt this Thursday

For anyone in the Charlotte area, Andy Hunt, of the Pragmatic Programmers, is speaking at this month's CharJUG meeting. We are being sponsored by the ACM Student Chapter of CPCC, The Futures Institute, and best of all, MobileHWY (my employer).



One of the guys from CharLUG put together a really nice graphic for it that we have up on the site. Speaking of CharLUG, they are having an install fest at the end of the month - April 30th. Which happens to be the same day I am speaking at the MSDN Code Camp being held by the Developer's Guild.



All in all a very busy month for me. Hope to see you soon!

Wednesday, April 13, 2005

MTTMPFS

One of my coworkers uses the term MTTMPFS a lot - Mean Time To Major Product Focus Shift. It's amazing how low that mean time really is.

Targetting NAnt to a different framework version

I'm sure this is all over the web, but bugger if I had a hard time initially finding it. I've been working on some custom extensions to NUnitASP and was having trouble building the project. The NUnitASP guys provide an NAnt build script, but when I ran it I was getting the following:



BUILD FAILED


[csc] C:\Windows\Microsoft.NET\Framework\v1.0.3705\csc.exe failed to start. The system cannot find the file specified

Which, of course, was driving me crazy because I was specifying in my path to use v1.1. But it was ignoring that, and I couldn't figure out why.


Turns out, I just need to learn the tools I'm using. Once I spoke with the NUnitASP guys and found out it wasn't an issue with them, but something with NAnt, I found the following article:



One note: NAnt may be configured out of the box to use a different .NET Framework version than you would like. For example, NAnt 0.84 is configured to use .NET Framework version 1.0 by default. If you only have version 1.1 of the .NET Framework installed on your machine and you try running NANT 0.84 on a task that requires the framework, you will get an error similar to this one:



[csc] C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\csc.exe failed to start.
The system cannot find the file specified



To change the default framework version, you need to edit NAnt.exe.config in the \bin directory. Change the default argument in the platform tag to the .NET Framework version you would like to use as the default. The following example sets the default Framework to use to 1.1:



<frameworks>
<platform name="win32" default="net-1.1">
...
</platform>
</frameworks>

- 4 Guys From Rolla

Friday, April 08, 2005

CharLUG Meeting tomorrow

The next Chalotte Linux User's Group meeting is tomorrow at our new location at Central Piedmont Community College in downtown Charlotte. They've got the lowdown up on the CharLUG site.

Screen Print Capture in C# using SendInput()

Recently I needed a way to have an app take a screen shot of itself and save it to a directory. I only wanted the currently focused screen to be captured. I looked around on the web, and found lots of crazy interop scripts to handle doing a screen shots.


But it just didn't seem right. *I* can screen capture by just hitting Alt->Print Screen, why can't my app? I knew there would be some interop involved, but certainly it doesn't have to be that hard, does it?


Turns out, it really doesn't. By sending some Keyboard events using the Win32 SendInput() via User32.dll, and working with the clipboard data in the normal fashion, it's fairly easy to get it all working. First, you need the capture and save code:




private void CaptureAndSave()
{
uint intReturn = 0;
NativeWIN32.INPUT structInput;
structInput = new NativeWIN32.INPUT();
structInput.type = (uint)1;
structInput.ki.wScan = 0;
structInput.ki.time = 0;
structInput.ki.dwFlags = 0;
structInput.ki.dwExtraInfo = 0;

//Press Alt Key
structInput.ki.wVk = (ushort)NativeWIN32.VK.MENU;
intReturn = NativeWIN32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));

// Key down the actual key-code
structInput.ki.wVk = (ushort)NativeWIN32.VK.SNAPSHOT;//vk;
intReturn = NativeWIN32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));

// Key up the actual key-code
structInput.ki.dwFlags = NativeWIN32.KEYEVENTF_KEYUP;
structInput.ki.wVk = (ushort)NativeWIN32.VK.SNAPSHOT;//vk;
intReturn = NativeWIN32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));

//Keyup Alt
structInput.ki.dwFlags = NativeWIN32.KEYEVENTF_KEYUP;
structInput.ki.wVk = (ushort)NativeWIN32.VK.MENU;
intReturn = NativeWIN32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));

IDataObject data = Clipboard.GetDataObject();

if (data.GetDataPresent(DataFormats.Bitmap))
{
Image image = (Image)data.GetData(DataFormats.Bitmap,true);

image.Save("image" + ".bmp",System.Drawing.Imaging.ImageFormat.Bmp);
image.Save("image" + ".jpg",System.Drawing.Imaging.ImageFormat.Jpeg);
image.Save("image" + ".gif",System.Drawing.Imaging.ImageFormat.Gif);
}
else
{
Console.WriteLine("The Data In Clipboard is not in an image format");
}
}


As you can see, all the heavy lifting appears to be in a class called NativeWIN32. This class is nothing more than an internal wrapper class around the User32.dll functions. I've included the full suite of VK enums since I already had it in my code:




public class NativeWIN32
{
public const ushort KEYEVENTF_KEYUP = 0x0002;

public enum VK : ushort
{
SHIFT = 0x10,
CONTROL = 0x11,
MENU = 0x12,
ESCAPE = 0x1B,
BACK = 0x08,
TAB = 0x09,
RETURN = 0x0D,
PRIOR = 0x21,
NEXT = 0x22,
END = 0x23,
HOME = 0x24,
LEFT = 0x25,
UP = 0x26,
RIGHT = 0x27,
DOWN = 0x28,
SELECT = 0x29,
PRINT = 0x2A,
EXECUTE = 0x2B,
SNAPSHOT = 0x2C,
INSERT = 0x2D,
DELETE = 0x2E,
HELP = 0x2F,
NUMPAD0 = 0x60,
NUMPAD1 = 0x61,
NUMPAD2 = 0x62,
NUMPAD3 = 0x63,
NUMPAD4 = 0x64,
NUMPAD5 = 0x65,
NUMPAD6 = 0x66,
NUMPAD7 = 0x67,
NUMPAD8 = 0x68,
NUMPAD9 = 0x69,
MULTIPLY = 0x6A,
ADD = 0x6B,
SEPARATOR = 0x6C,
SUBTRACT = 0x6D,
DECIMAL = 0x6E,
DIVIDE = 0x6F,
F1 = 0x70,
F2 = 0x71,
F3 = 0x72,
F4 = 0x73,
F5 = 0x74,
F6 = 0x75,
F7 = 0x76,
F8 = 0x77,
F9 = 0x78,
F10 = 0x79,
F11 = 0x7A,
F12 = 0x7B,
OEM_1 = 0xBA, // ',:' for US
OEM_PLUS = 0xBB, // '+' any country
OEM_COMMA = 0xBC, // ',' any country
OEM_MINUS = 0xBD, // '-' any country
OEM_PERIOD = 0xBE, // '.' any country
OEM_2 = 0xBF, // '/?' for US
OEM_3 = 0xC0, // '`~' for US
MEDIA_NEXT_TRACK = 0xB0,
MEDIA_PREV_TRACK = 0xB1,
MEDIA_STOP = 0xB2,
MEDIA_PLAY_PAUSE = 0xB3,
LWIN =0x5B,
RWIN =0x5C
}


public struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public long time;
public uint dwExtraInfo;
};

[StructLayout(LayoutKind.Explicit,Size=28)]
public struct INPUT
{
[FieldOffset(0)] public uint type;
[FieldOffset(4)] public KEYBDINPUT ki;
};


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

}


And viola! Quick, easy screen capture code.

Sunday, April 03, 2005

Halo 2 Golden Warthog

I admit it. I play Halo 2. On XBox Live nonetheless. And while, yes, most of the people are indeed teenagers (or younger) who think it is cool to say stupid things, it is a lot of fun being able to play with some of my friends from Florida.



However, like any popular game, there are always "secrets" that abound. One of particular note on Halo 2 is called the "Golden Warthog." The Warthog is a Hummer/Jeep like vehicle that has a driver, a rider and a gunner manning a vehicle-mounted machine gun. But apparantly there is a magical way you can find a Gold-colored one in one of the levels. While perusing the net about it, I found what was probably one of the best instructions ever given for the finding of a secret in a game.


"TO GET THE GOLDEN WARTHOG YOU HAVE 3 DIFFERENT WAYS. NUMBER 1:GET YOUR XBOX AND THROW IT OUT THE WINDOW AND PICK IT UP AND TURN IT ON THEN BOOM THERE IT IS. NUMBER 2:GET A HAMMER AND SMASH YOUR XBOX 20 TIMES THAN TURN IT ON IF U CAN THEN BOOM THERE IT IS. NUMBER 3:LET THE XBOX LOOK AT YOUR FACE THAN IT WILL GET SO SCARED OF ITS ULGYNESS IT WILL AUTOMATICLY POP UP ON THE SCREEN. THERE YOU GO JUST 2 ONE IT WORKS TRUST ME I DID MM ALL." - WaMbUlAnCe


Pure, pure genius. WaMbUlAnCe, I applaud you.

CharJUG Site up and running

I finally got a dedicated site and server for CharJUG. The new address is http://www.charjug.org and I actually took some time to make it pretty!


We have a great speaker coming up this month - Andy Hunt from the Pragmatic Programmers is giving a talk on Agile Techniques. I'm pumped, and we are holding it at CPCC's central campus because of the expected turnout.


Also, I'll be doing a presentation on Test-Driving ASP.NET development using NUnitASP and other techniques at the upcoming MSDN Code Camp. They still have slots open for registration at the conference, and it's free! Check out the Enterprise Developers Guild site for the low down.