How do I get ClickOnce to uninstall an old version

2019-06-26 05:49发布

问题:

I have been able to successfully package up my ClickOnce setup into an Inno Setup install script so I could deploy it as a single EXE file to my customers. This process works fine and is relatively painless.

Now I have a new version of my application that I want to deploy. I've updated the version, published the changes in Visual Studio 2013 and packaged them up using Inno Setup again. The install process works fine except that the old version of my application remains installed and the file associations still point to that old version.

So basically I want to know if it's possible to get ClickOnce to trigger an uninstall of an old version if it exists and if so, how to do it? Is it possible to get Inno Setup to help with this given that it is not actually doing the install?

UPDATE:

I've been doing some further research and it seems like Inno Setup might be able to trigger an uninstall for a previously installed ClickOnce application. I can see the uninstall key in the registry under

/Microsoft/Windows/CurrentVersion/Uninstall/<some random looking hex code>

If there is a way to know what the hex code above is, then I should be trigger the uninstall in Inno Setup. However I've looked through my solution and deployment files, and I can't find any reference to it. Is there a way to know what this value will be? Or is it just randomly generated at install time and we have no way of knowing what it will be?

UPDATE 2:

I found the code below, that (with some slight modifications) appears to detect my old version installed using ClickOnce (assuming that the GUID is static between installs).

[Code]
function GetUninstallString: string;
var
    sUnInstPath: string;
    sUnInstallString: String;
begin
    Result := '';
    sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\<hex value>'); //Your application's GUID/ID
    sUnInstallString := '';
    RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);
    Result := sUnInstallString;
end;

function IsUpgrade: Boolean;
begin
    Result := (GetUninstallString() <> '');
end;

function InitializeSetup(): Boolean;
var
    V: Integer;
    iResultCode: Integer;
    sUnInstallString: string;
begin

    Result := True; // In case when no previous version is found

    if RegValueExists(HKEY_CURRENT_USER,'Software\Microsoft\Windows\CurrentVersion\Uninstall\<hex value>', 'UninstallString') then  //Your application's GUID/ID
    begin
        V := MsgBox(ExpandConstant('An old version was detected. Do you want to uninstall it?'), mbInformation, MB_YESNO); //Custom message if the application is installed
        if V = IDYES then
        begin
            sUnInstallString := GetUninstallString();
            sUnInstallString := RemoveQuotes(sUnInstallString);
            Log(sUnInstallString);
            Exec(ExpandConstant(sUnInstallString), '', '', SW_SHOW, ewWaitUntilTerminated, iResultCode);
            Result := True; //If you want to proceed after uninstall
        end
        else
            Result := False; //When older version present and not uninstalled
        end;
    end;
end;

The problem I have now is that while it detects the entry, the EXEC isn't actually running the uninstall command successfully. The string looks something like this:

rundll32.exe dfshim.dll,ShArpMaintain MyApp.application, Culture=neutral, PublicKeyToken=27f9444c7c87407a, processorArchitecture=msil

If I run this from the command prompt it works perfectly, but from within Inno Setup nothing happens. I have checked the result code that comes back and retrieved the SysErrorMessage for it. It is:

The system cannot find the file specified.

I'm guessing that it can't find the MyApp.application file. I've tried adding a working directory into the arguments, but it's still not working.

UPDATE 3:

It looks like ClickOnce may have installed the application into the windows folder (I've no idea why that might have happened). Could this be why the the uninstall string works from the Command prompt, but not from Inno Setup? If so, is there a way around this?

UPDATE 4:

Okay, the "file not found" error is too vague. I have no idea where the application is looking or even which file it is looking for that it can't find. Is there a way to get more information from Inno Setup to debug this problem? What might be causing this command to fail when executed using Inno Setup? Why does it work from the command prompt?

UPDATE 5:

Since I've been unable to solve this problem, I've decided to go with a temporary workaround. Rather than attempting to trigger the uninstall automatically, I've modified the version check to simply alert the user that a previous version must be uninstalled before they can proceed.

It's not ideal, but hopefully this problem will disappear with future versions. Especially since it now looks like we will be moving from ClickOnce to having Inno Setup handle the entire installation process.