I know how to write a dll and how to write a service and how to run a dll with rundll32, but now I want to write a dll that install as a service in windows
I don't know if that's possible or which function in dll should be exported?
How can I install and run a dll as a service?
There are a few different ways to run a DLL as a service. You can either:
Write your own .exe service and have it load your DLL as needed. This is the recommended approach.
Use Microsoft's SVCHOST.EXE to host your DLL. Have your DLL export a ServiceMain() function, add a ServiceDLL value to your service's Registry key to point at your DLL, add your service name to a new group in SVCHOST's Registry key, and then set svchost -k <GroupName> as the executable for your service. See these articles for more details:
A description of Svchost.exe
Getting Started with SVCHOST.EXE Troubleshooting
Tricks with SVCHOST.EXE
The Service Host
Note, however, that MSDN's Service Programs documentation warns against this approach:
A service program created with the type SERVICE_WIN32_SHARE_PROCESS contains code for more than one service, enabling them to share code. An example of a service program that does this is the generic service host process, Svchost.exe, which hosts internal Windows services. Note that Svchost.exe is reserved for use by the operating system and should not be used by non-Windows services. Instead, developers should implement their own service hosting programs.
Write your service as a kernel-mode driver that exports a DriverEntry() function, and add a ServiceDLL value in your service's Registry key pointing at the DLL file. See this article for more details:
Driver Development Part 1: Introduction to Drivers.
I would not recommend this approach, unless you are designing your own hardware.
There's actually no inherent reason why you can't use rundll32.exe as the host executable, though use of rundll32 isn't recommended. (To expand on that: I gather you're trying to build a DLL service as an academic exercise, which is fine. In production, you should of course use an EXE, as you've already done.)
Your main function should have this signature:
void CALLBACK MyServiceEntry(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
and should call StartServiceCtrlDispatcher, in the same way as the main() or WinMain() function in a conventional service.
You would then install the service to use the following command line:
rundll32 MyService.dll,MyServiceEntry
For an academic exercise, it would also be acceptable to use svchost.exe as described in Remy's answer, but it is even more important not to use that in a production context: the use of rundll32 by third parties is supported but not recommended; the use of svchost by third parties is explicitly unsupported.
Related
I am attempting to create a small C++ Visual Studio Forms (via CPPCLR_WinformsProjekt) application that is essentially a browser but it also starts a local Tomcat 8.5 server with a WAR file in its web apps folder and redirects you to the localhost page. I am working on Windows.
My question precisely is - what is the best way to start the Tomcat server through C++ libraries?
Edit: The way I started solving this is by simply having the tomcat folder with the WAR file zipped within the Visual Studio project. On execution, the file gets unzipped, and I am thinking of having a system(*start tomcat command*).
NB: I know I can start Tomcat through the cmd but I need to get it working via C++.
[I am assuming you are under Windows, but on Unix-es similar ways are available.]
In a C++ program you can execute all commands that a shell can, so the easiest way to start Tomcat would be to use CreateProcess to execute catalina.bat (or startup.bat). The is also the most easily configurable way: a user can adapt setenv.bat to its needs.
Of course, if you want to omit the *.bat files you can:
either instantiate a JVM using java.exe with the appropriate parameters: you need at least bin/bootstrap.jar in the system classpath (and usually bin/tomcat-juli.jar) and call the main method of org.apache.catalina.startup.Bootstrap with a parameter of start.
or instantiate a JVM using jvm.dll through the Invocation API in a similar way as it is done by procrun.
I don't believe these methods give you any advantage over the *.bat scripts. To stop a modern Tomcat just send the kill signal.
Edit: If you plan to start only one specific web application a full-fledged Tomcat might be overkill. You might instead:
either use Tomcat Embedded, which boils up to writing on class and calling its main method instead of Boostrap#start. The advantage is, you just need to distribute a bunch of jar files and your WAR and you don't need a traditional Tomcat installation directory structure,
or user use Spring Boot.
I'm making a cross-platform background process. For Windows, I have a XML configuration file, which has a service name, load type etc. On windows, program during execution just parses this file and creates the service, easy. Linux, on other hand, has this *.service config file, which doesn't allow me to use my XML config, so I have to configure my daemon inside *.service.
So the question is, how to make *.service use my XML config to load preferences for daemon? I know this is possible, but have no idea how to do this.
I suspect you use the well-known technique of registering your Windows Service executable as a service, when you run it as a regular process. That is simply a matter of calling the right Service Control Manager API's. You know you're not a service if StartServiceCtrlDispatcher fails.
The same idea works for Linux. If you start your program normally, you register yourself as a service following the documented procedure. This procedure is of course different from Windows; it involves you dynamically writing a *.service file and registering it.
Not all API's in an OS need to be function calls, an API can also take the shape of a file format.
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?
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.
How can I hibernate a Windows machine that runs Windows 7 or 8 over my LAN from another PC?
Is there a WinAPI function for that? Or do I have to send special magic packets or something like this?
All I know is that PsShutdown.exe is able to do it (allegedly. I haven't tried it).
I don't want to use third party libraries and I also don't want to run a service on the computer that is supposed to get hibernated. I want to use the existing mechanism.
I'd also like to know if I need to change specific settings on the target computer.
I'm not sure if that's important, but shutdown /s /m \\ComputerName did not work on my target PC.
The TechNet document Restart or Shut Down a Remote Computer and Document the Reason describes the requirements to use the shutdown.exe command against a remote computer.
In order to use this feature, the Remote Registry service must be enabled on the remote computer.
Access to the Remote Registry or membership in the Administrators group on the remote computer is the minimum required to complete this procedure
To the best of my knowledge, the only way to remotely hibernate a machine is to use the same method that psshutdown does: copy an executable to the remote machine and install it as a system service.
The OpenSCManager API allows you to specify a target computer, and you can use the handle it returns to call CreateService and then StartService. The service can delete itself once it has done its work.