Sunday, June 28, 2009

Things I hate about my Mac

It's not quite a year since I moved to Mac. My reasoning was simple. A Mac IS a PC, so I'm not choosing either/or, I am saying, I will buy a PC, will I also choose to have a Mac at the same time ? My Mac has 20 gig of RAM and 8 cores. It's a pretty sweet box. I generally love using the Mac, too, there just seems to be little things where the OS seems to work with you, instead of against you.

The whole point of my blog is to point out things that I've found to not work as I'd expect, in all aspects of my computing life, especially where I know the solution, and hopefully I can feature in the search results of people trying to solve the same problems I have solved. What I'm basically writing about today, is VMWare Fusion and Boot Camp. VMWare Fusion is a piece of software that lets me install virtual machines on my Mac, and to basically run OSX and have windows running in a window. This is how I've used my Mac for most of it's life, which means I can use Safari, Pages, XCode, etc. as needed, but still go over to Windows when I need to write some Windows code, open a newer format Office file, etc. This has not been without issue, VMWare loses it's internet connection frequently, and while I've been given step by step instructions for what to type into the console to reset it, I am new enough to Mac that I am still working my way up to power userhood, I don't fully follow what it is that I'm doing, so I needed to keep looking it up. The support also takes the form of a public forum and it took me a while to work out that the people who were incredibly rude to me ( I assume for being a Windows user ), were actually not employees of VMWare. This made me feel better, because I know some people who work at VMWare, and I've found them to be really great folks, in real life. I must say, the guy who told me how to get around the internet dropout issue, also did not work for VMWare.

The main reason I use VMWare and not Parallels, is that the question I asked when buying was "who has the best 3D support ?". As my apps are all WPF, I need good DirectX support. VMWare also works with Boot Camp drives, so I had tried to set up a boot camp partition in the past, but had failed in my efforts to do so, so I had kept using an old PC for final testing, 3D was definitely sluggish under VMWare.

As I was going to the US in May, I took my Mac in to the Mac store, and told them I'd buy a hard drive from them, if they set up Boot Camp for me with Windows XP. I made clear that I am well capable of doing such things, given the time to work it out, but my one attempt at Boot Camp had not worked out, and I plain do not have the time to dedicate a day to making this thing work. While I was away, I emailed to check progress, they told me the XP CD I had given them was broken. I assured them this was not the case, and gave them some suggestions ( they claimed the CD was not booting ).

I got back, and picked up my Mac. When I tried to start it, it would tell me that there was no bootable media. As you can imagine, this upset me. Now, all my source code is backed up off site, but it's invariably the case, even with a Time Machine, that some data is lost when a HDD dies. To cut a long story short, my Mac was returned to me in a state where it kept trying to boot from my Windows CD, and would not boot from anything else. Once I worked this out, I found that the machine would indeed claim that my boot CD was corrupt.

I managed to convince the Mac to boot back to OSX ( I confess I don't recall how, this took place over 2 days and was a whole lot of stress ). So, I reformatted my new hard drive, and tried to install again. Same error. I verified the CD again. Fast forward a few hours of me doing this, and variations on the theme, and we get to my first point. I had asked the Mac store to create three partitions, I hoped to create a multi boot hard drive that booted XP ( for my day to day life ), Vista ( for testing only ) and Windows 7. It turns out that you can only install an OS for Boot Camp, on a drive that has only one partition. Once I formatted with one partition, the whole process worked effortlessly, with the CD I had given the Mac store. I called them and explained all this, for the benefit of the next person to walk through their doors and ask for some help.

So, I next tried to repartition my drive after windows was installed. This utterly broke my machine again, and I had to reinstall Windows again. For a time, my Windows would boot, but I could not recover the space I had moved to other partitions. At the same time, Acronis True Image could no longer back up my drives, as it could not recognise them. I wrote to their tech support, and they responded to say 'We understand you cannot back up from your drives. If this is true, let us know and we will mark this issue as closed'. I sent an angry reply, and by the time they followed up two weeks later, I had moved to Ghost, which is a great piece of software, and which worked when True Image would not. So, my second point is, buy Ghost, not True Image.

Apparently, the Boot Camp instructions tell you to never use repartitioning software, this was the point at which I realised that what I asked the Apple people to do for me, and they agreed, was in fact utterly impossible. Of course, I've heard these people tell prospective clients that Macs never have viruses, so I should have known better than to think they were experts.

I tend to update my Mac once every few months, I don't really keep track of when things come out, I just update as I think of it. So, I recently ran the update, and got told that there was an OSX update. I installed this, and then found that VMWare no longer worked, I would start a WPF app and immediately be told that the 3D was broken. It turns out that ATI video cards combined with the new OSX update, doesn't work with VMWAre. VMWare say that they knew this was the case in advance ( but chose not to email their clients to tell us ), and that they blame ATI and Apple ( despite Parallels apparently working fine with this update ). I've followed up on this on the VMWare forums, as far as I can tell, no VMWare employee has responded to me, but some guy who likes to insult me has basically blamed ATI and said that I should never install any update without doing a full system backup first. This is probably good advice. I just didn't see it coming that VMWare was so fragile, or that they wouldn't bother to tell their clients that their system is about to break.

So, my days of running Windows and Mac at once are over for now. I also found that running a Boot Camp partition in VMWare is not wise, it seemed to mess it up a bit, in fact, at one stage, my XP was so confused, that it would just reboot over and over, it took three hours of going between safe mode and normal to get my PC back. I would love to set up a shared drive to put data on, that is visible to boot camp and VMWare, once this ATI issue is resolved. I am assuming when it is fixed, they won't bother to email their clients to tell them. I suspect that the end result will be that I'll fall out of love with VMWare, get used to using boot camp, and just not use VMWare again. Which is a shame, it was very cool when it worked.

Tuesday, June 23, 2009

Changing tables in SQL Server 2008/good UI design

I was using SQL Server 2008 client tools to make some database changes today ( you'll recall, if I install SS 2005, it reports success, but does not install client tools ). I usually prefer to create tables in script, so I can easily execute the script again when I deploy, but this was a simple one, and I figured I'd just use the table designer. I created my table, saved it, and realised I missed a column, so I went ahead and modified the table. Set up my column, hit save, and got the following dialog:

So, an empty table, and the program feels I need to be told that I can't change it, because it would require dropping the table. I don't see that this is even true, can't I add a column using SQL, so long as I provide a default value ( or the table is empty ), and there's no need for the DB to drop the table and recreate it ?

Assuming for a moment that I did have data in the table, and this action WOULD cause me to lose data, why not ASK me before proceeding, instead of locking me out ? And, if I need to change a preference, why not provide a way to open the preferences in the right section ? I NEVER tell a user in my software that they need to set a preference to do what they requested, without opening the preferences on the right page, to show them where it is.

I guess this tells me what I knew all along. Never use the tools, always hand write code, it's the only thing that you can trust.

ASP.NET custom validators do not fire

An ASP.NET custom validator allows you to perform ( not surprisingly ) custom validation on user input. In theory, you can specify both a client and a server side function to call.

I have three checkboxes, they are not generated by a checkboxlist, because I want more control over their layout, AND I want to attach some js events on specific options. So, I created a custom validator like this:

<asp:customvalidator runat="server" id="selectOne" controltovalidate="address1" clientvalidationfunction="IsOneSelected" onservervalidate="CheckSelection" errormessage="*" text="*" display="Static">

Note that address1 is not one of my checkboxes, the custom validator will not allow me to validate a checkbox. I've tried removing this property, because some blogs I've read, suggest this. Then I write a validator method like this:

function IsOneSelected(source, args)
alert("got here");

var valid = false;

var demo = document.getElementById(demoCD);
if (demo)
var Trial = document.getElementById(trial);
if (Trial)
var Webinar = document.getElementById(webinar);
if (Webinar)
if (Webinar.checked) valid = true;
if (Trial.checked) valid = true;
if (demo.checked) valid = true;
args.isValid = valid;

The alert is obviously a temporary measure. Apparently, the js editor has support for enforced bracing standards, and it defaults to K&R braces, so I kept getting this:

function MyFunc(){


I hate that, but I can't be bothered finding it to turn it off ( as you can probably tell, I don't write js that often ). What worried me more was that my script block changed itself from language="javascript" to language="jscript". But, I digress.

It turns out that the client side event only fires if the control you are validating has been changed. So, in theory if I hook up the control to a textbox that needs to be filled, that textboxes validator will help out if it's not, otherwise, this one will fire and I'll get my validation on the client side, right ? Well, I get my alert, but even if I hard code the validator to ALWAYS fail, the postback always occurs, my validator never stops a postback.

Now for the fun bit. MS apparently respond to complaint about this by pointing out that validation should always occur on the server, so even if the client side fire fails, there should always be a server side that fires. I agree with this, although in our case, there's nothing malicious anyone could do by circumventing the validators, it's still good practice not to trust anything that has been on the client side. Here's the issue. No matter what I do, I can *never* get my server side validator to fire. It simply does not work.

Now, I have run the examples that are on MSDN, and they obviously work. There is something else going on here, some reason why it won't work in my page. I guess I could trawl through the script, and see what that reason is ( actually, this gives me a good excuse to install firebug ), but I don't have time, I will just add an OnClientClick to my submit button and do my validation there. If anyone knows either what I did wrong ( possible, obviously ), or what circumstances cause a custom validator to do nothing, even when it fires, please let me know.

Update - Wow. My OnClientClick does not fire, either. Only the server side click event will fire, looks like that is my only option for validation.

Further Update - Although I did initially try to make the validator part of my validation group, I suspect my use of validation groups is part of the problem. However, that does not explain why my OnClientClick event would not fire.

WPF crashes on XP when using MediaElement

The MediaElement has been the bane of my life for some time now. In our first release, we actually used the Windows Media Player in a dll, because we had issues with performance. I did ask about this many times on MSDN forums and never got a real answer. A lot of other people were asking, too, so let me answer that question: even when you're playing a video in a form that has no real 3D, you're still creating a video on a DirectX surface, because that's how WPF works. So, it's not surprising really when a MediaElement is not as smooth as Windows Media Player, which just throws frames at the screen. The resolution of a DVD is around 800 x 600, (although HD is bigger, so is your LCD TV bigger than the average monitor), if your video is much bigger, remember that doubling the width of your video ( so if you go 1600 x 1200 ), gives you four times as many pixels that need to be scaled and drawn. It took me a while to work this out, but once I got our videos rendered in a sensible resolution, they play just fine in the media element ( I did a project where playing one video was unreliable, because of high resolution, I didn't generate the videos, and when I checked the resolution, it all made sense ).

I use a Mac ( I need to post about Boot Camp, actually ). As a result, I probably rebuild my Windows more often than most, as it's easy to build a new VM without even touching the old one. As a result, I have more experience than most with the fact that if you install Windows XP, SP2, and then install .NET 3.5 and run a WPF app that has a media element in it, one of several things will happen:

1 - The app will blow up on start, with a message that the XAML is invalid
2 - If you try to show still images on the MediaElement, it just won't do anything at all.

It seems to me that if I install a framework, it should work from there. It also seems to me like if I need to install a specific extra component, that I could get a meaningful error message to tell me what is going on. The first time this happened to me, I spent a half day trying to work out why my code was broken. I don't believe that winforms ever had this sort of issue. I presume there's a reason why WPF requires WMP10, but if that's true, why can't it try to tell me ? I can see how Microsoft has had legal trouble for bundling stuff in the past, but I am either going to install WMP10, or I am going to not use the application I just bought ( assuming now I am an end user ). How does making it confusing, help anyone ? What if the install for WMP10 fails somehow ( remembering my post the other day on installers ) ? This is just going to cause work and headache for support staff, and general frustration for end users.

Of course, it works fine out of the box in Vista. The only downside is, then you're using Vista.

Saturday, June 20, 2009

Visual Studio has encountered a breakpoint....

OK, this one is new to me. I had selected a solution from the MRU, to open, and I got this error:

Clicking debug, indeed goes into the debugger, after telling me it's loading a ton of symbols, it tells me ( not surprisingly ) that it has no symbols for the code from within the IDE that has crashed. Has anyone seen this before ? I thought I'd seen it all, but this is news to me.

Editing XAML crashes the editor

Today I am playing with some personal stuff, just looking to improve my WPF skills. I found out this week that if you restyle a slider, you need to remember to put in the XAML for the areas you click outside the slider, to change your selection. However, I have a file with a styled slider, and because of the effect I want ( I have buttons in the background and I want to be able to click them ), I want to remove those areas from this particular style. EVERY time I open my XAML and delete the one that is below the slider, VS 2008 uses 13% of my processor ( always 13% ) and it locks up until I kill it. I am going to have to edit my XAML in notepad and then reopen the project.

And, that worked fine. The editor couldn't handle me removing some XAML ( as in, I select it, and remove it, the XML is valid before, and after the operation ) and it locks the editor every time. Remove the XAML in notepad, and reopen the project, it opens fine. So, my XAML was legible to the IDE before the operation, and also afterwards. I am assuming that some sort of control tree is maintained from the XAML to generate the preview, and that this somehow doesn't like having to deal with this ( invisible ) element being removed.

I believe Blend is less hostile to the idea of people hand editing XAML than it used to be ( the first versions I saw didn't even support searching in text, which was by design, because you were not supposed to use it if you wanted to edit code ). I am falling in love with Expression Design's ability to open an Adobe Illustrator file and let me export XAML. It often fails, but what it does is impressive enough that I am happy to fiddle with it to make it work. I still worry that the theory that Blend is what you use to create XAML, may be a reason that the tools in VS 2008 are still so poor, tho.

Update: This is the first project where I've used resources, I don't know if this is a factor, but I am finding more and more simple edits which kill the IDE and which therefore need to be done in notepad. How is this possible ? Surely the thing would be, if the control tree can't take the edit, just rebuild it. I am changing my resources file, so the IDE is not even rendering any sort of preview at the time.

Friday, June 19, 2009

ASP.NET traps for young players

No other area of programming seems to have as many inexperienced, beginner 'programmers' taking on contract tasks that they have no idea how to perform, than ASP.NET. I guess everyone wants a cheap website. There's a few ways that the framework does not help.

When you create a default page, it will have a page load event in it. As a result, a lot of people write all their code in the page load event, and never add a page prerender event. Because of the order of the page lifecycle ( that is, page load, then events fire, then page prerender ), the prerender is often the only event you really need to handle, and it's the one that any data bound page should handle. This leads to several issues.

First is the "I push a button and it doesn't work, I push it again and it does" scenario. This means they bound to a data source, then the event changed the data source, so, on refresh, the changed source is loaded and bound to, but the first time, the data was loaded before it was changed. Then there's the 'my control loses it's selected value' problem ( which should ideally be fixed with a !IsPostback block, but would also be fixed in terms of reading the value in code behind by reading the value first, then data binding ).

The next thing I don't understand is, if I write a site in VS, and use the built in web server, it will allow me to write code behind like this:

if (!someTest())
MessageBox.Show("The test failed, please open a file");
OpenFileDialog ofd = new OpenFileDialog();

This apparently WORKS in Visual Studio. So, every day, when people in a certain continent clock in for work, programming forums worldwide get the 'This works on my local machine, but when I deploy it, it gives me this error on the server, what does it mean ?' question. Now, it's true that this is a problem with the so-called programmer, and it's true that the error message explains the issue in plain English, but, as far as I can see, the MVP program exists to give people incentive to provide Microsoft tech support by answering these sort of questions, so I assume that having these people write code is part of Microsoft's business model. I am guessing they skim the cream of the programmers in these low wage countries for their own benefit, I don't know. Either way, why would you create an IDE that allows you to write code that is plainly not going to run on deployment, under any circumstances ?

And don't get me started on how AJAX fits into this mix. Most people using the ASP.NET AJAX library, both think it IS AJAX, and think that Microsoft invented AJAX. They certainly have no idea what AJAX is, or what it means, I see questions every day that say 'I want to use AJAX to do xxx', where xxx has nothing to do with AJAX, although it may involve javascript. It's become the new XML, if you write a website, you need to use AJAX, where-ever you can. As the AJAX library does include some controls that don't really need AJAX to exist, the line is blurred even further. The ASP.NET AJAX library is also horribly inefficient, when I worked on a website in ASP.NET that used AJAX, I rolled my own code, because our site had far too much traffic to pay the price of the library. I am glad, because it means I was able to learn how to hand code AJAX, and I believe anyone who uses a library, should have some idea of what it does, so they know what performance cost is associated with their actions.

Of course, in .NET, it's not deemed important to even make the decision between a vector or a list, so I guess performance doesn't matter nowadays.....

Wednesday, June 17, 2009

.NET 3.5 won't install with an ATI video card

I did my support call this morning, and solved the issue. Just so we're clear, I am not saying this is Microsoft's fault. However, I do think that their installer could give some more intelligent feedback to the lay person.

Basically, by reading the logs, I found that a file called CLI.exe was stopping .NET from being updated. This is a driver utility program for ATI video cards. So, if you have an ATI video card, and the .NET 3.5 installers don't work, and give you a meaningless error 1603 ( which is a generic error, and tells you nothing, which means if you google it, you'll get given all sorts of totally different solutions ), then I'd suggest stopping the video card utility and trying again. But, that just means I've added one more to the pile of wildly different solutions to the 1603 error code, because I know from googling, lots of people have solved the problem in totally different ways.

Your best bet is therefore to look at the error logs in the temp directory ( although they are quite verbose and therefore hard to read and close to useless ), or to read through the Warning and Information messages in the Event Viewer (Control Panel/Administrative Tools/Event Viewer), the errors in there are useless, things have broken by then. It's the Application list you want to select, that's where the action is.

SQL Server 2008 is installed, and it's able to connect to my SQL Server 2005 database, although it could not restore my old databases, I am guessing I need to install SS 2005 SP1 to maintain compatibility. I'll get around to that, I was able to script my website database, run the SQL, and get up and going again to do the development work I need to. I do wish that the SS 2005 would install it's client tools, or tell me why it is refusing to ( instead of claiming that it has ), but at least I had 2008 as an option, even if it means my dev machine is no longer a remotely valid test machine for my products.

Tuesday, June 16, 2009

Installers that don't

I am the final line of support for our product, and I've been informed of a machine that will not install .NET 3.5. It gives an error message, which I googled and found every possible suggestion from logging in as a local admin, to sacrificing a goat. It appears that the error message is meaningless, and I need to read the log files to find out what is wrong. Which means, I need to log in to a client machine and dig around, trying to work out why they can't install .NET.

Why is it so hard to give a meaningful error message ? We also are not distributing .NET 3.5 SP1, because it is 300 MB and can take hours to install, because it installs every possible windows update along the way. This bit me, because I wrote an app which shows video thumbnails in WPF, which I stress tested for hours. I had installed .NET 3.5 SP1 and wound back to 3.5, so I can test on the same environment our users will have. Well, when I deployed, that screen would crash within a few minutes, I guess some sort of memory bug in Windows Media Player that was fixed by a patch that was not uninstalled when I removed SP1. I fix this for .NET 3.5 by using the memory stomping code I've needed for every WPF app I've ever written that uses resources, the subject of a future blog entry.

I am currently trying to install SQL Server 2005. I can't install 2008, it installs .NET 3.5 SP1., which I can't run for the reasons stated. So, the installer runs fine, but at the end, the client tools are not installed. They are just not there. Now when I try to run the installer, it warns me that I should use a command line switch if I am upgrading versions. Why make it that hard ( why not, press 'here' to install an upgrade, for example ), and what version ? All I am trying to do, is make the installer install what I asked it to, and what it falsely claimed to have done. I've found several fixes on the web, so this is happening to other people, too. But, none of them have worked.

How hard is it to write installers that work ?

Update: I have given up and am installing SQL Server 2008. Wow, this install has got to a lot to be a more work than in the past. Tons of screens where I need to provide a login and other details, lots of user hostile error screens, and now I need to install VS 2008 SP1 before it will continue. How many of these service packs are actually needed to make these programs work ? Not many, I am betting.

Further Update: The VS 2008 SP1 took 90 minutes to download, and is close to taking an hour to install. This machine has 8 processors and 20 gig of RAM, the 1 TB drive is almost empty, so the machine is not the issue, nor do I have slow internet. 7 hours of trying to install SQL Server and counting.......

Sunday, June 14, 2009

Update - ArrayList is not a List

As Shog pointed out below, ArrayList is in fact an array. I did know that at one point, but I embraced typed containers from the moment they appeared, as I would hope most people did, and my experience with ArrayList for many years has been limited to saying 'why on earth do you use that ?' to people in forums. But, like the terrible MFC containers that were only written as a stop gap until they got STL, and yet so many shops forced their devs to use them, because 'we're a Microsoft shop', ArrayList is with us to stay, because it's part of the language, they can't remove it. Which is why we should have got typed containers in the first place.

But, even worse is that there was no list class in .NET 1.0. I can see how I forgot about this, it's really hard to believe. No list class ? How long could it have taken to 'whip one up' ? I realise that ArrayList is a name that came from Java, but, guys, steal the good stuff, not the bad. ArrayList is a stupid, stupid name for a container class, the benefits and pitfills of an array/vector class compared to a linked list are basically opposite ( which is also why both should be provided by any language released in the 21st century ).

I should mention, I set out to have a bit of content from the get-go, but I'm not claiming that MS has 365 bugs for me to report in a year, so although I have about 8 items queued up, rather than run out of steam, I am going to post roughly once a week, probably over my weekend. I do want to post with some gotchas that brought my Mac to it's knees this past week ( I do intend to post about anything where I know how to help someone fix something, Microsoft happens to be where I live, and so where I know of the most issues, but the Mac won't get off 100% scott free ), I may do that sometime this week, before a weekend post on a .NET or WPF bug.

Saturday, June 13, 2009

Missing C# language features

I'd be the first to admit that coming from C++ to C# was hard for me, because C++ had been my core language, and while I learned things like Python, they were so obviously NOT C++, that I just accepted they were different. C# is named after C++, and goes out of it's way to look like C++, so when it was plainly very different, I often took it hard. This was, obviously, my fault.

However, there are things about C# that still make no sense to me. I still hate that C# won't allow fallthrough in case statements, such as

case SaveAndQuit:
case Quit:

When I asked the C# team, I was told that C# will always err on the side of being easy for beginners, rather than being powerful. I believe a strength of C++ is that it assumes skill on the part of the programmer, rather than treating him like an idiot.

I was also astounded at the lack of generics support in C# 1.0. I still talk to people on forums using ArrayList today, despite generic containers having been in for some time now. The generics support we have is very limited compared to C++ templates, I don't see how 1.0 could not have contained an engine that generates a typed List class, for every templated argument given. That's basically all we have now, right ? Although at least the CLR means that you don't end up with a ton of different classes in your exe, as you did in C++.

In addition, in C++, we had the STL, with a vector and a list class. The vector is an array class, which means fast random lookups, but slow inserts. A list has the opposite O notation. In C#, we were given a class called ArrayList. OK, is it an array, or is it a list ? ( It's a list, by the way ). To my knowledge ( and I just googled again to make sure ), there's still no array class, although you can arguably just use an array, and HashSet only arrived in .NET 3.5. I don't understand why such basic things were not implimented.

I will say that I love LINQ and I love that C# is moving past being a poor mans C++, and establishing it's own set of power features.

One thing I asked the C# team for many times, was optional parameters. They want to keep the language simple, yet instead of having the compiler generate a method like

bool SomeMethod(int n)
return SomeMethod(n, "The default value");

they want me to write it and maintain it instead ? In C# 4.0, they are finally implimenting this, and doing it all the way, with named optional parameters, which is pretty cool, but it's sure been a long wait, and I don't see what damage an intermittent, non named parameter version could have done in the meantime.

Which brings me to my main point. One thing that took some getting used to in C#, is that classes are always passed by reference. If you pass me a class instance, and I change it, I changed it for you, too. So, it seems to me that if I were writing a library, I would want to create an interface that provides a contract to my users - I am not going to change this object, I can be trusted to return it in the state it was given to me. The fact that they kept a const keyword, but made it mean something totally different in C# to C++ threw me at first, but I eventually found the readonly keyword, I just don't see why it can't be applied to parameters on a method definition. Sure, it's syntactic sugar, it doesn't change what the method does, but, writing code that a computer can understand is EASY. The thing we need most to focus on, is writing code that HUMANS can understand and trust. Code that is maintainable, AND that explains itself well to a first time user, should always be the goal.

I do see that there's a level of complexity there, if a method takes a const parameter, passes it to another method, which passes it somewhere else. And I can see that the solution to the fallthrough problem in case statements apparently being goto means that we're encouraged to write spaghetti in C#, but, I still find myself from time to time wishing that when I write a method, I could actually remind others, and have the compiler remind me, that I wanted to pass an object into a method, without that method changing the object in any way. The only alternative I can see is to write and pass in a wrapper class which only allows getting of properties in the contained class. And, while I used to spend time writing strongly typed containers in C# 1.0, even I am not pedantic enough to do that.

And if anyone tells you they are learning C#, and know C++, the best piece of advice to give, is to say, C# is not based on C++, it's Java on steroids.

Friday, June 12, 2009

WPF destroys images when resizing them

This is the bug I was reminded of, which caused me to decide it was time to start a blog. Two years ago, I wrote my first WPF project. Basically, it's a program that gives you access to high quality images, which you can zoom in on, etc. Now, because of issues with WPF memory management ( which I'll cover at a later date ), we decided to save memory, by loading images as requested, then resizing them to the size of the screen. We'd reload at a bigger size if the user zoomed. What we found was, some of our images would become distorted sometimes when we zoomed ( which involved reloading the image at a new size ). WPF has a control for scaling images, however, it keeps the full size image in memory, making it useless for our purpose ( it just wasn't what it was for ). So, we resize the image the way the docs tell you to. Something like this:

fullHeight = bi.PixelHeight;
fullWidth = bi.PixelWidth;
bi = new BitmapImage();
if (heightBasedAR)
bi.DecodePixelHeight = (int)Math.Min(height, fullHeight);
bi.DecodePixelWidth = (int)Math.Min(width, fullWidth);
bi.StreamSource = new MemoryStream(fileBuffer);

As I said, this worked sometimes, and others, would destroy the image. We have illustrations in the program which are PNGs, and photos which are JPEGs. I am not sure if it was the photographic content, or the JPEG format that made the latter ones get distorted, but I have a feeling we changed some images to PNG and that helped, so I'd say that I believe it's the format that is the issue. In any case, it would only happen sometimes, but by experimenting, I proved that the issue was that it would only happen for certain sizes of image, that is, the same image would consistently break, if you found a new size that would break it.

I created a sample app and sent to Microsoft, it produces the following output:

As compared to my original image, which looked like this:

It actually took me three emails back and forth of 'I don't see a problem', before the Microsoft guy accepted that image 1 does NOT look like image 2. This seemed to me to be a pretty major bug, and it was duly reported and went on the pile. Two years later, I run the latest version of WPF and .NET ( 3.5 SP1 ), and my program still destroys this image, which is how I got that screenshot.

The only solution I could find, was to revert to GDI+ to do my image resizing. So, our application does something like this every time we load an image:

int scaledWidth = (int)Math.Round(fullWidth * scale);
int scaledHeight = (int)Math.Round(fullHeight * scale);
System.Drawing.Size newSize = new System.Drawing.Size(scaledWidth, (int)height);
using (System.Drawing.Bitmap bp = new System.Drawing.Bitmap(img, newSize))
using (MemoryStream ms2 = new MemoryStream())
bp.Save(ms2, System.Drawing.Imaging.ImageFormat.Png);
bi = new BitmapImage();
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.StreamSource = ms2;

So, GDI+ reloads the image at a new size, then saves it to a memory stream, and from there we read the stream into a WPF BitmapImage. Hardly neat, but it works, and WPF still does not.

Thursday, June 11, 2009

Welcome, one and all

So, after years of resistance ( apart from a brief dalliance with a music blog ), I am blogging. Why ? Well, I was a Microsoft MVP for three years ( I was kicked out for not liking Microsoft Vista ), and I was assured at the start of that experience that I now had an inside track to report issues with Microsoft, etc. I have found many bugs in Microsoft products, before, during and since. What is consistent in all my experiences is that reporting bugs means they either claim they can't reproduce ( although usually I press on until they accept the issue ), tell me it's a feature, or just plain don't fix it. So, I'm going to blog about the bugs I've found in Microsft frameworks, particularly C# and WPF, because that's what I tend to use nowadays, but, I'll be bringing stuff up that I reported in the past, so there will be other C# stuff as well. The idea is not to have a mindless bash at Microsoft, it's to report real issues in their frameworks, and, where possible, to report workarounds, so that hopefully I'll find readers from people who google the same error messages, and are looking for solutions. That's assuming anyone googles anymore, reading programming forums sometimes makes me wonder if that is true.

So, that's my statement of intent. I have a few decent issues in mind already, but I doubt I'll come up with an issue a day ( it's not THAT bad, bad as it can be ), but we'll see how long I can keep it up.