关闭

strong name

4305人阅读 评论(0) 收藏 举报

The Secrets of Strong Naming
http://www.ondotnet.com/pub/a/dotnet/2003/04/28/strongnaming.html
http://dev.csdn.net/develop/article/18/18445.shtm

在.NET环境禁止别人调用代码
http://network.ccidnet.com/pub/article/c1136_a59697_p1.html

浅析.Net共享程序集编程
http://tech.ccidnet.com/pub/disp/Article?columnID=294&articleID=34439&pageNO=1

浅析.Net下的AppDomain编程
http://developer.ccidnet.com/pub/disp/Article?columnID=294&articleID=30763&pageNO=1

创建密钥对请参见
创建和使用具有强名称的程序集语言
C#
ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/cpguide/html/cpconcreatingkeypairforuseincreatingstrongly-namedassembly.htm

Visual Basic

全部显示
要使用强名称为程序集签名,必须具有公钥/私钥对。这一对加密公钥和加密私钥用于在编译过程中创建强名称程序集。您可以使用强名称工具 (Sn.exe) 来创建密钥对。密钥对文件通常具有 .snk 扩展名。
创建密钥对
在命令提示处,键入下列命令:
sn -k <文件名>
在此命令中,“文件名”是包含密钥对的输出文件的名称。
下面的示例创建名为 sgKey.snk 的密钥对。
sn -k sgKey.snk
如果您需要延迟对程序集签名并控制整个密钥对(密钥对不太可能在测试方案之外),可使用以下命令生成密钥对,然后从中将公钥提取到一个单独的文件中。首先,创建密钥对:
sn -k keypair.snk
下一步,从密钥对中提取公钥,并将其复制到一个单独的文件中:
sn -p keypair.snk public.snk
创建密钥对之后,必须将文件放在强名称签名工具可以找到的位置。当使用强名称对程序集进行签名时,程序集链接器 (Al.exe) 查找与当前目录和输出目录相关的密钥文件。当使用命令行编译器时,只需将密钥复制到包含代码模块的当前目录即可。
如果要使用 IDE(例如 Visual Studio .NET)为程序集签署强名称,则必须知道 IDE 查找密钥文件的位置。例如,Visual Basic .NET 在包含 Visual Studio 解决方案的目录下查找密钥文件,而 C# 编译器则在包含二进制文件的目录下查找密钥文件。将密钥文件放在适当的项目目录中并设置文件属性,如下所示:
[Visual Basic]
<Assembly: AssemblyKeyFileAttribute("key.snk")>
[C#]
[assembly: AssemblyKeyFileAttribute(@"../../key.snk")]





在程序集中加入:
<Assembly: AssemblyVersion("1.0")>
<Assembly: AssemblyDelaySign(False)>
<Assembly: AssemblyKeyFile("../../Query.snk")> 'Query.snk是你强名类库的密钥文件。
用sn.exe生成密钥文件:
sn -k c:/Query.snk

找到解决方法:

1——
使用sn -k <infile>生成一个密钥文件 privateKey

2——
使用sn -p <infile> <outfile>,从privateKey获得publicKey文件

3——
使用sn -t privateKey和使用sn -t publicKey都可以获得那个PublicKeyToken(我想应该是),但这两个值不同,让我有点迷惑。

sn -T assembly
大写T可以直接从编译好的Assembly文件里取出PublicKeyToken

名包括一个公钥和一个私钥,snk仅仅在编译的时候起作用,他将assembly header用私钥加密,出了header中的保留区域,这个区域存放的是公钥。用户导入这个assembly前mscoree.dll首先会用公钥解密,然后比较保存在manifest中的hash值。snk文件组织内部编译用的,不给客户。

sn -k myKey.snk

[assembly: AssemblyVersion("1.0.1.1")]

[assembly: AssemblyKeyFile("..//..//myKey.snk")]

gacutil /i myAssembly.dll


可以直接使用VS来做,用不着用命令行方式.只要你生成了SN文件,然后在程序项目属性中,有一项可以设置密钥文件,设置好之后,编译生成的就是强名程序集了.


例如你使用
AppDomain.CurrentDomain.Load("MyLib,PublicKeyToken=324223423423");
这个方法加载MyLib,如果能够加载,则代表PublicKeyToken肯定就是324223423423
否则,找不到指定的Assembly.
这个是dotnet做的。而且不可抵赖的(基本不可能欺骗.除非该算法的私匙被破戒了)
asm.FullName的话,还需要自己分析字符串呢。.

asm.AssemblyName.GetPublicKeyToken()就好了。

PublicKeyToken是用非对称算法得到的结果。
只有用指定的私匙才能得到响应的PublicKeyToken.
就凭PublicKeyToken就能验证Assembly是谁发布的了。.




我创建了一个WinForm控件,使用了强名称(用"SN -Tp Assembly"命令可以看到公钥和公钥标记)。
http://community.csdn.net/Expert/topic/3395/3395888.xml?temp=.1084711

编译后的dll位置在:
D:/MyControl/Bin/MyControl.dll

我已成功将它发布到GAC:
gacutil /i D:/MyControl/Bin/MyControl.dll

现在的问题是:新建一个测试用的应用程序,点击工具箱上的“添加/移除项”,将D:/MyControl/Bin/MyControl.dll添加到工具箱后,再拖到Form中就会显示“未找到.NET程序集MyControl”,必须要先添加MyControl的引用才能将控件拖到Form中。如果不将MyControl.dll发布到GAC区,是可以不引用就直接拖到Form上的(能自动添加引用)。

这个问题困扰了我很久,在以前的帖子中,有人回复说需要重新签名,我用"SN -R <Assembly> <KeyFile>"命令重新签名后,仍然不行。

终于解决了,在注表表中添加相应的键才行:

HKEY_LOCAL_MACHINE/Software/Microsoft/.NETFramework




http://dev.csdn.net/article/21/21435.shtm

CSharp Tips:引用ActiveX/COM组件时的Strong Name     选择自 Mittermeyer 的 Blog
关键字   C#;Strong Name;COM/ActiveX
出处  
问题
DotNet平台下提供了比较完备的类库,但是第一个版本总归不可能面面俱到,而且由于历史遗留问题,经常会和COM/ActiveX的组件之间进行互操作。
笔者碰到的问题就是在一个Assembly中调用到了Excel的对象,但是该Assembly需要封装成为一个ActiveX的Control,供IE的客户端脚本调用。简而言之,我在C#中用到了一个COM组件,还需要把自己封装成一个COM组件,听起来有点多余不过想不到更好的办法。
在这样的封装模式下碰到了一个问题,如果一个Assembly希望封装成为ActiveX/COM组件,那么它必须拥有强名(Strong Name),也就是说在编译的时候需要指定SNK(Strong Name Key)。但是当一个Assembly如果以拥有强名的方式编译的话,它又要求所以自身所引用的其他Assembly都必须拥有强名,否则不能够成功编译。而当我们在工程中直接引用一个COM组件(例如:Excel 10 Object Library),VS.Net能够帮助我们自动导入类型库,但是此时的引用类型库是没有强名的,在笔者所期望的环境下无法编译成功。
 
解决
碰到这个问题觉得很棘手,似乎陷入和死循环,不过查阅一下文档,发现还是非常容易解决的,DotNet Framework中提供了相应的工具能够转换COM的类型库,他就是TlbImp.exe(大家可以在类似“C:/Program Files/Microsoft Visual Studio .NET 2003/SDK/v1.1”的目录中找到)。TlbImp能够将一个COM组件包装成为DotNet可以使用的类库的形式,VS.Net的自动转换想必也是以来这个工具。该工具有很多参数开关,需要支持强名只要额外打开一个开关即可。一下介绍笔者认为最可能用到的参数:
/out:Filename:类型库转换之后输出文件的名称。
/namespace:Namespace:类型库转换所使用的名称空间。
/keyfile:FileName:指定转换时使用的SNK文件,指明该参数,构造之后的类型库就拥有了强名。
完整的例子如下:
tlbimp excel.exe /out:interop.excel.dll /namespace:Excel /keyfile:excel.snk
其中snk文件可以通过DotNet中的另一个工具SN生成,此处不再赘述。
完成上述工作,在工程中直接引用我们自己构造的类型库,就可以成功的编译拥有强名的DLL了。
 
如果是控件,而不是普通的Component,那么就不能够使用tlbimp,而需要使用aximp.exe这个工具,使用方法与tlbimp类似,他会生成两个文件:一个是类型库的代理文件,另一个是Windows Form的代理文件。
 
进一步解决
然而还有更加简单的解决办法,就是在工程属性中设置“Wrapper Assembly Key File”(Common Properties/General/Wrapper Assembly Key File),这个属性。设置了该属性之后通过Add Reference添加的COM/ActiveX组件,都将被标识,拥有强名。
这需要一次设置就可以了,应该更加方便。
 
 
参考文档
 

相关文章



http://www.blogcn.com/User8/flier_lu/blog/3765092.html
使用 Fusion API 控制 GAC

    与传统 Windows 中目录存储定位,以及 COM 中注册表定位等方式不同,CLR 中使用了几级组件定位策略,以试图彻底解决 DLL Hell 的问题。其中 GAC 是 CLR 中代码共享的最重要的中心存储库,所有的强签名 (Strong Named) 配件 (Assembly) 都应该通过 GAC 来进行共享和版本管理。但遗憾的是 BCL 中并没有直接提供对 GAC 的控制和管理功能,而是通过一个名为 gacutil.exe 的命令行工具进行管理。麻烦的是这个界面并不友好的工具是不随 .NET Framework 发布版本分发的,必须在安装程序中自带安装。
    好在 CLR 提供了一个虽然没有写入正式文档,但通过 KB317540 半公开的 Fusion API 用以控制 GAC 等代码存储机制。

    这些接口和函数的定义文件在 .NET FX 1.1 中可在 SDK 的 Include/Fusion.h(.idl) 文件中找到,而在 FX 2.0 beta 中则只有 Include/Fusion.h,大概是因为 Fusion 以及完全合并到 mscorwks.dll 里面去了的原因吧。

    这套 API 主要分为三部分功能:Assembly 列表及信息的获取;Assembly 的安装、删除和信息查询;Assembly 安装引用信息的获取与设置。

    Assembly 列表及信息的获取功能是我们获得详细信息的最重要接口。

    首先,枚举 ASM_CACHE_FLAGS 中定义了缓存所在的位置:
以下内容为程序代码:

typedef enum
{
    ASM_CACHE_ZAP            = 0x1,
    ASM_CACHE_GAC            = 0x2,
    ASM_CACHE_DOWNLOAD       = 0x4
} ASM_CACHE_FLAGS;

    ZAP 是 ngen 生成本地代码的缓存;GAC 是全局强名字组件的缓冲;DOWNLOAD 则是 Internet 下载组件的缓存。可以使用 GetCachePath 函数获得这三种缓存的物理目录。
以下内容为程序代码:

  public class Fusion
  {
    [Flags] public enum ASM_CACHE_FLAGS
    {
      ASM_CACHE_ZAP            = 0x1,
      ASM_CACHE_GAC            = 0x2,
      ASM_CACHE_DOWNLOAD       = 0x4
    }

    [DllImportAttribute("fusion.dll"[img]/images/wink.gif[/img]]
    public static extern int GetCachePath(
      ASM_CACHE_FLAGS dwCacheFlags,
      [MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwzCachePath,
      ref uint pcchPath);
  }

  public class FusionUtil : Fusion, IEnumerable
  {
    public static string GetCachePath(ASM_CACHE_FLAGS cache)
    {
      uint len = 0;

      int hr = Fusion.GetCachePath(cache, null, ref len);

      if(hr == ComUtil.ERROR_INSUFFICIENT_BUFFER && len > 0)
      {
        StringBuilder sb = new StringBuilder((int)len);

        ComUtil.ComCheck(Fusion.GetCachePath(cache, sb, ref len));

        return sb.ToString();
      }
      else
      {
        return "";
      }
    }
  }

    对每种缓存,都可以通过 CreateAssemblyCache 函数获取一个 Assembly 枚举器 IAssemblyEnum 接口实例,然后通过 IAssemblyEnum::GetNextAssembly 函数遍历所有容器中的 Assembly。
以下内容为程序代码:

  public class Fusion
  {
    [ComImport, Guid("21b8916c-f28e-11d2-a473-00c04f8ef448"[img]/images/wink.gif[/img],
      InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
      public interface IAssemblyEnum
    {
      [PreserveSig]
      int GetNextAssembly(
        out IApplicationContext ppAppCtx, // Must be null.
        out IAssemblyName ppName,         // Pointer to a memory location that is to receive the interface pointer to the assembly name of the next assembly that is enumerated.
        uint dwFlags);                    // Must be zero

      [PreserveSig]
      int Reset();

      [PreserveSig]
      int Clone(out IAssemblyEnum ppEnum);
    }

    [DllImportAttribute("fusion.dll"[img]/images/wink.gif[/img]]
    public static extern int CreateAssemblyEnum(
      out IAssemblyEnum ppEnum,     // Pointer to a memory location that contains the IAssemblyEnum pointer
      IApplicationContext pAppCtx,  // Must be null. ???
      IAssemblyName pName,          // An assembly name that is used to filter the enumeration. Can be null to enumerate all assemblies in the GAC.
      ASM_CACHE_FLAGS dwFlags,      // Exactly one bit from the ASM_CACHE_FLAGS enumeration.
      int pvReserved);              // Must be NULL

  }

  public class FusionUtil : Fusion, IEnumerable
  {
    private ArrayList _asms = new ArrayList(256);
    private ASM_CACHE_FLAGS _cache = ASM_CACHE_FLAGS.ASM_CACHE_GAC;

    public void Refresh(ASM_CACHE_FLAGS cache)
    {
      IAssemblyEnum asmEnum;

      this._cache = cache;

      ComUtil.ComCheck(CreateAssemblyEnum(out asmEnum, null, null, cache, 0));

      IApplicationContext appCtxt;
      IAssemblyName asmName;

      _asms.Clear();

      while(ComUtil.SUCCEEDED(asmEnum.GetNextAssembly(out appCtxt, out asmName, 0)) && asmName != null)
      {
        AssemblyName name = new AssemblyName(asmName, appCtxt);

        _asms.Add(name);
      }
    }

    public void Refresh()
    {
      Refresh(ASM_CACHE_FLAGS.ASM_CACHE_GAC);
    }
  }

    对每一个 Assembly 都可以通过 IAssemblyEnum::GetNextAssembly 函数获得表现其名称信息的 IAssemblyName,通过此接口可以进一步获取 Assembly 的细节信息,如名称、版本号、Culture、Public Key 等等。可以通过一个 AssemblyName 类将之封装起来。
以下内容为程序代码:

public class AssemblyName
{
  private IAssemblyName _name;
  private IApplicationContext _ctxt;

  public AssemblyName(IAssemblyName name, IApplicationContext ctxt)
  {
    this._name = name;
    this._ctxt = ctxt;

    Properties = new PropertyCollection(this);
  }
  public readonly PropertyCollection Properties;
}

    IAssemblyName 接口本身提供了一些常用信息的直接的获取方法,如 Assembly 名字和版本号信息:
以下内容为程序代码:

public class AssemblyName
{
  public Version Version
  {
    get
    {
      uint hi, low;
      ComUtil.ComCheck(_name.GetVersion(out hi, out low));
      return new System.Version((int)(hi >> 16), (int)(hi & 0xFFFF), (int)(low >> 16), (int)(low & 0xFFFF));
    }
  }
}

    不过更加常用的是通过 GetDisplayName 方法获取类似 "System.Configuration.IgnoreSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 这样格式的显式名称:
以下内容为程序代码:

public class AssemblyName
{
  protected string getDisplayName(ASM_DISPLAY_FLAGS flags)
  {
    uint len = 0;

    int hr = _name.GetDisplayName(null, ref len, flags);

    if(hr == ComUtil.ERROR_INSUFFICIENT_BUFFER && len > 0)
    {
      StringBuilder displayName = new StringBuilder((int)len);

      ComUtil.ComCheck(_name.GetDisplayName(displayName, ref len, flags));

      return displayName.ToString();
    }
    else
    {
      return "";
    }
  }
}

    标志 ASM_DISPLAY_FLAGS 定义了希望获得由哪些部分组成的显式名称
以下内容为程序代码:

    [Flags] public enum ASM_DISPLAY_FLAGS
    {
      ASM_DISPLAYF_VERSION                = 0x1,  // Includes the version number as part of the display name.
      ASM_DISPLAYF_CULTURE                = 0x2,  // Includes the culture.
      ASM_DISPLAYF_PUBLIC_KEY_TOKEN       = 0x4,  // Includes the public key token.
      ASM_DISPLAYF_PUBLIC_KEY             = 0x8,  // Includes the public key.
      ASM_DISPLAYF_CUSTOM                 = 0x10, // Includes the custom part of the assembly name.
      ASM_DISPLAYF_PROCESSORARCHITECTURE  = 0x20, // Includes the processor architecture.
      ASM_DISPLAYF_LANGUAGEID             = 0x40, // Includes the language ID.
      ASM_DISPLAYF_DEFAULT                = ASM_DISPLAYF_VERSION | ASM_DISPLAYF_CULTURE | ASM_DISPLAYF_PUBLIC_KEY_TOKEN
    }

    一般来说使用由名称、版本号、Culture和Public Key Token 组成的显式名称。

    如果希望获取或设置更细致的信息,则可以使用 GetProperty/SetProperty 方法。
以下内容为程序代码:

public class Fusion
{
  ASM_NAME_PUBLIC_KEY,
  ASM_NAME_PUBLIC_KEY_TOKEN,
  ASM_NAME_HASH_VALUE,
  ASM_NAME_NAME,
  ASM_NAME_MAJOR_VERSION,
  ASM_NAME_MINOR_VERSION,
  ASM_NAME_BUILD_NUMBER,
  ASM_NAME_REVISION_NUMBER,
  ASM_NAME_CULTURE,
  ASM_NAME_PROCESSOR_ID_ARRAY,
  ASM_NAME_OSINFO_ARRAY,
  ASM_NAME_HASH_ALGID,
  ASM_NAME_ALIAS,
  ASM_NAME_CODEBASE_URL,
  ASM_NAME_CODEBASE_LASTMOD,
  ASM_NAME_NULL_PUBLIC_KEY,
  ASM_NAME_NULL_PUBLIC_KEY_TOKEN,
  ASM_NAME_CUSTOM,
  ASM_NAME_NULL_CUSTOM,
  ASM_NAME_MVID,
  ASM_NAME_MAX_PARAMS
}

public class AssemblyName
{
  protected string getProperty(ASM_NAME id)
  {
    uint len = 0;

    int hr = _name.GetProperty(id, IntPtr.Zero, ref len);

    if(hr == ComUtil.ERROR_INSUFFICIENT_BUFFER && len > 0)
    {
      IntPtr buf = Marshal.AllocCoTaskMem((int)len);

      ComUtil.ComCheck(_name.GetProperty(id, buf, ref len));

      string str = Marshal.PtrToStringUni(buf);

      Marshal.FreeCoTaskMem(buf);

      return str;
    }
    else
    {
      return "";
    }
  }

  protected byte[] getPropertyData(ASM_NAME id)
  {
    uint len = 0;

    int hr = _name.GetProperty(id, IntPtr.Zero, ref len);

    if(hr == ComUtil.ERROR_INSUFFICIENT_BUFFER && len > 0)
    {
      IntPtr buf = Marshal.AllocCoTaskMem((int)len);

      ComUtil.ComCheck(_name.GetProperty(id, buf, ref len));

      byte[] data = new byte[len];

      Marshal.Copy(buf, data, 0, (int)len);

      Marshal.FreeCoTaskMem(buf);

      return data;
    }
    else
      return new byte[0];
  }

  public string Name
  {
    get
    {
      return getProperty(ASM_NAME.ASM_NAME_NAME);
    }
  }

  public string Culture
  {
    get
    {
      return getProperty(ASM_NAME.ASM_NAME_CULTURE);
    }
  }

  public Data PublicKey
  {
    get
    {
      return new Data(getPropertyData(ASM_NAME.ASM_NAME_PUBLIC_KEY));
    }
  }
}

    枚举值 ASM_NAME 用于指定要获取哪个数据,可以通过一个 Data 类和 PropertyCollection 类进一步包装直接对数据进行的访问。
以下内容为程序代码:

public class AssemblyName
{
  public class Data
  {
    private byte[] _data;

    public Data(byte[] data)
    {
      _data = data;
    }

    public override string ToString()
    {
      return IntToHex(_data);
    }

    public static string IntToHex(byte[] data)
    {
      StringBuilder sb = new StringBuilder(data.Length * 2);

      for(int i=0; i<data.Length; i++)
        sb.Append(data[i].ToString("X2"[img]/images/wink.gif[/img]);

      return sb.ToString();
    }
  }

  public class PropertyCollection
  {
    readonly AssemblyName _name;

    internal PropertyCollection(AssemblyName name)
    {
      _name = name;
    }

    public Data this[AssemblyProperty id]
    {
      get
      {
        if((int)id >= (int)Fusion.ASM_NAME.ASM_NAME_MAX_PARAMS)
          throw new IndexOutOfRangeException();

        return new Data(_name.getPropertyData((ASM_NAME)id));
      }
    }

    public int Count
    {
      get
      {
        return (int)ASM_NAME.ASM_NAME_MAX_PARAMS;
      }
    }
  }

  public readonly PropertyCollection Properties;
}

    这样一来使用时只需要通过 Properties 属性的索引进行访问即可,如
以下内容为程序代码:

asmName.Properties[AssemblyProperty.PublicKeyToken].ToString()
asmName.Properties[AssemblyProperty.Custom].ToString()


    除了不同缓存的 Assembly 列表获取以外,对 Assembly 的安装、卸载和信息查询功能也经常用到。可以通过 CreateAssemblyCache 函数获取一个 IAssemblyCache 接口实例,进而对缓存进行操作。
以下内容为程序代码:

public class Fusion
{
  [ComImport, Guid("e707dcde-d1cd-11d2-bab9-00c04f8eceae"[img]/images/wink.gif[/img],
    InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IAssemblyCache
  {
    //...
  }

  [DllImportAttribute("fusion.dll"[img]/images/wink.gif[/img]]
  public static extern int CreateAssemblyCache(
    out IAssemblyCache ppAsmCache,
    uint dwReserved);
}


    在安装 Assembly 时,需要通过 pszManifestFilePath 参数指定 Assembly 的 manifest 文件所在路径。对大多数 Assembly 来说,只有一个独立的 dll 包括了所有的信息和数据;但某些情况下,一个 Assembly 可能被编译为一个包含 manifest 信息的主 Module 辅以多个延迟获取的网络分发的辅助 Module。例如不同语言的资源文件 Module 可能独立存在,直到需要的时候才从网络上获取。
    此外还可用通过 dwFlags 参数指定安装的策略,如 IASSEMBLYCACHE_INSTALL_FLAG_REFRESH 表示如果安装文件较新则替换缓存中原有文件;而 IASSEMBLYCACHE_INSTALL_FLAG_FORCE_REFRESH 标记则不考虑版本号强制进行替换,对应于 gacutil 的 /f 参数。
    最后还可以使用 FUSION_INSTALL_REFERENCE 结构指定 GAC 中此 Assembly 所依赖的外部信息,但这种方式降低了 GAC 的重用性,不被推荐也很少用到,这儿暂且忽略。
以下内容为程序代码:

public class Fusion
{
  [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
  public struct FUSION_INSTALL_REFERENCE
  {
    public uint cbSize;
    public uint dwFlags;
    public Guid guidScheme; // contains one of the pre-defined guids.
    public string szIdentifier;  // unique identifier for app installing this  assembly.
    public string szNonCannonicalData;  // data is description; relevent to the guid above
  }

  public enum ASM_INSTALL_FLAG
  {
    IASSEMBLYCACHE_INSTALL_FLAG_REFRESH       = 1,
    IASSEMBLYCACHE_INSTALL_FLAG_FORCE_REFRESH = 2
  }

  public interface IAssemblyCache
  {
    [PreserveSig]
    int InstallAssembly(
      ASM_INSTALL_FLAG dwFlags,
      [MarshalAs(UnmanagedType.LPWStr)] string pszManifestFilePath,
      IntPtr pvReserved);
  }
}

public class FusionUtil : Fusion, IEnumerable
{
  public void Install(string fileName)
  {
    IAssemblyCache cache;

    ComUtil.ComCheck(Fusion.CreateAssemblyCache(out cache, 0));

    ComUtil.ComCheck(cache.InstallAssembly(Fusion.ASM_INSTALL_FLAG.IASSEMBLYCACHE_INSTALL_FLAG_REFRESH, fileName, IntPtr.Zero));
  }
}

    卸载时则只需要给出 Assembly 的完整名称即可,注意是包括版本号等信息的名称。如果安装时指定了外部依赖信息,则必须给出同样信息。IAssemblyCache::UninstallAssembly 方法会返回一个状态信息 ASM_UNINSTALL_DISPOSITION,表示卸载成功与否。
以下内容为程序代码:

public class Fusion
{
  public enum ASM_UNINSTALL_DISPOSITION
  {
    IASSEMBLYCACHE_UNINSTALL_DISPOSITION_UNINSTALLED            = 1,
    IASSEMBLYCACHE_UNINSTALL_DISPOSITION_STILL_IN_USE           = 2,
    IASSEMBLYCACHE_UNINSTALL_DISPOSITION_ALREADY_UNINSTALLED    = 3,
    IASSEMBLYCACHE_UNINSTALL_DISPOSITION_DELETE_PENDING         = 4,
    IASSEMBLYCACHE_UNINSTALL_DISPOSITION_HAS_INSTALL_REFERENCES = 5,
    IASSEMBLYCACHE_UNINSTALL_DISPOSITION_REFERENCE_NOT_FOUND    = 6
  }

  public interface IAssemblyCache
  {
    [PreserveSig]
    int UninstallAssembly(
      uint dwFlags,
      [MarshalAs(UnmanagedType.LPWStr)] string pszAssemblyName,
      IntPtr pvReserved,
      out ASM_UNINSTALL_DISPOSITION pulDisposition);
  }
}

public class FusionUtil : Fusion, IEnumerable
{
  public ASM_UNINSTALL_DISPOSITION Uninstall(string assemblyName)
  {
    IAssemblyCache cache;

    ComUtil.ComCheck(Fusion.CreateAssemblyCache(out cache, 0));

    ASM_UNINSTALL_DISPOSITION disposition;

    ComUtil.ComCheck(cache.UninstallAssembly(0, assemblyName, IntPtr.Zero, out disposition));

    return disposition;
  }
}

    此外还可以通过 IAssemblyCache::QueryAssemblyInfo 方法查询某个 Assembly 是否被安装、缓存中的文件名、以及缓存中文件的大小等等信息。
以下内容为程序代码:

public class Fusion
{
  public enum QUERYASMINFO_FLAG
  {
    QUERYASMINFO_FLAG_VALIDATE  = 1,
    QUERYASMINFO_FLAG_GETSIZE   = 2
  }

  [StructLayout(LayoutKind.Sequential)]
  public struct ASSEMBLY_INFO
  {
    public uint cbAssemblyInfo; // size of this structure for future expansion
    public ASSEMBLYINFO_FLAG dwAssemblyFlags;
    public ulong uliAssemblySizeInKB;
    public IntPtr pszCurrentAssemblyPathBuf;
    public uint   cchBuf; // size of path buf.
  }

  public interface IAssemblyCache
  {
    [PreserveSig]
    int QueryAssemblyInfo(
      QUERYASMINFO_FLAG dwFlags,
      [MarshalAs(UnmanagedType.LPWStr)] string pszAssemblyName,
      out ASSEMBLY_INFO pAsmInfo);
  }
}

public class FusionUtil : Fusion, IEnumerable
{
  public bool Check(string assemblyName, out string msg)
  {
    IAssemblyCache cache;

    ComUtil.ComCheck(Fusion.CreateAssemblyCache(out cache, 0));

    ASSEMBLY_INFO info = new ASSEMBLY_INFO();

    info.cbAssemblyInfo = (uint)Marshal.SizeOf(info);
    info.cchBuf = 0;
    info.pszCurrentAssemblyPathBuf = IntPtr.Zero;

    int hr = cache.QueryAssemblyInfo(QUERYASMINFO_FLAG.QUERYASMINFO_FLAG_VALIDATE, assemblyName, out info);

    if(hr == ComUtil.ERROR_INSUFFICIENT_BUFFER && info.cchBuf > 0)
    {
      info.pszCurrentAssemblyPathBuf = Marshal.AllocCoTaskMem((int)info.cchBuf);

      ComUtil.ComCheck(cache.QueryAssemblyInfo(
        QUERYASMINFO_FLAG.QUERYASMINFO_FLAG_VALIDATE | QUERYASMINFO_FLAG.QUERYASMINFO_FLAG_GETSIZE,
        assemblyName, out info));

      string path = Marshal.PtrToStringUni(info.pszCurrentAssemblyPathBuf);

      Marshal.FreeCoTaskMem(info.pszCurrentAssemblyPathBuf);

      msg = string.Format("Assembly {0} ({1} KB) installed @ {2}",
        assemblyName, info.uliAssemblySizeInKB, path);

      return true;
    }
    else
    {
      try { Marshal.ThrowExceptionForHR(hr); msg = ""; } catch(Exception e) { msg = e.Message; }

      return false;
    }
  }
}

    如果指定 QUERYASMINFO_FLAG_VALIDATE 参数则 fusion 会对缓存中文件进行验证;如果指定 QUERYASMINFO_FLAG_GETSIZE 则通过 uliAssemblySizeInKB 返回 Assembly 的大小。

    最后还可以通过 CreateInstallReferenceEnum 函数和 IInstallReferenceEnum 接口,浏览安装 Assembly 时给出的外部依赖信息;或者通过 IAssemblyCache::CreateAssemblyCacheItem 方法和 IAssemblyCacheItem 接口,控制缓存项目内容。不过这些高级功能一般也用不上,这儿就不再罗嗦了。

    在 .NET Framework 2.0 beta 中,Fusion API 做了不大的调整:对缓存类型增加了 ASM_CACHE_ROOT 标记,表示在对某个缓存类型进行操作时的影响范围;还增加了 PEKIND 枚举类型提供对多平台支持;Assembly 属性 ASM_NAME 也做了相应扩展,增加了对文件版本号、平台架构等等信息的支持:
以下内容为程序代码:

public enum PEKIND
{
  peNone = 0,
peMSIL = 1,
peI386 = 2,
peIA64 = 3,
peAMD64 = 4,
peInvalid = -1
}

public enum ASM_NAME
{
  ...
ASM_NAME_FILE_MAJOR_VERSION = ASM_NAME_MVID + 1,
ASM_NAME_FILE_MINOR_VERSION = ASM_NAME_FILE_MAJOR_VERSION + 1,
ASM_NAME_FILE_BUILD_NUMBER = ASM_NAME_FILE_MINOR_VERSION + 1,
ASM_NAME_FILE_REVISION_NUMBER = ASM_NAME_FILE_BUILD_NUMBER + 1,
ASM_NAME_RETARGET = ASM_NAME_FILE_REVISION_NUMBER + 1,
ASM_NAME_SIGNATURE_BLOB = ASM_NAME_RETARGET + 1,
ASM_NAME_CONFIG_MASK = ASM_NAME_SIGNATURE_BLOB + 1,
ASM_NAME_ARCHITECTURE = ASM_NAME_CONFIG_MASK + 1,
ASM_NAME_MAX_PARAMS = ASM_NAME_ARCHITECTURE + 1
}

    一个新增的有趣特性是支持对两个 Assembly 的比较,能够检查两个 Assembly 的相似性。
以下内容为程序代码:

typedef
enum _tagAssemblyComparisonResult
{ ACR_Unknown = 0,
ACR_EquivalentFullMatch = ACR_Unknown + 1,
ACR_EquivalentWeakNamed = ACR_EquivalentFullMatch + 1,
ACR_EquivalentFXUnified = ACR_EquivalentWeakNamed + 1,
ACR_EquivalentUnified = ACR_EquivalentFXUnified + 1,
ACR_NonEquivalentVersion = ACR_EquivalentUnified + 1,
ACR_NonEquivalent = ACR_NonEquivalentVersion + 1,
ACR_EquivalentPartialMatch = ACR_NonEquivalent + 1,
ACR_EquivalentPartialWeakNamed = ACR_EquivalentPartialMatch + 1,
ACR_EquivalentPartialUnified = ACR_EquivalentPartialWeakNamed + 1,
ACR_EquivalentPartialFXUnified = ACR_EquivalentPartialUnified + 1,
ACR_NonEquivalentPartialVersion = ACR_EquivalentPartialFXUnified + 1
}  AssemblyComparisonResult;

STDAPI CompareAssemblyIdentity(LPCWSTR pwzAssemblyIdentity1, BOOL fUnified1, LPCWSTR pwzAssemblyIdentity2, BOOL fUnified2, BOOL *pfEquivalent, AssemblyComparisonResult *pResult);


完整的实现例子短期内可以从这里下载:::URL::http://flier.5i4k.net/GacUtilW.rar

btw: 感谢 Junfeng Zhang 在 Fusion 方面的强力支持 
flier_lu 发表于 >2004-9-11 22:44:41 保存该日志到本地  



如何创建带有强名称的程序集
http://chs.gotdotnet.com/quickstart/howto/doc/sharedname.aspx


0
0

猜你在找
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:212493次
    • 积分:2926
    • 等级:
    • 排名:第14518名
    • 原创:70篇
    • 转载:7篇
    • 译文:1篇
    • 评论:52条
    文章分类
    最新评论