2 extern crate windows_service
;
8 atomic
::{AtomicBool
, Ordering
},
12 time
::{self, Duration
},
16 use log
::{debug
, error
, info
, trace
, warn
};
17 use windows
::Win32
::Foundation
::{ERROR_SERVICE_DOES_NOT_EXIST
, WIN32_ERROR
};
18 use windows_service
::{
20 ServiceAccess
, ServiceControl
, ServiceControlAccept
, ServiceErrorControl
, ServiceExitCode
,
21 ServiceInfo
, ServiceStartType
, ServiceState
, ServiceStatus
, ServiceType
,
23 service_control_handler
::{self, ServiceControlHandlerResult
, ServiceStatusHandle
},
25 service_manager
::{ServiceManager
, ServiceManagerAccess
},
28 define_windows_service!(ffi_service_main
, service_main
);
31 #![allow(warnings, unused)]
32 include!(concat!(env!("OUT_DIR"), "/ols_api.rs"));
36 #![allow(warnings, unused)]
37 include!(concat!(env!("OUT_DIR"), "/intel_arc.rs"));
46 mod corsair_vengeance
;
49 // mod roccat; Disabled.
55 fn main() -> Result
<()> {
56 let is_debug
= cfg!(debug_assertions
);
58 flexi_logger
::Logger
::try_with_str(if is_debug
{ "debug" } else { "info" })?
60 flexi_logger
::FileSpec
::default()
61 .directory(dirs
::config_dir().unwrap().join(consts
::SERVICE_NAME
))
62 .basename(consts
::SERVICE_NAME
),
64 .duplicate_to_stdout(flexi_logger
::Duplicate
::All
)
66 flexi_logger
::default_format
68 flexi_logger
::detailed_format
71 flexi_logger
::Criterion
::Size(1024 * 1024),
72 flexi_logger
::Naming
::Timestamps
,
73 flexi_logger
::Cleanup
::KeepLogFiles(10),
78 let args
: Vec
<String
> = env
::args().collect();
80 info!("Temperature to RGB");
82 if args
.contains(&"--no-service".to_string()) {
83 let completed
: Arc
<AtomicBool
> = Arc
::new(AtomicBool
::new(false));
84 main_loop
::main_loop(completed
.clone());
85 } else if args
.contains(&"--tests".to_string()) {
87 } else if args
.contains(&"--install-service".to_string()) {
88 println!("Installing service...");
90 } else if args
.contains(&"--uninstall-service".to_string()) {
91 println!("Uninstalling service...");
94 service_dispatcher
::start(consts
::SERVICE_NAME
, ffi_service_main
)?
;
100 fn install_service() -> windows_service
::Result
<()> {
101 let manager_access
= ServiceManagerAccess
::CONNECT
| ServiceManagerAccess
::CREATE_SERVICE
;
102 let service_manager
= ServiceManager
::local_computer(None
::<&str>, manager_access
)?
;
104 let service_binary_path
= std
::env
::current_exe()
106 .with_file_name("temp_2_rgb.exe");
108 println!("Installing service: {service_binary_path:?}");
110 let service_info
= ServiceInfo
{
111 name
: OsString
::from(consts
::SERVICE_NAME
),
112 display_name
: OsString
::from(consts
::SERVICE_NAME
),
113 service_type
: ServiceType
::OWN_PROCESS
,
114 start_type
: ServiceStartType
::AutoStart
,
115 error_control
: ServiceErrorControl
::Normal
,
116 executable_path
: service_binary_path
,
117 launch_arguments
: vec
![],
118 dependencies
: vec
![],
119 account_name
: None
, // run as System
120 account_password
: None
,
122 let service
= service_manager
.create_service(&service_info
, ServiceAccess
::CHANGE_CONFIG
)?
;
123 service
.set_description(
124 "A service to set the color of hardware according to the temperature of GPU and CPU",
129 fn uninstall_service() -> windows_service
::Result
<()> {
130 let manager_access
= ServiceManagerAccess
::CONNECT
;
131 let service_manager
= ServiceManager
::local_computer(None
::<&str>, manager_access
)?
;
133 let service_access
= ServiceAccess
::QUERY_STATUS
| ServiceAccess
::STOP
| ServiceAccess
::DELETE
;
134 let service
= service_manager
.open_service(consts
::SERVICE_NAME
, service_access
)?
;
136 // The service will be marked for deletion as long as this function call succeeds.
137 // However, it will not be deleted from the database until it is stopped and all open handles to it are closed.
140 // Our handle to it is not closed yet. So we can still query it.
141 if service
.query_status()?
.current_state
!= ServiceState
::Stopped
{
142 // If the service cannot be stopped, it will be deleted when the system restarts.
146 // Explicitly close our open handle to the service. This is automatically called when `service` goes out of scope.
149 // Win32 API does not give us a way to wait for service deletion.
150 // To check if the service is deleted from the database, we have to poll it ourselves.
151 let start
= time
::Instant
::now();
152 let timeout
= Duration
::from_secs(5);
153 while start
.elapsed() < timeout
{
154 if let Err(windows_service
::Error
::Winapi(e
)) =
155 service_manager
.open_service(consts
::SERVICE_NAME
, ServiceAccess
::QUERY_STATUS
)
157 let WIN32_ERROR(error_num
) = ERROR_SERVICE_DOES_NOT_EXIST
;
158 if e
.raw_os_error() == Some(error_num
as i32) {
159 println!("{} is deleted.", consts
::SERVICE_NAME
);
163 sleep(Duration
::from_secs(1));
165 println!("{} is marked for deletion.", consts
::SERVICE_NAME
);
170 fn service_main(arguments
: Vec
<OsString
>) {
171 if let Err(error
) = run_service(arguments
) {
176 fn run_service(_arguments
: Vec
<OsString
>) -> Result
<(), windows_service
::Error
> {
177 let completed
: Arc
<AtomicBool
> = Arc
::new(AtomicBool
::new(false));
179 let completed_event_handler
= Arc
::clone(&completed
);
181 info!("Setuping the event handler...");
183 let event_handler
= move |control_event
| -> ServiceControlHandlerResult
{
184 match control_event
{
185 ServiceControl
::Stop
=> {
186 completed_event_handler
.store(true, Ordering
::Relaxed
);
187 // Handle stop event and return control back to the system.
188 ServiceControlHandlerResult
::NoError
190 ServiceControl
::Shutdown
=> {
191 completed_event_handler
.store(true, Ordering
::Relaxed
);
192 // Handle stop event and return control back to the system.
193 ServiceControlHandlerResult
::NoError
195 // ServiceControl::Preshutdown => {
196 // completed_event_handler.store(true, Ordering::Relaxed);
197 // ServiceControlHandlerResult::NoError
199 // ServiceControl::PowerEvent(param) => {
200 // ServiceControlHandlerResult::NotImplemented
202 // All services must accept Interrogate even if it's a no-op.
203 ServiceControl
::Interrogate
=> ServiceControlHandlerResult
::NoError
,
204 _
=> ServiceControlHandlerResult
::NotImplemented
,
208 // Register system service event handler
209 let status_handle
= service_control_handler
::register(consts
::SERVICE_NAME
, event_handler
)?
;
211 status_handle
.set_service_status(ServiceStatus
{
212 service_type
: ServiceType
::OWN_PROCESS
,
213 current_state
: ServiceState
::Running
,
214 controls_accepted
: ServiceControlAccept
::STOP
| ServiceControlAccept
::SHUTDOWN
,
215 exit_code
: ServiceExitCode
::Win32(0),
217 wait_hint
: Duration
::default(),
218 process_id
: None
, //Some(std::process::id()),
221 main_loop
::main_loop(completed
.clone());
223 status_handle
.set_service_status(ServiceStatus
{
224 service_type
: ServiceType
::OWN_PROCESS
,
225 current_state
: ServiceState
::Stopped
,
226 controls_accepted
: ServiceControlAccept
::empty(),
227 exit_code
: ServiceExitCode
::Win32(0),
229 wait_hint
: Duration
::default(),
230 process_id
: None
, //Some(std::process::id()),
233 info!("Main loop stopped: Temperature to RGB will now shut down");