Why to not use gacutil.exe in an application setup

I read the article titled Using the .NET fusion API to manipulate the GAC yesterday.  That article describes how to call fusion APIs from C++ code to programatically add assemblies to the global assembly cache (GAC) instead of using the .NET configuration utility or gacutil.exe.

In general, installing an assembly to the GAC is an application deployment activity, and is most often done during application setup.  The article I read does not specifically say that C++ code should be used to install assemblies during application setup, but it does not say not to either.  Therefore, I wanted to make sure that anyone reading this blog knows that you should not use C++ code or gacutil.exe to install assemblies during setup of your application.

You should use Windows Installer to install your application.  Starting with version 2.0, Windows Installer has built-in functionality to install assemblies to the GAC - the MsiAssembly and MsiAssemblyName tables in particular.  You can refer to this MSDN document for an overview of how to add assemblies to an MSI package and this MSDN document for a description of how to add Win32 assemblies to an MSI package.  Therefore you should use this built-in functionality to handle GAC installation and uninstallation for you.

I would also like to point out that the Windows Vista Logo Program requirements document contains the following statement:

Gacutil must not be called from a custom action. Gacutil is not designed to be used during installation.

This means that if you want to obtain Windows Vista Logo certification for your application, you should use Windows Installer and the built-in GAC installation functionality for your setup.

Comments (35)
  1. Aaron Fischer says:

    That’s not really a solution for vendors not currently using msi.  I assume this is why there is no gacutil installed in vista?

  2. Hi Aaron – This is not the only reason why gacutil is not included in Windows Vista.  Gacutil has always been an SDK tool and not a part of the .NET Framework redistributable.  It was inadvertantly included as part of the version of the .NET Framework that is installed on Windows Server 2003, but that was a mistake on our part because it led to setup developers using it to install their assemblies instead of the standard MSI functionality.

    Can I ask why you are not using MSIs for your solutions (and try to convince you to switch)?

  3. ehuna says:

    We have an application that has been on the market for over 10 years.

    For the last few years we have been using InstallShield.

    This means that every time we release a new version our customers can easily upgrade to the latest bits: InstallShield will see the previously installed version and upgrade accordingly (it might be using MSI in the backend, but I don’t really care).

    If we switched to MSI only how would this upgrade process work?  Would we have to tell thousands of our customers to first uninstall the previous version (InstallShield) and then run the new MSI installer?

    Even if we were able to easily implement the above, we now need to get new expertise in the team: our current build team knows how to work with the InstallShield projects and not pure MSI.

    There’s no reason not to leave gacutil in the .NET distributable – it works.  

    Saying that it was supposed to just be an SDK app is not a reason – it seems like you just want to make it harder to anyone who is not using MSIs.

  4. Wayne2K says:

    Personally, I feel that using Windows Installer causes more problems than it’s worth.

    For instance…when I start a program that was installed with Windows Installer, msiexec runs and makes sure that every-single-advertised-item exists *where it was originally installed* before the program runs. So if I install a program that had created a "My New Folder" somewhere inside of "My Documents", and I deleted that folder at some time, msiexec will keep creating a new one…it’s annoying.

    Another instance: Advertised shortcuts in the start menu break the "Find Target" function of the shortcut properties page.

    Another instance: Installing Program A that uses a dll from Program B and then running Program A sometimes causes Program B’s installer to run everytime Program A is executed.

    Lastly, there aren’t a whole lot of good free simple Windows Installer Setup Creator programs out there. Also, look at Inno Setup and compare one of it’s very simple and straight-forward setup scripts to something like a Wise .wsi file and see how over-engineered Windows Installer really is.

  5. Digital Wired says:

    Maybe because we as developers want to do something a bit more interesting with our installation routines.

    Maynbe because we do cross platform development and want to install on multi platforms.

    Maybe we spent so much time developing our own setup we cannot justify switching to msi.

    Maybe because msi wasn’t available on all platforms without a large download we didn’t bother using it.

    Maybe we wanted to install just a few files and msi was overkill.

    Maybe patching our product is easier when you don’t use msi.

    Maybe we can control security and distribution more leasily.

    Maybe there are more reasons why we don’t want to use an msi file so while you force us to register files in the GAC using an msi people will continue to find ways around it.

    I think it is called choice.

    I personally just copy the file via windows explorer but then I do all the installs myself.

  6. Hi Ehuna, Wayne2k and Digital Wired – Windows Installer has a lot of upgrade options that you can use for your setup.  I typically use the "major upgrade" algorithm (described at https://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/major_upgrades.asp).  This feature lets you update a couple of variables in your MSI and it will automatically uninstall the previous version and then install the new version without the user having to take any extra actions.

    Yes gacutil.exe works, but it is a developer tool, and developer tools go into SDKs and not runtime packages typically.  It isn’t really appropriate to put more tools into the runtime because that causes it to get larger, which makes it more difficult for applications to redistribute because of increased download size, etc.

    We did not leave gacutil.exe out of the redistributable to try to force people to use MSIs or make peoples’ lives harder or anything like that.

    There are a lot of benefits of using MSIs for setup packages – transactionality, reference counting, servicing, and many others.  It is a part of the Windows logo program for this and many other really good (IMO) reasons.

    I understand the cost of switching can be a barrier, but I don’t agree that an MSI is overkill for small packages or that patching is easier using other means.  Patching is a really hard thing to get right in general, and in my experience it is not easy to get it exactly right with MSIs, but it is more reliable and easier to get right with MSIs than with other means.  Windows Installer is widely available on all recent operating systems now, so there generally isn’t a reason to need to carry the redistributable installer for it in a setup package except in some targeted scenarios.  I’m not sure I understand how security or distribution is harder with MSI than with other installers.

    I agree there are some odd behaviors with respect to advertised components in MSIs.  That has been one of the trickiest things I have tried to debug in the past.  There are ways to author an MSI to avoid the advertising issues that are described above though.

    For tools – I use the WiX toolset to create my MSI packages.  It is a shared source tool available at http://wix.sourceforge.net, and there is a great tutorial at http://www.tramontana.co.hu/wix/ to get you jump started if you’re interested in learning more.  You can see an example WiX source file at http://astebner.sts.winisp.net/Tools/q.wxs that I think shows how an MSI can be represented in a relatively clean, simple XML format.

    I’m definitely in favor of choice when it comes to development strategies, algorithms, tools, etc, but I stand by my recommendation to use MSIs for application setups based on the reasons above and my experience with this and other setup technologies.

  7. Aaron Fischer says:

    Our product is over 15 years old we started with install shield and are currently on version 8, because between myself and QA we haven’t had the time to upgrade to the newest version.  Although my preference is to ditch install shield and use msi directly.  All of our new projects use installshield’s msi.  So its not a matter of why not, but rather when will there the time.  The sad part is i don’t like the GAC its problematic, and i don’t want to register any dlls there I just have to.

  8. CWeiss says:

    It’s been a while since I’ve actually dug into this, and maybe all the legacy stuff I’ve been dealing with has been solved, but the big problem I’ve run into is when you’ve got a series of ordered DLL/OCX/Assembly registrations (IE, one file’s registration depends on another file’s registration), the only way to deal with them is by creating a series of custom actions and calling them at the end of the Execute Sequence (I’m speaking in InstallShield terms here). If there’s stuff to be put into the GAC, you’re pretty much locked into GACUtil?

  9. Hi CWeiss – There are some issues if you rely upon assemblies that are a part of the MSI in other parts of the setup process (such as installing services).  Only commit custom actions or those custom actions sequenced after the InstallFinalize action have access to assemblies that are being installed to the GAC using the MsiAssembly and MsiAssemblyName tables during that MSI install transaction.  Your options here are to ensure that your dependencies are installed by a prerequisite package or to author a commit custom action to perform the activities that you rely upon the assembly for.

  10. CWeiss says:

    Ah, now I’m remembering why we did what we did – we’re using VS2005 assemblies and InstallShield 10.5, which doesn’t support the latest Fusion(?) calls. Thus, we were stuck packaging our own GACUtil and installing the assemblies by hand (install to temp folder, then run GACUtil in custom actions at the end of the Execute Sequence).

  11. Christopher Painter says:

    I’d really love to hear a solid reason for why MSI doesn’t call fusion to install assemblies to the GAC until the commit phase.  This is my major problem with this pattern.   The commit phase was meant to cleanup rollback data, not change system state.

    For example I have an install whose requirement is to start a service that not only depends on assemblies in the GAC, but also calls a couple web services that depend on assemblies in the GAC.  I can’t use the StartServices pattern because of this race condition.

    Commit CA’s and immeadiate execution CA’s after InstallFinalize don’t cut it as solutions in my book because of the disable rollback issue and my desire to support managed installations.  Nor do I want to ask for a reboot to get the service in the desired state on startup.

  12. Christopher Painter says:


    What do you mean when you say InstallShield 10.5 doesn’t support Fusion?   For GAC, InstallShield authors a component with an assembly which is a keyfile and then adds it to the MsiAssembly table.  The processing is done at runtime by MSI via the MsiPublishAssemblies action.

    This is the way MSI works and there really isn’t anything wrong with InstallShield in this respect.

  13. CWeiss says:

    Okay, trying to recall through the haze – For some reason, 10.5 didn’t recognize assemblies that were built under VS 2005 as being valid and would throw a 6211 error during the build process (assemblies created in VS 2003 worked fine). The assemblies registered fine when manually running them with GACUtil at the command line on the same machine.

    I can’t find the emails, but I was under the impression this was fixed in IS 11.

  14. Hi Debose – The link you posted describes how to implement the functionality in gacutil.exe in code.  Doing this as part of a setup is no better than running gacutil.exe during setup.  My overall point in this blog post is that you should use built-in Windows Installer functionality to install assemblies (the MsiAssembly and MsiAssemblyName tables) instead of using custom actions unless they cannot be avoided for some reason.

  15. debose says:


     I work in Windows Group at Oracle and to be specific I’m in the team of ODP.NET(the ADO.NET driver for Oracle by Oracle). Here at Oracle, for installation, ubiqutious install tool called OUI(Oracle Universal Installer) is used which is supported in all the platforms Oracle RDBMS has presence of. This beast is very different than MSI. For this installer I’ve to write this gacutil-replica. In other production environments – you are right – MSI should be used.




  16. awerber says:

    I wrote a .NET component to be used by a VB6 program. The VB6 program is used on our user’s desktops, and we have easy access to all of the machines. We have a custom VB6 program that repeats the install any time we upgrade. This program works by uninstalling and deleting all components, then copying them down and installing everything. The copying and installing is done by running DOS programs (like regsvr32) on the client. The easiest thing for me is to use gacutil on the user’s machines. Once that’s there, I can just put any new .NET DLLs into our deployment directory, and they’ll be installed.

    But I’m concerned about how things might work in the future if we upgrade our OS. Is there some equally simple way to do the installation given the way our installation program works?



  17. Hi Awerber – I suggest using an MSI for your installer and directly authoring files, registry and GAC installation steps using built-in Windows Installer functionality instead of using a batch script, regsvr32 and gacutil.  You gain a lot of benefits from using an MSI (clean rollback, uninstall, serviceability, deployment options, etc).

    I’m not sure what to recommend for this script-based install to make it work well across OS upgrades.  You would probably need to validate that the correct version of the .NET Framework is present and then have customers re-run the script to fix things up that might not be registered correctly after the upgrade.

  18. My biggest reason is the the MSI installer stinks for customization.  The custom actions stink.  Why oh why is it that you cannot call an EXE from a setup?  What if I NEED to do that?  The answer:  Create a BATCH or CMD file and have it call the EXE!?!?  Who thought that was a good idea?

    I have used Setup Factory for over 10 years.  I hate InstallShield with a passion.  It is the biggest bloatware out there.  Setup should be simple.  Setup Factory has the ability to write scripts in their basic-like language to modify the registry, install services, stop, start, reboot, whatever.  It is a very easy to use system.

    The very fact that the setup builder in VS 2005 does not comply with MS’s own GUI design guideline is dumb to me.  Everywhere else you can right click / properties and edit the object properties easily.  Not so with the setup tools.  You have to fall through about 10 menus to get the the custom actions and then it throws up a very strange UI that does not match anything else in the system.  Dumb.  It looks like InstallShield licensed bloatware to me.

    I personally don’t care what installs my apps as long as it is EASY for me to build / deploy / update.  There is not a good solution right now for Dot Net Apps.  GacUtil is a nightmare, and one you should not have to worry about.  Do I care how the user got the Dot Net Framework in the first place?  No, I don’t.  It is there as a pre-req.  SHOULD I care how my assembly gets into the GAC?  No, it should be a standard procedure open to everyone.  How do you register a service?  SCM.  How do you register an ActiveX Dll?  Do you need an MSI for that?  No.  They can even self register (imagine that!).

    Install is the achilles heal for us and many other Dot Net houses that I know of.  We built a setup using the VS 2005 integrated mess to deploy an Office toolbar for Outlook.  It did not pickup three key parts you need for ANY Office plugin (PIA anyone?), and it did not work for upgrades without over 10 hours of work on a programmers part.  That is just dumb, sloppy code.  I hated the Package and Deployment Wizard in VB days, and it was better than the current system.

  19. Hi Jasonshortphd – Thank you for your feedback regarding the issues you’ve run into in the deployment space and with the Visual Studio packaging tools.

    If you haven’t already, I’d suggest trying out WiX v3.0 and the Votive Visual Studio add-in for setup development.  You can find more information at http://wix.sourceforge.net/downloadv3.html.

    One question as well – you state that you cannot call an EXE from a setup.  That is possible to do via a custom action in an MSI without needing to use a batch/cmd file.  I’d be curious to learn more about your scenario that led you to conclude that calling an EXE was not possible.

  20. DevTop says:

    In our situation, we have a shared assembly used by many "applets".  We provide a utility that enables the user to select which version of the shared assembly to use.  The utility must ensure that only one version of the shared assembly is installed, and that the corresponding publisher policy is also installed, among other things.  

    We determined it was better to use a custom application versus MSI to provide the funtionality and user experience we desired.  Hence, we are using a .NET wrapper over the Fusion API.

    I don’t really understand the mentality of restricting programmatic access to the GAC and forcing developers to use MSI.  If .NET had a managed class for the GAC, then developers would be insulated from any underlying changes, but still have full programmatic access to the GAC.

  21. rngene says:


       The application I am building uses MSI for installation. However, it has a self-updating functionality. When updates to dlls are published, the application has the capability of downloading them from an update server.

    Some of those dlls live in the GAC, so the app needs to programmatically unregister the old dll and register the new one in the GAC.

      What would be the best approach to do this?


  22. Hi Rngene – If you are using an MSI for initial installation, then updates for your product should be in the form of a Windows Installer patch (MSP).  When you do this, you can update DLLs in the GAC using built-in Windows Installer functionality and should not have any need for gacutil.  You can have your self-updating service download and apply MSPs on users’ systems.

  23. rngene says:

    Hello Aaron:

       Thank you for your quick response! Our application, due to some business requirements, and to make it easier for the final users to manage updates (updates consists in not just dlls, but xsd, xslt and a bunch of other files) does not use MSP. The users just need to copy the files to an update server an edit a manifest xml file.

        So I am guessing using the fusion dll to access the gac is my only option? Any other ideas?

    Thanks again

  24. Hi Rngene – Correct.  If you are not using Windows Installer to manage your updates, then your options include using fusion APIs or gacutil to manage GAC installation.  However, I think you will likely see reference counting issues if you try to remove an assembly from the GAC using gacutil or fusion APIs if it was put there originally by Windows Installer (because Windows Installer places a reference count when it calls fusion APIs to prevent other apps from uninstalling the assembly out from under the product).

    In my experience it is definitely non-standard to perform initial installation using an MSI but perform updates manually.  This can get your system out of sync pretty easily, and you lose a lot of the benefits that MSIs provide (manageability, reference counting, repairs, rollback, etc).  If you need to go this route, please make sure to do in-depth testing to make sure that things behave as you’d expect.

  25. BigLar says:

    Aaron, I am hoping you might respond to new comment (to an old post).  I have just run into this issue with respect to ODP.Net and need to be able to remove all entries from either GAC (2.x or 4) that contain the text "Oracle.DataAccess" or "Oracle.Web" anywhere in their name, including assemblies and publisher policies, except those that are in the 2.x GAC and have a version number of  I am not familiar with MSI so my question is whether this type of action can be done through an MSI.  Please do not challenge whether I need to do this and just trust that I do.

  26. Hi BigLar – The reason that I wrote this blog post is that I had seen some setup packages calling gacutil.exe as a custom action to install assemblies from their MSI to the GAC and uninstall them from the GAC.  There are built-in Windows Installer tables to do this, and there is not any reason to use a custom action to do something that Windows Installer can do natively.

    Your scenario isn't something that is natively supported by Windows Intaller though.  Windows Installer allows you to add assemblies that are a part of the payload of your MSI to the GAC during installation of your MSI and remove them from the GAC during rollback and uninstall of your MSI.  It doesn't allow you to enumerate assemblies in the GAC that weren't installed by your MSI and remove them.  If you truly need to do this during your installation process, you will have to write a custom action to do this.  If you end up writing a custom action like this, please be very careful that it will only remove specific known assemblies that are a part of other versions of your product (and not any other assemblies installed by other products), and also pay particular attention to error handling – your custom action will need to make sure that the appropriate version(s) of the .NET Framework are present on the user's machine in order to remove from both the 2.x and 4 GAC's, and you should also handle cases where your installer fails and needs to rollback (ideally, rollback should put the user's machine back in the state it was in prior to starting the install, which in your case means you would need to re-install those assemblies to the GAC that your custom action is trying to find and remove).

  27. BigLar says:

    Since writing my original comment, I tried to convince Oracle to provide functionality to remove all of their .Net entries (GAC, machince.config, etc), but that did not seem to get anywhere.  Oracle provides a utility to update the GAC, but it does not list anything and cannot purge assemblies.  Not being a C programmer, I can't see using the fusion library and will instead wrap the GacUtil (yuk!).  

    Your point about the need for rollback transactional support is well taken, but will not be practical because I will often be removing assemblies from that GAC that do not exist elsewhere on the disk.  This utility will only be used in-house, and will be run via Tivoli desktop manager, so I can return a log file with the error details and generate an alert that it failed.  

    The Gacutil came close to having what I need, with its ability to remove all assemblies that match a name, but you need to specify the start of the name and the Oracle publisher policies do not start with a static prefix that can be used to isolate them.  So, I will have to call GACUTIL once to generate a list of all entries, then parse them then call GACUTIL again to remove each of the unwanted assemblies.

    Unless someone knows of a .Net wrapper for Fusion?

  28. ziad dudin says:

    i have the following problem and i need urgent help!!

    i have the firebird latest DDEX; i also have the latest firebird client dll file;

    i tried to follow the instructions for adding items to GAC  but i got an unexpected error that i can not handle or know why it happened !! this is what i got when i tried to use gacutil.exe :

    Microsoft Windows [Version 6.1.7600]

    Copyright (c) 2009 Microsoft Corporation.  All rights reserved.


    C:>cd program files

    C:Program Files>C:Program FilesMicrosoft SDKsWindowsv6.0Abin

    'C:Program' is not recognized as an internal or external command,

    operable program or batch file.

    C:Program Files>cd

    C:>cd C:Program FilesMicrosoft SDKsWindowsv6.0Abin

    C:Program FilesMicrosoft SDKsWindowsv6.0Abin>gacutil /i "FirebirdSql.Data.F


    Microsoft (R) .NET Global Assembly Cache Utility.  Version 3.5.30729.1

    Copyright (c) Microsoft Corporation.  All rights reserved.

    Failure adding assembly to the cache:   This assembly is built by a runtime newe

    r than the currently loaded runtime and cannot be loaded.

    C:Program FilesMicrosoft SDKsWindowsv6.0Abin>


    i tried the same without the quotes on the dll.item but got the same message again!!

    please help, thanks in advance!!

    ziad dudin


  29. Hi Ziad Dudin – This error about a newer runtime typically means that your assembly is built with a higher version of the .NET Framework than the version of gacutil.exe that you're trying to use to install the assembly to the GAC.  In your case, you're using the .NET Framework 3.5 version of gacutil.exe, so I'm guessing that the assembly you're trying to install to the GAC is a .NET Framework 4 assembly.  I'd suggest making sure that you have the .NET Framework 4 installed and then try to install this assembly to the GAC with the .NET Framework 4 version of gacutil.exe.

  30. Annesh Singh says:

    I use Gacutil because of strict Audit Requirements since my company is listed on Stock Exchange. Audit does not accept MSI installations of developer programs and instead allows dlls and exe bundled into a zip/cab.

  31. Hi Annesh Singh – I was referring to MSI-based installers when I made the statement in this blog post about not using gacutil.exe.  In scenarios such as yours where MSI-based installers are not an option, it would make sense to use a tool like gacutil.exe to add assemblies to the GAC.

  32. Benjamin Marty says:

    Using InstallShield 2015 and Visual Studio 2013, simply creating a do-nothing .NET DLL that's signed, and including that in a vanilla MSI installer did not put the DLL in the GAC. If I explicitly set the DLL's destination to [GlobalAssemblyCache] then the validation fails with a message, "error ISICE07: Component TestLib.Primary_output is installed to the Global Assembly Cache. This requires a waiver for Windows 7 Logo Certification. Component Directory_ TestLib.Primary_output." There's just no winning!

  33. Hi Benjamin Marty – I'm not familiar with the ISICE07 error that you're referring to, and I haven't heard of a Windows 7 Logo waiver being required in order to install an assembly to the GAC in an MSI-based setup.  It sounds like you're following the proper InstallShield authoring instructions (like the ones at msdn.microsoft.com/…/dkkx7f79(v=vs.110).aspx), so I'm not sure how to resolve this error.  It might be worth posting a question on the InstallShield forums to see if anyone there has any suggestions for you to try.

  34. BlueMonkMN says:

    I have not gotten much response from InstallShield forums in the past, so I decided to post to StackOverflow this time around (stackoverflow.com/…/isice07-component-is-installed-to-the-global-assembly-cache-this-requires). I ended up realizing that the GAC should be generally avoided where possible, and it was avoidable in my case. So at the moment, I'm down the path of trying to avoid the GAC. I've avoided it in the past, but now I'm creating installers for others' code. I still have some sway to change the code, though.

Comments are closed.

Skip to main content