Month: October 2012

  • Windows Shortcuts and Hot Keys

    A impressive reference guide of shorcuts and hot keys is available on the “Shortcut World” website here, covering various OS (Windows, MacOS, Linux) and products (Autocad, Office, … ). Use the search box to find shortcuts for your software (e.g.: “Windows 7”).

    But the most complete, up-to-date and official, lists of shortcuts for Windows should be the ones provided by Microsoft itself.

    Click to Read More

    Have a look:

    • here for Windows 7, 8.1 and 10
    • here for Windows XP

    To find shortcuts for other Microsoft products (Excel, Word, …) go to the page Accessibility in Microsoft Products, select a product in the list to open the related page and search for the “shortcut” word on that page. you will most probably find what you need 😉

    Notice that you may also create your own “keyboard shortcut” to open a program:

    1. Locate a shortcut to that program (e.g.: via the menu Start > All Programs).
    2. Right-click the shortcut, and then click Properties.
    3. In the Shortcut Properties dialog box, click the Shortcut tab.
    4. In the Shortcut key box, enter the key that you want to use in combination with Ctrl+Alt (keyboard shortcuts automatically start with Ctrl+Alt) and click OK.

    If the same key combination as the shortcut you just created is used by a program currently running, then your shortcut might not work.

    Loading

  • Drop Builds’ primary output in a “Latest” folder

    As briefly mentioned in another post, we have a specific “Reference Assemblies” folder on the Build Machines containing the latest version of each assembly issued from a successful Build. Assemblies in that folder, know as the “Latest” folder, can be used for “Continuous Integration” Builds.  This post is about the pragmatic solution implemented to drop only the primary output of the Builds in that folder.

    Click to Read More

    The output of a Build contains not only the assemblies and satellite assemblies issued from the compilation of the Visual Studio Projects (I.e.: assemblies part of the “primary output” as named in the Microsoft Setup Projects). It contains also a copy of all the referenced assemblies (file references) with the property “CopyLocal”=”True”.

    It’s important for our purpose to only drop the primary output into the “Latest” folder, otherwise we could override the latest version of some referenced assemblies with a  copy of the specific version found for the Build (e.g.: when targeting the Integration Environment, we use the promoted version on, the assemblies which are possibly not the latest).

    We may not set “CopyLocal”=”False” on all the “file references” because MSTest needs a copy of those in the bin folder to be able to run the unit Tests (That would not be the case if we could find for MSTest an equivalent of the “ReferencePath” parameter of MSBuild).

    We don’t have access to methods (or well described “algorithms”) to retrieve the exact list of assemblies part of the “primary output”. Such methods are only implemented in the Microsoft Setup Projects (Projects not supported, by the way, by MSBuild).

    We don’t want all our developers to add MSBuild Scripts in their Visual Studio Projects to drop the “Targets” in the “Latest” folder.

    Ex. copy “$(TargetDir)$(TargetName).???” “C:\RefAssemblies\Latest”

    This is not only too error prone (like everything you request to a human developer), but it’s also not robust enough. It’s in our opinion impossible to maintain this with enough guarantee taking into account that developers can for example add support for new languages at any time. For each Project, in addition to the assembly $(TargetDir)$(TargetName).dll, we also have to drop the satellite assemblies (e.g.: <culture>\<assemblyname>.resources.dll”), etc…

    The most generic solution we found to identify the assemblies part of the primary output, although quick and dirty, consists in parsing the FileListAbsolute.txt file generated by MSBuild itself and available in the “obj” folder. We “rely” so on direct output of Microsoft (the content of that file) and avoid to implement (and maintain) our own generic (and most probably complex) algorithm (“complex” because I have no idea how to detect satellite assemblies in a Visual Studio Project).

    Notice: We may only drop the primary output of Builds in the “Latest” folder for “Continuous Integration” Builds or Builds targeting the Integration Environment (both using the latest version of the sources). Builds targeting Qualification, Pre-Production or Production use always a specific version of the sources instead of the latest version. Their purpose is indeed to fix a bug in the assemblies deployed in the targeted environment and build with older sources.

    Click to Read More

    [csharp] using System;
    using System.IO;
    using System.Linq;
    using System.Activities;
    using System.Reflection;
    using System.Diagnostics;
    using System.ComponentModel;
    using System.Collections.Generic;
    using Microsoft.TeamFoundation.Build.Client;
    using Microsoft.Build.Evaluation;

    namespace AG.SCRM.TeamBuild.Activity
    {
    /// &lt;summary&gt;
    /// Collect Build’s Primary Output Items
    /// &lt;/summary&gt;
    [BuildActivity(HostEnvironmentOption.All)] public sealed class GetPrimayOutput : CodeActivity
    {
    /// &lt;summary&gt;
    /// List of Build’s Primary Output Items
    /// &lt;/summary&gt;
    [RequiredArgument] public InOutArgument&lt;List&lt;FileInfo&gt;&gt; PrimaryOutputItems { get; set; }

    /// &lt;summary&gt;
    /// Build’s Configuration Parameter
    /// &lt;/summary&gt;
    [RequiredArgument] public InArgument&lt;string&gt; Configuration { get; set; }

    /// &lt;summary&gt;
    /// Build’s Platform Parameter
    /// &lt;/summary&gt;
    [RequiredArgument] public InArgument&lt;string&gt; Platform { get; set; }

    /// &lt;summary&gt;
    /// Local path of Build’s project file
    /// &lt;/summary&gt;
    [RequiredArgument] public InArgument&lt;string&gt; LocalProject { get; set; }

    [RequiredArgument] public InArgument&lt;string&gt; OutDir { get; set; }

    /// &lt;summary&gt;
    /// Collect Build’s Primary Output Items
    /// &lt;/summary&gt;
    /// &lt;param name=&quot;context&quot;&gt;&lt;/param&gt;
    protected override void Execute(CodeActivityContext context)
    {
    var fileListAbsolute = PrimaryOutputItems.Get(context);
    var localProject = LocalProject.Get(context);
    var configuration = Configuration.Get(context);
    var platform = Platform.Get(context);

    // Default Configuration is &quot;Debug&quot;
    if (string.IsNullOrEmpty(configuration)) configuration = &quot;Debug&quot;;

    // Initialize the list of Build’s Primary Output Items if required.
    // Otherwise, add Build’s Primary Output Items to the provided list
    // to possibly support a loop on all Visual Studio Solution files in
    // Build’s
    if (fileListAbsolute == null) fileListAbsolute = new List&lt;FileInfo&gt;();

    if (Path.GetExtension(localProject).Equals(&quot;.sln&quot;, StringComparison.InvariantCultureIgnoreCase))
    {
    // Parse the Visual Studio Solution file
    SolutionParser sln = new SolutionParser(localProject);
    string root = Path.GetDirectoryName(localProject);
    foreach (SolutionProject project in sln.MSBuildProjects)
    {
    localProject = Path.Combine(root, project.RelativePath);
    CollectOutputItems(context, fileListAbsolute, configuration, platform, localProject);
    }
    }
    else
    {
    // Validate that the file is a Visual Studio Project
    var projectCollection = new ProjectCollection();
    try
    {
    Project project = projectCollection.LoadProject(localProject);
    string projectDirectoryPath = Path.GetDirectoryName(localProject);
    CollectOutputItems(context, fileListAbsolute, configuration, platform, localProject);
    }
    catch (Exception ex)
    {
    throw new Exception(string.Format(&quot;Project file ‘{0}’ is not a valid Visual Studio project.&quot;, localProject), ex);
    }
    projectCollection.UnloadAllProjects();

    }

    context.SetValue(PrimaryOutputItems, fileListAbsolute);
    }

    private static void CollectOutputItems(CodeActivityContext context, List&lt;FileInfo&gt; items, string configuration, string platform, string project)
    {
    string projectFileName = Path.GetFileName(project);
    string projectName = Path.GetFileNameWithoutExtension(project);
    string projectPath = Path.GetDirectoryName(project);
    string fileListAbsolute = GetFileListAbsolute(configuration, platform, projectFileName, projectPath);

    if (!string.IsNullOrEmpty(fileListAbsolute))
    {
    System.IO.StreamReader file = null;
    string line;

    string parent = Path.GetDirectoryName(fileListAbsolute);

    // Read the file and parse it line by line.
    using (file = new System.IO.StreamReader(fileListAbsolute))
    {
    while ((line = file.ReadLine()) != null)
    {
    // Ignore obj folder’s local items.
    if (!line.StartsWith(parent, StringComparison.OrdinalIgnoreCase))
    {
    FileInfo item = new FileInfo(line);
    if (item.Exists)
    {
    // We are actually only interested in .dll and .exe + their .pdb, .xml and .config
    if (item.Extension.Equals(&quot;.dll&quot;, StringComparison.OrdinalIgnoreCase) || item.Extension.Equals(&quot;.exe&quot;, StringComparison.OrdinalIgnoreCase))
    {
    //MessageHelper.DisplayInformation(context, string.Format(&quot;Build output of {0} contains: {1}.&quot;, projectName, item.Name));
    items.Add(item);

    var config = new FileInfo(Path.Combine(item.DirectoryName, item.Name + &quot;.config&quot;));
    if (config.Exists)
    {
    //MessageHelper.DisplayInformation(context, string.Format(&quot;Build output of {0} contains: {1}.&quot;, projectName, config.Name));
    items.Add(item);
    }

    var pdb = new FileInfo(Path.Combine(item.DirectoryName, Path.GetFileNameWithoutExtension(item.FullName) + &quot;.pdb&quot;));
    if (pdb.Exists)
    {
    items.Add(item);
    }

    var xml = new FileInfo(Path.Combine(item.DirectoryName, Path.GetFileNameWithoutExtension(item.FullName) + &quot;.xml&quot;));
    if (xml.Exists)
    {
    items.Add(item);
    }
    }
    }
    else
    {
    //MessageHelper.DisplayWarning(context, string.Format(&quot;Primary Output items not found for project {0}: {1}.&quot;, projectName, line));
    }
    }
    }
    }
    }
    else
    {
    //MessageHelper.DisplayWarning(context, string.Format(&quot;SCRM: No FileListAbsolute found for project ‘{0}’&quot;, projectName));
    }
    }

    /// &lt;summary&gt;
    ///
    /// &lt;/summary&gt;
    /// &lt;param name=&quot;configuration&quot;&gt;Build’s Configuration: Debug or Release&lt;/param&gt;
    /// &lt;param name=&quot;platform&quot;&gt;Build’s Target Platform: Any CPU or x86&lt;/param&gt;
    /// &lt;param name=&quot;projectFileName&quot;&gt;Visual Studio Project filename&lt;/param&gt;
    /// &lt;param name=&quot;projectPath&quot;&gt;Visual StudioProject path&lt;/param&gt;
    /// &lt;returns&gt;The path of the FileListAbsolute.txt file.&lt;/returns&gt;
    /// &lt;remarks&gt;This file should be located under /obj/{platform}/{configuration/}.
    /// But we also check the parent folders if the file is not found where expected.
    /// We did indeed experienced problem to locate this file for Builds with &quot;Mixed Plateform&quot; Target.&lt;/remarks&gt;
    private static string GetFileListAbsolute(string configuration, string platform, string projectFileName, string projectPath)
    {
    var fileListAbsoluteName = projectFileName + &quot;.FileListAbsolute.txt&quot;;
    var fileListAbsolutePath = Path.Combine(projectPath, &quot;obj&quot;, platform, configuration, fileListAbsoluteName);
    if (!File.Exists(fileListAbsolutePath))
    {
    fileListAbsolutePath = Path.Combine(projectPath, &quot;obj&quot;, configuration, fileListAbsoluteName);
    if (!File.Exists(fileListAbsolutePath))
    {
    fileListAbsolutePath = Path.Combine(projectPath, &quot;obj&quot;, fileListAbsoluteName);
    if (!File.Exists(fileListAbsolutePath))
    {
    fileListAbsolutePath = null;
    }
    }
    }

    return fileListAbsolutePath;
    }
    }

    /// &lt;summary&gt;
    /// This Visual Studio Solution file Parser can be used to retrieve lists of projects in a Solution.
    /// The first list contains all projects that can be built with MSBuild.
    /// The second list contains all the other projects.
    /// &lt;/summary&gt;
    /// &lt;remarks&gt;
    /// Based on http://stackoverflow.com/questions/707107/library-for-parsing-visual-studio-solution-files.
    /// It’s a wrapper on Microsoft Build’s internal class &quot;SolutionParser&quot;
    /// &lt;/remarks&gt;
    public class SolutionParser
    {
    static readonly Type s_SolutionParser;
    static readonly PropertyInfo s_SolutionParser_solutionReader;
    static readonly MethodInfo s_SolutionParser_parseSolution;
    static readonly PropertyInfo s_SolutionParser_projects;

    public List&lt;SolutionProject&gt; MSBuildProjects { get; private set; }
    public List&lt;SolutionProject&gt; OtherProjects { get; private set; }

    static SolutionParser()
    {
    s_SolutionParser = Type.GetType(&quot;Microsoft.Build.Construction.SolutionParser, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a&quot;, false, false);
    if (s_SolutionParser != null)
    {
    s_SolutionParser_solutionReader = s_SolutionParser.GetProperty(&quot;SolutionReader&quot;, BindingFlags.NonPublic | BindingFlags.Instance);
    s_SolutionParser_projects = s_SolutionParser.GetProperty(&quot;Projects&quot;, BindingFlags.NonPublic | BindingFlags.Instance);
    s_SolutionParser_parseSolution = s_SolutionParser.GetMethod(&quot;ParseSolution&quot;, BindingFlags.NonPublic | BindingFlags.Instance);
    }
    }

    public SolutionParser(string solutionFileName)
    {
    if (s_SolutionParser == null)
    {
    throw new InvalidOperationException(&quot;Cannot find type ‘Microsoft.Build.Construction.SolutionParser’ are you missing a assembly reference to ‘Microsoft.Build.dll’?&quot;);
    }
    var solutionParser = s_SolutionParser.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic).First().Invoke(null);
    using (var streamReader = new StreamReader(solutionFileName))
    {
    s_SolutionParser_solutionReader.SetValue(solutionParser, streamReader, null);
    s_SolutionParser_parseSolution.Invoke(solutionParser, null);
    }
    MSBuildProjects = new List&lt;SolutionProject&gt;();
    OtherProjects = new List&lt;SolutionProject&gt;();
    var array = (Array)s_SolutionParser_projects.GetValue(solutionParser, null);
    for (int i = 0; i &lt; array.Length; i++)
    {
    SolutionProject project = new SolutionProject(array.GetValue(i));

    if (project.ProjectType == &quot;KnownToBeMSBuildFormat&quot;)
    MSBuildProjects.Add(project);
    else
    OtherProjects.Add(project);
    }
    }
    }

    /// &lt;summary&gt;
    /// This class represent a Visual Studio Project member of a Solution.
    /// &lt;/summary&gt;
    /// &lt;remarks&gt;
    /// It’s a wrapper on Microsoft Build’s internal class &quot;ProjectInSolution&quot;
    /// &lt;/remarks&gt;
    [DebuggerDisplay(&quot;{ProjectName}, {RelativePath}, {ProjectGuid}, {ProjectType}&quot;)] public class SolutionProject
    {
    static readonly Type s_ProjectInSolution;
    static readonly PropertyInfo s_ProjectInSolution_ProjectName;
    static readonly PropertyInfo s_ProjectInSolution_RelativePath;
    static readonly PropertyInfo s_ProjectInSolution_ProjectGuid;
    static readonly PropertyInfo s_ProjectInSolution_ProjectType;

    static SolutionProject()
    {
    s_ProjectInSolution = Type.GetType(&quot;Microsoft.Build.Construction.ProjectInSolution, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a&quot;, false, false);
    if (s_ProjectInSolution != null)
    {
    s_ProjectInSolution_ProjectName = s_ProjectInSolution.GetProperty(&quot;ProjectName&quot;, BindingFlags.NonPublic | BindingFlags.Instance);
    s_ProjectInSolution_RelativePath = s_ProjectInSolution.GetProperty(&quot;RelativePath&quot;, BindingFlags.NonPublic | BindingFlags.Instance);
    s_ProjectInSolution_ProjectGuid = s_ProjectInSolution.GetProperty(&quot;ProjectGuid&quot;, BindingFlags.NonPublic | BindingFlags.Instance);
    s_ProjectInSolution_ProjectType = s_ProjectInSolution.GetProperty(&quot;ProjectType&quot;, BindingFlags.NonPublic | BindingFlags.Instance);
    }
    }

    public string ProjectName { get; private set; }
    public string RelativePath { get; private set; }
    public string ProjectGuid { get; private set; }
    public string ProjectType { get; private set; }

    public SolutionProject(object solutionProject)
    {
    this.ProjectName = s_ProjectInSolution_ProjectName.GetValue(solutionProject, null) as string;
    this.RelativePath = s_ProjectInSolution_RelativePath.GetValue(solutionProject, null) as string;
    this.ProjectGuid = s_ProjectInSolution_ProjectGuid.GetValue(solutionProject, null) as string;
    this.ProjectType = s_ProjectInSolution_ProjectType.GetValue(solutionProject, null).ToString();
    }
    }

    /// &lt;summary&gt;
    /// List of known project type Guids from http://www.mztools.com/articles/2008/mz2008017.aspx
    /// + BizTalk: http://winterdom.com/2008/12/biztalkserver2009msbuildtasks
    /// + Workflow 4.0
    /// &lt;/summary&gt;
    public enum ProjectType
    {
    [Description(&quot;{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}&quot;)] Windows_CSharp,
    [Description(&quot;{F184B08F-C81C-45F6-A57F-5ABD9991F28F}&quot;)] Windows_VBNET,
    [Description(&quot;{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}&quot;)] Windows_VisualCpp,
    [Description(&quot;{349C5851-65DF-11DA-9384-00065B846F21}&quot;)] Web_Application,
    [Description(&quot;{E24C65DC-7377-472B-9ABA-BC803B73C61A}&quot;)] Web_Site,
    [Description(&quot;{F135691A-BF7E-435D-8960-F99683D2D49C}&quot;)] Distributed_System,
    [Description(&quot;{3D9AD99F-2412-4246-B90B-4EAA41C64699}&quot;)] Windows_Communication_Foundation_WCF,
    [Description(&quot;{60DC8134-EBA5-43B8-BCC9-BB4BC16C2548}&quot;)] Windows_Presentation_Foundation_WPF,
    [Description(&quot;{C252FEB5-A946-4202-B1D4-9916A0590387}&quot;)] Visual_Database_Tools,
    [Description(&quot;{A9ACE9BB-CECE-4E62-9AA4-C7E7C5BD2124}&quot;)] Database,
    [Description(&quot;{4F174C21-8C12-11D0-8340-0000F80270F8}&quot;)] Database_other_project_types,
    [Description(&quot;{3AC096D0-A1C2-E12C-1390-A8335801FDAB}&quot;)] Test,
    [Description(&quot;{20D4826A-C6FA-45DB-90F4-C717570B9F32}&quot;)] Legacy_2003_Smart_Device_CSharp,
    [Description(&quot;{CB4CE8C6-1BDB-4DC7-A4D3-65A1999772F8}&quot;)] Legacy_2003_Smart_Device_VBNET,
    [Description(&quot;{4D628B5B-2FBC-4AA6-8C16-197242AEB884}&quot;)] Smart_Device_CSharp,
    [Description(&quot;{68B1623D-7FB9-47D8-8664-7ECEA3297D4F}&quot;)] Smart_Device_VBNET,
    [Description(&quot;{14822709-B5A1-4724-98CA-57A101D1B079}&quot;)] Workflow_30_CSharp,
    [Description(&quot;{D59BE175-2ED0-4C54-BE3D-CDAA9F3214C8}&quot;)] Workflow_30_VBNET,
    [Description(&quot;{06A35CCD-C46D-44D5-987B-CF40FF872267}&quot;)] Deployment_Merge_Module,
    [Description(&quot;{3EA9E505-35AC-4774-B492-AD1749C4943A}&quot;)] Deployment_Cab,
    [Description(&quot;{978C614F-708E-4E1A-B201-565925725DBA}&quot;)] Deployment_Setup,
    [Description(&quot;{AB322303-2255-48EF-A496-5904EB18DA55}&quot;)] Deployment_Smart_Device_Cab,
    [Description(&quot;{A860303F-1F3F-4691-B57E-529FC101A107}&quot;)] Visual_Studio_Tools_for_Applications_VSTA,
    [Description(&quot;{BAA0C2D2-18E2-41B9-852F-F413020CAA33}&quot;)] Visual_Studio_Tools_for_Office_VSTO,
    [Description(&quot;{F8810EC1-6754-47FC-A15F-DFABD2E3FA90}&quot;)] SharePoint_Workflow,
    [Description(&quot;{6D335F3A-9D43-41b4-9D22-F6F17C4BE596}&quot;)] XNA_Windows,
    [Description(&quot;{2DF5C3F4-5A5F-47a9-8E94-23B4456F55E2}&quot;)] XNA_XBox,
    [Description(&quot;{D399B71A-8929-442a-A9AC-8BEC78BB2433}&quot;)] XNA_Zune,
    [Description(&quot;{EC05E597-79D4-47f3-ADA0-324C4F7C7484}&quot;)] SharePoint_VBNET,
    [Description(&quot;{593B0543-81F6-4436-BA1E-4747859CAAE2}&quot;)] SharePoint_CSharp,
    [Description(&quot;{A1591282-1198-4647-A2B1-27E5FF5F6F3B}&quot;)] Silverlight,
    [Description(&quot;EF7E3281-CD33-11D4-8326-00C04FA0CE8D&quot;)] BizTalk,
    [Description(&quot;32f31d43-81cc-4c15-9de6-3fc5453562b6&quot;)] Workflow_40
    };

    /// &lt;summary&gt;
    /// Helper Class to manage Visual Studio Project’s types
    /// &lt;/summary&gt;
    public static class ProjectTypeExtensions
    {
    public static Guid ToGuid(this ProjectType val)
    {
    DescriptionAttribute[] attributes = (DescriptionAttribute[])val.GetType().GetField(val.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
    return attributes.Length &gt; 0 ? Guid.Parse(attributes[0].Description) : Guid.Empty;
    }

    public static ProjectType Parse(string val)
    {
    return Parse(Guid.Parse(val));
    }

    public static ProjectType Parse(Guid val)
    {
    ProjectType? type = null;
    FieldInfo[] fis = typeof(ProjectType).GetFields();
    foreach (FieldInfo fi in fis)
    {
    DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
    if (attributes.Length &gt; 0)
    {
    if (Guid.Parse(attributes[0].Description) == val)
    {
    if (Enum.IsDefined(typeof(ProjectType), fi.Name))
    type = (ProjectType)Enum.Parse(typeof(ProjectType), fi.Name);
    break;
    }
    }
    }
    if (type.HasValue)
    return type.Value;
    else
    throw new FormatException(string.Format(&quot;'{0}’ is not a valid Project Type’s Guid&quot;, val.ToString()));
    }

    public static List&lt;ProjectType&gt; GetMSBuildProjectTypes(string localProject)
    {
    var projectCollection = new ProjectCollection();
    Project project;
    try
    {
    project = projectCollection.LoadProject(localProject);
    }
    catch (Exception ex)
    {
    throw new Exception(string.Format(&quot;Project Type cannot be determined as ‘{0}’ is not a valid VS project.&quot;, localProject), ex);
    }

    var projectTypes = GetMSBuildProjectTypes(project);

    projectCollection.UnloadAllProjects();

    return projectTypes;
    }

    public static List&lt;ProjectType&gt; GetMSBuildProjectTypes(Project project)
    {
    try
    {
    var projectTypeGuids = (from property in project.Properties
    where property.Name == &quot;ProjectTypeGuids&quot;
    select property.EvaluatedValue).FirstOrDefault();

    List&lt;ProjectType&gt; projectTypes;
    if (string.IsNullOrEmpty(projectTypeGuids))
    projectTypes = new List&lt;ProjectType&gt;();
    else
    projectTypes = (from guid in projectTypeGuids.Split(‘;’) select Parse(guid)).ToList();

    return projectTypes;
    }
    catch (Exception ex)
    {
    throw new Exception(string.Format(&quot;Unable to determine the project type of ‘{0}’ due to: {1}&quot;, Path.GetFileNameWithoutExtension(project.FullPath), ex.Message));
    }
    }
    }
    }
    [/csharp]

    Loading

    ,
  • Customize TFS 201x – my sources of information

    Team Foundation or Team Build can be customized a lot with e.g. our own Build Process Templates, Build Activities or Plug’ins (like TFS Server-Side Event Handlers since TFS 2010). The biggest issue is usually to locate the required Microsoft assemblies on our PC and find the relevant documentation about the “TFS API’s”.

    Click to Read More

    On my own, I had among other to:

    1. Extend TFS with a plugin to check Policies server-side:.
      • This one enforces our branching strategy,
      • Check quota usage and maximum file size,
      • Restrict the file types that can be stored in TFS (no ISO, VHD, MKV – you can’t imagine what end-users can try to store in source control),
      • Validate project folders hierarchy according to our Design patterns, etc…

      Implementing Policies server-side is minimizing the maintenance efforts (nothing to distribute on all the development workstations), fixes are effective immediately after deployment, Policies are enforced for all clients and nobody can bypass them, …

    2. Create customize Build Process Templates to
      • Build Microsoft Setup Projects and Biztalk Projects,
      • Support automatic build deployment,
      • Support online Server maintenance and graceful TFS reboot (waiting on current build to complete before updating or rebooting the server),
      • Validate Build Definitions against our Policies (Build Timeouts, Drop folders location, etc…).

      For any task to be run on Build Servers, we use Custom Build Activities and Custom Build Process Templates, so those tasks can be easily integrated within the Build Schedule, …

    3. And finally, create Visual Studio Plugins to automate some TFS operations, e.g.:
      • Right click a Build to retrieve all its binaries and their sources in order to pass them to our in-house SCRM tool (a.o.: for backward compatibility between TFS and our Release Distribution processes),
      • Right click a Build to automatically create an Maintenance Branch from its sources in order to implement some fixes, …

    I used to be quite comfortable with the customization of Team Build 2005 and 2008, using custom complex MSBuild Scripts. But I didn’t find it easy to start the customization of Build Process Templates using the online MSDN documentation available for Team Build 2010 (i.e.: actually nothing relevant). I did also initially find difficult to implement the same features server side and client side as equivalent TFS API’s are implemented in distinct Microsoft Assemblies and have distinct signatures…

    Fortunately, there are always pioneers who are digging new stuff and publishing their findings on the web. So nowadays we can find a lot of information although the MSDN online documentation is still really poor. Here are my three main sources of information:

    And so far, it seems to me that the changes between TFS 2010 and TFS 2012 are much smaller than between TFS 2008 and TFS 2010. Knowledge only needs to be extended a bit, and not completely renewed. And again, we can count on great blogs to help.

    Loading

  • Cannot remove/cancel/delete Print jobs

    I did recently had to restart the “Print Spooler” Service to clear the Print job queue where a job was stuck and refused to abort.

    Click to Read More

    I did download the free software – HP Photo Creations – from HP to print at home calendars, greetings cards, etc… It’s missing some essentials features IMO, like “align” pictures/text/etc… but it’s not that bad.

    I just add one issue while printing one of my creation on my PhotoSmart C6280, which is most probably related neither to that model nor to HP Photo Creations, but to the HP Drivers and/or Windows 7: One of the print job in the queue never started to print…

    When print jobs are currently queued/printing, you should see a printer icon :printer: in the notification area. Click on this one to open the print queue. If you don’t see this icon, you can still open the queue  by clicking the Start button :start:, clicking Control Panel, clicking Hardware and Sound, and then clicking Devices and Printers. There, double-click your Printer to open its status window and access the Print Job Queue.

    In that queue, I found my print job in first position, apparently stuck… So I decided to cancel it (right click the job and select “Cancel”). Its status became something like “Deleting – Error – Printing” but the job never disappeared from the queue. Usually, the printer is displaying an error message (e.g.: no paper or ink any more) and once this error solved, the job disappears. But if you don’t find what’s wrong, the easiest solution consists in clearing the queue (including all the other pending jobs if any):

    1. Click Start-R to run a command and type services.msc to open the Service Administration console.
    2. Find the services “Print Spooler” in the list of services (As a tip: Select the first service and type “Print”. The cursor will move directly to the first matching name in the list)
    3. Right-click this “Print Spooler” service and Select “Restart”
    Et voilà. The Print Job Queue is now empty…

    Loading

  • Target multiple environments with only one TFS Build Server

    I had customize our Build Process Template to support multiple target environments on a single Build Machine. I.e.: to resolve the “file references” at Build time depending on the environment targeted for the deployment.

    Click to Read More

    At work, we have mainly four distinct environments: Integration, Qualification, Pre-Production and Production. Each application (and its referenced assemblies) are promoted from one environment to the next one via tasks (Release Distribution jobs) scheduled according to a predefined monthly Release Plan…

    TFS Build Machines not only compile the applications to be deployed via the standard Release Distribution, but also the urgent fixes to be deployed directly in Pre-Production without passing through Integration and Qualification environments. It also happens, although really quite seldom, that a Build skips the Integration and goes directly to Qualification.

    It’s also to be noticed that none of our applications (assemblies) are strong named and deployed in the GAC, neither on development workstations nor on servers. Instead, all referenced assemblies are always copied within the application’s bin folders, also on the servers.

    Therefore, basically, we would need Build Machines dedicated for each target environment with the adequate assemblies made available on them, for reference resolution purpose. That would be a pity to have such Build Machines (and the related setup, maintenance, backup costs, …) for at most one build per month (Fix in Production and Qualification are fortunately not common).

    To avoid that,  I did customize our Build Process Template to take a Reference Path as input and to pass it to MSBuild. Actually, when editing a Build Definition, the Builder can select the target Environment, and the Build will simply receive a path to the location containing the related assemblies.

    Ex.: MSBuild mySolution.sln /p:ReferencePath=”c:\RefAssemblies\Qualification\”

    How can I be sure that this Reference Path won’t interfere with any Hint Paths defined in the Visual Studio projects?

    First, note that the location provided to MSBuild via the “ReferencePath” parameter will be probed to resolve all “file references” before any other location on the standard probing path. But we also pay attention to not make the assemblies available on the Hint Path on the Build Machines:

    • On Development Workstations, all our assemblies are made available in a single “Reference Assemblies” folder. Developers add references on assemblies in there for development and local testing purpose. They can also start a task at will to update this “Reference Assemblies” folder with the latest version of the assemblies (the versions used in the Integration Environment) or with the version currently deployed in the Qualification or Production Environments (e.g.: for bug fixing purpose).
    • On the Build Machines, there is one “Reference Assemblies” folder per environment (i.e.: updated by the Release Distribution with the assemblies currently in use in that environment). None of those folders is located at the same path as the “Reference Assemblies” folder of the Development Workstations. As a result, MSBuild cannot use the Hint Paths found in the Visual Studio projects to locate the referenced assemblies. Instead, it uses the path of the “Reference Assemblies” folder passed to it via its parameter /p:ReferencePath.

    In addition to the “Reference Assemblies” folders per environment, we also have one  extra folder containing the output of each latest successful Build. This one is used for “Continuous Integration“. No need to update the references in the Visual Studio Projects, MSBuild always find in that folder the latest version of each assembly recently built on any Build Machine (if requested to do so via the Build Definition). This is by the way the default “target environment” for all “Rolling Builds” defined on “Development Branches”, so any breaking features in a new version of a referenced assembly is immediately detected. Builds “candidate” to be promoted use by default the Reference Path with the assemblies from the Integration environment.

    Loading

    ,
  • .Net: Do not Split your Strings

    It could result in an “Out of Memory Exception” on really large strings as a colleague experienced last week.

    Click to Read More

    I admit I used to call Split a lot too as it’s really easy and spares me a bunch of code. Ex.: to parse lines of a CSV file. And yet, the documentation on MSDN is clear about Split performances:

    The Split methods allocate memory for the returned array object and a String object for each array element. If your application requires optimal performance or if managing memory allocation is critical in your application, consider using the IndexOf or IndexOfAny method, and optionally the Compare method, to locate a substring within a string.

    Here is a guy who deeply analyzed the memory issue which occurs when splitting a very large string : “Out of Memory Exception

    And if you need to parse the content of a large .csv, here is an efficient custom parser that can be used instead of calling Split on each line: “Fast CSV Reader

    Loading

  • Line Break versus Paragraph in WordPress

    For a WordPress beginner (at least for me, who used to write html in notepad++), when editing a post, it is irritating that the ‘Enter’ key is not simply adding a line break but starting automatically a new paragraph instead, especially when typing some pieces of code.

    Fortunately, there is a trick to add a line break without starting a new paragraph.

    Click to Read More

    A new paragraph is usually started after a “Hard break” also known as a “Carriage Return”, which is indeed the default when typing “Enter” in a Word Processor. At the opposite, a simple “Line break” also known as “Soft Break” does not start a new paragraph and result in a normal line-spacing.

    Ex.: The white-space between the previous text and this line is due to a “paragraph separator”. But here after, you will see two lines A. and B. separated by a simple line break.

    A. first line of text
    B. second line of text

    Instead of typing “Enter” at the end of the line A., press “Shift-Enter” instead. That wilt result in a “soft break” (line break) instead of a “hard break” (carriage return).

    Loading

    ,
  • Add categories as dropdown menu in WordPress Navigation Bar

    Edit the file header.php of your theme to add such a menu.

    Click to Read More

    On Synology, this file is accessible via the “web” shared folder (See here for details) at:

    \\<YourSynology>\web\wordpress\wp-content\themes\<YourTheme>\header.php

    Find the right location in the code generating the navigation bar and add something like this (using the adequate ‘class’ from you own theme. Here after, I am using TwentyEleven.)

    [html]

    <!– Add a drop dow menu with all the categories –>
    <div style="text-align:center;">
    <ul id="menu" style="padding:0; margin:0;">
    <li class="cat-item">
    <a href="#" title="Filter by categories.">Categories</a>
    <ul class="children">
    <?php wp_list_categories(‘sort_column=name&sort_order=asc&
    style=list&children=true&hierarchical=true&
    title_li=0&exclude=1’); ?>
    </ul>
    </li>
    </ul>
    </div>

    [/html]

    Instead of href=”#” (to stay on the current page when selecting the head of that menu), you could also use:

    [php]href="<?php echo esc_url( home_url( ‘/’ ) ); ?>"[/php]

    The parameter “exclude=1” is used to skip the category “Uncategorized”. You can add other category IDs to be skipped separated with a comma. To determine the ID of a category, go to “Administration Dashboard > Posts > Categories” and move the mouse over the “Edit” link for that category. Look at the URL displayed by the browser for that link; this one includes the category ID as a parameter: “&tag_ID=xxx”

    Loading

  • Connect to TFS from VS with multiple accounts

    Assuming that you are using Windows Integration Authentication to access TFS, any instances of Visual Studio run during a Windows session will always use the current user to access TFS… Fortunately, there is a simple trick to connect on TFS with multiple accounts without starting new Windows sessions with other users.

    Click to Read More

    If like me you are a TFS administrator, you could indeed need to switch quite often from one user account to another. e.g.: to work in TFS with another profile (Contributor or Builder) and validate various configuration settings (security, etc…).

    In such a case, the easiest is to right-click on the Visual Studio Shortcut (e.g.: in the Start Menu >  All Programs > etc…) and select “Run As…”. Then enter the windows account to be used to connect to TFS.

    Notice: Each time you will do that for the first time with a new account, Visual Studio could start much slower than usually as it has to create a new profile…

    Notice: The account used to “Run As…” Visual Studio won’t become the new default account. I.e.: it won’t be reused the next time you run Visual Studio!

    You can also edit the properties of the shortcut to Visual Studio (or create a copy of that shortcut). Then, click on the “Advanced” button in the “Shortcut” tab and tick the option box “Run with different credentials”. Doing that, you will always be prompted to enter an account when running Visual Studio.

    To permanently change the default account used by Visual Studio to connect on TFS, I read that we have to change the credentials used for the that TFS server in the “Credentials Manager” (Control Panel > User Accounts > Credential Manager). Unfortunately  I may not do that here at the office :/

    To check with which user you are connected to TFS, check-out any file and have a look on the “User” column in the “Source Control Explorer”.

    Notice: You may run two instances of Visual Studio with distinct accounts simultaneously. There won’t be any “conflict”.

    Loading

    ,
  • Drivers Update Monitor: My-Config

    My-Config
    My-Config

    My-Config is from far the best and less intrusive online tool I found to check if your drivers are all up-to-date. And it’s free.

    Click to Read More

    My-Config which is mainly a web based tool (online) can detect your hardware and software configuration. It find next the appropriate drivers and  search for WHQL-certified (or beta as an option) updates compatible with your computer on the web site “TousLesDrivers.com”. It comes however with an offline modules to, among other, run analysis when disconnected from Internet.

    Depending on your hardware (i.e.: if there are the adequate sensors) My-Config is also able to report on your components’ activity: voltage or temperature of the processor, of the graphics card, etc. .

    After a complete analysis of your PC, you should focus on the summary pane. This one displays the drivers for which an update has been found. Next to each one, you have a button to download the update from “touslesdrivers.com” web site.

    The other panes show information on your hardware, installed applications, running process, startup programs, …. But nothing out of the ordinary here.

    A great feature is however the “network mode“. The offline module of My-Config can indeed be installed on remote PC in your LAN and configure to run as a service protected with a password. This remote service can next be query from any PC to display its analysis report. The offline module can be configured as a service via the menu Start > All Programs > ma-config.com > Settings. In that window, select the Network mode, a password, and click “start”.

    On PC not connected to Internet, you can run an offline analysis using the offline module via the menu Start > All Programs > ma-config.com > Settings. In that window, click the “Detect” button. This is going to save an analysis report in a file. Copy this file on a USB ley and go to a PC connected to internet. Finally, upload the file on http://www.ma-config.com/en/detectoffline (see the bottom of that page)

    Notice: if you PC runs fine, there is no reason to update anything. Updates are usually more a source of issues than a real improvement for your PC (except “Security” updates)…

    To check for programs update, have a look on Sumo

    Loading