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 // Important: when starting as a service, the directory where the log and config files
57 // are put is 'C:\Windows\System32\config\systemprofile\AppData\Roaming\Temp2RGB'.
58 fn main() -> Result
<()> {
59 let is_debug
= cfg!(debug_assertions
);
61 flexi_logger
::Logger
::try_with_str(if is_debug
{ "debug" } else { "info" })?
63 flexi_logger
::FileSpec
::default()
64 .directory(dirs
::config_dir().unwrap().join(consts
::SERVICE_NAME
))
65 .basename(consts
::SERVICE_NAME
),
67 .duplicate_to_stdout(flexi_logger
::Duplicate
::All
)
69 flexi_logger
::default_format
71 flexi_logger
::detailed_format
74 flexi_logger
::Criterion
::Size(1024 * 1024),
75 flexi_logger
::Naming
::Timestamps
,
76 flexi_logger
::Cleanup
::KeepLogFiles(10),
83 let args
: Vec
<String
> = env
::args().collect();
85 info!("Temperature to RGB");
87 if args
.contains(&"--no-service".to_string()) {
88 let completed
: Arc
<AtomicBool
> = Arc
::new(AtomicBool
::new(false));
89 main_loop
::main_loop(completed
.clone());
90 } else if args
.contains(&"--tests".to_string()) {
92 } else if args
.contains(&"--install-service".to_string()) {
93 println!("Installing service...");
95 } else if args
.contains(&"--uninstall-service".to_string()) {
96 println!("Uninstalling service...");
99 service_dispatcher
::start(consts
::SERVICE_NAME
, ffi_service_main
)?
;
105 fn install_service() -> windows_service
::Result
<()> {
106 let manager_access
= ServiceManagerAccess
::CONNECT
| ServiceManagerAccess
::CREATE_SERVICE
;
107 let service_manager
= ServiceManager
::local_computer(None
::<&str>, manager_access
)?
;
109 let service_binary_path
= std
::env
::current_exe()
111 .with_file_name("temp_2_rgb.exe");
113 println!("Installing service: {service_binary_path:?}");
115 let service_info
= ServiceInfo
{
116 name
: OsString
::from(consts
::SERVICE_NAME
),
117 display_name
: OsString
::from(consts
::SERVICE_NAME
),
118 service_type
: ServiceType
::OWN_PROCESS
,
119 start_type
: ServiceStartType
::AutoStart
,
120 error_control
: ServiceErrorControl
::Normal
,
121 executable_path
: service_binary_path
,
122 launch_arguments
: vec
![],
123 dependencies
: vec
![],
124 account_name
: None
, // run as System
125 account_password
: None
,
127 let service
= service_manager
.create_service(&service_info
, ServiceAccess
::CHANGE_CONFIG
)?
;
128 service
.set_description(
129 "A service to set the color of hardware according to the temperature of GPU and CPU",
134 fn uninstall_service() -> windows_service
::Result
<()> {
135 let manager_access
= ServiceManagerAccess
::CONNECT
;
136 let service_manager
= ServiceManager
::local_computer(None
::<&str>, manager_access
)?
;
138 let service_access
= ServiceAccess
::QUERY_STATUS
| ServiceAccess
::STOP
| ServiceAccess
::DELETE
;
139 let service
= service_manager
.open_service(consts
::SERVICE_NAME
, service_access
)?
;
141 // The service will be marked for deletion as long as this function call succeeds.
142 // However, it will not be deleted from the database until it is stopped and all open handles to it are closed.
145 // Our handle to it is not closed yet. So we can still query it.
146 if service
.query_status()?
.current_state
!= ServiceState
::Stopped
{
147 // If the service cannot be stopped, it will be deleted when the system restarts.
151 // Explicitly close our open handle to the service. This is automatically called when `service` goes out of scope.
154 // Win32 API does not give us a way to wait for service deletion.
155 // To check if the service is deleted from the database, we have to poll it ourselves.
156 let start
= time
::Instant
::now();
157 let timeout
= Duration
::from_secs(5);
158 while start
.elapsed() < timeout
{
159 if let Err(windows_service
::Error
::Winapi(e
)) =
160 service_manager
.open_service(consts
::SERVICE_NAME
, ServiceAccess
::QUERY_STATUS
)
162 let WIN32_ERROR(error_num
) = ERROR_SERVICE_DOES_NOT_EXIST
;
163 if e
.raw_os_error() == Some(error_num
as i32) {
164 println!("{} is deleted.", consts
::SERVICE_NAME
);
168 sleep(Duration
::from_secs(1));
170 println!("{} is marked for deletion.", consts
::SERVICE_NAME
);
175 fn service_main(arguments
: Vec
<OsString
>) {
176 if let Err(error
) = run_service(arguments
) {
181 fn run_service(_arguments
: Vec
<OsString
>) -> Result
<(), windows_service
::Error
> {
182 let completed
: Arc
<AtomicBool
> = Arc
::new(AtomicBool
::new(false));
184 let completed_event_handler
= Arc
::clone(&completed
);
186 info!("Setuping the event handler...");
188 let event_handler
= move |control_event
| -> ServiceControlHandlerResult
{
189 match control_event
{
190 ServiceControl
::Stop
=> {
191 completed_event_handler
.store(true, Ordering
::Relaxed
);
192 // Handle stop event and return control back to the system.
193 ServiceControlHandlerResult
::NoError
195 ServiceControl
::Shutdown
=> {
196 completed_event_handler
.store(true, Ordering
::Relaxed
);
197 // Handle stop event and return control back to the system.
198 ServiceControlHandlerResult
::NoError
200 // ServiceControl::Preshutdown => {
201 // completed_event_handler.store(true, Ordering::Relaxed);
202 // ServiceControlHandlerResult::NoError
204 // ServiceControl::PowerEvent(param) => {
205 // ServiceControlHandlerResult::NotImplemented
207 // All services must accept Interrogate even if it's a no-op.
208 ServiceControl
::Interrogate
=> ServiceControlHandlerResult
::NoError
,
209 _
=> ServiceControlHandlerResult
::NotImplemented
,
213 // Register system service event handler
214 let status_handle
= service_control_handler
::register(consts
::SERVICE_NAME
, event_handler
)?
;
216 status_handle
.set_service_status(ServiceStatus
{
217 service_type
: ServiceType
::OWN_PROCESS
,
218 current_state
: ServiceState
::Running
,
219 controls_accepted
: ServiceControlAccept
::STOP
| ServiceControlAccept
::SHUTDOWN
,
220 exit_code
: ServiceExitCode
::Win32(0),
222 wait_hint
: Duration
::default(),
223 process_id
: None
, //Some(std::process::id()),
226 main_loop
::main_loop(completed
.clone());
228 status_handle
.set_service_status(ServiceStatus
{
229 service_type
: ServiceType
::OWN_PROCESS
,
230 current_state
: ServiceState
::Stopped
,
231 controls_accepted
: ServiceControlAccept
::empty(),
232 exit_code
: ServiceExitCode
::Win32(0),
234 wait_hint
: Duration
::default(),
235 process_id
: None
, //Some(std::process::id()),
238 info!("Main loop stopped: Temperature to RGB will now shut down");