Installing an assembly to the GAC and the local file system

Some products require that assemblies be installed to both the global assembly cache (GAC) and to the local file system.  Windows Installer has native functionality that allows a setup author to do both.  You can author an assembly as a global assembly (which will cause Windows Installer to install the file to the GAC) by adding it to the MsiAssembly and the MsiAssemblyName tables of the MSI and setting the File_Application column of the MsiAssembly table to Null.  You can author an assembly as a private assembly (which will cause Windows Installer to install the file to the local file system) by adding it to the MsiAssembly table and setting the File_Application column to a file entry from the File table of the MSI.  Windows Installer will take the file entry, look up the component that owns it and then use the directory entry associated with that component to install the private assembly to that same directory.

One of the first questions that comes up when a setup developer is trying to install an assembly to multiple locations is how to author the data in the MSI to install the same assembly component to both the GAC and the local file system.  In most cases where a setup needs to install the same file to multiple locations, you can use the DuplicateFile table.  Unfortunately, the DuplicateFile table does not support installing an assembly as both a global and a private assembly.  In other words, you have the option to indicate that an assembly is a private assembly or a global assembly, but not both.  In order to install the assembly to both the GAC and the local file system, you will have to create a second component and author one component as a global assembly and the other component as a private assembly.

We have to install assemblies to both locations as part of the .NET Framework and Visual Studio setups.  In the case of the .NET Framework, the underlying architecture requires that the assemblies that are part it be installed to the GAC (for 3rd party applications) and to the local file system (for design-time scenarios in Visual Studio).  However, we had to carry 2 copies of each assembly in the setup package in order to install to both places because Windows Installer doesn't support using the DuplicateFile table to do this.  Carrying 2 copies of each assembly caused the overall size of the .NET Framework 1.0 and 1.1 redistributable setup package to grow even larger than it already was.  After looking at a lot of different options, we decided to implement a custom action solution in .NET Framework 2.0 that would manage the installation of assemblies to both the GAC and the local file system.  This allowed us to only carry a single copy of each file in the setup package and reduce the overall size of the .NET Framework setup by about 5 megabytes.  Of course, if you compare the size of dotnetfx.exe between versions 1.1 and 2.0 you won't see much of a difference.  What ended up happening was that the size of the features added in .NET 2.0 roughly cancelled out the size of the assemblies that we were carrying duplicate copies of in .NET 1.1.


Comments (23)
  1. John Gibbs says:

    Interesting post, but could you elaborate on what the custom action is doing? For example, is the MSI installing the private assembly and then the CA taking the file that was installed and installing a copy to the GAC? Thanks!

  2. Hi John – thank you for the feedback. Essentially what the custom action is doing is calling the same Fusion APIs that gacutil.exe does to install a copy of the assembly to the GAC. I will have to look at the source code because I don’t remember for sure if the custom action uses the private assembly (the copy already installed to the local file system) or if it uses the file carried with the setup package and installs from the source location. I believe it uses the source files because otherwise the custom action would require that 2 copies be installed. I’ll confirm that this weekend and post an update here when I find out.

    Also, for reference, here is a good overview of some of the Fusion GAC APIs from a member of the Fusion development team –

  3. Hi again John – I confirmed by looking at the custom action source code that it is using standard MSI API calls to query the contents of the Assembly and AssemblyName tables and then using the source files carried with the setup package to install to the GAC. Note that this custom action does NOT use the standard MSI tables (which are named MsiAssembly and MsiAssemblyName).

  4. Paul says:

    First off, thanks for posting this. I tried using Windows Installer (via InstallShield 10.5) to create a global assembly and use the DuplicateFile table to create local copy of the assembly. The error I am getting is "1308 Source file not found". For some reason it is trying to copy from C: instead of the source directory or the GAC. It this the error your would expect?

    Thanks again,


  5. Hi Paul – I am not positive what error to expect if you try to use the DuplicateFile table to install an assembly to the GAC and the local file system. When we originally designed this architecture for the .NET Framework, Windows Installer didn’t even support installing assemblies to the GAC at all, so we worked with them to develop that feature and ended up authoring our MSIs with duplicated components from the beginning. I believe that since Windows Installer uses fusion APIs to install assemblies to the GAC rather than handling installation directly, that this would explain why you see a 1308 error. Since it uses fusion, Windows Installer does not have any knowledge of the exact physical location on disk for assemblies that are installed into the GAC.

  6. TKent says:

    I have used the Windows Installer that comes with Visual Studio 2003 to install a file both on the local file system and in the GAC. Steps to follow:

    1) Create a Setup project (under Setup and Deployment Projects templates).

    2) Open the File System Editor (if it is not already open) by selecting the "View -> Editor -> File System" menu item.

    3) For local file system files:

    a) Select a desired folder in which to install the files (such as Application Folder) and add one or more files to the folder (right-click on folder and select "Add -> File…", and then select file).

    b) Configure the properties for the folder to point to the desired destination folder on the target machine.

    4) For installing into the GAC:

    a) Right-click in File System Editor window and select "Add Special Folder -> Global Assembly Cache Folder" menu item to add the GAC folder to the list.

    b) Add one or more assemblies to the GAC folder (right-click on folder and select "Add -> File…", and then select file).

    5) Build your Setup project and then run the resulting Setup.exe (or execute the resulting .msi). During installation, Installer will copy the designated files to the destination on the target machine and install designated assemblies to the GAC. During removal, the Installer will reverse the installation process.

  7. Hi TKent – thank you for the detailed instructions. These steps will end up creating an MSI that contains 2 components for each assembly – one to install the assembly to the local file system and another to install the assembly to the GAC.

  8. I wrote this post a couple of months ago describing how to install an assembly to both the GAC and the…

  9. Shyamal Bhowmik says:

    I want a basic help in creating a web set up project which will install my assembly to the GAC and also register it using regasm to be accessed from asp web pages. All should be done when I run the MSI to install the MSI on a machine.

    Thanks and regards

    Shyamal Bhowmik

  10. Hi Shyamal – There are a lot of resources available on the web for building MSI-based setups.  You can look at the Windows Installer site on MSDN at  I would also suggest trying to use WiX to build your MSI.  You can download the WiX toolset at and there is an excellent tutorial for WiX at

    One thing I would recommend is to not use regasm.exe as a custom action during your setup.  Instead, you should extract the registry information and install those keys/values using the Registry table of your MSI.  That will provide a more robust setup experience for your users.

  11. Rob Mensching posted an item on his blog last night that I wanted to bring to your attention. Recently,

  12. Question: I am creating an MSI-based setup using WiX . One of the files that I am installing is authored

  13. dev says:

    I have to get the details from the manifest file of the assembly . but i don't have the source. basically i need to put the details in the MSIAssemblyName table for that assembly.How to do it?

  14. Hi Dev – If you are using WiX to build your MSI, it will automatically scan the assembly and populate the values in the MsiAssemblyName table for you.  If you're not using WiX, you can use a tool like Reflector to look at the assembly and figure out the assembly identity, and then populate the appropriate values into the MsiAssemblyName table of your MSI.

  15. dev says:

    Hi Aaron – I came across a tool called mt.exe. that I am using for extracting the manifest information from assembly. basically we have our own application for creating msi packages. We want to install some of the assemblies in the local file system as well as in the GAC (the same assemblies). as per your article we need to have two copies of those assemblies. my question is that: can't  we have two separate entries in the component table for a single assembly file. one component will be used for installation in local file system and the other component will be used for the  installation of the assembly in the GAC ?

  16. Hi Dev – You will need to author 2 entries in the MSI Component table to install the same file to both the GAC and the local file system.  Entries in the MSI File table can only refer to one component though, so you'll also need to author 2 entries in the File table.  WiX includes a feature called "smart cabbing" that is used in this type of scenario to avoid needing to carry 2 identical copies of these files in an installer – see…/quotSmart-cabbingquot-added-to-WiX-toolset for more details if you're interested.  If you're not using WiX, you would have to either implement something this in your .cab build process, or you would have to live with the duplicate copy of the file in your installer payload.

  17. dev says:

    thanks Aaron – I am facing one more problem: while adding entries to MsiAssembly and MsiAssemblyName Table of msi database using MsiOpenDatabaseView() method it is justing failing with the error code – 1615. This is the case with only these two tables. At First I thought It would be due to the reason that I dint change the Application Type to .NET. but after changing that also it is not working. Then I tried updating  _Validation table for the entries of MsiAssembly and MsiAssemblyName tables. It too dint work out. Probably I am missing some dependency which is hindering the records to be entered in MsiAssembly and MsiAssembly Tables.  can u give me some clue or hint about this problem?????? thanks.

  18. Hi Dev – Error code 1615 means "The SQL query syntax is invalid or unsupported."  I'd suggest double-checking the syntax of the code you're using to update that table and make sure that you're using the correct schema and passing the correct data for each of the fields.

  19. dev says:

    @Aaron – I checked the syntax of the code it is working fine with other tables like Components , Files table etc. then I went for

    Calling MsiGetLastErrorRecord for additional details and passing the resulting handle to MsiFormatRecord results in the following:

    1: 2228

    2: F:SourceMymsi.msi

    3: MsiAssembly

    4: INSERT INTO MsiAssembly (MsiAssembly.Component_, MsiAssembly.Feature_, MsiAssembly.File_Manifest, MsiAssembly.File_Application, MsiAssembly.Attributes)

       VALUES ('Abc.dll','MainApp','Abc','', 0)

       2228: I checkd windows installer error codes, it stands for unknown table but table is present in msi DB. I wonder how it is possible bcoz when I open msi in

       wfwi it is showing the MsiAssembly table. also for other tables it is inserting records why this problem is particular to this table only?

  20. Hi Dev – It sounds like the MsiAssembly table isn't a part of the database schema that your MSI is using or something like that.  I'm not sure about how to fix that type of error though, so I think you may need to post a question on one of the Windows Installer forums and see if someone there can help suggest ideas for how to fix this type of error.  I'm sorry that I'm not able to be more helpful in this scenario.

  21. dev says:

    Thanks Aaron – I have somewhat resolved the issue . basically some of the msi database tables are reported to be unknown when they are empty. If they contain atleast one record then everything works fine while inserting records. so I edited the generic msi file we use for packaging by inserting a dummy file entry. but I think it is not an intelligent fix…….nyways I will try for some other better fix. thanks for guiding.

Comments are closed.

Skip to main content