📜 ⬆️ ⬇️

Implementing Services in MSWin (Part Two)

In addition to the habratopics about writing services, I will mention one more possibility - launching applications on behalf of the current terminal user.

This is convenient if you choose the option of managing the service and its interaction with the user on the principle that the service is not interactive and is running on behalf of the Local System, and the application must be running on behalf of the user.

First, there is a mechanism in the service management system that allows you to receive a message about connecting a new terminal user and disconnecting the current one.
Secondly, you can run any application on behalf of the current terminal user.
')
Personally, it is more convenient for me when both the service and the user application are located in the same executable file, but this is rather a personal whim, and no one limits the programmer to this.

Starting from Windows XP / Windows 2003 Server , the following SERVICE_CONTROL_SESSIONCHANGE message may appear in the service event handler, indicating that the user has changed the session (disconnecting from the session, creating a new one, etc.) Unfortunately, this is not provided in Windows 2000 , therefore (if this version is listed in the target list) it should be borne in mind that even the definition of this message in windows.h is framed by checking the _WIN32_WINNT define.

As a result, the message handler is supplemented with approximately the following code:
Copy Source | Copy HTML #if (_WIN32_WINNT > 0x0500 ) case SERVICE_CONTROL_SESSIONCHANGE: if (dwEventType == WTS_SESSION_LOGON) { system_logger_t::instance()->trace_info(L "service accept SESSION LOGON signal" ); if (!run_gui()) system_logger_t::instance()->trace_info(L "[ERROR] creating GUI window for service failed" ); } break ; #endif
  1. Copy Source | Copy HTML #if (_WIN32_WINNT > 0x0500 ) case SERVICE_CONTROL_SESSIONCHANGE: if (dwEventType == WTS_SESSION_LOGON) { system_logger_t::instance()->trace_info(L "service accept SESSION LOGON signal" ); if (!run_gui()) system_logger_t::instance()->trace_info(L "[ERROR] creating GUI window for service failed" ); } break ; #endif
  2. Copy Source | Copy HTML #if (_WIN32_WINNT > 0x0500 ) case SERVICE_CONTROL_SESSIONCHANGE: if (dwEventType == WTS_SESSION_LOGON) { system_logger_t::instance()->trace_info(L "service accept SESSION LOGON signal" ); if (!run_gui()) system_logger_t::instance()->trace_info(L "[ERROR] creating GUI window for service failed" ); } break ; #endif
  3. Copy Source | Copy HTML #if (_WIN32_WINNT > 0x0500 ) case SERVICE_CONTROL_SESSIONCHANGE: if (dwEventType == WTS_SESSION_LOGON) { system_logger_t::instance()->trace_info(L "service accept SESSION LOGON signal" ); if (!run_gui()) system_logger_t::instance()->trace_info(L "[ERROR] creating GUI window for service failed" ); } break ; #endif
  4. Copy Source | Copy HTML #if (_WIN32_WINNT > 0x0500 ) case SERVICE_CONTROL_SESSIONCHANGE: if (dwEventType == WTS_SESSION_LOGON) { system_logger_t::instance()->trace_info(L "service accept SESSION LOGON signal" ); if (!run_gui()) system_logger_t::instance()->trace_info(L "[ERROR] creating GUI window for service failed" ); } break ; #endif
  5. Copy Source | Copy HTML #if (_WIN32_WINNT > 0x0500 ) case SERVICE_CONTROL_SESSIONCHANGE: if (dwEventType == WTS_SESSION_LOGON) { system_logger_t::instance()->trace_info(L "service accept SESSION LOGON signal" ); if (!run_gui()) system_logger_t::instance()->trace_info(L "[ERROR] creating GUI window for service failed" ); } break ; #endif
  6. Copy Source | Copy HTML #if (_WIN32_WINNT > 0x0500 ) case SERVICE_CONTROL_SESSIONCHANGE: if (dwEventType == WTS_SESSION_LOGON) { system_logger_t::instance()->trace_info(L "service accept SESSION LOGON signal" ); if (!run_gui()) system_logger_t::instance()->trace_info(L "[ERROR] creating GUI window for service failed" ); } break ; #endif
  7. Copy Source | Copy HTML #if (_WIN32_WINNT > 0x0500 ) case SERVICE_CONTROL_SESSIONCHANGE: if (dwEventType == WTS_SESSION_LOGON) { system_logger_t::instance()->trace_info(L "service accept SESSION LOGON signal" ); if (!run_gui()) system_logger_t::instance()->trace_info(L "[ERROR] creating GUI window for service failed" ); } break ; #endif
  8. Copy Source | Copy HTML #if (_WIN32_WINNT > 0x0500 ) case SERVICE_CONTROL_SESSIONCHANGE: if (dwEventType == WTS_SESSION_LOGON) { system_logger_t::instance()->trace_info(L "service accept SESSION LOGON signal" ); if (!run_gui()) system_logger_t::instance()->trace_info(L "[ERROR] creating GUI window for service failed" ); } break ; #endif
  9. Copy Source | Copy HTML #if (_WIN32_WINNT > 0x0500 ) case SERVICE_CONTROL_SESSIONCHANGE: if (dwEventType == WTS_SESSION_LOGON) { system_logger_t::instance()->trace_info(L "service accept SESSION LOGON signal" ); if (!run_gui()) system_logger_t::instance()->trace_info(L "[ERROR] creating GUI window for service failed" ); } break ; #endif
  10. Copy Source | Copy HTML #if (_WIN32_WINNT > 0x0500 ) case SERVICE_CONTROL_SESSIONCHANGE: if (dwEventType == WTS_SESSION_LOGON) { system_logger_t::instance()->trace_info(L "service accept SESSION LOGON signal" ); if (!run_gui()) system_logger_t::instance()->trace_info(L "[ERROR] creating GUI window for service failed" ); } break ; #endif


Actually launching an executable file of the service on behalf of the current terminal user, but with the gui key:
Copy Source | Copy HTML
  1. / * <br/> * /
  2. bool service_t :: run_gui ()
  3. {
  4. HANDLE l_hToken = NULL;
  5. STARTUPINFOW l_startInfo;
  6. PROCESS_INFORMATION l_processInfo;
  7. ULONG l_SID = - 1 ;
  8. memset (& l_startInfo, 0x00 , sizeof (STARTUPINFOW));
  9. memset (& l_processInfo, 0x00 , sizeof (PROCESS_INFORMATION));
  10. l_startInfo.cb = sizeof (STARTUPINFOW);
  11. l_SID = static_cast < ULONG > (WTSGetActiveConsoleSessionId ());
  12. if (l_SID! = - 1 )
  13. {
  14. if (WTSQueryUserToken (l_SID, & l_hToken)! = FALSE)
  15. {
  16. std :: wstringstream l_wss;
  17. l_wss << get_path () << get_name ();
  18. if (CreateProcessAsUserW (
  19. l_hToken
  20. l_wss.str (). c_str (),
  21. L "/ gui" ,
  22. Null
  23. Null
  24. FALSE,
  25. CREATE_DEFAULT_ERROR_MODE,
  26. Null
  27. Null
  28. & l_startInfo,
  29. & l_processInfo)! = FALSE)
  30. {
  31. system_logger_t :: instance () -> trace_info (
  32. L "creating GUI window for service succeeded"
  33. );
  34. return true ;
  35. }
  36. }
  37. }
  38. return false ;
  39. }
  40. // ------------------------------------------------ ---------------------------


It only remains to recall that the application should be able to run only one copy if the service processes only WTS_SESSION_LOGON , and for this it is enough to create a named mutex whose name starts with L “Local \\” . This will create a mutex within the current user session. If the application instance must exist in one copy in principle, then we create a mutex “name” which starts with L “Global \\” and do not forget that in this case the application should have time to delete the mutex even in case of emergency completion.

Source: https://habr.com/ru/post/91497/


All Articles