native: fix uninstall self-destruction behavior...... by not showing the command prompt window and fork-spawning the cmd

This commit is contained in:
liushuyu 2019-04-10 21:00:25 -06:00 committed by James
parent 5603981af1
commit 4578450bff
2 changed files with 103 additions and 25 deletions

View File

@ -8,6 +8,7 @@
#include "objbase.h"
#include "objidl.h"
#include "shlguid.h"
#include "shlobj.h"
// https://stackoverflow.com/questions/52101827/windows-10-getsyscolor-does-not-get-dark-ui-color-theme
extern "C" int isDarkThemeActive() {
@ -32,60 +33,65 @@ extern "C" int saveShortcut(
const char *description,
const char *path,
const char *args,
const char *workingDir) {
char* errStr = NULL;
const char *workingDir)
{
char *errStr = NULL;
HRESULT h;
IShellLink* shellLink = NULL;
IPersistFile* persistFile = NULL;
IShellLink *shellLink = NULL;
IPersistFile *persistFile = NULL;
#ifdef _WIN64
wchar_t wName[MAX_PATH+1];
wchar_t wName[MAX_PATH + 1];
#else
WORD wName[MAX_PATH+1];
WORD wName[MAX_PATH + 1];
#endif
int id;
// Initialize the COM library
h = CoInitialize(NULL);
if (FAILED(h)) {
if (FAILED(h))
{
errStr = "Failed to initialize COM library";
goto err;
}
h = CoCreateInstance( CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
IID_IShellLink, (PVOID*)&shellLink );
if (FAILED(h)) {
h = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
IID_IShellLink, (PVOID *)&shellLink);
if (FAILED(h))
{
errStr = "Failed to create IShellLink";
goto err;
}
h = shellLink->QueryInterface(IID_IPersistFile, (PVOID*)&persistFile);
if (FAILED(h)) {
h = shellLink->QueryInterface(IID_IPersistFile, (PVOID *)&persistFile);
if (FAILED(h))
{
errStr = "Failed to get IPersistFile";
goto err;
}
//Append the shortcut name to the folder
MultiByteToWideChar(CP_UTF8,0,shortcutPath,-1,wName,MAX_PATH);
MultiByteToWideChar(CP_UTF8, 0, shortcutPath, -1, wName, MAX_PATH);
// Load the file if it exists, to get the values for anything
// that we do not set. Ignore errors, such as if it does not exist.
h = persistFile->Load(wName, 0);
// Set the fields for which the application has set a value
if (description!=NULL)
if (description != NULL)
shellLink->SetDescription(description);
if (path!=NULL)
if (path != NULL)
shellLink->SetPath(path);
if (args!=NULL)
if (args != NULL)
shellLink->SetArguments(args);
if (workingDir!=NULL)
if (workingDir != NULL)
shellLink->SetWorkingDirectory(workingDir);
//Save the shortcut to disk
h = persistFile->Save(wName, TRUE);
if (FAILED(h)) {
if (FAILED(h))
{
errStr = "Failed to save shortcut";
goto err;
}
@ -105,3 +111,46 @@ err:
return h;
}
// NOTE: app and cmdline cannot be constant when Unicode support is enabled
extern "C" int spawnDetached(const char *app, const char *cmdline)
{
// TODO: Unicode support
STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcessA(app, // No module name (use command line)
(LPSTR)cmdline, // Command line, no unicode allowed
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
CREATE_NO_WINDOW, // Create without window
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
return GetLastError();
}
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
extern "C" HRESULT getSystemFolder(wchar_t *out_path)
{
PWSTR path = NULL;
HRESULT result = SHGetKnownFolderPath(FOLDERID_System, 0, NULL, &path);
if (result == S_OK)
{
wcscpy_s(out_path, MAX_PATH + 1, path);
CoTaskMemFree(path);
}
return result;
}

View File

@ -20,10 +20,10 @@ mod natives {
use logging::LoggingErrors;
use std::env;
use std::process::Command;
use winapi::shared::minwindef::{DWORD, FALSE, MAX_PATH};
use winapi::um::processthreadsapi::OpenProcess;
use winapi::shared::winerror::HRESULT;
use winapi::um::psapi::{
EnumProcessModulesEx, GetModuleFileNameExW, K32EnumProcesses, LIST_MODULES_ALL,
};
@ -41,6 +41,15 @@ mod natives {
) -> ::std::os::raw::c_int;
pub fn isDarkThemeActive() -> ::std::os::raw::c_uint;
pub fn spawnDetached(
app: *const ::std::os::raw::c_char,
cmdline: *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int;
pub fn getSystemFolder(
out_path: *mut ::std::os::raw::c_ushort
) -> HRESULT;
}
// Needed here for Windows interop
@ -109,15 +118,35 @@ mod natives {
.log_expect("Unable to convert log path to string")
.replace(" ", "\\ ");
let target_arguments = format!("ping 127.0.0.1 -n 3 > nul && del {} {}", tool, log);
let target_arguments = format!("/C choice /C Y /N /D Y /T 2 & del {} {}", tool, log);
info!("Launching cmd with {:?}", target_arguments);
Command::new("C:\\Windows\\system32\\cmd.exe")
.arg("/C")
.arg(&target_arguments)
.spawn()
.log_expect("Unable to start child process");
#[allow(unsafe_code)]
let spawn_result : i32 = unsafe {
let mut cmd_path = [0u16; MAX_PATH + 1];
let result = getSystemFolder(cmd_path.as_mut_ptr());
let mut pos = 0;
for x in cmd_path.iter() {
if *x == 0 {
break;
}
pos += 1;
}
if result != winapi::shared::winerror::S_OK {
return;
}
spawnDetached(
CString::new(format!("{}\\cmd.exe", String::from_utf16_lossy(&cmd_path[..pos])))
.log_expect("Unable to convert Windows system folder name to string")
.as_ptr(),
CString::new(target_arguments).log_expect("Unable to convert arguments").as_ptr(),
)
};
if spawn_result != 0 {
warn!("Unable to start child process");
}
}
#[allow(unsafe_code)]