Creating Windows service without Visual Studio - c

So creating a Windows service using Visual Studio is fairly trivial. My question goes a bit deeper as to what actually makes an executable installable as a service & how to write a service as a straight C application. I couldn't find a lot of references on this, but I'm presuming there has to be some interface I can implement so my .exe can be installed as a service.

Setting up your executable as a service is part of it, but realistically it's usually handled by whatever installation software you're using. You can use the command line SC tool while testing (or if you don't need an installer).
The important thing is that your program has to call StartServiceCtrlDispatcher() upon startup. This connects your service to the service control manager and sets up a ServiceMain routine which is your services main entry point.
ServiceMain (you can call it whatever you like actually, but it always seems to be ServiceMain) should then call RegisterServiceCtrlHandlerEx() to define a callback routine so that the OS can notify your service when certain events occur.
Here are some snippets from a service I wrote a few years ago:
set up as service:
SERVICE_TABLE_ENTRY ServiceStartTable[] =
{
{ "ServiceName", ServiceMain },
{ 0, 0 }
};
if (!StartServiceCtrlDispatcher(ServiceStartTable))
{
DWORD err = GetLastError();
if (err == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
return false;
}
ServiceMain:
void WINAPI ServiceMain(DWORD, LPTSTR*)
{
hServiceStatus = RegisterServiceCtrlHandlerEx("ServiceName", ServiceHandlerProc, 0);
service handler:
DWORD WINAPI ServiceHandlerProc(DWORD ControlCode, DWORD, void*, void*)
{
switch (ControlCode)
{
case SERVICE_CONTROL_INTERROGATE :
// update OS about our status
case SERVICE_CONTROL_STOP :
// shut down service
}
return 0;
}

Hope this helps:
http://support.microsoft.com/kb/251192
It would seem that you simple need to run this exe against a binary executable to register it as a service.

Basically there are some registry settings you have to set as well as some interfaces to implement.
Check out this: http://msdn.microsoft.com/en-us/library/ms685141.aspx
You are interested in the SCM (Service Control Manager).

I know I'm a bit late to the party, but I've recently had this same question, and had to struggle through the interwebs looking for answers.
I managed to find this article in MSDN that does in fact lay the groundwork. I ended up combining many of the files here into a single exe that contains all of the commands I need, and added in my own "void run()" method that loops for the entirely life of the service for my own needs.
This would be a great start to someone else with exactly this question, so for future searchers out there, check it out:
The Complete Service Sample
http://msdn.microsoft.com/en-us/library/bb540476(VS.85).aspx

Related

How to set Powered property of /org/bluez/hci0 using sd_bus_set_property?

Recently I started to develop a bluetooth app using API exposed via D-BUS. After some research, I chose to use sd-bus library to communicate with D-Bus.
Here is my code:
#include <systemd/sd-bus.h>
sd_bus* bus_;
if (sd_bus_open_system(&bus_) < 0)
{
throw std::runtime_error("sd_bus_open_system");
}
sd_bus_error sd_error;
bool powered = true;
if (sd_bus_set_property(bus_,
"org.bluez",
"/org/bluez/hci0",
"org.bluez.Adapter1",
"Powered",
&sd_error,
"b", &powered) < 0)
{
throw std::runtime_error("Bluetooth Power On");
}
The code above throws "Bluetooth Power On" and the return value of sd_bus_set_property is -22 (EINVAL). I couldn't make much sense from sd_error, but for to whom may be interested, here is the details:
name:0x7fffffffdce8 "И\277UUU"
message:0x5555555d6fbd <handler::handler(std::span<door, 18446744073709551615ul>)+191> "\220H\213E\350dH+\004%("
_need_free:1439044320
I have checked the literal strings using D-Feet app and everything seems to be right.
I've tried running as root or without root.
I've tried adding the user to bluetooth group.
What is wrong with this code?
source code of sd_bus_set_property shows that internally, it calls "Set" from "org.freedesktop.DBus.Properties". Most of the bluetooth examples I've seen, do this without using "sd_bus_set_property", but I'm curious to see how it can be done via "sd_bus_set_property".
Thanks for reading.
I built systemd from source and stepped into its functions and saw at some point it checks the error and since it's not null, returns.
sd_bus_error sd_error = SD_BUS_ERROR_NULL;
fixed the issue.

Using dispatcher to invoke on another thread - Config/Settings is not threadsafe in .Net Core 3.1

Issue:
I am trying to update the GUI from a second thread.
Unfortunately the label stays the same. At first I thought there is an issue with the dispatcher but it works fine. It appears that the configuration is not threadsafe!
Code to reproduce:
I have a Settings File which is mainly used to keep variables persistent during application relaunches:
this is the Update code:
// get the amount of tickets created for me last week
int amountOftickets = JiraInterface.DayStatisticsGenerator.GetLastWeeksTicketAmount();
config.Default.Lastweekstickets = amountOftickets; // int == 12;
// Update GUI on GUI thread
mainWindow.Dispatcher.Invoke(() =>
{
mainWindow.SetIconsAccordingtoConfig();
mainWindow.NumberTicketsCreated.Content = config.Default.Lastweekstickets.ToString(); // int == 0!!
});
Does anyone have an Idea on how to shove the running configuration from the thread who updated it to the Gui thread?
After a quick look in the documentation, it seems that you have 2 options:
You can either use the Dispatcher.Invoke to set your config.Default
on GUI thread.
It seems that .NET Core and .NET Framework support synchronized SettingsBase which is what the Configs are ( https://learn.microsoft.com/en-us/dotnet/api/system.configuration.settingsbase.synchronized?view=netcore-3.0 )
EDIT 1:
Looking into the C# Properties more, it seems that if you look in your config file in Visual Studio under:
Properties -> Config.settings -> Config.Designer.cs
During the class initialization it seems that .NET Framework, already uses Synhronized property which should make the config thread safe
private static Config defaultInstance = ((Config)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Config())));
It could be that when you created this file, Synchronized wasn't used, so your config file isn't thread safe, especially if it was created in code and not designer/properties
From Microsoft Docs on SettingsBase Synchronized:
The indexer will get and set property data in a thread-safe manner if the IsSynchronized property is set to true. A SettingsBase instance by default is not thread-safe. However, you can call Synchronized passing in a SettingsBase instance to make the SettingsBase indexer operate in a thread-safe manner.

Revert to normal user in Windows program with requireAdministrator in manifest?

I'm trying to encapsulate a number of repetitive installation tasks into a private setup program. The program is for in-house use setting up custom, single purpose systems for industrial users. I need Administrator privileges to tweak a number of Windows settings for our environment and then I need to set some current user settings for the application software packages to use.
Is it possible for a Windows program (in plain C, created with Visual Studio 2017) that uses requireAdministrator in its manifest to revert to the user that started the program when the admin privilege is no longer needed? I've seen this done in linux, but have been unable to find any examples (or even mentions) of this being done in Windows. Help? Please?
You don't.
A way given awhile back is to track down the running instance of explorer, and spawn a remote thread in it (with CreateRemoteThread) that does what you want. However CreateRemoteTherad is touchy and what if explorer isn't running?
If you know the username you can use CreateService() to create a service that runs as that user and ServiceStart() to start it but that's its own pain and now the code has to deal with no access to the desktop. Getting code running as the user on the desktop involves digging into the undocumented.
The correct design is to use two executables, the first with asInvoker that starts the second with requireAdministrator using the API call ShellExecuteEx, waits for it to finish, checks the exit code, and on success does the individual user steps.
There is no way to de-elevate a running process. You might be able to lower your rights a little bit but not all the way. Even if it was possible, you would have to hardcode the list of groups and privileges to remove/disable in your token because I don't believe there is a API to restrict a token just like UAC does.
There are many half-assed solutions out there to start a un-elevated child process:
Using the Task Scheduler
IShellDispatch2::ShellExecute in the "main" Explorer.exe instance
CreateProcessAsUser with the token from the "main" Explorer.exe instance
Bootstrapper instance elevates another instance and communicates back to parent when it needs to perform un-elevated actions
Take advantage of Explorer bug and simply execute "%windir\Explorer.exe" "c:\path\to\myapp.exe"
All of those solutions have issues related to:
Explorer might not be running (custom shell or Explorer crash)
Explorer is running elevated
Non-admin users elevate with a different administrator account with a different SID
RunAs.exe has been used and your parent process is not the same as the "main" logon session nor Explorer.exe
Final Answer
When I was finally able to install a clean Windows 10 on a spare system for testing and create a pure non-admin account to test with, the new, improved answer did not work. I added a GetUserName() call after the impersonate and wrote it to the debug log to learn that the user name was the same before and after the impersonate, even though all of the functions returned success. I can only assume that the GetShellWindow() [I also tried GetDesktopWindow(), just in case] returned a handle to an explorer/shell under the Admin context. So, now I'm using a cleaned up (to make it plain C) version of the GetConsoleUserToken() function I found here: https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/17db92be-0ebd-4b54-9e88-a122c7bc351d/strange-problem-with-wtsqueryusertoken-and-impersonateloggedonuser?forum=windowsgeneraldevelopmentissues This is working on both my development system AND on the clean Windows 10 non-admin user. The function actually searches all running processes for the explorer.exe that belongs (is attached?) to the console session and while debugging it, I did see that it find more than one explorer.exe process, but only ONE is the right one.
Thanks for all of the suggestions and comments! They gave me good ideas and put me on a path that allowed me to use better search terms to find what I needed.
To Microsoft: This seems quite unnecessarily complex to do something that should not be difficult for an administrator-level process to do.
New, Improved Answer:
Following the suggestion made by eryksun, I created the following example function that shows all of the steps my program needed to get the current user key opened. My program has requireAdministrator in the manifest, if yours does not, you might need to make changes or additions to my sample. Here is what is working perfectly for me (but apparently not on a clean machine under a non-admin account):
BOOL ChangeHkcuSettings( void )
{
BOOL bResult = FALSE; // HKCU was not accessed
HWND hwndShell;
DWORD dwThreadId;
DWORD dwProcessId;
HKEY hKeyUserHive;
HANDLE hToken;
HANDLE hProcess;
hwndShell = GetShellWindow();
dwThreadId = GetWindowThreadProcessId( hwndShell, &dwProcessId );
hProcess = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, dwProcessId );
if( NULL != hProcess )
{
if( OpenProcessToken( hProcess,
TOKEN_QUERY
| TOKEN_DUPLICATE
| TOKEN_IMPERSONATE,
&hToken ) )
{
if( ImpersonateLoggedOnUser( hToken ) )
{
if( ERROR_SUCCESS == RegOpenCurrentUser( KEY_ALL_ACCESS, &hKeyUserHive ) )
{
// ... use the user hive key to access necessary HKCU items ...
RegCloseKey( hKeyUserHive );
bResult = TRUE; // HKCU was accessed
}
RevertToSelf();
}
CloseHandle( hToken );
}
CloseHandle( hProcess );
}
return bResult;
}
Thanks again to eryksun for the suggestion!
ORIGINAL ANSWER: I think I found another way that will work for me... Instead of using HKEY_CURRENT_USER (which will be the Administrator) the admin account can open the specific user's registry key(s) under HKEY_USERS instead. I will need to find the appropriate user's SID, but my setup knows the user's name (and password, for setting auto logon), so I think this is do-able. For me, this is much easier, since all of the code already exists in a single program that formerly write EVERYTHING to HKEY_LOCAL_MACHINE, which was easy and worked great. Trying to be "correct" is much more work, perhaps more than it should be! :-(

EF6 (6.1.3/ net45) Logging feature does not seem to work

When I attempt to run the line:
MyDBContext.Database.Log = Console.Write
The compiler smiles and tells me I don't know what I am doing...
The app won't compile because of the line and the error on that line is:
Overload resolution failed because no accessible Write accepts this number of arguments.
That makes sense. 'Console.Write' returns nothing and I am setting it equal to a System.Action(Of String)
This just seems kind of half baked.
I tried numerous ways to fix it including delegates, and some of the other 'new possibilities' moving this off the Context is supposed to offer but still no dice.
What am I missing? Is it something that was changed at the last minute?
I have two large edmx files (one connects to SQL Server and the other to Oracle) in the solution and all of that is working great.
Here are my version numbers if that can help.
EntityFramework 6.0.0.0 (folder is ...\EntityFramework.6.1.3\lib\net45\EntityFramework.dll)
EntityFramework.SqlServer 6.0.0.0 (folder is ...\EntityFramework.6.1.3\lib\net45\EntityFramework.dll)
Oracle.ManagedDataAccess.EntityFramework 6.121.2.0
I have a tool I created that lets me paste the output of the L2S 'mycontext.log' into it and it then parses it and creates SSMS ready SQL with variables... it has been incredibly useful. This has been one of my favorite features of L2S.
Please help me understand why this isn't working.
Thanks in advance.
This technique works for me:
public override int SaveChanges()
{
SetIStateInfo();
#if DEBUG
Database.Log = s => Debug.WriteLine(s);
#endif
return base.SaveChanges();
}
http://blogs.msdn.com/b/mpeder/archive/2014/06/16/how-to-see-the-actual-sql-query-generated-by-entity-framework.aspx
Well, the answer was to research the Action(T) Delegate which showed me how to do it.
#If DEBUG Then
myctx.Database.Log = AddressOf Console.Write
#End If
Just needed the AddressOf and I was back in business.

Runtime debugging tips for Windows Service?

I have a Windows Service that monitors a COM port connected to a vendors hardware. This is a very busy piece of hardware that is constantly polling other devices on the wire (this is a twisted-pair RS485 "network"). My software needs to emulate X number of hardware devices on this wire, so I've got a multi-threaded thing going on with a multi-tiered state machine to keep track of where the communications protocol is at any moment.
Problem is with a Windows Service (this is my first one, BTW) is that you need some debugging to let you know if stuff is working properly. When I was first developing this state machine/multi-thread code I had a windows form with a RichTextBox that displayed the ASCII chars going back-n-forth on the line. Seems like I can't really have that GUI niceness with a service. I tried opening a form in the service via another program that sent the service messages that are received via the OnCustomCommand() handler but it didn't seem to work. I had "Allow service to interact with desktop" checked and everything. I was using the Show() and Hide() methods of my debug form.
I guess I don't need to see all of the individual characters going on the line but man that sure would be nice (I think I really need to see them :-) ). So does anyone have any crazy ideas that could help me out? I don't want to bog down the system with some IPC that isn't meant for the voluminous amount of data that is sure to come through. It will only be very short-term debugging though, just confirmation that the program, the RS485-to-USB dongle, and hardware is all working.
Use OutputDebugString to write to the debugging buffer and then use DebugView to watch it. If you're running on Windows XP or earlier, then you can use PortMon to see the raw bytes going through the serial port. The advantage over a log file is that there's very little overhead, particularly when you're not watching it. You can even run DebugView from another machine and monitor your service remotely.
I dunno if it will work for you, but I always build my services with a extra Main that build them as console app to get debug output.
Edit:
Some example:
class Worker : ServiceBase
{
#if(RELEASE)
/// <summary>
/// The Main Thread where the Service is Run.
/// </summary>
static void Main()
{
ServiceBase.Run(new Worker());
}
#endif
#if(DEBUG)
public static void Main(String[] args)
{
Worker worker = new Worker();
worker.OnStart(null);
Console.ReadLine();
worker.OnStop();
}
#endif
// Other Service code
}
You could write the output to a log file and then use another application to watch that file. This question about "tail" outlines several options for watching log files with windows.
What I usually do when working on a Windows Service is to create it so that it can be run either as a service, or as a plain old command-line application. You can easily check whether you are running as a service by checking Environment.UserInteractive. If this property is true, then you are running from the command line. If the property is false, then you are running as a service. Add this code to Program.cs, and use it where you would normally call ServiceBase.Run(servicesToRun)
/// <summary>Runs the provided service classes.</summary>
/// <param name="servicesToRun">The service classes to run.</param>
/// <param name="args">The command-line arguments to pass to the service classes.</param>
private static void RunServices(IEnumerable<ServiceBase> servicesToRun, IEnumerable args)
{
var serviceBaseType = typeof(ServiceBase);
var onStartMethod = serviceBaseType.GetMethod("OnStart", BindingFlags.Instance | BindingFlags.NonPublic);
foreach (var service in servicesToRun)
{
onStartMethod.Invoke(service, new object[] { args });
Console.WriteLine(service.ServiceName + " started.");
}
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
var onStopMethod = serviceBaseType.GetMethod("OnStop", BindingFlags.Instance | BindingFlags.NonPublic);
foreach (var service in servicesToRun)
{
onStopMethod.Invoke(service, null);
Console.WriteLine(service.ServiceName + " stopped.");
}
}
Now you can debug your service, set breakpoints, anything you want. When you run your application, you'll get a console window, appropriate for displaying console messages, and it will stay open until you hit a key.
I'm answering my own question here. I tried a couple of suggestions here but here's what I ended up doing...
I created a Windows Form application with a single Button and RichTextBox. This application constructed a NamedPipeServerStream on it's end. The Button's job was to send either "debug on" (command 128) or "debug off" (129) to the Windows Service. The initial value was "debug off". When the button was clicked, a command of 128 was sent to the Windows Service to turn debugging on. In the Windows Service this triggered an internal variable to be true, plus it connected to the Form application with a NamedPipeClientStream and started sending characters with a BinaryWriter as they were received or sent on the COM port. On the Form side, a BackgroundWorker was created to WaitForConnection() on the pipe. When it got a connection, a BinaryReader.ReadString() was used to read the data off of the pipe and shoot it to the RichTextBox.
I'm almost there. I'm breaking my pipe when I click the debug button again and a subsequent click doesn't correctly redo the pipe. All in all I'm happy with it. I can post any code if anyone is interested. Thanks for the responses!

Resources