Fusion GAC API Samples

For displaying purpose, error handling is skipped in all the sample code. Please don’t skip error handling in production code.

1.1. Get GAC API Interfaces

Before use GAC API interfaces, you have to get GAC API interfaces.

GAC API interfaces are pseudo COM like. You need to call AddRef() and Release() when appropriate. But you can not get the interfaces by calling CoCreateInstance(). Instead, fusion.dll provides several exports to get those interfaces.

There is no lib file provided for fusion’s exports. The reason is simple: fusion.dll lives in .net framework directory, which by default is not in path. If we provided a fusion.lib, and you used it, NT loader will not be able to load fusion.dll for you.

The right way to get fusion’s exports is to use mscoree!LoadLibraryShim to locate fusion.dll, then call GetProcAddress().

The following is a sample code to get fusion’s exports:

#include “mscoree.h”

#include “fusion.h”

typedef HRESULT (__stdcall *CreateAsmCache)(IAssemblyCache **ppAsmCache, DWORD dwReserved);

typedef HRESULT (__stdcall *CreateAsmNameObj)(LPASSEMBLYNAME *ppAssemblyNameObj, LPCWSTR szAssemblyName, DWORD dwFlags, LPVOID pvReserved);

typedef HRESULT (__stdcall *CreateAsmEnum)(IAssemblyEnum **pEnum, IUnknown *pAppCtx, IAssemblyName *pName, DWORD dwFlags, LPVOID pvReserved);

HMODULE g_FusionDll = NULL;

CreateAsmCache g_pfnCreateAssemblyCache = NULL;

CreateAsmNameObj g_pfnCreateAssemblyNameObject = NULL;

CreateAsmEnum g_pfnCreateAssemblyEnum = NULL;

LoadLibraryShim(L"fusion.dll", 0, 0, &g_FusionDll);

g_pfnCreateAssemblyCache = (CreateAsmCache)GetProcAddress(g_FusionDll, CreateAssemblyCache");

g_pfnCreateAssemblyNameObject = (CreateAsmNameObj)GetProcAddress(g_FusionDll, “CreateAssemblyNameObject");

g_pfnCreateAssemblyEnum = (CreateAsmEnum)GetProcAddress(g_FusionDll, CreateAssemblyEnum");

You need to link against mscoree.lib, which is included in .Net framework SDK.

All the sample code below assumes you have initialized GAC API interfaces.

1.2. Install Assembly without Trace Reference

It is recommended that you install an assembly with reference. But the sample code of installing assembly without reference is included for illustration purpose.

// Get an IAssemblyCache interface

IAssemblyCache* pCache = NULL;

g_pfnCreateAssemblyCache(&pCache, 0);

// call IAssemblyCache::InstallAssembly

HRESULT hr = pCache->InstallAssembly(0, pszAssemblyFilePath, NULL);

// Report result based on the return hr.

1.3. Install Assembly with Trace Reference

// Create an FUSION_INSTALL_REFERENCE struct and fill it with data

FUSION_INSTALL_REFERENCE installReference;

Memset(&installReference, 0, sizeof(FUSION_INSTALL_REFERENCE);

installReference.cbSize= sizeof(FUSION_INSTALL_REFERENCE);

installReference.dwFlags=0;

// We use opaque scheme here

installReference.guidSchem = FUSION_REFCOUNT_OPAQUE_STRING_GUID;

installReference.szIdentifier = L”Your Application Identifier goes here”;

installReference.szNonCannonicalData= L”Informational Description goes here”;

// Get an IAssemblyCache interface

IAssemblyCache* pCache = NULL;

g_pfnCreateAssemblyCache(&pCache, 0);

// call IAssemblyCache::InstallAssembly with reference

HRESULT hr = pCache->InstallAssembly(0, pszAssemblyFilePath, &installReference);

pCache->Release();

// Report result based on the return hr.

1.4. Uninstall Assembly with Trace Reference

// Create an FUSION_INSTALL_REFERENCE struct and fill it with data

FUSION_INSTALL_REFERENCE installReference = NULL;

installReference.cbSize= sizeof(FUSION_INSTALL_REFERENCE);

installReference.dwFlags=0;

// We use opaque scheme here

installReference.guidSchem = FUSION_REFCOUNT_OPAQUE_STRING_GUID;

installReference.szIdentifier = L”Your Application Identifier goes here”;

installReference.szNonCannonicalData= L”Informational Description goes here”;

// Get an IAssemblyCache interface

IAssemblyCache* pCache = NULL;

g_pfnCreateAssemblyCache(&pCache, 0);

// call IAssemblyCache::UninstallAssembly with reference

// UninstallAssembly takes a fully specified (including processor architecture) assembly name as input.

LPWSTR pszAssemblyName = L”MyAssembly, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=0123456789abcdef, ProcessorArchitecture=MSIL”;

ULONG ulDisp = 0;

HRESULT hr = pCache->UninstallAssembly(0, pszAssemblyName, &installReference, &ulDisp);

pCache->Release();

// report result based on return hr and ulDisp.

1.5. Query Assembly in GAC

// Create an ASSEMBLY_INFO struct and fill it with data

ASSEMBLY_INFO info;

WCHAR path[MAX_PATH];

memset(&info, 0, sizeof(ASSEMBLY_INFO);

info.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);

info.pszCurrentAssemblyPathBuf = path;

info.cchBuf = MAX_PATH;

// Get an IAssemblyCache interface

IAssemblyCache* pCache = NULL;

g_pfnCreateAssemblyCache(&pCache, 0);

// QueryAssemblyInfo takes a fully specified (including processor architecture) assembly name as input.

LPWSTR pszAssemblyName = L”MyAssembly, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=0123456789abcdef, ProcessorArchitecture=MSIL”;

HRESULT hr = pCache->QueryAssemblyInfo(0, pszAssemblyName, &info);

pCache->Release();

// path[] now contain the path of the assembly in GAC if QueryAssemblyInfo returns success

1.6. Enumerate Assembly in GAC

// Enumerate GAC for all the assembly “System”.

// “System” can be any valid assembly display name.

// If you want to see all assemblies, set pNameFilter to NULL

LPWSTR pszAssemblyName = L”System”;

IAssemblyName* pNameFilter = NULL;

IAssemblyEnum* pEnum = NULL;

IAssemblyName* pAsmName = NULL;

DWORD dwDisplayFlags = ASM_DISPLAYF_VERSION

                        | ASM_DISPLAYF_CULTURE

                        | ASM_DISPLAYF_PUBLIC_KEY_TOKEN

                        | ASM_DISPLAYF_PROCESSORARCHITECTURE;

DWORD dwLen = 0;

LPWSTR szDisplayName = NULL;

// First, create a filter for “system”

g_pfnCreateAssemblyNameObject(&pNameFilter, pszAssemblyName, CANOF_PARSE_DISPLAY_NAME, NULL);

// now create the IAssemblyEnum for GAC

g_pfnCreateAssemblyEnum(&pEnum, NULL, pNameFilter, ASM_CACHE_GAC, NULL);

// Enumerating.

// GetNextAssembly return S_OK when there are still assemblies exist for the enum,

// and S_FALSE if there is nothing left.

While (pEnum->GetNextAssembly(NULL, &pAsmName, 0) == S_OK)

{

    // pAsmName is the assembly returned by the enum. Now let’s get its display name

    dwLen = 0;

    // get the size first.

    pAsmName->GetDisplayName(NULL, &dwLen, dwDisplayFlags);

    // allocate memory

    szDisplayName = new WCHAR[dwLen];

    // re-try

    pAsmName->GetDisplayName(szDisplayName, &dwLen, dwDisplayFlags);

    // show it

    printf(“%S”, szDisplayName);

    delete[] szDisplayName;

    pAsmName->Release();

}

pEnum->Release();

pNameFilter->Release();