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
);
30 mod wrapper_winring0
{
31 #![allow(warnings, unused)]
32 include!(concat!(env!("OUT_DIR"), "/ols_api.rs"));
35 #![allow(warnings, unused)]
36 include!(concat!(env!("OUT_DIR"), "/intel_arc.rs"));
40 mod corsair_lighting_pro
;
41 mod lian_li_sl_infinity
;
47 mod corsair_vengeance
;
50 // mod roccat; Disabled.
56 fn main() -> Result
<()> {
57 let is_debug
= cfg!(debug_assertions
);
59 flexi_logger
::Logger
::try_with_str(if is_debug
{ "debug" } else { "info" })?
61 flexi_logger
::FileSpec
::default()
62 .directory(dirs
::config_dir().unwrap().join(consts
::SERVICE_NAME
))
63 .basename(consts
::SERVICE_NAME
),
65 .duplicate_to_stdout(flexi_logger
::Duplicate
::All
)
67 flexi_logger
::default_format
69 flexi_logger
::detailed_format
72 flexi_logger
::Criterion
::Size(1024 * 1024),
73 flexi_logger
::Naming
::Timestamps
,
74 flexi_logger
::Cleanup
::KeepLogFiles(10),
81 let args
: Vec
<String
> = env
::args().collect();
83 info!("Temperature to RGB");
85 if args
.contains(&"--no-service".to_string()) {
86 let completed
: Arc
<AtomicBool
> = Arc
::new(AtomicBool
::new(false));
87 main_loop
::main_loop(completed
.clone());
88 } else if args
.contains(&"--tests".to_string()) {
90 } else if args
.contains(&"--install-service".to_string()) {
91 println!("Installing service...");
93 } else if args
.contains(&"--uninstall-service".to_string()) {
94 println!("Uninstalling service...");
97 service_dispatcher
::start(consts
::SERVICE_NAME
, ffi_service_main
)?
;
103 fn install_service() -> windows_service
::Result
<()> {
104 let manager_access
= ServiceManagerAccess
::CONNECT
| ServiceManagerAccess
::CREATE_SERVICE
;
105 let service_manager
= ServiceManager
::local_computer(None
::<&str>, manager_access
)?
;
107 let service_binary_path
= std
::env
::current_exe()
109 .with_file_name("temp_2_rgb.exe");
111 println!("Installing service: {service_binary_path:?}");
113 let service_info
= ServiceInfo
{
114 name
: OsString
::from(consts
::SERVICE_NAME
),
115 display_name
: OsString
::from(consts
::SERVICE_NAME
),
116 service_type
: ServiceType
::OWN_PROCESS
,
117 start_type
: ServiceStartType
::AutoStart
,
118 error_control
: ServiceErrorControl
::Normal
,
119 executable_path
: service_binary_path
,
120 launch_arguments
: vec
![],
121 dependencies
: vec
![],
122 account_name
: None
, // run as System
123 account_password
: None
,
125 let service
= service_manager
.create_service(&service_info
, ServiceAccess
::CHANGE_CONFIG
)?
;
126 service
.set_description(
127 "A service to set the color of hardware according to the temperature of GPU and CPU",
132 fn uninstall_service() -> windows_service
::Result
<()> {
133 let manager_access
= ServiceManagerAccess
::CONNECT
;
134 let service_manager
= ServiceManager
::local_computer(None
::<&str>, manager_access
)?
;
136 let service_access
= ServiceAccess
::QUERY_STATUS
| ServiceAccess
::STOP
| ServiceAccess
::DELETE
;
137 let service
= service_manager
.open_service(consts
::SERVICE_NAME
, service_access
)?
;
139 // The service will be marked for deletion as long as this function call succeeds.
140 // However, it will not be deleted from the database until it is stopped and all open handles to it are closed.
143 // Our handle to it is not closed yet. So we can still query it.
144 if service
.query_status()?
.current_state
!= ServiceState
::Stopped
{
145 // If the service cannot be stopped, it will be deleted when the system restarts.
149 // Explicitly close our open handle to the service. This is automatically called when `service` goes out of scope.
152 // Win32 API does not give us a way to wait for service deletion.
153 // To check if the service is deleted from the database, we have to poll it ourselves.
154 let start
= time
::Instant
::now();
155 let timeout
= Duration
::from_secs(5);
156 while start
.elapsed() < timeout
{
157 if let Err(windows_service
::Error
::Winapi(e
)) =
158 service_manager
.open_service(consts
::SERVICE_NAME
, ServiceAccess
::QUERY_STATUS
)
160 let WIN32_ERROR(error_num
) = ERROR_SERVICE_DOES_NOT_EXIST
;
161 if e
.raw_os_error() == Some(error_num
as i32) {
162 println!("{} is deleted.", consts
::SERVICE_NAME
);
166 sleep(Duration
::from_secs(1));
168 println!("{} is marked for deletion.", consts
::SERVICE_NAME
);
173 fn service_main(arguments
: Vec
<OsString
>) {
174 if let Err(error
) = run_service(arguments
) {
179 fn run_service(_arguments
: Vec
<OsString
>) -> Result
<(), windows_service
::Error
> {
180 let completed
: Arc
<AtomicBool
> = Arc
::new(AtomicBool
::new(false));
182 let completed_event_handler
= Arc
::clone(&completed
);
184 info!("Setuping the event handler...");
186 let event_handler
= move |control_event
| -> ServiceControlHandlerResult
{
187 match control_event
{
188 ServiceControl
::Stop
=> {
189 completed_event_handler
.store(true, Ordering
::Relaxed
);
190 // Handle stop event and return control back to the system.
191 ServiceControlHandlerResult
::NoError
193 ServiceControl
::Shutdown
=> {
194 completed_event_handler
.store(true, Ordering
::Relaxed
);
195 // Handle stop event and return control back to the system.
196 ServiceControlHandlerResult
::NoError
198 // ServiceControl::Preshutdown => {
199 // completed_event_handler.store(true, Ordering::Relaxed);
200 // ServiceControlHandlerResult::NoError
202 // ServiceControl::PowerEvent(param) => {
203 // ServiceControlHandlerResult::NotImplemented
205 // All services must accept Interrogate even if it's a no-op.
206 ServiceControl
::Interrogate
=> ServiceControlHandlerResult
::NoError
,
207 _
=> ServiceControlHandlerResult
::NotImplemented
,
211 // Register system service event handler
212 let status_handle
= service_control_handler
::register(consts
::SERVICE_NAME
, event_handler
)?
;
214 status_handle
.set_service_status(ServiceStatus
{
215 service_type
: ServiceType
::OWN_PROCESS
,
216 current_state
: ServiceState
::Running
,
217 controls_accepted
: ServiceControlAccept
::STOP
| ServiceControlAccept
::SHUTDOWN
,
218 exit_code
: ServiceExitCode
::Win32(0),
220 wait_hint
: Duration
::default(),
221 process_id
: None
, //Some(std::process::id()),
224 main_loop
::main_loop(completed
.clone());
226 status_handle
.set_service_status(ServiceStatus
{
227 service_type
: ServiceType
::OWN_PROCESS
,
228 current_state
: ServiceState
::Stopped
,
229 controls_accepted
: ServiceControlAccept
::empty(),
230 exit_code
: ServiceExitCode
::Win32(0),
232 wait_hint
: Duration
::default(),
233 process_id
: None
, //Some(std::process::id()),
236 info!("Main loop stopped: Temperature to RGB will now shut down");