免注册 COM/DLL?

Posted

技术标签:

【中文标题】免注册 COM/DLL?【英文标题】:Registration-free COM/DLL? 【发布时间】:2011-07-01 18:24:39 【问题描述】:

我的程序正在使用 Skype4COM.dll(Skype API 的包装器)。

我使用的是 Delphi 2010 - 有没有办法确保我的程序始终使用我将随附的 Skype4COM.dll?问题是,Skype4COM 有不同的版本,如果我通过其他人注册我的,他们的应用程序可能不再工作。

通常我使用 RegSvr32 在人的系统上注册 DLL,但我听说可以让它免注册(在 C# 中),所以我的问题是:我们也可以在 Delphi 中这样做吗?

谢谢!

【问题讨论】:

【参考方案1】:

在您触摸免费注册 com 之前,请确保您的应用程序在注册 dll 时可以正常工作。一旦你对此感到满意。是时候尝试让它免费注册了。第一步是注销您的 dll。如果你现在尝试运行你的程序,你应该得到 ClassId not found。

第一步是为您的应用程序创建一个清单文件。清单文件是一个 xml 文件,其中可以设置应用程序的依赖项。你可能不知道,但是从 Delphi 2007 开始,如果你启用了主题,你的应用程序一直都有一个清单。这是来自 Delphi 2010:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    type="win32"
    name="CodeGear RAD Studio"
    version="14.0.3615.26342" 
    processorArchitecture="*"/>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        publicKeyToken="6595b64144ccf1df"
        language="*"
        processorArchitecture="*"/>
    </dependentAssembly>
  </dependency>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel
          level="asInvoker"
          uiAccess="false"/>
        </requestedPrivileges>
    </security>
  </trustInfo>
</assembly>

现在我不确定你是否可以添加到这个并且每个应用程序只能有一个清单文件,我通常只是完全替换它。因为我想要启用主题,所以我从这个文件开始并添加我的依赖项。在您的情况下,您需要为 skype4com.dll 添加依赖项这是我需要添加的内容:

<assemblyIdentity 
  name="Skype4COM.X" 
  version="1.0.36.0" 
  type="win32" 
  processorArchitecture="x86">
</assemblyIdentity>

请注意,我实际上是在向 Assembly Skye4COM.X 添加依赖项,而不是向 dll 本身添加依赖项。不要混淆 2,虽然 dll 可以是程序集,但程序集不一定是 1 dll。当我们设置程序集清单时,这将变得清晰/

您的清单文件现在变为:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    type="win32"
    name="CodeGear RAD Studio"
    version="14.0.3615.26342" 
    processorArchitecture="*"/>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        publicKeyToken="6595b64144ccf1df"
        language="*"
        processorArchitecture="*"/>
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity 
        name="Skype4COM.X" 
        version="1.0.36.0" 
        type="win32" 
        processorArchitecture="x86">
      </assemblyIdentity>
</dependentAssembly>
  </dependency>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel
          level="asInvoker"
          uiAccess="false"/>
        </requestedPrivileges>
    </security>
  </trustInfo>
</assembly>

使用与您的可执行文件相同的名称保存此文件,但使用 .manifest 后缀。例如 SkypeClient.exe.manifest

下一步是将此清单嵌入到您的应用程序中。您需要使用以下文本创建一个资源文件(rc 文件):

#define RT_MANIFEST 24 
#define APP_MANIFEST 1

APP_MANIFEST RT_MANIFEST SkypeClient.exe.manifest

将此文件添加到您的应用程序并构建。如果您仍然启用主题,您将收到重复资源警告,只需从 dpr 文件中删除 $R *.res。您还应该在项目文件中看到这一点:

$R 'SkypeClient.manifest.res' 'SkypeClient.manifest.rc'

如果您现在尝试运行您的应用程序,您将收到以下错误消息:

无法创建进程: 应用程序无法启动 因为它的并排配置 是不正确的。请参阅 应用程序事件日志或使用 命令行 sxstrace.exe 工具 更详细。

我们现在需要为程序集 (Skype4COM.X) 添加清单。创建一个名为 Skype4COM.X.manifest 的文件。我们需要在清单文件中描述程序集:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

  <assemblyIdentity 
    name="Skype4COM.X" 
    version="1.0.36.0" 
    type="win32"
    processorArchitecture="x86">
  </assemblyIdentity>

  <file name="Skype4COM.dll">
    <typelib
      tlbid="03282B5D-B38F-469D-849A-09B0A7F4881B"
      version="1.0"
      helpdir=""
      flags="hasdiskimage"/>
  </file>
</assembly>

现在将应用程序的 dll 和程序集清单放在同一个文件夹中并运行!

如果您再遇到错误,则需要使用 SxSTrace 进行调试。这在 Vista 及更高版本上可用。首先开始跟踪:

SxSTrace trace -logfile:sxsTrace.etl

运行您的程序,然后在跟踪上按 Enter 键完成它。现在解析跟踪:

SxSTrace parse -logfile:SxSTrace.etl -outfile:SxStrace.txt

你应该在 SxSTrace.txt 中有一个完整的整个过程的日志

【讨论】:

哇,感谢您的详细指南! +1!一旦我回到我的IDE,我会试试这个。是否可以将所有外部文件作为资源嵌入到我的 exe 中?还是他们无法在应用需要它们之前提取它们? 所有外部文件是什么意思? @Steve .manifest 文件。我看到 SkypeClient.exe.manifest 被嵌入到资源中,但我也可以使用 Skype4COM.X.Manifest 来做到这一点吗? 如果我没有注册 Skype4COM 控件 (Skype4COM.dll),我将如何编译我的程序? 好的,到了我得到“并排配置”错误的地方。但是,添加 Skype4COM.X.manifest 不起作用。我仍然得到未注册的课程。 SxSTrace 日志解析生成了一个空的 .txt 文件。【参考方案2】:

请参阅 While & Muller 2005 年的 MSDN 文章“Registration-Free Activation of COM Components: A Walkthrough”。它使用 C++、C# 和 VB 进行演示,但这些都不重要。代码部分(步骤 1 到 3)与您在 any COM 应用程序中执行的操作相同。演练说明:

COM 组件的免注册激活不需要服务器或客户端中的特殊代码。所需要的只是一对匹配的清单文件。

为您的 COM DLL 创建一个清单文件,然后为您的应用程序创建一个引用它的清单文件。

【讨论】:

为 SideBySide.dll 组件创建一个私有程序集清单文件(文本文件)并将其命名为 SideBySide.X.manifest。 - 为什么要添加“.X”?另外,我是否必须在 Delphi 中做一些事情才能使用 .manifest 文件?我以前没有这样做过。 "在不可能的情况下,请注意为您的程序集(以及您的程序集清单)指定一个与 COM DLL 文件名不同的名称。因此,在上述情况下,COM DLL 被称为 SideBySide 但程序集被称为 SideBySide.X。如果您对这种约束的原因感兴趣,请在 疑难解答部分。” (特别是第 5-7 段。) 你不需要做任何事情来让你的 Delphi 程序使用清单,因为你的 Delphi 程序不会使用清单。清单是操作系统自动处理的东西;应用程序没有注意到它(除非您使用activation-context API,但正如文章所解释的那样,这种需求很少见)。【参考方案3】:

这是一个使用Chilkat's SSH (ChilkatSsh.dll) ActiveX 库的实际示例。

ChilkatSsh.dll 导出 6 个类:

Chilkat.Ssh Chilkat.Key Chilkat.Sftp Chilkat.SftpFile Chilkat.SftpDir Chilkat.SshTunnel

为此我创建了一个 Chilkat.SSH.manifest 程序集清单:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

    <assemblyIdentity type="win32" name="Chilkat.SSH" version="9.3.2.0" />

    <file name="ChilkatSsh.dll">

        <!-- CLASS_ChilkatSsh -->
        <comClass
                progid="Chilkat.Ssh"
                clsid="72A1C13F-1C23-4C52-97F0-BCA902148720"
                threadingModel="Apartment">
        </comClass>

        <!-- CLASS_ChilkatSshKey -->
        <comClass
                progid="Chilkat.SshKey"
                clsid="73111D94-E28A-4587-B687-60E23CD989A8"
                threadingModel="Apartment">
        </comClass>

        <!-- CLASS_ChilkatSFtp -->
        <comClass
                progid="Chilkat.SFtp"
                clsid="64A17FBB-89E2-403F-8E06-B7CE412FB0E6"
                threadingModel="Apartment">
        </comClass>

        <!-- CLASS_ChilkatSFtpFile -->
        <comClass
                progid="Chilkat.SFtpFile"
                clsid="B2208BCC-AB0F-4722-A908-2F54269D21C2"
                threadingModel="Apartment">
        </comClass>

        <!-- CLASS_ChilkatSFtpDir -->
        <comClass
                progid="Chilkat.SFtpDir"
                clsid="39B10683-ED49-47A3-A4A5-AB1F52D1C2CC"
                threadingModel="Apartment">
        </comClass>

        <!-- CLASS_ChilkatSshTunnel -->
        <comClass
                progid="Chilkat.SshTunnel"
                clsid="4D881197-5686-45BF-B9D9-9EC432F4BB75"
                threadingModel="Apartment">
        </comClass>
    </file>
</assembly>

现在您只需引用应用程序清单中的程序集。例如,您可以以完全相同的方式声明对Common Controls version 6 的依赖:

<dependency>
   <dependentAssembly>
      <assemblyIdentity
            type="win32"
            name="Microsoft.Windows.Common-Controls"
            version="6.0.0.0"
            processorArchitecture="*"
            publicKeyToken="6595b64144ccf1df"
            language="*" />
   </dependentAssembly>
</dependency>

你声明了对Chilkat SSH的依赖:

<dependency>
   <dependentAssembly>
      <assemblyIdentity type="win32" name="Chilkat.SSH" version="9.3.2.0" />
   </dependentAssembly>
</dependency>

【讨论】:

以上是关于免注册 COM/DLL?的主要内容,如果未能解决你的问题,请参考以下文章

无注册 COM - COM dll 相对于客户端 exe 的位置

为啥 C# 需要注册 COM DLL 才能引用它?

如果 com dll 未注册,如何防止崩溃

将 32 位 COM DLL 注册到 64 位 Windows 7

Setup Factory打包时注册com dll

使用C ++ API注册COM DLL的所有接口