我们有一个使用Visual Studio内置的ClickOnce部署工具部署的生产应用程序。我正在编写一个批处理文件来卸载应用程序:
rundll32.exe dfshim.dll,ShArpMaintain AppName.application, Culture=neutral,
PublicKeyToken=XXXXXX, processorArchitecture=x86
批处理文件有效,并且调用了应用程序的卸载。但是,我想要默默地这样做。我试过/Q /q /S /s /Silent
,但没有快乐。
我该怎么做?
我不想要隐藏批处理文件窗口。只有 ClickOnce 窗口。
答案 0 :(得分:24)
由于似乎没有好的解决方案,我实施了一个新的ClickOnce卸载程序。它可以通过命令行从.NET调用,也可以作为自定义操作集成到WiX安装项目中。
https://github.com/6wunderkinder/Wunder.ClickOnceUninstaller
我们将此用于我们的Wunderlist 2.1版本,我们从ClickOnce切换到Windows Installer程序包。它已集成到安装过程中,对用户完全透明。
答案 1 :(得分:3)
我可以确认WMIC对ClickOnce应用程序不起作用。他们只是没有列在那里......
我想把它放在这里,因为我一直在努力寻找如何解决这个问题很长时间以来找不到完整的解决方案。
我在整个编程方面相当新,但我认为这可以提供如何继续的想法。
它基本上验证应用程序当前是否正在运行,如果是,则会终止它。然后它检查注册表以找到卸载字符串,将其放入批处理文件中并等待进程结束。然后它会使Sendkeys自动同意卸载。就是这样。
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();
}
}
}
}
答案 2 :(得分:2)
您可以尝试使用Hidden Start。
答案 3 :(得分:1)
您无法取消ClickOnce应用程序的卸载对话框。您可以编写一个小.NET应用程序来卸载ClickOnce应用程序,并以编程方式点击对话框上的按钮,因此用户无需执行任何操作。这是你能做的最好的事情。
答案 4 :(得分:-3)
不要过度复杂化&amp;保持简单 - 这适用于Windows XP & 7
:
转到Add/Remove Programs
并记下该计划的确切名称。
打开Notepad
并粘贴以下文字:
wmic product,其中name =“PROGRAM NAME”卸载
但请务必在引号之间键入程序的确切名称,然后选择Save As /All Files
并将文件命名为Uninstall.bat
,然后将其测试以确保其正常工作。