How may I get the description of a Windows Service like below?
I tried by using the Windows Registry, but the majority of Services appear to not have a description, or the description value is stored in a dll - so this seems to be the wrong approach.
Example:
Windows Time Service (W32Time), the description in the registry is shown as
#%SystemRoot%\system32\w32time.dll,-201
Yet the actual description as seen in Services.msc is:
Maintains date and time synchronization on all clients and servers in
the network. If this service is stopped, date and time synchronization
will be unavailable. If this service is disabled, any services that
explicitly depend on it will fail to start.
-
I have been searching on the MSDN website and came across this:
SERVICE_DESCRIPTION structure
lpDescription
The description of the service. If this member is NULL, the
description remains unchanged. If this value is an empty string (""),
the current description is deleted.
The service description must not exceed the size of a registry value
of type REG_SZ.
This member can specify a localized string using the following format:
#[path]dllname,-strID
The string with identifier strID is loaded from dllname; the path is
optional. For more information, see RegLoadMUIString....
-
pszOutBuf [out, optional]
A pointer to a buffer that receives the string.
Strings of the following form receive special handling:
#[path]\dllname,-strID
The string with identifier strID is loaded from dllname; the path is
optional. If the pszDirectory parameter is not NULL, the directory is
prepended to the path specified in the registry data. Note that
dllname can contain environment variables to be expanded.
Which I think would suggest why viewing the Registry showed the W32Time description as #%SystemRoot%\system32\w32time.dll,-201
If I understand correctly I need to read the dll name in memory and retrieve the strID where the Service description is stored?
This is all confusing for me, I would be grateful if someone could help.
All I need is to get the description of a Service, it surely cannot be as complicated as this can it?
Thanks :)
In all versions of Delphi, the the JEDI JCL contains everything you need to get friendly descriptions of services, and anything else to do with the Service Control APIs.
THe class TJclSCManager in the unit JclSvcCtrl.pas contains a property Services, which includes name and description of each service registered, and lets you also do things like start, stop, enable, and disable services too.
Update: The other answer here from ldsandon points out that the Delphi RTL apparently includes this already in XE2, in the unit WinSvc. See answer below about QueryServiceConfig2. Thanks ldsandon for pointing this fact out.
Call QueryServiceConfig2 (you will find also a C example there).
Whatever you need to do with services should be done through the Service Manager API. Registry data should be treated as "private" to the OS.
Using WMI is another way to use the Windows API directly, for example with the help of the (free) API code generator
WMI Delphi Code Creator
The WMI Delphi Code Creator tool allows you to generate Object Pascal
and C++ code to access the WMI (Windows Management Instrumentation)
classes, events and methods.
Are you using Unicode? The remarks for the RegLoadMUIString function say that only the Unicode version is supported.
The RegLoadMUIString function is supported only for Unicode. Although
both Unicode (W) and ANSI (A) versions of this function are declared,
the RegLoadMUIStringA function returns ERROR_CALL_NOT_IMPLEMENTED.
Applications should explicitly call RegLoadMUIStringW or specify
Unicode as the character set in platform invoke (PInvoke) calls.
Have you tried calling RegLoadMUIStringW directly?
You also can check the GLibWMI library. Free (and source included) library for work with WMI. Include a component named TServiceInfo.
Also is included a demo for work wirh services.
With this component you can access at Win32_Service Class; You can check the properties and structure here.
Regards
Related
Interpreted languages such as PHP allow a separate file, often called config.php, to contain string constants such as server names. This facilitates deployment, as the config file is simply not uploaded when the code is updated - the server names, e.g. for REST transactions, are typically different in the deployment environment.
In Dart, since it is compiled, this approach does not work. If there are server name constants which are referred to in the HTML via {{ }}, it seems the code must be recompiled before deployment.
Is there a way to specify string constants in such a way to avoid this recompilation requirement?
There are a couple of options I can think of:
One trick is to put configuration in a map keyed by hostname. At runtime, look up the configuration from the map, using window.location as a key. This will allow configuration to be baked into the Dart source, yet still allow different values to be specified for different environments.
If you want to be able to change your configuration after compilation, you can embed it as JSON within the HTML source, or load it via an HTTP request. (This isn't using a constant as asked, however, by definition it's not possible to change a constant after compile time)
Ok, so short answer is "You can't" - at the moment. But the Dart team are aware of this limitation, and are discussing it in dartlang as per the comment above.
I have Datasnap Server (DBX) that scans at startup a directory, loads the BPLs (containing the DSServerModules) and then registers them in order make them available from remote.
It all works fine for functions and procedures that use primitive types (such as integer, string and so on) but from client I cannot see any method that has "structured" variables.
For example I tried to add a function that returns a TJSONValue (as I saw on an example) but the method is not visible from client.
Strangely enough, the same function is available (and works) if the DSServerModule is added statically to the project).
Any Guess?
I didn't attach any code because it is part of a quite big project.
If need I'll provide a small example.
Cheers,
Mirko
I build four different "types" of applications with my framework:
1) Windows Services
2) Normal Applications
3) Service Applications (a normal application with the functionality of a Windows Service but with a local GUI console and an ability to auto-upgrade)
4) Remote GUI Consoles
Now I can detect, through code, if the application is a Windows Service. But currently to detect between the others I use DEFINES that need to be added to the project file. I would like find an alternate way that does not rely on DEFINES if possible. My initial thoughts are to use the Comments field of the project's version info.
Any ideas?
Edit: I am after a general technique that works regardless of how I "type" my applications. At the moment I use DEFINES from the project configuration, which works, but makes the code slightly messier than using "if" code switches, and because it is stored in the .dproj file, can be hidden from view.
Solution: From David's suggestion I initially used the conditional defines (and any other information such as whether the application was running as a Windows Service) to map all applications to one of the 4 application types, stored in a globally accessible object. Unless linking files that made no sense to include with a particular application type, I replaced almost all of my conditional compilation flags with code, which significantly improved the readability of the code. There are a few other "tweaks" I implemented, but that was the basic implementation.
Depending how you are using the Application global variable you can detect if you application is a Service, a VCL or a console App checking the type of this global variable. for consoles app you can use the System.IsConsole variable.
function ApplicationIsService(Component:TComponent):Boolean;
begin
Result:=Component.ClassName='TServiceApplication';
end;
function ApplicationIsVcl(Component:TComponent):Boolean;
begin
Result:=Component.ClassName='TApplication';
end;
and you can use like this
if ApplicationIsVcl(Application) then
//do something
else
if ApplicationIsService(Application) then
//do something else
else
if IsConsole then
//do another thing
It sounds like each project has a single app type so it seems logical to differentiate in either the .dpr file or the .dproj files.
Call a function to set a private global variable from the .dpr file.
Or use a conditional defined in the .dproj as you do now.
If it was me I'd stick to a conditional but use the trick of converting it into a Delphi enum with a shared helper method to make it read better.
Can I get a little code example to use DDE as a server? I know how to use the client part, but can't figure setting up my app to act as a server and receive data.
Have a look in your Delphi installation for a folder called DDEDemo. It's a DDE project that Delphi use to ship with (I'm not 100% sure it's still included, but have a look). The demo includes a DDE client and server.
Edit - Try this link for some example code.
It is so easy to use the DDE server that you don't even need sample code. You can do it just at designtime inside the Delphi form designer:
To create a server that sends out data:
Drop a TDDEServerConv and
TDDEServerItem on your form or data
module.
Connect the server item to
the server conversation (set
DDEServerItem1.ServerConv=DdeServerConv1
using object inspector, there is a
drop down list, but double clicking
it is enough).
Set the DDEServerItem.Text value to some valid text value (ie 'A')
To receive data, you might want to have macros that are executed by the DDE client that pass data to the server. For this you use the DdeServerConv.OnExecuteMacro event. Try dumping the parameter Msg:TStrings to a memo like this:
Memo1.Lines.Assign(Msg);
Now save and run your project.
To test it in excel type in:
=Project1|DdeServerConv1!DdeServerItem1
The excel dde client syntax parts are Application name followed by vertical bar, conversation name, followed by exclamation mark, then item name.
And you will see the value (A, or whatever you put into the Text property in the item) appear in Excel.
That's a working single item DDE server without any code written by you.
I generally find that I create the conversations and the items at runtime, instead of at designtime, in a real world scenario that is more useful for me.
For older (non unicode) Delphi versions there is also a full featured commercial product called Django that helps a lot with DDE work.
I think also you might be looking for information on how to write a "DDE Poke" command handler on the delphi side. I don't have a demo for that. I tried it, and the obvious things didn' quite work right for me (the item on your server has an OnPoke event, I wrote a simple client, called PokeData, and it didn't work).
I am using someone else's library that provides its own scripting host instance, it appears.
This lib provides me with functions to define the type of scripting language such as "jscript" and "vbscript", and I can supply it with script code and have that executed, with passing arguments in and back. So, basically, it works.
However, when I try to access the "WScript" object, I get an exception saying that this keyword is undefined.
The developer, not knowing much about this either (he only made this lib for me because I do not want to deal with Windows SDKs right now), told me that he is using "IScriptControl" for this.
Oh, and the lib also provides flags to allow "only safe subset" and "allow UI", which I set to false and true, respectively.
Does that ring a bell with anyone? Do a user of IScriptControl have to take extra steps in order to make a WScript object available? Or, can he use IScriptControl in a way that this is supplied automatically, just as when running the same script from wscript.exe?
Basically, all I need is the WScript.CreateObject function in order to access another app's API via COM.
I don't know why WScript is not known, but I suspect it is because the script host doesn't provide it. Maybe only wscript.exe does this.
If you are using Javascript, to create an object you can use new ActiveXObject(). If you are using VBScript, you can just use CreateObject.
See this article for some background.