Installing a folder with specified permissions

So for the next release of our software, we need our installer to create a folder that’s writable by all users on the computer.

You’d think this wouldn’t be hard. You’d think this would be well-trod ground. But no, apparently not. We’re using an MSI-based installer, nice feature set, rather pricey, which apparently can’t grant permissions to the standard “Users” group because it claims that group doesn’t exist. (We’ve filed a bug report and are waiting to hear back.) And our attempt to write a little app to set the permissions programmatically isn’t going well either. I’m not actually the developer who’s working on installation issues (I just get some questions bounced off me now and then), but it seems to be causing rapid hair loss — not from ripping hair out, just from the friction caused by banging against brick walls. I’ve looked at the permission APIs before, and they’re pretty awful; according to my cohort, the documentation is even worse, basically amounting to “take a guess at the parameters and see if it works”.

Freeware to the rescue.

My boss suggested that I take a quick look at Jordan Russell’s Inno Setup, a freeware (with source) installation-building package that I had some prior experience with, and see if it could handle permissions. It originally took me a while to get used to Inno, since you have to write a text-based install script. The first time I downloaded it (around five years ago), I took a look at it and then uninstalled it — I made the mistake of being unimpressed by its lack of a pretty design-time GUI. (It has syntax highlighting now, which helps, but you still write your script as a text file.) But it’s powerful, and it can do just about anything; it’s even got a built-in scripting language. Jordan pays attention to building good apps (none of that “every time the user clicks the Next button, we’ll hide the current dialog box and then show another one, and hope nobody notices the flickering” crap like Wise and InstallShield both seem to be doing these days), and of course free is good. But can it change permissions?

Of course it can change permissions. Yes, it can grant modify access on a given folder to all users of the computer (I just tested it to make absolutely sure that it works, and it does, even on the same PC where the expensive installer didn’t work). You just tack “; Permissions: users-modify” onto the entry in the [Dirs] section. So, while we probably won’t switch our installer to Inno at this point, we do have ready access to source code (Delphi, no less) for changing permissions.

As if that weren’t cool enough, the FAQ on the Inno Setup web site suggested taking a look at SetACL, an open-source, command-line tool for changing file permissions. SetACL.exe (command-line version) is 258K — which seems awfully large for a C++ console app — but its list of command-line parameters is pretty substantial; it can set permissions on files, folders, printers, Registry entries, services, and network shares, and it’s full of options I’ve never even heard of. I think, between Inno and SetACL, that our permission problems should be pretty well wrapped up. And there was much rejoicing.

Code Coverage

NCover may be worth a look. In my copious spare time. Code-coverage analysis could be a Good Thing ™ for test-driven development. (Apparently the people who wrote NCover thought so too.)

Actually, there are two apps out there that are both called NCover. One is on SourceForge and the other is on GotDotNet Workspaces. The SourceForge one has a sample report on their Web site (showing its own test coverage) that looks pretty tempting, but the GotDotNet one has Visual Studio integration. Both projects seem fairly active.

Here’s a post from the csUnit mailing list on how to use the GotDotNet NCover with csUnit.

If I ever get around to trying either one, I’ll post my experiences here. (Has anyone else tried either or both of them?)

Security permissions in Windows Forms

Whenever I’m writing a custom WinForms control, unless I have some reason to do otherwise, I always try to write it so it’ll work in a partial-trust environment, like embedding the control inside a Web page (Internet zone), or running a program from a network drive (Intranet zone).

Windows.Forms does not tend to make this easy.

So I’m working on my FlowLinkLabel class, right? There’s some text (blue and underlined, of course (well, by default anyway)), there’s possibly an image. And depending on the length of the text string, there may be a bunch of empty space to the right of the text, or below the image. I don’t want the control to react to clicks in that empty area. Only clicks on blue underlined text (or on the image) should count. Okay.

That means I need to do my own click tracking; I need to override OnMouseDown and OnMouseUp. No problem. I also need to process WM_CANCELMODE. Problem!

If the user presses the left mouse button, and then (without letting up on the mouse button yet) Alt+Tabs away, or presses the Windows key to bring up the Start menu, or some ill-behaved application steals the focus because the user just got an instant message, then my OnMouseUp handler will never fire. But I still need to clear my “_isLeftButtonPressed” flag. Granted, if I can’t clear that flag, it will only cause real problems in certain pathological edge cases. But I don’t like leaving edge cases open, even pathological ones.

As I learned back in my Delphi days, Windows tells me about all these rude happenings by sending me a WM_CANCELMODE message. Lovely, says I. I’ll just override WndProc and — boom! Oops, there’s a security demand on WndProc. If I override WndProc in FlowLinkLabel, then nobody in the Internet zone can instantiate FlowLinkLabel. If they try, they get a SecurityException.

The interesting part is this: The SecurityException is not thrown by the call to new FlowLinkLabel(). Instead, it’s called when the Just-In-Time compiler tries to JIT the method containing the call to new FlowLinkLabel(). That is, it blows up when it’s partway through trying to JIT-compile InitializeComponent. Which means the exception’s stack trace is marvellously unhelpful; all I see is that an exception occurred in the Form1 constructor, on the line where it tries to call InitializeComponent. I never see anything that tells me which line within InitializeComponent is actually causing the problem, heavens no; so if this is the first time I’m trying to run my app under restricted permissions, I don’t have a clue which third-party component is being ill-behaved. Nice, eh?

Back to FlowLinkLabel. I can’t override WndProc if I want partial trust to work. I was getting started on an elaborate workaround, and then happened to be looking through Reflector and saw that Control.WndProc calls something named OnNotifyMessage. I fire up the help, and read that OnNotifyMessage is specifically meant for partial-trust scenarios! It can’t modify or suppress the message; all it can do is watch the message going by. Which is exactly what I need for WM_CANCELMODE.

Lovely, says I. I’ll just override OnNotifyMessage, and do the appropriate SetStyle() to tell WinForms it’s there. Run it under the Internet zone — it runs! Hooray! Write some more code. Run and — boom!

Undo checkout. Was it my override of OnMouseDown? Try that again, see what happens. No exception. Well, I know it wasn’t my override of OnNotifyMessage, I already tested that. Try again anyway, just to make sure. Hmm. Scratch my head. Finally go through all the motions again, testing much more often this time.

It’s when I add an if statement inside OnNotifyMessage. An if statement that does nothing but read the message struct’s Msg int property.

Open Reflector again. There’s a security demand on the Message structure. It requires unmanaged-code permissions. Which I very much do not have in the Internet zone.

So they give me a method I can override where I can see all these messages flying by. But I can’t see a blooming thing of what’s in those messages. That is frustration in action, folks. It also smells like poor design — OnNotifyMessage exists only for partial-trust scenarios; the docs even go so far as to say you don’t need to bother calling base.OnNotifyMessage(), which heavily implies that Microsoft will never, ever bother to put any of their own code into OnNotifyMessage. And aside from permissions, anything you can do with OnNotifyMessage can be done just as easily by overriding WndProc. OnNotifyMessage exists for one purpose, and yet, it’s useless for that purpose.

Sigh.

I worked around it. The first time FlowLinkLabel.OnNotifyMessage is called, I enter a try..except, where I call another method that tries to read message.Msg (has to be a separate method, since it’s the JIT throwing the exception — if I did it inline, my try..except would never finish getting JITted). If a SecurityException is thrown, I just don’t watch for WM_CANCELMODE anymore, and those pathological edge cases remain open. But any time it turns out that the code can read message.Msg, it will process WM_CANCELMODE quite happily. (Then, of course, I short-circuit my implementation on later calls, so I’m not throwing an exception every time a Windows message is received.) Decent compromise, I guess.

Windows Services in .NET (with Indy)

As part of my team’s project at work, we had to create a Windows service in .NET. Originally we built it in Delphi 8 for .NET, which worked fine as long as we could get the compiler to cooperate. But the D8 compiler is so buggy, especially when working with multi-assembly project groups, that we eventually wound up porting the service back to C#. Sigh.

Creating a Windows service in .NET is actually not too hard, though it isn’t well documented. If you have Visual Studio, there’s actually an option in File > New Project to create a Windows service. However, that doesn’t do everything you need; specifically, it doesn’t give you any way to install your service so that Windows will actually run it (or show it in the Services snap-in so you can start and stop it later). And if you have Delphi 8, you don’t have a Windows service wizard. (There was one in D6, but apparently its .NET rewrite didn’t make the D8 release schedule.)

This article on CodeProject was invaluable to us in getting things up and running. It shows how to build a .NET Windows service from the ground up; it doesn’t assume that you have Visual Studio with its Windows service project wizard (which is handy if you’re using Delphi 8, or if you only bought Visual C# instead of the full Studio, or if you’re writing your code in SharpDevelop or Notepad). It also shows how to install (and uninstall) the service using installutil.

Once you’ve walked through the article, and have your service up and running, it’s pretty slick. The service ends up as an EXE that’s intended to run under Windows’ service manager — and the .NET service plumbing will automatically give the user a meaningful error message if they try to run the EXE manually (though there is about a 15-second pause first), which is good. And if your service is starting an HTTP server using the open-source Indy networking libraries (check them out if you’re still using the wussy FTP and HTTP support in System.Net — Indy is better, and it supports just about every Internet protocol known to man, both client- and server-side, and it’s free), then you don’t even need to worry about the fact that there are something like three threads being created and juggled just to manage your service — it just works. Just set the server’s Active property to true in your override of ServiceBase.OnStart, and set it back to false in your override of ServiceBase.OnStop. Indy will even wait for any pending HTTP requests to finish before it returns from the Active = false setter. Very cool.

Merged cells in Xceed Grid

My team recently did a survey of the available WinForms grid controls for .NET, and we pretty unanimously voted for the Xceed Grid. We miss some features from the Delphi world’s TMS grid, like fixed columns and merged cells, but TMS hasn’t shown any signs that they intend to bring their grid forward into the Delphi for .NET world and we needed something.

However, even though fixed columns aren’t natively supported in the Xceed Grid, they can be emulated. Actually, we let their sales folks know that we couldn’t buy their grid if it couldn’t do fixed columns (true), and they supplied a workaround. Which didn’t work in the 2.0 version, but they were kind enough to send us a pre-release version of 2.1 (then about two weeks away from release) and the fixed-column workaround worked again. (2.1 is now available.) It works great; you’d never know it was a workaround.

And they just posted a knowledgebase article on how to emulate merged cells. So at this point (though not having tried the merged-cell workaround), I think we’re not missing any features from the TMS grid, and we sure have a lot more features to play with. Pretty cool.

This would’ve been easy in Delphi…

I’m writing a FlowLinkLabel WinForms control. It’s a LinkLabel-like control that automatically wordwraps, and changes its height as needed when its width changes. There’s a plain old non-hyperlinked FlowLabel too. Useful for headings and stuff, or explanatory text, or task panes, or anywhere you want flow layout. I wrote it because I’ll be needing it for a project at work, and I wrote it on my own time and will release it open-source, because that way I can use it in my other spare-time projects too. (grin)

Of course, in Delphi this would all be easy. I wouldn’t even need to write my own control. I’d just drop a TLabel, set AutoSize to True and WordWrap to True, and boom, it works. The WinForms Label has an AutoSize property (which defaults to False for some reason), but it’s horizontal only; it doesn’t grok word-wrap, so it’s useless for anything resembling flow layout. There’s nothing suitable for, say, putting a paragraph of explanatory text at the top of a window, and having it re-wrap and all stay visible as the window gets narrower. (There will be all sorts of flow layout in Longhorn, but that’s what, at least two or three years away, and would require all our clients to upgrade to Longhorn when it comes out… so for us, probably at least five or six years away.)

Anyway. So I was hoping to be able to have all the FlowLinkLabels on a form automatically share color settings (link color, hover color, active color, visited color), underline settings, etc. Stylesheet kind of stuff, only for WinForms. That’s why I was looking for the article I mentioned yesterday — I knew it touched on that sort of idea. Creating a service in one part of your app and getting at it from somewhere else.

My general thought was this: Have a non-visual Component (maybe added to the form manually by the application developer, or maybe created automatically the first time you drop a FlowLinkLabel onto a form) that stores the style settings. All the FlowLinkLabels in the form share this same stylesheet component by default (with the ability to override per label if you want some to have different style settings). Everything happens full automatic: you create a new form, you drop a bunch of FlowLinkLabels, and boom, you automatically — with no more effort than that — have a centralized place to set the colors for all of them at once. If I was sneaky enough, I thought, it might even be possible to share these stylesheet settings across multiple forms.

Alas, it looks like it’s not to be. For starters, given a Component, you can find its Container, but there’s no way to get from that Container up to the next Component up the chain (e.g., given an ImageList instance, there’s no way to get a reference to its containing UserControl), which would make it hard for the FlowLinkLabels to automatically discover the shared container that lives up in the form/usercontrol, and hard for the stylesheet to automatically notify the labels when its properties get changed. Second, even though Control descends from Component, it’s not treated like a Component: the designer adds Components to a Container, but Controls are added to a ControlCollection, and the Container and ControlCollection have no way of referencing each other. So again, no addressability between the controls and the components. Third, the ideal way of storing these settings would be by using IServiceContainer, but this only works if someone creates an IServiceContainer for you — which would require manual coding on the part of the application developer. Yuck.

Delphi makes this so much easier. TControl descends from TComponent, and it’s treated the same way. Iterating through all the components (and controls) owned by a form (or frame) is trivial; you just loop through the Components[] array property. WinForms seems bound and determined to make the same thing hard.

So it looks like there’s no good way to make these stylesheets work without forcing the application developer to drop their own stylesheet component onto the form and then manually hook each FlowLinkLabel to it. Which is error-prone (if you add a new label, you have to remember to hook it up), which is exactly what I was hoping to avoid. Feh.

System.ComponentModel

So I’m finally entering the blogging arena. Mostly ’cause I spent most of this afternoon looking for an article I knew I’d read before, but couldn’t find, and that had fallen off my browser history. See, if I had a blog, I would’ve just linked to it when I first found it. (Now I just need to talk the rest of my development team into starting their own blogs too, so they can help sift through all the interesting RSS feeds.)

Anyway, here’s the article: System.ComponentModel. Everything you ever wanted to know about the System.ComponentModel namespace, Component, IComponent, ISite, IContainer, IServiceContainer, GetService, AmbientProperties, etc.

I want a way to share the color settings among all the FlowLinkLabels on a form, in a fairly automatic way, and I’m thinking this article might get me there. We’ll see.