Graham Wideman, Visio MVP wrote:
Quote
> Anyone seen a sample of an NT Service that exposes an Automation
> interface that can be connected to via GetActiveObject?
> The idea is to have a desktop app able to communicate with the
> service. The advice everywhere is "just use some form of interprocess
> communication" -- where none of those methods are exactly well-beaten
> paths.
I just had nightmares with this. I did it a bit differently though -
instead of registering a single object in the ROT, I allowed each client to
create it's own object, with all of the objects accessing the same
underlying data structure in the service.
Also, my service had to work in a particular way:
1. I didn't want the client application to be able to start the service
with DCOM. That's because the clients would be in 300 separate locations
talking to a central server - and if I'd deliberatly stopped the service
for maintenance I didn't want a client somewhere trying to start it.
2. Because the clients had to be installed through a simple batch file, I
couldn't call use DCOMCNFG - so I had to call CoInitializeSecurity on both
the client and server.
Here's what I did:
I wrote a TServiceAutoObjectFactory class derived from TAutoObjectFactory,
and overrode UpdateRegistry to do the following things. (UpdateRegistry is
called (indirectly) by SvcMgr.Application.Initialize, and because it's
called after CoInitialize, but before any other com stuff, it's a good
place to call things like CoInitializeSecurity).
1. If the command line parameter was -Install or -Uninstall, the service
was simply being installed, and no COM stuff should be done. Simply call
Application.Run (so that the SvcMgr installs the service), and halt.
2. If the command line parameter was -RegServer or -Server , call
CoInitializeSecurity (see below) and install the com objects by calling
inherited UpdateRegistry, and RegisterAsService to that DCOM. You'd need
to call it like this on the client computers - which don't need the service,
but still need the registry entries so that CoYourControl.CreateRemote
works.
3. If there are no command line parameters, the .exe is probably being
started by the service control manager. It should call
CoInitializeSecurity, inherited UpdateRegistry amnd RegisterAsService.
When you call CoInitializeSecurity on the server, you need to pass a
security decriptor containing the owner and group SIDS for the current
process or thread's token. It's a bit tricky so let me know if you want
some sample code.
On the client end, simply call CoInitialize and CoInitializeSecurity in the
main form's OnCreate method - like this:
CoInitialize (nil);
OleCheck (CoInitializeSecurity(nil, -1, Nil, nil, RPC_C_AUTHN_LEVEL_NONE,
RPC_C_IMP_LEVEL_IMPERSONATE, nil, Integer (EOAC_NONE), nil));
It worked fine in W2K and XP Pro :
* If you try to start the client when the service isn't running, it says
'class not registered' - because it's not!
* If you start the client when the service is running, from whatever
remote computer, (or the local one) it connects!
*** HOWEVER *** I couldn't get the wretched thing working on NT4! If the
service was running and I ran the client, DCOM would start another instance
of the .exe running - despite the AppID registry stuff, LocalService value,
all being correctly set.. The only way I could get it to work was to have
DCOM start the service. Then the client(s) would connect fine - all to the
same instance of the .EXE - but it wasn't how I wanted it to work. I
spent days trawling through registry keys in HKEY_CLASSES_ROOT. I spent
days crawling through an MFC ATL service that did the same thing at startup
(and which works!) I spent days examining all the DCOM security issues,
using DCOMCNFG to totally relax security, etc. etc. etc.
In the end - with the deadline looming I rewrote the data transport layer
to use named pipes instead of DCOM.
Colin
e-mail :co...@wilsonc.demon.co.uk
web: http://www.wilsonc.demon.co.uk/delphi.htm
Posted with XanaNews