Solved

HRESULT 80070057 when registering a COM Server from a Windows Service

Posted on 2013-11-04
9
891 Views
Last Modified: 2013-11-23
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_REGISTRATIONKEEPSALIVE | 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.Register 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.RegisterActiveObjectEx(Unk: IUnknown; ClassID: TGUID; out Register:Longint): HResult;
var
  Moniker : IMoniker;  
  ClassName: PWideChar;
  RunningObjectTable: IRunningObjectTable;
  PrevUn : IUnknown;
begin
    try
        PrevUnk := RetrieveActiveObjectEx(ClassID);
        if assigned(PrevUnk) then
        begin
            Result := -2; //Ignore duplicate registration
        end
        else
        begin
            ClassName := StringToOleStr(GuidToString(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.Register(ROTFLAGS_REGISTRATIONKEEPSALIVE 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\Service.exe]
"AppId"="{COM server GUID}"

[HKEY_CLASSES_ROOT\AppID\{COM server GUID}]
"LocalService"="ServiceName"   - as used in a net start command
"AuthenticationLevel"=dword:00000001
"ROTFlags"=dword:00000001

Can anyone help?
0
Comment
Question by:jon-stewart
  • 6
  • 2
9 Comments
 
LVL 36

Assisted Solution

by:Geert Gruwez
Geert Gruwez earned 250 total points
Comment Utility
is your service running with the system account or with a specific account ?

try and run it with the account you run your app with as exe
then see what happens

not sure if you have a HKCR running with the system account
0
 

Author Comment

by:jon-stewart
Comment Utility
Thanks for the response.

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\AppID & HKLM\SOFTWARE\Classes\Wow6432Node\AppID (it's a 32 bit exe).

One further comment, the call to TROT.RegisterActiveObjectEx is made from the ServiceStart event - after creating a local COM object that connect to the server to pass to the Unk parameter).

Jon
0
 
LVL 25

Expert Comment

by:Sinisa Vuk
Comment Utility
I had similar experience. Try replace ROTFLAGS_REGISTRATIONKEEPSALIVE or ROTFLAGS_ALLOWANYCLIENT with 0 (zero).
0
 

Author Comment

by:jon-stewart
Comment Utility
Thanks Sinisav; unfortunately I get the same result when I pass zero to the grfFlags parameter.
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 25

Assisted Solution

by:Sinisa Vuk
Sinisa Vuk earned 250 total points
Comment Utility
Hmmm. Difference to my usage is that I'm using File Moniker:

...CreateFileMoniker(ClassName, Moniker);

....

initialization
  CoInitializeEx(nil,COINIT_APARTMENTTHREADED);

...

Open in new window

0
 

Author Comment

by:jon-stewart
Comment Utility
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?
0
 

Accepted Solution

by:
jon-stewart earned 0 total points
Comment Utility
We seem to have got it working by calling RegisterActiveObjectEx from ServiceCreate rather than ServiceStart, so it's important to have it on the right thread.  I've modified the code to explicitly use COINIT_APARTMENTTHREADED as Sinisav suggests, which makes it a bit clearer.

I thought I'd tried using the ServiceCreate event before, but it maybe that I didn't have ROTFlags value in the registry at that point.

Interestingly, the LocalService registry value doesn't seem to be necessary.

Thanks to both of you for your help.  I'll leave this open another day to see if anyone else wants to comment before accepting an answer.
0
 

Author Comment

by:jon-stewart
Comment Utility
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_REGISTRATIONKEEPSALIVE 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.
0
 

Author Closing Comment

by:jon-stewart
Comment Utility
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_REGISTRATIONKEEPSALIVE 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.
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

Suggested Solutions

Table of Contents: Lesson 1 - Installing Windows Server 2012 (http://www.experts-exchange.com/OS/Microsoft_Operating_Systems/Server/Windows_Server_2012/A_11592-Become-an-Administrator-Installing-Windows-Server-2012.html) Lesson 2 - Configuring Ser…
Understanding the various editions available is vital when you decide to purchase Windows Server 2012. You need to have a basic understanding of the features and limitations in each edition in order to make a well-informed decision that best suits y…
In this Micro Tutorial viewers will learn how to use Boot Corrector from Paragon Rescue Kit Free to identify and fix the boot problems of Windows 7/8/2012R2 etc. As an example is used Windows 2012R2 which lost its active partition flag (often happen…
In this Micro Tutorial viewers will learn how to restore their server from Bare Metal Backup image created with Windows Server Backup feature. As an example Windows 2012R2 is used.

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

6 Experts available now in Live!

Get 1:1 Help Now