Posts Tagged ‘PInvoke’

There are so many fun things you can do in Windows when your scripting language allows you to make PInvoke calls to Win32 APIs … but I have to say it’s amazing how many things have been added to Windows recently and still left out of the .Net framework …

Anyway, on to the Aero Peek stuff. If you haven’t seen it, Aero Peek is a feature of Windows 7, which lets you get a peek at your desktop, or at a single window for a moment. Basically, you can press Win+Space (the Windows logo key and the space bar) and all of your open windows instantly turn transparent, revealing … whatever was on your desktop: wallpaper, icons, and gadgets. You can also use it by hovering your mouse on the right corner of the taskbar, or you can peek at a single window by hovering over it’s taskbar button and then over it’s thumbnail.

In any case, I have a couple of windows which I would like to have stay visible on the desktop when I hit the aero peek hotkey: Rainlendar and Miranda. It turns out there’s a simple API call for this: DwmSetWindowAttribute which lets you set the DWMWA_EXCLUDED_FROM_PEEK attribute to ENABLED … causing a window to no longer hide when you press that hotkey. Of course, that API call should be made by those apps, in response to a user setting (so I’ve told their authors about it), but it doesn’t have to be (so I wrote a script to do it myself).

In the old days, I would have written a little systray app which would give you a popup list of all windows, or perhaps added a menu item to a window’s right-click menu … and I would have had to deal with creating some way to persist which apps you wanted to apply this to, and then I could have applied the setting to them whenever you opened them.

But now, I have PowerShell. I don’t need to give you menus and store settings, because I can just let you edit a little script instead.

So here’s a script which will let you turn off Aero Peek transparency for windows by window title and/or process name … Once you have this function available, you can keep Rainlendar’s calendar, tasks, and event windows all visible by just running Remove-AeroPeek -Process Rainlendar2 or you can keep your Miranda contact list visible by running Remove-AeroPeek "Miranda IM" (although you should not that depends on the window title matching just that one window — and Miranda lets you change what your title is, so you may have to adjust it).

Of course, that script really deserves explanation, because it’s showing off quite a few advanced things…

The first thing is that I’m using a Try/Catch block in the BEGIN block to make sure I only execute that code once. You can’t call Add-Type with the same code multiple times in a single PowerShell session, because the type will already exist when you call it the second time. So the code in the try block will throw an exception if the type doesn’t already exist, and in the catch handler, we’ll create the type, and define the other function we need.

Add-Type is a super-powerful cmdlet which compiles code on the fly (or imports types from pre-compiled assemblies). In this case we’re using it to import a little class called Dwm which I started writing myself from PInvoke.net and the MSDN documentation, but then eventually copied most of from a NeoWin forum thread… All this class really does is define the API function and the flags we need to pass to it, and then provides a wrapper for the DwmSetWindowAttribute call. We could have written that call in PowerShell, but at the end of the day, once you start compiling C# code in PowerShell, it’s hard to know when to stop ;)

The Select-Window function is (yet another customized version of) a function I wrote awhile back on PoshCode as part of my (still in progress) rewrite of WASP to use the UIAutomationClient … I’ve just modified it to add only the three properties of the window that I’m interested in: Title and ProcessId (for identifying the correct windows) and Handle (for passing to the DwmSetWindowAttribute call). It uses the RootElement property of System.Windows.Automation.AutomationElement to do a search, and then a series of GetCurrentPropertyValue calls to determine the Name, ProcessId, and NativeWindowHandle of the windows it finds.

That’s pretty much all there is to it, other than filtering out the window(s) that we want and actually calling the API. I think I’m going to have to play a little bit more with this to see what else we can do — I’ve already realized that this means we can make little widgets with PowerBoots and set them to stick around just like regular desktop gadgets …

Reblog this post [with Zemanta]

I wrote yesterday about the WPF Snap-To Behavor that I created, and showed you how simple it is, but I skipped over where the magic happens, so I thought I’d go through how I created the Native Behaviors collection class, because there are a few cool tricks in here that I wanted to share with WPF developers at large (even if you’re not interested in hooking the Window Procedure).

The framework for Native Bahaviors is made up of just two classes, the first of which is basically 3 lines of code.

NativeBehavior is the abstract base class for behaviors, and consists of just definitions for the mandatory abstract GetHandlers() method (where you return an IEnumerable collection of mappings from Window Messages to your delegate methods) and the two optional (virtual) methods AddTo and RemoveFrom which are called when your behavior is initially added to a window (generally before the Window is initialized).

NativeBehaviors is an ObservableCollection of NativeBehaviors, obviously ;) . But it’s ever so much more than that. First of all, it has the NativeBehaviors attached property, but it also has the code for actually hooking a WPF window to get the Window Messages, and a WndProc which processes each message against the mappings retrieved from the various NativeBehaviors that have been registered.

Lets start with the attached dependency property. There’s a very clever (and problematic) trick in the way this property is exposed. If you look at this code, you’ll see I create a private NativeBehavior dependency property, and then create public Get/Set accessors for “Behavior” which just call the NativeBehavior property. The reason for this is that if the dependency property is public, or if the public accessors even have the same name … the XAML parser finds the dependency property and uses it directly (bypassing the get/set accesors), which means you have to have an extra element in your XAML markup to initialize the NativeBehaviors collection, or you get something like this screenshot.

The behavior collection doesn't get created...

So instead, we hide the dependency property, and supply a getter which is backed by the dependency property. I should not that although this works great in the .Net Framework, it’s not recognized properly by all of the tools (including Resharper 4.1 and even Expression Blend), so you may have to fiddle with things.


      private static readonly DependencyProperty NativeBehaviorsProperty =
          DependencyProperty.RegisterAttached(
          "NativeBehaviors", typeof(NativeBehaviors), typeof(NativeBehaviors),
          new FrameworkPropertyMetadata(null));
      // A public setter (for the non-existent "Behaviors" property)
      public static void SetBehaviors(Window window, NativeBehaviors behaviors)
      {
         if (window == null){ throw new ArgumentNullException("window"); }
         window.SetValue(NativeBehaviorsProperty, behaviors);
      }
      // The public getter  (for the non-existent "Behaviors" property)
      public static NativeBehaviors GetBehaviors(Window window)
      {  // instead of GetValue, call the accessor!
         return GetNativeBehaviors(window);
      }
      // This dependency property getter makes sure it returns a collection
      private static NativeBehaviors GetNativeBehaviors(Window window)
      {
         if (window == null) { throw new ArgumentNullException("window"); }
         // This is the plain old normal thing:
         var behaviors = (NativeBehaviors)window.GetValue(NativeBehaviorsProperty);
         // Our raison d'être: create a new collection if there isn't one yet
         if (behaviors == null) { behaviors = new NativeBehaviors(window); }

         return behaviors;
      }
 

There’s a little more to it in the actual class source code, I’m glossing over the simplest parts, and leaving out all the XML documentation comments too. We override the CollectionChanged event so that we can hook new Behaviors as they arrive, and we make sure to hook the WndProc whenever the Target Window is set:


protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs nccea)
{
   base.OnCollectionChanged(nccea);
   // design mode bailout because NativeBehaviors don't work in DesignMode
   if (DesignerProperties.GetIsInDesignMode(Target)) { return; }
   // notify new behaviors they are being hooked up, and track their handlers
   if (nccea.Action == NotifyCollectionChangedAction.Add ||
       nccea.Action == NotifyCollectionChangedAction.Replace)
   {
      foreach (NativeBehavior behavior in nccea.NewItems)
      {
         behavior.AddTo(Target);
         Handlers.AddRange(behavior.GetHandlers());
      }
   }

   // notify removed behaviors they are being unhooked, and stop tracking their handlers
   if (nccea.Action == NotifyCollectionChangedAction.Remove ||
       nccea.Action == NotifyCollectionChangedAction.Replace)
   {
      foreach (NativeBehavior behavior in nccea.OldItems)
      {
         behavior.RemoveFrom(Target);
         foreach (var h in behavior.GetHandlers())
         {
            Handlers.Remove(h);
         }
      }
   }
}

// Hook the Window when its added
// but keep only a week reference to it...
public Window Target
{
   get
   {
      if (_owner != null) {
         return _owner.Target as Window;
      } else return null;
   }
   set
   {
      // design mode bailout (in Design mode there's no window, and no wndproc)
      if (DesignerProperties.GetIsInDesignMode(value)) { return; }

      if (_owner != null && WindowHandle != IntPtr.Zero)
      {
         HwndSource.FromHwnd(WindowHandle).RemoveHook(WndProc);
      }

      Debug.Assert(null != value);
      _owner = new WeakReference(value);

      // Check for an HWND to determine if the Window has been loaded.
      WindowHandle = new WindowInteropHelper(value).Handle;

      if (IntPtr.Zero == WindowHandle)
      { // If there's no handle, set the hook when the Source is initialised.
         value.SourceInitialized += (sender, e) =>
         {
            WindowHandle = new WindowInteropHelper((Window)sender).Handle;
            // hook the WndProc
            HwndSource.FromHwnd(WindowHandle).AddHook(WndProc);
         };
      }
      else
      { // hook the WndProc
         HwndSource.FromHwnd(WindowHandle).AddHook(WndProc);
      }
   }
}
// the weak reference to the actual window...
private WeakReference _owner;
 

And finally, the last part of the puzzle is my actual WndProc implementation, which has a minor drawback in that we can hypothetically have multiple behaviors which process the same window message … and may each return a different value (which we cannot reconcile). For now I’m just returning the last (non-zero) result (in actuality, all of the behaviors I’ve written thus far return zero).


private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
   Debug.Assert(hwnd == WindowHandle); // Only expecting messages for our cached HWND.

   // cast and cache the message
   var message = (NativeMethods.WindowMessage)msg;
   // NOTE: we may process a message multiple times
   // and we have no good way to handle that...
   var result = IntPtr.Zero;
   foreach (var handlePair in Handlers)
   {  if (handlePair.Key == message)
      {
         var r = handlePair.Value(wParam, lParam, ref handled);
         // So, we'll return the last non-zero result (if any)
         if (r != IntPtr.Zero) { result = r; }
   }  }
   return result;
}
 

That pretty much covers the framework. The actual behaviors can be fairly simple like my Snap-To behavior (which is actually too simple), or extremely complex like my latest behavior, which is a port Joe Castro’s custom Window ‘Chrome’ to my behavior framework, and I’m hoping some of you will choose to write new ones and submit them as patches to the CodePlex project (for now, I’m just piggybacking it on the PoshConsole project). But in any case, the latest code is available via subversion on CodePlex, and you can download today’s snapshot here.

Reblog this post [with Zemanta]

While working on my WPF PowerShell console, I’m working on implementing PSRawUserInterface, and had to implement a method called ReadKey which returns a KeyInfo object. KeyInfo is a pretty simple struct class with four properties:

  • VirtualKeyCode
  • Character
  • ControlKeyState
  • KeyDown

So it doesn’t seem like it would be a real problem … just handle the KeyDown event or PreviewKeyDown event on the WPF control, right? Well, no. Because all of these just use a KeyEventArgs parameter which has a Key property which doesn’t map to a virtual key code (why isn’t the WPF Key enumeration in the right order? It’s ridiculous), and there’s no character information at all.

Thankfully, it is possible to get this information using PInvoke, but I wouldn’t want to try to do this in Silverlight. ;)

Here’s how it goes:

First, you need to get the VirtualKey code. Thankfully, there’s a simple class called KeyInterop, which exposes a static method VirtualKeyFromKey that gets us this information.

Then, we need to get the character. This is much trickier. First we have to get the keyboard state and then we have to map that VirtualKey we got in the first step to a ScanCode, and finally, convert all of that to Unicode, because .Net doesn’t really speak ASCII ;)

The rest of the code is pretty clear, I hope… Read the rest of this entry »

I have a problem with my laptop where I connect to my home network and my work network, and my school network … and I have to use different proxy settings for Windows internet connection settings (which are used by virtually all .Net apps, including PowerShell) by default…

Of course, there are a lot of different apps that can manage those settings (and more) automatically using Windows NLA to trigger. However, I have an extra special requirement: when I plug in at work or at home, I want to run Synergy on the laptop as a client … but the name and ip of the host is different, of course — so I need to stop synergy and restart it with a different server name … something I can easily accomplish from a script or batch file … but changing proxies is a bit trickier.

I thought it would a simple call to a .Net library method, but after much searching, the only way of setting or retrieving Internet options seems to be through the old WinInet API, using InternetSetOptions (or InternetQueryOption to read them). Of course, to use these, you have to map the INTERNET_PER_CONN_OPTION_LIST and INTERNET_PER_CONN_OPTION structures to C#, and do whole lot of marshalling and manual memory management.

I did find some C# mappings for the Option structure on PInvoke.net but not for the others. I actually started writing them all by hand and then found a “recipe” in the (see the examples link) C# 3.0 Cookbook for retrieving Internet settings which had versions of all the structures I needed, as well as definitions for the flags I wanted. So… without further ado, let me share the code with you … Read the rest of this entry »

Search My Content