Service not created correctly under windows 11 but any older version.
-
I'm using the following function for years and used it under any Version of Windows since XP. It creates a systemtask with the start type set to "auto", just like it is expected to do. But under windows 11, the start type of the installed service always defaults to "manual" when being created. Any help solving this is very much appreciated. Am using VS2022 using toolset 1.41_XP (for reasons) (already added some extra check for win 11... but still the start type defaults to manual in the newly created task)
static int manage_service(int action) {
SC_HANDLE hSCM = NULL, hService = NULL;
SERVICE_DESCRIPTION descr = { server_name };
char path[PATH_MAX + 20]; // Path to executable plus magic argument
int success = 1;GetModuleFileName(NULL, path, sizeof(path)); strncat(path, " ", sizeof(path)); strncat(path, service\_magic\_argument, sizeof(path)); if (IsRunAsAdministrator()) { if ((hSCM = OpenSCManager(NULL, NULL, action == ID\_INSTALL\_SERVICE ? GENERIC\_WRITE : GENERIC\_READ)) == NULL) { success = 0; show\_error(); } else if (action == ID\_INSTALL\_SERVICE) { hService = CreateService(hSCM, service\_name, service\_name, SERVICE\_ALL\_ACCESS, SERVICE\_WIN32\_OWN\_PROCESS, SERVICE\_AUTO\_START, SERVICE\_ERROR\_NORMAL, path, NULL, NULL, NULL, NULL, NULL); if (hService) { ChangeServiceConfig(hService, SERVICE\_NO\_CHANGE, SERVICE\_AUTO\_START, SERVICE\_NO\_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); ChangeServiceConfig2(hService, SERVICE\_CONFIG\_DESCRIPTION, &descr); // Check Windows version OSVERSIONINFOEX osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); osvi.dwMajorVersion = 11; // Windows 11 if (GetVersionEx((OSVERSIONINFO\*)&osvi)) { // Set start type to AUTO\_START for Windows 11 ChangeServiceConfig(hService, SERVICE\_NO\_CHANGE, SERVICE\_AUTO\_START, SERVICE\_NO\_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); } } else { show\_error(); } } else if (action == ID\_REMOVE\_SERVICE) { if ((hService = OpenService(hSCM, service\_name, DELETE)) == NULL || !DeleteService(hService)) { show\_error(); } } else if ((hService = OpenService(hSCM, service\_name, SERVICE\_QUERY\_STATUS)) == NULL) { success = 0; } CloseServiceHandle(hService); CloseServiceHandle(hSCM); } else { if (action == ID\_INSTALL\_SERVICE) { RunServiceAsAdmin('I', path, service\_name); } else if (action == ID\_REMOVE\_
-
I'm using the following function for years and used it under any Version of Windows since XP. It creates a systemtask with the start type set to "auto", just like it is expected to do. But under windows 11, the start type of the installed service always defaults to "manual" when being created. Any help solving this is very much appreciated. Am using VS2022 using toolset 1.41_XP (for reasons) (already added some extra check for win 11... but still the start type defaults to manual in the newly created task)
static int manage_service(int action) {
SC_HANDLE hSCM = NULL, hService = NULL;
SERVICE_DESCRIPTION descr = { server_name };
char path[PATH_MAX + 20]; // Path to executable plus magic argument
int success = 1;GetModuleFileName(NULL, path, sizeof(path)); strncat(path, " ", sizeof(path)); strncat(path, service\_magic\_argument, sizeof(path)); if (IsRunAsAdministrator()) { if ((hSCM = OpenSCManager(NULL, NULL, action == ID\_INSTALL\_SERVICE ? GENERIC\_WRITE : GENERIC\_READ)) == NULL) { success = 0; show\_error(); } else if (action == ID\_INSTALL\_SERVICE) { hService = CreateService(hSCM, service\_name, service\_name, SERVICE\_ALL\_ACCESS, SERVICE\_WIN32\_OWN\_PROCESS, SERVICE\_AUTO\_START, SERVICE\_ERROR\_NORMAL, path, NULL, NULL, NULL, NULL, NULL); if (hService) { ChangeServiceConfig(hService, SERVICE\_NO\_CHANGE, SERVICE\_AUTO\_START, SERVICE\_NO\_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); ChangeServiceConfig2(hService, SERVICE\_CONFIG\_DESCRIPTION, &descr); // Check Windows version OSVERSIONINFOEX osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); osvi.dwMajorVersion = 11; // Windows 11 if (GetVersionEx((OSVERSIONINFO\*)&osvi)) { // Set start type to AUTO\_START for Windows 11 ChangeServiceConfig(hService, SERVICE\_NO\_CHANGE, SERVICE\_AUTO\_START, SERVICE\_NO\_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); } } else { show\_error(); } } else if (action == ID\_REMOVE\_SERVICE) { if ((hService = OpenService(hSCM, service\_name, DELETE)) == NULL || !DeleteService(hService)) { show\_error(); } } else if ((hService = OpenService(hSCM, service\_name, SERVICE\_QUERY\_STATUS)) == NULL) { success = 0; } CloseServiceHandle(hService); CloseServiceHandle(hSCM); } else { if (action == ID\_INSTALL\_SERVICE) { RunServiceAsAdmin('I', path, service\_name); } else if (action == ID\_REMOVE\_
Hmmm, Your code looks good to me. Although it would be nice if you captured the return values of
ChangeServiceConfig
. I would recommend debugging this by checking the Event logs. Look for event ID 7040 in the "Service Control Manager" log source. You might need to enable auditing. Also, try temporarily adding a Windows Defender exclusion on the service file path if your executable is unsigned/untrusted. I'm wondering if Defender is blocking the change. -
Hmmm, Your code looks good to me. Although it would be nice if you captured the return values of
ChangeServiceConfig
. I would recommend debugging this by checking the Event logs. Look for event ID 7040 in the "Service Control Manager" log source. You might need to enable auditing. Also, try temporarily adding a Windows Defender exclusion on the service file path if your executable is unsigned/untrusted. I'm wondering if Defender is blocking the change.Just found out somethhing more.... As soon as I invoke the service creation function from within the program, I do get the normal service controll manager asking for elevated rights in order to create the service, what is exactly what happen. But then the service gets created with start type set to "manual". If I do start the program manually "as Administrator" and then invoke the service creation function, the service gets created correctly with start type "auto". So there probably might be a problem with my elevation of rights!?... will check this. Strange though, that it works fin under any Windows version since XP... just not windows 11... Here is the code to start with elevated rights:
BOOL IsRunAsAdministrator()
{
BOOL isRunAsAdmin = FALSE;
DWORD dwError = ERROR_SUCCESS;
PSID pAdministratorsGroup = NULL;// Allocate and initialize a SID of the administrators group. SID\_IDENTIFIER\_AUTHORITY NtAuthority = SECURITY\_NT\_AUTHORITY; if (!AllocateAndInitializeSid( &NtAuthority, 2, SECURITY\_BUILTIN\_DOMAIN\_RID, DOMAIN\_ALIAS\_RID\_ADMINS, 0, 0, 0, 0, 0, 0, &pAdministratorsGroup)) { goto Cleanup; } // Determine whether the SID of administrators group is enabled in // the primary access token of the process. if (!CheckTokenMembership(NULL, pAdministratorsGroup, &isRunAsAdmin)) { goto Cleanup; }
Cleanup:
// Centralized cleanup for all allocated resources.
if (pAdministratorsGroup)
{
FreeSid(pAdministratorsGroup);
pAdministratorsGroup = NULL;
}return isRunAsAdmin;
}
void RunServiceAsAdmin(char ch, const char *program, const char* name)
{
// Launch itself as admin
char param[255];
SHELLEXECUTEINFO sei = { sizeof(sei) };memset(param, 0 , sizeof(param)); sei.lpVerb = "runas"; sei.lpFile = "sc.exe"; sei.hwnd = NULL; sei.nShow = SW\_NORMAL; if(ch == 'I') { sprintf(param, "create \\"%s\\" binPath= \\"%s\\" DisplayName=\\"%s\\"", name, program, name); } else { sprintf(param, "delete \\"%s\\"", name); } sei.lpParameters = param; if (!ShellExecuteEx(&sei)) { show\_error(); }
}
-
Just found out somethhing more.... As soon as I invoke the service creation function from within the program, I do get the normal service controll manager asking for elevated rights in order to create the service, what is exactly what happen. But then the service gets created with start type set to "manual". If I do start the program manually "as Administrator" and then invoke the service creation function, the service gets created correctly with start type "auto". So there probably might be a problem with my elevation of rights!?... will check this. Strange though, that it works fin under any Windows version since XP... just not windows 11... Here is the code to start with elevated rights:
BOOL IsRunAsAdministrator()
{
BOOL isRunAsAdmin = FALSE;
DWORD dwError = ERROR_SUCCESS;
PSID pAdministratorsGroup = NULL;// Allocate and initialize a SID of the administrators group. SID\_IDENTIFIER\_AUTHORITY NtAuthority = SECURITY\_NT\_AUTHORITY; if (!AllocateAndInitializeSid( &NtAuthority, 2, SECURITY\_BUILTIN\_DOMAIN\_RID, DOMAIN\_ALIAS\_RID\_ADMINS, 0, 0, 0, 0, 0, 0, &pAdministratorsGroup)) { goto Cleanup; } // Determine whether the SID of administrators group is enabled in // the primary access token of the process. if (!CheckTokenMembership(NULL, pAdministratorsGroup, &isRunAsAdmin)) { goto Cleanup; }
Cleanup:
// Centralized cleanup for all allocated resources.
if (pAdministratorsGroup)
{
FreeSid(pAdministratorsGroup);
pAdministratorsGroup = NULL;
}return isRunAsAdmin;
}
void RunServiceAsAdmin(char ch, const char *program, const char* name)
{
// Launch itself as admin
char param[255];
SHELLEXECUTEINFO sei = { sizeof(sei) };memset(param, 0 , sizeof(param)); sei.lpVerb = "runas"; sei.lpFile = "sc.exe"; sei.hwnd = NULL; sei.nShow = SW\_NORMAL; if(ch == 'I') { sprintf(param, "create \\"%s\\" binPath= \\"%s\\" DisplayName=\\"%s\\"", name, program, name); } else { sprintf(param, "delete \\"%s\\"", name); } sei.lpParameters = param; if (!ShellExecuteEx(&sei)) { show\_error(); }
}
-
Well, You appear to have a function that is checking if you are running as Administrator. Could you show me the content of that function?
Here is some more complete code:
BOOL IsRunAsAdministrator()
{
BOOL isRunAsAdmin = FALSE;
DWORD dwError = ERROR_SUCCESS;
PSID pAdministratorsGroup = NULL;// Allocate and initialize a SID of the administrators group. SID\_IDENTIFIER\_AUTHORITY NtAuthority = SECURITY\_NT\_AUTHORITY; if (!AllocateAndInitializeSid( &NtAuthority, 2, SECURITY\_BUILTIN\_DOMAIN\_RID, DOMAIN\_ALIAS\_RID\_ADMINS, 0, 0, 0, 0, 0, 0, &pAdministratorsGroup)) { goto Cleanup; } // Determine whether the SID of administrators group is enabled in // the primary access token of the process. if (!CheckTokenMembership(NULL, pAdministratorsGroup, &isRunAsAdmin)) { goto Cleanup; }
Cleanup:
// Centralized cleanup for all allocated resources.
if (pAdministratorsGroup)
{
FreeSid(pAdministratorsGroup);
pAdministratorsGroup = NULL;
}return isRunAsAdmin;
}
void RunServiceAsAdmin(char ch, const char *program, const char* name)
{
// Launch itself as admin
char param[255];
SHELLEXECUTEINFO sei = { sizeof(sei) };memset(param, 0 , sizeof(param)); sei.lpVerb = "runas"; sei.lpFile = "sc.exe"; sei.hwnd = NULL; sei.nShow = SW\_NORMAL; if(ch == 'I') { sprintf(param, "create \\"%s\\" binPath= \\"%s\\" DisplayName=\\"%s\\"", name, program, name); } else { sprintf(param, "delete \\"%s\\"", name); } sei.lpParameters = param; if (!ShellExecuteEx(&sei)) { show\_error(); }
}
static int manage_service(int action) {
SC_HANDLE hSCM = NULL, hService = NULL;
SERVICE_DESCRIPTION descr = { server_name };
char path[PATH_MAX + 20]; // Path to executable plus magic argument
int success = 1;GetModuleFileName(NULL, path, sizeof(path)); strncat(path, " ", sizeof(path)); strncat(path, service\_magic\_argument, sizeof(path)); if (IsRunAsAdministrator()) { if ((hSCM = OpenSCManager(NULL, NULL, action == ID\_INSTALL\_SERVICE ? GENERIC\_WRITE : GENERIC\_READ)) == NULL) { success = 0; show\_error(); } else if (action == ID\_INSTALL\_SERVICE) { hService = CreateService(hSCM, service\_name, service\_name, SERVICE\_ALL\_ACCESS, SERVICE\_WIN32\_OWN\_PROCESS, SERVICE\_AUTO\_START, SERVICE\_ERROR\_NORMAL, path, NULL, NULL, NULL, NULL, NULL); if (hService) { ChangeServiceConfig(hService, SERVICE\_NO\_CHANGE, SERVICE\_AUTO\_START, SERVICE\_NO\_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); ChangeServic
-
Here is some more complete code:
BOOL IsRunAsAdministrator()
{
BOOL isRunAsAdmin = FALSE;
DWORD dwError = ERROR_SUCCESS;
PSID pAdministratorsGroup = NULL;// Allocate and initialize a SID of the administrators group. SID\_IDENTIFIER\_AUTHORITY NtAuthority = SECURITY\_NT\_AUTHORITY; if (!AllocateAndInitializeSid( &NtAuthority, 2, SECURITY\_BUILTIN\_DOMAIN\_RID, DOMAIN\_ALIAS\_RID\_ADMINS, 0, 0, 0, 0, 0, 0, &pAdministratorsGroup)) { goto Cleanup; } // Determine whether the SID of administrators group is enabled in // the primary access token of the process. if (!CheckTokenMembership(NULL, pAdministratorsGroup, &isRunAsAdmin)) { goto Cleanup; }
Cleanup:
// Centralized cleanup for all allocated resources.
if (pAdministratorsGroup)
{
FreeSid(pAdministratorsGroup);
pAdministratorsGroup = NULL;
}return isRunAsAdmin;
}
void RunServiceAsAdmin(char ch, const char *program, const char* name)
{
// Launch itself as admin
char param[255];
SHELLEXECUTEINFO sei = { sizeof(sei) };memset(param, 0 , sizeof(param)); sei.lpVerb = "runas"; sei.lpFile = "sc.exe"; sei.hwnd = NULL; sei.nShow = SW\_NORMAL; if(ch == 'I') { sprintf(param, "create \\"%s\\" binPath= \\"%s\\" DisplayName=\\"%s\\"", name, program, name); } else { sprintf(param, "delete \\"%s\\"", name); } sei.lpParameters = param; if (!ShellExecuteEx(&sei)) { show\_error(); }
}
static int manage_service(int action) {
SC_HANDLE hSCM = NULL, hService = NULL;
SERVICE_DESCRIPTION descr = { server_name };
char path[PATH_MAX + 20]; // Path to executable plus magic argument
int success = 1;GetModuleFileName(NULL, path, sizeof(path)); strncat(path, " ", sizeof(path)); strncat(path, service\_magic\_argument, sizeof(path)); if (IsRunAsAdministrator()) { if ((hSCM = OpenSCManager(NULL, NULL, action == ID\_INSTALL\_SERVICE ? GENERIC\_WRITE : GENERIC\_READ)) == NULL) { success = 0; show\_error(); } else if (action == ID\_INSTALL\_SERVICE) { hService = CreateService(hSCM, service\_name, service\_name, SERVICE\_ALL\_ACCESS, SERVICE\_WIN32\_OWN\_PROCESS, SERVICE\_AUTO\_START, SERVICE\_ERROR\_NORMAL, path, NULL, NULL, NULL, NULL, NULL); if (hService) { ChangeServiceConfig(hService, SERVICE\_NO\_CHANGE, SERVICE\_AUTO\_START, SERVICE\_NO\_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); ChangeServic
-
I do see a bug.
SHELLEXECUTEINFO sei = { sizeof(sei) };
You should zero that struct out. Then set the
cbSize
member. Not sure if this is causing your problem though. I'm on my TV right now so reviewing on my couch. But don't see any other issues.Thanks for the tip! :) Am also currently looking into a way to use the ControlService utility via CreateProcess to install the service, instead of calling CreateService directly... But not sure if I can pull that off correctly...
-
Thanks for the tip! :) Am also currently looking into a way to use the ControlService utility via CreateProcess to install the service, instead of calling CreateService directly... But not sure if I can pull that off correctly...
-
I just noticed in your original post:
Rick R. 2023 wrote:
Am using VS2022 using toolset 1.41_XP
Do you get the same behavior if you compile for Windows 11?
Starting to suspect the toolset, too. Have to fix a bunch of linker problems caused by my old and pretty messy project settings, in order to test with a newer version... might take a while.
-
Starting to suspect the toolset, too. Have to fix a bunch of linker problems caused by my old and pretty messy project settings, in order to test with a newer version... might take a while.