【问题标题】:Typelib Generation and Installation with WiX使用 WiX 生成和安装 Typelib
【发布时间】:2009-02-20 01:03:50
【问题描述】:

asking about what Visual Studio does to register a COM Library之后,很明显VS为COM注册做了两件事:

  1. 注册 COM 库
  2. 创建和注册类型库

Visual Studio 似乎使用 regasm.exe 进行此注册。对于第一部分(直接 COM 注册),使用 tallowheat(WiX 2.0 或 WiX 3.0)似乎可以正确获取所有基本 COM 注册信息。

但是,tallow/heat 似乎没有做的是设置类型库安装。可以使用 WiX 安装程序和 regasm.exe 创建自定义操作来执行此操作,但对于基于 Microsoft 安装程序的安装程序,调用自定义操作并不是最佳做法。

经过进一步研究,msi 似乎能够在安装时生成类型库。事实上,WiX 似乎对它有直接的支持!在文件元素中,您可以添加Typelib 元素。其实an article over here on wix有一个用Interface元素填充TypeLib元素的例子。

界面元素似乎至少有两个必需的属性:

  1. 身份证
  2. 姓名

Larry Osterman speaks about the other parts of the interface that need to be registered for a TypeLib in general,并且这个接口条目似乎处理了各个部分。 Larry 说我们需要将 ProxyStubClassId32 指定为“{00020424-0000-0000-C000-000000000046}”,因此我们可以轻松添加它。

从那里去哪里以及为各种界面元素填写什么让我很难过。我已经继续并将 TypeLib 元素添加到我的 wix 文件中,并且它成功编译。不过,我对如何设置界面元素有点无能为力。我们需要做什么才能正确填写 TypeLib 元素,我可以使用哪些应用程序或工具来获取它?

下面 wcoenen 的答案看起来很有希望...我要试一试。

更新:在下面发布了我的最终解决方案作为答案。

【问题讨论】:

  • +1,我希望这个网站上的所有问题都是这样写的......
  • 嘿,我尽力了。 :)

标签: windows wix windows-installer typelib


【解决方案1】:

这是懒人解决这个问题的方法:使用 WiX 3.0 中的heat

如果你有一个自动生成并通过 regasm 安装的类型库,heat 可以将 .tlb 作为参数

heat file c:\my\path\to\my.tlb -out tlb.wxs

它将生成您需要注册的所有类型库和接口元素。这不会解决需要提前知道它们的问题,也不会解决在程序集版本更改时 GUID 更改的问题(即使界面没有 - 这是您唯一的一次)应该改变它)但它会让你走到那里。

【讨论】:

  • 虽然我不认为有任何可变的 GUID,如果你在你的 .NET 代码中使用类型库的 GUID [assembly: Guid("...")] 属性和 [ COM 接口和类的 Guid("...")] 属性
  • 对于 COM guid,我认为您是正确的。不幸的是,类型库有不同的指南。 :|我想知道是否也有一个属性来设置这些 guid...
【解决方案2】:

以下技巧可以帮助收集任何注册表更改并将它们转换为 wxs 文件,包括您所追求的 typelib 元素。

  1. 首先,将您的注册表恢复到未注册类型库的状态:

    c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\regasm.exe /tlb /u mylib.dll
    
  2. 将注册表的这种干净状态导出到 hklm-before.reg:

    c:\WINDOWS\system32\reg.exe export HKLM hklm-before.reg
    
  3. 重新注册类型库:

    c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\regasm.exe /tlb mylib.dll
    
  4. 将注册表的新状态导出到hklm-after.reg:

    c:\WINDOWS\system32\reg.exe export HKLM hklm-after.reg
    
  5. 现在我们有两个文本文件,hklm-before.reg 和 hklm-after.reg。 创建一个 diff.reg 文件,该文件仅包含它们之间的相关差异。您可以使用差异工具轻松找到差异。我喜欢使用 TortoiseSVN 中包含的差异工具,因为我已经每天都在使用它。 (由于文本编码问题,WinDiff 在这种情况下似乎无法正常工作。)

  6. 我们现在可以通过使用reg 命令调用heat.exe 将diff.reg 转换为.wxs。 (需要 wix 3.5 或更高版本。)

    heat reg diff.reg -out typelib.wxs
    

【讨论】:

  • 哎哟。难怪他们说 WiX 创作现在是一个手动过程,哎呀!
  • 这是因为 WIX 主要是一种映射到 Windows 安装程序数据库 (msi/msm/mst/pcp) 的 XML 格式。例如,有一个“typelib”元素,因为还有一个“typelib”表。收割工具heat.exe是有用的附加值,但需要专家来完成。
  • 从 WiX 3.10 开始,heat 具有专门用于收集注册表文件的参数 reg。
  • @AndriyK 谢谢,我已经更新了使用该功能的答案。
  • 刚刚检查:从 WIX 3.5 开始有 reg 选项
【解决方案3】:

看起来像是注册一个类型库,最好的方法是生成您自己的 IDL 或 ODL 文件,其中将包含您的 GUID。直接从程序集生成的类型库 [i] 依赖于[/i] 程序集版本号:GUID 是基于该信息生成的,即使接口没有更改。 Visual Studio 使用 regasm 注册和生成类型库。在此之下,它使用了一个 Win32 调用 RegisterTypeLib。使用 typelib 元素似乎做了类似的事情。不好。

但是!手动创建类型库很痛苦。可以通过另一种方式获取这些 GUID:将它们从类型库中挖掘出来并自己创建元素。

Larry Osterman 拥有所需的信息:需要设置某些注册表项。您可以使用 Registry 表(在 Wix3 中,这意味着 RegistryValue 元素)来执行这些操作。这里的技巧是获取 GUID:任何旧的 GUID 都不起作用。通常,获取 GUID 只需在 IDL 中查找您的库即可(您编写了自己的 IDL,对吗?:))。

如果您没有编写 IDL 或 ODL 文件来编译到类型库中,它们仍然存在于文件中。 Microsoft 提供了几个方便的工具:LoadTypeLibEx 和 ITypeLib 接口。通过这些接口,您可以浏览类型库并获取各种信息。我们如何浏览图书馆?

我只是看看 Regasm 是如何做到的!稍后快速反汇编,我们发现 regasm 也是用 C# 编写的。荣耀日。我启动了一个项目,之后使用了一些 using 语句和一个 PInvoke,我们有:

using System.Runtime.InteropServices;          // for struct marshaling 
using System.Runtime.InteropServices.ComTypes; // for the ITypeLib + related types

// TYPELIBATTR lives in two places: Interop and ComTypes, but the one
// in Interop is deprecated.
using TYPELIBATTR = System.Runtime.InteropServices.ComTypes.TYPELIBATTR; 

/// <summary>
/// The registry kind enumeration for LoadTypeLibEx.  This must be made
/// here, since it doesn't exist anywhere else in C# afaik.  This is found
/// here: http://msdn.microsoft.com/en-us/library/ms221159.aspx
/// </summary>
enum REGKIND
{
    REGKIND_DEFAULT,
    REGKIND_REGISTER,
    REGKIND_NONE
}

// and this is how we get the library.
[DllImport("oleaut32.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
  private static extern void LoadTypeLibEx(string strTypeLibName, REGKIND regKind, out ITypeLib TypeLib);

哇!一旦我们有了这个,我们必须导航结构。这是与非托管资源交互,所以准备好成为Marshaling 的东西。

ITypeLib lib = null;
LoadTypeLibEx(Value, REGKIND.REGKIND_NONE, out lib);
IntPtr libInfoPtr = IntPtr.Zero;
lib.GetLibAttr(out libInfoPtr);
TYPELIBATTR libInfo = 
    (TYPELIBATTR) Marshal.PtrToStructure(libInfoPtr, typeof(TYPELIBATTR));
int typeCount = lib.GetTypeInfoCount();
for (int i = 0; i < typeCount; ++i)
{
    ITypeInfo info;
    lib.GetTypeInfo(i, out info);
    IntPtr typeDescrPtr = IntPtr.Zero;
    info.GetTypeAttr(out typeDescrPtr);
    TYPELIBATTR type =
        (TYPELIBATTR)Marshal.PtrToStructure(typeDescrPtr, typeof(TYPELIBATTR));
    // get GUID, other info from the specific type
}

lib.ReleaseTLibAttr(libInfoPtr);
libInfoPtr = IntPtr.Zero;

哇。因此,您必须编写一些代码来提取信息。完成后,您必须将该信息填写到注册表项中,指定为By Larry Osterman

当然,您可以通过简单地编写自己的 IDL 文件来避免该步骤。痛苦中的选择:由你决定!

【讨论】:

  • 我重读了几次,但我非常困惑。不知道你在这里取得了什么成就。
  • 代码不是解决方案。作为 regasm 的一部分,Visual Studio 会在 IDL 文件中生成您应该自己处理的所有信息。这可以让您弄清楚 regasm 代表您做了什么。你应该做的是制作一个 IDL 文件。
  • 如果您想弄清楚 regasm 在 tlb 中放入了什么,那么为什么不直接使用 oleview.exe 打开 regasm 生成的 tlb 文件呢?
  • 是的,你可以用简单的方法做到这一点......我想要一个可以做到这一点的工具,而你并没有比这更接近金属了。 :)
  • 我尊重你做了功课,并发现了 regasm 中真正发生的事情。即使我现在不使用代码解决方案,知道如何连接我自己的软件来做到这一点也很有用。感谢您提供的重要信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多