Fusion API & C++
От: Аноним  
Дата: 13.12.11 11:29
Оценка:
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);
            }
        }
    }
}
Re: Fusion API & C++
От: Аноним  
Дата: 13.12.11 11:34
Оценка:
Забыл еще код "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;
};
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.