Scott Hanselman

The Weekly Source Code 8

October 19, 2007 Comment on this post [10] Posted in Source Code
Sponsored By

In my new ongoing quest to read source code to be a better developer, I now present the eighth an infinite number of a weekly series called "The Weekly Source Code." Here's some source I'm reading this week that I enjoyed.

  • The Vista Battery Saver is a fun and simple little application that shuts off Aero and the Sidebar when you're running on batteries. The source is up at CodePlex. He registered his application with Windows for Power Notifications. Windows will send his application a Window Message when the system's power state changes.
  •     //In the main WinForm, he overrides the WndProc
        protected override void WndProc(ref Message m)
        {
             base.WndProc(ref m);
             if (m.Msg == PowerMngr.WM_POWERBROADCAST)
             {
                 PowerMngr.GetManager().PowerSettingChange(m);
             }
        }
    
            //Earlier he selects the messages he's interested in.
            internal void RegisterForPowerNotifications(IntPtr hwnd)
            {
                hPowerSrc = RegisterPowerSettingNotification(hwnd,
                ref GUID_ACDC_POWER_SOURCE,
                DEVICE_NOTIFY_WINDOW_HANDLE);
    
                hBattCapacity = RegisterPowerSettingNotification(hwnd,
                ref GUID_BATTERY_PERCENTAGE_REMAINING,
                DEVICE_NOTIFY_WINDOW_HANDLE);
    
                hMonitorOn = RegisterPowerSettingNotification(hwnd,
                ref GUID_MONITOR_POWER_ON,
                DEVICE_NOTIFY_WINDOW_HANDLE);
    
                hPowerScheme = RegisterPowerSettingNotification(hwnd,
                ref GUID_POWERSCHEME_PERSONALITY,
                DEVICE_NOTIFY_WINDOW_HANDLE);
            }
    
            [DllImport(@"User32", SetLastError = true, EntryPoint = "RegisterPowerSettingNotification", CallingConvention = CallingConvention.StdCall)]
            private static extern IntPtr RegisterPowerSettingNotification(
                IntPtr hRecipient,
                ref Guid PowerSettingGuid,
                Int32 Flags);
  • Patrick Smacchia released a Strongly Typed Path Library today. You know Patrick, he's NDepend-guy and he rocks. He includes a Class Diagram as well:
    PathClassDiagram
    I'll let you go check it out, because you should. I think a class this smart would be a nice addition to the BCL. Here's some of his tests showing the usage of the library. Make careful note of the !'s inside the Asserts. They weren't totally obvious to me. I usually use == false. I find it easier to read.
  •       //
          // Path string validation
          //
          string reason;
          Debug.Assert(PathHelper.IsValidAbsolutePath(@"C:\Dir2\Dir1", out reason));
          Debug.Assert(!PathHelper.IsValidAbsolutePath(@"C:\..\Dir1", out reason));
          Debug.Assert(!PathHelper.IsValidAbsolutePath(@".\Dir1", out reason));
          Debug.Assert(!PathHelper.IsValidAbsolutePath(@"1:\Dir1", out reason));
          Debug.Assert(PathHelper.IsValidRelativePath(@".\Dir1\Dir2", out reason));
          Debug.Assert(PathHelper.IsValidRelativePath(@"..\Dir1\Dir2", out reason));
          Debug.Assert(PathHelper.IsValidRelativePath(@".\Dir1\..\Dir2", out reason));
          Debug.Assert(!PathHelper.IsValidRelativePath(@".\Dir1\..\..\Dir2", out reason));
          Debug.Assert(!PathHelper.IsValidRelativePath(@"C:\Dir1\Dir2", out reason));
  • I was talking to John Lam this week and he said: "BTW I’m having a ton of fun with C# 3.0 – it really is a beautiful language. Here’s an app that I wrote today that dumps all of our implemented Ruby methods to a YAML file." It'll be up on RubyForge later this week, but here's a snippet. It's about 100 lines and it takes a while to sink in. It's simple and it's a nice way to use LINQ against Reflection and the extension methods that use generics is nice and clean. Start at the Main() at the bottom and work your way around. Sure it could be shorter and hackier, but he appears to be balancing functionality with his own sense of aesthetic.
  • using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using Ruby;
    using Ruby.Extensions;
    using Microsoft.Scripting.Utils;
    using Ruby.Runtime;
    
    namespace IronRuby.Library.Scanner {
        static class ExtensionMethods {
            public static IEnumerable<T> SelectCustomAttributes<T>(this Type type) where T : Attribute {
                return type.GetCustomAttributes(typeof(T), false).Cast<T>();
            }
    
            public static IEnumerable<T> SelectCustomAttributes<T>(this MethodInfo method) where T : Attribute {
                return method.GetCustomAttributes(typeof(T), false).Cast<T>();
            }
        }
    
        class RubyClassInfo {
            public Type ClrType { get; set; }
    
            public delegate void Block(IEnumerable<RubyMethodAttribute> methods);
    
            public string Name {
                get { return ClrType.SelectCustomAttributes<RubyClassAttribute>().First().Name ?? ClrType.Name; }
            }
    
            private Type LookupExtensionModuleType(IncludesAttribute attr) {
                Type includedType;
                Program.ExtensionModules.TryGetValue(attr.Type, out includedType);
                return includedType ?? attr.Type;
            }
    
            private void GetMethodNames(Type t, Block accumulate) {
                var methods = (from m in t.GetMethods()
                               where m.IsDefined(typeof(RubyMethodAttribute), false)
                               select m.SelectCustomAttributes<RubyMethodAttribute>().First());
    
                accumulate(methods);
    
                foreach (IncludesAttribute attr in t.SelectCustomAttributes<IncludesAttribute>()) 
                    GetMethodNames(LookupExtensionModuleType(attr), accumulate);
            }
    
            private IEnumerable<string> GetMethodNames(RubyMethodAttributes methodType) {
                var result = new List<string>();
                GetMethodNames(ClrType, methods => 
                    result.AddRange((from m in methods
                                     where m.MethodAttributes == methodType 
                                     select m.Name).Distinct()));
                result.Sort();
                return result;
            }
    
            public IEnumerable<string> InstanceMethods {
                get { return GetMethodNames(RubyMethodAttributes.PublicInstance); }
            }
    
            public IEnumerable<string> SingletonMethods {
                get { return GetMethodNames(RubyMethodAttributes.PublicSingleton); }
            }
        }
    
        class Program {
            static IEnumerable<RubyClassInfo> GetRubyTypes(Assembly a) {
                return from rci in
                            (from t in a.GetTypes()
                             where t.IsDefined(typeof(RubyClassAttribute), false) 
                                   && !t.IsDefined(typeof(RubyExtensionModuleAttribute), false) 
                             select new RubyClassInfo { ClrType = t })
                       orderby rci.Name
                       select rci;
            }
    
            static Dictionary<Type, Type> GetExtensionModules(Assembly a) {
                var modules = from t in a.GetTypes()
                              where t.IsDefined(typeof(RubyExtensionModuleAttribute), false)
                              select new { Type = t, Attribute = t.SelectCustomAttributes<RubyExtensionModuleAttribute>().First() };
                
    
                var result = new Dictionary<Type, Type>();
                foreach(var m in modules)
                    result[m.Attribute.Extends] = m.Type;
                return result;
            }
    
            const string RubyAssembly = @"Ruby, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
            internal static Dictionary<Type, Type> ExtensionModules;
    
            static void DumpMethods(IEnumerable<RubyClassInfo> types, Func<RubyClassInfo, IEnumerable<string>> getMethods) {
                foreach (RubyClassInfo rci in types) {
                    Console.WriteLine("{0}:", rci.Name);
                    foreach (string methodName in getMethods(rci))
                        Console.WriteLine("  - {0}", methodName);
                }
            }
    
            static void Main(string[] args) {
                var name = new AssemblyName(RubyAssembly);
                var a = Assembly.Load(name);
    
                ExtensionModules = GetExtensionModules(a);
                var types = GetRubyTypes(a);
    
                DumpMethods(types, t => t.InstanceMethods);
                DumpMethods(types, t => t.SingletonMethods);
            }
        }
    }

Feel free to send me any links to cool source you find.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
October 19, 2007 11:13
The codesnippets are not really good to read because of bad formation. Perhaps you are able to correct it...

Would be very nice!
October 19, 2007 11:19
agreed. impossible to read.
October 19, 2007 11:24
Already fixed. It was a whitespace thing.
October 19, 2007 13:07
The code snippets don't work in Google reader, but I guess it does bring me to your actual site... :)
October 19, 2007 17:57
Yeah your code snippets always look horrible in the RSS. There is also always a big chunk of CSS beneath each code snippet, like this...

.csharpcode, .csharpcode pre {font-size:small;color:black;font-family:consolas, "Courier New", courier, monospace;background-color:#ffffff;} .csharpcode pre {margin:0em;} .csharpcode .rem {color:#008000;} .csharpcode .kwrd {color:#0000ff;} .csharpcode .str {color:#006080;} .csharpcode .op {color:#0000c0;} .csharpcode .preproc {color:#cc6633;} .csharpcode .asp {background-color:#ffff00;} .csharpcode .html {color:#800000;} .csharpcode .attr {color:#ff0000;} .csharpcode .alt {background-color:#f4f4f4;width:100%;margin:0em;} .csharpcode .lnum {color:#606060;}
October 19, 2007 18:07
Hi Scott,
If you or your readers are using Windows Live Writer, I have a code formatter plug-in for it at http://stevedunns.blogspot.com/2007/09/new-version-of-code-formatter-plug-in.html

Lanugages include:
* Assembly
* BatchFile
* CSharp
* CSS
* HTML
* INIFile
* Java
* JScript
* Lua (pronounced LOO-ah)
* MSIL
* Pascal
* Perl
* PHP
* PowerShell
* Python
* SQL
* VBDotNet
* VBScript
* XAML
* XML


There's also some source code to read if that takes your fancy!

Cheers,

Steve

October 19, 2007 18:58
Don't forget you can just put Vista in power saver mode when running on batteries and it'll disable all that junk for you. And it'll do all the other things that make your battery last longer.
October 19, 2007 19:26
Sorry about the code snippets. Any ideas on what to fix?
October 19, 2007 21:33
Interesting - I wonder why he used P/Invoke for the power management stuff. Looks to me like that info is available through managed APIs (SystemEvents, ...)
October 23, 2007 9:09
Apropos John Lam's code snippet - C# is looking like the overly verbose Java with every passing day. There is something to be said for the aesthetics of a language. That's one of the primary reasons I love Ruby.

Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.