Enumerating the assemblies in the GAC.
This is a version that fulfills my needs but if you need filtering, the information required is in the documents I’m pointing to in Gac.h file. As usual, comments are welcome!
Example of use:
for each( String ^ s in gcnew Gac() )
Console::WriteLine(s);
StdAfx.h:
#pragma once
#include <Windows.h>
#include <mscoree.h>
#include <fusion.h>
Gac.h:
#pragma once
// DOC: Global Assembly Cache (GAC) APIs Are Not Documented in the .NET Framework Software Development Kit (SDK) Documentation
// (https://support.microsoft.com/default.aspx?scid=kb;en-us;317540)
// Fusion GAC API Samples
// (https://blogs.msdn.com/junfeng/articles/229648.aspx)
// Sample Managed GAC API Wrappers
// (https://blogs.msdn.com/junfeng/articles/229649.aspx)
// Test Application for Managed GAC API Wrappers
// (https://blogs.msdn.com/junfeng/articles/229650.aspx)
namespace Microsoft { namespace Services { namespace Partners { namespace ISV {
using namespace System;
using namespace System::Collections ;
typedef HRESULT (__stdcall * CreateAssemblyEnum)( IAssemblyEnum * * pEnum,
IUnknown * pAppCtx,
IAssemblyName * pName,
DWORD dwFlags,
LPVOID pvReserved ) ;
typedef HRESULT (__stdcall * CreateAssemblyNameObject) ( LPASSEMBLYNAME * ppAssemblyNameObj,
LPCWSTR szAssemblyName,
DWORD dwFlags,
LPVOID pvReserved ) ;
public ref class Gac : Generic::IEnumerable<String ^>
{
public:
virtual Generic::IEnumerator<String ^> ^ GetEnumerator() ;
virtual IEnumerator ^ GetObjectEnumerator() = IEnumerable::GetEnumerator ;
ref class AssemblyEnumerator : Generic::IEnumerator<String ^>
{
public:
AssemblyEnumerator() ;
~AssemblyEnumerator() ;
!AssemblyEnumerator() ;
virtual property Object ^ CurrentObject
{
Object ^ get () = Collections::IEnumerator::Current::get ;
}
virtual property String ^ Current
{
String ^ get () ;
}
virtual bool MoveNext() ;
virtual void Reset() ;
private:
static AssemblyEnumerator() ;
private:
static CreateAssemblyEnum _pfnCreateAssemblyEnum ;
static CreateAssemblyNameObject _pfnCreateAssemblyNameObject ;
initonly DWORD _displayFlags ;
IAssemblyEnum * _pIAssemblyEnum ;
String ^ _currentAssemblyName ;
} ;
} ;
}}}}
Gac.cpp:
#include "stdafx.h"
#include "GacEnumerator.h"
namespace Microsoft { namespace Services { namespace Partners { namespace ISV {
using namespace System::Runtime::InteropServices ;
Generic::IEnumerator<String ^> ^ Gac::GetEnumerator()
{
return gcnew AssemblyEnumerator() ;
}
IEnumerator ^ Gac::GetObjectEnumerator()
{
return GetEnumerator() ;
}
static Gac::AssemblyEnumerator::AssemblyEnumerator()
{
HMODULE fusionDll ;
HRESULT hr = LoadLibraryShim( L"fusion.dll", 0, 0, & fusionDll ) ;
if ( FAILED(hr) )
Marshal::ThrowExceptionForHR(hr) ;
_pfnCreateAssemblyEnum = reinterpret_cast<CreateAssemblyEnum>( GetProcAddress( fusionDll, "CreateAssemblyEnum" ) ) ;
if ( ! _pfnCreateAssemblyEnum )
throw gcnew InvalidOperationException( "Failed to retrieve CreateAssemblyEnum() address from fusion.dll" ) ;
_pfnCreateAssemblyNameObject = reinterpret_cast<CreateAssemblyNameObject>( GetProcAddress(fusionDll, "CreateAssemblyNameObject" ) ) ;
if ( ! _pfnCreateAssemblyNameObject )
throw gcnew InvalidOperationException( "Failed to retrieve CreateAssemblyNameObject() address from fusion.dll" ) ;
}
Gac::AssemblyEnumerator::AssemblyEnumerator()
{
pin_ptr<IAssemblyEnum *> p( & _pIAssemblyEnum ) ;
HRESULT hr = _pfnCreateAssemblyEnum( p, NULL, NULL, ASM_CACHE_GAC, NULL ) ;
if ( FAILED(hr) )
Marshal::ThrowExceptionForHR(hr) ;
_displayFlags = ASM_DISPLAYF_VERSION | ASM_DISPLAYF_CULTURE | ASM_DISPLAYF_PUBLIC_KEY_TOKEN | ASM_DISPLAYF_PROCESSORARCHITECTURE ;
}
Gac::AssemblyEnumerator::~AssemblyEnumerator()
{
AssemblyEnumerator::!AssemblyEnumerator() ;
}
Gac::AssemblyEnumerator::!AssemblyEnumerator()
{
if ( _pIAssemblyEnum )
_pIAssemblyEnum->Release();
}
Object ^ Gac::AssemblyEnumerator::CurrentObject::get()
{
return Current::get() ;
}
String ^ Gac::AssemblyEnumerator::Current::get()
{
return _currentAssemblyName ;
}
bool Gac::AssemblyEnumerator::MoveNext()
{
_currentAssemblyName = nullptr ; // 9/9/05: Added.
IAssemblyName * pIAssemblyName = nullptr ;
wchar_t * assemblyName = nullptr ;
try
{
if ( _pIAssemblyEnum->GetNextAssembly( nullptr, & pIAssemblyName, 0 ) != S_OK || ! pIAssemblyName) // S_FALSE when it fails.
return false ;
DWORD characterCount = 0 ;
pIAssemblyName->GetDisplayName( nullptr, & characterCount, _displayFlags ) ;
if ( ! characterCount ) // 9/9/05: Fixed.
return false ;
wchar_t * assemblyNameStorage = new wchar_t[characterCount+1] ;
HRESULT hr = pIAssemblyName->GetDisplayName( assemblyNameStorage, & characterCount, _displayFlags ) ;
if ( FAILED(hr) )
Marshal::ThrowExceptionForHR(hr) ;
_currentAssemblyName = gcnew String(assemblyNameStorage) ;
return true ;
}
finally
{
if ( pIAssemblyName )
pIAssemblyName->Release() ;
if ( assemblyName )
delete [] assemblyName ;
}
return false ;
}
void Gac::AssemblyEnumerator::Reset()
{
if ( _pIAssemblyEnum )
_pIAssemblyEnum->Reset() ;
}
}}}}