I wrote a service which will run as the local system. The service has a COM object. I'd like to create and access that object from any local user's account.
Of course, it fails during a call to CoGetClassObject()
in order to get the class factory. It fails with (debugger watch):
hr 0x80080005 : Server execution failed HRESULT
The ATL framework is registering the class factories on startup. I've stepped through the code and verified they are being registered with CLSCTX_LOCAL_SERVER
and REGCLS_MULTIPLEUSE
.
The service is running. I can't find any useful examples to solve this problem. I am thinking it is probably just a registry setting or possibly the way I call CoInitializeSecurity()
.
I call CoInitializeSecurity() like this:
class CCppServiceModule : public ATL::CAtlServiceModuleT< CCppServiceModule, IDS_SERVICENAME >
{
public :
DECLARE_LIBID(LIBID_CppServiceLib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CPPSERVICE, "{3a266de3-e432-4269-af44-5f76fdd0231f}")
HRESULT InitializeSecurity() throw()
{
// TODO : Call CoInitializeSecurity and provide the appropriate security settings for your service
// Suggested - PKT Level Authentication,
// Impersonation Level of RPC_C_IMP_LEVEL_IDENTIFY
// and an appropriate non-null Security Descriptor.
HRESULT _hr = S_OK;
_hr = CoInitializeSecurity((PSECURITY_DESCRIPTOR)&LIBID_CppServiceLib, -1, NULL, NULL, 0, RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_APPID, NULL);
return _hr;
}
// more stuff ...
};
In the above call, LIBID_CppServiceLib and the AppID of the service are the same...the wizard created them that way. Originally, I had a different call to CoInitializeSecurity()
when I was registering solely as a local server and not a service. I could get it to run when registering as a local server, but I need it to run as a server under the System account.
The .rgs files for the service and the COM object look like this:
CppService.rgs:
HKCR
{
NoRemove AppID
{
ForceRemove {3a266de3-e432-4269-af44-5f76fdd0231f} = s 'CppService'
{
val LocalService = s 'CppService'
val ROTFlags = d '1'
val RunAs = s 'nt authority\system'
val AuthenticationLevel = d '1'
}
ForceRemove CppService.exe
{
val AppID = s '{3a266de3-e432-4269-af44-5f76fdd0231f}'
}
}
}
TestObject.rgs:
HKCR
{
CppService.TestObject.1 = s 'TestObject class'
{
CLSID = s '{7594592c-ddc5-47f3-a2df-9cc397988fd0}'
}
CppService.TestObject = s 'TestObject class'
{
CurVer = s 'CppService.TestObject.1'
}
NoRemove CLSID
{
ForceRemove {7594592c-ddc5-47f3-a2df-9cc397988fd0} = s 'TestObject class'
{
AppID = s '{3a266de3-e432-4269-af44-5f76fdd0231f}'
ProgID = s 'CppService.TestObject.1'
VersionIndependentProgID = s 'CppService.TestObject'
ForceRemove Programmable
LocalServer32 = s '%MODULE%'
{
val ServerExecutable = s '%MODULE_RAW%'
}
TypeLib = s '{3a266de3-e432-4269-af44-5f76fdd0231f}'
Version = s '1.0'
}
}
}
When I originally verified it worked when running as a local server, the CppService.rgs file was just a plain HKCR {}
and the entry under CLSID for the object did not have the AppID key. As I said, originally it all worked fine when running as a local server, so the beginning COM plumbing worked fine, and I have many, many years working with COM. Maybe this isn't doable as COM. I could probably solve my problem with a WCF service in C#, but I wanted to do it in COM so I wouldn't have to listen on a port or named pipe.
I've seen comments in some places where people have registered the class factory in the ROT with the ROTREGFLAGS_ALLOWANYCLIENT
flag, and then manually tried to connect to the class factory via the ROT. But, Microsoft's documentation says that my AppID value of ROTFlags being equal to 1 is supposed to have the same effect...but doesn't seem to.
I'm not calling CoInitializeSecurity()
in the client application. Ideally, I'd like to be able to create with a simple vb script like:
set obj = CreateObject('CppService.TestObject')
Is this a solvable problem and I'm just missing something critical, or is it impossible?