Setup authors: Make sure "TrustedInstaller" is enabled

Scott Hanselman had the idea that him and I should get together and put together all the best practices for writing installers, specifically for .NET applications. Clearly this is a good idea, although it’s one where all the information is difficult to organize since it’s never really come together at any single point in time (at least, for me!). So, I will periodically post things that I’ve had to deal with in my installer, and eventually we’ll get around to organizing it all. Hopefully 🙂

Today’s post will cover a difficult to diagnose problem you may run across if you are installing side-by-side assemblies ("SxS") in Windows Vista. Note that in this case "assembly" doesn’t refer to a .NET assembly, but rather a "native" assembly installed into the side-by-side repository. You can poke around in it by going to C:\windows\winsxs. Even if you aren’t explicitly installing SxS assemblies, something else you depend on may be.

Anyway, Paint.NET version 3.10 incorporated Dean Ashton‘s DDS file type plugin, which makes use of Simon Brown‘s "Squish" library. The latter is written in C++ and sits in three DLL’s: one each for x86, x86 with SSE2, and x64. I added some multithreaded optimizations to the Squish code which then pulled in a dependency on OpenMP — something that had to be installed into the SxS repository. Visual Studio automatically figured out what to add to my MSI in order to get things installed right, so that part was easy enough.

Most applications out there won’t need to install OpenMP, but they quite often need to install things like the Visual C++ Runtime DLL’s. And if you’re installing the .NET Framework, then that installer has things it puts into the SxS cache as well.

Some people started reporting some problems when installing. They were all able to give a screenshot that showed a wonderfully cryptic error message:

"An error occurred during the installation of assembly ‘Microsoft.VC90.OpenMP,version="9.0.30729.1",publicKeyToken="1fc8b3b9a1e18e3b",processorArchitecture="x86",type="win32"’. Please refer to Help and Support for more information."

(Side bar rant: Why do these errors always say to refer to Help and Support? It never has any useful information!)

This then caused the generic 1603 "setup failed" error. They were always running Windows Vista, and I had no idea what was going on here. Fortunately a member of the forum, "wolf5", managed to find the solution, although it was several months after the problem was originally discovered:

I found a solution that might be the fix:

Go check in windows services that the service named "Windows Modules Installer" is up and running. Mine was disabled. Enabling it removed the VC90 error. ( i also had problems with windows update because of it and a few other VC90 installations ive tried (vcredist_x86.exe for vs.net 2008).

I don’t know why the service was set to Disabled, but my guess is that some "tweak" program was used or they followed the advice of one of those "optimization" guides. In any case, it doesn’t matter – it’s their computer and their business. "Windows Modules Installer" is better known by its EXE’s name: TrustedInstaller, and if it’s disabled then even things like Windows Update will have trouble working right.

Why can’t we be proactive about this? Anything I can do to easily improve the success rate of my installer is something I should probably do. My setup wizard is written in C#, but it is launched from a small EXE written in C called SetupShim who’s job is to check for major dependencies like Windows Installer and the .NET Framework. If TrustedInstaller is disabled, then those installers will fail as well, and so that’s ultimately where I needed to place the fix.

Fortunately this is very easy to do. All you need to do is call into the SCM (Service Control Manager), query the configuration for Trusted Installer, and then set it to Manual if it’s in the Disabled state.

Here’s the C code for ensuring that TrustedInstaller is running before you launch into your install flow, written in good old fashioned C. It requires administrator privilege to succeed.


hr = EnsureServiceIsNotDisabled(L"TrustedInstaller");

HRESULT EnsureServiceIsNotDisabled(const WCHAR* szServiceName)
{
    HRESULT hr = S_OK;
    DWORD dwError = ERROR_SUCCESS;
    BOOL bResult = TRUE;

    // Open SCM
    SC_HANDLE hSCManager = NULL;
    if (SUCCEEDED(hr))
    {
        hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);

        if (NULL == hSCManager)
        {
            dwError = GetLastError();
            hr = HRESULT_FROM_WIN32(dwError);
        }
    }

    // Open service
    SC_HANDLE hService = NULL;
    if (SUCCEEDED(hr))
    {
        hService = OpenServiceW(hSCManager, szServiceName, SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG);

        if (NULL == hService)
        {
            dwError = GetLastError();
            hr = HRESULT_FROM_WIN32(dwError);
        }
    }

    // Query the service’s configuration
    BYTE rgbQueryServiceConfig[8000];
    ZeroMemory(rgbQueryServiceConfig, sizeof(rgbQueryServiceConfig));
    QUERY_SERVICE_CONFIG *pQueryServiceConfig = (QUERY_SERVICE_CONFIG *)rgbQueryServiceConfig;

    if (SUCCEEDED(hr))
    {
        DWORD dwCbBytesNeeded = 0;
        bResult = QueryServiceConfigW(hService, pQueryServiceConfig, sizeof(rgbQueryServiceConfig), &dwCbBytesNeeded);

        if (!bResult)
        {
            dwError = GetLastError();
            hr = HRESULT_FROM_WIN32(dwError);
        }
    }

    // If the configuration is Disabled, then set it to be Manual
    if (SUCCEEDED(hr) && SERVICE_DISABLED == pQueryServiceConfig->dwStartType)
    {
        bResult = ChangeServiceConfigW(
            hService,
            SERVICE_NO_CHANGE,
            SERVICE_DEMAND_START, // "Manual"
            SERVICE_NO_CHANGE,
            NULL,
            NULL,
            NULL,
            NULL,
            NULL,
            NULL,
            NULL);

        if (!bResult)
        {
            dwError = GetLastError();
            hr = HRESULT_FROM_WIN32(dwError);
        }
    }

    // Clean up
    if (NULL != hService)
    {
        CloseServiceHandle(hService);
        hService = NULL;
    }

    if (NULL != hSCManager)
    {
        CloseServiceHandle(hSCManager);
        hSCManager = NULL;
    }

    return hr;
}

And that’s it. You’ve now increased the success rate of your installer by a fraction of 1%. (It’s always that fraction that’s important though!)

Experimenting with Vista Aero/Glass

It’s a very cool effect to extend glass into the non-client area, but it looks like GDI’s ClearType text rendering is obliterating the alpha channel. Thus, all text is essentially see-through. I don’t know of a way to tell the DWM to exclude certain areas from "glassification", you can essentially only give it 1 rectangle.

(Click for full size version)

So if I want to do something with glass it’ll take quite a bit of effort — maybe I’ll wait until a later milestone 🙂

Anyway let me know what you think. I do have plans for a visual "facelift" for Paint.NET v4. The first thing I’ve done is add a little gradient to the thumbnails in the image list at the top right (which took all of 5 seconds to implement, then 5 minutes to tweak the alpha values so it didn’t look wonky).

Beware of fake Paint.NET releases – or, there is no 4.0 yet!

I just received an e-mail from BetaNews this morning,

Rick,

Someone just submitted an 4.0 Alpha of Paint.NET. Do you want us to post this release? We would of course not post it over top of v3.36, but we would post it as a seperate release.

Let me know.

Thank you

Well, that was strange — I haven’t publicly released anything! I have some people on the forum doing some private testing on the install/update changes, but nothing too exciting. So I wondered if one of them leaked it (they didn’t), and inquired further.

As it turns out, there’s another download site that’s hosting a file called "Paint.NET.4.00.Alpha.rar," no doubt based on a trusted user submission. This was then simply forwarded to BetaNews.

So I downloaded the file and pawed around, although I did not run the EXE inside of the RAR. Here’s what I found:

  1. The file size was wrong. Like I said in my previous post, the installer is currently 3.7mb. I really doubt that RAR can compress a heavily LZMA-compressed archive down by another 25%. (Or vice versa)
  2. The file name was wrong. "Paint.NET.4.00.Alpha.exe" is a good guess, but you can see even from the screenshot in my previous post that the file name I’m using is actually "Paint.NET.4.0.Install.exe" (I would put an Alpha in there for an Alpha release though, of course).
  3. The file version of the EXE was wrong. The real one would say 4.0.0.0 for the EXE-inside-the-ZIP. This one was 0.0.0.0.
  4. And here’s the kicker, the file wasn’t digitally signed by me. In fact, it wasn’t signed at all!

The first 3 can be faked easily enough, and I’m not worried about divulging that information. The last one cannot be faked*.

My conclusion was that it’s probably a virus, and so I told BetaNews not to publish the file. If it was a leak, that would be annoying but at least it would be reasonably "safe" (plus it would expire soon anyway, limiting the "damage").

So, how do you verify that you have a "genuine" Paint.NET installer? It all comes down to the 4th one: the digital signature. I sign every release of Paint.NET with a certificate that has the dotPDN LLC name on it. It will show up all throughout the process of downloading and installing it, because Windows and Internet Explorer like to remind you about it about 5 times.

Although, as a digression, the best way to make sure you have a "genuine" Paint.NET installer is to simply go to http://www.getpaint.net/ and go from there.

Anyway, when you run the installer EXE in Windows XP, you will get a dialog like this: (assuming you downloaded the ZIP from the website and ran the EXE from there — using something like WinRAR / WinZIP might not result in this)

Note how it highlights the Publisher name, which is dotPDN LLC. If you click on the name, you’ll get a dialog titled "Digital Signature Details". It should say, near the top, "This digital signature is OK." This is the same dialog you’ll see a little later in this post.

In Windows Vista, UAC will help you out here. You’ll get a dialog like this when you try to run the installer:

The dialog states "dotPDN LLC" again, and has the neutral colors as opposed to the big yellow warning version of the UAC dialog.

You can also verify the signature before you launch the program, which is of course a good thing. You want to get the installer EXE unpacked somewhere, then right click and go to Properties:

Next, go to the tab named "Digital Signatures." If there is no such tab, then the file is not signed and you’re done — the file is not from me, or is corrupted/incomplete somehow. You sould see an entry for dotPDN LLC:

Go ahead and click the "Details" button for the final step of verification:

The key here is "This digital signature is OK." At that point you know the file is "genuine", and neither corrupt nor incomplete.

And hey, if someone says, "Hey I found an alpha of Paint.NET version 4.0!" the first thing you should do is go to the Paint.NET website. If it’s not there, then it’s not real!

And yes, I’ve informed the other download site that the "Paint.NET 4.00 Alpha" is probably a virus and that they should remove it.

* Well, I shouldn’t say it can’t be faked. No doubt someone will hack around and prove me wrong eventually. For now though, it’s a fairly safe statement to make.

The Paint.NET install experience — Part 2, version 4.0

In my previous post I detailed the epic adventure of a normal user installing Paint.NET v3.xx on a "fresh" XP SP2 computer. I also said that I’ve made it a lot easier in Paint.NET v4. Let’s check it out:

Again, from the top, the user has excitedly downloaded the Paint.NET installer, and goes to double click on it …

The first thing we get is a dialog telling the user what’s going to be installed. Since this is a fresh XP SP2 box with no updates installed yet, they will need Windows Installer 3.1, .NET Framework 3.5 SP1, and of course Paint.NET. Compare this to the old dialog that tells the user what they need, and barely helps them to get it all.

Once the user clicks OK, the Windows Installer 3.1 package will be installed in automatic ("passive") mode. Installation will begin immediately, and the user will not need to click on any "Next" or "Finish" buttons. It will close once it’s done.

It installs fairly fast, and that’s good because most people will have no clue what any of the stuff on the dialog means.

Next, the .NET Client Profile package will also be installed in automatic ("passive") mode. Installation begins immediately — there’s no need to futz with buttons saying Accept, Next, or Finish, and it closes once it’s done.

This part can take awhile depending on your Internet connection, and I really wish they had a better UI to indicate this. The alternative is to add tens of megabytes to the download ZIP. I haven’t customized the graphics in the .NET Framework Client Profiler installer yet, but I plan to in order to make it more apparent that this is part of the Paint.NET install flow.

Finally, the Paint.NET v4 installer is launched! Ok, now the user finally has to worry about buttons saying Next, Accept, and Finish.

Note that the header graphics are just placeholders, I’m still figuring out what exactly I want there. I need a good "night" picture to put behind the white-text version of the logo 🙂

The installation progresses …

By the way, the "optimizing" portion of installation is much faster now with .NET 3.5 SP1 because of improvements to NGEN.

Once the user clicks "Finish" on the last page of the installer, they will be asked to reboot. This is because Windows Installer 3.1 requires it. (Remember, this blog post details installation on a "fresh" XP SP2 system! Most users will not have to worry about this rebooting nonsense.) I’ve written my install flow to only require a reboot at the very end of all the installations. Rebooting in the middle causes a lot of continuity problems and is a horrible user experience. Most systems won’t have to reboot though, as Microsoft has done a pretty good job of not requiring it for .NET itself. The v3.xx releases of Paint.NET actually cheat here and simply tell the user they should restart. Most people don’t see this, or ignore it, and it actually causes crashes and whatnot. So, yes, a new feature of Paint.NET v4: a reboot dialog! You heard it hear first! 🙂

And there you have it. Once the user has their hands on the Paint.NET v4 installer, that’s all they have to figure out. The rest is done for them. Once they restart, they’ve got Paint.NET installed. No ifs, ands, or buts. The barrier to entry for Paint.NET has been dramatically reduced.

So far the Paint.NET v4 download is about 3.7MB and includes Windows Installer 3.1, .NET Framework 3.5 SP1 Client Profile bootstrapper, Visual C++ 2008 SP1 runtimes (x86 and x64)*, the OpenMP redistributable (x86 and x64), and of course Paint.NET. I’ve done a lot of work and experimenting to figure out the best way to pack things together to get the smallest download possible — that 3.7MB actually expands to over 20MB in the temp directory!

Anyway that’s enough on the installer for now. My next chunk of work on Paint.NET v4 is in the guts of the rendering engine with the goal of dramatically reducing the memory footprint, and increasing rendering throughput on many-core (4x and up) systems.

* Version 3.xx uses the static versions of the runtime. Using the DLL version is preferred, for various reasons, and so I decided that Paint.NET v4 would finally switch to it.

The Paint.NET install experience — Part 1, version 3.xx

Note #1: This blog post is fairly long because it is image intensive. The point is to illustrate what a massive task this is 🙂 Don’t worry though, I ran the images through PNGOUT.

Note #2: If you haven’t already done so, I highly recommend that you go and install .NET 3.5 SP1 immediately!

Ok. I’ll admit it: getting Paint.NET v3.xx installed for many users is a massive chore. If you take a normal user, they almost certainly don’t have the .NET Framework installed. If it’s a newly formatted or purchased computer, it might even be a "fresh" XP SP2 installation that doesn’t even have Windows Installer 3.1 installed (which the .NET Framework requires).

One of the most educational things I ever saw was on Google Video called, "Paint.NET Install Part 1" (there’s also a part 2!). First, why should a tutorial be necessary? I should make my installer so easy as to make that completely unnecessary. Second, it was very enlightening to watch where the guy fumbled or was confused by things. I highly recommend watching that tutorial video if you want insight into just how unfriendly installing a .NET client application can be. (Note that I’m not trying to disparage the author of that video at all!)

Anyway, back to the blog post. Let’s journal a normal user’s adventure toward installing Paint.NET v3.xx. This user will excitedly download the 1.6MB Paint.NET v3.35 installer only to be bombarded with ridiculousness:

"Hi, I’m the Paint.NET installer. Hey, you need to install .NET — go here to download it!"

Ok, so the user goes to the website, fumbles around, clicks "Download" …

Then they click Open, and then … "Hi, I’m the .NET installer. You don’t have Windows Installer 3.1, come back when you do!"

(Why can’t it just download it for them?) When the user clicks "Exit Setup," they are left at a blank desktop. I think the next thought they have will be, "Huh? Now what?" But hey, let’s see what happens if the user gains psychic abilities and manages to find this mystical "Windows Installer 3.1" :

Forget for a moment that nobody other than people like myself and Scott Hanselman even know what "redistributable" even means (yes, I’ve had friends/family ask me if they are downloading the "right" thing as they were confused by what-in-the-world a "redistributable" was). So they managed to download it from the very unintuitive download page…

The user clicks next and continue a few times … and they got it installed! But what’s this?

They have to restart. Boo. Let’s assume the user manages to restart now and remember to come back to installing Paint.NET.



"Please wait forever."

The user is once again at a blank desktop. Is Paint.NET installed? Where is it? Well, hmm, it isn’t installed. Let’s assume the user once again harnesses their psychic power and double-clicks the Paint.NET download again (or, just as likely, they re-download it from the website).

Argh! I thought I already did that! Ok. The user channels their psychic powers to once again run the .NET installer …

Not that the stuff on this dialog box makes any sense to a normal user … but most people have gotten used to clicking "Accept" and then "Next". Although the download time estimate of 2 hours is quite a turn-off.



"Please wait forever."

Yes, please wait forever. Hope you aren’t on dial-up! Next, .NET is done installing:

If the user is really unlucky at this point, then another reboot will be required.

So … is Paint.NET installed? Hmm, where is it … I can’t find it. I’ll tap into those psychic powers and double click the Paint.NET installer again (this is the 3rd time!).

Oh thank goodness! Although then they get this fun part, which with a fresh .NET installation can actually take quite awhile (it actually times out after 4 minutes):



"Please wait forever."

Other than that installation generally goes smoothly, and then the user has Paint.NET installed.

Updating it at this point is fairly painless and easy. It only took like 6 downloads*, 3 setup wizards, a reboot, and about 1 hour of time… I’m almost amazed that any Windows XP users have managed to install Paint.NET at all. Or any .NET client software for that matter.

This whole process is no big deal for someone like myself, as I already know what needs to be installed and exactly where to click on things (relative to the normal user, I am "psychic"). But when’s the last time you met someone outside of Redmond who really knows and cares what "Windows Installer" is?

Anyway, in the next post I’ll detail how much better Paint.NET v4 is for this important deployment scenario. It’s a combination of a much smarter installation package and the new .NET 3.5 SP1 Client Profile.

* Assume that the user is not perfectly organized and just re-downloads the Paint.NET and .NET Framework installers whenever prompted to, as opposed to keeping them in a "Downloads" folder and remembering their names and which ones to click on at the right moments. This is actually quite normal! 🙂

Paint.NET 3.35 … "ugly" canvas background?

In the latest update, I changed the canvas background in Paint.NET so that it was a solid color instead of a grey gradient. The rationale for this change was based on a comment made by forum member "mkidd":

"The top-to-bottom grayscale gradient on the desktop area of Paint .NET (3.30 in my specific case) can cause serious toning misjudgments. I didn’t fully appreciate this until a colleague pointed out how much it was throwing him off, i.e. printed results didn’t seem to match on-screen results due to improper relative corrections applied to the top and bottom areas of images, say sky vs. ground. It seems that the plain uniform gray background in Photoshop is actually pretty important."

I agreed. So, I changed it to a solid color and got rid of the gradient. The color I used is based on a system color — in fact, it’s a 50% blend between SystemColors.Control and SystemColors.ControlDark. This produces mostly good results, but apparently there are some custom color schemes where it looks downright awful. The first person to really express a passionate opinion about this was Jelle Mees (forum name), who wrote a forum post about it, and included a screenshot:

In Vista, I think it looks pretty good:

 

Here is how it looks in XP with the Luna / Olive Green theme:

Similarly, I think it looks fine in the other built-in XP themes, especially "Classic". I was trying to honor the system color choices, but a few other forum members have expressed a very strong opinion that the canvas background should be a static (or configurable) color that is not based on the system theme.

It got me to thinking, and I realized that I didn’t fully parse the original statement about the gradient versus a plain gray background. In fact, I’m now convinced that basing the canvas background on a system color is a bad thing. The reason for this has to do with color calibration between systems: if the canvas background is grey on one system, but off-white/yellow on another, then it could throw off a person’s perceptions of colors between the systems. Or, two different people on two separate but differently configured systems would perceive colors differently (all else being equal of course, such as the monitors’ color reproduction). Gray is a neutral color, and won’t have much of a radiosity effect than colors with hue.

Well, what do you think? Is the new canvas background in 3.35 ugly? Would you rather it be a solid gray on all systems regardless of theme, such as in the Vista screenshot above?

In the forum post mentioned above, I have made a available a replacement PaintDotNet.Core.dll that sets the canvas background to #c6c6c6 regardless of the system theme. If you’d like, you can try it out before commenting! That DLL will not work in future versions of Paint.NET, however.

C# Extension Methods … Portability Aid?

In my first post about Paint.NET v4, I mentioned that I was learning a lot about C# 3.0 and .NET 3.5. One of the things I’m absolutely falling head-over-heels for is extension methods.

One use of these is to add utility functionality on to existing classes that you don’t own the implementation for. As an example, consider the System.Uri class. In my opinion, it could use an Append method:

public static class UriExtensions
{
    public static Uri Append(this Uri baseUri, string relativePath)
    {
        return new Uri(baseUri, relativePath);
    }
}

You can then use code such as this:

Uri donateUri = new Uri("http://www.getpaint.net").Append("/donate.html");

Instead of:

Uri donateUri = new Uri(new Uri("http://www.getpaint.net"), "/donate.html");

(Bear in mind that the string literals would probably be pulled out of a list of constants, and not inlined like in the code above.) In this case, we’re simply enabling a choice of coding style and not really doing anything new. We are avoiding pathological nesting such as "new Uri(new Uri(new Uri(…" for when we need to paste together multiple relative Uri paths.

One place I’m finding extensions methods to be very useful is in defining and implementing interfaces with only strictly orthogonal functionality. You don’t need to add utility methods to interfaces, you can simply define them as extension methods.

For example, my resource manager is contained in an IResourcesService interface that has GetString() and GetBinaryStream() methods. And that’s it.

using System.IO;

namespace PaintDotNet.Framework
{
    public interface IResourcesService
    {
        string GetString(string stringID);
        Stream GetBinaryStream(string streamID);
    }
}

All resources other than strings are stored as binary streams, such as icons, bitmaps, text files, etc. If you want to load a bitmap, then you can use the handy extension method:

using System.Drawing; // pull in GDI+

namespace PaintDotNet.WinForms
{
    public static class ResourcesServiceExtensions
    {
        public static Bitmap GetBitmap(this IResourcesService resources, string streamID)
        {
            return new Bitmap(resources.GetBinaryStream(streamID));
        }

        // similarly for GetIcon, GetCursor, etc.
    }
}

… elsewhere in the code …

menuItem.Image = Resources.GetBitmap("Icons.MenuFileExitIcon.png");
    // Resources is a local property that gets the IResourcesService assigned to us

I could have multiple implementations of IResourcesService. For example, I could have the "normal" implementation that pulls from the local file system, then a test version that does all sorts of fakery, and then maybe experiment with one that loads all my resources via HTTP GET. But, I only ever need one implementation of GetBitmap() because it is just a helper method sitting on top of GetBinaryStream().

But wait, there’s more!

GetBitmap() returns a reference to a System.Drawing.Bitmap object. You generally only care about this type if you’re writing a WinForms application (which I am doing). Or, put another way, you wouldn’t want an object of this type if you were writing a WPF application. You’d want a BitmapSource or something. I am not writing a WPF version of Paint.NET v4, but one of my goals is to have the ability to write one. This is where the "separation of UI and logic" comes into play from my previous post. I refer to the WinForms UI as the shell. The "business logic" portion of the code base is referred to as the application (app for short). You could potentially have a WPF shell, or a command-line shell. Or you could write your own UI toolkit that P/Invokes straight to the Win32 API and bypasses WinForms completely (I believe the latest Zune UI does this).

So, if we wanted a WPF shell for Paint.NET, we could still use the same interface and implementation for IResourcesService. No changes needed anywhere. Why should the resource loader care about what UI you’re using? Its job is to give you strings and binary streams. It’s your job to parse them. It shouldn’t need a reference to the likes of System.Drawing.dll or PresentationCore.dll.

Thus, we’d probably find the following extension method setup useful in our hypothetical WPF shell:

using System.Windows.Media.Imaging;
namespace PaintDotNet.Wpf
{
    public static class ResourcesServiceExtensions
    {
        public static BitmapSource GetBitmapSource(this IResourcesService resources, string streamID)
        {
            return …; // not sure what code goes here exactly 🙂
        }
    }
}

The WPF-based shell would never pull in the PaintDotNet.WinForms namespace, and would instead use the PaintDotNet.Wpf namespace. They’d almost certainly be in separate DLL’s. So these two static extension classes will never collide, even if they have similarly named methods.

Using extension methods this way is probably preferable to "interface inheritance" for adding utility methods. For example, now I don’t need to declare a IWinFormsResourceService that derives from IResourcesService. I can avoid putting all the utility functionality into the base interface which could cause headaches.

As another example of only implementing "strictly orthogonal functionality", consider the case of the System.Windows.Threading.Dispatcher class and its CheckAccesss() and VerifyAccess() methods. The latter basically calls the former and converts true/false into return/throw. It could be done as an extension method. In fact, I have my own IDispatcher interface in Paint.NET v4, and this is exactly what I do. For sections of my code that are P/Invoke heavy, I’ve found it useful to have a SizeOf() method attached to any struct, as opposed to calling Marshal.SizeOf(Type). Less keystrokes, and I think it improves readability.

Yet Another Poorly Done Business Proposal

I can’t make these things up, folks. I honestly feel that if someone really wants to do business with you, they’ll at least do more than 3 seconds of research and get your product’s name correct. It should be easy to figure out that the product hosted at http://www.getpaint.net/ is called Paint.NET, and not "Get Paint." The logo is only emblazoned at the top of every page…

Hello,

Our company, Firstlook, is currently seeking partners to distribute our latest software product, SearchInOneStep.com.

With 10 million active users of search software and a stellar record in the search industry, we feel we would be a great match with Get Paint.

Get Paint attracts a large number of downloads, with which our software could be easily bundled during install to provide an alternate steady source of risk free revenue  which goes directly to your bottom line.

We offer our bundling partners the option to be paid per download and would be open to any volume of downloads that your company could provide.

Please feel free to contact me at your earliest convenience if you are interested in monetizing your downloads with Search in One step.  I look forward to discussing this matter with you further.

Thank you,

Sanjay

Well, Sanjay, my product is not called "Get Paint". I went to the website and tried the "search in one step" and it’s garbage. All it does is syndicate a bunch of ads. There aren’t even any search results! So I told Sanjay that I would not be doing business with him.

As for everyone else, if you want a good search engine for Paint.NET stuff, might I recommend http://searchpaint.net instead? 🙂

The very first Paint.NET v4.0 screenshot!

It’s really not as exciting as it sounds unfortunately 🙂 I’ve been quiet on the subject for some time, though, and wanted to put out some information.

For a long time I debated whether I should fully refactor Paint.NET, or do it from scratch. I finally decided on the latter, and have finally been able to make some progress. Bear in mind that "from scratch" means that I started with a brand new, empty solution file in Visual Studio. It does not mean I’m throwing out all the current Paint.NET code. There are many places where I will be able to reuse vast amounts of it — rendering kernels, effects, math, algorithms, etc. The entire structure of the program will be different, however. If you demolish your old house to build a new one, you don’t throw out the grand piano in the living room too. It still has plenty of value.

The screenshot above is from a build that so far contains about 12,000 lines of code. This sounds like an exorbitant amount for a few menus and an About dialog, but hear me out. I’m building it using Inversion-of-Control (IoC) and related patterns, which requires a lot of new decisions to be made regarding assembly layout (layering, essentially). I’ve also got a new system for asynchronous programming, separation of UI and logic, separation of "contract" and "implementation" assemblies (this becomes very important when plugins come into play), command routing and handling, etc. Along the way I’m learning more about .NET 3.5 and C# 3.0, and have come across some wickedly cool things that are now possible.

As far as possible, everything is lazy initialized or loaded in Paint.NET v4. To aid this, I have a new asynchronous programming model and exception handling pattern, which I could probably talk about for hours. For example, in the screenshot above, the icons for the menu items are not loaded until you click on the menu — in fact, they are loaded using background threads (the threadpool). The graphics and rich text that populate the About dialog are also loaded from the resource manager service using a background thread. For these specific cases, there are no major performance requirements that necessitate this; however, it’s much easier to solve these simple cases and to establish good patterns for later, than the reverse. I’ve also got an old Pentium 4 that I now have available for baseline performance testing, and it will be interesting to see if I can keep the program as responsive on that system as on my Core 2 Quad — even if rendering kernels take longer to complete, it should still always immediately respond to input. *crosses fingers* (Anyone else get sick of Safari on iPhone not being responsive while loading some web pages? Yeah.)

Also, in the screenshot you may notice that the mouse cursor is resting in the File menu even though the About dialog is open. In Paint.NET 3, all dialogs are modal and you can’t do anything with the rest of the program while one is open. In Paint.NET 4, I’m trying to remove this as much as possible and as far as it makes sense to. For example, why should an update download prevent you from using the rest of the program? Why can’t you switch from image 1 to image 2 while a compute-intensive (aka, "takes a long time") effect is rendering on image 1? Why can’t you interact with the canvas while an effect dialog is open? Or change the selected colors?

Anyway, that’s all for now. I estimate that Paint.NET v4 will be 200,000 lines-of-code when it is done, which places me at about 6% complete.

Software Developer Tip: RSS Aggregator + Google Blog Search

Large companies, such as Microsoft or Google, have entire sections of their company dedicated to things like PR (Public Relations) and paying attention to what the media says about them. As a small time individual developer, you probably don’t have time to track down everything that is said about your product. But, if you know how to use an RSS Aggregator such as RSS Bandit or Google Reader, then you can passively (efficiently) watch a lot of the buzz about your product.

The trick is to use the RSS syndication feature in Google Blog Search. Basically you do a search for your product’s name, and then you click on the button to get an RSS feed for that search query. Whenever you check in on your RSS feeds, you’ll know if people have been talking about your product in the “blogosphere.”

Step 1 — Go to Google Blog Search and type in your product’s name. Usually you want to surround it with quotes.

Step 2 — On the top right side inside the browser window, click on “Sort by date”. The default is to sort by relevance.

Step 3 — On the left side of the window, find where it says “Subscribe:” and then click on the format that you prefer (I use RSS, for instance).

Try it out 🙂 I use this to keep up on what people are saying about Paint.NET — both good and negative.