29
votes

My program is using the Skype4COM.dll (A wrapper for the Skype API).

I am using Delphi 2010 - is there a way to make sure that my program is ALWAYS using the Skype4COM.dll that I will ship it with? The thing is, there are different versions of Skype4COM, and if I register mine over someone elses, their app may not work anymore.

Usually I use RegSvr32 to register the DLL on peoples system, but I heard its possible to make it registration-free (in C#), so my question is: Can we do that in Delphi, too?

Thanks!

3

3 Answers

46
votes

Before you even touch registration free com make sure your application works when the dll is registered. Once you are happy with this. It's time to try and get it to work registration free. First step is to unregister your dll. If you try and run your program now you should get ClassId not found.

First step is to create a manifest file for your application. A manifest file is an xml file which among other things can setup dependencies for your application. You may not know it, but since about Delphi 2007, if you have themes enabled, your application has had a manifest all along. Here it is from 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>

Now I'm not sure if you can add to this and you can only have one manifest file per application, I just usually replace it completely. Since I want themes enabled I start off with this file and add my dependency. In your case you need to add a dependency for the skype4com.dll Here's what I need to add :

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

Note I am actually adding a dependency to the Assembly Skye4COM.X and not the dll itself. Don't confuse the 2, although a dll can be an assembly an assembly is not necessarily 1 dll. This will become clear when we set up the assembly manifest/

Your manifest file now becomes :

<?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>

Save this file with the same name as your executable, but with a .manifest suffix. For example SkypeClient.exe.manifest

The next step is to embed this manifest in your application. You'll need to create an resource file (rc file) with the following text :

#define RT_MANIFEST 24 
#define APP_MANIFEST 1

APP_MANIFEST RT_MANIFEST SkypeClient.exe.manifest

Add this file to your application and build. If you still have themes enabled you will get a duplicate resource warning, just removed the {$R *.res} from your dpr file. You should also see this in the project file :

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

If you try and run your application now, you will get the following error message :

Unable to create process: The application has failed to start because its side-by-side configuration is incorrect. Please see the application event log or use the command-line sxstrace.exe tool for more detail.

We now need to add a manifest for the assembly (Skype4COM.X). Create a file called Skype4COM.X.manifest. We need to describe the assembly in the manifest file :

<?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>

Now place the Application the dll and the assembly manifest in the same folder and run!

If you get anymore errors you'll need to use SxSTrace to debug. This is available on Vista onwards. First start a trace :

SxSTrace trace -logfile:sxsTrace.etl

run your program, and then press enter on the trace to finish it. Now parse the trace :

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

You should have a comprehensive log of the whole process in SxSTrace.txt

14
votes

Refer to While & Muller's 2005 MSDN article "Registration-Free Activation of COM Components: A Walkthrough." It demonstrates with C++, C#, and VB, but none of that's important. The code portion — in steps 1 through 3 — are the same things you'd do in any COM application. The walkthrough explains:

The registration-free activation of COM components requires no special code in the server or in the client. All that's required is a matching pair of manifest files.

Create a manifest file for your COM DLL, and then create a manifest file for your application that refers to it.

1
votes

Here's a practical example when using Chilkat's SSH (ChilkatSsh.dll) ActiveX library.

The ChilkatSsh.dll exports 6 classes:

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

For which i created a Chilkat.SSH.manifest assembly 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>

Now you just need to reference the assembly in your application's manifest. For example, in the exact same way you might declare a dependency on 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>

You declare a dependency on Chilkat SSH:

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