1use std::env::current_exe;
2use std::ffi::{OsStr, OsString};
3use std::io;
4use std::path::Path;
5
6use crate::convert::encode_escaped_os_str;
7use crate::error::Error;
8use crate::error::ErrorKind::*;
9use crate::registry::OpenRegistryKey;
10use crate::Result;
11
12#[non_exhaustive]
14pub struct AutoStart {
15 name: Box<OsStr>,
16 executable: Box<Path>,
17 arguments: Vec<OsString>,
18}
19
20impl AutoStart {
21 pub fn current_exe<N>(name: N) -> Result<Self>
23 where
24 N: AsRef<OsStr>,
25 {
26 let executable = current_exe().map_err(CurrentExecutable)?;
27 Ok(Self::new(name, executable))
28 }
29
30 #[inline]
35 pub fn new<N, E>(name: N, executable: E) -> Self
36 where
37 N: AsRef<OsStr>,
38 E: AsRef<Path>,
39 {
40 Self {
41 name: name.as_ref().into(),
42 executable: executable.as_ref().into(),
43 arguments: Vec::new(),
44 }
45 }
46
47 pub fn arguments<A>(&mut self, arguments: A)
49 where
50 A: IntoIterator,
51 A::Item: AsRef<OsStr>,
52 {
53 self.arguments = arguments
54 .into_iter()
55 .map(|a| a.as_ref().to_os_string())
56 .collect();
57 }
58}
59
60impl AutoStart {
61 fn registry_entry(&self) -> Result<String> {
63 let mut entry = String::new();
64
65 encode_escaped_os_str(&mut entry, self.executable.as_os_str())
66 .map_err(BadAutoStartExecutable)?;
67
68 for argument in &self.arguments {
69 entry.push(' ');
70 encode_escaped_os_str(&mut entry, argument).map_err(BadAutoStartArgument)?;
71 }
72
73 Ok(entry)
74 }
75
76 pub fn is_installed(&self) -> Result<bool> {
78 let key = OpenRegistryKey::current_user()
79 .open("Software\\Microsoft\\Windows\\CurrentVersion\\Run")
80 .map_err(OpenRegistryKey)?;
81
82 let path = match key.get_string(&self.name) {
83 Ok(path) => path,
84 Err(e) if e.kind() == io::ErrorKind::NotFound => return Ok(false),
85 Err(e) => return Err(Error::new(GetRegistryValue(e))),
86 };
87
88 Ok(self.registry_entry()?.as_str() == path)
89 }
90
91 pub fn install(&self) -> Result<()> {
93 let key = OpenRegistryKey::current_user()
94 .set_value()
95 .open("Software\\Microsoft\\Windows\\CurrentVersion\\Run")
96 .map_err(OpenRegistryKey)?;
97 key.set(&self.name, self.registry_entry()?)
98 .map_err(SetRegistryKey)?;
99 Ok(())
100 }
101
102 pub fn uninstall(&self) -> Result<()> {
104 let key = OpenRegistryKey::current_user()
105 .set_value()
106 .open("Software\\Microsoft\\Windows\\CurrentVersion\\Run")
107 .map_err(OpenRegistryKey)?;
108 key.delete(&self.name).map_err(DeleteRegistryKey)?;
109 Ok(())
110 }
111}