I know the answer (it's 42)

A blog on coding, .NET, .NET Compact Framework and life in general....

Posts
  • I know the answer (it's 42)

    C# 3.0: Lambda expressions. I don't like it that much

    • 59 Comments

    This is the my third post on the series of post I am making on C#3.0 after it got declared on PDC. See the previous two here and here.

    It's not that I do not like lambda expression, I just don't like that its being supported in C#. Lets first see what its like and then I'll clarify on why I do not like it. If you are just interested on why I do not like it, go to the end of this post.

    What is Lambda Expression

    In C#2.0 anonymous methods were introduced ( :(  I'm already using past tense on a product that is still not formally released). It required a little cumbersome syntax to create in-line function block like the ones supported by many functional languages. Lambda expressions in C# along with type inference give a cleaner (????) way of declaring and using anonymous methods.

    Lambda expressions are based on lambda calculus. Many functional languages like Lisp use lambda notations to define functions. Typical lambda expressions in C# can contain both expressions and or statement blocks.

    x => 2 * x // this is a expression
    y => {return 2*x; } // this is a statement block

                        //
    and not supported in the PDC bits.

    Here the => is the lambda operator.

    The following delegate and lambda expression are equivalent and the lambda expression here is automatically converted into a corresponding delegate.

    delegate T Func<T>(T t);
    Func
    <int> funcDel = delegate(int x)
                        {
                            return
    x + x;
                        };

    Func<int> lambda = x => x + x;

    Console
    .WriteLine(funcDel(5));
    Console.WriteLine(lambda(5));

    For the lambda expression the type can be explicitly specified or it can be implicit and the complier can figure it out. So the above expression could be written as

    Func<int> lambda = (int x) => x + x;

    Lambda with Extension methods

    Writing predicate functions for the extension methods becomes real easy with  lambda expressions. The System.Query namespace comes with nifty extension methods which use predicates. The following using the Where extension method prints out all the integers in the array which is less than 3

    int[] a = new int[] { 1, 2, 2, 3, 3, 5, 6 };
    var lessThan3 = a.Where(x => x < 3);
    foreach(var val in
    lessThan3)
        Console.WriteLine(val);

    Type Inference and Lambda Expression

    When a generic method is called without explicitly giving its type then the compiler can infer the type. In the following case both calls to GenericFunc is equivalent and will print System.Int32

    static void GenericFunc<T>(T t)
    {
        Console
    .WriteLine(t.GetType().ToString());
    }

    GenericFunc(5); // Type is inferred
    GenericFunc<
    int>(5);

    Just like any other expression when a lambda expression is passed as a parameter to a generic function it is used to infer the type. Lets take the following example which is a modified version of the one used in the C# 3.0 spec

    delegate R Func<A, R>(A a);

    // the generic function
    static
    Z FuncInfer<X, Y, Z>(X value, Func<X, Y> f1, Func<Y, Z> f2)
    {
        return
    f2(f1(value));
    }

    var size = FuncInfer(@"c:\vcvars32.bat", s => new FileInfo(s), t => t.Length);

    Lets see how the type inference happens here.

    • Since the first parameter is a string, compiler looks at it and infers X to be a string.
    • For the first lambda expression the input type is X so s becomes a string. Since it returns FileInfo the return type of it and hence Y becomes FileInfo.
    • For the second lambda expression Y is the input type and so t is FileInfo.
    • The second lambda returns FileInfo.Length so Z becomes long and hence size is a long and contains the size of the file passed as the first argument.

    Why I don't like lambda expression in C#

    C# has originally developed from C++ /Java and is (was :^) ) a strongly typed object-oriented language. The new features being introduced like closure, continuation (yes, yes very limited continuation) in C#2.0 and now type inference, lambda expressions are de-generating the language. Even though there are people go gaga about continuation and lexical closures these are fundamentally functional language features and should be left to that. Introduction of bits and pieces of functional language features are not going to add value to C# and at the same time the surface area of C# is growing beyond what most developer can grasp.

    Every language has a domain of application and an audience. Most people who work in C# developing web-services and web-based applications today are not necessary computer science grads. For them these concepts are a huge variation from the way C# used to behave. Functional programming is for the academia and not from the industry and should be left as such.

    If I am asked, whether I'll use these language features, my answer will be maybe, and that is because the code written by me will be reviewed and maintained by people in MS who are fairly conversant with these. However, I think these features add burden to the learning curve of people who are not super interested in C# and should be avoided in favor of easier language constructs’ that might take couple of lines of code more, but would be more readable and maintainable.

    These are just my opinions and I'm sure the designers of C# had given a lot of thought before adding them, but I strongly feel that these features are just adding more surface area to the language and will mostly go unused by the masses.

  • I know the answer (it's 42)

    C# 3.0: I like Extension Methods

    • 24 Comments

    After the declaration of C# 3.0 I went ahead and installed the PDC bits. After reading through the language spec. I was very very very unhappy. I mean we were just getting excited over C#2.0 supporting generics, anonymous mehtods, Nullable types and then suddenly someone ruins all the fun by showing us C#3.0. C#2.0 already appears stale. Some great blogs on this are from Cyrus and Matt Warren

    The good part is that since I work in Microsoft, soon (after VS 2005 release I guess) we'd move to C#3.0 to dogfood it. So that means I'll not be required to wait for the super enhancements in C# for long!!!!

    I thought I'd try out the features of C#3.0 and write some stuff on it. Here goes the second one (the first is already there)

    Extension Methods

    With extension methods you can attach additional functionalities to an existing type even if you do not have access to it. For example I can write an  extension method Print() which prints each element of any collection on a different line and then invoke it on any collection such as

    List<string> first = new List<string>();

    first.AddRange (new string[] {"Hello", "how"});

    first.Print();

    Importantly note is that even though Print() is not a member of List<> but is still called as if its a method. There are a couple of restrictions in defining the extension method Print. All of which are marked in bold in the example below

    public static class Extensions

    {

    public static void Print<T>(this ICollection<T> col)

    {

    foreach(T t in col)

    Console.WriteLine(t);

    }

    }

    static void Main(string[] args)

    {

    List<string> first = new List<string>();

    first.AddRange (new string[] {"Hello", "how"});

    first.Print();

    }

    The method has to be a static method in a static class. The first parameter to the method has to be qualified using this and this first parameter indicates the types on which this extension method can be applied. Its important to note that this is just syntactic sugar and both the following calls are equivalent and legal.

    first.Print();

    Extensions.Print(first);

    So whats the benefit? I think this makes code more elegant and this can be used very much like C++ STL algorithms. Lets say I write a merge algorithm that merges two collections and then I'd be able to call this merge algorithm on any collection in a very elegant way. Following is the implementation of a merge algorithm

    using System;
    using
    System.Collections.Generic;
    // Will compile only with C#3.0 complilers
    namespace
    ExtensionMethodDemo
    {
        public static class
    Extensions
        {
            public static void Merge<T>(this ICollection
    <T> first, ICollection<T> second)
            {
                foreach(T t in
    second)
                    first.Add(t);
            }
       
    }

        class Program
        {
            static void Main(string
    [] args)
           
                List<string> first = new List<string
    >();
                first.AddRange (
    new string[] {"Hello", "how"
    });

                List<string> second = new List<string
    > ();
                second.AddRange (
    new string[] {"are", "you", "doing"
    });

                first.Merge(second);
            }
        }
    }

    Moreover the class libarary already ships with some standard extension methods (like standard algorithms of STL) and you can directly use them. Consider the following

    int[] a = new int[] {1, 2, 2, 4, 3};

    Console.WriteLine(a.Distinct().Count());

    Here two of the methods Distinct and Count are used and the combined result is that we get the number of distinct elements in the array and that is 4. This is really really cool.

    As a real life sample I wrote a pretty print extension method that prints the directory listing is a pretty fashion.

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Query;
    using System.IO;

    namespace ExtDemo
    {
       
        public static class Extensions
        {
            public
    static void PrettyPrint(this
    IEnumerable<FileInfo> fInfo)
            {
                ConsoleColor defColor = Console.ForegroundColor;
                string format = "{0, -17} {1,10} {2}";
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine(format,
    "Date", "Size (kb)", "File name");
                Console.ForegroundColor = defColor;
                foreach(FileInfo file in fInfo)
                Console.WriteLine(format, file.CreationTime.ToString(
    "dd/MM/yyyy hh:mm"), (float)file.Length / 1024, file.Name);
            }
        }
        class Program
        {
            static void Main(string[] args)
           
                DirectoryInfo
    dirInfo = new DirectoryInfo(@"c:\");
                dirInfo.GetFiles().PrettyPrint();
            }
        }
    }

    The C# 3.0 spec clearly calls out that since this is not a very discoverable feature and is somewhat misleading (very much like operator overloading) and so should be used sparingly. I think that this'll be more and more used by class libraries to implement STL like algorithms that can be run on containers.

  • I know the answer (it's 42)

    C# 3.0 : I don't like vars

    • 25 Comments

    Due to my upbringing in C/C++ somehow I feel uneasy whenever I see some like

    var a = 5;

    I guess this is ok in scripting languages. So when I heard that C# 3.0 is going to support implicit types for local variables that made me feel uneasy. I installed the PDC C# 3.0 bits (from the link mentioned before) and tried the following

    var a = 5;

    var s = "hello";

    Console.WriteLine(a.GetType());

    Console.WriteLine(s.GetType());

    The output was as expected a was System.Int32 and s System.String. However C# 3.0 is supporting implicit types and not the variant data type that many non-typed languages support. So the following will not compile

    var a = 5;

    a = "hello";

    Since C# is a strongly typed language once the implicit type has been inferred during compilation it does not change.

    While I do agree for things like LINQ implicit type is absolutely required but elsewhere as in the examples above vars make code more unreadable for me. Wherever I'll see a line of code with var I scroll up-down  to figure out what type it exactly is. Specially in some situation the type of variable has a lot to do with performance so if I see some thing like

    var al = Func1();
    ....
    ....
    for (i = 0; i < 10000000; i++)
    foreach (int el in al)
         total += el;

    I'd right click on al and say goto definition and see its a var. At this point its super important for me to figure out what's its type. If its an ArrayList and not a List<> then I have a huge perf degradation. Check out Rico Mariani's blog to find out why.

    <edited some stuff like the example above to add clarity based on the comments>
    < Fixed some syntax errors >

  • I know the answer (it's 42)

    C# 3.0

    • 0 Comments

    Even before C#2.0 is out (RTM) we already have some sneek preview of the C#3.0 features. Check out Cyrus's blog on this. Some time back I had said to some folks here that with some powerful functional programming fans :) in MS we are surely going to see some functional programming features creep into C#. Anonymous methods (lexical closure), continuation (yes I know in very limited format) got into 2.0 and now we have lambda expressions in 3.0.

    However I had expected more features from Spec# like contract verification and checked exception to have been introduced. Maybe they will be.

  • I know the answer (it's 42)

    Killing spree in India Development Center

    • 0 Comments

    Q.What does a bunch of disgruntled programmers do after work in MS IDC?
    A. They kill each other and shout with Joy when they see blood splatter all around.

    If you do not believe me drop into the 3rd floor lobby at IDC.

    Over the last couple of months Halo mania has taken over the IDC Burton (Team System) and DPM (Data Protection Manager) team. We all fight it out on the XBox on the third floor lobby. With the departure of our beloved Froddo who'd prove to be a far better assassin than a programmer, DPM is beating us hands down. However, some of the people in our team are not that far behind and we soon hope to frag DPM guys. The way Neeraj is ramping up on his core competency of shooting people with the hand gun, we soon hope to get our first win against DPM.

    Today was an auspicious day. The ladies in our group till now refrained from joining into the blood bath. But today two of them did. The sight of Neeti clapping with joy after killing me really shook me up. I never knew she'd get back to me like this for troubling her with weird bugs (she tests the features I work on :) ).

  • I know the answer (it's 42)

    Animation and Text in System tray using C#

    • 13 Comments

    Application running from the system tray is very common these days. Mostly these applications show an icon in the system tray (beside the clock) and almost always have a pop-up context menu.

    Adding additional features like showing text in the tray or show animations is also possible with little code. In this post I have discussed a class I wrote to accomplish this. If you are interested in using this enhanced SysTray class and do not care much about how it works jump to the last section Using SysTray.

    First things first: How do you show an icon in the system tray

    With .NET doing this is pretty simple and there is no need to play around with NOTIFYICONDATA and Shell_NotifyIcon of the Win32 world.

    You just need to create a instance of  System.Windows.Forms.NotifyIcon and fill out the relevant fields as in

    private NotifyIcon m_notifyIcon;

    m_notifyIcon = new NotifyIcon();

    m_notifyIcon.Text = text; // tooltip text show over tray icon

    m_notifyIcon.Visible = true;

    m_notifyIcon.Icon = icon; // icon in the tray

    m_notifyIcon.ContextMenu = menu; // context menu

    That’s it and the icon appear in the system tray and on right clicking on it the menu is popped up.

    Extending the NotifyIcon

    NotifyIcon is sealed so you cannot extend by inheritance. So I created a class SysTray which extends NotifyIcon by creating an instance of it in a field. The constructor takes in the tooltip text, the default Icon and the context menu.

    This class also adds other methods to show animation and text as explained below.

    Showing Text

    An application can only put in an icon in the tray. So the workaround is (there’s always one) to convert the text into an icon. ShowText API of the SysTray class just does this.

    public void ShowText(string text, Font font, Color col)

    {

        Brush brush = new SolidBrush(col);

     

        // Create a bitmap and draw text on it

        Bitmap bitmap = new Bitmap(16, 16);

        Graphics graphics = Graphics.FromImage(bitmap);

        graphics.DrawString(text, m_font, brush, 0, 0);

     

        // Convert the bitmap with text to an Icon

        IntPtr hIcon = bitmap.GetHicon();

        Icon icon = Icon.FromHandle(hIcon);

        m_notifyIcon.Icon = icon;

    }

    What we are doing here is creating a bitmap, drawing the text to be shown on it and then converting it to an icon. Since NotifyIcon can show an Icon in the tray it’ll show the textual icon just fine.

     

    Showing Animation

    Showing animation in the tray is equally easy by making an array of icons each of which represent an animation frame and then switching the icons in the tray on timer events. SysTray accepts the image frame in different formats

    public void SetAnimationClip (Icon [] icons)
    Here icon needs to be an array of 16x16 icon each for a frame


    public void SetAnimationClip (Bitmap [] bitmap)
    Here bitmap needs to be an array of 16x16 bitmap each for a frame

    public void SetAnimationClip (Bitmap bitmapStrip)
    bitmapStrip is a bitmap strip of size n16x16. Where n is the number of frames. SysTray class extracts the individual frames from this strip and converts it to icons and uses it for the animation. 

    The last method is the easiest to use. For this you need to prepare an animation strip image. The image needs to have each frame of animation side by side. Each frame is 16x16 pixels and the color to render transparent is the common background of all the frames. Let’s take

    The caller prepares this image by making it transparent and then calling SetAnimationClip

     

    private void button1_Click(object sender, System.EventArgs e)

    {

        m_sysTray.StopAnimation();

        Bitmap bmp = new Bitmap("tick.bmp");

        // the color from the left bottom pixel will be made transparent

        bmp.MakeTransparent();

        m_sysTray.SetAnimationClip(bmp);

        m_sysTray.StartAnimation(150, 5);

    }

     

    SetAnimationClip uses the following code to create the animation frame

    public void SetAnimationClip (Bitmap bitmapStrip)

    {

        m_animationIcons = new Icon[bitmapStrip.Width / 16];

        for (int i = 0; i < m_animationIcons.Length; i++)

        {

            Rectangle rect = new Rectangle(i*16, 0, 16, 16);

            Bitmap bmp = bitmapStrip.Clone(rect, bitmapStrip.PixelFormat);

            m_animationIcons[i] = Icon.FromHandle(bmp.GetHicon());

        }

    }

     

    To animate the frame StartAnimation starts a timer and in the timer the icons are changed to animate the whole sequence.

     

    public void StartAnimation(int interval, int loopCount)

    {

        if(m_animationIcons == null)

            throw new ApplicationException("Animation clip not set with    

                                            SetAnimationClip");

     

        m_loopCount = loopCount;

        m_timer.Interval = interval;

        m_timer.Start();

    }

     

    private void m_timer_Tick(object sender, EventArgs e)

    {

        if(m_currIndex < m_animationIcons.Length)

        {

            m_notifyIcon.Icon = m_animationIcons[m_currIndex];

            m_currIndex++;

        }

        ....

    }

     

    Using SysTray

     

    This is how you use the class

    1. Create and wire up your menu
          ContextMenu m_menu = new ContextMenu();                                   

          m_menu.MenuItems.Add(0, new MenuItem("Show",new

                               System.EventHandler(Show_Click)));

    2. Get an icon you want to show statically in the tray.

    3. Create a SysTray object with all the required information
          m_sysTray = new SysTray("Right click for context menu",
                      new Icon(GetType(),"TrayIcon.ico"), m_menu);
    4. Create image strips with the animation frames. For 6 frame strip the image will have a width of 6*16 and height as 16 pixels

          Bitmap bmp = new Bitmap("tick.bmp");
          // the color from the left bottom pixel will be made transparent

          bmp.MakeTransparent();
          m_sysTray.SetAnimationClip(bmp);
    5. Start animation indicating how many times you need to loop the animation and the frame delay
          m_sysTray.StartAnimation(150, 5);
    6. To stop animation call
          m_sysTray.StopAnimation();

    Sources - SysTray Implementation: SysTray.cs

     

     

    using System;

    using System.Windows.Forms;

    using System.Drawing;

     

    namespace Abhinaba.SysTray

    {

        /// <summary>

        /// SysTray class that can be used to display animated icons or text in the system tray

        /// </summary>

        public class SysTray : IDisposable

        {

            #region Constructor

            /// <summary>

            /// The constructor

            /// </summary>

            /// <param name="text">The toolip text</param>

            /// <param name="icon">The icon that will be shown by default, can be null</param>

            /// <param name="menu">The context menu to be opened on right clicking on the

            ///                    icon in the tray. This can be null.</param>

            public SysTray(string text, Icon icon, ContextMenu menu)

            {

                m_notifyIcon = new NotifyIcon();

                m_notifyIcon.Text = text; // tooltip text show over tray icon

                m_notifyIcon.Visible = true;

                m_notifyIcon.Icon = icon; // icon in the tray

                m_DefaultIcon = icon;

                m_notifyIcon.ContextMenu = menu; // context menu

                m_font = new Font("Helvetica", 8);

     

                m_timer = new Timer();

                m_timer.Interval = 100;

                m_timer.Tick += new System.EventHandler(this.m_timer_Tick);

     

            }

            #endregion // Constructor

     

            #region Public APIs

            /// <summary>

            /// Shows text instead of icon in the tray

            /// </summary>

            /// <param name="text">The text to be displayed on the tray.

            ///                    Make this only 1 or 2 characters. E.g. "23"</param>

            public void ShowText(string text)

            {

                ShowText(text, m_font, m_col);

            }

            /// <summary>

            /// Shows text instead of icon in the tray

            /// </summary>

            /// <param name="text">Same as above</param>

            /// <param name="col">Color to be used to display the text in the tray</param>

            public void ShowText(string text, Color col)

            {

                ShowText(text, m_font, col);

            }

            /// <summary>

            /// Shows text instead of icon in the tray

            /// </summary>

            /// <param name="text">Same as above</param>

            /// <param name="font">The default color will be used but in user given font</param>

            public void ShowText(string text, Font font)

            {

                ShowText(text, font, m_col);

            }

            /// <summary>

            /// Shows text instead of icon in the tray

            /// </summary>

            /// <param name="text">the text to be displayed</param>

            /// <param name="font">The font to be used</param>

            /// <param name="col">The color to be used</param>

            public void ShowText(string text, Font font, Color col)

            {

                Bitmap bitmap = new Bitmap(16, 16);//, System.Drawing.Imaging.PixelFormat.Max);

     

                Brush brush = new SolidBrush(col);

     

                Graphics graphics = Graphics.FromImage(bitmap);

                graphics.DrawString(text, m_font, brush, 0, 0);

     

                IntPtr hIcon = bitmap.GetHicon();

                Icon icon = Icon.FromHandle(hIcon);

                m_notifyIcon.Icon = icon;

     

            }

     

            /// <summary>

            /// Sets the animation clip that will be displayed in the system tray

            /// </summary>

            /// <param name="icons">The array of icons which forms each frame of the animation

            ///                     This'll work by showing one icon after another in the array.

            ///                     Each of the icons must be 16x16 pixels </param>

            public void SetAnimationClip(Icon[] icons)

            {

                m_animationIcons = icons;

            }

     

            /// <summary>

            /// Sets the animation clip that will be displayed in the system tray

            /// </summary>

            /// <param name="icons">The array of bitmaps which forms each frame of the animation

            ///                     This'll work by showing one bitmap after another in the array.

            ///                     Each of the bitmaps must be 16x16 pixels  </param>

            public void SetAnimationClip(Bitmap[] bitmap)

            {

                m_animationIcons = new Icon[bitmap.Length];

                for (int i = 0; i < bitmap.Length; i++)

                {

                    m_animationIcons[i] = Icon.FromHandle(bitmap[i].GetHicon());

                }

            }

     

            /// <summary>

            /// Sets the animation clip that will be displayed in the system tray

            /// </summary>

            /// <param name="icons">The bitmap strip that contains the frames of animation.

            ///                     This can be created by creating a image of size 16*n by 16 pixels

            ///                     Where n is the number of frames. Then in the first 16x16 pixel put

            ///                     first image and then from 16 to 32 pixel put the second image and so on</param>

            public void SetAnimationClip(Bitmap bitmapStrip)

            {

                m_animationIcons = new Icon[bitmapStrip.Width / 16];

                for (int i = 0; i < m_animationIcons.Length; i++)

                {

                    Rectangle rect = new Rectangle(i * 16, 0, 16, 16);

                    Bitmap bmp = bitmapStrip.Clone(rect, bitmapStrip.PixelFormat);

                    m_animationIcons[i] = Icon.FromHandle(bmp.GetHicon());

                }

            }

     

            /// <summary>

            /// Start showing the animation. This needs to be called after

            /// setting the clip using any of the above methods

            /// </summary>

            /// <param name="loop">whether to loop infinitely or stop after one iteration</param>

            /// <param name="interval">Interval in millisecond in between each frame. Typicall 100</param>

            public void StartAnimation(int interval, int loopCount)

            {

                if (m_animationIcons == null)

                    throw new ApplicationException("Animation clip not set with SetAnimationClip");

     

                m_loopCount = loopCount;

                m_timer.Interval = interval;

                m_timer.Start();

            }

     

            /// <summary>

            /// Stop animation started with StartAnimation with loop = true

            /// </summary>

            public void StopAnimation()

            {

                m_timer.Stop();

            }

            #endregion // Public APIs

     

            #region Dispose

            public void Dispose()

            {

                m_notifyIcon.Dispose();

                if (m_font != null)

                    m_font.Dispose();

            }

            #endregion

     

            #region Event handlers

            private void m_timer_Tick(object sender, EventArgs e)

            {

                if (m_currIndex < m_animationIcons.Length)

                {

                    m_notifyIcon.Icon = m_animationIcons[m_currIndex];

                    m_currIndex++;

                }

                else

                {

                    m_currIndex = 0;

                    if (m_loopCount <= 0)

                    {

                        m_timer.Stop();

                        m_notifyIcon.Icon = m_DefaultIcon;

                    }

                    else

                    {

                        --m_loopCount;

                    }

                }

            }

     

            #endregion // Event handlers

     

            #region private variables

     

            private NotifyIcon m_notifyIcon;

            private Font m_font;

            private Color m_col = Color.Black;

            private Icon[] m_animationIcons;

            private Timer m_timer;

            private int m_currIndex = 0;

            private int m_loopCount = 0;

            private Icon m_DefaultIcon;

     

            #endregion // private variables

        }

    }

     

    Sources - SysTray Usage: Form1.cs

    using System;

    using System.Drawing;

    using System.Collections;

    using System.ComponentModel;

    using System.Windows.Forms;

    using System.Data;

     

  • I know the answer (it's 42)

    Build Type creation and Drop Location

    • 1 Comments

    One of the most common issues everyone is running into with Team Build is configuring the Drop Location.

    All builds that happen through Team Build are dropped (bits are copied) to this location. Drop location is entered in the Location page of the Build Type wizard. This is essentially a shared folder on the network and needs to be available in UNC format as in \\server\share. However most users enter a path in the wizard and then any of the following three things happen

    1.      They forget to share the folder out
    Result: First build fails

    2.      The folder is shared out but adequate permissions are not given on it
    Result: First build fails

    3.      The folder gets unshared at some point of time
    Result: Suddenly builds start failing after that

    A common question is raised that both the first and second reasons of failure are a pre-requisite to starting a build, why doesn’t the Build Type wizard verify that the share exists. We could have done this but there are a couple of reasons we do not.

    Firstly it could be a common scenario that the administrator is first setting up couple of Build Types and will then go and share those folders. So failing would simply hinder this process. However, this is not a very good excuse because we could have at least gone ahead verified the share and then given warnings stating that the share does not exist and the admin should share them with the correct permissions.

    The main reason for not doing this verification is that scenario 2 is not easily verifiable. To undertand this let’s consider the permission required on the shared folder

    1.      The service account under which the Team Build Service is running on the  Build Machine needs write permission on this folder

    2.      Other users need to have read permission on this folder so that they get to see build logs and the build itself

    On the client where the Build Type is getting created through the wizard there is no information regarding the service account on the Build Machine so we cannot verify 1. This is because the admin while installing the BM could have chosen any valid account to run the service and can give explicitly and exclusive write permission to this account on the share. Moreover, user can change the Build Machine while firing the build and the service account on the new Build Machine might be a different account and that might not have permissions.

    On OS’s like WinXP in addition to the sharing permission you can go to the security tab on the folders properties and apply a lot of permissions which are not accessible over the network but would make the build to fail. Take for example in share tab you give Full control to everyone and in the security for that folder you explicitly deny create folder permission. So even though our verification succeeds build will fail.

    Verifying 2 does not add any value if we cannot verify 1.

    Its not that we cannot verify drop location, what I tried to highlight above is that it is non-trivial. Many users think that the Wizard should just try to see if the share exists and then create and delete a file on the share to ensure it is writable. However for the reasons mentioned above this approach would just not work.

     

  • I know the answer (it's 42)

    subscribe / unsubscribe to an event

    • 5 Comments

    In one of the internal aliases there was a discussion going on some time back regarding which is the better way to unsubscribe from an event and why does the first one even work

     

    1. myClass1.MyEvent += new EventHandler(Function);
      Do all stuff
      myClass1.MyEvent -= new EventHandler(Function);

     

    1. EventHandler eventHandler = new EventHandler(Function);
      myClass2.MyEvent += eventHandler;
      myClass2.OnEvent();
      myClass2.MyEvent -= eventHandler;

     

    In the first approach different objects are used to add and remove the event subscription. This can work only if the removal mechanism does not work by just comparing references. Because if it did then the removal mechanism would not find the object in the methods invocation list of the underlying delegate and would simply not remove the method.

     

    I thought I’d do a little more snooping into this.

     

    A class definition like
     public delegate void EventHandler(Object source, EventArgs eventArgs);

        class MyClass

        {

            public event EventHandler MyEvent;

    }

    Is converted to code equivalent to

     

        class MyClass

        {

            private EventHandler __MyEvent;

            public event EventHandler MyEvent

            {

                add

                {

                    lock (this) { __MyEvent += value; }

                }

                remove

                {

                    lock (this) { __MyEvent -= value; }

                }

            }

    }

    So the compiler generates the add/remove accessors.

     

    If you see the code of the accessors in ILDasm then you can see for the add_MyEvent method compiler emits code to call the System.Delegate.Combine method to combine the existing delegate and new delegate and for remove_MyEvent it uses System.Delegate.Remove method.

     

    So

     

    myClass1.MyEvent += new EventHandler(Function); è System.Delegate.Combine (myClass1.__MyEvent, newdelegate)

     

    and

    myClass1.MyEvent -= new EventHandler(Function); è System.Delegate.Remove (myClass1, newdelegate)

     

    So all of the trick lies in the Combine and Remove methods of System.Delegate.

     

    System.Delegate.Remove goes through the invocation list of the first delegate looking for invocations from the second delegate. If there is a match it removes it. System.Delegate overrides the == (Equals) operator so that the match does not happen based on object reference but based on the method the delegate encapsulates. This operator compares the instance object (null in case of static method callback) and the function pointed to and then removes the callback from the invocation list.

     

    So both works but which one should we use? If the events are subscribed/unsubscribed once at the beginning/end like in a typical WinForm application then it hardly matters. However if this is done multiple times then the second approach is preferable as it does less of costly heap allocations and will work faster.

     

    The complete code listing of the sample I used is as follows

     

    using System;

    using System.Collections.Generic;

    using System.Text;

     

    namespace EventAddRemove

    {

        public delegate void EventHandler(Object source, EventArgs eventArgs);

     

        class MyClass

        {

            public event EventHandler MyEvent;


            public void OnEvent()

            {

                if (MyEvent != null)

                    MyEvent(this, EventArgs.Empty);

                else

                    Console.WriteLine("No Event to fire");

            }

        }

       

        class Program

        {

            static void Function(object source, EventArgs eventArgs)

            {

                Console.WriteLine("Event got fired");

            }

     

            static void Main(string[] args)

            {

                Console.WriteLine("myClass1");

                MyClass myClass1 = new MyClass();

                myClass1.MyEvent += new EventHandler(Function);

                myClass1.OnEvent();

     

                myClass1.MyEvent -= new EventHandler(Function);

                myClass1.OnEvent();

     

     

                Console.WriteLine("myClass2");

                EventHandler eventHandler = new EventHandler(Function);

     

                MyClass myClass2 = new MyClass();

                myClass2.MyEvent += eventHandler;

                myClass2.OnEvent();

     

                myClass2.MyEvent -= eventHandler;

                myClass2.OnEvent();

            }

        }

    }

     

    Output is

    myClass1

    Event got fired

    No Event to fire

    myClass2

    Event got fired

    No Event to fire

    Lines in bold indicate that the correct methods was indeed removed from the invocation list in both approaches.

  • I know the answer (it's 42)

    Emails, Emails and more emails

    • 0 Comments

    Just saw the post Slaves to email on excess email in MS and I couldn't agree more.....

    Large email volume for people who manage others, or those who interact with external customers is expected. But even for individual contributors (Dev/Test) the volume is just too high. We should really use the internal communicator more and get rid of those one-liner emails.

    Since we work in a different time zone within a team distributed between Redmond/NorthCarolina/India we face a different issue. Each morning you enter office and you are welcomed with 100s of emails which were sent to you in the local night time. By the time you wade through them almost an hour is over. Mondays are worse as you have to wade through the all the emails sent during Friday in US.

  • I know the answer (it's 42)

    The CLR Nullable DCR works!!!!!

    • 0 Comments

    CLR took a DCR some time back on how nullable types are implemented. See here and here to find out more about the DCR. I found from one of the internal DLs that the fix was already in the RTM bits.

    I wrote a small piece of code which should work only with the DCR changes and kept it aside so once this DCR gets implemented I'd try it out. So each time I upgraded to a new build of VS/CLR I built/ran this code to see if it works. And it just did, with my todays upgrade to about 10 day old build in our lab. The new nullable type after becoming a  basic runtime intrinsic just rocks. I have put in comment all the failures that used to happen previously with the same piece of code....

    // this code works only with the latest bits of
    // Visual Studio 2005 (C#2.0) and will fail to
    // compile/run with older Beta2 bits

    static
    void Main(string[] args)
    {
        int
    ? val = 1;
        int? nullval = null;

        // this always worked
        if (nullval == null
    )
            Console.WriteLine("It worked"
    );

        // this used to fail before and I think one of
        // the biggest issue with the previous implementation
        object
    nullobj = nullval;
        if(nullobj == null
    )
            Console.WriteLine("It worked"
    );

        // previously required 
        // box = Nullable.ToObject<int>(val); argh!!!!
        object
    box = val;

        // If you do not need exceptional code
        // (that's code that throws exception)
        //
     you needed to do int? unbox = Nullable.FromObject<int>(box);
        int? unbox = (int
    ?)box;
        if
    (unbox == val)
            Console.WriteLine("It worked again"
    );

        int intval = (int)box;
        if
    (intval == val.Value)
            Console.WriteLine("attained Nullable Nirvana"
    );

        int x = 10;
        object
    y = x;
        // Previously Exception!!! cast is not valid
        int? z = (int
    ?)y;

        IComparable c = val;
        // Previously Exception!!! : object type cannot be
        // converted to target type
        if
    (c.CompareTo(box) == 0)
            Console.WriteLine("I have seen it all"
    );

        // compilation failure
        IComparable<int
    > ic = val;
        if(ic.CompareTo((int
    )box) == 0)
            Console.WriteLine("Wow there is even more to see"
    );
    }

    The output of the program is

    It worked
    It worked
    It worked again
    attained Nullable Nirvana
    I have seen it all
    Wow there is even more to see

  • I know the answer (it's 42)

    Frame arrangement in image strips used for animation

    • 0 Comments

    Sometimes we get so used to things being the way they are we stop questioning them. We always have the perception in mind that individual frames of animated logo in a Bitmap strip is always horizontally arranged. I remember writing code to extract icons from a image lists that store individual frames of an animation sequence one after the other horizontally using something like

    animationIcons = new Icon[bitmapStrip.Width / 16];
    for (int
    i = 0; i < m_animationIcons.Length; i++)
    {
        Rectangle rect =
    new
    Rectangle(i*16, 0, 16, 16);
        Bitmap bmp = bitmapStrip.Clone(rect, bitmapStrip.PixelFormat);
        animationIcons[i] = Icon.FromHandle(bmp.GetHicon());
    }

    Even winforms ImageList works on this assumption that the AddStrip method of the ImageCollection in the control has the images placed side-by-side. However this is not at all the optimal placement of images. Read it on Raymond Chen's blog .....

  • I know the answer (it's 42)

    CLR takes a DCR for Nullable type

    • 5 Comments

    I saw from Soma's blog that VS is taking a DCR to fix the issues about Nullable types that is being talked about in various blog. This is super cool as Microsoft demonstrated like never before that we do care about customer feedback as this is a direct result of some solid feedbacks. If you do not get the connection read Cyrus Najmabadi blog pointing to one of the original blogs that brought out the issue http://sab39.dev.netreach.com/Blog/12?vobId=172&pm=18

     

  • I know the answer (it's 42)

    Function generator in C++

    • 0 Comments

    Some of us were just chatting about my previous post about function generators and we wondered about whether it can be done in C++ without using function pointers.... Most of my C++ knowledge has been rusted beyond repair but I thought even though its not possible to do directly, one can overload the ( ) operator to simulate this. So it should be possible to code so that the following is valid

    FuncGen(Adder)(p1, p2)

    Here the part in red semantically behaves like a function generator returning different functions based on the flag you pass. So here's some code in C++ that does it. Again I want to stress that this is not a function generator in C++, it just simulates something like it so that a statement like FuncGen(Adder)(p1, p2) will actually work....

    #include <iostream>
    #include
    <string>
    using namespace std;

    enum FuncType
    {
        Adder,
        Subtractor,
        Multiplicator,
    };

    class CFunc
    {
        public
    :
            FuncType m_funcType; 
            template <typename
    T>
            T
    operator
    ()(T p1, T p2)
            {
                if
    (m_funcType == Adder)
                    return
    FuncAdder(p1, p2);
                else if
    (m_funcType == Subtractor)
                    return
    FuncSub(p1, p2);
                else if
    (m_funcType == Multiplicator)
                    return
    FuncMult(p1, p2);
            }

        private:
            template <typename
    T>
            T FuncAdder(T p1, T p2)
            {
                return
    p1 + p2;
            }
            template <typename
    T>
            T FuncSub(T p1, T p2)
            {
                return
    p1 - p2;
            }
           
    template <typename T>
            T FuncMult(T p1, T p2)
            {
                return
    p1 * p2;
            }
    };

    CFunc cfunc;
    CFunc& FuncGen(FuncType ftype)
    {
        cfunc.m_funcType = ftype;
        return
    cfunc;
    };

    int main(int argc, char* argv[])
    {
        int
    p1 = 5, p2 = 1;
        cout << FuncGen(Adder)(p1, p2) << endl;
        cout << FuncGen(Subtractor)(p1, p2) << endl;
        cout << FuncGen(Multiplicator)(p1, p2) << endl;
        return
    0;
    }

    Instead of using a global variable like cfunc I could have also created a object on the heap in FuncGen and later deleted it but since I have been coding in C# so long that I felt too lazy to write a delete statement.

  • I know the answer (it's 42)

    My experiments with continuation in C#

    • 4 Comments

    The blogs are buzzing with continuation support in C# 2.0 and what cool things can be done with it. http://www.intertwingly.net/blog/2005/04/13/Continuations-for-Curmudgeons explains the concept of continuation extremely well. I also found Don Box's posting http://pluralsight.com/blogs/dbox/archive/2005/04/27/7780.aspx very interesting.

    Traditionally in languages like C/C++ functions works off the stack. Each function call creates a new frame on the stack in which current context is stored (return address, current stack pointer) and then any arguments to the function is pushed in. The function also creates all its local variables on the stack and pops them off before the function returns. So when the function returns, all information regarding the functions execution is lost. So in case you call the function again it starts from the beginning.

    However in continuation this is not what happens. Here the state of the function is preserved and when you call back on the function it starts off from where it left off. All the function locals are allocated on the heap so that their values are preserved when the function is called again. In C# we have a *very* restricted version of continuation using the yield return statement. Even though its restrictive it allows some very cool way of programming.

    Here a sample of code where I have a container containing my friends names and I enumerate them.

    public class MyContainer
    {
        string[] m_friends = { "Samrat", "Kaushik", "Rahul", "Abhinaba" };
        public IEnumerator<string> GetEnumerator()
        {
            for (int index = 0; index < m_friends.Length; index++ )
                yield return m_friends[index];
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
           
    MyContainer myContainer = new MyContainer();
            foreach
    (string str in myContainer)
                Console.WriteLine(str);
        }
    }

    You can have multiple enumerators too as in

    public class CoolContainer
    {
        string[] m_friends = { "Samrat", "Kaushik", "Rahul", "Abhinaba" };
        public IEnumerable<string> straight
        {
            get {
                for (int index = 0; index < m_friends.Length; index++ )
                    yield return m_friends[index];
            }
        }
        public IEnumerable<string> Reverse
        {
            get{
                for (int index = m_friends.Length - 1; index >= 0; index--)
                    yield return m_friends[index];
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            CoolContainer cc = new CoolContainer();
        
            foreach
    (string str in cc.Reverse)
                Console.WriteLine(str);
            
           
    Console.WriteLine("----------------");
            
            foreach
    (string str in cc.straight)
                Console.WriteLine(str);
        }
    }

    Seeing all these work I got carried away and tried to do the enumeration without the foreach as in

     

    IEnumerator<string> enumerator = myContainer.GetEnumerator();

     

    enumerator.MoveNext();

    Console.WriteLine(enumerator.Current);

    enumerator.MoveNext();

    Console.WriteLine(enumerator.Current);           

    enumerator.Reset();

               

    enumerator.MoveNext();

    Console.WriteLine(enumerator.Current);

     

    My idea was that after the call to Reset internally I would be able to reach the first element in the list as the index variable will be reset. That’s where I got the surprise in the form of a NotSupportedException in the call to Reset. I send emails to the CSharp user group and found out that its indeed not supported and you need to create new enumerator to go back or if the enumerator once runs till end (i.e. one return is executed) then you’ll automatically get the reset you wanted. This means that iterating twice or more using the same iterator works as in

     

    MyContainer myContainer = new MyContainer();
    foreach
    (string str in myContainer)
        Console.WriteLine(str);
    foreach (string str in myContainer)

        Console.WriteLine(str);

  • I know the answer (it's 42)

    Team Build notification tool

    • 11 Comments

    < this tool has been updated check out here>

    As we go on developing the product we frequently feel strong about doing new things around our product either to increase customer value, easy of use, flexibility or just because it can be done. Most of these are either too late to be included in the product or does not meet the criteria. Either way they serve as great samples and keep us busy.screen shot of build ticker

    One great example would be RSS feed for Team Foundation version control checkin notifications. Check out http://blogs.msdn.com/jefflu/archive/2005/07/27/443900.aspx. So now in addition to getting emails, you can also subscribe for RSS feeds.

    Similarly for Team Build I have written a tool that monitors Team Build events and shows notifications with link to the Web UI of the Build. Currently it has the following feature

    • The tool can monitor any number of Team Foundation servers and is not tied to a single server.
    • It works over web services and does not need any VS installation to run. So this can be installed on your home PC to monitor if the build you fired before leaving office succedded or failed.
    • It has links to the Web UI, so you can also open the detailed report in the browser and see the status.
    • Poling frequency can be changed at two levels. Polling for list of builds from server and polling individual builds.
    • It shows cool Office 2003 like notification over the system tray and also animated icons in the tray.

    I plan to add additional features like listing all builds on the server and allowing user to specify different user name to connect to the server (required if running from home PC).

  • I know the answer (it's 42)

    Anonymous methods and closures in C#

    • 8 Comments

    Anonymous Method

    One of the new features in C#2.0 being shipped in with Whidbey is anonymous methods. Though this at first glance looks like an easy way of creating delegates, where instead of having to create a new function which the delegate will call you can pass the code inline.

    Before C#2.0

    class MyClass
    {
         delegate void MyDelegate
    ();
         static public void
    Function()
         {
             Console.WriteLine("I'm called"
    );
         }

         static void Main()
         {
            MyDelegate writeMessage = new MyDelegate
    (Function);
            writeMessage();
         }
    }

    With C#2.0 and anonymous methods: the Function is eliminated and the same piece of code can be written more elegantly as follows

    class MyClass
    {
        delegate void MyDelegate();
        static void Main()
        {
            MyDelegate writeMessage = delegate ()
                                      {
                                          Console.WriteLine("I'm called"
    );
                                      };
            writeMessage(); 
        }
    }

    For more details on Anonymous methods check out http://msdn.microsoft.com/msdnmag/issues/04/05/c20/default.aspx.

    However, there is more to it than just getting a short hand way of writing code. With anonymous methods you can now do a lot of things in C# which are commonly done in Functional languages. Consider the code below which is actually a function generator.

    class Program
    {
        delegate void MyDelegate
    <T>(T t);
        enum
    FunctionType
        {
            WithPrefix,
            WithoutPrefix
        }
        static MyDelegate<T> FunctionGenerator<T>(FunctionType
    fType)
        {
           
    int i = 0;

            if (fType == FunctionType
    .WithPrefix)
            {
               
    return delegate(T t)
                       {
                           Console.WriteLine(i.ToString() + ": "
    + t.ToString());
                           i++;

                       };
            }
            else
            {
                return delegate
    (T t)
                       {
                           Console.WriteLine(
    t.ToString());
                       };
            }
        }

        static void Main(string[] args)
        {
            MyDelegate<int> mdWith = FunctionGenerator<int>(FunctionType
    .WithPrefix);
            mdWith(5);
            mdWith(5);

            MyDelegate<string> mdWithout = FunctionGenerator<string>(FunctionType
    .WithoutPrefix);
            mdWithout(
    "Hello"
    );
        }
    }

    The output is
    0 : 5
    1 : 5
    Hello

    As in the above piece of code you can create Function Generator that actually return different implementations based on requirement. For another interesting sample see Don Box's blog http://pluralsight.com/blogs/dbox/archive/2005/04/17/7467.aspx

    Closure

    For any languages which allow passing around functions as arguments or functions returning another function the Closure abstraction is very important. For more info on Closure see http://en.wikipedia.org/wiki/Closure_(computer_science). C#2.0 supports closure by the use of anonymous methods.

    Closure is a function along with its lexical environment (available variables and their values) when the function is created.

    int i = 10; 
    return delegate(T t)
    {
        Console.WriteLine(i.ToString() + ": "
    + t.ToString());
    };
     

    Since the variable i was available with the value 0 when the Anonymous method was created, inside the method, i will be available with the same value when the method is called via the delegate.

    From the definition of Closure it can be inferred that Closure remembers the values of the variables during its creation. However in C# the outer local variable (i in this case) is shared with the anonymous method by creating it on the heap. This means any change to it in the anonymous method changes the original value and when the method is called the second time it gets the modified value of i as 1 (see second line of output). This leads many to argue that anonymous method is not actually a Closure as by its definition the value of a variable at the time of creation of the Closure should be remembered and not modifiable.

    Check out the link http://blogs.msdn.com/brada/archive/2004/08/03/207164.aspx on how the implementation of Anonymous methods in C# have led to interesting issues.

  • I know the answer (it's 42)

    Renaming, Deleting or Hiding a Build Type

    • 3 Comments

    Renaming, deleting or hiding a build type is not directly available from the Team Explorer or from any menu or tool bar. Essentially a Build Type's name is same as the name of the sub folder in which the build type files are checked in. So if there is a team project MyTeamProject with a Build Type MyBuildType this means there is a source control folder on the server with the server path

    $/MyTeamProject/TeamBuildTypes/MyBuildType

    On Beta 2 bits the path will be $/MyTeamProject/TeamBuildConfigurations/MyBuildType

    So renaming means renaming the folder named MyBuildType. Deleting would mean deleting this folder. If you want to hide this Build Type from coming up in the Team Explorer you need to rename the file TeamBuild.proj inside this folder to some other name ($/MyTeamProject/TeamBuildTypes/MyBuildType/TeamBuild.proj). The steps are as follows

    Adding Workspace Mapping

    Edit workspace dialog First you need to have a workspace that maps the TeamBuildTypes folder (or TeamBuildConfiguration on Beta2 bits). To do this go through the menu File -> SourceControl -> Workspaces... Select a workspace and click edit and then add the mapping similar to the one shown in the screen shot. Rest is more easily done from the command prompt.

    Open a Visual Studio 2005 command prompt. In that cd into the local folder that maps the TeamBuildTypes folder. Run the following command to get the latest files
    tf get * /r.

    Hiding a Build Type

    cd into the MyBuildType folder and run the following
    tf rename TeamBuild.proj foo.proj
    tf checkin

    This should bring up the checkin window. Click on the Checkin button. Now if you refresh the Team Explorer the build type should go away from under the Team Build node.

    Rename Build Type

    To rename the BuildType go to the folder above and run the following 
    tf rename MyBuildType CoolBuildType
    tf checkin

    On refreshing the Team Explorer a new Build Type named CoolBuildType should come.

    Deleting a Build Type

    To deleting a build type run
    tf delete MyBuildType
    tf checkin

     


     

  • I know the answer (it's 42)

    TechEd Hyderabad starts tomorrow

    • 0 Comments
    TechEd is starting tomorrow in Hyderabad (home to the MS India development centre). Most of the devs in our team will not be able to attend tomorrow and we will join the show from Tuesday. VSTS is getting a lot of attention this year and we heard great stories from the people who attended TechED in Bangalore and Chennai. The India Team System team working on Team Build and the converters will all be there in our Black T-shirts with Team System written in front. So if any one of you have any questions or need any insider info ;) catch us.
  • I know the answer (it's 42)

    marking required fields on forms/UI

    • 3 Comments

    How do you communicate to users which fields on a UI is required and which is optional? This was the questions I was trying to answer while implmenting the Team Build Type creation wizard. Though there exists some common conventions in Web forms like marking the fields with asterix and putting something like "Fields marked with an asterix * are required" somewhere on top, there seems to exist no convention to do this on Windows user interfaces.

    In team system the work item tracking UI does this by making the background color of the required fields  with the same color as tooltip (yellow) and then as soon as the user types in some thing in them the color changes back to window backgorund color (white). So the user can quckly review the form and can locate fields that are left to be filled as they are marked with a different color (yellow).

    I liked this idea a lot and wanted to do the same thing with our wizard and Start build forms. But could'nt get that approved by the User Experience team becuase they think that on wizards the visual cue should come from the enabling of the Next button. The idea is that once the user has filled in all the required fields in the page Next should get enabled so that he can move to the next page. I think this works well only when the number of controls on the Wizard page is less, other wise the user will keep trying to guess why the next button in not getting enabled. Since wizard guideline clearly calls out against crowding too many things in one page, I guess this is fine but still think we should move towards a common guideline on marking required fields and I think the background color change is a fine way of doing just that.

  • I know the answer (it's 42)

    What are the Build Types, how do I edit them

    • 9 Comments

    For people new to Team Build do read Overview of Team Build

    Though most people using Team Build easily finds out how to create a build type and fire a Team Build, they find it difficult to figure out how to edit a Build Type. So one of the common use scenario is to re-create the Build Type again with the changes required. Though this is perfectly fine and talks a great deal about the ease of using the Wizard to create a new build type, but results in Build Types hanging around.

    Editing build type is easy once you know what is a Build Type and where they go once created.

    How do you create a Build type

    Right click on the Team Build node on the Team Explorer and choose "New Team Build Type" from the context menu. This launches the Wizard to create the Build Type (refer Using the New Build Type Wizard for more info)

    Where did the Build Type go?

    Once a Build Type is created a set of three files are created and checked in to source control at the following server location $/{TeamProjectName}/TeamBuildTypes/{BuildTypeName}

    In Beta2 the server location used to be $/{TeamProjectName}/TeamBuildConfigurations/{BuildTypeName}. So replace all references to TeamBuildTypes with TeamBuildConfigurations if you are working with VS2005 Beta2

    Team Build operates and works on some thing called Build Types. Build Type is essentially a set of 3 files that reside on the Source Control as follows

    • $/{TeamProjectName}/TeamBuildTypes/{BuildTypeName}/TeamBuild.proj
      The main BuildType file that we would be interesting is editing.
    • $/{TeamProjectName}/TeamBuildTypes/{BuildTypeName}/VCOverrides.vsprops
      Used for building VC++ projects to override some build properties like the OutputDirectory
    • $/{TeamProjectName}/TeamBuildTypes/{BuildTypeName}/WorkspaceMapping.xml
      This is used to recreate the users Workspace on the Build Machine to sync sources prior to build.

    Interestingly the Build Type name is not stored in any of the files. The name is same as the name of the folder in TeamBuildTypes that contain these files

    Viewing the Build Type files

    Build Types in Source Control Viewing the build type files is same as viewing any file in the Source Control. You need to create a Workspace that maps the Build Type files to some local folder, sync the file and open them in any text editor. This can be done in a number of ways and one of them is clearly mentioned as comment on top of the generated TeamBuild.proj file. So if you right click on any of the Build Types under the Team Build node in the Team Explorer and choose "View Team Build Type" then the file is downloaded from the server to the local machine and opened in VS. One thing to keep in mind is that the file opened is a local copy and changes made to it will NOT be reflected in the actual TeamBuild.proj on the server.

    Editing the file

    Double click on the version control node in the Team Explorer to bring up the Source Control Explorer. If in the Folder list the TeamBuildTypes and its children are grayed out then that means that the folders are not mapped in the current workspace. In the tool window on the top of the Source Control Explorer select Workspaces... in the Workspace drop down. Select your current workspace and click on edit. In the Edit workspace dialog add mapping for the TeamBuildTypes folder. See image.

    Edit workspace dialog

    Once the mapping has been added right click on the TeamBuildTypes node in the folder and get the latest version. After that right click on the TeamBuild.proj and check out for edit. Double click on the file to open it in VS for edit.

    TeamBuild.proj file is an xml file and heavily commented so that it is easy to edit. Just look for <Description> and add some description to the Build Type, search for <DropLocation> and change the location where the build bits will be dropped. Keep reading the comments and that will guide you in your changes to this file. At the end save the file and go back to the Source Control Explorer, right click on the checked out TeamBuild.proj and check in the file and you are done

    You can verify that your changes have gone through by right clicking on the Build Type you changed in the Team Explorer and choose "View Team Build Type". The opened Build Type should have your changes in it.

     

     

     

     

     

  • I know the answer (it's 42)

    Using the New Build Type Wizard

    • 8 Comments

    Team Build and Build Types

    The build type wizard is used to generate Build Types which are a collection of Build Scripts used to fire the remote builds on the Build Machines. These scripts are XML scripts consumed by MSBuild which is used by Team Build to build the user's solutions. Just as the local VS build works on solutions (.sln) and projects (.proj) Team Build works on Build Types.

    Entry Point

    You need to have the Team Explorer open (View->Team Explorer). There is couple of entry points in Visual Studio to the New Build Type Wizard. It can be launched by right-clicking on the Team Build node in the Team Explorer (under any Team Project) or through the menu Build->New Team Build Type. The later works only when a solution is open in VS (cause the top level Build menu comes up only when a solution is currently open).

    Using the Wizard

    There are six pages in the Wizard. Only when all the mandatory fields are filled in a page the next button gets enabled. The Finish button remains disabled till you reach the end of the Wizard. You can also browse between the pages using the navigation pane on the left. If the links of some of the pages are disabled on the pane this means that some of the pages have to be filled before reaching that page.

    In case you get a pop-up saying that "No workspace Exists for the Given team project". It means that there is no source control workspace on the client that maps into the Team Project. Change an existing workspace mapping or create a new workspace for the team project for which you are trying to create the build type.

    Welcome page

    You need to give a name to the Build Type. This is the only mandatory field on this page. Build Type name has to be unique for the Team Project.

    The Wizard verifies the uniqueness of the name when you hit Next and gives an popup error message in case is finds another Build Type with the same name.

    Selections Page

    This is where you select the solutions you want to build for the Build Type. The combo box on top shows the names of the available workspaces with the name of the workspace owner in parenthesis. Select the workspace and all the solutions in the source control that are mapped in the workspace will be listed. Check all the solutions you want to build and use the arrow buttons on the right to set the order in which the solutions will be built. The ordering may be important if there are interdependencies between the solutions and one solution requires the binaries generated by another solution.

    If you do not see any solutions listed, it means that there are either no solutions checked in to the source control or the workspace mapping is not correct.

    Configurations Page

    You can give the configurations that will be built for each of the solutions. This is the same list that you see in through Build->ConfigurationManager. You can add as many unique combinations of Configurations and platforms you need. The platform list is pre-defined and can be any one of x86, x64, Itanium, Win32 and AnyCPU. Configuration can be Debug, Release or any other user defined configuration.

    The solution should support the given combination i.e. you must have had added the same configuration/platform pair in Build->Configuration Manager for that solution for the build to succeed.

    Location Page

    This is where you specify which build machine will be used and where the built binaries will be dropped (copied to). Type the name of the Build Machine (server name) without the leading \\.

    The build directory is the local folder on the build machine where the sources are downloaded from the Team Foundation Server and built using MSBuild. This folder is created in case it is not already present. You have to give the local path of the build directory on the build machine (something like c:\builds). In case you are wondering why there is no browse button beside the folder name the reason is that the folder is a local folder on the build machine and will not be browsable from the client machine where you are creating the Build Type. This is more of a internal detail that has been exposed. For all normal purposes you will not be needed to be bothered about the build folder.

    Both the build machine and the build directory can be overridden at the time of firing the build.

    The drop location is the place where the binaries will be copied to once the build is over. You need to create a folder on a server and share it out with write permission to Everyone and then type the name here. This needs to be in UNC format (\\server\share). You can browse for the share on the network. In case you forget to share out the folder with write permission then build will fail.

    In case you fail to browse for the drop location try browsing to the same machine using "My network places"->"Entire Network" in Windows explorer. Most probably you'll see the same error as the one you saw in the Wizard. Call your network admin to fix issues with your permission settings or any other network issues.

    Build Steps

    Though this page is named Build Steps you can only change the test related steps through this page. Check the Run Test checkbox if you have a test project in your solution and would like to run the tests in it once the solutions are built. The test metadata file and test list become mandatory fields if the run tests check box is checked. All the vsmdi files in the Team Project will be listed here. Select the once you want to use to test. The test list combo box will be automatically updated to show all the test lists in the vsmdi file. You can choose any one of the test list or use the default "All loaded tests".

    If no vsmdi files show up in the combo box then there are no such files checked into source control. You will be needed to create test projects check them in to source control and try creating the Build Type again.

    Check the perform code analysis check box if you want to run FxCop for static analysis of the source code.

    Summary Page

    Finally this is where the Finish button gets enabled. Review the selections you had made in all the pages, pray to god and hit the Finish button

    What happens next?

    Team Build generates the build scripts and some associated helper files and checks them in. If the Build Type name in MyBuildType then this is what is created and checked into source control

    $/MyTeamProject/TeamBuildConfigurations/MyBuildType/TeamBuild.proj This is the main build script file that is generated by team build $/MyTeamProject/TeamBuildConfigurations/MyBuildType/CustomAction.targets This file is included by TeamBuild.proj and is used for customizing team build to suit your organizations

    A node named MyBuildType is created under the Team Builds node in the Team Explorer and the created TeamBuild.proj file is downloaded to a temporary file and opened in Visual Studio. Note that this is a temporary copy and changes made to it are not reflected on the server. I will post some time later on how to modify the teambuild.proj file.

    Firing a Build

    Right-click on the newly created node (MyBuildType) and then in the context menu choose "Build Team Project <MYTEAMPROJECT>". In the dialog that opens click on the Build button. If all is well, build should start and the Build Summary page should come up. Double click on the name of the build just fired and see the detailed report.

    In Beta 2 the summary and the detailed report does not auto refresh. So you need to manually refresh the pages using the refresh button on top of the Summary page or the context menu of the detailed report page. When the build complets click on the drop location link on the detailed report and the folder with the binaries just built will come up.

  • I know the answer (it's 42)

    Visit to redmond

    • 0 Comments

    Its almost a month, I'm here in Remond. I was very excited to come to the heart of things where everything of VSTS other than team build gets done. I was very excited to meet all the people and attach faces to the email aliases and caught off handed many a times when someone looked or talked so differentlly than the person you conjured in your mind. I loved the open campus which is so different than the walled campuses I have seen back home.

    I was surprised to see a soccer field in the middle of the campus. I always thougt that cricket and soccer is not so common in US. A visit to the cafeteria and a stroll around was enough to explain it. There are so many europeans and latin americans all around. I met people from so many coutries, people from Vietnam, Russian, England, China, Japan and of course from India. Did not see Bill Gates yet, but I do hope to catch a glimpse of him.What I hated most about the place was the rains. Do not get me wrong here, I am from coastal country and love the rains. But back home rain is torrential like a white blanket that comes down and cleans the earth of dust, dirt and sin. Then the sun is back again and you run for shelter. Here the rain is like a dripping tap, it goes on and on like drip, drip, drip, drip, drip.....

    I visited Whidbey island and took a photo of an insect on a leaf. Then had a blast sending an email to all the folks in India that I found a bug in Whidbey and sent a link to the picture. I gave the bug repro steps as well. Visit Whidbey, look around on the leaves and you'll find plenty of bugs.

  • I know the answer (it's 42)

    Team Build blog

    • 2 Comments

    I guess the least represented module of Visual Studio Team System on msdn blog was Team Build . This is going to change now with the Team Build PM khushboo taking up bloging actively. See http://blogs.msdn.com/team_foundation or http://blogs.msdn.com/team_foundation/archive/2005/03/02/383479.aspx

     

  • I know the answer (it's 42)

    command line tool syntax

    • 1 Comments
    Command line interface (CUI) designs for many of the tools found with VS or in Windows were to include a bunch of individual commands or exe with options or flags.

    To get a directory listing: dir <options> as in dir c:\temp /w
    To create a directory: md c:\temp\foo
    To delete a directory: rd /s c:\temp\foo

    So even though all the tasks pertain to directory or path handling , you need to know three command to do the task. This design is slowly changing to the format of command <action> [</options:attributes>]

    For example if we change the above commands to this format with the common command called dir, we will be getting
    To get a directory listing: DIR list c:\temp /w
    To create a directory: DIR  make c:\temp\foo
    To delete a directory: DIR rem c:\temp\foo /s

    So effectively user learning is reduced. One can argue that he still needs to remember the names of the actions. But in the previous case he needs to remember rd, md, dir. Now he knows everything to do with path handling is to be done with DIR. So he can run DIR /? to get the list of actions and then do a DIR list /? to know the options for listing. The other advantage is namespace pollution in terms of the names of the executables also reduces.

    This new format has also been adopted in the VS as in the source control tool. So to get the listing of all workspaces on MyServer you  run the command
    h.exe workspaces /s:MyServer
    To create a new workspace you run the command
    h.exe workspace /new MySpace /s:abhinab-test
    I guess going forward we will see more and more of the standard OS commands also taking up this format. A very common example is the NET command

  • I know the answer (it's 42)

    Error messages

    • 2 Comments

    Frequently we are presented with error message pop-ups with messages like "Unable to open file". Error messages are popped up when something has gone wrong. If SW cannot convey to the user what went wrong and what he can try to fix the problem, it might as well not show the error message at all.

    So all errors messages must have three components

    • Notification
    • Explanation
    • Solution

    A good example for a Team Build scenario would be

    Unable to connect to the build machine "BuildServer01"
    Make sure that the machine is connected to the network and the TeamBuild Service is running on it.

    So all error messages that have one sentence in them are most probably not as helpful as it states what happened and not what can be done to rectify it.

    Another important thing to note is that the user is never to be blamed for any error. If the action he did was dumb then we are at fault that we did not restrict him from committing a dumb action.

Page 15 of 16 (379 items) «1213141516