diff --git a/dlls/ole32/moniker.c b/dlls/ole32/moniker.c index afe2343b77b..320a5612145 100644 --- a/dlls/ole32/moniker.c +++ b/dlls/ole32/moniker.c @@ -33,6 +33,7 @@ #include "windef.h" #include "winbase.h" #include "winuser.h" +#include "winsvc.h" #include "wtypes.h" #include "ole2.h" @@ -131,32 +132,52 @@ static IrotHandle get_irot_handle(void) static BOOL start_rpcss(void) { - PROCESS_INFORMATION pi; - STARTUPINFOW si; - WCHAR cmd[MAX_PATH]; - static const WCHAR rpcss[] = {'\\','r','p','c','s','s','.','e','x','e',0}; - BOOL rslt; - void *redir; + static const WCHAR rpcssW[] = {'R','p','c','S','s',0}; + SC_HANDLE scm, service; + SERVICE_STATUS_PROCESS status; + BOOL ret = FALSE; TRACE("\n"); - ZeroMemory(&si, sizeof(STARTUPINFOA)); - si.cb = sizeof(STARTUPINFOA); - GetSystemDirectoryW( cmd, MAX_PATH - sizeof(rpcss)/sizeof(WCHAR) ); - strcatW( cmd, rpcss ); - - Wow64DisableWow64FsRedirection( &redir ); - rslt = CreateProcessW( cmd, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi ); - Wow64RevertWow64FsRedirection( redir ); - - if (rslt) + if (!(scm = OpenSCManagerW( NULL, NULL, 0 ))) { - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - Sleep(100); + ERR( "failed to open service manager\n" ); + return FALSE; } + if (!(service = OpenServiceW( scm, rpcssW, SERVICE_START | SERVICE_QUERY_STATUS ))) + { + ERR( "failed to open RpcSs service\n" ); + CloseServiceHandle( scm ); + return FALSE; + } + if (StartServiceW( service, 0, NULL ) || GetLastError() == ERROR_SERVICE_ALREADY_RUNNING) + { + ULONGLONG start_time = GetTickCount64(); + do + { + DWORD dummy; - return rslt; + if (!QueryServiceStatusEx( service, SC_STATUS_PROCESS_INFO, + (BYTE *)&status, sizeof(status), &dummy )) + break; + if (status.dwCurrentState == SERVICE_RUNNING) + { + ret = TRUE; + break; + } + if (GetTickCount64() - start_time > 30000) break; + Sleep( 100 ); + + } while (status.dwCurrentState == SERVICE_START_PENDING); + + if (status.dwCurrentState != SERVICE_RUNNING) + WARN( "RpcSs failed to start %u\n", status.dwCurrentState ); + } + else ERR( "failed to start RpcSs service\n" ); + + CloseServiceHandle( service ); + CloseServiceHandle( scm ); + return ret; } static HRESULT create_stream_on_mip_ro(const InterfaceData *mip, IStream **stream) diff --git a/dlls/rpcrt4/rpc_epmap.c b/dlls/rpcrt4/rpc_epmap.c index 540c1c41036..1380bf34286 100644 --- a/dlls/rpcrt4/rpc_epmap.c +++ b/dlls/rpcrt4/rpc_epmap.c @@ -25,6 +25,7 @@ #include "windef.h" #include "winbase.h" #include "winerror.h" +#include "winsvc.h" #include "rpc.h" @@ -77,32 +78,52 @@ static const struct epm_endpoints static BOOL start_rpcss(void) { - PROCESS_INFORMATION pi; - STARTUPINFOW si; - WCHAR cmd[MAX_PATH]; - static const WCHAR rpcss[] = {'\\','r','p','c','s','s','.','e','x','e',0}; - BOOL rslt; - void *redir; + static const WCHAR rpcssW[] = {'R','p','c','S','s',0}; + SC_HANDLE scm, service; + SERVICE_STATUS_PROCESS status; + BOOL ret = FALSE; TRACE("\n"); - ZeroMemory(&si, sizeof(STARTUPINFOA)); - si.cb = sizeof(STARTUPINFOA); - GetSystemDirectoryW( cmd, MAX_PATH - sizeof(rpcss)/sizeof(WCHAR) ); - lstrcatW( cmd, rpcss ); - - Wow64DisableWow64FsRedirection( &redir ); - rslt = CreateProcessW( cmd, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi ); - Wow64RevertWow64FsRedirection( redir ); - - if (rslt) + if (!(scm = OpenSCManagerW( NULL, NULL, 0 ))) { - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - Sleep(100); + ERR( "failed to open service manager\n" ); + return FALSE; } + if (!(service = OpenServiceW( scm, rpcssW, SERVICE_START | SERVICE_QUERY_STATUS ))) + { + ERR( "failed to open RpcSs service\n" ); + CloseServiceHandle( scm ); + return FALSE; + } + if (StartServiceW( service, 0, NULL ) || GetLastError() == ERROR_SERVICE_ALREADY_RUNNING) + { + ULONGLONG start_time = GetTickCount64(); + do + { + DWORD dummy; - return rslt; + if (!QueryServiceStatusEx( service, SC_STATUS_PROCESS_INFO, + (BYTE *)&status, sizeof(status), &dummy )) + break; + if (status.dwCurrentState == SERVICE_RUNNING) + { + ret = TRUE; + break; + } + if (GetTickCount64() - start_time > 30000) break; + Sleep( 100 ); + + } while (status.dwCurrentState == SERVICE_START_PENDING); + + if (status.dwCurrentState != SERVICE_RUNNING) + WARN( "RpcSs failed to start %u\n", status.dwCurrentState ); + } + else ERR( "failed to start RpcSs service\n" ); + + CloseServiceHandle( service ); + CloseServiceHandle( scm ); + return ret; } static inline BOOL is_epm_destination_local(RPC_BINDING_HANDLE handle) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 48fcb095565..f611ea0665f 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -121,6 +121,7 @@ AddReg=\ AddService=BITS,0,BITSService AddService=MSIServer,0,MSIService AddService=MountMgr,0x800,MountMgrService +AddService=RpcSs,0,RpcSsService AddService=Spooler,0,SpoolerService AddService=StiSvc,0,StiService AddService=TermService,0,TerminalServices @@ -134,6 +135,7 @@ AddService=Schedule,0,TaskSchedulerService AddService=BITS,0,BITSService AddService=MSIServer,0,MSIService AddService=MountMgr,0x800,MountMgrService +AddService=RpcSs,0,RpcSsService AddService=Spooler,0,SpoolerService AddService=StiSvc,0,StiService AddService=TermService,0,TerminalServices @@ -147,6 +149,7 @@ AddService=Schedule,0,TaskSchedulerService AddService=BITS,0,BITSService AddService=MSIServer,0,MSIService AddService=MountMgr,0x800,MountMgrService +AddService=RpcSs,0,RpcSsService AddService=Spooler,0,SpoolerService AddService=StiSvc,0,StiService AddService=TermService,0,TerminalServices @@ -3165,6 +3168,14 @@ ServiceType=1 StartType=2 ErrorControl=1 +[RpcSsService] +Description="RPC service" +DisplayName="Remote Procedure Call (RPC)" +ServiceBinary="%11%\rpcss.exe" +ServiceType=32 +StartType=3 +ErrorControl=1 + [SpoolerService] Description="Loads files to memory for later printing" DisplayName="Print Spooler" @@ -3258,7 +3269,6 @@ HKLM,%CurrentVersionNT%\SvcHost,"netsvcs",0x00010008,"Schedule" HKLM,%CurrentVersion%\RunServices,"winemenubuilder",2,"%11%\winemenubuilder.exe -a -r" HKLM,"System\CurrentControlSet\Services\Eventlog\Application",,16 HKLM,"System\CurrentControlSet\Services\Eventlog\System",,16 -HKLM,"System\CurrentControlSet\Services\RpcSs",,16 HKLM,"System\CurrentControlSet\Services\Tcpip\Parameters",,16 HKLM,"System\CurrentControlSet\Services\VxD\MSTCP",,16 HKLM,"System\CurrentControlSet\Services\Winsock\Parameters",,16 diff --git a/programs/rpcss/Makefile.in b/programs/rpcss/Makefile.in index e397e3c51b2..79895af1166 100644 --- a/programs/rpcss/Makefile.in +++ b/programs/rpcss/Makefile.in @@ -1,6 +1,6 @@ MODULE = rpcss.exe -APPMODE = -mconsole -IMPORTS = rpcrt4 +APPMODE = -mconsole -municode +IMPORTS = rpcrt4 advapi32 C_SRCS = \ epmp.c \ diff --git a/programs/rpcss/rpcss_main.c b/programs/rpcss/rpcss_main.c index 1d246ea7b9f..5899adb5116 100644 --- a/programs/rpcss/rpcss_main.c +++ b/programs/rpcss/rpcss_main.c @@ -15,32 +15,6 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - * ---- rpcss_main.c: - * Initialize and start serving requests. Bail if rpcss already is - * running. - * - * ---- RPCSS.EXE: - * - * Wine needs a server whose role is somewhat like that - * of rpcss.exe in windows. This is not a clone of - * windows rpcss at all. It has been given the same name, however, - * to provide for the possibility that at some point in the future, - * it may become interface compatible with the "real" rpcss.exe on - * Windows. - * - * ---- KNOWN BUGS / TODO: - * - * o Service hooks are unimplemented (if you bother to implement - * these, also implement net.exe, at least for "net start" and - * "net stop" (should be pretty easy I guess, assuming the rest - * of the services API infrastructure works. - * - * o There is a looming problem regarding listening on privileged - * ports. We will need to be able to coexist with SAMBA, and be able - * to function without running winelib code as root. This may - * take some doing, including significant reconceptualization of the - * role of rpcss.exe in wine. */ #include @@ -51,6 +25,7 @@ #include "windef.h" #include "winbase.h" #include "winnt.h" +#include "winsvc.h" #include "irot.h" #include "epm.h" @@ -58,9 +33,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); +static WCHAR rpcssW[] = {'R','p','c','S','s',0}; static HANDLE exit_event; - -extern HANDLE CDECL __wine_make_process_system(void); +static SERVICE_STATUS_HANDLE service_handle; static BOOL RPCSS_Initialize(void) { @@ -103,8 +78,6 @@ static BOOL RPCSS_Initialize(void) if (status != RPC_S_OK) goto fail; - exit_event = __wine_make_process_system(); - return TRUE; fail: @@ -113,31 +86,76 @@ fail: return FALSE; } -/* returns false if we discover at the last moment that we - aren't ready to terminate */ -static BOOL RPCSS_Shutdown(void) +static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context ) { - RpcMgmtStopServerListening(NULL); - RpcServerUnregisterIf(epm_v3_0_s_ifspec, NULL, TRUE); - RpcServerUnregisterIf(Irot_v0_2_s_ifspec, NULL, TRUE); + SERVICE_STATUS status; - CloseHandle(exit_event); + status.dwServiceType = SERVICE_WIN32; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + status.dwWin32ExitCode = 0; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 0; + status.dwWaitHint = 0; - return TRUE; + switch (ctrl) + { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + TRACE( "shutting down\n" ); + RpcMgmtStopServerListening( NULL ); + RpcServerUnregisterIf( epm_v3_0_s_ifspec, NULL, TRUE ); + RpcServerUnregisterIf( Irot_v0_2_s_ifspec, NULL, TRUE ); + status.dwCurrentState = SERVICE_STOP_PENDING; + status.dwControlsAccepted = 0; + SetServiceStatus( service_handle, &status ); + SetEvent( exit_event ); + return NO_ERROR; + default: + FIXME( "got service ctrl %x\n", ctrl ); + status.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus( service_handle, &status ); + return NO_ERROR; + } } -int main( int argc, char **argv ) +static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv ) { - /* - * We are invoked as a standard executable; we act in a - * "lazy" manner. We register our interfaces and endpoints, and hang around - * until we all user processes exit, and then silently terminate. - */ + SERVICE_STATUS status; - if (RPCSS_Initialize()) { - WaitForSingleObject(exit_event, INFINITE); - RPCSS_Shutdown(); - } + TRACE( "starting service\n" ); - return 0; + if (!RPCSS_Initialize()) return; + + exit_event = CreateEventW( NULL, TRUE, FALSE, NULL ); + + service_handle = RegisterServiceCtrlHandlerExW( rpcssW, service_handler, NULL ); + if (!service_handle) return; + + status.dwServiceType = SERVICE_WIN32; + status.dwCurrentState = SERVICE_RUNNING; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + status.dwWin32ExitCode = 0; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 0; + status.dwWaitHint = 10000; + SetServiceStatus( service_handle, &status ); + + WaitForSingleObject( exit_event, INFINITE ); + + status.dwCurrentState = SERVICE_STOPPED; + status.dwControlsAccepted = 0; + SetServiceStatus( service_handle, &status ); + TRACE( "service stopped\n" ); +} + +int wmain( int argc, WCHAR *argv[] ) +{ + static const SERVICE_TABLE_ENTRYW service_table[] = + { + { rpcssW, ServiceMain }, + { NULL, NULL } + }; + + StartServiceCtrlDispatcherW( service_table ); + return 0; }