ArtinSoft's Blogs

Software Migration Experts
Welcome to ArtinSoft's Blogs Sign in | Join | Help
in Search

Mauricio Rojas Blog

April 2008 - Posts

  • ActiveX Controls in .NET and the Enabled bug

    We found and interesting bug during a migration. The issue was that when there was an iteration through the controls in the forms, and you set the Enabled property, the property didn't get set.

    After some research my friend Olman found this workaroung

     

    foreach(Control c in Controls)

      ctrl.Enabled = true;
      if (ctrl is AxHost) ((AxHost)ctrl).Enabled = true;
    }

  • Install Assembly in GAC with C#

     

    Do you want to create a program to install your assembly in the GAC using C#. Well if you had that requirement or you are just curious, here is how.

    I read these three articles:

    Demystifying the .NET Global Assembly Cache

    GAC API Interface 

    Undocumented Fusion

    What I wanted just a straight answer of how to do it. Well here is how:

     

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.GAC;
    //// Artinsoft
    //// Author: Mauricio Rojas orellabac@gmail.com mrojas@artinsoft.com
    //// This program uses the undocumented GAC API to perform a simple install of an assembly in the GAC
    namespace AddAssemblyToGAC
    {
        class Program
        {
            static void Main(string[] args)
            {
                // Create an FUSION_INSTALL_REFERENCE struct and fill it with data
                FUSION_INSTALL_REFERENCE[] installReference = new FUSION_INSTALL_REFERENCE[1];
                installReference[0].dwFlags = 0;
                // Using opaque scheme here
                installReference[0].guidScheme = System.GAC.AssemblyCache.FUSION_REFCOUNT_OPAQUE_STRING_GUID;
                installReference[0].szIdentifier = "My Pretty Aplication Identifier";
                installReference[0].szNonCannonicalData= "My other info";
     
                // Get an IAssemblyCache interface
     
                IAssemblyCache pCache = AssemblyCache.CreateAssemblyCache();
                String AssemblyFilePath = args[0];
     
                if (!System.IO.File.Exists(AssemblyFilePath))
                {
                    Console.WriteLine("Hey! Please use a valid path to an assembly, assembly was not found!");
                }
                int result = pCache.InstallAssembly(0, AssemblyFilePath,installReference);
     
                Console.WriteLine("Process returned " + result);
                Console.WriteLine("Done!");
     
            }
     
        }
    }

    And here's the complete source code for this application: DOWNLOAD SOURCE CODE AND BINARIES

  • Useful MSBuild Custom Tasks

    I present here the implementation of some useful tasks
    In Artinsoft we perform massive migrations of VB6 code to VB.Net
    and C#.

    And sometimes after migration there are customizations to be
    performed on the code, to add new functionality or to set certain new
    properties.

     The idea was to provide a couple of very simple and puntual MSBuildTask
     to illustrate how easy it is to create custom tasks and to provide a starting
     point to create new one.

     You can freely use this code, just keep this comments and remember this is just
     a sample code. There are not warranties. ;) And i made it a rush I know it could have
     been written better

     Artinsoft
     mrojas@artinsoft.com
     

    The implemented tasks are:

    RemoveCOMReference 
     Removes COMReferences from your project. COM references are for when you are using things thru Interop
    FixOutputPath 
     Resets the output paths to bin\Release and bin\Debug
    AddProjectReference Add a reference to another project. A nice feature is that it generates RelativePaths the way Visual Studio does
    AddSimpleReference Add a reference to a very simple references like the ones you add when you click Add Reference and add System.EnterpriseServices
    ChangeCurrentBuildSetting This can be used for a lot of things.

    For example to turn on or off the RegisterForComInterop setting

    To set conditional compilation variables

    To set debug info to pdbonly

    The sky is the limit jeje

    The following is a sample project file

    <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <!-- make sure that the Assembly is in a place where msbuild can find it, a simple way is just to put it 
    in the same directory of your .proj file -->
    <UsingTask TaskName="SomeUsefulTasks.MSBuild.RemoveCOMReference"    
      AssemblyFile="SomeUsefulTasks.dll"/> 
    <UsingTask TaskName="SomeUsefulTasks.MSBuild.FixOutputPath"         
      AssemblyFile="SomeUsefulTasks.dll"/> 
    <UsingTask TaskName="SomeUsefulTasks.MSBuild.AddProjectReference"   
      AssemblyFile="SomeUsefulTasks.dll"/> 
    <UsingTask TaskName="SomeUsefulTasks.MSBuild.AddSimpleReference"    
      AssemblyFile="SomeUsefulTasks.dll"/> 
    <UsingTask TaskName="SomeUsefulTasks.MSBuild.ChangeProjectBuildSetting"    
      AssemblyFile="SomeUsefulTasks.dll"/> 
     
       <ItemGroup>
        <VSProjects Include="$(Start)\**\*.*proj" />
      </ItemGroup>
     
    <!--
    Run with 
    MSBUILD SampleProject.proj /target:COMReference /p:Start="C:\MyCode"
    -->
      <Target Name="COMReference">
        <RemoveCOMReference SourceFiles="@(VSProjects)" ComReferenceName="MSXML2" />
      </Target> 
      
      
    <!-- 
    Adds a project reference  
    Run with 
    MSBUILD SampleProject.proj /target:AddProjectReference /p:Start="C:\MyCode" /p:ProjectPath="C:\MyCode\MyNewSuperProject\Project1.csproj"
    -->
       <Target Name="AddProjectReference">
          <AddProjectReference SourceFiles="@(VSProjects)"  AbsolutePathToProject="$(ProjectPath)"/>
       </Target> 
       
       
    <!-- 
    Adds a reference to a standard assembly 
    Run with 
    MSBUILD SampleProject.proj /target:AddSimpleReference /p:Start="C:\MyCode" /p:Reference="System.EnterpriseServices"   
    -->
    <Target Name="AddSimpleReference">
          <AddSimpleReference SourceFiles="@(VSProjects)" Reference="$(Reference)" />
    </Target> 
     
      
    <!-- 
    Resets the OutputPaths to .\bin\Debug and .\bin\Release 
    Run with 
    MSBUILD SampleProject.proj /target:FixOutput /p:Start="C:\MyCode" /p:Reference="System.EnterpriseServices"   
    -->
    <Target Name="FixOutput">
        <FixOutputPath SourceFiles="@(VSProjects)"  />
    </Target> 
      
    <!-- 
    Adds a reference to a standard assembly 
    There are several options here for example to set the project debug info to pdb-only do this:
    Run with 
    MSBUILD SampleProject.proj /target:ChangeSettingToPDBOnly /p:Start="C:\MyCode" 
    Or run with 
    MSBUILD SampleProject.proj /target:ChangeSettingAddAConstant /p:Start="C:\MyCode" 
    Or run with 
    MSBUILD SampleProject.proj /target:SettingComInterop /p:Start="C:\MyCode" 
    -->
     
    <Target Name="ChangeSettingToPDBOnly">
          <ChangeProjectBuildSetting 
              SourceFiles="@(VSProjects)" 
              ConfigurationType="All" 
              Setting="DebugType" 
              NewValue="pdbonly" />
    </Target> 
       
    <Target Name="ChangeSettingAddAConstant">
          <ChangeProjectBuildSetting 
              SourceFiles="@(VSProjects)" 
              ConfigurationType="All" 
              Setting="DefineConstants" 
              NewValue="MYNEWVAL" 
              Add="True"/>
    </Target> 
     
     
    <Target Name="SettingComInterop">
          <ChangeProjectBuildSetting 
              SourceFiles="@(VSProjects)" 
              ConfigurationType="All" 
              Setting="RegisterForComInterop" 
             NewValue="true" />
    </Target> 
     
      
    </Project>

    DOWNLOAD CODE AND BINARIES

  • Get Relative Path

    I had the requirement of creating a MSBuild custom task that opens a .csproj
    adds a reference to another project.

    The problem I faced is that references in VisualStudio are generated as relative paths,
    so I needed something to help me generate relative paths.

    After some Googleing I finally found this code. It was in a long forum discussion
    and was posted by a guy named something like Marcin Grzabski. And here it is for posterity.

            private static string EvaluateRelativePath(string mainDirPath, string absoluteFilePath)
            {
                string[]
                firstPathParts = 
                 mainDirPath.Trim(Path.DirectorySeparatorChar).Split(Path.DirectorySeparatorChar);
                string[]
                secondPathParts = 
                 absoluteFilePath.Trim(Path.DirectorySeparatorChar).Split(Path.DirectorySeparatorChar);
     
                int sameCounter = 0;
                for (int i = 0; i < Math.Min(firstPathParts.Length,secondPathParts.Length); i++)
                {
                    if (
                    !firstPathParts[i].ToLower().Equals(secondPathParts[i].ToLower()))
                    {
                        break;
                    }
                    sameCounter++;
                }
     
                if (sameCounter == 0)
                {
                    return absoluteFilePath;
                }
     
                string newPath = String.Empty;
                for (int i = sameCounter; i < firstPathParts.Length; i++)
                {
                    if (i > sameCounter)
                    {
                        newPath += Path.DirectorySeparatorChar;
                    }
                    newPath += "..";
                }
                if (newPath.Length == 0)
                {
                    newPath = ".";
                }
                for (int i = sameCounter; i < secondPathParts.Length; i++)
                {
                    newPath += Path.DirectorySeparatorChar;
                    newPath += secondPathParts[i];
                }
                return newPath;
            }

    And to use is just do somelines like:

     

                String test = EvaluateRelativePath(@"E:\Source_Code\Code\ProjectsGroup1\Project1", @"E:\Source_Code\Code\ProjecstGroup2\Project2");
     
    //This will genearate something like ..\..\ProjectGroup2\Project2
Powered by Community Server (Non-Commercial Edition), by Telligent Systems