Fusion API в С++-варианте не находит .Net 4.0 сборки расположенные в GAC.
Как допилить код на C++ чтобы он находил все сборки?
Пример на C++ (находит сборки только до .Net 3.5):
#include "stdafx.h"
#include "fusion.h"
#include "mscoree.h"
#include <string>
#include "fusion_test.h"
#pragma comment(lib, "mscoree.lib")
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);
CreateAsmCache g_pfnCreateAssemblyCache = NULL;
CreateAsmNameObj g_pfnCreateAssemblyNameObject = NULL;
CreateAsmEnum g_pfnCreateAssemblyEnum = NULL;
void init_fusion()
{
CoInitialize ( NULL );
HMODULE g_FusionDll = 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");
}
// null means enumerate all the assemblies
AssemblyCacheEnum::AssemblyCacheEnum(const std::wstring & assemblyName)
{
m_AssemblyEnum = NULL;
done = false;
IAssemblyName * fusionName = 0;
int hr = 0;
if (!assemblyName.empty())
{
hr = (*g_pfnCreateAssemblyNameObject)(
& fusionName,
assemblyName.c_str(),
CANOF_PARSE_DISPLAY_NAME,
NULL
);
}
if (hr == S_OK)
{
hr = (*g_pfnCreateAssemblyEnum)(
& m_AssemblyEnum,
NULL,
fusionName,
GAC,
NULL
);
}
if (hr != S_OK)
{
done = true;
}
}
std::wstring AssemblyCacheEnum::GetNextAssembly()
{
int hr = 0;
IAssemblyName * fusionName = 0;
if (done)
{
return std::wstring();
}
// Now get next IAssemblyName from m_AssemblyEnum
hr = m_AssemblyEnum->GetNextAssembly(NULL, & fusionName, 0);
if (hr != S_OK )
{
done = true;
return std::wstring();
}
if (fusionName)
{
std::wstring s = GetFullName(fusionName);
fusionName->Release();
return s;
}
else
{
done = true;
return std::wstring();
}
}
std::wstring AssemblyCacheEnum::GetFullName(IAssemblyName * fusionAsmName)
{
TCHAR sDisplayName[2048];
DWORD iLen = 2048;
int hr = fusionAsmName->GetDisplayName(sDisplayName, &iLen, (int)ALL);
if (hr != S_OK )
{
return std::wstring();
}
return &sDisplayName[0];
}
int _tmain(int argc, TCHAR* argv[])
{
init_fusion();
AssemblyCacheEnum ace (_T("mscorlib"));
std::wstring assembly;
while ( !( assembly = ace.GetNextAssembly()).empty() )
{
std::wstring s = assembly;
_tprintf(_T("%s\n"),s.c_str());
}
}
Пример на C#: (находит все сборки, включая .Net 4.0)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace fusion_test
{
internal class Win32
{
[DllImport("fusion.dll")]
internal static extern int CreateAssemblyEnum(
out IAssemblyEnum ppEnum,
IntPtr pUnkReserved,
IAssemblyName pName,
AssemblyCacheFlags flags,
IntPtr pvReserved);
[DllImport("fusion.dll")]
internal static extern int CreateAssemblyNameObject(
out IAssemblyName ppAssemblyNameObj,
[MarshalAs(UnmanagedType.LPWStr)]
String szAssemblyName,
CreateAssemblyNameObjectFlags flags,
IntPtr pvReserved);
}
[Flags]
internal enum AssemblyCacheFlags
{
GAC = 2,
}
internal enum CreateAssemblyNameObjectFlags
{
CANOF_DEFAULT = 0,
CANOF_PARSE_DISPLAY_NAME = 1,
}
[Flags]
internal enum AssemblyNameDisplayFlags
{
VERSION = 0x01,
CULTURE = 0x02,
PUBLIC_KEY_TOKEN = 0x04,
PROCESSORARCHITECTURE = 0x20,
RETARGETABLE = 0x80,
// This enum will change in the future to include
// more attributes.
ALL = VERSION
| CULTURE
| PUBLIC_KEY_TOKEN
| PROCESSORARCHITECTURE
| RETARGETABLE
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("CD193BC0-B4BC-11d2-9833-00C04FC31D2E")]
internal interface IAssemblyName
{
[PreserveSig()]
int SetProperty(
int PropertyId,
IntPtr pvProperty,
int cbProperty);
[PreserveSig()]
int GetProperty(
int PropertyId,
IntPtr pvProperty,
ref int pcbProperty);
[PreserveSig()]
int Finalize();
[PreserveSig()]
int GetDisplayName(
StringBuilder pDisplayName,
ref int pccDisplayName,
int displayFlags);
[PreserveSig()]
int Reserved(ref Guid guid,
Object obj1,
Object obj2,
String string1,
Int64 llFlags,
IntPtr pvReserved,
int cbReserved,
out IntPtr ppv);
[PreserveSig()]
int GetName(
ref int pccBuffer,
StringBuilder pwzName);
[PreserveSig()]
int GetVersion(
out int versionHi,
out int versionLow);
[PreserveSig()]
int IsEqual(
IAssemblyName pAsmName,
int cmpFlags);
[PreserveSig()]
int Clone(out IAssemblyName pAsmName);
}// IAssemblyName
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("21b8916c-f28e-11d2-a473-00c04f8ef448")]
internal interface IAssemblyEnum
{
[PreserveSig()]
int GetNextAssembly(
IntPtr pvReserved,
out IAssemblyName ppName,
int flags);
[PreserveSig()]
int Reset();
[PreserveSig()]
int Clone(out IAssemblyEnum ppEnum);
}// IAssemblyEnum
[ComVisible(false)]
public class AssemblyCacheEnum
{
// null means enumerate all the assemblies
public AssemblyCacheEnum(String assemblyName)
{
IAssemblyName fusionName = null;
int hr = 0;
if (assemblyName != null)
{
hr = Win32.CreateAssemblyNameObject(
out fusionName,
assemblyName,
CreateAssemblyNameObjectFlags.CANOF_PARSE_DISPLAY_NAME,
IntPtr.Zero);
}
if (hr >= 0)
{
hr = Win32.CreateAssemblyEnum(
out m_AssemblyEnum,
IntPtr.Zero,
fusionName,
AssemblyCacheFlags.GAC,
IntPtr.Zero);
}
if (hr < 0)
{
Marshal.ThrowExceptionForHR(hr);
}
}
public String GetNextAssembly()
{
int hr = 0;
IAssemblyName fusionName = null;
if (done)
{
return null;
}
// Now get next IAssemblyName from m_AssemblyEnum
hr = m_AssemblyEnum.GetNextAssembly((IntPtr)0, out fusionName, 0);
if (hr < 0)
{
return null;
}
if (fusionName != null)
{
return GetFullName(fusionName);
}
else
{
done = true;
return null;
}
}
private String GetFullName(IAssemblyName fusionAsmName)
{
StringBuilder sDisplayName = new StringBuilder(1024);
int iLen = 1024;
int hr = fusionAsmName.GetDisplayName(sDisplayName, ref iLen, (int)AssemblyNameDisplayFlags.ALL);
if (hr < 0)
{
return null;
}
return sDisplayName.ToString();
}
private IAssemblyEnum m_AssemblyEnum = null;
private bool done;
}// class AssemblyCacheEnum
class Program
{
static void Main(string[] args)
{
AssemblyCacheEnum ace = new AssemblyCacheEnum("mscorlib");
string assembly;
while (!string.IsNullOrEmpty(assembly = ace.GetNextAssembly()))
{
string s = assembly;
Console.WriteLine(s);
}
}
}
}
Забыл еще код "fusion_test.h" добавить
#include "fusion.h"
#include <string>
enum AssemblyNameDisplayFlags
{
VERSION = 0x01,
CULTURE = 0x02,
PUBLIC_KEY_TOKEN = 0x04,
PROCESSORARCHITECTURE = 0x20,
RETARGETABLE = 0x80,
// This enum will change in the future to include
// more attributes.
ALL = VERSION
| CULTURE
| PUBLIC_KEY_TOKEN
| PROCESSORARCHITECTURE
| RETARGETABLE,
};
enum AssemblyCacheFlags
{
GAC = 2,
};
class AssemblyCacheEnum
{
public:
AssemblyCacheEnum(const std::wstring & assemblyName);
std::wstring GetNextAssembly();
std::wstring GetFullName(IAssemblyName * fusionAsmName);
private:
IAssemblyEnum * m_AssemblyEnum;
bool done;
};