Uninstalling a ClickOnce application silently

后端 未结 5 988
故里飘歌
故里飘歌 2020-12-10 03:44

We have an production application that is deployed using Visual Studio\'s built-in ClickOnce deployment tool. I am writing a batch file to uninstall the application:

5条回答
  •  一生所求
    2020-12-10 03:44

    I can confirm that WMIC doesn't work for ClickOnce applications. They are just not listed in there...

    I thought of putting this here as I've been working on finding how to resolve this for a long time now and couldn't find a complete solution.

    I'm rather new in this whole programming thing but I think this could give ideas of how to proceed.

    It basically verifies if the application is currently running, and if so, it kills it. Then it checks the registry to find the uninstall string, put it in a batch file and wait for the process to end. Then it does Sendkeys to automatically agree to uninstall. That's it.

    namespace MyNameSpace
    {
        public class uninstallclickonce
        {
            [System.Runtime.InteropServices.DllImport("user32.dll")]
    
            private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    
            [System.Runtime.InteropServices.DllImport("user32.dll")]
    
            private static extern bool SetForegroundWindow(IntPtr hWnd);
    
            private Process process;
            private ProcessStartInfo startInfo;
    
            public void isAppRunning()
            {
                // Run the below command in CMD to find the name of the process
                // in the text file.
                //
                //     WMIC /OUTPUT:C:\ProcessList.txt PROCESS get Caption,Commandline,Processid
                //
                // Change the name of the process to kill
                string processNameToKill = "Auto-Crop"; 
    
                Process [] runningProcesses = Process.GetProcesses();
    
                foreach (Process myProcess in runningProcesses)
                {
                    // Check if given process name is running
                    if (myProcess.ProcessName == processNameToKill)
                    {
                        killAppRunning(myProcess);
                    }
                }
            }
    
            private void killAppRunning(Process myProcess)
            {
                // Ask the user if he wants to kill the process
                // now or cancel the installation altogether
                DialogResult killMsgBox =
                    MessageBox.Show(
                        "Crop-Me for OCA must not be running in order to get the new version\nIf you are ready to close the app, click OK.\nClick Cancel to abort the installation.",
                        "Crop-Me Still Running",
                        MessageBoxButtons.OKCancel,
                        MessageBoxIcon.Question);
    
                switch(killMsgBox)
                {
                    case DialogResult.OK:
                        //Kill the process
                        myProcess.Kill();
                        findRegistryClickOnce();
                        break;
                    case DialogResult.Cancel:
                        //Cancel whole installation
                        break;
                }
            }
    
            private void findRegistryClickOnce()
            {
                string uninstallRegString = null; // Will be ClickOnce Uninstall String
                string valueToFind = "Crop Me for OCA"; // Name of the application we want
                                                        // to uninstall (found in registry)
                string keyNameToFind = "DisplayName"; // Name of the Value in registry
                string uninstallValueName = "UninstallString"; // Name of the uninstall string
    
                //Registry location where we find all installed ClickOnce applications
                string regProgsLocation = 
                    "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
    
                using (RegistryKey baseLocRegKey = Registry.CurrentUser.OpenSubKey(regProgsLocation))
                {
                    //Console.WriteLine("There are {0} subkeys in here", baseLocRegKey.SubKeyCount.ToString());
    
                    foreach (string subkeyfirstlevel in baseLocRegKey.GetSubKeyNames())
                    {
                       //Can be used to see what you find in registry
                       // Console.WriteLine("{0,-8}: {1}", subkeyfirstlevel, baseLocRegKey.GetValueNames());
    
                        try
                        {
                            string subtest = baseLocRegKey.ToString() + "\\" + subkeyfirstlevel.ToString();
    
                            using (RegistryKey cropMeLocRegKey =
                                     Registry.CurrentUser.OpenSubKey(regProgsLocation + "\\" + subkeyfirstlevel))
                            {
                                //Can be used to see what you find in registry
                                //  Console.WriteLine("Subkey DisplayName: " + cropMeLocRegKey.GetValueNames());
    
                                //For each
                                foreach (string subkeysecondlevel in cropMeLocRegKey.GetValueNames())
                                {
                                    // If the Value Name equals the name application to uninstall
                                    if (cropMeLocRegKey.GetValue(keyNameToFind).ToString() == valueToFind)
                                    {
                                        uninstallRegString = cropMeLocRegKey.GetValue(uninstallValueName).ToString();
    
                                        //Exit Foreach
                                        break;
                                    }
                                }
                            }
                        }
                        catch (System.Security.SecurityException)
                        {
                            MessageBox.Show("security exception?");
                        }
                    }
                }
                if (uninstallRegString != null)
                {
                    batFileCreateStartProcess(uninstallRegString);
                }
            }
    
            // Creates batch file to run the uninstall from
            private void batFileCreateStartProcess(string uninstallRegstring)
            {
                //Batch file name, which will be created in Window's temps foler
                string tempPathfile = Path.GetTempPath() + "cropmeuninstall.bat";
    
                if (!File.Exists(@tempPathfile))
                {
                    using (FileStream createfile = File.Create(@tempPathfile))
                    {
                        createfile.Close();
                    }
                }
    
                using (StreamWriter writefile = new StreamWriter(@tempPathfile))
                {
                    //Writes our uninstall value found earlier in batch file
                    writefile.WriteLine(@"Start " + uninstallRegstring);
                }
    
                process = new Process();
                startInfo = new ProcessStartInfo();
    
                startInfo.FileName = tempPathfile;
                process.StartInfo = startInfo;
                process.Start();
                process.WaitForExit();
    
                File.Delete(tempPathfile); //Deletes the file
    
                removeClickOnceAuto();
            }
    
            // Automation of clicks in the uninstall to remove the
            // need of any user interactions
            private void removeClickOnceAuto()
            {
                IntPtr myWindowHandle = IntPtr.Zero;
    
                for (int i = 0; i < 60 && myWindowHandle == IntPtr.Zero; i++)
                {
                    Thread.Sleep(1500);
    
                    myWindowHandle = FindWindow(null, "Crop Me for OCA Maintenance");
                }
    
                if (myWindowHandle != IntPtr.Zero)
                {
                    SetForegroundWindow(myWindowHandle);
    
                    SendKeys.Send("+{TAB}"); // Shift + TAB
                    SendKeys.Send("{ENTER}");
                    SendKeys.Flush();
                }
            }
        }
    }
    

提交回复
热议问题