Sunday, June 16, 2013

Fixing Internet Explorer 10: upgrade to Internet Explorer 9

This doesn't have anything to do with C# or Visual Studio today, other than to show how you can make utter crap with a decent language and an overcomplicated IDE.

Microsoft, as usual, has decided that it knows what broken piece of crap browser is better than what I'm using and keeps shoving the piece of crap Internet Explorer 10 down my throat. Well, during a backup and restore procedure, I accidentally missed telling Windows not to load that piece of crap IE10 on my computer. So I ended up with that piece of crap IE10 on my computer.

Well, it's a simple fix to remove it, right? Oh, hell no. Microsoft not only screwed up IE10, but they screwed up restoring IE9 also. After uninstalling IE10 program - oh wait, it's not a program that can be uninstalled, it's a part of the frigging operating system! OK, after uninstalling the piece of crap IE10 Windows component, just reinstall IE9.

But wait, there's more! When you try to reinstall IE9, Windows happily stops the installation and tells you it's already installed. Asshats.

OK. Now I get to go to the Microsoft Support site and find out how to get around the bug to get around the bug when removing the piece of crap IE10. Fortunately, Microsoft has several troubleshooting alternatives at http://support.microsoft.com/kb/2579295 for when the first solution decoy, Mr. Fixit Wizard, fails. The second one, running a command line, actually seemed to do the job Mr. Fixit failed to do. The Mr. Fixit Wizard is probably a union employee, and was smoking crack and drinking beer behind the curtain when he was supposed to be doing his job. Of course, I had to fix the command to remove the piece of crap IE10 rather than IE9. Here's what I ran:


FORFILES /P %WINDIR%\servicing\Packages /M Microsoft-Windows-InternetExplorer-*10.*.mum /c "cmd /c echo Uninstalling package @fname && start /w pkgmgr /up:@fname /norestart"

Windows still had some complaints and opened copious other command windows. But after that, at least, I was able to complete the IE9 installer.

But wait, there's more! After removing the piece of crap IE10, rebooting, and installing IE9, and rebooting, Windows decides that there are some files in use and fails to finish installing IE9. Run the installer again, reboot. Now is Windows happy?

Hallelujah, it is! Amazing how Microsoft can turn such a simple little procedure into an annoying mess. Better that mess than the mess that is the piece of crap IE10.

Oh, by the way, I don't like the piece of crap IE10.

Friday, September 28, 2012

WCF handles streamed content type badly

While trying to help a colleague with a perplexing deserialization problem with derived types, which the KnownTypes attribute wouldn't fix.

Take One: we tried to pass JSON data into our REST service through a Stream parameter. We were thinking that we could simply read the raw object data and perform our own deserialization. But, no, we began to get a "500 Internal Server Error" with the exception:

Incoming message for operation 'test' (contract 'RuleService' with namespace 'http://tempuri.org/') contains an unrecognized http body format value 'Json'. The expected body format value is 'Raw'. This can be because a WebContentTypeMapper has not been configured on the binding. See the documentation of WebContentTypeMapper for more details.

With .NET, it seems nothing is ever as easy as advertised.

The data was getting to our service, but it was throwing an exception before dispatching the request to our service method, so the Visual Studio debugger was useless to run down the problem.

Take Two: We created a test method to accept a Stream and return it as a string. This failed, too. WCF, WTF!

Turns out WCF is really that stupid. A Stream is supposed to accept any data regardless of format. It doesn't. WCF still tries to interpret the content according to the Content-Type header, instead of ignoring it as it should. The client must tell the service the data is unformatted before it will work without throwing an exception. So a client that isn't completely well-behaved and strictly compliant with the web service interface will blow up your program. I guess it's a security feature.

Here's the raw deal on raw data: if your method accepts a Stream, the client must set the request's Content-Type header to application/octet-stream or text/plain or some other type that indicates unformatted content. If you only switch your input parameter from a class to a Stream, a message that could have worked before will immediately fail. Using WebContentTypeMapper requires substituting your own mapper for the entire service, not just for a single operation. Apparently there is no simple workaround.

Take Three: luckily for us, the client is our own program. We can make it compliant. If it were a third-party application, we would be SOL.

The End: After we changed the client to set the message header to Content-Type: application/octet-stream, the service starting receiving data again and our program went on happily deserializing the object that WCF's stock deserializer wouldn't.

Tuesday, February 21, 2012

Random notes about getting IBM WebSphere MQ 7.1 installed and working

I had an enormous amount of trouble while starting to develop an application that had to interface to another application using IBM WebShere MQ 7.1 message queues. Installation is not simply using the setup program's defaults. These notes are vague because this procedure was painfully time-consuming and I didn't have time to hunt down the facts about what actually got it working.

1. Installation Part I. This gets the files onto the workstation. This took me a couple days because IBM's documentation is pretty obscure about what installation set is needed, server or client, or where it puts files. A lot changed between versions 7.0 and 7.1 that was undocumented. In addition to being vague, the documentation is also inaccurate, as the documented defaults are not the real defaults. In short, to develop and test on a single machine, the Server set (which includes the Client files) was required, not just the Client set. And you had to manually select the Client files from a custom installation because - contrary to the instructions - the Client files were not selected by default.

2. Installation Part II. Once the files are physically installed, a second part of the installation runs to "prepare" the message queues. Under Windows 7 at least, this portion terminates with a "there's something wrong" error. Real helpful. Fixing this had to deal with security. In addition to the domain user required to execute services, another two separate domain users had to be created. One user is apparently to create queue managers and another to manage queues. They are identical accounts except they have different names; complete waste of resources. And you may have to start the installed services manually. As an Administrator. A Domain Administrator. WTF!

3. More security problems. Attempting to create a remote queue runs afoul of more security issues. A minimum of four layers of Authorizations have to be set up (by a local Administrator this time?) before a queue can be created. Some permissions are for creating the queue manager and some are for creating the queue.

4. Sample programs. The sample programs provided as part of the installation cannot be built using the supplied bldcssamp2.bat batch file. Firstly, because the batch file must be run from the command line, the PATH environment variable must be updated to include the compiler directory; in my case, for compiling against the .NET Framework 4.0, it was setting:
PATH=%PATH%;C:\Windows\Microsoft.NET\Framework\v4.0.30319.

Secondly, the path to the libraries must be edited. One every compile statement. Original:
/lib:..\..\..\..\Bin
Correct:
/lib:..\..\..\..\Lib.

On Windows 7 (and Windows Vista, from reading other comments) the compiled executables won't run. When you launch an executable, the program crashes and the following error shows up in the Windows Application Event Log:


Activation context generation failed for "C:\Program Files (x86)\IBM\WebSphere MQ\tools\dotnet\samples\cs\base\nmqsput.exe".Error in manifest or policy file "C:\Program Files (x86)\IBM\WebSphere MQ\tools\dotnet\samples\cs\base\nmqsput.exe.Config" on line 8. The element assemblyBinding appears as a child of element configuration which is not supported by this version of Windows.


This has something to do with Windows 7 not liking the "side-by-side" Win32 manifest files that the compiler generates by default. To get around this error, the batch file had to be edited yet again. Add to every compile statement:

/nowin32manifest

So, parameterizing it a bit, in the interest of helping other IBM customers, here's the complete sample build script:


PATH=%PATH%;C:\Windows\Microsoft.NET\Framework\v4.0.30319
SET LIBPATH=..\..\..\..\Lib
SET MFTOPT=/nowin32manifest
echo building nmqsget.exe
echo.
csc /t:exe /r:System.dll /r:amqmdnet.dll /lib:%LIBPATH% /out:nmqsget.exe %MFTOPT% nmqsget.cs
echo.

echo building nmqsput.exe
echo.
csc /t:exe /r:System.dll /r:amqmdnet.dll /lib:%LIBPATH% /out:nmqsput.exe %MFTOPT% nmqsput.cs
echo.

echo building nmqswrld.exe
echo.
csc /t:exe /r:System.dll /r:amqmdnet.dll /lib:%LIBPATH% /out:nmqswrld.exe %MFTOPT% nmqswrld.cs
echo.

echo building MQPubSubSample.exe
echo.
csc /t:exe /r:System.dll /r:amqmdnet.dll /lib:%LIBPATH% /out:MQPubSubSample.exe %MFTOPT% MQPubSubSample.cs
echo.

echo building MQMessagePropertiesSample.exe
echo.
csc /t:exe /r:System.dll /r:amqmdnet.dll /lib:%LIBPATH% /out:MQMessagePropertiesSample.exe %MFTOPT% MQMessagePropertiesSample.cs
echo.


And another thing... The documentation makes no mention about how to compile against the .NET libraries. Oh, there's a sample solution for Visual Studio, but it makes web service calls instead of using the MQ library. Wonderful, another irrelevant example. Without scanning my hard drive and digging through the command-line samples, it would have been nearly impossible to find where they buried the correct DLL that had to be referenced: C:\Program Files (x86)\IBM\WebSphere MQ\tools\Lib\amqmdnet.dll.

Fortunately, there is this outdated but still useful RedBook reference document: WebSphere MQ Solutions in a Microsoft .NET Environment. It has some helpful information about developing MQ applications in .NET and Visual Studio .NET. The conceptual information in it is still relevant for current development.

Monday, June 27, 2011

Running Device Emulator in XP Mode

If the frustration of VS2008 corrupting some of the VS2005 SDKs isn't enough to burn your butt, it's just a warm-up exercise to getting the Device Emulator working in Windows 7's XP Mode.

The first month of isolating VS2008 and VS2005 by installing one of them into XP Mode Virtual PC (VPC) was certainly disappointing. VS2008 didn't want to cooperate at all. So I did the next best thing: installed VS2005 there instead. It was a long and boring process to get VS2005, its service packs and a bunch of SDKs installed, but it worked without much pain. It even compiled some code. But launching a device emulator was a different story.

On connecting to the Mobile 5 Pocket PC Emulator device, which I use regularly for testing, the computer just stared blankly at me for a few minutes before declaring:


Cannot connect to device. Error: 0x8007064a


Try a web search for that. Mwa-hah-ha!

Anyway, the short story and the two-part solution. I finally found some obscure and easily overlooked references from people who had similar experiences.


Part One. Visual Studio won't open the project.


  1. Open the solution. Visual Studio complains: "The project file cannot be loaded. The application for project ... is not installed.". Shutting down VS and restarting does nothing.

  2. Right-click the project (which offers no information about why it fails. Other than some stupid message about "platform not available" or something moronically insulting like that. It's all BS - the SDKs are installed.

  3. Select Reload project.

  4. Watch with anger and puzzlement as VS loads the project correctly this time. Shoot me.



Part Two. The device emulator fails when running in XP Mode. I followed Brian Peek's useful guide to replacing the missing Microsoft network adapter, Windows Virtual PC and the Microsoft Device Emulator, which may have helped solved other future problems. For the emulator error, the article Cannot connect to device. Error: 0x8007064a was helpful.


  1. Launch the emulator by trying to connect or by executing in with or without debugging. VS complains: "Cannot connect to device. Error: 0x8007064a".

  2. Terminate the Device Emulator Manager.

  3. Rename the Folder "CoreCon" (in "Documents and Settings\Application Data\Microsoft\") to "xCoreCon".

  4. Start the Device Emulator (list of devices is now empty).

  5. Terminate the Device Emulator.

  6. Rename "xCoreCon" back to "CoreCon".

  7. Now the emulator works. Shoot me and the computer.



Is Microsoft running the US Congress? Maybe that's the problem. Well, at least Solitaire still works.

Thursday, May 26, 2011

Visual Studio 2005 & 2008 side-by-side incompatibility

The short story:
VS2005 and VS2008 will not co-exist peacefully.

The long story:
After several fruitless days trying to create an environment for developing an application for the Windows CE 5.0 platform using Visual Studio 2008, I had to admit defeat. The reason is, when Visual Studio 2008 is installed on a system that has Visual Studio 2005 already, it clobbers the Windows CE 5.0 platform so it cannot be used by either IDE. No complaints, no warnings, just gone.

Microsoft contends that VS2005 and VS2008 can be installed and will work side-by-side. What they did not document - typical for MS - is that certain platforms not only are incompatible between the two, but are also disabled for both. The Standard Windows CE 5.0 SDK is one of those platforms that is disabled when VS2008 is installed. I haven't had time to find out what additional platforms may be affected.

It's not an operating system issue. I develop on a Windows 7 machine. My co-worker uses Windows XP. Both of us experienced identical problems.

My objective was to install VS2008 to work on a project I had inherited where a back-end database application had already been written as a VS2008 project. I wanted to create a Windows CE 5.0 application using the same IDE. Silly me, always expecting "new and improved" tools to work as advertised.

VS2005 with the Standard Windows CE 5.0 SDK was already installed and working fine, as I had just completed another project with that exact combination. Install VS2008. See Windows CE 5.0 platform disappear. Did installing with Administrator Privileges work better? Nope. Uninstall, reinstall, uninstall, reinstall without Documentation = No joy. Jump up and down on keyboard, smash fist through monitor, throw laptop through front window - *sigh* just wishful thinking.

Last resort, uninstall VS2008. Gee, that worked; now I had my Windows CE 5.0 platform back in VS2005. So I couldn't use VS2008 for my new project. In summary, VS2005 and VS2008 can co-exist, but only if they are on separate machines. :-/ I was burned by Microsoft marketing hype yet again.

And they want me to upgrade to VS2010. Hahahahahahaha!

Tuesday, April 19, 2011

Using Crystal Reports Basic for VS2008 with VS2005

I had a client for whom I developed a project in Visual Studio 2005. The reports were written for the bundled version 10.2 of Crystal Reports (CR). The application was to be installed on the client's server that already had a number of applications that were using the later Crystal Reports version 10.5 (bundled as Crystal Reports Basic for Visual Studio 2008), a newer version.

Anecdotal evidence showed it was possible to use a version of CR other than what was bundled with VS2005. Unfortunately, no hard documentation existed that defined or instructed one on how to do so. These notes are what I pieced together after a week of intense research and trial & error.

The first thing that must be done is to create and test reports with CR v10.2 that is bundled with VS2005. Easy, right? Of course I'm being sarcastic.

The next step is to install the CR v10.5 runtime package. These can be acquired from several places, the official one being the Crystal Reports page on the SAP Community Network web site. Another source is Visual Studio 2008 Pro, if you have it handy. The x86 package, though, is hidden deep in the bowels of the installation: C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bootstrapper\Packages\CrystalReports10_5\CRRedist2008_x86.msi. Install it on your machine; I've encountered no problems with it co-existing with CR v10.2.

Depending on your architecture, you need one of these setup packages:
   CRRedist2008_ia64.msi (64 bit Itanium)
   CRRedist2008_x64.msi (64 bit Intel)
   CRRedist2008_x86.msi (BootStrapper)

In your project, make a list of all references to the CR assemblies and remove them. Here comes the fun part. You can't simply add references to the new assemblies. From a command prompt, go to your %windir%\assembly directory. You will find GAC, GAC_32, and GAC_MSIL directories there. Inside those are subdirectories for each version of the Crystal Reports assemblies on your machine. Copy the 10.5.* version of the DLLs to a folder you create within your project: I called mine CRRedist2008.

In your project, add references by browsing to your CRRedist2008 folder and selecting the same assemblies as were in your original list. Why the copying? Visual Studio does not allow adding references to assemblies in the General Assembly Cache. You need separate files so VS lets you add them as references to your project.

One more step: if you check the reference properties, you may still see the v10.2 assembly being referenced. Set the Use Specific Version property to True to force VS to use the v10.5 assembly you added as a reference.

Recompile and your reports should now run with the VS2008 version of the Crystal Reports libraries.

Barrel of fun, huh?

Thursday, March 10, 2011

Updating the MDI parent menu icon for maximized child form

While working on a C# .NET program recently, I ran up against an infamous (and another apparently long-standing) bug in Microsoft's Multiple Document Interface (MDI) architecture. When a child form has been maximized, and its window icon is updated, the icon that is merged into the MDI parent's menu strip is not updated to reflect the change.

I was using the child window icon to identify the document type being displayed and to mark when it had been modified. Everything worked fine when the window was open in Normal mode, but the icon stopped being updated when the child was maximized to fill its parent's client area.

After literally days of searching the web to see if anybody else solved the problem, I found answers ranging from "impossible" to "keep track of your own windows" (a.k.a. the old roll-your-own interface standby). Digging through the layers of classes with the debugger, I figured out a hack that seems to work.

Here's the basis of my solution: when a child window is maximized, the controls on its title bar are merged with its parent window. The parent menu inserts an image as its first element that is a copy of the child window's icon. The image (a Bitmap image) is copied only at the time the child is maximized, and is never updated afterward, regardless of calling Refresh(), Update(), Invalidate(), etc. So, to get around this missing functionality, my solution was to check the parent menu when I changed the icon of the child window; if it had an image in its first element, I converted the Icon into a Bitmap and replaced the image. It may sound hokey, but it worked.

These are the steps I used for updating the icon. I raised an event to update the parent form.


// Change the child icon according to the document state.
// Called from a method in the child form.
int newState = this.GetChildState();
this.Icon = (newState == 0) ?
myProject.Properties.Resources.savedicon :
myProject.Properties.Resources.modifiedicon;

// ...raise event to notify the parent. sender is the child form.

// Change the parent menu icon when child is maximized.
// Called from an event handler in the parent form.
if (MainMenuStrip.Items[0].Image != null)
{
// Copy the new state icon from the child window.
MainMenuStrip.Items[0].Image = ((Form)sender).Icon.ToBitmap();
}


The MDI architecture has its quirks. This is just a way to get around one of them. I think this is an inelegant solution to an inelegant problem, but sometimes you just have to be practical.

Saturday, February 12, 2011

RichTextBox.SelectedRtf property has incomplete documentation

The Microsoft documentation for this property is missing critical information (there's a shock, huh?). It explains use of the property in terms of text. It's not text that is being used here, it is a completely formatted document. That document is extracted from or integrated into the complete document stored within the RichTextBox control.

If used to insert text, the assigned string must be a correctly-formatted RTF document (even a minimal document will work) or it will throw a System.ArgumentException error, with the unhelpful inner message of "File format is not valid", especially maddening when not working with files.

To illustrate an incorrect and correct use of this property, in the example code snippets below, myRtfControl is an instance of the RtfTextBox control.

Example that fails:

myRtfControl.Select(myRtfControl.TextLength, 0); // Set caret to append

text.myRtfControl.SelectedRtf = "\ul underlined text\ul0";

// ^ Throws System.ArgumentException


Example that works:

myRtfControl.Select(myRtfControl.TextLength, 0); // Set caret to append

text.myRtfControl.SelectedRtf = "{\rtf1\ul underlined text\ul0}";

// ^ Adds underlined text as expected.


Note that for an empty selection, SelectedRtf actually contains the following document:

{\rtf1\ansi\ansicpg1252\deff0\deflang1033\uc1 }


The text consists of a single Unicode space character "\uc1 ". It's this "empty" document that assignment will replace.

Gathering this information came at the expense of several days of wasted time poring through tangential examples on the web (and some peeled wall paint from cursing bad documentation). Thanks to those intrepid pioneers.

For further reference, a link to the Rich Text Format Specification, version 1.6 can be found at http://msdn.microsoft.com/en-us/library/aa140277%28office.10%29.aspx.

Happy document bug hunting!

Thursday, January 20, 2011

MobileLPR - LPR client for.NET Compact Framework 2.0

I recently wrote a client library for Windows CE/Mobile devices, giving them the ability to print to a network printer. The library and article, MobileLPR - LPR client for.NET Compact Framework 2.0 - CodeProject, are usable under The Code Project Open License (CPOL).

The library allows printing to network print servers implementing the LPR, LPRng, and SocketAPI (direct socket connection) printing protocols. LPR and SocketAPI are venerable and widely-used on all major platforms. Since most contemporary printers offer built-in network printing using one of these protocols, this library is a great addition to your mobile developer's tool belt.

I've been going to the Code Project web site for years. It is a nice place to learn and contribute!

Monday, November 15, 2010

Differences between enum in C# and C/C++


Recently I encountered a confusing situation that took me by surprise while porting some old, well-proven C++ code to C#: the languages treat enumerated types differently. In C and C++, an enum defines a value type that represents a restricted set of values. An enum type can be declared just about anywhere before it is used, including statement blocks.

In C#,  an enum defines a class (i.e. types are classes), meaning it can be declared only at the namespace or class level; it cannot be defined in a statement block within a method as it can in C++. If you try, Visual Studio issues an error not about the enum definition itself, but instead at the opening brace of the method, stating '} expected' rather than something useful like 'enum cannot be defined at statement level' or even 'invalid statement'. Another unintuitive error message brought to you courtesy of Microsoft.

So if you're a C++ programmer learning C#, beware this trap. It's easily fixed by moving (and naming or renaming) your enumeration to a less narrowly scoped portion of your module, but it's annoying and unwelcome, nonetheless.

Monday, September 20, 2010

Mobile Device Emulator Error on Windows 7: No VPC network adapters enumerated

After upgrading from Windows Vista (pronounced fiasco) to Windows 7 (OMG, there is life after XP!) and reloading everything because there was no migration path (probably for the best anyway), the Windows Mobile device emulator I was using could not be configured with a network connection.

Several articles were well-written and helped me to understand that it could have been something other than missing the Virtual Machine Network Services driver that was the source of the error (which was not my problem). Brian Peek's Windows Virtual PC and the Microsoft Device Emulator article was a excellent piece that led me to try other debugging perspectives. Ben Armstrong's (Virtual PC Guy's Blog) Fixing broken virtual networking was concise and gave me other clues about dealing with the virtual network driver. Many thanks to them for sharing their experiences.

I tried both solutions and neither fixed the problem. What finally worked was getting to the emulator's connection settings through Visual Studio, since the options I needed were disabled within the emulator itself. Go to Tools > Options > Device Tools > Devices, pick a preferred emulator, click the Properties... button, then the Emulator Options button there. On the Network tab, I added a check to the Enable NE2000 PCMCIA network adapter and bind to: checkbox. The critical step was selecting the actual connected network card - not the Connected Network Card option - in the network adapters dropdown box.

Next time I started the emulator, it saw the network adapter and was able to use it. Without selecting the actual network card, the emulator must try to use a hidden, disconnected network adapter (I have both Ethernet and WiFi network adapters in my notebook, both with virtual network services enabled) and fails to see the connected one, hence the notorious error:


No VPC network adapters enumerated or no host network adapter with provided MAC address found


I tried some other solutions, such as replacing the virtual machine network services driver with the one from Virtual PC 2007. It didn't work either, so I uninstalled and reinstalled the VMNS driver that came with Windows 7's Virtual PC. I also cleared the emulator's saved state several times during my ordeal.

Obviously this workaround to the bug in the VM's network device driver has the drawback that you have to reconfigure your network connection if you change network adapters. But at least it got me working again.

For reference, the development platform I got this working on is Windows 7 32-bit Tablet PC with 2 GB RAM, 100GB hard drive, 1.7 GHz CPU and Windows XP Mode with Vista/7 Service Pack. I use Visual Studio 2005 SP2 with the Window Mobile 5 Pocket PC emulator from the Microsoft Windows Mobile 5 SDK. I do a lot of industrial handheld computer development.

Thursday, June 10, 2010

Error: ShowDialog exits immediately

I was trying to implement a WinForm login class called from a menu navigation class, but when I called ShowDialog(), it was exiting immediately without displaying the window or setting the DialogResult code. It was working the first time through the loop, but subsequent calls always failed. I searched all over the 'net for answers without success; in the end, I had to trace through my program a few lines at a time in the debugger until I found the culprit.

Watching the behavior of the preparation call to Login.ShowDialog() resulted in everything appearing normal the first time. Later, the Owner property would not allow assignment - no error, but the value stayed null - and calling ShowDialog() would return immediately with the default value of DialogResult.None. My Load event was even being called as expected. To me, this appeared to be working incorrectly. It turned out to be not incorrect, but undefined behavior I was seeing.

As the stereotypical engineer, I nearly outsmarted myself by designing a library of classes that would handle the details of performing their appropriate menu operations and allow me to define the menus declaratively. One of the classes was responsible for calling a named method and instantiating its type object through reflection if needed. To allow a ShowDialog() method call, the .NET Framework requires the object to be manually disposed afterward. I got fancy and added code to call Dispose() on the object automatically if it was a Form. But...some of my called methods were part of my active menu navigation class, which was itself a Form. When the menu operation was executed, my navigation class got destroyed, so I was clobbering myself.

The resolution was to be careful to not dispose of the class I was actively using. Assigning a disposed Form as the owner of another Form is undefined, pointless, and creates bizarre results, as I so painfully found. Fixing this issue solved the inconsistent behavior. I'm deservedly embarrassed by my mistake, but wiser for it.

If this saves somebody else the inconvenience I experienced to track down this problem, then it will have been worth my time to share this story. Leave me a comment if this helped you in any way.

Friday, January 15, 2010

Installing NUnit with Visual Studio 2005 on Windows Vista

This article isn't about how to use or configure NUnit, it is simply about getting it installed. The short version is listed at the end of this article.

Running Visual Studio 2005 on a Windows Vista platform, the documentation on the NUnit project web site was a bit anemic and left me perplexed. I posted my notes and experience here to help the next programmer who falls into the same trap of using inadequate documentation and having no previous experience with the product.

Getting started with the NUnit testing framework was rather like touching an electrified fence: the shock certainly woke me up. Now, don't think I don't like the package and the effort that went into it. I certainly want to thank the authors for putting together a very useful software framework that improves the quality of my code. On the other hand, it would be nicer if it were easier to get working or at least had some accurate installation instructions somewhere. To the best of my ability, here are those instructions.

The download page was pretty clear about what package you should use. Since I wanted to install on Windows and wasn't going to be developing NUnit itself, I picked the Windows binary Installer package. At the time this article was written, NUnit 2.5.3 was the current production release, so I downloaded the "win" installation archive, NUnit-2.5.3.9345.msi, and ran it on my development machine. I picked the Typical installation and got what I thought I needed. Seemed simple enough.

Following the text on the Installation page, I got to the Configuration section (about half a page) before the fog started setting in. The document mentions the configuration files are different depending on the NUnit executable you run. Personally I think this belongs in a different section of the document, but I could go back and look at it again later, so I just overlooked it for now.

The Installation Verification really threw me for a loop. It states:
Verify that the installation has worked successfully by running the NUnit gui and loading and running NUnitTests.nunit. All tests should pass.


Warning! Misleading Documentation Alert! OK, it's elementary that I can run the GUI NUnit by going to Start->NUnit 2.5.3->NUnit. Now I just needed to find NUnitTests.nunit. No dice. After searching fruitlessly through every folder the installer created, I deduced that somebody simply forgot to include the file in the installer archive. Oh well, mistakes happen. I went back to the web site and downloaded the previous version. Uninstalled 2.5.3 and installed 2.5.2. *#&*@^! Same problem. The file didn't exist in either of the latest packages, so I thought. Grrr!

After a brief email exchange with the project administrator, Charlie Poole, it turns out that performing the Typical install, the file is not available. Only if you install the Unit Tests for NUnit under .NET 1.1 does the noted file get installed. This is confusing and a revision of the documentation or installer is under consideration. I have to say this was very responsive and indicative of the quality of the package as I saw so far.

Well, I just skipped the verification and tried one of the samples. Curiously, there were no *.nunit files to be found anywhere. Maybe they were just for the GUI? I hadn't found it in the documentation so I moved on to compile a sample.

I use C# most of the time, so I used one of those samples. The samples\csharp directory contained several different tests organized under what appears to be a Visual Studio Solution so I opened CSharp.sln. OK, VS had to convert it to my version, so I let it and it didn't complain. Built the solution and got an error in MoneyTest.cs:

The type or namespace name 'Framework' does not exist in the namespace 'NUnit' (are you missing an assembly reference?)




I checked the references; no, it was there. But there was a warning label on the icon. Looking at its properties, the reference had no path and no version!

Now was Visual Studio giving me problems? I clicked on the project icon, added the reference again - at least I was able to pick it off the .NET reference list. It was named nunit.framework, not NUnit.Framework, so that didn't look right. But, no change, the reference still showed the warning label. @$#@#&%#@!

I removed the existing reference and added the reference again. Now it sorta looked right that the warning label was gone. Build, and the projects were compiled. I launched the NUnit GUI application. Selected Open Project... and browsed to the csharp/money directory. Nothing. Really? No, nothing. Drilled down into bin/Debug and find a couple .dll files, but still no *.nunit files. Tried loading the cs-money.dll assembly directly and I saw the tree of tests. That was promising. So I clicked the Run button and a green progress bar filled the status area.



Success!? Yes, no, maybe? Yes, I'll call it success.

My suspicion was the .dll assembly contained all the information an NUnit project file would have, but I didn't locate the documentation to prove it. Trial and error is a heck of a poor way to find out. Moral: bad documentation doesn't make for good testing. Your mileage may vary :-/.

Here's the short version of all this:
  1. Download the NUnit installer package.

  2. Run the installer.

  3. Skip the Installation Verification step because the files weren't installed.

  4. To create and use NUnit tests with a new project, add a reference to the nunit.framework.dll library to the project.

  5. To use NUnit with the sample projects, remove the existing nunit.framework.dll library references first. Add a reference to the newly installed library to the projects.

  6. Don't bother looking for *.nunit files. Or do a full install.



It's difficult to be grateful when you're annoyed. But at least I was running and demonstrated the framework will actually do what it's told, once I figured that out.

The End

Friday, January 8, 2010

Revised WorkerThread class and Bug in EventWaitHandle.WaitOne() in .Net CF 2.0

The WaitOne(int millisecondsTimeout, bool exitContext) method of the ManualResetEvent (based on EventWaitHandle) class allows waiting for a synchronization flag to be set, but timing out if it does not. On the .Net Compact Framework (.NetCF) 2.0, calling this method with exitContext set to true throws an ArgumentException exception. The fix is to always set exitContext to false.

How I got into this was researching .Net worker threads. There was a very good article written by Juval Löwy, titled Working with .NET Threads, and provided a useful wrapper class, named WorkerThread, to make managing threads easier in your application. Thank you, Juval!

I use .NetCF frequently and, as usual, found some incompatibilities I had to correct before the WorkerThread class worked on that platform. The revised and better-documented WorkerThread for .NetCF 2.0 is listed below. Even after rewriting for the methods missing in the compact framework, I ran across a bug in .NetCF 2.0 that prevents the class from working properly.

The wrapper class relies on several synchronization constructs in order to provide safe access to its functionality across threads. One such case is where an extra integrity check attempts to determine that the thread is actually running, in the code that implements the IsAlive property. As originally coded, it was:


public bool IsAlive
{
get
{
Debug.Assert(m_ThreadObj != null);
bool isAlive = m_ThreadObj.IsAlive;
bool handleSignaled = m_ThreadHandle.WaitOne(0,true);
Debug.Assert(handleSignaled == ! isAlive);
return isAlive;
}
}


The problem appears in the call to WaitOne(0,true). While it compiles fine, at runtime it throws an ArgumentException error instead of ignoring or saving & restoring the synchronization context (a completely different concept than the thread synchronization I'm writing about here). Simple to fix, but maddening to diagnose.

The other minor issues I fixed were:

  • No IsAlive property on the .NetCF Thread class. Reference was commented out. I added a new instance variable, m_IsAlive, to emulate the missing property.

  • No Join(TimeSpan timeout) method on the .NetCF Thread class. Translated that method to use Join(int millisecondsTimeout) instead.

  • Fixed IsAlive property code to avoid the ArgumentException error, as mentioned above.

  • Added a Yield() method to relinquish the processor to other threads as an alternative to using the more cryptic Thread.Sleep(1).

  • Added an overridable Work() method to allow this class to be inherited instead of copied and modified. Replace Work() in your derived class to implement your processing.

  • Modified the Run() method to call Work() and automatically manage the IsAlive property.



As a way to pass on the bits of knowledge I've gained from this exercise, here is the final source for the .NetCF 2.0 WorkerThread class:


////////////////////////////////////////////////////////////////////////////////
// File.......: WorkerThread.cs
// Author.....: Edward F Eaglehouse
// Date.......: 11/21/2009
// Notes......:
// Adapted for .NetCF 2.0 from the WorkerThread class by Juval Lowy in his
// article, Working with .NET Threads. The full article text can be found at
// http://www.devx.com/codemag/Article/17442/0/page/1.
////////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace gltech.trackaway
{
///
/// Class that implements a separate worker thread.
///

///
/// Based closely on the WorkerThread wrapper class described in the
/// article Working with .NET Threads,
/// by Juval Löwy. Modified so it works with the .NET Compact Framework.
///

public class WorkerThread : IDisposable
{

#region Protected Members

///
/// Synchronization construct for signalling completion of the thread.
///

protected ManualResetEvent m_ThreadHandle;

///
/// Contains a reference to the uninheritable underlying Thread object.
///

protected Thread m_ThreadObj;

///
/// Flag to indicate that thread processing should be stopped.
///

protected bool m_EndLoop;

///
/// Synchronization construct to protect the EndLoop flag.
///

protected Mutex m_EndLoopMutex;

///
/// Flag to indicate the thread is actively running.
///

protected bool m_IsAlive;

#endregion

#region Constructors

///
/// Initialize a new instance of the WorkerThread class.
///

public WorkerThread()
{
m_EndLoop = false;
m_ThreadObj = null;
m_EndLoopMutex = new Mutex();
m_ThreadHandle = new ManualResetEvent(false);

ThreadStart threadStart = new ThreadStart(Run);
m_ThreadObj = new Thread(threadStart);
m_ThreadObj.Name = "Worker Thread";
m_IsAlive = false;
}

///
/// Initialize a new instance of the WorkerThread class.
///

/// True to launch the thread immediately; otherwise, false.
public WorkerThread(bool autoStart)
: this()
{
if (autoStart)
{
Start();
}
}

#endregion

#region Properties

///
/// Get the underlying Thread object.
///

public Thread Thread
{
get
{
return m_ThreadObj;
}
}

///
/// Get the thread completion synchronization object.
///

public WaitHandle Handle
{
get
{
return m_ThreadHandle;
}
}

///
/// Get the indicator that the thread is active.
///

public bool IsAlive
{
get
{
Debug.Assert(m_ThreadObj != null);
//bool isAlive = m_Thread.IsAlive;
bool isAlive = this.m_IsAlive;
//bool handleSignaled = m_ThreadHandle.WaitOne(0, true);
bool handleSignaled = m_ThreadHandle.WaitOne(0, false);
Debug.Assert(handleSignaled == !isAlive);
return isAlive;
}
}

///
/// Get or set the indicator that processing should stop.
///

protected bool EndLoop
{
set
{
m_EndLoopMutex.WaitOne();
m_EndLoop = value;
m_EndLoopMutex.ReleaseMutex();
}
get
{
bool result = false;
m_EndLoopMutex.WaitOne();
result = m_EndLoop;
m_EndLoopMutex.ReleaseMutex();
return result;
}
}

///
/// Get or set the debuggable thread name.
///

public string Name
{
get
{
return m_ThreadObj.Name;
}
set
{
m_ThreadObj.Name = value;
}
}

#endregion

#region Public Methods

///
/// Launch the thread.
///

public void Start()
{
Debug.Assert(m_ThreadObj != null);
//Debug.Assert(m_ThreadObj.IsAlive == false);
m_ThreadObj.Start();
} // Start()

///
/// Overridable method that implements the processing to be done.
///

public virtual void Work()
{
int i = 0;
while (EndLoop == false)
{
Debug.WriteLine("Thread is alive, Counter is " + i);
i++;
}
} // Work()

///
/// Destroy this WorkerThread instance.
///

public void Dispose()
{
Kill();
} // Dispose()

///
/// Notify the processing loop to stop.
///

public void Kill()
{
//Kill is called on client thread - must use cached object
Debug.Assert(m_ThreadObj != null);
if (IsAlive == false)
{
return;
}
EndLoop = true;
//Wait for thread to die
Join();
m_EndLoopMutex.Close();
m_ThreadHandle.Close();
} // Kill()

///
/// Blocks the calling thread until this thread terminates.
///

public void Join()
{
Debug.Assert(m_ThreadObj != null);
if (IsAlive == false)
{
return;
}
Debug.Assert(Thread.CurrentThread.GetHashCode() !=
m_ThreadObj.GetHashCode());
m_ThreadObj.Join();
} // Join()

///
/// Blocks the calling thread until this thread terminates or the
/// specified time elapses.
///

/// Number of milliseconds to wait.
///
public bool Join(int millisecondsTimeout)
{
TimeSpan timeout;
timeout = TimeSpan.FromMilliseconds(millisecondsTimeout);
return Join(timeout);
} // Join(int millisecondsTimeout)

///
/// Blocks the calling thread until this thread terminates or the
/// specified time elapses.
///

/// TimeSpan set to the amount of time to wait.
///
public bool Join(TimeSpan timeout)
{
int timeout_ms = (int)timeout.TotalMilliseconds;

Debug.Assert(m_ThreadObj != null);
if (IsAlive == false)
{
return true;
}
Debug.Assert(Thread.CurrentThread.GetHashCode() !=
m_ThreadObj.GetHashCode());
return m_ThreadObj.Join(timeout_ms);
} // Join(TimeSpan timeout)

///
/// Suspend this thread to allow other waiting threads to execute.
///

public void Yield()
{
// Yield processor to other threads, even ones at a lower priority.
Thread.Sleep(1);
} // Yield()

#endregion

#region Protected Methods

///
/// Do the processing defined by this thread.
///

protected void Run()
{
try
{
m_IsAlive = true;
Work();
}
finally
{
m_IsAlive = false;
m_ThreadHandle.Set();
}
} // Run()

#endregion

}
}

Wednesday, September 23, 2009

XML Default Namespaces and XPath Queries

The use of namespaces in XML schemas are useful and even necessary, but they cause a lot of confusion! This is compounded (confounded?) by the XPath API having different rules for applying namespaces than the rules applied to documents.

The biggest confusion for me came from the use of the default namespace. Use of a default namespace simplifies writing an XML document because it limits or eliminates the need to prefix element and attribute names. However, it places a bigger burden on the reader because the use of any namespace mandates the additional requirement of using a namespace manager in the API calls when executing queries. Any namespace that may be used in the document must be added to the namespace manager's map, including the default namespace. Be aware that the default namespace is not the same as no namespace, which is a vitally important principle of XPath queries.

Additionally, the query itself must include a namespace prefix for any and every element to be parsed. Regardless if the XML document qualifies the element to identify the namespace or not, the XPath query must qualify the elements. An unqualified element in the query will search the "no namespace" or "null" namespace, not the default namespace; XPath has no concept of a default namespace. This short blurb is found in the Microsoft documentation: XPath treats the empty prefix as the null namespace. So if your schema specifies a target namespace, an unqualified query element will never match anything in it.

What's the solution? Here are two.

1. Remove all namespaces from your XML document. For simple documents you don't plan on validating, this may be an acceptable alternative. But it's probably not a good idea for complex documents or documents where the construction will be validated; in these cases, the use of namespaces is almost mandated.

Sample XML document with no namespaces:

<?xml version="1.0" encoding="utf-8"?>
<parent>
  <child id="1">
    <item>Item 1</item>
    <item>Item 2</item>
  </child>
</parent>


Sample reader code:

use System.Xml;

XmlDocument doc = new XmlDocument();
doc.Load("/hasnodefault.xml");

// Query some elements. This is what you would naturally expect.
// Namespace prefixes cannot be used in these queries.
XmlNode root = doc.SelectSingleNode("/parent");
foreach (XmlNode node in root.SelectNodes("child/item"))
{
  // Do something with the child items.
  ;
}


2. Use a namespace manager when you are parsing your documents. If you use a default namespace, you must map it to some prefix (something other than an empty string); I will often use "default", which makes it obvious where I'm looking. Your XPath queries, unfortunately, will necessarily be more complicated, as you will have to include the namespace prefix on all elements you will be querying.

Sample XML document using a default namespace (xmlns=...):

<?xml version="1.0" encoding="utf-8"?>
<parent xmlns="http://tempuri.org/sample.xsd">
  <child id="1">
    <item>Item 1</item>
    <item>Item 2</item>
  </child>
</parent>


Sample reader code:

use System.Xml;

XmlDocument doc = new XmlDocument();
doc.Load("/hasdefault.xml");
XmlNamespaceManager nsmanager = new XmlNamespaceManager(doc.NameTable);

// Map the default namespace. Not optional.
// Note that the namespace URI is significant, not the prefix.
nsmanager.AddNamespace("default", "http://tempuri.org/sample.xsd");

// Query some elements.
// The namespace prefixes are required or the query will return null.
XmlNode root = doc.SelectSingleNode("/default:parent", nsmanager);
foreach (XmlNode node in root.SelectNodes("default:child/default:item", nsmanager))
{
  // Do something with the child items.
  ;
}


The short version of this story is: if you use namespaces in your document, even if it is a default namespace, you must qualify the elements used in your XPath queries and use a namespace manager with them.

Obviously, things can get more complicated than these simple examples. Understanding these fundamental concepts about namespaces is critical to maintaining your sanity.

For .NET users new to XML, the XPath queries (a W3C standard for addressing parts of XML documents) are implemented by the .NET framework's XmlNode.SelectNodes() and XmlNode.SelectSingleNode() methods and their related counterparts built on XPathNavigator and XPathExpression classes.

More information about XPath 1.0 is available at http://www.w3.org/TR/xpath.

Tuesday, September 15, 2009

Convincing Visual Studio 2005 that SqlClient is a valid namespace

While getting a project started to connect and use an SQL Server database from a mobile device, I ran into the same problem apparently many others have, too. You had to force Visual Studio to include some framework components so you were allowed to use them. I happened to be using Visual Studio 2005 (aka Visual Studio 8.0) to build an application for a .NET Compact Framework 2.0 platform that exchanged data with a Microsoft SQL Server 2005 database over a wireless network.

To execute a query directly against the remote database without using the SQL Compact (aka SQL Mobile aka SQL CE) SDK and without using dataset objects, required SqlConnection, SqlCommand, SqlParameter, and several other classes that existed in the System.Data.SqlClient namespace. Unfortunately you couldn't just type your using statements and have VS magically link them to your application. You expected Microsoft to make it automatic? No way. That's where the Add Reference... feature is needed and was a source of confusion (days!) in my early development with the VS .NET IDE.

Without adding a proper reference, the statement:

using System.Data.SqlClient;

caused the following compilation error and would not complete the build:

The type or namespace name 'SqlClient' does not exist in the namespace 'System.Data' (are you missing an assembly reference?)

Part of the problem is the multiplicity of .NETCF versions. As is standard with Microsoft, things get moved, renamed, and otherwise mangled between versions. In .NET CF 2.0, SqlClient is part of the System.Data namespace and the System.Data.dll library file; in later versions, there is a separate System.Data.SqlClient.dll. To allow this necessary namespace to be used in your project, you must add a reference to the System.Data.SqlClient component. The trick is learning a couple things about a listed component on the .NET tab: the "Runtime" column identifies the framework version it belongs to, not the "Version" column, that is for the version of the component itself. Also the "Path" column refers to the component as used by the IDE, not by the target device. The path does not even exist on the target device. There were a few clues, but putting them together to arrive at a coherent solution took experience or lots of trials & errors.

At the time I wrote this, the SqlClient namespace for .NET CF 2.0 was added by referencing the component named System.Data.SqlClient, version 3.0.3600.0, runtime version v.0.50727, whose (IDE) path was C:\Program Files\Microsoft Visual Studio 8\SmartDevices\SDK\\SQL Server\Client\v2.0\System.Data.SqlClient.dll. And before you point out my "typo", yes, that was the real path.

Adding this component as a reference finally allowed me to compile without VS coughing up the error.

Tuesday, August 4, 2009

Visual Studio Resource Designer

Visual Studio 2008 was designed to make your life easier.
Now that you're done laughing, it is actually a very nice environment, if you don't mind wasting hours working around a few big bugs and mind-twisting procedures for simple objectives. It takes me back to the good ole days of programming, where the words to live by were, "Save early, save often."
VS2008 is a great reminder that no non-trivial piece of software is perfectly bug-free. Although it tries to be helpful by automatically coordinating your editing to ripple the changes through to the other classes, files, and tool panels in your project, it is very irritating to add a static modifier to a method only to have the entire IDE crash seconds later. I have learned when modifying existing classes, a quick tap of the CTRL-S key to save the edit before VS applies the change in a dozen other places saves me about 10 minutes per crash. I only have 2 GB of memory and a dual-core processor, so obviously my development system is a little slow :-(.
Oh well, next problem. Following some of the Microsoft's tutorials is an exercise in abnormal psychology. How many different write-ups that explain the same procedure can you apply until you realize they are all leading you down a blind alley. That was how I felt when I realized today that there is only one correct way to add an embedded resource to a project that will actually be available at runtime.
I kept seeing the same incorrect instructions over and over: from the Resources folder in the Solution Explorer, select Add > New Item... from the folder's context menu. Great, my bitmap file just got included as an embedded resource, right? Wrong.
The right way: In your project's Properties folder there is a resource object named Resources.resx. Double-click this object to open the Resource Designer; alternatively, you can also double-click the Properties folder and select the Resources tab. At the top of the pane is a toolbar with an Add Resource dropdown. Select Add and choose or create your new resource. Now it gets included as an embedded resource, right? Sorry, wrong again.
Once your new item has been included as a resource in your project, you have to visit the object in the Resources folder. Select the item. In the Properties list, change Build Action to Embedded Resource. OK, now is it an embedded resource? Wait, don't forget to hit Save. Yes, it is at long last, after executing multiple steps, an embedded resource.
So, how much time did you save today? :-/