Microsoft has released a new website this week that I can only describe as the other half of GotDotNet. If you used to use GotDotNet, you know there were two reasons to go there: the third party projects that were hosted there, and the Microsoft Samples.

GotDotNet was replaced by CodePlex, and a lot of Microsoft samples are, in fact, showing up there. But the thing about sites like CodePlex and SourceForge is that they expect you to use all the services — source control, download mirroring, forums, wiki, etc. In fact, both CodePlex and SourceForge have “activity” metrics which include measurements of the amount of developer activity that happens in their source control.

Microsoft Code Gallery is for those “samples” projects and other projects that don’t need source control — If you were using GotDotNet or CodePlex or SourceForge just for the download mirroring, then you could consider using the CodeGallery. They provide download mirroring with your choice of software licenses, and even a small wiki and forum … it’s basically exactly the same as CodePlex, but without source control.

I’m not sure why the world needed such a thing separate from CodePlex. Wouldn’t they be better off just creating a special “we don’t need source control” option for CodePlex projects? I mean, maybe they were seeing a lot of projects on CodePlex that weren’t using the source-control and such — just using it as a dumping ground for downloads. (I know that happens a lot on SourceForge — they have TONS of projects which are there just for download mirroring). But I don’t see the need for a separate project, nor do I understand the desire to have it be on the MSDN domain.

The hard drive in my development box died last week, and although I’ll spare you the story of the replacement process, I thought it might be interesting to document the process of rebuilding my dev box, and provide color commentary while I’m at it.

  1. Install Windows Vista (Business)
  2. Get domain admin (my boss) to log in and connect my machine to the domain
  3. Add my domain account as an administrator
  4. Log out and log back in as my domain accout (it’s important to do this ASAP or I end up with shortcuts and things in the ‘root’ user account).
  5. Adjust Windows settings (via “Programs and Features”) to include the IIS Features required for SQL Reporting services (*). I had to add the “Basic Authentication” to this list, I think, and I changed a few other features while I was in there … this actually required a reboot for some reason (presumably not because I added minesweeper and solitaire).
  6. Install Windows PowerShell (in hopes of doing other things faster)
  7. Create User Account for Sql Server to use
  8. Install SQL Server (before Visual Studio, to avoid SQL Express and the resulting lack of SQL Manager)
  9. While waiting for that, slow it down by copying my Projects, Documents, and Pictures folders over from the backup … I need my PowerShell profile and wallpaper before the defaults drive me insane.
  10. Change my wallpaper and avatar (that orange flower is actually annoying).
  11. Install Notepad++ (and copy userDefineLang.xml from backup for PowerShell scripts)
  12. In order to finder Change Explorer settings to:
    1. Show Hidden files and folders
    2. NOT Hide extensions for known file types
    3. Hide protected operating system files (I leave this, because Vista has tons of hidden junction points (for compatability) in my user directory which are very distracting)
    4. Launch folder windows in a separate process (Explorer still crashes sometimes in Vista)

Some side notes:
I’m actually capable of compiling most of my projects (using MSBuild on the command line) without installing SQL Server, and the rest of them require third party controls which I will not install until after Visual Studio is installed. However, having installed SQL Client, Notepad++ and PowerShell I can actually edit, recompile, and run queries via PowerShell … so in an emergency, at this point I can start fixing bugs ;)

Windows Vista, SQL Server, Visual Studio, and MS Office all want me to go online and check for service patches as soon as I install them. Since I feel fairly secure sitting behind my firewall, I don’t bother with this until all of them are installed — Microsoft Update will find and install all of the service packs in one fell swoop.

SQL Server and Visual Studio are the only two apps I install which have installers which are so badly behaved that I don’t even try to install them in my usual sub-folders (C:\Programs\DevTools\ in this case).. SQL Server, for instance, will make a “C:\Program Files\Microsoft SQL Server\” folder no matter what you tell it during install, and nothing I’ve found can convince it to do otherwise, so I might as well install to that location, and not end up with multiple confusing folders (I’ll make junctions in C:\Programs\DevTools\ later to keep myself sane).

More Software (more…)

So, I’ve been practically invisible for a few weeks here, and liable to be invisible for at least one more week … this is my vacation time, so it’s hard to motivate myself to blog about anything. However, I have been spending some time working on a side project: a PowerShell Host.

Now, there are a few other hosts out there, but with PowerShell Analyzer seemingly swallowing up PowerShell IDE and going the fifty dollar route … as an open sourcer and contributor to the PowerShell Community Extensions it seemed to me that this couldn’t be that hard, so I started looking for an open source implementation of PSHostRawUserInterface and couldn’t find one. I mean, there are a couple of implementations out there, but essentially they are the PowerShell Remoting interface (which actually runs inside PowerShell.exe, and thus doesn’t seem to implement anything itself) and a half-implemented console block from a Japanese file manager called kuon

So, being myself, I stepped in an implemented it in the weirdest way I could think of: on top of a WPF RichTextBox. Yep, that’s right. I’ve made myself a ConsoleTextBox which subclasses the RichTextBox and handles keyboard input etc to behave … roughly … the way a Console should.

It’s far from finished, but it is working, so this is by way of announcing the first public alpha release of PoshConsole! The vast majority of PowerShell scripts will run without a hitch — the only time you’ll have problems is with secure string input (eg: passwords), with direct raw buffer interaction, and with running “legacy” console applications — it does not yet redirect standard input/output/error.

One small tip: if you have the PowerShell Community Extensions installed, you’ll want to remove the alias they set up to pipe help through “less” ... because less is a legacy console app — you won’t get any help at all.

Technorati Tags: , , ,

So David Morgenstern over at eWeek has an opinion piece claiming that “PC users should forget their outrage and come to understand that life isn’t fair. The Mac platform is more secure than Windows and will continue to be so.”

Just for fun, I’m not going to try to debate that. It’s absolutely true (as he points out) that practically all of the “in the wild” viruses, trojans, and other malware target Windows. Of course, it’s also true that practically all of the software in the world targets Windows. Yeah, there’s plenty of Mac software, and plenty of Linux software too … but numbers-wise …. Yah, anyway. I said I wasn’t going to debate that … instead, I’m just going to poke fun at his ridiculous arguments.

Still, no matter how much you might consider this comparison an unfair shot, it is real. The Mac is a better platform when it comes to security and malware attacks.

I’ve used Macs since 1984, and I’ve been infected by some malware twice. Two times.

Now, I’m sure many of you can echo what I’m about to say, but with longer dates. I got my first PC in high school, sometime around 1990. Since then, I’ve been running DOS and Windows. The closest I’ve ever come to being infected was when I put other people’s infected floppies in my PC to run a virus cleaner on them … or maybe when I had a look at the source code for the Melissa and “I love you” javascript bugs… I’ve literally never been infected. Sorry David. That’s not an argument about macs vs. PCs, it just shows you’re not very careful.

By my reckoning of the installed bases for each platform, there should be many more exploits for the Mac. Depending on how you calculate the number—2, 3, 5 or whatever percent—shouldn’t there be that corresponding percentage of viruses on the Mac in these lists?

... Scripting News listed the site’s readers by browser. Firefox was the largest (49.76 percent), and Internet Explorer came in second (23.43 percent). However, Mac-only browsers Safari and Camino were next in line (21.31 and a guesstimate of 2 percent, respectively).

Well, I didn’t want to debate exact numbers … but now you’ve got me riled up. It’s preposterous to even mention the visitor logs of a single website when discussing computer market share … (more…)

Microsoft made several big announcements today at MIX07…

CLR in Silverlight

The most exciting announcement I’ve today is that Silverlight will include the Common Language Runtime (CLR) on both Windows and Mac … which means that it will allow development using any .NET-supported languages. They’re even including the open source Dynamic Language Runtime and thus IronRuby (which like IronPython is also open source).

On top of that, these features, plus support for Language Integrated Query language (LINQ) and cross-platform debugging capabilities, are available now in the Silverlight 1.1 Alpha (and will be released more publicly after Silverlight 1.0 comes out this summer?).

Silverlight Streaming

They also announced today that they will offer a media-hosting service for free called Silverlight Streaming! In a move that targets both Adobe’s flash and other media-hosting sites like YouTube and Revver … they will allow developers to stream high -quality video (up to DVD quality) into their Silverlight apps from Microsoft’s servers without any restrictions on branding or embedding (including use in “rich internet applications” — i.e.: outside the browser).

The current package in pre-release offers only 4GB of storage and unlimited bandwidth delivery of up to DVD quality video (700 Kbps), but their plan calls for Microsoft to provide hosting for unlimited Silverlight content and up to a million minutes of free video streaming at 700 Kpbs per site per month … that’s over 5,000 Gigabytes of bandwidth)+*+700+Kbps)+in+gigabytes of streaming per month, for free! They’ll also offer unlimited streaming for a fee, or free, but supported by advertising…

Jasper and Astoria CTPs

Astoria builds on ADO.NET and WCF to allows you to expose a data service for the web which can be consumed via HTTP and since it uses standard HTTP verbs (GET, POST, DELETE, etc) you can even make it accessible as a REST-style resource collection with unique URIs … and simple formats like JSON or plain XML ...

Jasper is another ADO.NET incubation project … aimed at dynamically typed .Net languages like VB.Net or IronPython … it dynamically generates data classes (instead of requiring manual, static configuration … or even code generation which must be kept up to date). It’s built on the Entity Framework (which was postponed until some time in 2008 … after Orcas ships), so it supports rich queries and object-relational mapping and automatic databinding.

Ozzie speaks on Services and Clients…

The orchestration of announcements has many people buzzing about strong leadership and strategy … and the keynote by Ray Ozzie left no doubt about who’s behind that, highlighting the work Microsoft is doing to integrate all the various aspects of their strategy. Ozzie pitched Software-as-a-Service (SaaS) 2.0: web and hosted services which have “grown to embrace the uniquely valuable role of the client.”

IE 8 will require Standards Mode

In a move that only the undisputed king of browsers could hope to pull off, Microsoft has announced that they’ll be requiring web developers to opt in to standards-compliant web design … feel free to take a moment to check for flying pigs.

They’re also planning on making the IE object model more interoperable with other browsers and provide more client-side APIs — including local storage for AJAX apps and more extensibility in the form of a plugin API. Look for it in 2008.

Today I’m going to write about some “use cases” for computers that should be common place, but aren’t, because they don’t work. Sometimes it seems that nobody is thinking about how people want to use their computers … or at least, nobody is taking that into account when they design their applications.

Hopefully this will remind a few software engineers somewhere that your “usability study” where you ask your users to perform specific tasks and determine how easy it was for them … doesn’t cover what they will want to do once they get a copy of your software. Anyway, on to the examples…

Lets take John (the imaginary users in use cases always have names, and even short profiles…), he’s a sophomore college student that commutes to school from off-campus, and he spends several hours every night on his computer. Tonight he’s chatting with a couple of the members of a project team for a design class he’s taking, and they’re working on doing some research.

John finds a website with some very well designed … forks … and wants to show that page to his teammates. He drags the URL into the chat window by dragging the little icon from his browser address bar, and sends it to them (so far so good). Then he notices further down the page, a particularly interesting design in amongst several others in a list with notes on each … so he clicks on the picture of that design and drags it to his chat window — whoops!

Much to his frustration his IM client can only deal with images by sending them as files to the other users, and to prevent spamming, it doesn’t have a feature to allow you to send a file to multiple users as the same time, even if they’re in a chat with you! Even worse, when he dragged the image, he may have selected the text with it, and seeing formatted html, his IM client may have just rejected it altogether … or copied just the text …

You know what? Let’s not deal with any other use cases today … lets just examine this one in further detail. At this point, John has several options:

(more…)

One of my myriad email newsletters had a link this week to this Techworld article, entitled: Microsoft admits OneCare flaws … which is basically an article about a couple of blog posts by the AntiMalware Team and the OneCare Team

Corporate communications on spaces.live.com? Really? My company has the whole domain blocked off as being a “Dating/Social” site and prevents access from within the corporate internet…. is that really where you want to make your official Mea Culpa statement? Of course, maybe that’s the point — not only is it on MSN spaces, it’s the first post on a blog that’s been dead since January … maybe they were hoping nobody would notice. And the other blog is even worse: it hasn’t been active since at least October of last year, and then suddenly, this Hello World post

Which begs the question: do news people really leave a blog in their RSS reader after 5 months of inactivity, or did someone at Microsoft email Gregg Keizer, Computerworld and ask him to have a look at their blog and write a story about it? What ever happened to Press Releases? I mean, I’m no “regular Joe user” but if you paid money for OneCare … is this how you expect them to issue apologies and promises to do better? It seems overly informal to me.

(more…)

As I’ve said before, the Windows Vista system automatically reserves the Windows’ Logo + Number key combinations for the shortcuts on your Quick Launch bar, so that you can easily launch your Quick Launch applications. That is, to start the first shortcut on your Quick Launch bar, you just press Win+1, and to start the second, you press Win+2 … and so on.

The problem is that pressing this hotkey always runs a new copy of the application (although obviously some applications have their own system for making sure only a single app is running, so for instance, you won’t get multiple copies of Windows Media Player) ... so I wrote a little application called RunOnlyOne which solves this problem. RunOnlyOne allows you to call it with an executable as an argument and it will either run that application or switch to it if it’s already running, making sure you only have a single copy running. You can use it in shortcuts on your Quick Launch bar, but also in geoShell shortcuts and hotkeys, Start Menu shortcuts, or even explorer desktop shortcuts (did you know you can assign a “Shortcut Key” to any shortcut in your Start Menu or on your desktop?).

I’ve actually just posted a new version of it, so if you downloaded it earlier (after my first post) you should go ahead and get the new version: the main change is the addition of a new command-line argument: -proc: which allows you to specify the name of the process module to look for, in case you want to run a shortcut or “launcher” app, but check for something else to be running.

For instance, if you want to run PowerShell, you probably want to run it via the shortcut which has font settings, window sizes, etc. So if you want to make sure you only keep one instance running, you can just specify the command line as: RunOnlyOne.exe -proc:PowerShell.exe "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Windows PowerShell 1.0\Windows PowerShell.lnk" You might have to specify the full path to RunOnlyOne.exe, and if you’re not on Vista, the path to the PowerShell.lnk file is probably different.

At any rate, I thought I’d share the source code and a couple of pointers about how to do this sort of thing. The source code includes a copy of some Iterator classes (two files: EnumProc.cpp and EnumProc.h) which were part of an MSDN Article back in 2002 … and basically uses them to do it’s magic:

  1. Loop through all the processes
  2. Check the first module from each process against either the -proc argument, or the name of the executable in the command-line path …
  3. If we find a match, pick the first window in the process and call SwitchToThisWindow, the Windows’ API for activating application windows.

The only real trick — apart from using the iterators — is that this is a “Windows” application, not a command-line application, so I had to remember to make a call to get the command-line arguments: int argc; LPWSTR *argv = CommandLineToArgvW ( GetCommandLineW(), &argc );. If you run it with no arguments, it pops up a MessageBox which shows the parameters which it accepts:

  • -? to show help
  • -s to RunAs Administrator (still only runs a new copy if the application is not already running, but you can bypass this by using the -proc argument to pass something impossible, like -proc:???)
  • -proc to specify the process module name, like: -proc:Explorer.exe.
  • the first argument after the flags should be the path to what you want to run
  • any following arguments will be passed to that application as arguments

As a side note: despite what you might have thought from my previous article, this is not a Vista-only application, it should run fine all the way back to Windows 2000 at least. Also: I’m not 100% sure what would happen if you call this to try to ‘sudo’ a command line app or any other app which has no window — it may crash (the other application I announced yesterday (sudo) doesn’t check for windows, so it’s a better choice for that).

On Windows Vista, the system automatically reserves the Windows’ Logo key + Number key combinations for Quick Launch, which means that you can easily launch any of your Quick Launch applications. That is, to start the first shortcut on your Quick Launch bar, you just press Win+1, and to start the second, you press Win+2 … and so on.

Run Only One

Anyway, this made me think that it sure would be nice to have the functionality I’m used to with geoShell via the QuickLaunch hotkeys — regardless of whether geoShell’s actually running or not. So I wrote up a little app called RunOnlyOne which takes another application (and any command-line parameters for that app) as arguments and either starts that app, or activates an existing instance of it.

In other words, if you drop RunOnlyOne.exe into a folder on your computer (ideally in your path) ... and put a shortcut to Firefox or IE on your QuickLaunch bar …. you can then right-click the Firefox shortcut and edit the Properties ... put (the path to) RunOnlyOne.exe at the front of the “Target” box, and make sure you edit the icon (RunOnlyOne has no icon, and you want to make sure the icon still points at your application, anyway). Now you can click that button (or press it’s Win+# hotkey as I mentioned earlier) and it will start Firefox (or IE) — but if you click it or press it’s hotkey again later, you’ll just activate the running application, instead of starting another copy!

While I was working on that, I thought it would be nice to be able to run things as administrator using that same tool, so I put in a “-s” command-line parameter, so if you call RunOnlyOne.exe -s Notepad.exe for instance, (on Vista) you’ll be prompted to elevate, and then Notepad.exe will run with administrative rights.

Vista Sudo

Having done that … I went ahead and made a separate app: Sudo which basically does the same thing, but without the “OnlyOne” restriction, so you can use it to force-start anything as administrator. Of course, you could do that from the Start Menu searchbox by pressing Ctrl+Shift+Enter anyway, but it never hurts to have more ways. Also, sudo has a “-multi” command-line parameter that allows invocations like this:

Sudo.exe -multi "Notepad.exe C:\Windows\system.ini" "Notepad C:\Windows\win.ini"

The idea is that if you run Sudo -multi you’ll get a very ugly Unidentified Application dialog instead of the usual elevation prompt, but you’ll only get it once, because once you allow Sudo to run as administrator, it will run each application in the command line as though you’d elevated each one individually. Again, there’s lots of other ways to do this (like running an administrator level PowerShell window and launching everything from there) but I’m of the opinion that there can’t be too many ways to skin a cat.

Source code to RunOnlyOne and Sudo.

I’ve been crazy busy the last few weeks, but I’ve been really rather distracted from my main project and it’s past time I got back to it. To really feel like I’ve moved on, I need to write a bunch of articles here and publish a couple of cool apps and some source code so that I can feel like I’ve reached a release point. What I’ve been playing with in all this coding is the new technology that’s been coming out of Microsoft in the last couple months: PowerShell, .NET 3 and WPF, and Windows Vista so you may or may not actually be able to use these apps …

The Vista Thumbnailer is a really slick little app that shows off some of what Vista can do … and some of what WPF can do. I’ll write more about it in the morning, because there’s some interesting things I learned in the coding of it, but in the meantime, you can download Vista Thumbnailer (7-Zip file with a config file). The only thing you really need to know is that there’s a hotkey: Win+X which will bring Thumbnailer back to the foreground even if it’s minimized in the tray. I’ll make the hotkey configurable in version 2, but for now you’re stuck with Win+X. The rest you can figure out from the screenshots (0 1 2) and by reading the tooltips on the buttons.

Play around. Let me know what you think.

(Oh, source code is here with your usual choice of BSD/Ms-PL/GPL)

[New] Edit: Continuing

So … I’ve had a lot of questions about this app during it’s development (from a few friends in our IRC channel) so it’s clear that I should try to at least give the highlights of how it works.

Thumbnails

By now you’ve probably seen more than your fill of screenshots of Windows Vista’s semi-transparent windows, and maybe you’ve had a chance to try Vista and seen these live-updating thumbnails on the Alt+Tab window, the Flip3D Win+Tab task switcher, and even the task-bar’s mouse-over (or Win+T) popups. All of this is possible because of the way Windows does desktop compositing using a new Desktop Window Manager. This DWM is actually a process which runs all the time when you have the “Aero” interface turned on, but it’s also an API exposed through dwmapi.dll … and one of the deepest fundamental changes to the way Windows work in Vista. Let me quote from “one of the developers” blogs:

... The way an application gets pixels on the screen has fundamentally changed. [In the past] applications were asked by Windows to paint their visible region, and they would paint directly to the buffer that was to be displayed by the video card. With Windows Vista, applications are asked by Windows to paint their entire surface to an offscreen surface (alternatively known as a bitmap, buffer, or texture), and it’s up to the DWM to take all of these offscreen surfaces, and “compose” them together to the onscreen buffer.

Because the windows are rendered “offscreen” and without regard to what part of the window might actually be visible … the visual representation can be reused in many places very cheaply — that is, since the visual representation is just a cached picture, there’s very little CPU cost involved in repainting it in many places … and the caching and repainting are easily handled by the DWM. Now, the DWM also does lots of other cool things, like using DirectX and hardware accelleration to do all this extra rendering of these cached surfaces, but despite appearances, this isn’t really an article about the DWM — we’re here to talk about JUST the thumbnails. Greg Schechter again:

Thumbnails in the DWM are not static snapshots of a window. They’re dynamic, constant connections between a thumbnail source window, and a place on a target window that that source window will get a “thumbnail rendering”.

Basically, the APIs in the Desktop Window Manager allow you to ask for a certain portion of one Window’s screen to be painted over (at some specified level of opacity) with all or part of the contents of another Window’s screen. In every sense, the thumbnail is just as live and up-to-date as the actual window (since it is, in fact, being painted by the same process).

So anyway, what I did is I took a “Thumbnail” class from Douglas Stockwell and enhanced it a bit … it’s still not quite perfect, but it’s trivially easy to use now: just pass it a Window handle and it hooks itself up and renders within it’s available bounds — mostly.

Glass Effect

The Vista Thumbnailer app also showcases a couple of other slick API features. First, I added a couple of simple wrappers to DwmExtendFrameIntoClientArea and DwmIsCompositionEnabled so that you can easily get the translucent “glass” effect on your whole window, or write, for instance: if( !NativeMethods.IsCompositionEnabled ) { MessageBox.Show( "Sorry you can't use this feature!" ); }

Hotkeys

I also wrote a global hotkey manager class which can be easily added to WPF applications that want to register global hotkeys. VistaThumbnailer only has one, to focus it (you can change it by editing the .config file).

These are global hotkeys, not like the “Ctrl+O” for opening a file, but like the Win+R to bring up a run dialog. They’re registered through Window’s RegisterHotkey and UnregisterHotkey APIs, and you get notified of them via window messages (but my HotkeyManager class will handle the WM_HOTKEY message for you). Here’s the short-form for how to use them (you can grab the source if you’d like to borrow the class, but I’ll be re-releasing this in a few days with some enhancements I’ll detail below).

using GeoCore.Win32;

public class Window1 : System.Windows.Window {
   private WPFHotkeyManager hkManager;
   // You need to keep a reference to the hotkey around
   // Otherwise you won't know *which* hotkey was pressed!
   private Hotkey focusHotkey; 

   public Window1() {
      // ... somewhere ... hook SourceInitialized (you can do it in the XAML)
      SourceInitialized +=new EventHandler(Window1_SourceInitialized);
   }
   
   void Window_SourceInitialized(object sender, EventArgs e)
   {
      // make the whole window glassy, preserving the border
      NativeMethods.TryExtendFrameIntoClientArea(this, BorderThickness);

      // create the hotkey manager in "SourceInitialized" because
      // it doesn't accept hotkeys anyway until the window is Initialized
      // -- this is because it needs a window handle.
      hkManager = new WPFHotkeyManager(this);
      // register for the hotkey event, otherwise ... nothing happens.
      hkManager.HotkeyPressed += new WPFHotkeyManager.HotkeyPressedEvent(Hotkey_Pressed);
      // create a hotkey -- remember, this is global (and be careful of the types here)
      focusKey = new Hotkey(ModifierKeys.Win, Keys.X);
      // register the hotkey
      hkManager.Register(FocusKey);
   }


   void Hotkey_Pressed(System.Windows.Window window, Hotkey hotkey)
   {
      // an action for each hotkey ....
      if (hotkey.Equals(FocusKey))
      {
         Show(); Activate();
      }
   }
}
 

I want you to notice that I had to create my own Keys enumeration in this, because the WPF developers unbelievably chose to use an ordering for their Key enumeration which is inconsistent with the Windows API ordering. You could use the System.Windows.Forms enumeration, but that would require adding a reference to the Forms assembly in your WPF application just to get a silly enum! I have to say that this seems to be absolutely the WORST design decision I’ve seen in the .NET Framework — not only are they duplicating enumerations which exist elsewhere, but they couldn’t even copy-and-paste it in order?

Chrome Free Windows!

I thought I’d mention this, just in case you haven’t seen it before. Irregular shaped windows are trivially easy to do in WPF. All you have to do is add the following attributes to your Window tag: WindowStyle=“None” AllowsTransparency=“True” Background=“Transparent”

Further Development

DWM API Thumbnails

There are still a few tweaks that need to be made to the Thumbnail Image control. It doesn’t adjust when the source window is changed until you resize the window (because it doesn’t check the size except when WPF asks it to) and I’m not sure if it’s possible apart from re-checking the source window shape on a timer. I’m a little afraid that I’m leaking the thumbnail window so I need to wrap them in a Safe Handle, and override OnUnloaded to clean up.

I’m also curious if there’s a way, in the DWM api, to get these thumbnails batched into a video or saved to an image handle so you can use them for screenshots … I’ll have to take some additional time to research that.

Hotkeys

There’s also some changes I want to make to the way my hotkeys class works. Right now you have to hang on to your Hotkey objects in order to be able to process the hotkey events correctly (unless you only have a single Hotkey) ... and it’s not possible to use a switch statement on the event, so if you have a lot of hotkeys, it gets a bit ridiculous. I initially did this because I didn’t like trusting the user to come up with unique Hotkey Id’s, but now I’m thinking that it might be better if you could use just the Ids and create yourself an enumeration for them. I need to play with this, because one of my key use scenarios is having windowless plugins be able to register and process their own hotkeys — which makes enums not completely safe, because different pieces of code are dynamically creating hotkeys.

I also don’t like not being able to register the hotkeys during construction. My first attempt to fix that is a version of this HotkeyManager (which I’ll release shortly) that creates it’s own window — this means you don’t have to worry about calling it in SourceInitialized, but it’s a pretty expensive fix if you’ve already got a window. I’m going to try doing it another way — where hotkeys registered before the handle is initialized will be queued for registration later, and this should be a better solution in most cases. I do have a System.Windows.Forms version (which I will release with all the other versions) that doesn’t have this problem (because with Windows.Forms you get a window handle on construction), but again, I don’t like including that whole assembly for something fairly trivial.

Hopefully I’m going to get better at these writeups as time goes on, because I feel like this one is a bit rambling. Questions and comments are welcome!