jon-stewart
asked on
HRESULT 80070057 when registering a COM Server from a Windows Service
Hi,
I’ve got an executable that registers a COM server; it can run as an application or as a Windows service, depending on a run time parameter. When run as an application, other applications can create COM objects that connect to it. However, I want to run it as a service and to have other applications and other services (on the same machine) create objects that connect to it.
The specific problem: I’m trying to register the COM server with the Windows Running Object Table with grfFlags of (ROTFLAGS_REGISTRATIONKEEP SALIVE | ROTFLAGS_ALLOWANYCLIENT), but I’m getting an HRESULT of 80070057, “One or more arguments are not valid”.
The code below works if the exe is run as an application; but the RunningObjectTable.Registe r call fails with HRESULT 80070057 when the exe is run as a service. That leads me to suspect that one of my registry keys/values is not correct for running as a service. I have tried to set them up according to MSDN page http://msdn.microsoft.com/en-us/library/windows/desktop/ms693774%28v=vs.85%29.aspx, and other nearby pages – details below.
I’m maintaining a bit of code that has been around for a long time, but I think this is the first time it’s been used to register a COM Server hosted by a windows service. The code is written using Delphi, but help from anyone familiar with unmanaged calls to these Windows functions would be greatly appreciated! The target OS is Windows 2012 R2.
The code is:
class function TROT.RegisterActiveObjectE x(Unk: IUnknown; ClassID: TGUID; out Register:Longint): HResult;
var
Moniker : IMoniker;
ClassName: PWideChar;
RunningObjectTable: IRunningObjectTable;
PrevUn : IUnknown;
begin
try
PrevUnk := RetrieveActiveObjectEx(Cla ssID);
if assigned(PrevUnk) then
begin
Result := -2; //Ignore duplicate registration
end
else
begin
ClassName := StringToOleStr(GuidToStrin g(ClassID) );
try
Result := CreateItemMoniker('!', ClassName, Moniker);
if Failed(Result) then
begin
exit;
end
else
begin
Result := GetRunningObjectTable(0, RunningObjectTable);
if Failed(Result) then
begin
exit;
end
else
begin
Result := RunningObjectTable.Registe r(ROTFLAGS _REGISTRAT IONKEEPSAL IVE or ROTFLAGS_ALLOWANYCLIENT, Unk, Moniker, Register);
end;
end;
finally
SysFreeString(ClassName);
end;
end;
except
on E:Exception do
begin
Result := -1;
end;
end;
end;
Registry values set up for the service are given below (HKCR is used to ensure that they are mirrored everywhere required):
[HKEY_CLASSES_ROOT\AppID\S ervice.exe ]
"AppId"="{COM server GUID}"
[HKEY_CLASSES_ROOT\AppID\{ COM server GUID}]
"LocalService"="ServiceNam e" - as used in a net start command
"AuthenticationLevel"=dwor d:00000001
"ROTFlags"=dword:00000001
Can anyone help?
I’ve got an executable that registers a COM server; it can run as an application or as a Windows service, depending on a run time parameter. When run as an application, other applications can create COM objects that connect to it. However, I want to run it as a service and to have other applications and other services (on the same machine) create objects that connect to it.
The specific problem: I’m trying to register the COM server with the Windows Running Object Table with grfFlags of (ROTFLAGS_REGISTRATIONKEEP
The code below works if the exe is run as an application; but the RunningObjectTable.Registe
I’m maintaining a bit of code that has been around for a long time, but I think this is the first time it’s been used to register a COM Server hosted by a windows service. The code is written using Delphi, but help from anyone familiar with unmanaged calls to these Windows functions would be greatly appreciated! The target OS is Windows 2012 R2.
The code is:
class function TROT.RegisterActiveObjectE
var
Moniker : IMoniker;
ClassName: PWideChar;
RunningObjectTable: IRunningObjectTable;
PrevUn : IUnknown;
begin
try
PrevUnk := RetrieveActiveObjectEx(Cla
if assigned(PrevUnk) then
begin
Result := -2; //Ignore duplicate registration
end
else
begin
ClassName := StringToOleStr(GuidToStrin
try
Result := CreateItemMoniker('!', ClassName, Moniker);
if Failed(Result) then
begin
exit;
end
else
begin
Result := GetRunningObjectTable(0, RunningObjectTable);
if Failed(Result) then
begin
exit;
end
else
begin
Result := RunningObjectTable.Registe
end;
end;
finally
SysFreeString(ClassName);
end;
end;
except
on E:Exception do
begin
Result := -1;
end;
end;
end;
Registry values set up for the service are given below (HKCR is used to ensure that they are mirrored everywhere required):
[HKEY_CLASSES_ROOT\AppID\S
"AppId"="{COM server GUID}"
[HKEY_CLASSES_ROOT\AppID\{
"LocalService"="ServiceNam
"AuthenticationLevel"=dwor
"ROTFlags"=dword:00000001
Can anyone help?
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
I had similar experience. Try replace ROTFLAGS_REGISTRATIONKEEPS ALIVE or ROTFLAGS_ALLOWANYCLIENT with 0 (zero).
ASKER
Thanks Sinisav; unfortunately I get the same result when I pass zero to the grfFlags parameter.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Hi Sinisav,
Thanks for persisting with this. I've tried CreateFileMoniker - not sure what your ClassName variable is: my first attempt was to pass the full path to C:\...\Service.exe, but I've also tried passing the ClassGuid. I get the same result each time - it would be nice to see a different error code even!
I was just using Coinitialize(nil), and have changed it to CoInitializeEx(nil, COINIT_APARTMENTTHREADED). I am calling it from the ServiceStart event, to match the thread on which I'm creating the client object.
Is your code running as a Windows service?
Thanks for persisting with this. I've tried CreateFileMoniker - not sure what your ClassName variable is: my first attempt was to pass the full path to C:\...\Service.exe, but I've also tried passing the ClassGuid. I get the same result each time - it would be nice to see a different error code even!
I was just using Coinitialize(nil), and have changed it to CoInitializeEx(nil, COINIT_APARTMENTTHREADED).
Is your code running as a Windows service?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
To summarise the solution:
Comments from Geert_Gruwez in the first response are essential to check. In answer to his query about HKCR, we found that registry values created there can by seen by the the System account, since they are reflected in the appropriate HKLM keys.
After reading the comments from Sinisav, I changed Coinitialize calls to CoInitializeEx, in order to be more explicit about the intention. However in the working solution, we did not change CreateItemMoniker to CreateFileMoniker, and we kept the ROTFLAGS_REGISTRATIONKEEPS ALIVE or ROTFLAGS_ALLOWANYCLIENT flags which specify the functionality we wanted.
The bottom line solution to the problem was that we needed to call RegisterActiveObjectEx from the ServiceCreate thread, and we needed the ROTflags value in the registry.
Comments from Geert_Gruwez in the first response are essential to check. In answer to his query about HKCR, we found that registry values created there can by seen by the the System account, since they are reflected in the appropriate HKLM keys.
After reading the comments from Sinisav, I changed Coinitialize calls to CoInitializeEx, in order to be more explicit about the intention. However in the working solution, we did not change CreateItemMoniker to CreateFileMoniker, and we kept the ROTFLAGS_REGISTRATIONKEEPS
The bottom line solution to the problem was that we needed to call RegisterActiveObjectEx from the ServiceCreate thread, and we needed the ROTflags value in the registry.
ASKER
I graded the solution as excellent because I think there's good information in these posts for anyone encountering the same problems.
Comments from Geert_Gruwez in the first response are essential to check.
From reading the comments from Sinisav, I changed Coinitialize calls to CoInitializeEx, in order to be more explicit about the intention. However in the working solution, we did not change CreateItemMoniker to CreateFileMoniker, and we kept the ROTFLAGS_REGISTRATIONKEEPS ALIVE or ROTFLAGS_ALLOWANYCLIENT flags which was the functionality we wanted.
The bottom line solution to the problem was that we needed to call RegisterActiveObjectEx from the ServiceCreate thread, and we needed the ROTflags value in the registry.
Comments from Geert_Gruwez in the first response are essential to check.
From reading the comments from Sinisav, I changed Coinitialize calls to CoInitializeEx, in order to be more explicit about the intention. However in the working solution, we did not change CreateItemMoniker to CreateFileMoniker, and we kept the ROTFLAGS_REGISTRATIONKEEPS
The bottom line solution to the problem was that we needed to call RegisterActiveObjectEx from the ServiceCreate thread, and we needed the ROTflags value in the registry.
ASKER
I get the same result when running under a user account (with administrative privileges).
Looking through the registry I see that creating the registry values under HKCR\AppID causes them to also appear under HKLM\SOFTWARE\Classes\AppI
One further comment, the call to TROT.RegisterActiveObjectE
Jon