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 "objbase.h"
#include "objidl.h" #include "objidl.h"
#include "shlguid.h" #include "shlguid.h"
#include "shlobj.h"
// https://stackoverflow.com/questions/52101827/windows-10-getsyscolor-does-not-get-dark-ui-color-theme // https://stackoverflow.com/questions/52101827/windows-10-getsyscolor-does-not-get-dark-ui-color-theme
extern "C" int isDarkThemeActive() { extern "C" int isDarkThemeActive() {
@ -32,60 +33,65 @@ extern "C" int saveShortcut(
const char *description, const char *description,
const char *path, const char *path,
const char *args, const char *args,
const char *workingDir) { const char *workingDir)
char* errStr = NULL; {
char *errStr = NULL;
HRESULT h; HRESULT h;
IShellLink* shellLink = NULL; IShellLink *shellLink = NULL;
IPersistFile* persistFile = NULL; IPersistFile *persistFile = NULL;
#ifdef _WIN64 #ifdef _WIN64
wchar_t wName[MAX_PATH+1]; wchar_t wName[MAX_PATH + 1];
#else #else
WORD wName[MAX_PATH+1]; WORD wName[MAX_PATH + 1];
#endif #endif
int id; int id;
// Initialize the COM library // Initialize the COM library
h = CoInitialize(NULL); h = CoInitialize(NULL);
if (FAILED(h)) { if (FAILED(h))
{
errStr = "Failed to initialize COM library"; errStr = "Failed to initialize COM library";
goto err; goto err;
} }
h = CoCreateInstance( CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, h = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
IID_IShellLink, (PVOID*)&shellLink ); IID_IShellLink, (PVOID *)&shellLink);
if (FAILED(h)) { if (FAILED(h))
{
errStr = "Failed to create IShellLink"; errStr = "Failed to create IShellLink";
goto err; goto err;
} }
h = shellLink->QueryInterface(IID_IPersistFile, (PVOID*)&persistFile); h = shellLink->QueryInterface(IID_IPersistFile, (PVOID *)&persistFile);
if (FAILED(h)) { if (FAILED(h))
{
errStr = "Failed to get IPersistFile"; errStr = "Failed to get IPersistFile";
goto err; goto err;
} }
//Append the shortcut name to the folder //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 // 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. // that we do not set. Ignore errors, such as if it does not exist.
h = persistFile->Load(wName, 0); h = persistFile->Load(wName, 0);
// Set the fields for which the application has set a value // Set the fields for which the application has set a value
if (description!=NULL) if (description != NULL)
shellLink->SetDescription(description); shellLink->SetDescription(description);
if (path!=NULL) if (path != NULL)
shellLink->SetPath(path); shellLink->SetPath(path);
if (args!=NULL) if (args != NULL)
shellLink->SetArguments(args); shellLink->SetArguments(args);
if (workingDir!=NULL) if (workingDir != NULL)
shellLink->SetWorkingDirectory(workingDir); shellLink->SetWorkingDirectory(workingDir);
//Save the shortcut to disk //Save the shortcut to disk
h = persistFile->Save(wName, TRUE); h = persistFile->Save(wName, TRUE);
if (FAILED(h)) { if (FAILED(h))
{
errStr = "Failed to save shortcut"; errStr = "Failed to save shortcut";
goto err; goto err;
} }
@ -105,3 +111,46 @@ err:
return h; 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 logging::LoggingErrors;
use std::env; use std::env;
use std::process::Command;
use winapi::shared::minwindef::{DWORD, FALSE, MAX_PATH}; use winapi::shared::minwindef::{DWORD, FALSE, MAX_PATH};
use winapi::um::processthreadsapi::OpenProcess; use winapi::um::processthreadsapi::OpenProcess;
use winapi::shared::winerror::HRESULT;
use winapi::um::psapi::{ use winapi::um::psapi::{
EnumProcessModulesEx, GetModuleFileNameExW, K32EnumProcesses, LIST_MODULES_ALL, EnumProcessModulesEx, GetModuleFileNameExW, K32EnumProcesses, LIST_MODULES_ALL,
}; };
@ -41,6 +41,15 @@ mod natives {
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
pub fn isDarkThemeActive() -> ::std::os::raw::c_uint; 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 // Needed here for Windows interop
@ -109,15 +118,35 @@ mod natives {
.log_expect("Unable to convert log path to string") .log_expect("Unable to convert log path to string")
.replace(" ", "\\ "); .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); info!("Launching cmd with {:?}", target_arguments);
Command::new("C:\\Windows\\system32\\cmd.exe") #[allow(unsafe_code)]
.arg("/C") let spawn_result : i32 = unsafe {
.arg(&target_arguments) let mut cmd_path = [0u16; MAX_PATH + 1];
.spawn() let result = getSystemFolder(cmd_path.as_mut_ptr());
.log_expect("Unable to start child process"); 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)] #[allow(unsafe_code)]