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
;
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),
80 let args
: Vec
<String
> = env
::args().collect();
82 info!("Temperature to RGB");
84 if args
.contains(&"--no-service".to_string()) {
85 let completed
: Arc
<AtomicBool
> = Arc
::new(AtomicBool
::new(false));
86 main_loop
::main_loop(completed
.clone());
87 } else if args
.contains(&"--tests".to_string()) {
89 } else if args
.contains(&"--install-service".to_string()) {
90 println!("Installing service...");
92 } else if args
.contains(&"--uninstall-service".to_string()) {
93 println!("Uninstalling service...");
96 service_dispatcher
::start(consts
::SERVICE_NAME
, ffi_service_main
)?
;
102 fn install_service() -> windows_service
::Result
<()> {
103 let manager_access
= ServiceManagerAccess
::CONNECT
| ServiceManagerAccess
::CREATE_SERVICE
;
104 let service_manager
= ServiceManager
::local_computer(None
::<&str>, manager_access
)?
;
106 let service_binary_path
= std
::env
::current_exe()
108 .with_file_name("temp_2_rgb.exe");
110 println!("Installing service: {service_binary_path:?}");
112 let service_info
= ServiceInfo
{
113 name
: OsString
::from(consts
::SERVICE_NAME
),
114 display_name
: OsString
::from(consts
::SERVICE_NAME
),
115 service_type
: ServiceType
::OWN_PROCESS
,
116 start_type
: ServiceStartType
::AutoStart
,
117 error_control
: ServiceErrorControl
::Normal
,
118 executable_path
: service_binary_path
,
119 launch_arguments
: vec
![],
120 dependencies
: vec
![],
121 account_name
: None
, // run as System
122 account_password
: None
,
124 let service
= service_manager
.create_service(&service_info
, ServiceAccess
::CHANGE_CONFIG
)?
;
125 service
.set_description(
126 "A service to set the color of hardware according to the temperature of GPU and CPU",
131 fn uninstall_service() -> windows_service
::Result
<()> {
132 let manager_access
= ServiceManagerAccess
::CONNECT
;
133 let service_manager
= ServiceManager
::local_computer(None
::<&str>, manager_access
)?
;
135 let service_access
= ServiceAccess
::QUERY_STATUS
| ServiceAccess
::STOP
| ServiceAccess
::DELETE
;
136 let service
= service_manager
.open_service(consts
::SERVICE_NAME
, service_access
)?
;
138 // The service will be marked for deletion as long as this function call succeeds.
139 // However, it will not be deleted from the database until it is stopped and all open handles to it are closed.
142 // Our handle to it is not closed yet. So we can still query it.
143 if service
.query_status()?
.current_state
!= ServiceState
::Stopped
{
144 // If the service cannot be stopped, it will be deleted when the system restarts.
148 // Explicitly close our open handle to the service. This is automatically called when `service` goes out of scope.
151 // Win32 API does not give us a way to wait for service deletion.
152 // To check if the service is deleted from the database, we have to poll it ourselves.
153 let start
= time
::Instant
::now();
154 let timeout
= Duration
::from_secs(5);
155 while start
.elapsed() < timeout
{
156 if let Err(windows_service
::Error
::Winapi(e
)) =
157 service_manager
.open_service(consts
::SERVICE_NAME
, ServiceAccess
::QUERY_STATUS
)
159 let WIN32_ERROR(error_num
) = ERROR_SERVICE_DOES_NOT_EXIST
;
160 if e
.raw_os_error() == Some(error_num
as i32) {
161 println!("{} is deleted.", consts
::SERVICE_NAME
);
165 sleep(Duration
::from_secs(1));
167 println!("{} is marked for deletion.", consts
::SERVICE_NAME
);
172 fn service_main(arguments
: Vec
<OsString
>) {
173 if let Err(error
) = run_service(arguments
) {
178 fn run_service(_arguments
: Vec
<OsString
>) -> Result
<(), windows_service
::Error
> {
179 let completed
: Arc
<AtomicBool
> = Arc
::new(AtomicBool
::new(false));
181 let completed_event_handler
= Arc
::clone(&completed
);
183 info!("Setuping the event handler...");
185 let event_handler
= move |control_event
| -> ServiceControlHandlerResult
{
186 match control_event
{
187 ServiceControl
::Stop
=> {
188 completed_event_handler
.store(true, Ordering
::Relaxed
);
189 // Handle stop event and return control back to the system.
190 ServiceControlHandlerResult
::NoError
192 ServiceControl
::Shutdown
=> {
193 completed_event_handler
.store(true, Ordering
::Relaxed
);
194 // Handle stop event and return control back to the system.
195 ServiceControlHandlerResult
::NoError
197 // ServiceControl::Preshutdown => {
198 // completed_event_handler.store(true, Ordering::Relaxed);
199 // ServiceControlHandlerResult::NoError
201 // ServiceControl::PowerEvent(param) => {
202 // ServiceControlHandlerResult::NotImplemented
204 // All services must accept Interrogate even if it's a no-op.
205 ServiceControl
::Interrogate
=> ServiceControlHandlerResult
::NoError
,
206 _
=> ServiceControlHandlerResult
::NotImplemented
,
210 // Register system service event handler
211 let status_handle
= service_control_handler
::register(consts
::SERVICE_NAME
, event_handler
)?
;
213 status_handle
.set_service_status(ServiceStatus
{
214 service_type
: ServiceType
::OWN_PROCESS
,
215 current_state
: ServiceState
::Running
,
216 controls_accepted
: ServiceControlAccept
::STOP
| ServiceControlAccept
::SHUTDOWN
,
217 exit_code
: ServiceExitCode
::Win32(0),
219 wait_hint
: Duration
::default(),
220 process_id
: None
, //Some(std::process::id()),
223 main_loop
::main_loop(completed
.clone());
225 status_handle
.set_service_status(ServiceStatus
{
226 service_type
: ServiceType
::OWN_PROCESS
,
227 current_state
: ServiceState
::Stopped
,
228 controls_accepted
: ServiceControlAccept
::empty(),
229 exit_code
: ServiceExitCode
::Win32(0),
231 wait_hint
: Duration
::default(),
232 process_id
: None
, //Some(std::process::id()),
235 info!("Main loop stopped: Temperature to RGB will now shut down");