Archived Forum Post

Index of archived forum posts

Question:

How to Check to see if an ActiveX is Already Installed?

Jul 19 '16 at 02:52

(This question reproduced with the customer's permission.)

Hello,
I’m developing with Powerbuilder and now use the Chilkat-ActiveX.

I want to redistribute the file ‘Chilkat ActiveX 9.5.0 win32/ChilkatAx-9.5.0-win32.msi’ along with my application. If the msi is not installed yet on the client computer then it is installed automatically by calling msiexec.exe.

This works fine, but the basic question is, how to determine if the ActiveX is yet installed or not. Could you give me a hint, what the best solution could be: Looking for registry entries? Looking for files on the local PC? I also read about testing the registry key HKLMSOFTWAREMicrosoftWindowsCurrentVersionUninstall, but in my system there is no ‘Chilkat’-entry under this key?

A solution that works for all Windows OS’s would be fine!

Of course I could say, that when ‘ConnectToNewObject’ gives an error, then it is not installed, but this could also have other reasons. Here’s my basic PB code of this task:

ole = create oleobject

ll_rc = ole.ConnectToNewObject("Chilkat_9_5_0.Crypt2")

if ll_rc < 0 then n_runandwait ln_rnw w_start.setmicrohelp("Installing Chilkat_9_5_0 ...") ll_rc = ln_rnw.of_run("msiexec /i ~"" + gs_pfad_version + "" + & "Chilkat ActiveX 9.5.0 win32ChilkatAx-9.5.0-win32.msi" + "~" /passive", normal!) if ll_rc <> ln_rnw.WAIT_COMPLETE then Messagebox(gs_app_tit, "Error installing 'Chilkat_9_5_0‘") lb_err = true exit end if end if



Answer

Checking the Windows registry is the best solution. Also, once the registry locations are verified, double-check that the DLL file exists in the filesystem where it is indicated in the registry.

An ActiveX DLL can and usually does contain many classes. The Chilkat ActiveX is one such DLL. An object instance for a given class is typically created via a CreateObject statement, or something similar depending on the programming language. The class name, such as "Chilkat_9_5_0.SFtp", is passed to CreateObject. For example, in VBScript:

set obj = CreateObject("Chilkat_9_5_0.SFtp")
The object name for each Chilkat class is indicated in the reference documentation. For example: https://www.chilkatsoft.com/refdoc/xChilkatSFtpRef.html

The class name is used to find the registry entry. These are the pertinent registry entries:

HKEY_CLASSES_ROOT
  |
  -- Chilkat_9_5_0.SFtp
      |
      -- CLSID -- {345A5644-4F8E-4BCC-8E65-389B3C9D52B6}

HKEY_CLASSES_ROOT | -- CLSID | -- {345A5644-4F8E-4BCC-8E65-389B3C9D52B6} | -- InProcServer32 -- C:\My-Chilkat-Install-Dir\ChilkatAx-9.5.0-win32.dll

The CLSID is obtained from the name (Chilkat_9_5_0.SFtp), and then the file location is determined from the CLSID.

You can see that the ActiveX DLL can be located anywhere on your computer (but should be on a local hard drive). (It does not need to be placed in the Windows/System32 directory.) However, once the DLL is registered, it should not be moved — otherwise the pointer from the registry is no longer valid.

To check to see if the Chilkat ActiveX is installed, pick a class and then check to see if the registry entries exist. First get the CLSID, then lookup the CLSID record to get the DLL file location and check to see if the file actually exists.

Important: A Windows system will have entirely separate 32-bit and 64-bit registries. A 32-bit program implicitly uses the 32-bit registry, and a 64-bit program implicitly uses the 64-bit registry.

Here is some sample C# code that checks to see if Chilkat is registered. (I know it's not PowerBuilder, but it can be reviewed as a general guideline for programming the same in any other language..)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Win32;
using System.IO;

namespace CheckChilkatActiveX
    {
    public partial class Form1 : Form
    {
    public Form1()
        {
        InitializeComponent();
        }

private bool m_is32bit = false;
    private string m_bitSizeStr = "64-bit";

private void button1_Click(object sender, EventArgs e)
        {
        string dllPath = null;

// The Chilkat ActiveX DLL contains many COM objects.  
        // Check for the CLSID subkey for one of them (in this case, Ftp2)
        RegistryKey comKey = Registry.ClassesRoot.OpenSubKey("Chilkat_9_5_0.Ftp2\\CLSID");
        if (comKey == null)
        {
        textBox4.Text = "HKEY_CLASSES_ROOT/Chilkat_9_5_0.Ftp2 not found.  The " + m_bitSizeStr + " ActiveX is not registered.";
        return;
        }
        string clsid = (string)comKey.GetValue("");
        if (clsid == null)
        {
        textBox4.Text = "HKEY_CLASSES_ROOT/Chilkat_9_5_0.Ftp2 not found.  The " + m_bitSizeStr + " ActiveX is not registered.";
        return;
        }
        else
        {
        // Find the path to the DLL.
        textBox2.Text = clsid;
        comKey = Registry.ClassesRoot.OpenSubKey("CLSID\\" + clsid + "\\InprocServer32");
        dllPath = (string)comKey.GetValue("");
        if (dllPath == null)
            {
            textBox3.Text = "The InprocServer32 registry key was not found.";
            }
        else
            {
            textBox3.Text = dllPath;
            }
        }

if (dllPath == null) return;

// Does the DLL exist?
        bool bDllExists = File.Exists(dllPath);
        if (!bDllExists)
        {
        lblExists.Text = "The DLL file does not exist!";
        lblExists.ForeColor = Color.Red;
        return;
        }
        else
        {
        lblExists.Text = "OK, the DLL exists.";
        // Can we open the DLL?
        FileStream fs = null;
        try
            {
            fs = File.OpenRead(dllPath);
            }
        catch (Exception )
            {
            MessageBox.Show("Failed to open DLL for reading!");
            return;
            }

}

// Now try to create an instance of an object contained in the ActiveX DLL.  We'll try to create the Crypt2 object:
        dynamic crypt2 = Activator.CreateInstance(Type.GetTypeFromProgID("Chilkat_9_5_0.Crypt2"));
        if (crypt2 == null)
        {
        textBox4.Text = "Failed to load the DLL and instantiate a Chilkat ActiveX object.";
        }
        else
        {
        // What is the version of this Chilkat ActiveX component?
        textBox1.Text = crypt2.Version;

// Do something to get the LastErrorText..
        crypt2.UnlockComponent("Test");
        textBox4.Text = crypt2.LastErrorText;
        }

}

private void Form1_Load(object sender, EventArgs e)
        {
        if (IntPtr.Size == 4)
        {
        // 32-bit
        this.Text = "Check the 32-bit Chilkat ActiveX Registration";
        m_is32bit = true;
        m_bitSizeStr = "32-bit";
        }
        else if (IntPtr.Size == 8)
        {
        // 64-bit
        this.Text = "Check the 64-bit Chilkat ActiveX Registration";
        }
        }
    }
    }

Answer

Thank you, that helped me a lot. If somebody's interested in the Powerbuilder Code see the following snippet of code: I have this code in the constructor of my OLE wrapper object. It checks if Chilkat (in this case Crypt2) is installed otherwise installs it from a local msi-file, then creates the OLE object. I tested this on XP32, W7-64, W10-32 and W10-64 with and without UAC active. Works well!

// Check if Chilkat is installed
ll_rc = RegistryGet("HKEY_CLASSES_ROOT\Chilkat_9_5_0.Crypt2\CLSID", "", RegString!, ls_clsid)

if ll_rc = 1 then

    if gn_api.of_is_32or64bit_windows() = 32 then    // own function to get Bitness of W
        ll_rc = RegistryGet("HKEY_CLASSES_ROOT\CLSID\" + ls_clsid + "\InprocServer32", "", RegString!, ls_ips32)
    else
        ll_rc = RegistryGet("HKEY_CLASSES_ROOT\Wow6432Node\CLSID\" + ls_clsid + "\InprocServer32", "", RegString!, ls_ips32)
    end if

    if ll_rc = 1 then

        if Fileexists(ls_ips32) then lb_installed = true

    end if

end if

// Install Chilkat
if not lb_installed then

    n_runandwait ln_rnw

    w_start.setmicrohelp("Installing Chilkat_9_5_0 ...")

    ls_fullpath = gs_path_program
    if ls_fullpath <> "" then ls_fullpath += "\"
    ls_fullpath += "ChilkatAx-9.5.0-win32.msi"

    ll_rc = ln_rnw.of_run("msiexec /i ~"" + ls_fullpath + "~" /passive", normal!)

    if ll_rc <> ln_rnw.WAIT_COMPLETE then 
        Messagebox(gs_app_tit, "Error auto-installing 'Chilkat_9_5_0'!")
        lb_err = true
        exit
    end if

end if

// Create Chilkat Crypt2 OLE-Object
ole = create oleobject

ll_rc = ole.ConnectToNewObject("Chilkat_9_5_0.Crypt2")

if ll_rc < 0 then

    Messagebox(gs_app_tit, "Error initializing 'Chilkat_9_5_0'!")
    lb_err = true
    exit

end if

Answer

Hi, Good work, but this is working only for OS 32 bit. When OS and app are 64 bit you must instal 64 bit chilcat ;-)

regards