29

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!

Jeff
  • 11,384
  • 12
  • 77
  • 145

3 Answers3

46

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

Steve
  • 6,042
  • 3
  • 37
  • 64
  • Woah, thanks for this detailed guide! +1! Will try this once I get home to my IDE. Would it be possible to embed all the external files to my exe, as a resource? Or will they not be able to extract before the app needs them? – Jeff Feb 22 '11 at 19:42
  • What do you mean by all the external files? – Steve Feb 22 '11 at 21:32
  • @Steve The .manifest files. I see the SkypeClient.exe.manifest gets embedded into the Resource, but can I do that with the Skype4COM.X.Manifest too? – Jeff Feb 23 '11 at 10:36
  • How will I compile my program when I do not have the Skype4COM control registered (Skype4COM.dll)? – Jeff Feb 23 '11 at 18:20
  • Alright, got to where I get the "Side by side configuration" error. However, adding the Skype4COM.X.manifest does not work. I still get the Class Not Registered. The SxSTrace log parsing generated an empty .txt file. – Jeff Feb 23 '11 at 18:38
  • I didn't say it was easy! You could embed the SKype4COM.X.Manifest as a resource in the dll if you had control over it, but you don't. You really need to get the SxStrace working. It is your friend. Are you sure you are closing the trace before parsing? – Steve Feb 24 '11 at 10:28
  • @Steve Yes, I am sure. I will try again though. – Jeff Feb 24 '11 at 15:52
  • @Steve Still nothing. It's empty. What do I do now? – Jeff Feb 24 '11 at 18:57
  • @Steve - I tried viewing the resources using XN Resource Editor. The Modified Manifest is present in my exe. – Jeff Feb 24 '11 at 19:31
  • @Jeff the only time I have an empty Parse file is when things work. – Steve Feb 28 '11 at 12:26
  • @Steve - Well, the SxS seems to be working I guess, but I still get a Class Not Registered. – Jeff Mar 02 '11 at 18:28
14

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.

Rob Kennedy
  • 156,531
  • 20
  • 258
  • 446
  • **create a private assembly manifest file (a text file) for the SideBySide.dll component and call it SideBySide.X.manifest.** - Why add the ".X"? Also, wont I have to do something in Delphi so that the .manifest files will be used? I havent done this before. – Jeff Feb 22 '11 at 09:22
  • "In cases where this is not possible, please be careful to give your assembly (and consequently your assembly manifest) a name that differs from that of the COM DLL's file name. So, in the above case, the COM DLL is called *SideBySide* but the assembly is called *SideBySide.X*. If you're interested in the reason for this constraint, it is explained in the *Troubleshooting* section." (In particular, paragraphs 5–7.) – Rob Kennedy Feb 22 '11 at 15:27
  • There's nothing you have to do to make your Delphi program use manifests because your Delphi program won't use manifests. Manifests are something processed automatically by the OS; applications are oblivious to it (unless you use the activation-context API, but as the article explains, the need for that is rare). – Rob Kennedy Feb 22 '11 at 15:28
1

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>
Ian Boyd
  • 220,884
  • 228
  • 805
  • 1,125