How to make existing DCOM (OPC) application run as a service? - c++

Background:
I have used developed an OPC server based on LightOPC (https://github.com/Sayen/LightOPC). This works perfectly fine as a local executable. The only problem is that I want multiple clients to connect to the same instance of the exe so they can share data. Currently, even if the DCOM settings are such that it runs as a specific user, it seems that sometimes multiple instances of the exe start. The only solution has been to set it to run as the Interactive User. However this has an issue where it won't run if no user is logged in. I believe the right way is to make it run as a windows service.
Question:
How can I take my DCOM local executable and make it into a service?
Things I tried:
Based off of this question: Create Windows service from executable I used the NSSM( the non-Sucking Service Manager ) to make my exe into a service name MYOPCSERVICE.
Then based on some other googling and examining other OPC servers that run as services, I modified the following registry key:
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\WOW6432Node\AppID{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} (where X's are my AppId) and added a "Local Service" key with the value of "MYOPCSERVICE".
After doing this, when I used DCOMCNFG, my DCOM Application shows up as Application Type = Local Service.
However, after adding this registry key, when I try to start the service or connect to the OPC server, the service fails to start with "CoRegisterClassObject() failed. Exiting..."
I found this document: https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coregisterclassobject which has the following:
As of Windows Server 2003, if a COM object application is registered
as a service, COM verifies the registration. COM makes sure the
process ID of the service, in the service control manager (SCM),
matches the process ID of the registering process. If not, COM fails
the registration. If the COM object application runs in the system
account with no registry key, COM treats the objects application
identity as Launching User.
I don't know if this is the issue, and I also don't really understand what it means. What is the "process ID" being referred to? Is this the 1-4 digit integer that all Windows processes have? Or is this the name of the service and does it have to match the name of the executable or the class or the AppId?
Update:
I have been experimenting more, and I am starting to get the feeling that it isn't possible to use NSSM to make the COM executable into a service. It seems like the exe of the service needs to be the one that calls CoRegisterClassObject. I have made a simple service based off of Simple Windows Service in c++ https://www.codeproject.com/script/Articles/ViewDownloads.aspx?aid=499465 and when I do so, I can successfully call CoRegisterClassObject with the AppId of {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} if this AppId registry key contains the string LocalService = MYOPCSERVICE.
I think Windows is enforcing a rule that only the exe registered as a service (which is nssm.exe) is allowed to call CoRegisterClassObject. However nssm spawns another exe (the local OPC executable) and it doesn't pass along this ability. Does this sound accurate? Is there any work around besides having to write all my own service handlers?

Related

My dll service disappears after restarting the system

I wrote a dll service in c++ with API functions and working properly. I implemented a ServiceMain() function as dllexport in which call RegisterServiceCtrlHandlerW() function to handle the incoming signals (e.g. stop, pause, ...) of my service.
Every thing working good and I defined all the necessary functions to run the service :
ServiceMain() is defined and RegisterServiceCtrlHandlerW() calls within to register control handler.
Set service status to SERVICE_START_PENDING then to SERVICE_RUNNING to run the service.
I implemented a thread to do stuffs as service jobs and working properly.
And I can start and stop my service.
My service is a dll not exe so I'm using svchost.exe to host it and I did below steps to register in windows registry:
1. I create a new value in registry as a group to introduce my service to svchost.exe as following :
2. I create Parameters subkey And fill a value with my dll (service file) as following :
3. Also I defined a value (ServiceMain) due to introduce my ServiceMain function to svchost.exe as start point.
So far, my service working even in logged off user BUT when I restart my computer, after logon to windows my service disappeared from Windows Service Manager. Actually it is removed from SCM database.
By the way I installed my service with 3 methods. And I'm using svchost.exe as binarypath to install the service (because svchost.exe behave as host for my dll service). For example with sc.exe program I set binarypath to svchost.exe to run my service indirectly with -k groupname as parameters.
My problem is : When I restart my system then my service disappeared (is deleted) after logging in. Please help me to solve this problem.

ColdFusion 11 console doesn't use Windows service wrapper to start app server

I have a ColdFusion11 environment with two app servers defined. The default cfusion server was created with a Windows system service wrapper to go along with it; the second app server, for some reason, was not.
The SC tool was later used to create a Windows service wrapper for the second app server; however, when the 2nd app server is controlled within the cfusion Enterprise Manager instance, it does not use the Windows Service wrapper to control it. Is there a configuration file I can amend that will instruct CF to invoke the Windows service wrapper to control this second service? This is particularly important as this 2nd server instance has a logon identity that must be used at startup, but if the server is restarted within the CF console, the identity is obviously not used.
In effect, I need to tell the cfusion enterprise manager to use the Windows service wrapper to control the 2nd app server instance, not to just control it directly. I'm assuming there is a configuration setting buried deep within the bowels of CF that would allow me to specify this.
I've tried searching the XML configuration files, looking for a non-obvious setting within them that might point to a startup configuration parameter, but so far have found nothing. Something must control how a secondary app server is managed, so I thought I'd ask here for some insight.
For the sake of anyone else who might encounter this situation, I've discovered the answer. It has nothing to do with changing the configuration of the application server itself.
When the ColdFusion11 administrator console is told to start an instance of another application server within the Enterprise Manager, it first queries the Windows Service Control database for a defined service of the exact name "ColdFusion 11 Application Server [AppServerName]" (without the brackets). If it finds such a service, CF automatically invokes the service wrapper and starts it. Absent that, a direct invocation of the CF instance commences.
The solution to the issue for an app server created without a Windows service wrapper is, when the 'sc' utility is invoked to create the service, to provide a service name that exactly matches the format above.

How can I launch a C++ native application from a Windows Service main function (the application interacts with the console)?

I'm using the _spawnl() function for launching a C++ native application from the main Service function (SvcMain), but the application never gets to run.
Is there any trick to launch applications that interacts with the user?
It runs, you just cannot see it. You have to use CreateProcessAsUser() instead of _spawnl() so the new process runs in a specific user's session, not in the service's own session. In Vista and later, services run in their own isolated sessions (Session 0 Isolation), which users cannot see or interact with. A common solution is to use WTSGetActiveConsoleSessionId() and/or WTSEnumerateSessions() to find the desired user session, then use WTSQueryUserToken() to get a token hanlde can be used with CreateEnvironmentBlock() and CreateProcessAsUser(). Also, when providing a STARTUPINFO to CreateProcessAsUser(), set the lpDesktop field to "WinSta0\\default" (the user's default desktop that they can interact with after logging in).

Windows Service not launching as local session

Am working on Creating windows service and launching an exe application through this,
from this link i have created a windows service Windows Service
But when i create a setup and deployment and then if i install, the exe which am calling from the service is launched as LOCAL SERVICE.
Still i can the xxx.exe in task manager as LOCAL SERVICE.
I cant figure even with this help : Launching GUI from windows service
How can i launch this exe as the local username which i have logged in ?
You have a number of options for creating a process that runs under a different user from the parent process:
CreateProcessAsUser or CreateProcessWithTokenW. These require you to obtain a primary token that represents a user, calling either LogonUser or DuplicateTokenEx.
CreateProcessWithLogonW which allows you to specify the user name and password as parameters.
However, if you want the process that you create to appear on the interactive desktop, you need to do quite a bit of work. This article covers the details: Launching an interactive process from Windows Service in Windows Vista and later.

How can a Windows service execute a GUI application?

I have written a Windows service that allows me to remotely run and stop applications. These applications are run using CreateProcess, and this works for me because most of them only perform backend processing. Recently, I need to run applications that present GUI to the current log in user. How do I code in C++ to allow my service to locate the currently active desktop and run the GUI on it?
Roger Lipscombe's answer, to use WTSEnumerateSessions to find the right desktop, then CreateProcessAsUser to start the application on that desktop (you pass it the handle of the desktop as part of the STARTUPINFO structure) is correct.
However, I would strongly recommend against doing this. In some environments, such as Terminal Server hosts with many active users, determining which desktop is the 'active' one isn't easy, and may not even be possible.
But most importantly, if an application will suddenly appear on a user's desktop, this may very well occur at a bad time (either because the user simply isn't expecting it, or because you're trying to launch the app when the session isn't quite initialized yet, in the process of shutting down, or whatever).
A more conventional approach would be to put a shortcut to a small client app for your service in the global startup group. This app will then launch along with every user session, and can be used start other apps (if so desired) without any juggling of user credentials, sessions and/or desktops.
Also, this shortcut can be moved/disabled by administrators as desired, which will make deployment of your application much easier, since it doesn't deviate from the standards used by other Windows apps...
The short answer is "You don't", as opening a GUI program running under another user context is a security vulnerability commonly known as a Shatter Attack.
Take a look at this MSDN article: Interactive Services. It gives some options for a service to interact with a user.
In short you have these options:
Display a dialog box in the user's session using the WTSSendMessage function.
Create a separate hidden GUI application and use the CreateProcessAsUser function to run the application within the context of the interactive user. Design the GUI application to communicate with the service through some method of interprocess communication (IPC), for example, named pipes. The service communicates with the GUI application to tell it when to display the GUI. The application communicates the results of the user interaction back to the service so that the service can take the appropriate action. Note that IPC can expose your service interfaces over the network unless you use an appropriate access control list (ACL).
If this service runs on a multiuser system, add the application to the following key so that it is run in each session: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run. If the application uses named pipes for IPC, the server can distinguish between multiple user processes by giving each pipe a unique name based on the session ID.
WTSEnumerateSessions and CreateProcessAsUser.
Several people suggested WTSEnumerateSessions and CreateProcessAsUser. I wonder why no one suggested WTSGetActiveConsoleSessionId, since you said you only want to target one logged in user.
Several people sure are right to suggest CreateProcessAsUser though. If you call plain old CreateProcess the way you said, then the application's GUI will run with your service's privileges instead of the user's privileges.
That problems Session 0 , Interactive Services ,
Windows Service Allow Service To Interact With Desktop
on Windows 7 or Windows Vista
You can read this article
http://www.codeproject.com/KB/vista-security/SubvertingVistaUAC.aspx
I try explained here it's working on Windows 7
On Win2K, XP and Win2K3 the console user is logged on in Session 0, the same session the services live in. If a service is configured as interactive, it'll be able to show the UI on the user's desktop.
However, on Vista, no user can be logged on in Session 0. Showing UI from a service there is a bit trickier. You need to enumerate the active sessions using WTSEnumerateSessions API, find the console session and create the process as that user. Of course, you need also a token or user credentials to be able to do that. You can read more details about this process here.
I think as long as you have only one user logged in, it will automatically display on that user's desktop.
Anyway, be very careful when having a service start an exe.
If the write access to the folder with the exe is not restricted, any user can replace that exe with any other program, which will then be run with sytem rights. Take for example cmd.exe (available on all windows sytems). The next time the service tries to start your exe, you get a command shell with system rights...
If you launch a GUI from your service it will show up on the currently active desktop.
But only if you adjusted the service permissions: You need to allow it to interact with the desktop.
Important Services cannot directly interact with a user as of Windows Vista. Therefore, the techniques mentioned in the section titled Using an Interactive Service should not be used in new code.
This is taken from : http://msdn.microsoft.com/en-us/library/ms683502(VS.85).aspx