Location of a Windows service *not* in my project - c#

If I right-click and choose Properties on a service (like, say, Plug and Play) in the Services dialog, I get several pieces of information, including "Path to executable". For Plug and Play (in Vista) this is:
C:\Windows\system32\svchost.exe -k DcomLaunch
Is there some way I can get this same piece of information using .NET code if I know the service name (and/or the display name)?
(I can't use GetExecutingAssembly() because I'm not running the service from my project.)

Another option, without the interop, would be a WMI lookup (or registry - bit hacky!).
Here's a quick example, based on this code:
private static string GetServiceImagePathWMI(string serviceDisplayName)
{
string query = string.Format("SELECT PathName FROM Win32_Service WHERE DisplayName = '{0}'", serviceDisplayName);
using (ManagementObjectSearcher search = new ManagementObjectSearcher(query))
{
foreach(ManagementObject service in search.Get())
{
return service["PathName"].ToString();
}
}
return string.Empty;
}

This information is in the QUERY_SERVICE_CONFIG structure. You will need to use P/Invoke to get it out.
The basic process is:
Call OpenSCManager to get a handle to the services managed.
Call OpenService to get a handle to the service.
Call QueryServiceConfig to get the QUERY_SERVICE_CONFIG structure.

There's always the WMI class Win32_Service as described here, specifically the PathName.
This works:
ManagementClass mc = new ManagementClass("Win32_Service");
foreach(ManagementObject mo in mc.GetInstances())
{
if(mo.GetPropertyValue("Name").ToString() == "<Short name of your service>")
{
return mo.GetPropertyValue("PathName").ToString().Trim('"');
}
}
If you have any issue related to Reference then add a reference of System.Management in your project.

Related

Programmatically check if a windows service is running c#

I am writing an app to check to see if certain software is installed. One of my cases im looking for a service. I know the full path of the service. i.e. "c:\some folder\MyService.exe" I want to check to see if the service is installed and running. I have tried process.GetProcessbyName, but running into issues with 64 bit vs 32 bit processes. I've also tried ManagementObject but i keep getting invalid object path. Is it possible to get a service knowing only the path to the executable?
I know only the name and path of the executable. There may be more than one version of the executable as well, each with a different service name, which i do not have.
Here is how you can check if the service is installed or not , also get the status of the service
public static string CheckService(string ServiceName)
{
//check service
var services = ServiceController.GetServices();
string serviceStatu = string.Empty;
bool isServiceExist = false;
foreach (var s in services)
{
if (s.ServiceName == ServiceName)
{
serviceStatu = "Service installed , current status: " + s.Status;
isServiceExist = true;
}
}
if (!isServiceExist)
{
serviceStatu= "Service is not installed";
}
return serviceStatu;
}
Console.WriteLine(CheckService("Service name"));
you need to add System.ServiceProcess to the project reference
Try looking into the ServiceController / Management object for the executable path. Then based the executable path determine whether the service is running.
How to get executable path : [1] [2] [3]
Borrowed from an answer above
ManagementClass mc = new ManagementClass("Win32_Service");
foreach(ManagementObject mo in mc.GetInstances())
{
if(mo.GetPropertyValue("PathName").ToString().Trim('"') == "<your executable path>")
{
return mo.GetPropertyValue("Name").ToString(); // or return true;
}
}
I haven't tested this, and a comment suggested PathName may return command line arguments as well, so you may need to write another method to separate the path from the arguments (I'm assuming it'll just be a split on the string), and pass PathName to it in If statement..

Retrieve formatted performance data from WMI

I'm writing a WMI Provider and I've managed to retrieve all info on the Computer System and Hardware Classes but cannot get data I want from the Performance Counter Classes. (Win32 Classes)
Looking through the MSDN documentation and using examples they provide, I've come up with a shell script that should return all properties of the Win32_PerfFormattedData abstract base class.
Script:
$osClass = New-Object System.Management.ManagementClass Win32_PerfFormattedData
$osClass.Options.UseAmendedQualifiers = $true
# Get the Properties in the class
$properties = $osClass.Properties
"This class has {0} properties as follows:" -f $properties.count
# display the Property name, description, type, qualifiers and instance values
foreach ($property in $properties) {
"Property Name: {0}" -f $property.Name
"Description: {0}" -f $($property.Qualifiers["Description"].Value)
"Type: {0}" -f $property.Type
"-------"
}
(referenced from here)
The problem is that I'm only retrieving the properties from it's base class Win32_Perf
EDIT
After doing more research, I found this on MSDN:
The WMI formatted class name for a counter object is of the form "Win32_PerfFormattedData_service_name_object_name"
I am trying to get the service_name's that are in the Win32_PerfFormattedData and the object_name's within those services.
I'm unsure whether getting the properties is how I want to go about this now but I cannot find any documentation to get the services. Are they the same thing? And, if not, how can I get the info I require? (service_name's & object_name's)
I've also tried this in some C# code and get the same result:
ManagementClass processClass = new ManagementClass();
processClass.Path = new ManagementPath("Win32_PerfFormattedData");
PropertyDataCollection properties = processClass.Properties;
Console.WriteLine("\nProperties:");
foreach (PropertyData property in properties)
{
Console.WriteLine(property.Name);
}
And I tried retrieving the methods to check if that is what I wanted but nothing is returned:
Console.WriteLine("Methods: ");
foreach (MethodData method in methods)
{
Console.WriteLine(method.Name);
}
EDIT 2
Is there another way to retrieve this data? I've looked all through the MSDN documentation on the WMI and I think to get the information I want, I have to access that class (Win32_PerfFormattedData). Sorts of values I want to retrieve:
CPU
RAM
Drives (SSD/HDD)
Processes
OS
GPU
I've retrieved a few classes that will give basic information about some of these but will not provide up to date data on, for example, the temperature of each logical processor. I've managed to get 1 service from the class Win32_PerfFormattedData_PerfOS_Processor which provides the load % of each logical processor but that class must holds other services which I need.
Win32_PerfFormattedData_* classes are located under the "root\cimv2" namespace. To enumerate these classes (and get the service names) you run the following WQL query against that namespace:
SELECT * FROM meta_class WHERE __Class LIKE "Win32_PerfFormattedData%"
Actually you can omit the namespace (at least with ManagementObjectSearcher) in which case the search occurs everywhere. Here is how to search through WMI with C#:
void SearchWmi()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM meta_class WHERE __Class LIKE \"Win32_PerfFormattedData%\"");
foreach (ManagementClass wmiClass in searcher.Get())
{
Console.WriteLine(wmiClass["__CLASS"].ToString());
}
}
You need to add referece to System.Management as well as the corresponding using directive.
You could find performance data about the:
CPU: Win32_PerfFormattedData_Processor
RAM: Win32_PerfFormattedData_Memory
OS: Win32_PerfFormattedData_System
Drives: Win32_PerfFormattedData_PerfDisk_*
Processes: Win32_PerfFormattedData_PerfProc_*
I have no idea about the GPU. Most likely it is driver dependent.
There are numerous WMI explorer tools out there with a UI and all the good stuff. Have you tried some? I use the "WMI Explorer 2.0"
You can download it from here

Rackspace Cloud Files Get Objects In Container C#

I have been looking at the documentation, testing examples and getting familiar with the Rackspace Cloud Files API. I got the basic code down, got the API key, got a username, the basic stuff. Now one thing confuses me, this problem is something that appears to be not well documented.
So what I am trying to do is to get all the objects, including folders and files in a container. I have tried this example:
IEnumerable<ContainerObject> containerObjects = cloudFilesProvider.ListObjects("storage",null,null,null,null,null,false,ci);
foreach(ContainerObject containerObject in containerObjects)
{
MessageBox.Show(containerObject.ToString());
}
This doesn't return the result I am looking for, it seems to not return anything.
I am using OpenStack provided by running this in the NuGet console:
Install-Package Rackspace.
I am trying to create a file backup program for me and my family.
A common problem is not specifying the region. When your Rackspace cloud account's default region is not the same region as where your container lives, then you must specify region, otherwise you won't see any results listed. Which is quite misleading...
Here is a sample console application which prints the contents of all your containers (and their objects) in a particular region. Change "DFW" to the name of the region where your container lives. If you aren't sure which region has your container, log into the Rackspace cloud control panel and go to "Storage > Files" and note the region drop down at the top right.
using System;
using net.openstack.Core.Domain;
using net.openstack.Providers.Rackspace;
namespace ListCloudFiles
{
class Program
{
static void Main()
{
var region = "DFW";
var identity = new CloudIdentity
{
Username = "username",
APIKey = "apikey"
};
var cloudFilesProvider = new CloudFilesProvider(identity);
foreach (Container container in cloudFilesProvider.ListContainers(region: region))
{
Console.WriteLine(container.Name);
foreach (ContainerObject obj in cloudFilesProvider.ListObjects(container.Name, region: region))
{
Console.WriteLine(" * " + obj.Name);
}
}
Console.ReadLine();
}
}
}
If you are using the Openstack.NET API the reference documentation indicates that CloudFilesProvider has a method called ListObjects.
The docs say that this method:
Lists the objects in a container
The method returns IEnumerable<ContainerObject> and a quick glance at the parameter list looks to me like you can pass just a container name in the first parameter and null for the rest -- I'll leave it to you to figure out your use-case needs.
The following doc page describes the method in detail and includes a complete C# example.
http://www.openstacknetsdk.org/docs/html/M_net_openstack_Providers_Rackspace_CloudFilesProvider_ListObjects.htm

Configure existing service to run at system startup

I'm looking for a C# version of the following command:
sc config "someServiceName" start=auto
I've found a lot of information about configuring a service to start automatically as you install it, but I'm having trouble finding out how to do the same for an existing service.
Right now, I've resorted to shelling it out, but if there's a way to use .NET APIs, I'd much rather do that.
This should do the trick:
var serviceName = "<your service name here>";
string objPath = string.Format("Win32_Service.Name='{0}'", serviceName);
using (var service = new ManagementObject(new ManagementPath(objPath)))
{
var result = (int)service.InvokeMethod("ChangeStartMode", new object[] {"Automatic"});
}
You'll need to add a reference to the System.Management assembly, as well as import the namespace System.Management.
Note that your program must elevated (running as an Administrator) for this to work, and there is no way around that. For other possible values for ChangeStartMode, you can refer to MSDN.
The result variable will be a numeric value that indicates the result. For example, 0 for Success. Refer the the previously linked MSDN article for all of the possible return values.
var serviceName = "<your service name here>";
string objPath = string.Format("Win32_Service.Name='{0}'", serviceName);
using (var service = new ManagementObject(new ManagementPath(objPath)))
{
service.InvokeMethod("ChangeStartMode", new object[] {"Automatic"});
}
You'll need to add a reference to the System.Management assembly, as well as import the namespace System.Management.

C# Waiting for other services to start

I'm writing a Windows service that relies on other services, how should I wait for the other services to start?
Thanks
In addition to what other answers have alredy pointed out, if one of those services is SQL Server you will need to ensure that the specific database is available as well as the SQL Server service itself.
I use a function similar to the following:
public class DbStatus
{
public static bool DbOnline()
{
const int MaxRetries = 10;
int count = 0;
while (count < MaxRetries)
{
try
{
// Just access the database. any cheap query is ok since we don't care about the result.
return true;
}
catch (Exception ex)
{
Thread.Sleep(30000);
count++;
}
}
return false;
}
}
I think you shoud this line
installer.ServicesDependedOn = new string [] { "DependenceService" };
like this:
using (ServiceProcessInstaller processInstaller = new ServiceProcessInstaller())
{
processInstaller.Account = ServiceAccount.LocalSystem;
processInstaller.Username = null;
processInstaller.Password = null;
using (ServiceInstaller installer = new ServiceInstaller())
{
installer.DisplayName = "yourservice.";
installer.StartType = ServiceStartMode.Automatic;
installer.ServiceName = "YourService";
installer.ServicesDependedOn = new string [] { "DependenceService" };
this.Installers.Add(processInstaller);
this.Installers.Add(installer);
}
}
good luck
You need to specify the dependencies. You can do this in your Installer class.
Further clarification
You should be using an Installer class as a Custom Action in your setup project to install your service. If you aren't, post a comment and I'll update this answer with steps on how to do that.
Inside the designer for your Installer class you should see two components: a serviceInstaller and a serviceProcessInstaller. I don't remember which off of the top of my head, but one of these has a property that allows you to specify a multiline string that lists the service names of your service's dependencies.
As others here said, you should use the ServiceInstaller Class, but you don't need a full blowned setup project.
You can do a quick instalation using InstallUtil.exe, a command-line utility that comes with the .NET Framework.
Do you have control over the other services?
If yes have them start you, if not I guess you have to start anyway and monitor yourself what is going on.
It is possible to register yourself with WMI to get notifyied when other processes are started - there is a question about it.
In your service project, add a project installer as described here. One of the properties of your ProjectInstaller will be ServicesDependedOn. When you add services to that array of strings (you can do that through the IDE), they will be required to be started before your service will start. If they are not started the SCM will try and start them.

Categories

Resources