DCSIMG
Temporary Title
Bing Maps sample - advanced flavor
18 December 10 04:11 PM | grozen | with no comments

The last several months have been an exceptionally busy time for me, with the last month or so presenting me with a workload which can only be categorized as “unearthly”. All for a good cause, however, as even more XNA 4.0 content is now available for the eager game developers out there.

One of my particular contributions to this batch of content is the Bing Maps sample,  which shows how to retrieve data from the Bing Maps REST Services and how to incorporate it into your game.

What you probably don’t know about this sample is that it is actually a simplified version of the original sample Microsoft asked us for. The original ended up being dauntingly complex, which in turn made it rather inaccessible and therefore not the best learning material.

While the original sample lacked the ability to focus on a location by typing its name in, it did boast a handful of other features that did not make it to the sample that was eventually released:

  1. Completely navigable map: Unlike the current sample which limits your movement to a set area around the location on which you focus, the original sample allowed for unlimited scrolling in any direction (there’s a caveat to this, which will be detailed later).
  2. Image caching: Allowing the map to be fully scrollable necessitated managing a cache of the images downloaded from the Bing Maps REST Service in order to make the sample much more responsive by preventing an excessive amount of web requests from being performed.
  3. Zooming capabilities: The original sample allowed zooming in and out using pinching gestures (something you won’t be able to see unless you are using an actual Windows Phone 7 device or have a multi-touch display for work with the emulator).
  4. Pin placement: Tapping a location in the original sample would cause a pin to be placed there. Pressing and holding over a pin would remove it. This feature makes a comeback in another one of our samples which has not been released yet.

I have to admit that on top of being more complex, the original sample has some blemishes as well. These are mostly the result of an even older version of the sample (the primal sample, if you will) on which the original sample was based.

  1. The sample does not use standard tile sizes: Instead of conforming with the tiles defined as part of the Bing Maps Tile System (an excellent read if you plan on doing things with Bing Maps data), the sample uses tiles which are the same size as the device’s display. This makes us lose something very important which the Bing Maps Tile System guarantees – cohesiveness. If we were to use the Bing Maps tiles, our tiles would “magically” connect to each other at the edges of the map, allowing continuous scrolling around the globe. Since our tiles do not connect at the edge of the map, the sample simply doesn’t allow scrolling past the map’s edges, and may even clip a small portion of the map’s edge (this is that caveat I mentioned earlier).
  2. The sample tries to prefetch too much data at once: The way in which the sample works is that it tries to fetch all tile images surrounding the current tile at the center of the display. Once it finishes with that, it fetches tiles one zoom level deeper and then one zoom level higher than the current zoom level (but at the same position, naturally). This is assuming you are not scrolling the map, as that would change the tile that is at the screen’s center. This may not look so bad, until you consider the fact that the sample opens a thread for each image request. While I have not tested it, I have a heavy suspicion that eight (or at times, nine) threads all vying for data from the Bing Maps REST Service just end up slowing everything down. It would have probably been better to use a single additional thread to get the images one at a time.
  3. The sample performs too many allocations: Once image data is retrieved, a new Texture2D is created to contain the data (essentially allocating and populating a duplicate of the data which we already have in out hands). This leads to a very noticeable performance hit just before each image tile appears (most easily visible when dragging the display around while images load). This was not fixed as it would have taken quite a bit of effort, and since we knew the sample wasn’t going to be released there was no sense in investing said effort.

To be fair, there are also a couple of things which I am very pleased about in the original sample:

  1. The code is tidy and readable: Seeing how this version of the sample was tricky to follow, I went to great lengths to make the code as readable as possible. Perhaps I took it even more seriously than usual, seeing how the primal sample can only be described as an insane flurry of incomprehensible code chunks. I didn’t want anyone to go through what I did while figuring out how it all worked.
  2. There is no thread management code: As mentioned previously, the sample has quite a few threads working in concert, but none of these threads are managed directly by the sample code. All threads are created using asynchronous operations made available by the WebClient and IsolatedStorageFileStream classes and the result of these asynchronous operations are then handled in callbacks which execute in the sample’s main thread. This means that there is no synchronization code anywhere in the sample, which is always a cause for merriment.

So, if you find the official Bing Maps sample too simple for your taste, or if you are simply curious, then here is a downloadable version of the original version of the sample in all its glory. Keep in mind that you may encounter other issues than those mentioned above while running the sample (though you shouldn’t) since things that are not released end up being scrutinized to a lesser degree.

Converting a 3D XNA 3.0 game to XNA 4.0 – an example
23 October 10 07:41 PM | grozen | 7 comment(s)

XNA 4.0 is great, but greatness comes at a cost. In order to have XNA 4.0 work uniformly across all its target platforms (Xbox, PC and Windows Phone 7) some breaking changes had to be made. While the changes improved the XNA framework by making things simpler (a lot of properties which didn’t really affect anything are gone) and better (the architecture makes more sense now, and it would be easy for XNA to support DirectX 10 at some point in the future), they also made it hard to port XNA 3.0 games to XNA 4.0. The main reason this task is so difficult is that there is no centralized location which catalogs all of the changes made and how they should be dealt with when porting a game. This is how this post was born.

I took one of the XNA 3.0 games available on the App Hub and converted it to XNA 4.0, documenting the various issues I overcame along the way. While this does not serve as a comprehensive guide as it is based on a single case, it does serve as the next best thing – a concrete example of how to get the job done.

I’ll just go ahead and say that the information to overcome most of these issues is spread about the web, namely on Shawn Hargreave’s blog, but now you don’t have to dig around for it.

So let us get started. Here are the main issues I have faced, along with their resolution.

Pixel shader 1.x is no longer supported:

All shaders contained in the project used Pixel Shader 1.x, which is no longer supported. The simple solution is to update all compilation targets to use Pixel Shader 2.0, though other options exist as detailed here.

For example, change the following:

       1: PixelShader = compile ps_1_1 ShipPS();

Which can be usually found in shader files (.fx files) to:

       1: PixelShader = compile ps_2_0 ShipPS();

This will prevent the following error: “error X3539: ps_1_x is no longer supported”.

Some shader effect states are now obsolete:

Certain aspects of the graphics state can no longer be controlled from within shaders, but are set in the game’s code instead. Specifically, I had to remove the following marked line from one of the shaders:

   1: technique Ship
   2: {
   3:    pass Single_Pass
   4:    {
   5:         ZENABLE = TRUE;
   6:         ZWRITEENABLE = TRUE;
   7:         ALPHATESTENABLE = FALSE;
   8: ...

Failure to do so will result in the error: “The effect state 'AlphaTestEnable' is obsolete and can no longer be used”. Whether or not you will have to compensate for such removed lines in code depends on XNA 4.0’s default states.

Have a look at this thread, which sheds a bit more light on the matter.

Old format XAP files need to be updated:

Most XNA 3.0 games contain a XAP file created with an old version of XACT. Simply open it with the version of XACT shipped with XNA 4.0 and save it again, that should do the trick. This will prevent the “Error 10 The .xap file was created with a version of XACT that is incompatible with the XNA Framework Content Pipeline version used by this project” error.

PresentationParameters has had a property overhaul:

Compare the previous version of the PresentationParameters class with the new one. As you can see, both classes are quite different, though some new properties are reminiscent of older ones (some are even identical). Each property has its own set of reasons for appearing, changing or disappearing and fixes have to be applied on a case by case basis.

In my specific case, I had to replace the creation of a render target which took in PresentationParameters.MultiSampleType and PresentationParameters.MultiSampleQuality to control antialiasing. Both properties are gone only to be replaced by the singular PresentationParameters.MultiSampleCount, which is now also an argument for the render target’s constructor. I will show a more concrete example in the next section.

The DepthStencilBuffer class no longer exists:

One of the breaking changes in XNA Game Studio 4.0 was the extermination of the DepthStencilBuffer class, for reasons detailed in this post. As stated in the post, the data previously contained in the DepthStencilBuffer class has been incorporated into the various render targets. This, combined with the necessary changes detailed in the previous section, caused the following bit of code:

   1: PresentationParameters pp = graphics.GraphicsDevice.PresentationParameters;
   2:  
   3: drawBuffer = new RenderTarget2D(graphics.GraphicsDevice,
   4:                                 FixedDrawingWidth, FixedDrawingHeight, 1,
   5:                                 SurfaceFormat.Color,
   6:                                 pp.MultiSampleType, pp.MultiSampleQuality);
   7:  
   8: drawDepthBuffer = new DepthStencilBuffer(graphics.GraphicsDevice,
   9:                                 FixedDrawingWidth, FixedDrawingHeight,
  10:                                 pp.AutoDepthStencilFormat,
  11:                                 pp.MultiSampleType, pp.MultiSampleQuality);
  12:  
  13: spriteBatch = new SpriteBatch(graphics.GraphicsDevice);

To turn into:

   1: PresentationParameters pp = graphics.GraphicsDevice.PresentationParameters;
   2:  
   3: drawBuffer = new RenderTarget2D(graphics.GraphicsDevice,
   4:                                 FixedDrawingWidth, FixedDrawingHeight,
   5:                                 true, SurfaceFormat.Color,
   6:                                 DepthFormat.Depth24Stencil8, pp.MultiSampleCount,
   7:                                 RenderTargetUsage.DiscardContents);
   8:  
   9: spriteBatch = new SpriteBatch(graphics.GraphicsDevice);

The member “drawDepthBuffer” appeared in other places in the code, and naturally must be removed.

GraphicsDevice no longer has a RenderState property:

One of the main reasons you would want to interact with the RenderState property is to properly mix 3D and 2D drawing as detailed in this post. To overcome this hurdle, just replace your code to match the updated post.

You would change code like this:

   1: IGraphicsDeviceService graphicsService = (IGraphicsDeviceService)GameInstance.Services.GetService(typeof(IGraphicsDeviceService));
   2:  
   3: graphicsService.GraphicsDevice.RenderState.AlphaTestEnable = false;
   4: graphicsService.GraphicsDevice.RenderState.AlphaBlendEnable = false;
   5: graphicsService.GraphicsDevice.RenderState.DepthBufferEnable = true;
   6: graphicsService.GraphicsDevice.RenderState.DepthBufferFunction = CompareFunction.LessEqual;
   7: graphicsService.GraphicsDevice.RenderState.DepthBufferWriteEnable = true;

To:

   1: IGraphicsDeviceService graphicsService = (IGraphicsDeviceService)GameInstance.Services.GetService(typeof(IGraphicsDeviceService));
   2:  
   3: graphicsService.GraphicsDevice.BlendState = BlendState.Opaque;
   4: graphicsService.GraphicsDevice.DepthStencilState = DepthStencilState.Default;

VertexBuffer has been changed to be strongly typed:

Instead of wasting my “breath” (I am typing, after all), another post by Shawn Hargreaves says all there is to say about this change. This entails numerous changes to the project’s code, but following Shawn’s example should get you there. A specific example will be shown in the next section.

Effect and EffectPass classes have changed:

The main difference in Effect and EffectPass is that code no longer has to be enclosed between calls to Begin() and End(). Instead, EffectPass has a new Apply() method which you simply call whenever you wish to set the effect state onto the graphics device. Have a look over here, especially in the comments section.

Since examples always make things easier, not to say tangible, have a look at the following rendering method:

   1: public override void Render()
   2: {
   3:     IGraphicsDeviceService graphicsService = (IGraphicsDeviceService)GameInstance.Services.GetService(typeof(IGraphicsDeviceService));
   4:     GraphicsDevice device = graphicsService.GraphicsDevice;
   5:  
   6:     base.Render();
   7:  
   8:     device.VertexDeclaration = vertexDecl;
   9:     device.Vertices[0].SetSource(buffer, 0, VertexPositionColor.SizeInBytes);
  10:  
  11:     effect.Begin();
  12:     effect.Techniques[0].Passes[0].Begin();
  13:  
  14:     layer1TextureParam.SetValue(layer1);
  15:     layer2TextureParam.SetValue(layer2);
  16:     layer3TextureParam.SetValue(layer3);
  17:     layerFactorParam.SetValue(layerFactor);
  18:     layer1OffsetParam.SetValue(layer1Offset);
  19:     layer2OffsetParam.SetValue(layer2Offset);
  20:     effect.CommitChanges();
  21:  
  22:     device.DrawPrimitives(PrimitiveType.TriangleList, 0, xCount * yCount * 2);
  23:  
  24:     effect.Techniques[0].Passes[0].End();
  25:     effect.End();
  26: }

And now look at the updated version, which includes changes relating to VertexBuffer as well as Effect/EffectPass:

   1: public override void Render()
   2: {
   3:     IGraphicsDeviceService graphicsService = (IGraphicsDeviceService)GameInstance.Services.GetService(typeof(IGraphicsDeviceService));
   4:     GraphicsDevice device = graphicsService.GraphicsDevice;
   5:  
   6:     base.Render();
   7:  
   8:     device.SetVertexBuffer(buffer);
   9:     
  10:     layer1TextureParam.SetValue(layer1);
  11:     layer2TextureParam.SetValue(layer2);
  12:     layer3TextureParam.SetValue(layer3);
  13:     layerFactorParam.SetValue(layerFactor);
  14:     layer1OffsetParam.SetValue(layer1Offset);
  15:     layer2OffsetParam.SetValue(layer2Offset);
  16:  
  17:     effect.Techniques[0].Passes[0].Apply();
  18:  
  19:     device.DrawPrimitives(PrimitiveType.TriangleList, 0, xCount * yCount * 2);
  20: }

SpriteBatch.Begin(…) now takes in different parameters:

This change isn’t all that hard to get around, since enough plowing through MSDN (specifically here and here), combined with the similarly named arguments, should make it easy to translate your old calls to new ones. For example, the following call:

   1: SpriteBatch.Begin(SpriteBlendMode.None);

Turns into this:

   1: SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque);

ModelMesh and ModelMeshPart had some properties changed:

Much like PresentationParameters mentioned earlier, these two classes have had some properties changed, and by changed I also mean removed/added. Have a look at the 3.1 MSDN pages (ModelMesh, ModelMeshPart) and the new 4.0 pages (ModelMesh, ModelMeshPart). By way of example, the following code (where modelMesh is a ModelMesh and meshPart is a ModelMeshPart):

   1: if (meshPart.PrimitiveCount > 0)
   2: {
   3:     IGraphicsDeviceService graphicsService = (IGraphicsDeviceService)GameInstance.Services.GetService(typeof(IGraphicsDeviceService));
   4:     GraphicsDevice gd = graphicsService.GraphicsDevice;
   5:  
   6:     gd.VertexDeclaration = meshPart.VertexDeclaration;
   7:     gd.Vertices[0].SetSource(modelMesh.VertexBuffer, meshPart.StreamOffset, meshPart.VertexStride);
   8:     gd.Indices = modelMesh.IndexBuffer;
   9:  
  10:     gd.DrawIndexedPrimitives(PrimitiveType.TriangleList, meshPart.BaseVertex, 0, meshPart.NumVertices, meshPart.StartIndex, meshPart.PrimitiveCount);
  11: }

Turns into something slightly different (this also contains changes made to work with the new VertexBuffer):

   1: if (meshPart.PrimitiveCount > 0)
   2: {
   3:     IGraphicsDeviceService graphicsService = (IGraphicsDeviceService)GameInstance.Services.GetService(typeof(IGraphicsDeviceService));
   4:     GraphicsDevice gd = graphicsService.GraphicsDevice;
   5:  
   6:     gd.SetVertexBuffer(meshPart.VertexBuffer);
   7:     gd.Indices = meshPart.IndexBuffer;
   8:  
   9:     gd.DrawIndexedPrimitives(PrimitiveType.TriangleList, meshPart.VertexOffset, 0, meshPart.NumVertices, meshPart.StartIndex, meshPart.PrimitiveCount);
  10: }

Point sprites are a thing of the past:

There is a pretty detailed post about this issue on Shawn Hargreave’s blog, which says more than I could hope to say about the matter.

One of the alternatives to point sprites, which I adopted, is rendering tiny triangles. Just be sure not to use the exact same point for all of the triangle’s vertices, as nothing will be rendered that way. Instead, make sure that all vertices are slightly different.

Texture content processor now has a “Premultiply Alpha” property:

This point is easy to overlook and caused me quite a bit of grief. XNA 4.0’s texture content processor (the one used by default for images) has a new “Premultiply Alpha” property which is on by default. This was not the default in earlier versions of XNA, which caused a plethora of baffling rendering issues. If your texture does not expect this, simply turn it off.

State objects are read only:

This is not strictly related to the conversion process, but is something to be aware of nonetheless. The GraphicDevice’s various state objects, such as GraphicsDevice.RasterizerState or GraphicsDevice.DepthStencilState are read only.
If you try to do something like GraphicsDevice.DepthStencilState.DepthBufferWriteEnable = true; you will be greeted by the following InvalidOperationException: “Cannot change read-only DepthStencilState. State objects become read-only the first time they are bound to a GraphicsDevice. To change property values, create a new DepthStencilState instance.”.

Instead, just do what the exception suggests and write something like:
GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
For a read-only depth stencil. You could also define your own state objects and assign them, just be sure to cache the objects instead of creating them repeatedly.

In retrospect, I could have named this post “A guided tour of Shawn Hargreave’s blog”. Hopefully this information, bolstered by some concrete example, will help you in your game converting endeavors.

תגים:, ,
Creating games for Windows Phone 7™ has never been easier
31 August 10 06:15 PM | grozen | with no comments

Technically, game development for the Windows Phone 7™ was not possible until recently, so the fact that it has never been easier is not too reassuring if you stop to think about it.

However, having spent the better part of the passing month working on some learning materials tackling Windows Phone 7™ game development using the XNA Game Studio 4.0, I can safely say that developing games for the device should be a very pleasant and familiar experience, assuming you have some C# background.

The current batch of samples and articles should provide a solid base for game development by introducing some of the basic concepts and capabilities of the Windows Phone 7™. There’s even an article for the less C# savvy, which mainly targets Java and Objective-C developers, but can help anyone with some programming knowledge get on the C# bandwagon more smoothly.

A considerable share of my work went into the Catapult Wars lab, which is a step by step tutorial for building a complete 2D game for Windows Phone 7™. My main objective was to keep the lab as streamlined as possible by providing just enough explanations to make everything clear yet not tedious.

I hope you enjoy the content already available, and look forward to providing you with more materials in the near future, as I am sure the rest of my team here at Sela does (to name a few, as they don’t all have blogs).

Action filters can cause the coded UI recording engine to crash
27 July 10 11:44 PM | grozen | with no comments

Recently, at one of our clients which I have mentioned in other posts, I’ve been receiving complaints that every now and then, after recording a coded UI test (or performing an action recording in the Test Manager), the involved application crashes. After some trial and error, I was able to pinpoint the exact actions which, if performed during a recording, induced the crash.

Sadly, that got me no closer to understanding how that specific set of actions induced the crash. All I had to go on was a crash dump (and the aid of my colleague Dima Zurbalev, who has no blog I can link to).

Long story short, I discovered that an action filter I installed at the client was at fault. In certain cases it altered the action recording to include actions which currently go under the recording mechanism’s radar (it has an xsd used to validate UI maps), only to have it crash later on.

I will now demonstrate how to cause this issue to surface, which may help anyone running into a similar issue diffusing it more swiftly.

First off, you can download this nasty little extension, which once installed will have your action recordings crashing in no time. Now let’s see just how the extension “achieves” this. Here’s the relevant part of the action filter contained in the extension:

   1: /// <summary>
   2: /// Adds one sendkeys action which sends no keys.
   3: /// </summary>
   4: /// <param name="actionStack"></param>
   5: /// <returns></returns>
   6: public override bool ProcessRule(IUITestActionStack actionStack)
   7: {
   8:     if (addAction == true)
   9:     {
  10:         addAction = false;
  11:  
  12:         SendKeysAction evilAction = new SendKeysAction(actionStack.Peek(0).UIElement);
  13:         evilAction.Text = String.Empty;
  14:  
  15:         actionStack.Push(evilAction);
  16:  
  17:         Trace.WriteLine("Added an eeeeevil action");
  18:  
  19:         return true;
  20:     }
  21:             
  22:  
  23:     return false; // Handle the event regularly.
  24: }

What the extension does is check a static variable called “addAction”. If the variable is true then a single SendKeys action will be added to the recording’s action stack. The real culprit is line 13, where the action is instructed to type in an empty string. When the recording mechanism process the UI map created using this extension, it will eventually crash thusly:

Alas, I have crashed

Taking a peek inside the generated dump will reveal the following System.InvalidOperationException:

I suppose I can make an exception

Notice the part which says “There is an error in the XML document”. What me and my aforementioned colleague had to go on was just this error, which we eventually matched against a scrap of the UI map we found in the memory of a full dump.

So, the bottom line is that if you see the above exception, it’s probably your fault. I hope the contents of this post help you expose the specific cause all the quicker.

Coded UI support for Janus ExplorerBar v3 for Winforms
25 June 10 04:24 PM | grozen | with no comments

You may remember a very recent and likely named post dealing with the Janus GridEX control. The main difference between that post and this one, is that by the end of this one I will actually supply you with code which adds proper accessibility, and therefore Coded UI support, to the Janus ExplorerBar control. You may wonder, justly, why I would choose to discriminate between the ExplorerBar and the GridEX. There are basically two reasons:

  1. Adding accessibility to the ExplorerBar was much easier. Adding accessibility to the GridEX was quite an ordeal. It involved plenty of trial and error and even required an additional action filter to work properly. The ExplorerBar’s accessibility support was much more straightforward to implement and was made even simpler since a major part of the control is a plain old Pane control, which already has proper accessibility.
  2. This accessibility implementation caters a specific application. While I suspect the eventual implementation should work well for most usages of the ExplorerBar, I did create it for a specific client which uses it in a specific way in his application. The area where this might cause the most difficulty is with the ExplorerBar’s group buttons. While the ExplorerBar contains properties to let the user know whether its various group headers contain close and/or expand buttons, there is no direct way of getting the bounds of said buttons. My implementation assumes specific sizes for said buttons and specific placement relative to the bounds of their containing control, which is obviously not something which necessarily fits all applications (in fact, it necessarily does not fit all applications). I am sure, however, that should the need arise, you will be able to alter the supplied code to suit your needs.

Keep in mind that as in any piece of software, there may be imperfections. If you come across one, you can either let me know or tackle it yourself.

The goods.

List of illegal characters in TFS area/iteration paths
12 June 10 05:06 PM | grozen | with no comments

Last Thursday I’ve been at a client converting their Quality Center repository into TFS work items. Since items in Quality Center are arranged in a tree, there is need to preserve this hierarchy in the TFS work items somehow. One of the more reasonable approaches is to use the “Area Path” work item field, which is in itself a tree with hierarchy, in order to preserve said information. The problem is that nodes in the Quality Center tree can contain characters which are illegal in TFS area (or for that matter, iteration) paths. Since these migration processes are done automatically (unless you hardly have any data), it is important to get these illegal characters out of the way beforehand.

While it is legitimate for certain characters not to be legal in area paths, I find it preposterous that there is no easily locatable list of these illegal characters. I wish to correct this problem.

So here are the characters which are illegal in TFS area/iteration paths (comma separated and with explanations where necessary):

\t (tab), \n (line feed), \r (carriage return), , #, $, %, &, *, /, :, <, >, ?, |

תגים:,
Two unfortunate test behaviors which are still present in VS2010
08 June 10 11:42 PM | grozen | with no comments

I have always found one thing amazingly infuriating about the testing framework supplied with Visual Studio - on some occasions your test code will fail, or act in unusual ways, just because you are running it using the testing framework. Fortunately, these cases are quite rare, but should you do come across them you can expect quite some work in store just to get your code to act like it is supposed to.

I have had the dubious pleasure of encountering such an issue yet again at one of our clients where Visual Studio 2008 is still in use and that made me wonder whether two of my least favorite testing framework behaviors have made it into Visual Studio 2010 (I’ll go ahead and give you a spoiler, they have).

Tests run inside a job:

I wouldn’t be too surprised if some of you aren’t really aware of what a job is, exactly. I myself was not aware of jobs until I had some tests failing with an error message saying that I could not create jobs inside other jobs. Jobs (formally known as Job Objects) are in essence entities which allow greater control over processes associated with them. While I suppose there is some reason behind running all tests inside a job, a direct  and unfortunate result is, as I have stated, that if your test code creates job objects you are bound to fail as you cannot create jobs in a process running inside a job. In order to overcome this hurdle there is usually no alternative but to communicate with a different process which runs outside the test’s job in order to realize the test properly. It is worth mentioning that if you run your tests directly by calling MSTest.exe you can use the /noisolation flag to make your tests job-free (though this is not the only way /noisolation affects the test run).

Unhandled exceptions outside the main thread crash the test engine:

This one is pretty straightforward, and sometimes quite devastating. If your test creates additional threads and an unhandled exception occurs in one of them, then the process running the tests will simply crash. This is especially nasty when you have a large list of tests which runs overnight and the second test displays this issue, causing all following tests not to be executed since the test process is dead. As a precaution, make sure to handle all exceptions in threads launched by your test (while this is generally a good idea regardless, I didn’t really expect the test process to crash the first time this happened to me).

Coded UI support for Janus GridEX v3 for Winforms
07 May 10 06:20 PM | grozen | 4 comment(s)

I partially hate myself for writing this post. Chances are, if you’ve reached this page, that you really really want coded UI tests to work with your application, which for some reason or another harbors the insidious Janus GridEX. While I have spent considerable time and effort on a solution, I will have to disappoint you by not making anything available for download just like that.

Do not lose heart, however, for I will do my best to tell you what must be done in order to overcome the GridEX’s shortcomings when it comes to being testable using coded UI tests. The problem, you see, is twofold.

GridEX – so inaccessible:
As I have mentioned in other post(s), the coded UI mechanism interacts with Winforms controls using accessibility. While all controls have a default implementation for supporting accessibility, this default provides only the most basic capabilities which are insufficient when dealing with complex controls. The GridEX, which is a rather complex control, provides absolutely no custom accessibility implementation. The most obvious symptom for this lack of accessibility support is that while recording coded UI tests the coded UI builder does not “understand” GridEX controls. Interactions with individual cells will simply be recorded as clicks in various coordinates on the GridEX control (which is a real shame should you happen to play the test again with a differently sized window or an altered form layout), not to mention that there is absolutely no way to use any sort of validation on the cell contents.

Solving this issue is pretty simple on a theoretical level, just implement the missing accessibility support. While this is an intrusive (though not very intrusive) solution, as it will require you to alter the application under test, I have found no sensible alternative.

Luckily for us, while accessibility support requires implementing a set of COM methods, Winforms hides this little nastiness away from us and provides a much more friendly approach. All that we need in order to make a control accessible is to provide a custom implementation for the CreateAccessibilityInstance method, which is derived from the Control class. This method is expected to return an AccessibleObject which exposes a set of functions which serve as implementations for their COM counterparts. Simply put, the AccessibleObject presents methods which allow one to both manipulate the associated control and navigate to its children. It is important to note that not all AccessibleObjects have an actual associated control. When dealing with grids, the grid rows and cells have (or should have) accessible objects which allow examining their values and manipulating them, but the rows and cells are not actual controls in and of themselves.

The GridEX may be a very capable control, but in essence it is still a grid and as such should expose the accessibility functions expected of a grid. The out-of-the-box DataGridView control provides perfect accessibility implementation and therefore I would advise you to do as I did and simply mimic what the DataGridView does and implement it in a GridEX subclass. This is more tedious than difficult as you will have to do a lot of Reflectoring to figure out exactly how the DataGridView works from an accessibility perspective and you will also have to be well versed in the GridEX’s capabilities in order to mimic everything successfully. A good place to start looking would be the DataGridViewAccessibleObject class and its two counterparts DataGridViewRowAccessibleObject and DataGridViewCellAccessibleObject. It is also worth noting that while the DataGridView provides accessibility for the row and column headers, the GridEX cannot as there is no way to get the bounds of either of them, so their supposed AccessibleObjects will not be able to portray their location.

GridEX – diabolically dynamic:

Grids can contain a very large amount of cells, each of them potentially editable. Keeping an individual input control for each cell would be inefficient, if not impossible. That is why most grid implementations dynamically create an input control over the cell a user interacts with, thus requiring just one control while supporting input to any of the cells. From a coded UI perspective this should not pose a problem, assuming the dynamic control is always identifiable by the same means (being the child of the grid control and having a specific name would be sufficient). Unfortunately, when dealing with the GridEX, the input control does not necessarily have the same name at different times. To be fair, there is need to differentiate between several distinct input controls the GridEX exposes. Some cells will expose a combobox control or a date picker control, both of which will always have specific names so there is no need to worry about them, which is lucky since they are internal to the GridEX and can’t really be customized for better support. The real issue is with editbox controls, which are the most common control as they are used for all free text cells. For some inconceivable reason, perhaps just out of spite, the name of the editbox created when interacting with a cell is tied directly to the contents of said cell when it was clicked. This means that if you have a coded UI test recorded where you clicked a cell which contained the value “Cake” and you run it again with a different set of data in the GridEX so that the cell now contains the value “Zucchini”, then the test will fail since it will not find the “Cake” editbox, only the “Zucchini” editbox.

Overcoming this issue was far trickier. What I eventually did was create a coded UI extension to specifically handle this issue. The extension contained an action filter which identified interaction with the GridEX’s dynamic editbox and translated it to keypresses directed at the GridEX itself (to handle keyboard navigation) and value set actions aimed directly at the cells instead of the dynamic edit box control created when the cells are clicked.

I realize what I just said is far from trivial, but sadly there is not much more to say, as the specifics of the implementation are what make up the bulk of the action filter. If you don’t care much for keyboard navigation, then all you really need is to translate a sequence of clicking on a grid cell and typing in an editbox into an action for setting the text typed in the editbox directly into the cell.

 

Assuming you overcome both issues presented here, your GridEX will now be perfectly suitable for coded UI recordings.

Two small and not very related things
23 April 10 01:53 PM | grozen | with no comments

Thing 1: Overzealous search and replace can be hazardous to your Coded UI tests

Well, this is hardly a surprise considering that carelessly searching and replacing can decimate just about any piece of code. It is worth noticing, however, that since Coded UI tests are generated from the XML contained in the test’s “uitest” file (usually UIMap.uitest), then any errant replace operations that find their way into said file could cause quite a bit of damage that would be difficult to repair without having intimate knowledge of the uitest file’s contents.

One particular problem I’ve come across recently at one of our client sites had one of the testers incapable of using the Coded UI test builder no matter what. Each time the builder launched he would receive the following error message: “An item with the same key has already been added”. Here’s a photo illustration of the problem:

Provided by code illustrated

The “uitest” file contains a section called ExecuteActions which details all the actions which were recorded as part of the various Coded UI tests. Each action is an XML node which has an attribute called MarkerInformation which serves as the action’s name. What happened was that two actions were accidentally given the same value in the above attribute. Changing one of the values caused the problem to vanish.

Thing 2: Console tool for getting build products

Nothing much to say about this one. I needed a console tool that would allow me fetch team build products from a server to a specified directory, and I couldn’t google one easily enough. Here’s the code for the tool, so compile away and use it.

Using the tool should feel fairly familiar if you’ve used a TFS command line tool before. The tool itself doesn’t provide too much usage information if you don’t give it the proper argument (I wrote it for myself, after all) so here’s the lowdown on how to use it:

BuildGetter /collection:<collection uri> /project:<team project> /definition:<build definition> [/build:<build number/name>] /out:<destination folder>

Where:

  • /collection: is used to specify the collection which contains the build you want, such as http://server:8080/tfs/collection.
  • /project: is the name of the TFS project which contains the build.
  • /definition: is the name of the build definition for the build you want.
  • /build: is the actual name of the build you want to get. If this is omitted then the tool will simply get the most recent successful build for the definition supplied.
  • /out: is the directory where the contents of the build should be copied.
Setting up test controllers and agents across multiple domains
16 April 10 01:03 PM | grozen | with no comments

I have recently had the pleasure of setting up another set of test agents and a controller. Even though the proper release version is upon us, the client I did this for is still using Beta 2. One can wonder if the issue I came across has been fixed since Beta 2 (I hardly have the environment to try and reproduce this) but just in case it hasn’t, I hope this post saves someone both time and aggravation.

The setup in this case was as follows: Two machines were involved, let us call them A and C. Machine A was part of the Abacus domain while machine C was part of the Cactus domain. The controller was to be installed on machine C and the agent on machine A (how fitting). The tricky part was that machine A can’t access C without specifying a proper DNS suffix, so that if we were to access machine C from machine A, we would have to specify C.Cac.tus (where Cac.tus is the DNS suffix).

Setting up the controller went pretty smoothly. Setting up the agent, however, was a whole different matter. Trying to configure the the agent post installation by supplying C.Cac.tus as the controller (or even C’s IP) resulted in the following message:

Failed to register this test agent with the test controller. Possible reasons could be you do not have the right permissions to connect to the test controller C.Cac.tus, or a firewall is blocking the connection.
To fix this problem, verify that you are a local administrator on the test controller machine, and that the Windows Firewall Settings on the test controller machine has "File and Printer Sharing" exception.

Unfortunately, none of the possible reasons for failure were in fact possible. There were no firewall issues and I could connect from A to C in just about any conceivable way. I decided to try connecting to the controller from within Visual Studio on computer A in hopes of getting a more useful error message. What I got, however, was:

Pixelated for your pleasure

Which was not useful at all, as it was more akin to a blatant lie. The odd thing was that it again claimed machine C could not be found even when I supplied it as C.Cac.tus or the direct IP.

On a whim, I added Cac.tus to the list of DNS suffixes on machine A’s network connection and that solved the problem. I could now simply tell the agent its controller was C and it would connect without a hitch.

Update: Though this wasn’t an issue before, recently the environment described above moved from Beta 2 to the RTM version of 2010 and setting up everything again, there was now a necessity to add the DNS suffix in the other direction as well (That is, you needed the Abacus domain’s suffix on machine C).

Improving the way Coded-UI tests search for grid cells in MSAA controls
30 March 10 08:16 PM | grozen | with no comments

If you’ve stumbled upon this post, most chances are you are here for the right reasons, seeing how this is all about a very specific problem.

I have recently been working for a client on various Coded-UI related issues. The client’s application is a WinForms one and is riddled with many a grid. While working on the application I have run across a very peculiar issue which I will first present and then continue to solve.

Let us observe the following Winforms application:
I couldn't afford a designer

This is a very simple application which contains a data grid. Were you to recorded a Coded-UI test and click the various cells within the grid, the resulting test code would look something like this:

// Click 'one' cell
Mouse.Click(uIOneCell, new Point(59, 9));
// Click 'one' cell
Mouse.Click(uIOneCell1, new Point(40, 13));
// Click 'moo' cell
Mouse.Click(uIMooCell, new Point(66, 13));
// Click 'goo' cell
Mouse.Click(uIGooCell, new Point(37, 10));
// Click 'two' cell
Mouse.Click(uITwoCell, new Point(71, 11));

The first two actions above were created after clicking both cells which contain the value “one”. Let us dig a bit deeper and see just how exactly the test code locates said cells.

The top left cell’s search criteria:

this.mUIOneCell.SearchProperties[WinCell.PropertyNames.Value] = "one";
this.mUIOneCell.WindowTitles.Add("Form1");

The top middle cell’s search criteria:

this.mUIOneCell1.SearchProperties[WinCell.PropertyNames.Value] = "one";
this.mUIOneCell1.SearchProperties[WinCell.PropertyNames.Instance] = "2";
this.mUIOneCell1.WindowTitles.Add("Form1");

I’ve taken the liberty of highlighting the difference between the two sets of criteria and as you can see, the difference is that the second cell is forcefully denoted as the second instance which meets the other search criteria. The blame for this sub-par additional criterion is the fact that cells are sought using their contents (WinCell.PropertyNames.Value), which is generally a very ponderous idea, seeing how the contents may change over time and/or between runs of the application, thus making certain test scenarios very tricky to record.

A much more sensible idea would be to look for cells by using their row/column combination, which is obviously unique and which does not depend on the application’s data as much as the contents of the cell. Coincidentally, the cell’s name (unlike its value) is composed of the row/column combination and is therefore unique.

Following the instructions in this post I was able to convince the coded UI recorder to use the cell’s name in order to seek it out.

After creating the following extension and recording the same test, the search properties turned more reasonable:

The new top left cell’s search criteria:

this.mUIOneCell.SearchProperties[WinCell.PropertyNames.Name] = "Grilled Row 0";
this.mUIOneCell.WindowTitles.Add("Form1");

The new top middle cell’s search criteria:

this.mUIOneCell1.SearchProperties[WinCell.PropertyNames.Name] = "Cheese Row 0";
this.mUIOneCell1.WindowTitles.Add("Form1");
What to do when the Coded UI Builder uses MSAA instead of UIA
16 February 10 12:16 AM | grozen | with no comments

I was sitting with my esteemed colleague Shai Raiten the other day facing a very obscure problem. We were given an application which refused to cooperate during Coded-UI test recordings and were told to “make it work”.

The application was pretty run-of-the-mill WPF, without any sort of insane custom controls which typically cause issues during recording. What appeared most strange was the fact that examining the various elements of the application through the Coded-UI test builder (you know, using the Ba-ton button) revealed that the technology selected to handle them was the older MSAA.

MSAA stands for Microsoft Active Accessibility, and is essentially a COM interface which allows controls (which serve as accessibility providers) to be manipulated by external applications (which act as accessibility clients). This technology has been around for a while, since 1997 in fact, and was recently succeeded by the much newer UIA, or User Interface Automation, which supports a much richer object model (and a less archaic feel).

All common WPF controls have UIA support built in and needless to say this odd fallback to MSAA left us with very little data coming back from the various controls. Seeing how most UI elements didn’t even have a name property with content it was no wonder that the Coded UI Builder couldn’t produce any working test code.

The ever so trusty Reflector was most useful in cracking the case. The idea was to get inside the UIA extension (sitting in the Microsoft.VisualStudio.TestTools.UITest.Extension.Uia.dll assembly) and see just how the technology manager implemented there decides that a window is supported by the UIA extension (if you’re asking yourself what a technology manager is, do not be alarmed. Instead, read this excellent series of posts).

After digging around, it all boils down to matching the window’s class name with the following regular expression:

^HwndWrapper\[.*;;.*\]

In case you do not speak regular expression, this means that windows are supported if their window class name looks like:

HwndWrapper[bla bla bla;;la di da]

The two semicolons are red to emphasize the fact that there should be absolutely nothing between them. Funny thing was that the problematic application had window class names that looked like this: HwndWrapper[bla bla bla;Evil Text;la di da]. Searching for “Evil Text” in the problematic application’s code yielded the following line:

Thread.CurrentThread.Name = “Evil Text”;

Right inside the application’s OnStartup method. Removing that line fixed everything right up.

The moral of the story? If you intend to perform Coded-UI tests on your WPF application, don’t give the WPF thread a name. Of course, since we brought this to Microsoft’s attention I imagine it will eventually be resolved, or at the very least a reason for this odd limitation will be supplied.

WPF designer crashes when working on a VSPackage in Visual Studio 2010 Beta 2
13 February 10 09:37 PM | grozen | with no comments

While working on an add-in for visual studio for several days over the last few weeks, I’ve had the joy of coming to terms with the various peculiarities of add-in projects.

The add-in I was making was a fairly simple one which has a tool window that allows the user to deploy the contents of TFS build drop folders into a predefined location. What I found almost maddening was the fact that after working on the tool window itself for several minutes the WPF designer would always crash:

I am bereft of life

After digging around for quite a bit I managed to find this issue on Microsoft Connect, and gladly it has been fixed and will not be present in VS2010 RTM. Of course, this doesn’t necessarily help you if you are working on a VSPackage right now.

I seem to have misplaced the link, but the resolution for this matter is quite simple: Create your tool window user control in a standalone project. The downside is that you will not be able to use any functionality from the various add-in related assemblies in the tool window’s code (since once you reference them, this issue will pop-up again).

Yet another generic type converter
06 February 10 06:02 PM | grozen | 2 comment(s)

A while back, 6 or so months ago, I found myself in need of a generic type converter. This was due to a design decision in one of the projects I am working on, a project which relies heavily on WCF.

While I was not privy to the entire set of considerations behind the decision, as I only joined the project while it was well on its way, the end result was that all our WCF contracts were not put in a shared assembly to be referenced by the various consumers, but instead each entity which wanted to make use of the contract would add the required contract files as a link.

The positive effect of this decision is that each entity could easily expand the contract as needed using the magic of partial classes. For me, however, this was more a serious pain than anything else. As one of the main testers for the project, I would often find myself referencing multiple entities in my test code and even, heaven forbid, using the output of one entity as input for another.

To illustrate the issue, let us say I have two entities: CoffeeShop and Restaurant. Each entity resides in its own assembly and supports, as part of its contract IFoodProvider, the following methods:

  • MakeOrder, which returns an Order object
  • ServeOrder, which takes an Order object as an argument.

Now let us say I would try and do something like this:

CoffeeShop starBucks = new CoffeeShop();
Restaurant mcShnitzles = new Restaurant();

Order pastry = starBucks.MakeOrder();
mcShnitzles.ServeOrder(pastry);

Assuming McShnitzels have all their pastries made by StarBucks, of course.

This would not compile, naturally, since the Order type which Restaurant uses is defined in the Restaurant assembly, while the Order type which the CoffeeShop provides is defined in the CoffeeShop assembly (not to mention that you would be forced to use extern alias to get both assemblies to play nice in the first place). This was amazingly frustrating as both types were in fact nearly, or in most cases completely, identical.

When I went out to solve this I ran across this post, which seemed to fit the bill perfectly, except that I needed something a little more robust. The code I eventually devised is not nearly as impressive as what appears to be going on over at the AutoMapper project, though on the plus side I do believe it is smaller, simpler and quite useful all the same.

The attached code contains a class called SimilarTypeConverter which has a single Convert method. This method basically takes an instance of type A and turns it into an instance of type B, by creating a new type B and populating all its public fields and properties with the values from A. This means that whatever isn’t a public field/property in the source does not end up inside the resulting value.

Here are a few useful facts about the conversion process:

  • Fields/Properties which are present in the source but not in the destination will simply be ignored. Properties which do not have a setter in the destination are also ignored (if the setter is merely private it will still be used).
  • The mapping between converted fields/properties is name based, so if type A has a “Manliness” property, it will be mapped to type B’s “Manliness” property, assuming it has one. Properties will only get mapped to properties and fields to fields, so if A has a “Flavor” property and B has a “Flavor” field, the value from A.Flavor won’t be present in the resulting B.Flavor.
  • Conversion is only possible to types which have a default constructor, which is what my code uses to instantiate the destination value.
  • If, for some reason, you are converting something to its own type (as in, taking an A and converting it into an A), you will get back a reference to the object you supplied, instead of a new yet similar instance. This is the way I needed the class implemented, but look for the word “Kill” inside the code to find the condition you must remove to change this behavior (though this is what copy constructors or the ICloneable interface are for, really).
  • The conversion is recursive, so let us say you have the similar types A and B and the similar types C and D, then taking one of these:

    public class A
    {
           C inner;
    }

    And converting it to one of these:

    public class B
    {
           D inner;
    }

    Would work just as you expect it, and the resulting B.inner will contain all the values of A.inner.

  • The conversion correctly handles:
    • Arrays
    • Anything which implements IDictionary<T,S>
    • Anything which implements ICollection<T>
    • Nullables
    • All manners of value types, naturally
    • Anything composed of the above
  • The conversion does not choke on circular references, and handles them just fine (this is a bonus feature I wrote this weekend, hurray!).

I hope I didn’t neglect any important details. You’ll notice that I’ve only attached the converter itself, and not an ounce of testing code. This is due to the fact that even though I wrote this code, I was forced to print it out and OCR it back in (don’t ask), and that was bad enough with the code itself. I performed quite a bit of manual testing this time around, and it appears that the code has survived the OCRing without harm.

Le code

תגים:,
Work Item form rendering differences between VS2010 and MTLM
13 January 10 07:32 PM | grozen | with no comments

Last week I performed some run-of-the-mill work item customization for a client which opted to adapt TFS2010. Since it wasn’t something overly fancy it was all wrapped up pretty quickly (especially using the power tools). To my dismay, after reviewing my work with the client I was informed that some fields which were meant to be read-only were in fact editable and that the work item form had some layout issues.

This was rather odd, considering I believed I tested everything quite thoroughly. The crux of the matter was that I did all my work using Visual Studio, while the client reviewed my work using the Test and Lab Manager. Turns out that the two tools render work item forms differently (though I doubt this is intentional).

So, let me present the two differences I am aware of. This will be accomplished by modifying the out-of-the-box “Bug” work item. Normally, a bug’s form looks like this (assuming we use the Agile process template):

Normal bug

What we’ll do is add an additional field and set its control as read-only and another field which is a rich-edit field.

The field elements (as added to the work item definition):
<FIELD name="ReadOnly" refname="RenderIssue.ReadOnly" type="String"/>

<FIELD name="RichField" refname="RenderIssue.RichField" type="HTML"/>

And their respective controls:
<Control FieldName="RenderIssue.ReadOnly" Type="FieldControl" Label="&amp;Readonly:" LabelPosition="Left" ReadOnly="True" />

<Control FieldName="RenderIssue.RichField" Type="HtmlFieldControl" Label="Master Plan:" LabelPosition="Top" />

What we get using Visual Studio is:

I feel so different

But what we get using MTLM is:

I feel even more different

How do we get around these little quirks? For the read-only control, the only way I found to get consistent behavior is to make the backing field (in this case, RenderIssue.Readonly) read-only, though this isn’t always what you want. For the downsized rich-edit control, the best solution is simply to specify a minimum size for it (using the MinimumSize attribute as seen here).

More Posts Next page »