1
votes

How do I structure my Inno Setup script to automatically register a dll if it is the first time a user has installed my application but unregister a previous version if there is one and then register the new one (assuming the interface is different)?

I currently use the the regserver and ignoreversion flags in my Files section as seen below:

[Setup]
...

[Languages]
...

[Files]
Source: "C:\example.dll"; DestDir: "{app}"; Flags: ignoreversion regserver

In my google search I have found UnregisterServer but I not know how to add this to my script. I would gladly start tinkering around to see how this works, but I do not want to do anything that will mess-up my registry.

There is a similar post here but it does not address how this is actually accomplished.

EDIT

After hacking around in Pascal I was able to add the following to the [Code] section and it worked. Does anyone know how to use the {app} constant to dynamically define the fileName in the code below?

[Code]
const
  fileName = 'C:\Program Files\TFolderName\tigercontroller.dll';
var
  serverExists: Boolean;

function InitializeSetup(): Boolean;
begin     
  serverExists := UnregisterServer(False, fileName, False);

  if serverExists then begin
    Result:= True;
    MsgBox('This will update with the most recent version', mbInformation, mb_Ok);
  end else
    Result := True;
end;
2
It is too early to expand the {app} constant at the InitializeSetup time. Moreover, the {app} constant contains the currently selected install folder whilst you want to check the previous application folder. You can get the last folder from WizardForm.PrevAppDir property soonest from the InitializeWizard event method e.g. this way. - TLama
Tlama, Thank you for that! I was wondering why I could not reference {app}. How does WizardForm.PrevAppDir work? Do I have to keep my .iss script the same so that the wizard knows that this wizard was used before? - Michael David Watson
Typically you're not supposed to change COM interfaces sufficiently so that they're incompatible (you're supposed to only ever add, never subtract). As such there is never any need to unregister the old version. Of course, you get a bit more leeway when it's an app-private library rather than a shared one. - Miral
I was under the impression that if I add a new method call on the interface, I would need to unregister the previous COM interface and re-register with the new one (using same GUID). Is this not the case? - Michael David Watson
@Michael, the WizardForm.PrevAppDir is just a property holding the folder path, where the installer with a certain AppId has previously installed the application (empty if not yet installed). In other words, this property will return you the previous install folder path unless you change the AppId in your script. Once you change AppId, it is treated as a different setup. - TLama

2 Answers

2
votes

What about using BeforeInstall and AfterInstall parameters for file?

Usage is:

[Files]
Source: "MYDLL.DLL"; DestDir: "{app}"; BeforeInstall: MyBeforeInstall; AfterInstall: MyAfterInstall;

BeforeInstall and AfterInstall functions must not have a return value!

procedure MyBeforeInstall();
begin
  // Your code here: If file (old) file exists call UnregisterServer() on old file
  // Use function FileExists(const Name: String): Boolean; or similar for it
  // Also you can delete the file entirely with function DeleteFile(const FileName: string): Boolean;

  // Hint: You can use 'CurrentFileName' variable to get currently processed file 
end;

procedure MyAfterInstall();
begin
  // Your (new) file was processed and now you can do additional tweaks on it
  // 'CurrentFileName' variable is still available 
  // Setup registers all files with the 'regserver' or 'regtypelib' flags as the last step of installation so in this function the file is still not registered!
end;
0
votes

Try this one, it also handles 32/64bit side-by-side COM servers:

 function UnregisterCOMServer(sServerCLSID: String): Boolean;
var
   sServerPath: String;
Begin
    Result:=False;
     //search in HKCR (merged view)
     if RegQueryStringValue(HKEY_CLASSES_ROOT, 'CLSID\'+sServerCLSID+'\InprocServer32', '', sServerPath) then
     Begin
        if sServerPath<>'' then
        Begin
            Log('Found COM server CLSID:'+ sServerCLSID +', path:'+sServerPath);
            Result:=UnregisterServer(False, sServerPath, True);
            if Result then Log('COM server '+ sServerCLSID +' unregistered.')
            else Log('UnregisterServer on '+ sServerPath +' failed!');
        end
        else Log('No COM server path found.');
     end
     else Log('COM server CLSID:'+ sServerCLSID +' not found!'+sServerPath);

 if Is64BitInstallMode then
 Begin
     if RegQueryStringValue(HKEY_CLASSES_ROOT, 'Wow6432Node\CLSID\'+sServerCLSID+'\InprocServer32', '', sServerPath) then
     Begin
        if sServerPath<>'' then
        Begin
            Log('Found COM server (Wow6432) CLSID:'+ sServerCLSID +', path:'+sServerPath);
            Result:=UnregisterServer(True, sServerPath, True);
            if Result then Log('COM server (Wow6432) '+ sServerCLSID +' unregistered.')
            else Log('UnregisterServer (Wow6432) on '+ sServerPath +' failed!');
        end
        else Log('No COM server (Wow6432) path found.');
     end
     else Log('COM server (Wow6432) CLSID:'+ sServerCLSID +' not found!'+sServerPath);
 end;

end;