winehq.org
Sign In
Sign Up
Sign In
Sign Up
Manage this list
×
Keyboard Shortcuts
Thread View
j
: Next unread message
k
: Previous unread message
j a
: Jump to all threads
j l
: Jump to MailingList overview
2025
April
March
February
January
2024
December
November
October
September
August
July
June
May
April
March
February
January
2023
December
November
October
September
August
July
June
May
April
March
February
January
2022
December
November
October
September
August
July
June
May
April
March
February
January
2021
December
November
October
September
August
July
June
May
April
March
February
January
2020
December
November
October
September
August
July
June
May
April
March
February
January
2019
December
November
October
September
August
July
June
May
April
March
February
January
2018
December
November
October
September
August
July
June
May
April
March
February
January
2017
December
November
October
September
August
July
June
May
April
March
February
January
2016
December
November
October
September
August
July
June
May
April
March
February
January
2015
December
November
October
September
August
July
June
May
April
March
February
January
2014
December
November
October
September
August
July
June
May
April
March
February
January
2013
December
November
October
September
August
July
June
May
April
March
February
January
2012
December
November
October
September
August
July
June
May
April
March
February
January
2011
December
November
October
September
August
July
June
May
April
March
February
January
2010
December
November
October
September
August
July
June
May
April
March
February
January
2009
December
November
October
September
August
July
June
May
April
March
February
January
2008
December
November
October
September
August
July
June
May
April
March
February
January
2007
December
November
October
September
August
July
June
May
April
March
February
January
2006
December
November
October
September
August
July
June
May
April
March
February
January
2005
December
November
October
September
August
July
June
May
April
March
February
January
2004
December
November
October
September
August
July
June
May
April
March
February
January
2003
December
November
October
September
August
July
June
May
April
March
February
January
2002
December
November
October
September
August
July
June
May
April
March
February
January
2001
December
November
October
September
August
July
June
May
April
March
February
List overview
wine-devel
April 2020
----- 2025 -----
April 2025
March 2025
February 2025
January 2025
----- 2024 -----
December 2024
November 2024
October 2024
September 2024
August 2024
July 2024
June 2024
May 2024
April 2024
March 2024
February 2024
January 2024
----- 2023 -----
December 2023
November 2023
October 2023
September 2023
August 2023
July 2023
June 2023
May 2023
April 2023
March 2023
February 2023
January 2023
----- 2022 -----
December 2022
November 2022
October 2022
September 2022
August 2022
July 2022
June 2022
May 2022
April 2022
March 2022
February 2022
January 2022
----- 2021 -----
December 2021
November 2021
October 2021
September 2021
August 2021
July 2021
June 2021
May 2021
April 2021
March 2021
February 2021
January 2021
----- 2020 -----
December 2020
November 2020
October 2020
September 2020
August 2020
July 2020
June 2020
May 2020
April 2020
March 2020
February 2020
January 2020
----- 2019 -----
December 2019
November 2019
October 2019
September 2019
August 2019
July 2019
June 2019
May 2019
April 2019
March 2019
February 2019
January 2019
----- 2018 -----
December 2018
November 2018
October 2018
September 2018
August 2018
July 2018
June 2018
May 2018
April 2018
March 2018
February 2018
January 2018
----- 2017 -----
December 2017
November 2017
October 2017
September 2017
August 2017
July 2017
June 2017
May 2017
April 2017
March 2017
February 2017
January 2017
----- 2016 -----
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
----- 2015 -----
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
----- 2014 -----
December 2014
November 2014
October 2014
September 2014
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
----- 2013 -----
December 2013
November 2013
October 2013
September 2013
August 2013
July 2013
June 2013
May 2013
April 2013
March 2013
February 2013
January 2013
----- 2012 -----
December 2012
November 2012
October 2012
September 2012
August 2012
July 2012
June 2012
May 2012
April 2012
March 2012
February 2012
January 2012
----- 2011 -----
December 2011
November 2011
October 2011
September 2011
August 2011
July 2011
June 2011
May 2011
April 2011
March 2011
February 2011
January 2011
----- 2010 -----
December 2010
November 2010
October 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
----- 2009 -----
December 2009
November 2009
October 2009
September 2009
August 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
January 2009
----- 2008 -----
December 2008
November 2008
October 2008
September 2008
August 2008
July 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
----- 2007 -----
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
February 2007
January 2007
----- 2006 -----
December 2006
November 2006
October 2006
September 2006
August 2006
July 2006
June 2006
May 2006
April 2006
March 2006
February 2006
January 2006
----- 2005 -----
December 2005
November 2005
October 2005
September 2005
August 2005
July 2005
June 2005
May 2005
April 2005
March 2005
February 2005
January 2005
----- 2004 -----
December 2004
November 2004
October 2004
September 2004
August 2004
July 2004
June 2004
May 2004
April 2004
March 2004
February 2004
January 2004
----- 2003 -----
December 2003
November 2003
October 2003
September 2003
August 2003
July 2003
June 2003
May 2003
April 2003
March 2003
February 2003
January 2003
----- 2002 -----
December 2002
November 2002
October 2002
September 2002
August 2002
July 2002
June 2002
May 2002
April 2002
March 2002
February 2002
January 2002
----- 2001 -----
December 2001
November 2001
October 2001
September 2001
August 2001
July 2001
June 2001
May 2001
April 2001
March 2001
February 2001
wine-devel@winehq.org
87 participants
854 discussions
Start a n
N
ew thread
[PATCH 1/3] server: Abort waiting on a completion port when closing it.
by Alexey Prokhin
29 Apr '20
29 Apr '20
Signed-off-by: Alexey Prokhin <alexey(a)prokhin.ru> --- server/completion.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/server/completion.c b/server/completion.c index db04727b93..9e15c1ca07 100644 --- a/server/completion.c +++ b/server/completion.c @@ -48,12 +48,14 @@ struct completion struct object obj; struct list queue; unsigned int depth; + int abandoned; }; static void completion_dump( struct
…
[View More]
object*, int ); static struct object_type *completion_get_type( struct object *obj ); static int completion_signaled( struct object *obj, struct wait_queue_entry *entry ); static unsigned int completion_map_access( struct object *obj, unsigned int access ); +static int completion_close( struct object *obj, struct process *process, obj_handle_t handle ); static void completion_destroy( struct object * ); static const struct object_ops completion_ops = @@ -75,7 +77,7 @@ static const struct object_ops completion_ops = default_unlink_name, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ - no_close_handle, /* close_handle */ + completion_close, /* close_handle */ completion_destroy /* destroy */ }; @@ -88,6 +90,22 @@ struct comp_msg unsigned int status; }; +static int completion_close( struct object *obj, struct process *process, obj_handle_t handle ) +{ + struct completion *completion = (struct completion *) obj; + struct wait_queue_entry *entry; + + LIST_FOR_EACH_ENTRY( entry, &obj->wait_queue, struct wait_queue_entry, entry ) + { + make_wait_abandoned( entry ); + } + + completion->abandoned = 1; + wake_up( &completion->obj, 0 ); + + return 1; +} + static void completion_destroy( struct object *obj) { struct completion *completion = (struct completion *) obj; @@ -118,7 +136,7 @@ static int completion_signaled( struct object *obj, struct wait_queue_entry *ent { struct completion *completion = (struct completion *)obj; - return !list_empty( &completion->queue ); + return !list_empty( &completion->queue ) || completion->abandoned; } static unsigned int completion_map_access( struct object *obj, unsigned int access ) @@ -141,6 +159,7 @@ static struct completion *create_completion( struct object *root, const struct u if (get_error() != STATUS_OBJECT_NAME_EXISTS) { list_init( &completion->queue ); + completion->abandoned = 0; completion->depth = 0; } } @@ -224,7 +243,7 @@ DECL_HANDLER(remove_completion) entry = list_head( &completion->queue ); if (!entry) - set_error( STATUS_PENDING ); + set_error( completion->abandoned ? STATUS_ABANDONED_WAIT_0 : STATUS_PENDING ); else { list_remove( entry ); -- 2.26.2
[View Less]
2
3
0
0
[PATCH rebase 1/2] winemenubuilder: Blacklist desktop integration for certain associations
by Alex Henrie
29 Apr '20
29 Apr '20
Wine-Bug:
https://bugs.winehq.org/show_bug.cgi?id=41275
Signed-off-by: Alex Henrie <alexhenrie24(a)gmail.com> --- dlls/mshtml/mshtml.inf | 6 +++ loader/wine.inf.in | 10 ++++ programs/winemenubuilder/winemenubuilder.c | 54 +++++++++++++++++++--- 3 files changed, 63 insertions(+), 7 deletions(-) diff --git a/dlls/mshtml/mshtml.inf b/dlls/mshtml/mshtml.inf index 4a650b444f..548739f432 100644 --- a/dlls/mshtml/mshtml.inf +++ b/dlls/mshtml/
…
[View More]
mshtml.inf @@ -111,6 +111,7 @@ HKCR,"giffile\shell\open\ddeexec",,,"""file:%%1"",,-1,,,,," HKCR,"giffile\shell\open\ddeexec\Application",,,"IExplore" HKCR,"giffile\shell\open\ddeexec\Topic",,,"WWW_OpenURL" ;; HKCR,"giffile\DefaultIcon",,,"%16422%\Internet Explorer\iexplore.exe,9" +HKCU,Software\Wine\FileOpenBlacklist\.gif,"iexplore",,"""%16422%\Internet Explorer\iexplore.exe"" -nohome" ;; GZIP HKCR,"MIME\Database\Content Type\application/x-gzip","Extension",,".gz" @@ -158,6 +159,7 @@ HKCR,"jpegfile\shell\open\ddeexec",,,"""file:%%1"",,-1,,,,," HKCR,"jpegfile\shell\open\ddeexec\Application",,,"IExplore" HKCR,"jpegfile\shell\open\ddeexec\Topic",,,"WWW_OpenURL" ;; HKCR,"jpegfile\DefaultIcon",,,"%16422%\Internet Explorer\iexplore.exe,8" +HKCU,Software\Wine\FileOpenBlacklist\.jpe,"iexplore",,"""%16422%\Internet Explorer\iexplore.exe"" -nohome" ;; JPEG HKCR,"MIME\Database\Content Type\image/jpeg","CLSID",,"%CLSID_HTMLDocument%" @@ -173,6 +175,7 @@ HKCR,"jpegfile\shell\open\ddeexec",,,"""file:%%1"",,-1,,,,," HKCR,"jpegfile\shell\open\ddeexec\Application",,,"IExplore" HKCR,"jpegfile\shell\open\ddeexec\Topic",,,"WWW_OpenURL" ;; HKCR,"jpegfile\DefaultIcon",,,"%16422%\Internet Explorer\iexplore.exe,8" +HKCU,Software\Wine\FileOpenBlacklist\.jpeg,"iexplore",,"""%16422%\Internet Explorer\iexplore.exe"" -nohome" ;; JPG HKCR,".jpg",,2,"jpegfile" @@ -184,6 +187,7 @@ HKCR,"jpegfile\shell\open\ddeexec",,,"""file:%%1"",,-1,,,,," HKCR,"jpegfile\shell\open\ddeexec\Application",,,"IExplore" HKCR,"jpegfile\shell\open\ddeexec\Topic",,,"WWW_OpenURL" ;; HKCR,"jpegfile\DefaultIcon",,,"%16422%\Internet Explorer\iexplore.exe,8" +HKCU,Software\Wine\FileOpenBlacklist\.jpg,"iexplore",,"""%16422%\Internet Explorer\iexplore.exe"" -nohome" ;; MHTML HKCR,"MIME\Database\Content Type\message/rfc822","CLSID",,"%CLSID_MHTMLDocument%" @@ -221,6 +225,7 @@ HKCR,"pjpegfile\shell\open\ddeexec",,,"""file:%%1"",,-1,,,,," HKCR,"pjpegfile\shell\open\ddeexec\Application",,,"IExplore" HKCR,"pjpegfile\shell\open\ddeexec\Topic",,,"WWW_OpenURL" ;; HKCR,"pjpegfile\DefaultIcon",,,"%16422%\Internet Explorer\iexplore.exe,8" +HKCU,Software\Wine\FileOpenBlacklist\.jfif,"iexplore",,"""%16422%\Internet Explorer\iexplore.exe"" -nohome" ;; PNG HKCR,"MIME\Database\Content Type\image/png","Extension",,".png" @@ -234,6 +239,7 @@ HKCR,"pngfile\shell\open\ddeexec",,,"""file:%%1"",,-1,,,,," HKCR,"pngfile\shell\open\ddeexec\Application",,,"IExplore" HKCR,"pngfile\shell\open\ddeexec\Topic",,,"WWW_OpenURL" ;; HKCR,"pngfile\DefaultIcon",,,"%16422%\Internet Explorer\iexplore.exe,9" +HKCU,Software\Wine\FileOpenBlacklist\.png,"iexplore",,"""%16422%\Internet Explorer\iexplore.exe"" -nohome" ;; PS HKCR,"MIME\Database\Content Type\application/postscript","Extension",,".ps" diff --git a/loader/wine.inf.in b/loader/wine.inf.in index e602546da8..5a229312ab 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -501,6 +501,16 @@ HKCR,MIME\Database\Charset\us-ascii,"AliasForCharset",,iso-8859-1 HKCR,MIME\Database\Charset\visual,"AliasForCharset",,iso-8859-8 HKCR,MIME\Database\Charset\Windows-1254,"AliasForCharset",,iso-8859-9 +HKCU,Software\Wine\FileOpenBlacklist\.htm,"winebrowser",,"""%11%\winebrowser.exe"" -nohome" +HKCU,Software\Wine\FileOpenBlacklist\.html,"winebrowser",,"""%11%\winebrowser.exe"" -nohome" +HKCU,Software\Wine\FileOpenBlacklist\.ini,"notepad",,"%11%\notepad.exe %1" +HKCU,Software\Wine\FileOpenBlacklist\.pdf,"winebrowser",,"""%11%\winebrowser.exe"" -nohome" +HKCU,Software\Wine\FileOpenBlacklist\.rtf,"wordpad",,"""%16422%\Windows NT\Accessories\wordpad.exe"" %1" +HKCU,Software\Wine\FileOpenBlacklist\.txt,"notepad",,"%11%\notepad.exe %1" +HKCU,Software\Wine\FileOpenBlacklist\.url,"ieframe",,"rundll32.exe ieframe.dll,OpenURL %l" +HKCU,Software\Wine\FileOpenBlacklist\.wri,"wordpad",,"""%16422%\Windows NT\Accessories\wordpad.exe"" %1" +HKCU,Software\Wine\FileOpenBlacklist\.xml,"winebrowser",,"""%11%\winebrowser.exe"" -nohome" + [ContentIndex] HKLM,System\CurrentControlSet\Control\ContentIndex\Language\Neutral,"WBreakerClass",,"{369647e0-17b0-11ce-9950-00aa004bbb1f}" HKLM,System\CurrentControlSet\Control\ContentIndex\Language\Neutral,"StemmerClass",,"" diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c index d6fc9e2923..64e1dbdf20 100644 --- a/programs/winemenubuilder/winemenubuilder.c +++ b/programs/winemenubuilder/winemenubuilder.c @@ -2470,7 +2470,7 @@ static BOOL write_freedesktop_mime_type_entry(const char *packages_dir, const ch return ret; } -static BOOL is_extension_blacklisted(LPCWSTR extension) +static BOOL is_hard_blacklisted(const WCHAR *extension) { /* These are managed through external tools like wine.desktop, to evade malware created file type associations */ static const WCHAR comW[] = {'.','c','o','m',0}; @@ -2484,6 +2484,42 @@ static BOOL is_extension_blacklisted(LPCWSTR extension) return FALSE; } +static BOOL is_soft_blacklisted(const WCHAR *extension, const WCHAR *command) +{ + static const WCHAR FileOpenBlacklistW[] = {'S','o','f','t','w','a','r','e','\\', + 'W','i','n','e','\\', + 'F','i','l','e','O','p','e','n','B','l','a','c','k','l','i','s','t','\\',0}; + WCHAR blacklist_key_path[MAX_PATH]; + HKEY blacklist_key; + WCHAR program_name[MAX_PATH], *blacklisted_command; + DWORD len = ARRAY_SIZE(program_name); + DWORD i = 0; + + if (ARRAY_SIZE(FileOpenBlacklistW) + lstrlenW(extension) > ARRAY_SIZE(blacklist_key_path)) + return FALSE; + + lstrcpyW(blacklist_key_path, FileOpenBlacklistW); + lstrcatW(blacklist_key_path, extension); + + if (RegOpenKeyExW(HKEY_CURRENT_USER, blacklist_key_path, 0, KEY_QUERY_VALUE, &blacklist_key) != ERROR_SUCCESS) + return FALSE; + + while (RegEnumValueW(blacklist_key, i, program_name, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) + { + blacklisted_command = reg_get_valW(HKEY_CURRENT_USER, blacklist_key_path, program_name); + if (strcmpW(command, blacklisted_command) == 0) + { + RegCloseKey(blacklist_key); + return TRUE; + } + len = ARRAY_SIZE(program_name); + i++; + } + + RegCloseKey(blacklist_key); + return FALSE; +} + static const char* get_special_mime_type(LPCWSTR extension) { static const WCHAR lnkW[] = {'.','l','n','k',0}; @@ -2564,7 +2600,7 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package size *= 2; } while (ret == ERROR_MORE_DATA); - if (ret == ERROR_SUCCESS && extensionW[0] == '.' && !is_extension_blacklisted(extensionW)) + if (ret == ERROR_SUCCESS && extensionW[0] == '.' && !is_hard_blacklisted(extensionW)) { char *extensionA = NULL; WCHAR *commandW = NULL; @@ -2582,6 +2618,15 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package char *progIdA = NULL; char *mimeProgId = NULL; + commandW = assoc_query(ASSOCSTR_COMMAND, extensionW, openW); + if (commandW == NULL) + /* no command => no application is associated */ + goto end; + + if (is_soft_blacklisted(extensionW, commandW)) + /* command is on the blacklist => desktop integration is not desirable */ + goto end; + extensionA = wchars_to_utf8_chars(strlwrW(extensionW)); if (extensionA == NULL) { @@ -2650,11 +2695,6 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package } } - commandW = assoc_query(ASSOCSTR_COMMAND, extensionW, openW); - if (commandW == NULL) - /* no command => no application is associated */ - goto end; - executableW = assoc_query(ASSOCSTR_EXECUTABLE, extensionW, openW); if (executableW) openWithIconA = extract_icon(executableW, 0, NULL, FALSE); -- 2.26.2
[View Less]
1
1
0
0
[PATCH] advapi32: Move service functions into sechost.
by Zebediah Figura
29 Apr '20
29 Apr '20
Based on a patch by Micah N Gorrell. Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com> --- dlls/advapi32/Makefile.in | 1 - dlls/advapi32/advapi32.spec | 70 +- dlls/advapi32/service.c | 2370 +------------------------ dlls/sechost/Makefile.in | 5 + dlls/sechost/sechost.spec | 70 +- dlls/sechost/service.c | 1969 ++++++++++++++++++++ dlls/{advapi32 => sechost}/svcctl.idl | 0 7 files
…
[View More]
changed, 2089 insertions(+), 2396 deletions(-) create mode 100644 dlls/sechost/service.c rename dlls/{advapi32 => sechost}/svcctl.idl (100%) diff --git a/dlls/advapi32/Makefile.in b/dlls/advapi32/Makefile.in index 33dbe851c9f..e70b1a7a07a 100644 --- a/dlls/advapi32/Makefile.in +++ b/dlls/advapi32/Makefile.in @@ -19,6 +19,5 @@ C_SRCS = \ service.c \ wmi.c -IDL_SRCS = svcctl.idl RC_SRCS = version.rc diff --git a/dlls/advapi32/advapi32.spec b/dlls/advapi32/advapi32.spec index cb3e856ce98..cd4dedac74d 100644 --- a/dlls/advapi32/advapi32.spec +++ b/dlls/advapi32/advapi32.spec @@ -89,10 +89,10 @@ @ stdcall BuildTrusteeWithSidA(ptr ptr) @ stdcall BuildTrusteeWithSidW(ptr ptr) # @ stub CancelOverlappedAccess -@ stdcall ChangeServiceConfig2A(long long ptr) -@ stdcall ChangeServiceConfig2W(long long ptr) -@ stdcall ChangeServiceConfigA(long long long long wstr str ptr str str str str) -@ stdcall ChangeServiceConfigW(long long long long wstr wstr ptr wstr wstr wstr wstr) +@ stdcall -import ChangeServiceConfig2A(long long ptr) +@ stdcall -import ChangeServiceConfig2W(long long ptr) +@ stdcall -import ChangeServiceConfigA(long long long long wstr str ptr str str str str) +@ stdcall -import ChangeServiceConfigW(long long long long wstr wstr ptr wstr wstr wstr wstr) # @ stub CheckForHiberboot @ stdcall -import CheckTokenMembership(long ptr ptr) @ stdcall ClearEventLogA (long str) @@ -100,12 +100,12 @@ # @ stub CloseCodeAuthzLevel @ stdcall CloseEncryptedFileRaw(ptr) @ stdcall CloseEventLog (long) -@ stdcall CloseServiceHandle(long) +@ stdcall -import CloseServiceHandle(long) # @ stub CloseThreadWaitChainSession @ stdcall -import CloseTrace(int64) @ stdcall CommandLineFromMsiDescriptor(wstr ptr ptr) # @ stub ComputeAccessTokenFromCodeAuthzLevel -@ stdcall ControlService(long long ptr) +@ stdcall -import ControlService(long long ptr) # @ stub ControlServiceExA # @ stub ControlServiceExW @ stdcall -import ControlTraceA(int64 str ptr long) @@ -143,8 +143,8 @@ @ stdcall CreateProcessWithLogonW(wstr wstr wstr long wstr wstr long ptr wstr ptr ptr) @ stdcall CreateProcessWithTokenW(long long wstr wstr long ptr wstr ptr ptr) @ stdcall -import CreateRestrictedToken(long long long ptr long ptr long ptr ptr) -@ stdcall CreateServiceA(long str str long long long long str str ptr str str str) -@ stdcall CreateServiceW(long wstr wstr long long long long wstr wstr ptr wstr wstr wstr) +@ stdcall -import CreateServiceA(long str str long long long long str str ptr str str str) +@ stdcall -import CreateServiceW(long wstr wstr long long long long wstr wstr ptr wstr wstr wstr) # @ stub CreateTraceInstanceId @ stdcall -import CreateWellKnownSid(long ptr ptr ptr) # @ stub CredBackupCredentials @@ -235,7 +235,7 @@ @ stdcall DecryptFileA(str long) @ stdcall DecryptFileW(wstr long) @ stdcall -import DeleteAce(ptr long) -@ stdcall DeleteService(long) +@ stdcall -import DeleteService(long) @ stdcall DeregisterEventSource(long) @ stdcall -import DestroyPrivateObjectSecurity(ptr) # @ stub DuplicateEncryptionInfoFile @@ -271,13 +271,13 @@ # @ stub EncryptedFileKeyInfo # @ stub EncryptionDisable @ stdcall EnumDependentServicesA(long long ptr long ptr ptr) -@ stdcall EnumDependentServicesW(long long ptr long ptr ptr) +@ stdcall -import EnumDependentServicesW(long long ptr long ptr ptr) @ stdcall -import EnumDynamicTimeZoneInformation(long ptr) @ stub EnumServiceGroupA @ stub EnumServiceGroupW @ stdcall EnumServicesStatusA (long long long ptr long ptr ptr ptr) @ stdcall EnumServicesStatusExA(long long long long ptr long ptr ptr ptr str) -@ stdcall EnumServicesStatusExW(long long long long ptr long ptr ptr ptr wstr) +@ stdcall -import EnumServicesStatusExW(long long long long ptr long ptr ptr ptr wstr) @ stdcall EnumServicesStatusW (long long long ptr long ptr ptr ptr) @ stdcall EnumerateTraceGuids(ptr long ptr) # @ stub EnumerateTraceGuidsEx @@ -361,9 +361,9 @@ @ stdcall GetSecurityInfoExA (long long long str str ptr ptr ptr ptr) @ stdcall GetSecurityInfoExW (long long long wstr wstr ptr ptr ptr ptr) @ stdcall GetServiceDisplayNameA(ptr str ptr ptr) -@ stdcall GetServiceDisplayNameW(ptr wstr ptr ptr) +@ stdcall -import GetServiceDisplayNameW(ptr wstr ptr ptr) @ stdcall GetServiceKeyNameA(long str ptr ptr) -@ stdcall GetServiceKeyNameW(long wstr ptr ptr) +@ stdcall -import GetServiceKeyNameW(long wstr ptr ptr) @ stdcall -import GetSidIdentifierAuthority(ptr) @ stdcall -import GetSidLengthRequired(long) @ stdcall -import GetSidSubAuthority(ptr long) @@ -526,7 +526,7 @@ @ stdcall NotifyChangeEventLog (long long) # @ stub NotifyServiceStatusChange # @ stub NotifyServiceStatusChangeA -@ stdcall NotifyServiceStatusChangeW(ptr long ptr) +@ stdcall -import NotifyServiceStatusChangeW(ptr long ptr) # @ stub NpGetUserName @ stdcall ObjectCloseAuditAlarmA(str ptr long) @ stdcall -import ObjectCloseAuditAlarmW(wstr ptr long) @@ -543,10 +543,10 @@ @ stdcall OpenEventLogA (str str) @ stdcall OpenEventLogW (wstr wstr) @ stdcall -import OpenProcessToken(long long ptr) -@ stdcall OpenSCManagerA(str str long) -@ stdcall OpenSCManagerW(wstr wstr long) -@ stdcall OpenServiceA(long str long) -@ stdcall OpenServiceW(long wstr long) +@ stdcall -import OpenSCManagerA(str str long) +@ stdcall -import OpenSCManagerW(wstr wstr long) +@ stdcall -import OpenServiceA(long str long) +@ stdcall -import OpenServiceW(long wstr long) @ stdcall -import OpenThreadToken(long long long ptr) # @ stub OpenThreadWaitChainSession @ stdcall -ret64 OpenTraceA(ptr) @@ -593,16 +593,16 @@ # @ stub QueryLocalUserServiceName # @ stub QueryRecoveryAgentsOnEncryptedFile # @ stub QuerySecurityAccessMask -@ stdcall QueryServiceConfig2A(long long ptr long ptr) -@ stdcall QueryServiceConfig2W(long long ptr long ptr) -@ stdcall QueryServiceConfigA(long ptr long ptr) -@ stdcall QueryServiceConfigW(long ptr long ptr) +@ stdcall -import QueryServiceConfig2A(long long ptr long ptr) +@ stdcall -import QueryServiceConfig2W(long long ptr long ptr) +@ stdcall -import QueryServiceConfigA(long ptr long ptr) +@ stdcall -import QueryServiceConfigW(long ptr long ptr) # @ stub QueryServiceDynamicInformation @ stdcall QueryServiceLockStatusA(long ptr long ptr) @ stdcall QueryServiceLockStatusW(long ptr long ptr) -@ stdcall QueryServiceObjectSecurity(long long ptr long ptr) -@ stdcall QueryServiceStatus(long ptr) -@ stdcall QueryServiceStatusEx (long long ptr long ptr) +@ stdcall -import QueryServiceObjectSecurity(long long ptr long ptr) +@ stdcall -import QueryServiceStatus(long ptr) +@ stdcall -import QueryServiceStatusEx (long long ptr long ptr) # @ stub QueryTraceA @ stdcall QueryTraceW(int64 wstr ptr) # @ stub QueryUserServiceName @@ -697,10 +697,10 @@ @ stdcall RegisterEventSourceA(str str) @ stdcall RegisterEventSourceW(wstr wstr) # @ stub RegisterIdleTask -@ stdcall RegisterServiceCtrlHandlerA(str ptr) -@ stdcall RegisterServiceCtrlHandlerExA(str ptr ptr) -@ stdcall RegisterServiceCtrlHandlerExW(wstr ptr ptr) -@ stdcall RegisterServiceCtrlHandlerW(wstr ptr) +@ stdcall -import RegisterServiceCtrlHandlerA(str ptr) +@ stdcall -import RegisterServiceCtrlHandlerExA(str ptr ptr) +@ stdcall -import RegisterServiceCtrlHandlerExW(wstr ptr ptr) +@ stdcall -import RegisterServiceCtrlHandlerW(wstr ptr) @ stdcall RegisterTraceGuidsA(ptr ptr ptr long ptr str str ptr) ntdll.EtwRegisterTraceGuidsA @ stdcall RegisterTraceGuidsW(ptr ptr ptr long ptr wstr wstr ptr) ntdll.EtwRegisterTraceGuidsW @ stdcall RegisterWaitChainCOMCallback(ptr ptr) @@ -761,17 +761,17 @@ # @ stub SetSecurityInfoExA # @ stub SetSecurityInfoExW @ stdcall SetServiceBits(long long long long) -@ stdcall SetServiceObjectSecurity(long long ptr) -@ stdcall SetServiceStatus(long ptr) +@ stdcall -import SetServiceObjectSecurity(long long ptr) +@ stdcall -import SetServiceStatus(long ptr) @ stdcall -import SetThreadToken(ptr ptr) @ stdcall -import SetTokenInformation(long long ptr long) # @ stub SetTraceCallback # @ stub SetUserFileEncryptionKey # @ stub SetUserFileEncryptionKeyEx -@ stdcall StartServiceA(long long ptr) -@ stdcall StartServiceCtrlDispatcherA(ptr) -@ stdcall StartServiceCtrlDispatcherW(ptr) -@ stdcall StartServiceW(long long ptr) +@ stdcall -import StartServiceA(long long ptr) +@ stdcall -import StartServiceCtrlDispatcherA(ptr) +@ stdcall -import StartServiceCtrlDispatcherW(ptr) +@ stdcall -import StartServiceW(long long ptr) @ stdcall -import StartTraceA(ptr str ptr) @ stdcall -import StartTraceW(ptr wstr ptr) @ stdcall StopTraceA(int64 str ptr) diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c index eb195d84d05..2146ddfb186 100644 --- a/dlls/advapi32/service.c +++ b/dlls/advapi32/service.c @@ -20,1661 +20,34 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "config.h" -#include "wine/port.h" - -#include <stdarg.h> -#include <string.h> -#include <time.h> -#include <assert.h> - -#define NONAMELESSUNION - -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "windef.h" -#include "winbase.h" -#include "winsvc.h" -#include "winerror.h" -#include "winreg.h" -#include "wine/unicode.h" -#include "wine/debug.h" -#include "winternl.h" -#include "lmcons.h" -#include "lmserver.h" - -#include "svcctl.h" - -#include "advapi32_misc.h" - -#include "wine/exception.h" -#include "wine/list.h" - -WINE_DEFAULT_DEBUG_CHANNEL(service); - -void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len) -{ - return heap_alloc(len); -} - -void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr) -{ - heap_free(ptr); -} - -typedef struct service_data_t -{ - LPHANDLER_FUNCTION_EX handler; - LPVOID context; - HANDLE thread; - SC_HANDLE handle; - SC_HANDLE full_access_handle; - BOOL unicode : 1; - union { - LPSERVICE_MAIN_FUNCTIONA a; - LPSERVICE_MAIN_FUNCTIONW w; - } proc; - LPWSTR args; - WCHAR name[1]; -} service_data; - -typedef struct dispatcher_data_t -{ - SC_HANDLE manager; - HANDLE pipe; -} dispatcher_data; - -typedef struct notify_data_t { - SC_HANDLE service; - SC_RPC_NOTIFY_PARAMS params; - SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 cparams; - SC_NOTIFY_RPC_HANDLE notify_handle; - SERVICE_NOTIFYW *notify_buffer; - HANDLE calling_thread, ready_evt; - struct list entry; -} notify_data; - -static struct list notify_list = LIST_INIT(notify_list); - -static CRITICAL_SECTION service_cs; -static CRITICAL_SECTION_DEBUG service_cs_debug = -{ - 0, 0, &service_cs, - { &service_cs_debug.ProcessLocksList, - &service_cs_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") } -}; -static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 }; - -static service_data **services; -static unsigned int nb_services; -static HANDLE service_event; -static BOOL stop_service; - -extern HANDLE CDECL __wine_make_process_system(void); - -static inline LPWSTR SERV_dupmulti(LPCSTR str) -{ - UINT len = 0, n = 0; - LPWSTR wstr; - - if( !str ) - return NULL; - do { - len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 ); - n += (strlen( &str[n] ) + 1); - } while (str[n]); - len++; - n++; - - wstr = heap_alloc( len*sizeof (WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len ); - return wstr; -} - -static inline DWORD multisz_cb(LPCWSTR wmultisz) -{ - const WCHAR *wptr = wmultisz; - - if (wmultisz == NULL) - return 0; - - while (*wptr) - wptr += lstrlenW(wptr)+1; - return (wptr - wmultisz + 1)*sizeof(WCHAR); -} - -/****************************************************************************** - * RPC connection with services.exe - */ -static handle_t rpc_wstr_bind(RPC_WSTR str) -{ - WCHAR transport[] = SVCCTL_TRANSPORT; - WCHAR endpoint[] = SVCCTL_ENDPOINT; - RPC_WSTR binding_str; - RPC_STATUS status; - handle_t rpc_handle; - - status = RpcStringBindingComposeW(NULL, transport, str, endpoint, NULL, &binding_str); - if (status != RPC_S_OK) - { - ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status); - return NULL; - } - - status = RpcBindingFromStringBindingW(binding_str, &rpc_handle); - RpcStringFreeW(&binding_str); - - if (status != RPC_S_OK) - { - ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status); - return NULL; - } - - return rpc_handle; -} - -static handle_t rpc_cstr_bind(RPC_CSTR str) -{ - RPC_CSTR transport = (RPC_CSTR)SVCCTL_TRANSPORTA; - RPC_CSTR endpoint = (RPC_CSTR)SVCCTL_ENDPOINTA; - RPC_CSTR binding_str; - RPC_STATUS status; - handle_t rpc_handle; - - status = RpcStringBindingComposeA(NULL, transport, str, endpoint, NULL, &binding_str); - if (status != RPC_S_OK) - { - ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status); - return NULL; - } - - status = RpcBindingFromStringBindingA(binding_str, &rpc_handle); - RpcStringFreeA(&binding_str); - - if (status != RPC_S_OK) - { - ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status); - return NULL; - } - - return rpc_handle; -} - -DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEA_bind(MACHINE_HANDLEA MachineName) -{ - return rpc_cstr_bind((RPC_CSTR)MachineName); -} - -DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEA_unbind(MACHINE_HANDLEA MachineName, handle_t h) -{ - RpcBindingFree(&h); -} - -DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName) -{ - return rpc_wstr_bind((RPC_WSTR)MachineName); -} - -DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h) -{ - RpcBindingFree(&h); -} - -DECLSPEC_HIDDEN handle_t __RPC_USER SVCCTL_HANDLEW_bind(SVCCTL_HANDLEW MachineName) -{ - return rpc_wstr_bind((RPC_WSTR)MachineName); -} - -DECLSPEC_HIDDEN void __RPC_USER SVCCTL_HANDLEW_unbind(SVCCTL_HANDLEW MachineName, handle_t h) -{ - RpcBindingFree(&h); -} - -static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr) -{ - return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode); -} - -static DWORD map_exception_code(DWORD exception_code) -{ - switch (exception_code) - { - case RPC_X_NULL_REF_POINTER: - return ERROR_INVALID_ADDRESS; - case RPC_X_ENUM_VALUE_OUT_OF_RANGE: - case RPC_X_BYTE_COUNT_TOO_SMALL: - return ERROR_INVALID_PARAMETER; - case RPC_S_INVALID_BINDING: - case RPC_X_SS_IN_NULL_CONTEXT: - return ERROR_INVALID_HANDLE; - default: - return exception_code; - } -} - -/****************************************************************************** - * Service IPC functions - */ -static LPWSTR service_get_pipe_name(void) -{ - static const WCHAR format[] = { '\\','\\','.','\\','p','i','p','e','\\', - 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0}; - static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\', - 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', - 'C','o','n','t','r','o','l','\\', - 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0}; - LPWSTR name; - DWORD len; - HKEY service_current_key; - DWORD service_current; - LONG ret; - DWORD type; - - ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0, - KEY_QUERY_VALUE, &service_current_key); - if (ret != ERROR_SUCCESS) - return NULL; - len = sizeof(service_current); - ret = RegQueryValueExW(service_current_key, NULL, NULL, &type, - (BYTE *)&service_current, &len); - RegCloseKey(service_current_key); - if (ret != ERROR_SUCCESS || type != REG_DWORD) - return NULL; - len = ARRAY_SIZE(format) + 10 /* strlenW("4294967295") */; - name = heap_alloc(len * sizeof(WCHAR)); - if (!name) - return NULL; - snprintfW(name, len, format, service_current); - return name; -} - -static HANDLE service_open_pipe(void) -{ - LPWSTR szPipe = service_get_pipe_name(); - HANDLE handle = INVALID_HANDLE_VALUE; - - do { - handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE, - 0, NULL, OPEN_ALWAYS, 0, NULL); - if (handle != INVALID_HANDLE_VALUE) - break; - if (GetLastError() != ERROR_PIPE_BUSY) - break; - } while (WaitNamedPipeW(szPipe, NMPWAIT_USE_DEFAULT_WAIT)); - heap_free(szPipe); - - return handle; -} - -static service_data *find_service_by_name( const WCHAR *name ) -{ - unsigned int i; - - if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */ - return services[0]; - for (i = 0; i < nb_services; i++) - if (!strcmpiW( name, services[i]->name )) return services[i]; - return NULL; -} - -/****************************************************************************** - * service_thread - * - * Call into the main service routine provided by StartServiceCtrlDispatcher. - */ -static DWORD WINAPI service_thread(LPVOID arg) -{ - service_data *info = arg; - LPWSTR str = info->args; - DWORD argc = 0, len = 0; - - TRACE("%p\n", arg); - - while (str[len]) - { - len += strlenW(&str[len]) + 1; - argc++; - } - len++; - - if (info->unicode) - { - LPWSTR *argv, p; - - argv = heap_alloc((argc+1)*sizeof(LPWSTR)); - for (argc=0, p=str; *p; p += strlenW(p) + 1) - argv[argc++] = p; - argv[argc] = NULL; - - info->proc.w(argc, argv); - heap_free(argv); - } - else - { - LPSTR strA, *argv, p; - DWORD lenA; - - lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL); - strA = heap_alloc(lenA); - WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL); - - argv = heap_alloc((argc+1)*sizeof(LPSTR)); - for (argc=0, p=strA; *p; p += strlen(p) + 1) - argv[argc++] = p; - argv[argc] = NULL; - - info->proc.a(argc, argv); - heap_free(argv); - heap_free(strA); - } - return 0; -} - -/****************************************************************************** - * service_handle_start - */ -static DWORD service_handle_start(service_data *service, const void *data, DWORD data_size) -{ - DWORD count = data_size / sizeof(WCHAR); - - if (service->thread) - { - WARN("service is not stopped\n"); - return ERROR_SERVICE_ALREADY_RUNNING; - } - - heap_free(service->args); - service->args = heap_alloc((count + 2) * sizeof(WCHAR)); - if (count) memcpy( service->args, data, count * sizeof(WCHAR) ); - service->args[count++] = 0; - service->args[count++] = 0; - - service->thread = CreateThread( NULL, 0, service_thread, - service, 0, NULL ); - SetEvent( service_event ); /* notify the main loop */ - return 0; -} - -/****************************************************************************** - * service_handle_control - */ -static DWORD service_handle_control(service_data *service, DWORD control, const void *data, DWORD data_size) -{ - DWORD ret = ERROR_INVALID_SERVICE_CONTROL; - - TRACE("%s control %u data %p data_size %u\n", debugstr_w(service->name), control, data, data_size); - - if (control == SERVICE_CONTROL_START) - ret = service_handle_start(service, data, data_size); - else if (service->handler) - ret = service->handler(control, 0, (void *)data, service->context); - return ret; -} - -/****************************************************************************** - * service_control_dispatcher - */ -static DWORD WINAPI service_control_dispatcher(LPVOID arg) -{ - dispatcher_data *disp = arg; - - /* dispatcher loop */ - while (1) - { - service_data *service; - service_start_info info; - BYTE *data = NULL; - WCHAR *name; - BOOL r; - DWORD data_size = 0, count, result; - - r = ReadFile( disp->pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL ); - if (!r) - { - if (GetLastError() != ERROR_BROKEN_PIPE) - ERR( "pipe read failed error %u\n", GetLastError() ); - break; - } - if (count != FIELD_OFFSET(service_start_info,data)) - { - ERR( "partial pipe read %u\n", count ); - break; - } - if (count < info.total_size) - { - data_size = info.total_size - FIELD_OFFSET(service_start_info,data); - data = heap_alloc( data_size ); - r = ReadFile( disp->pipe, data, data_size, &count, NULL ); - if (!r) - { - if (GetLastError() != ERROR_BROKEN_PIPE) - ERR( "pipe read failed error %u\n", GetLastError() ); - heap_free( data ); - break; - } - if (count != data_size) - { - ERR( "partial pipe read %u/%u\n", count, data_size ); - heap_free( data ); - break; - } - } - - EnterCriticalSection( &service_cs ); - - /* validate service name */ - name = (WCHAR *)data; - if (!info.name_size || data_size < info.name_size * sizeof(WCHAR) || name[info.name_size - 1]) - { - ERR( "got request without valid service name\n" ); - result = ERROR_INVALID_PARAMETER; - goto done; - } - - if (info.magic != SERVICE_PROTOCOL_MAGIC) - { - ERR( "received invalid request for service %s\n", debugstr_w(name) ); - result = ERROR_INVALID_PARAMETER; - goto done; - } - - /* find the service */ - if (!(service = find_service_by_name( name ))) - { - FIXME( "got request for unknown service %s\n", debugstr_w(name) ); - result = ERROR_INVALID_PARAMETER; - goto done; - } - - if (!service->handle) - { - if (!(service->handle = OpenServiceW( disp->manager, name, SERVICE_SET_STATUS )) || - !(service->full_access_handle = OpenServiceW( disp->manager, name, - GENERIC_READ|GENERIC_WRITE ))) - FIXME( "failed to open service %s\n", debugstr_w(name) ); - } - - data_size -= info.name_size * sizeof(WCHAR); - result = service_handle_control(service, info.control, data_size ? - &data[info.name_size * sizeof(WCHAR)] : NULL, data_size); - - done: - LeaveCriticalSection( &service_cs ); - WriteFile( disp->pipe, &result, sizeof(result), &count, NULL ); - heap_free( data ); - } - - CloseHandle( disp->pipe ); - CloseServiceHandle( disp->manager ); - heap_free( disp ); - return 1; -} - -/* wait for services which accept this type of message to become STOPPED */ -static void handle_shutdown_msg(DWORD msg, DWORD accept) -{ - SERVICE_STATUS st; - SERVICE_PRESHUTDOWN_INFO spi; - DWORD i, n = 0, sz, timeout = 2000; - ULONGLONG stop_time; - BOOL res, done = TRUE; - SC_HANDLE *wait_handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SC_HANDLE) * nb_services ); - - EnterCriticalSection( &service_cs ); - for (i = 0; i < nb_services; i++) - { - res = QueryServiceStatus( services[i]->full_access_handle, &st ); - if (!res || st.dwCurrentState == SERVICE_STOPPED || !(st.dwControlsAccepted & accept)) - continue; - - done = FALSE; - - if (accept == SERVICE_ACCEPT_PRESHUTDOWN) - { - res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO, - (LPBYTE)&spi, sizeof(spi), &sz ); - if (res) - { - FIXME( "service should be able to delay shutdown\n" ); - timeout = max( spi.dwPreshutdownTimeout, timeout ); - } - } - - service_handle_control( services[i], msg, NULL, 0 ); - wait_handles[n++] = services[i]->full_access_handle; - } - LeaveCriticalSection( &service_cs ); - - /* FIXME: these timeouts should be more generous, but we can't currently delay prefix shutdown */ - timeout = min( timeout, 3000 ); - stop_time = GetTickCount64() + timeout; - - while (!done && GetTickCount64() < stop_time) - { - done = TRUE; - for (i = 0; i < n; i++) - { - res = QueryServiceStatus( wait_handles[i], &st ); - if (!res || st.dwCurrentState == SERVICE_STOPPED) - continue; - - done = FALSE; - Sleep( 100 ); - break; - } - } - - HeapFree( GetProcessHeap(), 0, wait_handles ); -} - -/****************************************************************************** - * service_run_main_thread - */ -static BOOL service_run_main_thread(void) -{ - DWORD i, n, ret; - HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS]; - UINT wait_services[MAXIMUM_WAIT_OBJECTS]; - dispatcher_data *disp = heap_alloc( sizeof(*disp) ); - - disp->manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT ); - if (!disp->manager) - { - ERR("failed to open service manager error %u\n", GetLastError()); - heap_free( disp ); - return FALSE; - } - - disp->pipe = service_open_pipe(); - if (disp->pipe == INVALID_HANDLE_VALUE) - { - WARN("failed to create control pipe error %u\n", GetLastError()); - CloseServiceHandle( disp->manager ); - heap_free( disp ); - SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT ); - return FALSE; - } - - service_event = CreateEventW( NULL, FALSE, FALSE, NULL ); - stop_service = FALSE; - - /* FIXME: service_control_dispatcher should be merged into the main thread */ - wait_handles[0] = __wine_make_process_system(); - wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, disp, 0, NULL ); - wait_handles[2] = service_event; - - TRACE("Starting %d services running as process %d\n", - nb_services, GetCurrentProcessId()); - - /* wait for all the threads to pack up and exit */ - while (!stop_service) - { - EnterCriticalSection( &service_cs ); - for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++) - { - if (!services[i]->thread) continue; - wait_services[n] = i; - wait_handles[n++] = services[i]->thread; - } - LeaveCriticalSection( &service_cs ); - - ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE ); - if (!ret) /* system process event */ - { - handle_shutdown_msg(SERVICE_CONTROL_PRESHUTDOWN, SERVICE_ACCEPT_PRESHUTDOWN); - handle_shutdown_msg(SERVICE_CONTROL_SHUTDOWN, SERVICE_ACCEPT_SHUTDOWN); - ExitProcess(0); - } - else if (ret == 1) - { - TRACE( "control dispatcher exited, shutting down\n" ); - /* FIXME: we should maybe send a shutdown control to running services */ - ExitProcess(0); - } - else if (ret == 2) - { - continue; /* rebuild the list */ - } - else if (ret < n) - { - i = wait_services[ret]; - EnterCriticalSection( &service_cs ); - CloseHandle( services[i]->thread ); - services[i]->thread = NULL; - LeaveCriticalSection( &service_cs ); - } - else return FALSE; - } - - return TRUE; -} - -/****************************************************************************** - * StartServiceCtrlDispatcherA [ADVAPI32.@] - * - * See StartServiceCtrlDispatcherW. - */ -BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent ) -{ - service_data *info; - unsigned int i; - - TRACE("%p\n", servent); - - if (nb_services) - { - SetLastError( ERROR_SERVICE_ALREADY_RUNNING ); - return FALSE; - } - while (servent[nb_services].lpServiceName) nb_services++; - if (!nb_services) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return FALSE; - } - - services = heap_alloc( nb_services * sizeof(*services) ); - - for (i = 0; i < nb_services; i++) - { - DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0); - DWORD sz = FIELD_OFFSET( service_data, name[len] ); - info = heap_alloc_zero( sz ); - MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len); - info->proc.a = servent[i].lpServiceProc; - info->unicode = FALSE; - services[i] = info; - } - - return service_run_main_thread(); -} - -/****************************************************************************** - * StartServiceCtrlDispatcherW [ADVAPI32.@] - * - * Connects a process containing one or more services to the service control - * manager. - * - * PARAMS - * servent [I] A list of the service names and service procedures - * - * RETURNS - * Success: TRUE. - * Failure: FALSE. - */ -BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent ) -{ - service_data *info; - unsigned int i; - - TRACE("%p\n", servent); - - if (nb_services) - { - SetLastError( ERROR_SERVICE_ALREADY_RUNNING ); - return FALSE; - } - while (servent[nb_services].lpServiceName) nb_services++; - if (!nb_services) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return FALSE; - } - - services = heap_alloc( nb_services * sizeof(*services) ); - - for (i = 0; i < nb_services; i++) - { - DWORD len = strlenW(servent[i].lpServiceName) + 1; - DWORD sz = FIELD_OFFSET( service_data, name[len] ); - info = heap_alloc_zero( sz ); - strcpyW(info->name, servent[i].lpServiceName); - info->proc.w = servent[i].lpServiceProc; - info->unicode = TRUE; - services[i] = info; - } - - return service_run_main_thread(); -} - -/****************************************************************************** - * LockServiceDatabase [ADVAPI32.@] - */ -SC_LOCK WINAPI LockServiceDatabase( SC_HANDLE manager ) -{ - /* this function is a no-op in Vista and above */ - TRACE("%p\n", manager); - return (SC_LOCK)0xdeadbeef; -} - -/****************************************************************************** - * UnlockServiceDatabase [ADVAPI32.@] - */ -BOOL WINAPI UnlockServiceDatabase( SC_LOCK lock ) -{ - /* this function is a no-op in Vista and above */ - TRACE("%p\n", lock); - return TRUE; -} - -/****************************************************************************** - * SetServiceStatus [ADVAPI32.@] - * - * PARAMS - * hService [] - * lpStatus [] - */ -BOOL WINAPI -SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus ) -{ - DWORD err; - - TRACE("%p %x %x %x %x %x %x %x\n", hService, - lpStatus->dwServiceType, lpStatus->dwCurrentState, - lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode, - lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint, - lpStatus->dwWaitHint); - - __TRY - { - err = svcctl_SetServiceStatus( hService, lpStatus ); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - if (err != ERROR_SUCCESS) - { - SetLastError(err); - return FALSE; - } - - if (lpStatus->dwCurrentState == SERVICE_STOPPED) - { - unsigned int i, count = 0; - EnterCriticalSection( &service_cs ); - for (i = 0; i < nb_services; i++) - { - if (services[i]->handle == (SC_HANDLE)hService) continue; - if (services[i]->thread) count++; - } - if (!count) - { - stop_service = TRUE; - SetEvent( service_event ); /* notify the main loop */ - } - LeaveCriticalSection( &service_cs ); - } - - return TRUE; -} - - -/****************************************************************************** - * OpenSCManagerA [ADVAPI32.@] - * - * Establish a connection to the service control manager and open its database. - * - * PARAMS - * lpMachineName [I] Pointer to machine name string - * lpDatabaseName [I] Pointer to database name string - * dwDesiredAccess [I] Type of access - * - * RETURNS - * Success: A Handle to the service control manager database - * Failure: NULL - */ -SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName, - DWORD dwDesiredAccess ) -{ - LPWSTR machineW, databaseW; - SC_HANDLE ret; - - machineW = strdupAW(lpMachineName); - databaseW = strdupAW(lpDatabaseName); - ret = OpenSCManagerW(machineW, databaseW, dwDesiredAccess); - heap_free(databaseW); - heap_free(machineW); - return ret; -} - -/****************************************************************************** - * OpenSCManagerW [ADVAPI32.@] - * - * See OpenSCManagerA. - */ -static DWORD SERV_OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName, - DWORD dwDesiredAccess, SC_HANDLE *handle ) -{ - DWORD r; - - TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName), - debugstr_w(lpDatabaseName), dwDesiredAccess); - - __TRY - { - r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, (SC_RPC_HANDLE *)handle); - } - __EXCEPT(rpc_filter) - { - r = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - if (r!=ERROR_SUCCESS) - *handle = 0; - - TRACE("returning %p\n", *handle); - return r; -} - -SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName, - DWORD dwDesiredAccess ) -{ - SC_HANDLE handle = 0; - DWORD r; - - r = SERV_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, &handle); - if (r!=ERROR_SUCCESS) - SetLastError(r); - return handle; -} - -/****************************************************************************** - * ControlService [ADVAPI32.@] - * - * Send a control code to a service. - * - * PARAMS - * hService [I] Handle of the service control manager database - * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h") - * lpServiceStatus [O] Destination for the status of the service, if available - * - * RETURNS - * Success: TRUE. - * Failure: FALSE. - * - * BUGS - * Unlike M$' implementation, control requests are not serialized and may be - * processed asynchronously. - */ -BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl, - LPSERVICE_STATUS lpServiceStatus ) -{ - DWORD err; - - TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus); - - __TRY - { - err = svcctl_ControlService(hService, dwControl, lpServiceStatus); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - if (err != ERROR_SUCCESS) - { - SetLastError(err); - return FALSE; - } - - return TRUE; -} - -/****************************************************************************** - * CloseServiceHandle [ADVAPI32.@] - * - * Close a handle to a service or the service control manager database. - * - * PARAMS - * hSCObject [I] Handle to service or service control manager database - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI -CloseServiceHandle( SC_HANDLE hSCObject ) -{ - DWORD err; - - TRACE("%p\n", hSCObject); - - __TRY - { - err = svcctl_CloseServiceHandle((SC_RPC_HANDLE *)&hSCObject); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - if (err != ERROR_SUCCESS) - { - SetLastError(err); - return FALSE; - } - return TRUE; -} - - -/****************************************************************************** - * OpenServiceA [ADVAPI32.@] - * - * Open a handle to a service. - * - * PARAMS - * hSCManager [I] Handle of the service control manager database - * lpServiceName [I] Name of the service to open - * dwDesiredAccess [I] Access required to the service - * - * RETURNS - * Success: Handle to the service - * Failure: NULL - */ -SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName, - DWORD dwDesiredAccess ) -{ - LPWSTR lpServiceNameW; - SC_HANDLE ret; - - TRACE("%p %s 0x%08x\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess); - - lpServiceNameW = strdupAW(lpServiceName); - ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess); - heap_free(lpServiceNameW); - return ret; -} - - -/****************************************************************************** - * OpenServiceW [ADVAPI32.@] - * - * See OpenServiceA. - */ -static DWORD SERV_OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName, - DWORD dwDesiredAccess, SC_HANDLE *handle ) -{ - DWORD err; - - TRACE("%p %s 0x%08x\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess); - - if (!hSCManager) - return ERROR_INVALID_HANDLE; - - __TRY - { - err = svcctl_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, (SC_RPC_HANDLE *)handle); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - if (err != ERROR_SUCCESS) - *handle = 0; - - TRACE("returning %p\n", *handle); - return err; -} - -SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName, - DWORD dwDesiredAccess) -{ - SC_HANDLE handle = 0; - DWORD err; - - err = SERV_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, &handle); - if (err != ERROR_SUCCESS) - SetLastError(err); - return handle; -} - -/****************************************************************************** - * CreateServiceW [ADVAPI32.@] - */ -SC_HANDLE WINAPI -CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName, - LPCWSTR lpDisplayName, DWORD dwDesiredAccess, - DWORD dwServiceType, DWORD dwStartType, - DWORD dwErrorControl, LPCWSTR lpBinaryPathName, - LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, - LPCWSTR lpDependencies, LPCWSTR lpServiceStartName, - LPCWSTR lpPassword ) -{ - SC_HANDLE handle = 0; - DWORD err; - SIZE_T passwdlen; - - TRACE("%p %s %s\n", hSCManager, - debugstr_w(lpServiceName), debugstr_w(lpDisplayName)); - - if (!hSCManager) - { - SetLastError( ERROR_INVALID_HANDLE ); - return 0; - } - - if (lpPassword) - passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR); - else - passwdlen = 0; - - __TRY - { - BOOL is_wow64; - - IsWow64Process(GetCurrentProcess(), &is_wow64); - - if (is_wow64) - err = svcctl_CreateServiceWOW64W(hSCManager, lpServiceName, - lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl, - lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies, - multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen, - (SC_RPC_HANDLE *)&handle); - else - err = svcctl_CreateServiceW(hSCManager, lpServiceName, - lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl, - lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies, - multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen, - (SC_RPC_HANDLE *)&handle); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - if (err != ERROR_SUCCESS) - { - SetLastError(err); - handle = 0; - } - return handle; -} - - -/****************************************************************************** - * CreateServiceA [ADVAPI32.@] - */ -SC_HANDLE WINAPI -CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName, - LPCSTR lpDisplayName, DWORD dwDesiredAccess, - DWORD dwServiceType, DWORD dwStartType, - DWORD dwErrorControl, LPCSTR lpBinaryPathName, - LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, - LPCSTR lpDependencies, LPCSTR lpServiceStartName, - LPCSTR lpPassword ) -{ - LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW, - lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW; - SC_HANDLE r; - - TRACE("%p %s %s\n", hSCManager, - debugstr_a(lpServiceName), debugstr_a(lpDisplayName)); - - lpServiceNameW = strdupAW( lpServiceName ); - lpDisplayNameW = strdupAW( lpDisplayName ); - lpBinaryPathNameW = strdupAW( lpBinaryPathName ); - lpLoadOrderGroupW = strdupAW( lpLoadOrderGroup ); - lpDependenciesW = SERV_dupmulti( lpDependencies ); - lpServiceStartNameW = strdupAW( lpServiceStartName ); - lpPasswordW = strdupAW( lpPassword ); - - r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW, - dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl, - lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId, - lpDependenciesW, lpServiceStartNameW, lpPasswordW ); - - heap_free( lpServiceNameW ); - heap_free( lpDisplayNameW ); - heap_free( lpBinaryPathNameW ); - heap_free( lpLoadOrderGroupW ); - heap_free( lpDependenciesW ); - heap_free( lpServiceStartNameW ); - heap_free( lpPasswordW ); - - return r; -} - - -/****************************************************************************** - * DeleteService [ADVAPI32.@] - * - * Delete a service from the service control manager database. - * - * PARAMS - * hService [I] Handle of the service to delete - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DeleteService( SC_HANDLE hService ) -{ - DWORD err; - - TRACE("%p\n", hService); - - __TRY - { - err = svcctl_DeleteService(hService); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - if (err != 0) - { - SetLastError(err); - return FALSE; - } - - return TRUE; -} - - -/****************************************************************************** - * StartServiceA [ADVAPI32.@] - * - * Start a service - * - * PARAMS - * hService [I] Handle of service - * dwNumServiceArgs [I] Number of arguments - * lpServiceArgVectors [I] Address of array of argument strings - * - * NOTES - * - NT implements this function using an obscure RPC call. - * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc - * to get things like "%SystemRoot%\\System32\\service.exe" to load. - * - This will only work for shared address space. How should the service - * args be transferred when address spaces are separated? - * - Can only start one service at a time. - * - Has no concept of privilege. - * - * RETURNS - * Success: TRUE. - * Failure: FALSE - */ -BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs, - LPCSTR *lpServiceArgVectors ) -{ - LPWSTR *lpwstr=NULL; - unsigned int i; - BOOL r; - - TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors); - - if (dwNumServiceArgs) - lpwstr = heap_alloc( dwNumServiceArgs*sizeof(LPWSTR) ); - - for(i=0; i<dwNumServiceArgs; i++) - lpwstr[i]=strdupAW(lpServiceArgVectors[i]); - - r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr); - - if (dwNumServiceArgs) - { - for(i=0; i<dwNumServiceArgs; i++) - heap_free(lpwstr[i]); - heap_free(lpwstr); - } - - return r; -} - - -/****************************************************************************** - * StartServiceW [ADVAPI32.@] - * - * See StartServiceA. - */ -BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs, - LPCWSTR *lpServiceArgVectors) -{ - DWORD err; - - TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors); - - __TRY - { - err = svcctl_StartServiceW(hService, dwNumServiceArgs, lpServiceArgVectors); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - if (err != ERROR_SUCCESS) - { - SetLastError(err); - return FALSE; - } - - return TRUE; -} - -/****************************************************************************** - * QueryServiceStatus [ADVAPI32.@] - * - * PARAMS - * hService [I] Handle to service to get information about - * lpservicestatus [O] buffer to receive the status information for the service - * - */ -BOOL WINAPI QueryServiceStatus(SC_HANDLE hService, - LPSERVICE_STATUS lpservicestatus) -{ - SERVICE_STATUS_PROCESS SvcStatusData; - BOOL ret; - DWORD dummy; - - TRACE("%p %p\n", hService, lpservicestatus); - - if (!hService) - { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - if (!lpservicestatus) - { - SetLastError(ERROR_INVALID_ADDRESS); - return FALSE; - } - - ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData, - sizeof(SERVICE_STATUS_PROCESS), &dummy); - if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ; - return ret; -} - - -/****************************************************************************** - * QueryServiceStatusEx [ADVAPI32.@] - * - * Get information about a service. - * - * PARAMS - * hService [I] Handle to service to get information about - * InfoLevel [I] Level of information to get - * lpBuffer [O] Destination for requested information - * cbBufSize [I] Size of lpBuffer in bytes - * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small - * - * RETURNS - * Success: TRUE - * FAILURE: FALSE - */ -BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel, - LPBYTE lpBuffer, DWORD cbBufSize, - LPDWORD pcbBytesNeeded) -{ - DWORD err; - - TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded); - - if (InfoLevel != SC_STATUS_PROCESS_INFO) - { - err = ERROR_INVALID_LEVEL; - } - else if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS)) - { - *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS); - err = ERROR_INSUFFICIENT_BUFFER; - } - else - { - __TRY - { - err = svcctl_QueryServiceStatusEx(hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - } - if (err != ERROR_SUCCESS) - { - SetLastError(err); - return FALSE; - } - return TRUE; -} - -/****************************************************************************** - * QueryServiceConfigA [ADVAPI32.@] - */ -BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config, - DWORD size, LPDWORD needed ) -{ - DWORD n; - LPSTR p, buffer; - BOOL ret; - QUERY_SERVICE_CONFIGW *configW; - - TRACE("%p %p %d %p\n", hService, config, size, needed); - - if (!(buffer = heap_alloc( 2 * size ))) - { - SetLastError( ERROR_NOT_ENOUGH_MEMORY ); - return FALSE; - } - configW = (QUERY_SERVICE_CONFIGW *)buffer; - ret = QueryServiceConfigW( hService, configW, 2 * size, needed ); - if (!ret) goto done; - - config->dwServiceType = configW->dwServiceType; - config->dwStartType = configW->dwStartType; - config->dwErrorControl = configW->dwErrorControl; - config->lpBinaryPathName = NULL; - config->lpLoadOrderGroup = NULL; - config->dwTagId = configW->dwTagId; - config->lpDependencies = NULL; - config->lpServiceStartName = NULL; - config->lpDisplayName = NULL; - - p = (LPSTR)(config + 1); - n = size - sizeof(*config); - ret = FALSE; - -#define MAP_STR(str) \ - do { \ - if (configW->str) \ - { \ - DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \ - if (!sz) goto done; \ - config->str = p; \ - p += sz; \ - n -= sz; \ - } \ - } while (0) - - MAP_STR( lpBinaryPathName ); - MAP_STR( lpLoadOrderGroup ); - MAP_STR( lpDependencies ); - MAP_STR( lpServiceStartName ); - MAP_STR( lpDisplayName ); -#undef MAP_STR - - *needed = p - (LPSTR)config; - ret = TRUE; - -done: - heap_free( buffer ); - return ret; -} - -static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr) -{ - DWORD cb; - - if (!*string_ptr) - { - cb = sizeof(WCHAR); - memset(*buf, 0, cb); - } - else - { - cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR); - memcpy(*buf, *string_ptr, cb); - MIDL_user_free(*string_ptr); - } - - *string_ptr = (LPWSTR)*buf; - *buf += cb; - - return cb; -} - -static DWORD size_string(LPCWSTR string) -{ - return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR)); -} - -/****************************************************************************** - * QueryServiceConfigW [ADVAPI32.@] - */ -BOOL WINAPI -QueryServiceConfigW( SC_HANDLE hService, - LPQUERY_SERVICE_CONFIGW lpServiceConfig, - DWORD cbBufSize, LPDWORD pcbBytesNeeded) -{ - QUERY_SERVICE_CONFIGW config; - DWORD total; - DWORD err; - BYTE *bufpos; - - TRACE("%p %p %d %p\n", hService, lpServiceConfig, - cbBufSize, pcbBytesNeeded); - - memset(&config, 0, sizeof(config)); - - __TRY - { - err = svcctl_QueryServiceConfigW(hService, &config, cbBufSize, pcbBytesNeeded); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - if (err != ERROR_SUCCESS) - { - TRACE("services.exe: error %u\n", err); - SetLastError(err); - return FALSE; - } - - /* calculate the size required first */ - total = sizeof (QUERY_SERVICE_CONFIGW); - total += size_string(config.lpBinaryPathName); - total += size_string(config.lpLoadOrderGroup); - total += size_string(config.lpDependencies); - total += size_string(config.lpServiceStartName); - total += size_string(config.lpDisplayName); - - *pcbBytesNeeded = total; - - /* if there's not enough memory, return an error */ - if( total > cbBufSize ) - { - SetLastError( ERROR_INSUFFICIENT_BUFFER ); - MIDL_user_free(config.lpBinaryPathName); - MIDL_user_free(config.lpLoadOrderGroup); - MIDL_user_free(config.lpDependencies); - MIDL_user_free(config.lpServiceStartName); - MIDL_user_free(config.lpDisplayName); - return FALSE; - } - - *lpServiceConfig = config; - bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW); - move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName); - move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup); - move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies); - move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName); - move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName); +#include <stdarg.h> +#include "windef.h" +#include "winbase.h" +#include "winsvc.h" +#include "wine/unicode.h" +#include "wine/debug.h" - TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) ); - TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) ); - TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) ); - TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) ); - TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) ); +#include "advapi32_misc.h" - return TRUE; -} +WINE_DEFAULT_DEBUG_CHANNEL(service); /****************************************************************************** - * QueryServiceConfig2A [ADVAPI32.@] - * - * Note - * observed under win2k: - * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same - * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION + * LockServiceDatabase [ADVAPI32.@] */ -BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer, - DWORD size, LPDWORD needed) +SC_LOCK WINAPI LockServiceDatabase( SC_HANDLE manager ) { - BOOL ret; - LPBYTE bufferW = NULL; - - TRACE("%p %u %p %u %p\n", hService, dwLevel, buffer, size, needed); - - if(buffer && size) - bufferW = heap_alloc(size); - - ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed); - if(!ret) goto cleanup; - - switch(dwLevel) { - case SERVICE_CONFIG_DESCRIPTION: - if (buffer && bufferW) { - LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer; - LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW; - if (configW->lpDescription && (size > sizeof(SERVICE_DESCRIPTIONA))) { - DWORD sz; - configA->lpDescription = (LPSTR)(configA + 1); - sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1, - configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL ); - if (!sz) { - FIXME("WideCharToMultiByte failed for configW->lpDescription\n"); - ret = FALSE; - configA->lpDescription = NULL; - } - } - else configA->lpDescription = NULL; - } - break; - case SERVICE_CONFIG_PRESHUTDOWN_INFO: - if (buffer && bufferW && *needed<=size) - memcpy(buffer, bufferW, *needed); - break; - default: - FIXME("conversation W->A not implemented for level %d\n", dwLevel); - ret = FALSE; - break; - } - -cleanup: - heap_free( bufferW); - return ret; + /* this function is a no-op in Vista and above */ + TRACE("%p\n", manager); + return (SC_LOCK)0xdeadbeef; } /****************************************************************************** - * QueryServiceConfig2W [ADVAPI32.@] - * - * See QueryServiceConfig2A. + * UnlockServiceDatabase [ADVAPI32.@] */ -BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer, - DWORD size, LPDWORD needed) +BOOL WINAPI UnlockServiceDatabase( SC_LOCK lock ) { - BYTE *bufptr; - DWORD err; - - TRACE("%p %u %p %u %p\n", hService, dwLevel, buffer, size, needed); - - if (!buffer && size) - { - SetLastError(ERROR_INVALID_ADDRESS); - return FALSE; - } - - switch (dwLevel) - { - case SERVICE_CONFIG_DESCRIPTION: - if (!(bufptr = heap_alloc( size ))) - { - SetLastError( ERROR_NOT_ENOUGH_MEMORY ); - return FALSE; - } - break; - - case SERVICE_CONFIG_PRESHUTDOWN_INFO: - bufptr = buffer; - break; - - default: - FIXME("Level %d not implemented\n", dwLevel); - SetLastError(ERROR_INVALID_LEVEL); - return FALSE; - } - - if (!needed) - { - if (dwLevel == SERVICE_CONFIG_DESCRIPTION) heap_free(bufptr); - SetLastError(ERROR_INVALID_ADDRESS); - return FALSE; - } - - __TRY - { - err = svcctl_QueryServiceConfig2W(hService, dwLevel, bufptr, size, needed); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - switch (dwLevel) - { - case SERVICE_CONFIG_DESCRIPTION: - { - SERVICE_DESCRIPTIONW *desc = (SERVICE_DESCRIPTIONW *)buffer; - struct service_description *s = (struct service_description *)bufptr; - - if (err != ERROR_SUCCESS && err != ERROR_INSUFFICIENT_BUFFER) - { - heap_free( bufptr ); - SetLastError( err ); - return FALSE; - } - - /* adjust for potentially larger SERVICE_DESCRIPTIONW structure */ - if (*needed == sizeof(*s)) *needed = sizeof(*desc); - else - *needed = *needed - FIELD_OFFSET(struct service_description, description) + sizeof(*desc); - - if (size < *needed) - { - heap_free( bufptr ); - SetLastError( ERROR_INSUFFICIENT_BUFFER ); - return FALSE; - } - if (desc) - { - if (!s->size) desc->lpDescription = NULL; - else - { - desc->lpDescription = (WCHAR *)(desc + 1); - memcpy( desc->lpDescription, s->description, s->size ); - } - } - heap_free( bufptr ); - break; - } - case SERVICE_CONFIG_PRESHUTDOWN_INFO: - if (err != ERROR_SUCCESS) - { - SetLastError( err ); - return FALSE; - } - break; - - default: - break; - } - + /* this function is a no-op in Vista and above */ + TRACE("%p\n", lock); return TRUE; } @@ -1871,158 +244,41 @@ EnumServicesStatusExA( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD st heap_free( servicesW ); return FALSE; } - MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) ); - } - - ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz, - needed, returned, resume_handle, groupW ); - if (!ret) goto done; - - p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA); - n = size - (p - (char *)services); - ret = FALSE; - for (i = 0; i < *returned; i++) - { - sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL ); - if (!sz) goto done; - services[i].lpServiceName = p; - p += sz; - n -= sz; - if (servicesW[i].lpDisplayName) - { - sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL ); - if (!sz) goto done; - services[i].lpDisplayName = p; - p += sz; - n -= sz; - } - else services[i].lpDisplayName = NULL; - services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess; - } - - ret = TRUE; - -done: - heap_free( servicesW ); - heap_free( groupW ); - return ret; -} - -/****************************************************************************** - * EnumServicesStatusExW [ADVAPI32.@] - */ -BOOL WINAPI -EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state, - LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned, - LPDWORD resume_handle, LPCWSTR group ) -{ - DWORD err, i, offset, buflen, count, total_size = 0; - ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer; - struct enum_service_status_process *entry; - const WCHAR *str; - BYTE *buf; - - TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer, - size, needed, returned, resume_handle, debugstr_w(group)); - - if (level != SC_ENUM_PROCESS_INFO) - { - SetLastError( ERROR_INVALID_LEVEL ); - return FALSE; - } - if (!hmngr) - { - SetLastError( ERROR_INVALID_HANDLE ); - return FALSE; - } - if (!needed || !returned) - { - SetLastError( ERROR_INVALID_ADDRESS ); - return FALSE; - } - - /* make sure we pass a valid pointer */ - buflen = max( size, sizeof(*services) ); - if (!(buf = heap_alloc( buflen ))) - { - SetLastError( ERROR_NOT_ENOUGH_MEMORY ); - return FALSE; - } - - __TRY - { - err = svcctl_EnumServicesStatusExW( hmngr, SC_ENUM_PROCESS_INFO, type, state, buf, buflen, needed, - &count, resume_handle, group ); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code( GetExceptionCode() ); - } - __ENDTRY - - *returned = 0; - if (err != ERROR_SUCCESS) - { - /* double the needed size to fit the potentially larger ENUM_SERVICE_STATUS_PROCESSW */ - if (err == ERROR_MORE_DATA) *needed *= 2; - heap_free( buf ); - SetLastError( err ); - return FALSE; - } - - entry = (struct enum_service_status_process *)buf; - for (i = 0; i < count; i++) - { - total_size += sizeof(*services); - if (entry->service_name) - { - str = (const WCHAR *)(buf + entry->service_name); - total_size += (strlenW( str ) + 1) * sizeof(WCHAR); - } - if (entry->display_name) - { - str = (const WCHAR *)(buf + entry->display_name); - total_size += (strlenW( str ) + 1) * sizeof(WCHAR); - } - entry++; - } - - if (total_size > size) - { - heap_free( buf ); - *needed = total_size; - SetLastError( ERROR_MORE_DATA ); - return FALSE; + MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) ); } - offset = count * sizeof(*services); - entry = (struct enum_service_status_process *)buf; - for (i = 0; i < count; i++) - { - DWORD str_size; - str = (const WCHAR *)(buf + entry->service_name); - str_size = (strlenW( str ) + 1) * sizeof(WCHAR); - services[i].lpServiceName = (WCHAR *)((char *)services + offset); - memcpy( services[i].lpServiceName, str, str_size ); - offset += str_size; + ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz, + needed, returned, resume_handle, groupW ); + if (!ret) goto done; - if (!entry->display_name) services[i].lpDisplayName = NULL; - else + p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA); + n = size - (p - (char *)services); + ret = FALSE; + for (i = 0; i < *returned; i++) + { + sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL ); + if (!sz) goto done; + services[i].lpServiceName = p; + p += sz; + n -= sz; + if (servicesW[i].lpDisplayName) { - str = (const WCHAR *)(buf + entry->display_name); - str_size = (strlenW( str ) + 1) * sizeof(WCHAR); - services[i].lpDisplayName = (WCHAR *)((char *)services + offset); - memcpy( services[i].lpDisplayName, str, str_size ); - offset += str_size; + sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL ); + if (!sz) goto done; + services[i].lpDisplayName = p; + p += sz; + n -= sz; } - services[i].ServiceStatusProcess = entry->service_status_process; - entry++; + else services[i].lpDisplayName = NULL; + services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess; } - heap_free( buf ); - *needed = 0; - *returned = count; - return TRUE; + ret = TRUE; + +done: + heap_free( servicesW ); + heap_free( groupW ); + return ret; } /****************************************************************************** @@ -2071,59 +327,6 @@ cleanup: return ret; } -/****************************************************************************** - * GetServiceKeyNameW [ADVAPI32.@] - */ -BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName, - LPWSTR lpServiceName, LPDWORD lpcchBuffer ) -{ - DWORD err; - WCHAR buffer[2]; - DWORD size; - - TRACE("%p %s %p %p\n", hSCManager, - debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer); - - if (!hSCManager) - { - SetLastError( ERROR_INVALID_HANDLE ); - return FALSE; - } - - /* provide a buffer if the caller didn't */ - if (!lpServiceName || *lpcchBuffer < 2) - { - lpServiceName = buffer; - /* A size of 1 would be enough, but tests show that Windows returns 2, - * probably because of a WCHAR/bytes mismatch in their code. - */ - *lpcchBuffer = 2; - } - - /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer - * includes the nul-terminator on input. */ - size = *lpcchBuffer - 1; - - __TRY - { - err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName, - &size); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - /* The value of *lpcchBuffer excludes nul-terminator on output. */ - if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER) - *lpcchBuffer = size; - - if (err) - SetLastError(err); - return err == ERROR_SUCCESS; -} - /****************************************************************************** * QueryServiceLockStatusA [ADVAPI32.@] */ @@ -2195,284 +398,6 @@ cleanup: return ret; } -/****************************************************************************** - * GetServiceDisplayNameW [ADVAPI32.@] - */ -BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName, - LPWSTR lpDisplayName, LPDWORD lpcchBuffer) -{ - DWORD err; - DWORD size; - WCHAR buffer[2]; - - TRACE("%p %s %p %p\n", hSCManager, - debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer); - - if (!hSCManager) - { - SetLastError( ERROR_INVALID_HANDLE ); - return FALSE; - } - - /* provide a buffer if the caller didn't */ - if (!lpDisplayName || *lpcchBuffer < 2) - { - lpDisplayName = buffer; - /* A size of 1 would be enough, but tests show that Windows returns 2, - * probably because of a WCHAR/bytes mismatch in their code. - */ - *lpcchBuffer = 2; - } - - /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer - * includes the nul-terminator on input. */ - size = *lpcchBuffer - 1; - - __TRY - { - err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName, - &size); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - /* The value of *lpcchBuffer excludes nul-terminator on output. */ - if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER) - *lpcchBuffer = size; - - if (err) - SetLastError(err); - return err == ERROR_SUCCESS; -} - -/****************************************************************************** - * ChangeServiceConfigW [ADVAPI32.@] - */ -BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType, - DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName, - LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies, - LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName) -{ - DWORD cb_pwd; - DWORD err; - - TRACE("%p %d %d %d %s %s %p %p %s %s %s\n", - hService, dwServiceType, dwStartType, dwErrorControl, - debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup), - lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName), - debugstr_w(lpPassword), debugstr_w(lpDisplayName) ); - - cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0; - - __TRY - { - err = svcctl_ChangeServiceConfigW(hService, dwServiceType, - dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, - (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName, - (const BYTE *)lpPassword, cb_pwd, lpDisplayName); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - if (err != ERROR_SUCCESS) - SetLastError(err); - - return err == ERROR_SUCCESS; -} - -/****************************************************************************** - * ChangeServiceConfigA [ADVAPI32.@] - */ -BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType, - DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName, - LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies, - LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName) -{ - LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies; - LPWSTR wServiceStartName, wPassword, wDisplayName; - BOOL r; - - TRACE("%p %d %d %d %s %s %p %p %s %s %s\n", - hService, dwServiceType, dwStartType, dwErrorControl, - debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup), - lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName), - debugstr_a(lpPassword), debugstr_a(lpDisplayName) ); - - wBinaryPathName = strdupAW( lpBinaryPathName ); - wLoadOrderGroup = strdupAW( lpLoadOrderGroup ); - wDependencies = SERV_dupmulti( lpDependencies ); - wServiceStartName = strdupAW( lpServiceStartName ); - wPassword = strdupAW( lpPassword ); - wDisplayName = strdupAW( lpDisplayName ); - - r = ChangeServiceConfigW( hService, dwServiceType, - dwStartType, dwErrorControl, wBinaryPathName, - wLoadOrderGroup, lpdwTagId, wDependencies, - wServiceStartName, wPassword, wDisplayName); - - heap_free( wBinaryPathName ); - heap_free( wLoadOrderGroup ); - heap_free( wDependencies ); - heap_free( wServiceStartName ); - heap_free( wPassword ); - heap_free( wDisplayName ); - - return r; -} - -/****************************************************************************** - * ChangeServiceConfig2A [ADVAPI32.@] - */ -BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, - LPVOID lpInfo) -{ - BOOL r = FALSE; - - TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo); - - if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION) - { - LPSERVICE_DESCRIPTIONA sd = lpInfo; - SERVICE_DESCRIPTIONW sdw; - - sdw.lpDescription = strdupAW( sd->lpDescription ); - - r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw ); - - heap_free( sdw.lpDescription ); - } - else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS) - { - LPSERVICE_FAILURE_ACTIONSA fa = lpInfo; - SERVICE_FAILURE_ACTIONSW faw; - - faw.dwResetPeriod = fa->dwResetPeriod; - faw.lpRebootMsg = strdupAW( fa->lpRebootMsg ); - faw.lpCommand = strdupAW( fa->lpCommand ); - faw.cActions = fa->cActions; - faw.lpsaActions = fa->lpsaActions; - - r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw ); - - heap_free( faw.lpRebootMsg ); - heap_free( faw.lpCommand ); - } - else if (dwInfoLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO) - { - r = ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo); - } - else - SetLastError( ERROR_INVALID_PARAMETER ); - - return r; -} - -/****************************************************************************** - * ChangeServiceConfig2W [ADVAPI32.@] - */ -BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, - LPVOID lpInfo) -{ - SERVICE_RPC_REQUIRED_PRIVILEGES_INFO rpc_privinfo; - DWORD err; - - __TRY - { - SC_RPC_CONFIG_INFOW info; - - info.dwInfoLevel = dwInfoLevel; - if (dwInfoLevel == SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO) - { - SERVICE_REQUIRED_PRIVILEGES_INFOW *privinfo = lpInfo; - WCHAR *p; - - for (p = privinfo->pmszRequiredPrivileges; *p; p += strlenW(p) + 1); - rpc_privinfo.cbRequiredPrivileges = - (p - privinfo->pmszRequiredPrivileges + 1) * sizeof(WCHAR); - rpc_privinfo.pRequiredPrivileges = (BYTE *)privinfo->pmszRequiredPrivileges; - info.u.privinfo = &rpc_privinfo; - } - else - info.u.descr = lpInfo; - err = svcctl_ChangeServiceConfig2W( hService, info ); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - if (err != ERROR_SUCCESS) - SetLastError(err); - - return err == ERROR_SUCCESS; -} - -static NTSTATUS SERV_QueryServiceObjectSecurity(SC_HANDLE hService, - SECURITY_INFORMATION dwSecurityInformation, - PSECURITY_DESCRIPTOR lpSecurityDescriptor, - DWORD cbBufSize, LPDWORD pcbBytesNeeded) -{ - SECURITY_DESCRIPTOR descriptor; - NTSTATUS status; - DWORD size; - ACL acl; - - FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation, - lpSecurityDescriptor, cbBufSize, pcbBytesNeeded); - - if (dwSecurityInformation != DACL_SECURITY_INFORMATION) - FIXME("information %d not supported\n", dwSecurityInformation); - - InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION); - - InitializeAcl(&acl, sizeof(ACL), ACL_REVISION); - SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE); - - size = cbBufSize; - status = RtlMakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size); - *pcbBytesNeeded = size; - return status; -} - -/****************************************************************************** - * QueryServiceObjectSecurity [ADVAPI32.@] - */ -BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService, - SECURITY_INFORMATION dwSecurityInformation, - PSECURITY_DESCRIPTOR lpSecurityDescriptor, - DWORD cbBufSize, LPDWORD pcbBytesNeeded) -{ - NTSTATUS status = SERV_QueryServiceObjectSecurity(hService, dwSecurityInformation, lpSecurityDescriptor, - cbBufSize, pcbBytesNeeded); - if (status != STATUS_SUCCESS) - { - SetLastError(RtlNtStatusToDosError(status)); - return FALSE; - } - return TRUE; -} - -/****************************************************************************** - * SetServiceObjectSecurity [ADVAPI32.@] - * - * NOTES - * - SetSecurityInfo should be updated to call this function once it's implemented. - */ -BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService, - SECURITY_INFORMATION dwSecurityInformation, - PSECURITY_DESCRIPTOR lpSecurityDescriptor) -{ - FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor); - return TRUE; -} - /****************************************************************************** * SetServiceBits [ADVAPI32.@] */ @@ -2486,69 +411,6 @@ BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus, return TRUE; } -/* thunk for calling the RegisterServiceCtrlHandler handler function */ -static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context ) -{ - LPHANDLER_FUNCTION func = context; - - func( control ); - return ERROR_SUCCESS; -} - -/****************************************************************************** - * RegisterServiceCtrlHandlerA [ADVAPI32.@] - */ -SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler ) -{ - return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler ); -} - -/****************************************************************************** - * RegisterServiceCtrlHandlerW [ADVAPI32.@] - */ -SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler ) -{ - return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler ); -} - -/****************************************************************************** - * RegisterServiceCtrlHandlerExA [ADVAPI32.@] - */ -SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context ) -{ - LPWSTR nameW; - SERVICE_STATUS_HANDLE ret; - - nameW = strdupAW(name); - ret = RegisterServiceCtrlHandlerExW( nameW, handler, context ); - heap_free( nameW ); - return ret; -} - -/****************************************************************************** - * RegisterServiceCtrlHandlerExW [ADVAPI32.@] - */ -SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName, - LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext ) -{ - service_data *service; - SC_HANDLE hService = 0; - - TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext); - - EnterCriticalSection( &service_cs ); - if ((service = find_service_by_name( lpServiceName ))) - { - service->handler = lpHandlerProc; - service->context = lpContext; - hService = service->handle; - } - LeaveCriticalSection( &service_cs ); - - if (!hService) SetLastError( ERROR_SERVICE_DOES_NOT_EXIST ); - return (SERVICE_STATUS_HANDLE)hService; -} - /****************************************************************************** * EnumDependentServicesA [ADVAPI32.@] */ @@ -2562,145 +424,3 @@ BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState, *lpServicesReturned = 0; return TRUE; } - -/****************************************************************************** - * EnumDependentServicesW [ADVAPI32.@] - */ -BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState, - LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize, - LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned ) -{ - FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState, - lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned); - - *lpServicesReturned = 0; - return TRUE; -} - -static DWORD WINAPI notify_thread(void *user) -{ - DWORD err; - notify_data *data = user; - SC_RPC_NOTIFY_PARAMS_LIST *list = NULL; - SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 *cparams; - BOOL dummy; - - __TRY - { - /* GetNotifyResults blocks until there is an event */ - err = svcctl_GetNotifyResults(data->notify_handle, &list); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - EnterCriticalSection( &service_cs ); - - list_remove(&data->entry); - - LeaveCriticalSection( &service_cs ); - - if (err == ERROR_SUCCESS && list) - { - cparams = list->NotifyParamsArray[0].u.params; - - data->notify_buffer->dwNotificationStatus = cparams->dwNotificationStatus; - memcpy(&data->notify_buffer->ServiceStatus, &cparams->ServiceStatus, - sizeof(SERVICE_STATUS_PROCESS)); - data->notify_buffer->dwNotificationTriggered = cparams->dwNotificationTriggered; - data->notify_buffer->pszServiceNames = NULL; - - QueueUserAPC((PAPCFUNC)data->notify_buffer->pfnNotifyCallback, - data->calling_thread, (ULONG_PTR)data->notify_buffer); - - HeapFree(GetProcessHeap(), 0, list); - } - else - WARN("GetNotifyResults server call failed: %u\n", err); - - - __TRY - { - err = svcctl_CloseNotifyHandle(&data->notify_handle, &dummy); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - if (err != ERROR_SUCCESS) - WARN("CloseNotifyHandle server call failed: %u\n", err); - - CloseHandle(data->calling_thread); - HeapFree(GetProcessHeap(), 0, data); - - return 0; -} - -/****************************************************************************** - * NotifyServiceStatusChangeW [ADVAPI32.@] - */ -DWORD WINAPI NotifyServiceStatusChangeW(SC_HANDLE hService, DWORD dwNotifyMask, - SERVICE_NOTIFYW *pNotifyBuffer) -{ - DWORD err; - BOOL b_dummy = FALSE; - GUID g_dummy = {0}; - notify_data *data; - - TRACE("%p 0x%x %p\n", hService, dwNotifyMask, pNotifyBuffer); - - data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data)); - if (!data) - return ERROR_NOT_ENOUGH_MEMORY; - - data->service = hService; - data->notify_buffer = pNotifyBuffer; - if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), - GetCurrentProcess(), &data->calling_thread, 0, FALSE, - DUPLICATE_SAME_ACCESS)) - { - ERR("DuplicateHandle failed: %u\n", GetLastError()); - HeapFree(GetProcessHeap(), 0, data); - return ERROR_NOT_ENOUGH_MEMORY; - } - - data->params.dwInfoLevel = 2; - data->params.u.params = &data->cparams; - - data->cparams.dwNotifyMask = dwNotifyMask; - - EnterCriticalSection( &service_cs ); - - __TRY - { - err = svcctl_NotifyServiceStatusChange(hService, data->params, - &g_dummy, &g_dummy, &b_dummy, &data->notify_handle); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - if (err != ERROR_SUCCESS) - { - WARN("NotifyServiceStatusChange server call failed: %u\n", err); - LeaveCriticalSection( &service_cs ); - CloseHandle(data->calling_thread); - CloseHandle(data->ready_evt); - HeapFree(GetProcessHeap(), 0, data); - return err; - } - - CloseHandle(CreateThread(NULL, 0, ¬ify_thread, data, 0, NULL)); - - list_add_tail(¬ify_list, &data->entry); - - LeaveCriticalSection( &service_cs ); - - return ERROR_SUCCESS; -} diff --git a/dlls/sechost/Makefile.in b/dlls/sechost/Makefile.in index 9f573ccc2f9..eb98d04859c 100644 --- a/dlls/sechost/Makefile.in +++ b/dlls/sechost/Makefile.in @@ -1,8 +1,13 @@ MODULE = sechost.dll IMPORTLIB = sechost IMPORTS = kernelbase +DELAYIMPORTS = rpcrt4 EXTRADLLFLAGS = -mno-cygwin C_SRCS = \ + service.c \ trace.c + +IDL_SRCS = \ + svcctl.idl diff --git a/dlls/sechost/sechost.spec b/dlls/sechost/sechost.spec index f54de38c289..df6af1646df 100644 --- a/dlls/sechost/sechost.spec +++ b/dlls/sechost/sechost.spec @@ -19,13 +19,13 @@ @ stub BuildSecurityDescriptorForSharingAccessEx @ stub CapabilityCheck @ stub CapabilityCheckForSingleSessionSku -@ stdcall ChangeServiceConfig2A(long long ptr) advapi32.ChangeServiceConfig2A -@ stdcall ChangeServiceConfig2W(long long ptr) advapi32.ChangeServiceConfig2W -@ stdcall ChangeServiceConfigA(long long long long wstr str ptr str str str str) advapi32.ChangeServiceConfigA -@ stdcall ChangeServiceConfigW(long long long long wstr wstr ptr wstr wstr wstr wstr) advapi32.ChangeServiceConfigW -@ stdcall CloseServiceHandle(long) advapi32.CloseServiceHandle +@ stdcall ChangeServiceConfig2A(long long ptr) +@ stdcall ChangeServiceConfig2W(long long ptr) +@ stdcall ChangeServiceConfigA(long long long long wstr str ptr str str str str) +@ stdcall ChangeServiceConfigW(long long long long wstr wstr ptr wstr wstr wstr wstr) +@ stdcall CloseServiceHandle(long) @ stdcall CloseTrace(int64) -@ stdcall ControlService(long long ptr) advapi32.ControlService +@ stdcall ControlService(long long ptr) @ stub ControlServiceExA @ stub ControlServiceExW @ stdcall ControlTraceA(int64 str ptr long) @@ -38,9 +38,9 @@ @ stub ConvertStringSDToSDRootDomainW @ stdcall ConvertStringSecurityDescriptorToSecurityDescriptorW(wstr long ptr ptr) advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW @ stdcall ConvertStringSidToSidW(ptr ptr) advapi32.ConvertStringSidToSidW -@ stdcall CreateServiceA(long str str long long long long str str ptr str str str) advapi32.CreateServiceA +@ stdcall CreateServiceA(long str str long long long long str str ptr str str str) @ stub CreateServiceEx -@ stdcall CreateServiceW(long wstr wstr long long long long wstr wstr ptr wstr wstr wstr) advapi32.CreateServiceW +@ stdcall CreateServiceW(long wstr wstr long long long long wstr wstr ptr wstr wstr wstr) @ stub CredBackupCredentials @ stdcall CredDeleteA(str long long) advapi32.CredDeleteA @ stdcall CredDeleteW(wstr long long) advapi32.CredDeleteW @@ -84,10 +84,10 @@ @ stub CredpDecodeCredential @ stub CredpEncodeCredential @ stub CredpEncodeSecret -@ stdcall DeleteService(long) advapi32.DeleteService +@ stdcall DeleteService(long) @ stdcall EnableTraceEx2(int64 ptr long long int64 int64 long ptr) -@ stdcall EnumDependentServicesW(long long ptr long ptr ptr) advapi32.EnumDependentServicesW -@ stdcall EnumServicesStatusExW(long long long long ptr long ptr ptr ptr wstr) advapi32.EnumServicesStatusExW +@ stdcall EnumDependentServicesW(long long ptr long ptr ptr) +@ stdcall EnumServicesStatusExW(long long long long ptr long ptr ptr ptr wstr) @ stub EnumerateIdentityProviders @ stub EnumerateTraceGuidsEx @ stub EtwQueryRealtimeConsumer @@ -99,8 +99,8 @@ @ stub GetIdentityProviderInfoByGUID @ stub GetIdentityProviderInfoByName @ stub GetServiceDirectory -@ stdcall GetServiceDisplayNameW(ptr wstr ptr ptr) advapi32.GetServiceDisplayNameW -@ stdcall GetServiceKeyNameW(long wstr ptr ptr) advapi32.GetServiceKeyNameW +@ stdcall GetServiceDisplayNameW(ptr wstr ptr ptr) +@ stdcall GetServiceKeyNameW(long wstr ptr ptr) @ stub GetServiceRegistryStateKey @ stub I_QueryTagInformation @ stub I_RegisterSvchostNotificationCallback @@ -159,45 +159,45 @@ @ stdcall LsaStorePrivateData(ptr ptr ptr) advapi32.LsaStorePrivateData @ stub NotifyServiceStatusChange @ stub NotifyServiceStatusChangeA -@ stdcall NotifyServiceStatusChangeW(ptr long ptr) advapi32.NotifyServiceStatusChangeW -@ stdcall OpenSCManagerA(str str long) advapi32.OpenSCManagerA -@ stdcall OpenSCManagerW(wstr wstr long) advapi32.OpenSCManagerW -@ stdcall OpenServiceA(long str long) advapi32.OpenServiceA -@ stdcall OpenServiceW(long wstr long) advapi32.OpenServiceW +@ stdcall NotifyServiceStatusChangeW(ptr long ptr) +@ stdcall OpenSCManagerA(str str long) +@ stdcall OpenSCManagerW(wstr wstr long) +@ stdcall OpenServiceA(long str long) +@ stdcall OpenServiceW(long wstr long) @ stdcall -ret64 OpenTraceW(ptr) @ stdcall ProcessTrace(ptr long ptr ptr) @ stdcall QueryAllTracesA(ptr long ptr) @ stdcall QueryAllTracesW(ptr long ptr) @ stub QueryLocalUserServiceName -@ stdcall QueryServiceConfig2A(long long ptr long ptr) advapi32.QueryServiceConfig2A -@ stdcall QueryServiceConfig2W(long long ptr long ptr) advapi32.QueryServiceConfig2W -@ stdcall QueryServiceConfigA(long ptr long ptr) advapi32.QueryServiceConfigA -@ stdcall QueryServiceConfigW(long ptr long ptr) advapi32.QueryServiceConfigW +@ stdcall QueryServiceConfig2A(long long ptr long ptr) +@ stdcall QueryServiceConfig2W(long long ptr long ptr) +@ stdcall QueryServiceConfigA(long ptr long ptr) +@ stdcall QueryServiceConfigW(long ptr long ptr) @ stub QueryServiceDynamicInformation -@ stdcall QueryServiceObjectSecurity(long long ptr long ptr) advapi32.QueryServiceObjectSecurity -@ stdcall QueryServiceStatus(long ptr) advapi32.QueryServiceStatus -@ stdcall QueryServiceStatusEx(long long ptr long ptr) advapi32.QueryServiceStatusEx +@ stdcall QueryServiceObjectSecurity(long long ptr long ptr) +@ stdcall QueryServiceStatus(long ptr) +@ stdcall QueryServiceStatusEx(long long ptr long ptr) @ stub QueryTraceProcessingHandle @ stub QueryTransientObjectSecurityDescriptor @ stub QueryUserServiceName @ stub QueryUserServiceNameForContext -@ stdcall RegisterServiceCtrlHandlerA(str ptr) advapi32.RegisterServiceCtrlHandlerA -@ stdcall RegisterServiceCtrlHandlerExA(str ptr ptr) advapi32.RegisterServiceCtrlHandlerExA -@ stdcall RegisterServiceCtrlHandlerExW(wstr ptr ptr) advapi32.RegisterServiceCtrlHandlerExW -@ stdcall RegisterServiceCtrlHandlerW(wstr ptr) advapi32.RegisterServiceCtrlHandlerW +@ stdcall RegisterServiceCtrlHandlerA(str ptr) +@ stdcall RegisterServiceCtrlHandlerExA(str ptr ptr) +@ stdcall RegisterServiceCtrlHandlerExW(wstr ptr ptr) +@ stdcall RegisterServiceCtrlHandlerW(wstr ptr) @ stdcall RegisterTraceGuidsA(ptr ptr ptr long ptr str str ptr) advapi32.RegisterTraceGuidsA @ stub ReleaseIdentityProviderEnumContext @ stub RemoveTraceCallback @ stub RpcClientCapabilityCheck @ stub SetLocalRpcServerInterfaceSecurity @ stub SetLocalRpcServerProtseqSecurity -@ stdcall SetServiceObjectSecurity(long long ptr) advapi32.SetServiceObjectSecurity -@ stdcall SetServiceStatus(long ptr) advapi32.SetServiceStatus +@ stdcall SetServiceObjectSecurity(long long ptr) +@ stdcall SetServiceStatus(long ptr) @ stub SetTraceCallback -@ stdcall StartServiceA(long long ptr) advapi32.StartServiceA -@ stdcall StartServiceCtrlDispatcherA(ptr) advapi32.StartServiceCtrlDispatcherA -@ stdcall StartServiceCtrlDispatcherW(ptr) advapi32.StartServiceCtrlDispatcherW -@ stdcall StartServiceW(long long ptr) advapi32.StartServiceW +@ stdcall StartServiceA(long long ptr) +@ stdcall StartServiceCtrlDispatcherA(ptr) +@ stdcall StartServiceCtrlDispatcherW(ptr) +@ stdcall StartServiceW(long long ptr) @ stdcall StartTraceA(ptr str ptr) @ stdcall StartTraceW(ptr wstr ptr) @ stdcall StopTraceW(int64 wstr ptr) diff --git a/dlls/sechost/service.c b/dlls/sechost/service.c new file mode 100644 index 00000000000..7a4211631e2 --- /dev/null +++ b/dlls/sechost/service.c @@ -0,0 +1,1969 @@ +/* + * Service control API + * + * Copyright 1995 Sven Verdoolaege + * Copyright 2005 Mike McCormack + * Copyright 2007 Rolf Kalbermatter + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * 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 + */ + +#define NONAMELESSUNION +#include <stdarg.h> +#include "windef.h" +#include "winbase.h" +#include "winsvc.h" +#include "winternl.h" + +#include "wine/debug.h" +#include "wine/exception.h" +#include "wine/heap.h" +#include "wine/list.h" + +#include "svcctl.h" + +WINE_DEFAULT_DEBUG_CHANNEL(service); + +struct notify_data +{ + SC_HANDLE service; + SC_RPC_NOTIFY_PARAMS params; + SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 cparams; + SC_NOTIFY_RPC_HANDLE notify_handle; + SERVICE_NOTIFYW *notify_buffer; + HANDLE calling_thread, ready_evt; + struct list entry; +}; + +static struct list notify_list = LIST_INIT(notify_list); + +static CRITICAL_SECTION service_cs; +static CRITICAL_SECTION_DEBUG service_cs_debug = +{ + 0, 0, &service_cs, + { &service_cs_debug.ProcessLocksList, + &service_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") } +}; +static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 }; + +struct service_data +{ + LPHANDLER_FUNCTION_EX handler; + void *context; + HANDLE thread; + SC_HANDLE handle; + SC_HANDLE full_access_handle; + unsigned int unicode : 1; + union + { + LPSERVICE_MAIN_FUNCTIONA a; + LPSERVICE_MAIN_FUNCTIONW w; + } proc; + WCHAR *args; + WCHAR name[1]; +}; + +struct dispatcher_data +{ + SC_HANDLE manager; + HANDLE pipe; +}; + +static struct service_data **services; +static unsigned int nb_services; +static HANDLE service_event; +static BOOL stop_service; + +extern HANDLE CDECL __wine_make_process_system(void); + +static WCHAR *heap_strdupAtoW( const char *src ) +{ + WCHAR *dst = NULL; + if (src) + { + DWORD len = MultiByteToWideChar( CP_ACP, 0, src, -1, NULL, 0 ); + if ((dst = heap_alloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, src, -1, dst, len ); + } + return dst; +} + +static WCHAR *heap_strdup_multi_AtoW( const char *src ) +{ + WCHAR *dst = NULL; + const char *p = src; + DWORD len; + + if (!src) return NULL; + + while (*p) p += strlen(p) + 1; + for (p = src; *p; p += strlen(p) + 1); + p++; /* final null */ + len = MultiByteToWideChar( CP_ACP, 0, src, p - src, NULL, 0 ); + if ((dst = heap_alloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, src, p - src, dst, len ); + return dst; +} + +static inline DWORD multisz_size( const WCHAR *str ) +{ + const WCHAR *p = str; + + if (!str) return 0; + + while (*p) p += wcslen(p) + 1; + return (p - str + 1) * sizeof(WCHAR); +} + +void __RPC_FAR * __RPC_USER MIDL_user_allocate( SIZE_T len ) +{ + return heap_alloc(len); +} + +void __RPC_USER MIDL_user_free( void __RPC_FAR *ptr ) +{ + heap_free(ptr); +} + +static LONG WINAPI rpc_filter( EXCEPTION_POINTERS *eptr ) +{ + return I_RpcExceptionFilter( eptr->ExceptionRecord->ExceptionCode ); +} + +static DWORD map_exception_code( DWORD exception_code ) +{ + switch (exception_code) + { + case RPC_X_NULL_REF_POINTER: + return ERROR_INVALID_ADDRESS; + case RPC_X_ENUM_VALUE_OUT_OF_RANGE: + case RPC_X_BYTE_COUNT_TOO_SMALL: + return ERROR_INVALID_PARAMETER; + case RPC_S_INVALID_BINDING: + case RPC_X_SS_IN_NULL_CONTEXT: + return ERROR_INVALID_HANDLE; + default: + return exception_code; + } +} + +static handle_t rpc_wstr_bind( RPC_WSTR str ) +{ + WCHAR transport[] = SVCCTL_TRANSPORT; + WCHAR endpoint[] = SVCCTL_ENDPOINT; + RPC_WSTR binding_str; + RPC_STATUS status; + handle_t rpc_handle; + + status = RpcStringBindingComposeW( NULL, transport, str, endpoint, NULL, &binding_str ); + if (status != RPC_S_OK) + { + ERR("RpcStringBindingComposeW failed, error %d\n", status); + return NULL; + } + + status = RpcBindingFromStringBindingW( binding_str, &rpc_handle ); + RpcStringFreeW( &binding_str ); + + if (status != RPC_S_OK) + { + ERR("Couldn't connect to services.exe, error %d\n", status); + return NULL; + } + + return rpc_handle; +} + +static handle_t rpc_cstr_bind(RPC_CSTR str) +{ + RPC_CSTR transport = (RPC_CSTR)SVCCTL_TRANSPORTA; + RPC_CSTR endpoint = (RPC_CSTR)SVCCTL_ENDPOINTA; + RPC_CSTR binding_str; + RPC_STATUS status; + handle_t rpc_handle; + + status = RpcStringBindingComposeA( NULL, transport, str, endpoint, NULL, &binding_str ); + if (status != RPC_S_OK) + { + ERR("RpcStringBindingComposeA failed, error %d\n", status); + return NULL; + } + + status = RpcBindingFromStringBindingA( binding_str, &rpc_handle ); + RpcStringFreeA( &binding_str ); + + if (status != RPC_S_OK) + { + ERR("Couldn't connect to services.exe, error %d\n", status); + return NULL; + } + + return rpc_handle; +} + +DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEA_bind( MACHINE_HANDLEA name ) +{ + return rpc_cstr_bind( (RPC_CSTR)name ); +} + +DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEA_unbind( MACHINE_HANDLEA name, handle_t h ) +{ + RpcBindingFree( &h ); +} + +DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind( MACHINE_HANDLEW name ) +{ + return rpc_wstr_bind( (RPC_WSTR)name ); +} + +DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind( MACHINE_HANDLEW name, handle_t h ) +{ + RpcBindingFree( &h ); +} + +DECLSPEC_HIDDEN handle_t __RPC_USER SVCCTL_HANDLEW_bind( SVCCTL_HANDLEW name ) +{ + return rpc_wstr_bind( (RPC_WSTR)name ); +} + +DECLSPEC_HIDDEN void __RPC_USER SVCCTL_HANDLEW_unbind( SVCCTL_HANDLEW name, handle_t h ) +{ + RpcBindingFree( &h ); +} + +static BOOL set_error( DWORD err ) +{ + if (err) SetLastError( err ); + return !err; +} + +/****************************************************************************** + * OpenSCManagerA (sechost.@) + */ +SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenSCManagerA( const char *machine, const char *database, DWORD access ) +{ + WCHAR *machineW, *databaseW; + SC_HANDLE ret; + + machineW = heap_strdupAtoW( machine ); + databaseW = heap_strdupAtoW( database ); + ret = OpenSCManagerW( machineW, databaseW, access ); + heap_free( databaseW ); + heap_free( machineW ); + return ret; +} + +/****************************************************************************** + * OpenSCManagerW (sechost.@) + */ +SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenSCManagerW( const WCHAR *machine, const WCHAR *database, DWORD access ) +{ + SC_RPC_HANDLE handle = NULL; + DWORD err; + + TRACE( "%s %s %#x\n", debugstr_w(machine), debugstr_w(database), access ); + + __TRY + { + err = svcctl_OpenSCManagerW( machine, database, access, &handle ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + if (!err) return handle; + SetLastError( err ); + return NULL; +} + +/****************************************************************************** + * OpenServiceA (sechost.@) + */ +SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenServiceA( SC_HANDLE manager, const char *name, DWORD access ) +{ + WCHAR *nameW; + SC_HANDLE ret; + + TRACE( "%p %s %#x\n", manager, debugstr_a(name), access ); + + nameW = heap_strdupAtoW( name ); + ret = OpenServiceW( manager, nameW, access ); + heap_free( nameW ); + return ret; +} + +/****************************************************************************** + * OpenServiceW (sechost.@) + */ +SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenServiceW( SC_HANDLE manager, const WCHAR *name, DWORD access ) +{ + SC_RPC_HANDLE handle = NULL; + DWORD err; + + TRACE( "%p %s %#x\n", manager, debugstr_w(name), access ); + + if (!manager) + { + SetLastError( ERROR_INVALID_HANDLE ); + return NULL; + } + + __TRY + { + err = svcctl_OpenServiceW( manager, name, access, &handle ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + if (!err) return handle; + SetLastError( err ); + return 0; +} + +/****************************************************************************** + * CreateServiceA (sechost.@) + */ +SC_HANDLE WINAPI DECLSPEC_HOTPATCH CreateServiceA( SC_HANDLE manager, const char *name, const char *display_name, + DWORD access, DWORD service_type, DWORD start_type, + DWORD error_control, const char *path, const char *group, + DWORD *tag, const char *dependencies, const char *username, + const char *password ) +{ + WCHAR *nameW, *display_nameW, *pathW, *groupW, *dependenciesW, *usernameW, *passwordW; + SC_HANDLE handle; + + TRACE( "%p %s %s\n", manager, debugstr_a(name), debugstr_a(display_name) ); + + nameW = heap_strdupAtoW( name ); + display_nameW = heap_strdupAtoW( display_name ); + pathW = heap_strdupAtoW( path ); + groupW = heap_strdupAtoW( group ); + dependenciesW = heap_strdupAtoW( dependencies ); + usernameW = heap_strdupAtoW( username ); + passwordW = heap_strdupAtoW( password ); + + handle = CreateServiceW( manager, nameW, display_nameW, access, service_type, start_type, error_control, + pathW, groupW, tag, dependenciesW, usernameW, passwordW ); + + heap_free( nameW ); + heap_free( display_nameW ); + heap_free( pathW ); + heap_free( groupW ); + heap_free( dependenciesW ); + heap_free( usernameW ); + heap_free( passwordW ); + + return handle; +} + +/****************************************************************************** + * CreateServiceW (sechost.@) + */ +SC_HANDLE WINAPI DECLSPEC_HOTPATCH CreateServiceW( SC_HANDLE manager, const WCHAR *name, const WCHAR *display_name, + DWORD access, DWORD service_type, DWORD start_type, + DWORD error_control, const WCHAR *path, const WCHAR *group, + DWORD *tag, const WCHAR *dependencies, const WCHAR *username, + const WCHAR *password ) +{ + SC_RPC_HANDLE handle = NULL; + DWORD err; + SIZE_T password_size = 0; + + TRACE( "%p %s %s\n", manager, debugstr_w(name), debugstr_w(display_name) ); + + if (!manager) + { + SetLastError( ERROR_INVALID_HANDLE ); + return 0; + } + + if (password) password_size = (wcslen(password) + 1) * sizeof(WCHAR); + + __TRY + { + BOOL is_wow64; + + if (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64) + err = svcctl_CreateServiceWOW64W( manager, name, display_name, access, service_type, start_type, + error_control, path, group, tag, (const BYTE *)dependencies, + multisz_size( dependencies ), username, (const BYTE *)password, + password_size, &handle ); + else + err = svcctl_CreateServiceW( manager, name, display_name, access, service_type, start_type, + error_control, path, group, tag, (const BYTE *)dependencies, + multisz_size( dependencies ), username, (const BYTE *)password, + password_size, &handle ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + if (!err) return handle; + SetLastError( err ); + return NULL; +} + +/****************************************************************************** + * DeleteService (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH DeleteService( SC_HANDLE service ) +{ + DWORD err; + + TRACE( "%p\n", service ); + + __TRY + { + err = svcctl_DeleteService( service ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + return set_error( err ); +} + +/****************************************************************************** + * CloseServiceHandle (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH CloseServiceHandle( SC_HANDLE handle ) +{ + DWORD err; + + TRACE( "%p\n", handle ); + + __TRY + { + err = svcctl_CloseServiceHandle( (SC_RPC_HANDLE *)&handle ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + return set_error( err ); +} + +/****************************************************************************** + * ChangeServiceConfig2A (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfig2A( SC_HANDLE service, DWORD level, void *info) +{ + BOOL r = FALSE; + + TRACE( "%p %d %p\n", service, level, info ); + + if (level == SERVICE_CONFIG_DESCRIPTION) + { + SERVICE_DESCRIPTIONA *sd = info; + SERVICE_DESCRIPTIONW sdw; + + sdw.lpDescription = heap_strdupAtoW( sd->lpDescription ); + + r = ChangeServiceConfig2W( service, level, &sdw ); + + heap_free( sdw.lpDescription ); + } + else if (level == SERVICE_CONFIG_FAILURE_ACTIONS) + { + SERVICE_FAILURE_ACTIONSA *fa = info; + SERVICE_FAILURE_ACTIONSW faw; + + faw.dwResetPeriod = fa->dwResetPeriod; + faw.lpRebootMsg = heap_strdupAtoW( fa->lpRebootMsg ); + faw.lpCommand = heap_strdupAtoW( fa->lpCommand ); + faw.cActions = fa->cActions; + faw.lpsaActions = fa->lpsaActions; + + r = ChangeServiceConfig2W( service, level, &faw ); + + heap_free( faw.lpRebootMsg ); + heap_free( faw.lpCommand ); + } + else if (level == SERVICE_CONFIG_PRESHUTDOWN_INFO) + { + r = ChangeServiceConfig2W( service, level, info ); + } + else + SetLastError( ERROR_INVALID_PARAMETER ); + + return r; +} + +/****************************************************************************** + * ChangeServiceConfig2W (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfig2W( SC_HANDLE service, DWORD level, void *info ) +{ + SERVICE_RPC_REQUIRED_PRIVILEGES_INFO rpc_privinfo; + DWORD err; + + __TRY + { + SC_RPC_CONFIG_INFOW rpc_info; + + rpc_info.dwInfoLevel = level; + if (level == SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO) + { + SERVICE_REQUIRED_PRIVILEGES_INFOW *privinfo = info; + + rpc_privinfo.cbRequiredPrivileges = multisz_size( privinfo->pmszRequiredPrivileges ); + rpc_privinfo.pRequiredPrivileges = (BYTE *)privinfo->pmszRequiredPrivileges; + rpc_info.u.privinfo = &rpc_privinfo; + } + else + rpc_info.u.descr = info; + err = svcctl_ChangeServiceConfig2W( service, rpc_info ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + return set_error( err ); +} + +/****************************************************************************** + * ChangeServiceConfigA (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfigA( SC_HANDLE service, DWORD service_type, DWORD start_type, + DWORD error_control, const char *path, const char *group, + DWORD *tag, const char *dependencies, const char *username, + const char *password, const char *display_name ) +{ + WCHAR *pathW, *groupW, *dependenciesW, *usernameW, *passwordW, *display_nameW; + BOOL r; + + TRACE( "%p %d %d %d %s %s %p %p %s %s %s\n", service, service_type, start_type, + error_control, debugstr_a(path), debugstr_a(group), tag, dependencies, + debugstr_a(username), debugstr_a(password), debugstr_a(display_name) ); + + pathW = heap_strdupAtoW( path ); + groupW = heap_strdupAtoW( group ); + dependenciesW = heap_strdup_multi_AtoW( dependencies ); + usernameW = heap_strdupAtoW( username ); + passwordW = heap_strdupAtoW( password ); + display_nameW = heap_strdupAtoW( display_name ); + + r = ChangeServiceConfigW( service, service_type, start_type, error_control, pathW, + groupW, tag, dependenciesW, usernameW, passwordW, display_nameW ); + + heap_free( pathW ); + heap_free( groupW ); + heap_free( dependenciesW ); + heap_free( usernameW ); + heap_free( passwordW ); + heap_free( display_nameW ); + + return r; +} + +/****************************************************************************** + * ChangeServiceConfigW (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfigW( SC_HANDLE service, DWORD service_type, DWORD start_type, + DWORD error_control, const WCHAR *path, const WCHAR *group, + DWORD *tag, const WCHAR *dependencies, const WCHAR *username, + const WCHAR *password, const WCHAR *display_name ) +{ + DWORD password_size; + DWORD err; + + TRACE( "%p %d %d %d %s %s %p %p %s %s %s\n", service, service_type, start_type, + error_control, debugstr_w(path), debugstr_w(group), tag, dependencies, + debugstr_w(username), debugstr_w(password), debugstr_w(display_name) ); + + password_size = password ? (wcslen(password) + 1) * sizeof(WCHAR) : 0; + + __TRY + { + err = svcctl_ChangeServiceConfigW( service, service_type, start_type, error_control, path, group, tag, + (const BYTE *)dependencies, multisz_size(dependencies), username, + (const BYTE *)password, password_size, display_name ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + return set_error( err ); +} + +/****************************************************************************** + * QueryServiceConfigA (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfigA( SC_HANDLE service, QUERY_SERVICE_CONFIGA *config, + DWORD size, DWORD *ret_size ) +{ + DWORD n; + char *p, *buffer; + BOOL ret; + QUERY_SERVICE_CONFIGW *configW; + + TRACE( "%p %p %d %p\n", service, config, size, ret_size ); + + if (!(buffer = heap_alloc( 2 * size ))) return set_error( ERROR_NOT_ENOUGH_MEMORY ); + configW = (QUERY_SERVICE_CONFIGW *)buffer; + ret = QueryServiceConfigW( service, configW, 2 * size, ret_size ); + if (!ret) goto done; + + config->dwServiceType = configW->dwServiceType; + config->dwStartType = configW->dwStartType; + config->dwErrorControl = configW->dwErrorControl; + config->lpBinaryPathName = NULL; + config->lpLoadOrderGroup = NULL; + config->dwTagId = configW->dwTagId; + config->lpDependencies = NULL; + config->lpServiceStartName = NULL; + config->lpDisplayName = NULL; + + p = (char *)(config + 1); + n = size - sizeof(*config); + ret = FALSE; + +#define MAP_STR(str) \ + do { \ + if (configW->str) \ + { \ + DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \ + if (!sz) goto done; \ + config->str = p; \ + p += sz; \ + n -= sz; \ + } \ + } while (0) + + MAP_STR( lpBinaryPathName ); + MAP_STR( lpLoadOrderGroup ); + MAP_STR( lpDependencies ); + MAP_STR( lpServiceStartName ); + MAP_STR( lpDisplayName ); +#undef MAP_STR + + *ret_size = p - (char *)config; + ret = TRUE; + +done: + heap_free( buffer ); + return ret; +} + +static DWORD move_string_to_buffer(BYTE **buf, WCHAR **string_ptr) +{ + DWORD cb; + + if (!*string_ptr) + { + cb = sizeof(WCHAR); + memset(*buf, 0, cb); + } + else + { + cb = (wcslen( *string_ptr ) + 1) * sizeof(WCHAR); + memcpy(*buf, *string_ptr, cb); + MIDL_user_free( *string_ptr ); + } + + *string_ptr = (WCHAR *)*buf; + *buf += cb; + + return cb; +} + +static DWORD size_string( const WCHAR *string ) +{ + return (string ? (wcslen( string ) + 1) * sizeof(WCHAR) : sizeof(WCHAR)); +} + +/****************************************************************************** + * QueryServiceConfigW (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfigW( SC_HANDLE service, QUERY_SERVICE_CONFIGW *ret_config, + DWORD size, DWORD *ret_size ) +{ + QUERY_SERVICE_CONFIGW config; + DWORD total; + DWORD err; + BYTE *bufpos; + + TRACE( "%p %p %d %p\n", service, ret_config, size, ret_size ); + + memset(&config, 0, sizeof(config)); + + __TRY + { + err = svcctl_QueryServiceConfigW( service, &config, size, ret_size ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + if (err) return set_error( err ); + + /* calculate the size required first */ + total = sizeof(QUERY_SERVICE_CONFIGW); + total += size_string( config.lpBinaryPathName ); + total += size_string( config.lpLoadOrderGroup ); + total += size_string( config.lpDependencies ); + total += size_string( config.lpServiceStartName ); + total += size_string( config.lpDisplayName ); + + *ret_size = total; + + /* if there's not enough memory, return an error */ + if (size < total) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + MIDL_user_free( config.lpBinaryPathName ); + MIDL_user_free( config.lpLoadOrderGroup ); + MIDL_user_free( config.lpDependencies ); + MIDL_user_free( config.lpServiceStartName ); + MIDL_user_free( config.lpDisplayName ); + return FALSE; + } + + *ret_config = config; + bufpos = ((BYTE *)ret_config) + sizeof(QUERY_SERVICE_CONFIGW); + move_string_to_buffer( &bufpos, &ret_config->lpBinaryPathName ); + move_string_to_buffer( &bufpos, &ret_config->lpLoadOrderGroup ); + move_string_to_buffer( &bufpos, &ret_config->lpDependencies ); + move_string_to_buffer( &bufpos, &ret_config->lpServiceStartName ); + move_string_to_buffer( &bufpos, &ret_config->lpDisplayName ); + + TRACE( "Image path = %s\n", debugstr_w( ret_config->lpBinaryPathName ) ); + TRACE( "Group = %s\n", debugstr_w( ret_config->lpLoadOrderGroup ) ); + TRACE( "Dependencies = %s\n", debugstr_w( ret_config->lpDependencies ) ); + TRACE( "Service account name = %s\n", debugstr_w( ret_config->lpServiceStartName ) ); + TRACE( "Display name = %s\n", debugstr_w( ret_config->lpDisplayName ) ); + + return TRUE; +} + +/****************************************************************************** + * QueryServiceConfig2A (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfig2A( SC_HANDLE service, DWORD level, BYTE *buffer, + DWORD size, DWORD *ret_size ) +{ + BYTE *bufferW = NULL; + + TRACE( "%p %u %p %u %p\n", service, level, buffer, size, ret_size ); + + if (buffer && size) + bufferW = heap_alloc( size ); + + if (!QueryServiceConfig2W( service, level, bufferW, size, ret_size )) + { + heap_free( bufferW ); + return FALSE; + } + + switch (level) + { + case SERVICE_CONFIG_DESCRIPTION: + if (buffer && bufferW) { + SERVICE_DESCRIPTIONA *configA = (SERVICE_DESCRIPTIONA *)buffer; + SERVICE_DESCRIPTIONW *configW = (SERVICE_DESCRIPTIONW *)bufferW; + if (configW->lpDescription && size > sizeof(SERVICE_DESCRIPTIONA)) + { + configA->lpDescription = (char *)(configA + 1); + WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1, configA->lpDescription, + size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL ); + } + else configA->lpDescription = NULL; + } + break; + case SERVICE_CONFIG_PRESHUTDOWN_INFO: + if (buffer && bufferW && *ret_size <= size) + memcpy(buffer, bufferW, *ret_size); + break; + default: + FIXME("conversion W->A not implemented for level %d\n", level); + heap_free( bufferW ); + return FALSE; + } + + heap_free( bufferW ); + return TRUE; +} + +/****************************************************************************** + * QueryServiceConfig2W (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfig2W( SC_HANDLE service, DWORD level, BYTE *buffer, + DWORD size, DWORD *ret_size ) +{ + BYTE *bufptr; + DWORD err; + + TRACE( "%p %u %p %u %p\n", service, level, buffer, size, ret_size ); + + if (!buffer && size) + { + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } + + switch (level) + { + case SERVICE_CONFIG_DESCRIPTION: + if (!(bufptr = heap_alloc( size ))) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return FALSE; + } + break; + + case SERVICE_CONFIG_PRESHUTDOWN_INFO: + bufptr = buffer; + break; + + default: + FIXME("Level %d not implemented\n", level); + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + + if (!ret_size) + { + if (level == SERVICE_CONFIG_DESCRIPTION) heap_free( bufptr ); + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } + + __TRY + { + err = svcctl_QueryServiceConfig2W( service, level, bufptr, size, ret_size ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + switch (level) + { + case SERVICE_CONFIG_DESCRIPTION: + { + SERVICE_DESCRIPTIONW *desc = (SERVICE_DESCRIPTIONW *)buffer; + struct service_description *s = (struct service_description *)bufptr; + + if (err != ERROR_SUCCESS && err != ERROR_INSUFFICIENT_BUFFER) + { + heap_free( bufptr ); + SetLastError( err ); + return FALSE; + } + + /* adjust for potentially larger SERVICE_DESCRIPTIONW structure */ + if (*ret_size == sizeof(*s)) + *ret_size = sizeof(*desc); + else + *ret_size = *ret_size - FIELD_OFFSET(struct service_description, description) + sizeof(*desc); + + if (size < *ret_size) + { + heap_free( bufptr ); + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + if (desc) + { + if (!s->size) desc->lpDescription = NULL; + else + { + desc->lpDescription = (WCHAR *)(desc + 1); + memcpy( desc->lpDescription, s->description, s->size ); + } + } + heap_free( bufptr ); + break; + } + case SERVICE_CONFIG_PRESHUTDOWN_INFO: + return set_error( err ); + + default: + break; + } + + return TRUE; +} + +/****************************************************************************** + * GetServiceDisplayNameW (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH GetServiceDisplayNameW( SC_HANDLE manager, const WCHAR *service, + WCHAR *display_name, DWORD *len ) +{ + DWORD err; + DWORD size; + WCHAR buffer[2]; + + TRACE( "%p %s %p %p\n", manager, debugstr_w(service), display_name, len ); + + if (!manager) + { + SetLastError( ERROR_INVALID_HANDLE ); + return FALSE; + } + + /* provide a buffer if the caller didn't */ + if (!display_name || *len < sizeof(WCHAR)) + { + display_name = buffer; + /* A size of 1 would be enough, but tests show that Windows returns 2, + * probably because of a WCHAR/bytes mismatch in their code. */ + *len = 2; + } + + /* RPC call takes size excluding nul-terminator, whereas *len + * includes the nul-terminator on input. */ + size = *len - 1; + + __TRY + { + err = svcctl_GetServiceDisplayNameW( manager, service, display_name, &size ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + /* The value of *len excludes nul-terminator on output. */ + if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER) + *len = size; + return set_error( err ); +} + +/****************************************************************************** + * GetServiceKeyNameW (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH GetServiceKeyNameW( SC_HANDLE manager, const WCHAR *display_name, + WCHAR *key_name, DWORD *len ) +{ + DWORD err; + WCHAR buffer[2]; + DWORD size; + + TRACE( "%p %s %p %p\n", manager, debugstr_w(display_name), key_name, len ); + + if (!manager) + { + SetLastError( ERROR_INVALID_HANDLE ); + return FALSE; + } + + /* provide a buffer if the caller didn't */ + if (!key_name || *len < 2) + { + key_name = buffer; + /* A size of 1 would be enough, but tests show that Windows returns 2, + * probably because of a WCHAR/bytes mismatch in their code. + */ + *len = 2; + } + + /* RPC call takes size excluding nul-terminator, whereas *len + * includes the nul-terminator on input. */ + size = *len - 1; + + __TRY + { + err = svcctl_GetServiceKeyNameW( manager, display_name, key_name, &size ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + /* The value of *lpcchBuffer excludes nul-terminator on output. */ + if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER) + *len = size; + return set_error( err ); +} + +/****************************************************************************** + * StartServiceA (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH StartServiceA( SC_HANDLE service, DWORD argc, const char **argv ) +{ + WCHAR **argvW = NULL; + DWORD i; + BOOL r; + + if (argc) + argvW = heap_alloc( argc * sizeof(WCHAR) ); + + for (i = 0; i < argc; i++) + argvW[i] = heap_strdupAtoW( argv[i] ); + + r = StartServiceW( service, argc, (const WCHAR **)argvW ); + + for (i = 0; i < argc; i++) + heap_free( argvW[i] ); + heap_free( argv ); + return r; +} + + +/****************************************************************************** + * StartServiceW (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH StartServiceW( SC_HANDLE service, DWORD argc, const WCHAR **argv ) +{ + DWORD err; + + TRACE( "%p %u %p\n", service, argc, argv ); + + __TRY + { + err = svcctl_StartServiceW( service, argc, argv ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + return set_error( err ); +} + +/****************************************************************************** + * ControlService (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH ControlService( SC_HANDLE service, DWORD control, SERVICE_STATUS *status ) +{ + DWORD err; + + TRACE( "%p %d %p\n", service, control, status ); + + __TRY + { + err = svcctl_ControlService( service, control, status ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + return set_error( err ); +} + +/****************************************************************************** + * QueryServiceStatus (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceStatus( SC_HANDLE service, SERVICE_STATUS *status ) +{ + SERVICE_STATUS_PROCESS process_status; + BOOL ret; + DWORD size; + + TRACE( "%p %p\n", service, status ); + + if (!service) return set_error( ERROR_INVALID_HANDLE ); + if (!status) return set_error( ERROR_INVALID_ADDRESS ); + + ret = QueryServiceStatusEx( service, SC_STATUS_PROCESS_INFO, (BYTE *)&process_status, + sizeof(SERVICE_STATUS_PROCESS), &size ); + if (ret) memcpy(status, &process_status, sizeof(SERVICE_STATUS) ); + return ret; +} + +/****************************************************************************** + * QueryServiceStatusEx (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceStatusEx( SC_HANDLE service, SC_STATUS_TYPE level, + BYTE *buffer, DWORD size, DWORD *ret_size ) +{ + DWORD err; + + TRACE( "%p %d %p %d %p\n", service, level, buffer, size, ret_size ); + + if (level != SC_STATUS_PROCESS_INFO) return set_error( ERROR_INVALID_LEVEL ); + + if (size < sizeof(SERVICE_STATUS_PROCESS)) + { + *ret_size = sizeof(SERVICE_STATUS_PROCESS); + return set_error( ERROR_INSUFFICIENT_BUFFER ); + } + + __TRY + { + err = svcctl_QueryServiceStatusEx( service, level, buffer, size, ret_size ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + return set_error( err ); +} + +/****************************************************************************** + * EnumServicesStatusExW (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH EnumServicesStatusExW( SC_HANDLE manager, SC_ENUM_TYPE level, DWORD type, DWORD state, + BYTE *buffer, DWORD size, DWORD *needed, DWORD *returned, + DWORD *resume_handle, const WCHAR *group ) +{ + DWORD err, i, offset, buflen, count, total_size = 0; + ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer; + struct enum_service_status_process *entry; + const WCHAR *str; + BYTE *buf; + + TRACE( "%p %u 0x%x 0x%x %p %u %p %p %p %s\n", manager, level, type, state, buffer, + size, needed, returned, resume_handle, debugstr_w(group) ); + + if (level != SC_ENUM_PROCESS_INFO) return set_error( ERROR_INVALID_LEVEL ); + if (!manager) return set_error( ERROR_INVALID_HANDLE ); + if (!needed || !returned) return set_error( ERROR_INVALID_ADDRESS ); + + /* make sure we pass a valid pointer */ + buflen = max( size, sizeof(*services) ); + if (!(buf = heap_alloc( buflen ))) return set_error( ERROR_NOT_ENOUGH_MEMORY ); + + __TRY + { + err = svcctl_EnumServicesStatusExW( manager, SC_ENUM_PROCESS_INFO, type, state, buf, buflen, needed, + &count, resume_handle, group ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + *returned = 0; + if (err != ERROR_SUCCESS) + { + /* double the needed size to fit the potentially larger ENUM_SERVICE_STATUS_PROCESSW */ + if (err == ERROR_MORE_DATA) *needed *= 2; + heap_free( buf ); + SetLastError( err ); + return FALSE; + } + + entry = (struct enum_service_status_process *)buf; + for (i = 0; i < count; i++) + { + total_size += sizeof(*services); + if (entry->service_name) + { + str = (const WCHAR *)(buf + entry->service_name); + total_size += (wcslen( str ) + 1) * sizeof(WCHAR); + } + if (entry->display_name) + { + str = (const WCHAR *)(buf + entry->display_name); + total_size += (wcslen( str ) + 1) * sizeof(WCHAR); + } + entry++; + } + + if (total_size > size) + { + heap_free( buf ); + *needed = total_size; + SetLastError( ERROR_MORE_DATA ); + return FALSE; + } + + offset = count * sizeof(*services); + entry = (struct enum_service_status_process *)buf; + for (i = 0; i < count; i++) + { + DWORD str_size; + str = (const WCHAR *)(buf + entry->service_name); + str_size = (wcslen( str ) + 1) * sizeof(WCHAR); + services[i].lpServiceName = (WCHAR *)((char *)services + offset); + memcpy( services[i].lpServiceName, str, str_size ); + offset += str_size; + + if (!entry->display_name) services[i].lpDisplayName = NULL; + else + { + str = (const WCHAR *)(buf + entry->display_name); + str_size = (wcslen( str ) + 1) * sizeof(WCHAR); + services[i].lpDisplayName = (WCHAR *)((char *)services + offset); + memcpy( services[i].lpDisplayName, str, str_size ); + offset += str_size; + } + services[i].ServiceStatusProcess = entry->service_status_process; + entry++; + } + + heap_free( buf ); + *needed = 0; + *returned = count; + return TRUE; +} + +/****************************************************************************** + * EnumDependentServicesW (sechost.@) + */ +BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState, + LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize, + LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned ) +{ + FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState, + lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned); + + *lpServicesReturned = 0; + return TRUE; +} + +/****************************************************************************** + * QueryServiceObjectSecurity (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceObjectSecurity( SC_HANDLE service, SECURITY_INFORMATION type, + PSECURITY_DESCRIPTOR ret_descriptor, DWORD size, DWORD *ret_size ) +{ + SECURITY_DESCRIPTOR descriptor; + NTSTATUS status; + ACL acl; + + FIXME( "%p %d %p %u %p - semi-stub\n", service, type, ret_descriptor, size, ret_size ); + + if (type != DACL_SECURITY_INFORMATION) + FIXME("information %d not supported\n", type); + + InitializeSecurityDescriptor( &descriptor, SECURITY_DESCRIPTOR_REVISION ); + + InitializeAcl( &acl, sizeof(ACL), ACL_REVISION ); + SetSecurityDescriptorDacl( &descriptor, TRUE, &acl, TRUE ); + + status = RtlMakeSelfRelativeSD( &descriptor, ret_descriptor, &size ); + *ret_size = size; + + return set_error( RtlNtStatusToDosError( status ) ); +} + +/****************************************************************************** + * SetServiceObjectSecurity (sechost.@) + */ +BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService, + SECURITY_INFORMATION dwSecurityInformation, + PSECURITY_DESCRIPTOR lpSecurityDescriptor) +{ + FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor); + return TRUE; +} + +static DWORD WINAPI notify_thread(void *user) +{ + DWORD err; + struct notify_data *data = user; + SC_RPC_NOTIFY_PARAMS_LIST *list = NULL; + SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 *cparams; + BOOL dummy; + + __TRY + { + /* GetNotifyResults blocks until there is an event */ + err = svcctl_GetNotifyResults(data->notify_handle, &list); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code(GetExceptionCode()); + } + __ENDTRY + + EnterCriticalSection( &service_cs ); + + list_remove(&data->entry); + + LeaveCriticalSection( &service_cs ); + + if (err == ERROR_SUCCESS && list) + { + cparams = list->NotifyParamsArray[0].u.params; + + data->notify_buffer->dwNotificationStatus = cparams->dwNotificationStatus; + memcpy(&data->notify_buffer->ServiceStatus, &cparams->ServiceStatus, + sizeof(SERVICE_STATUS_PROCESS)); + data->notify_buffer->dwNotificationTriggered = cparams->dwNotificationTriggered; + data->notify_buffer->pszServiceNames = NULL; + + QueueUserAPC((PAPCFUNC)data->notify_buffer->pfnNotifyCallback, + data->calling_thread, (ULONG_PTR)data->notify_buffer); + + HeapFree(GetProcessHeap(), 0, list); + } + else + WARN("GetNotifyResults server call failed: %u\n", err); + + + __TRY + { + err = svcctl_CloseNotifyHandle(&data->notify_handle, &dummy); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code(GetExceptionCode()); + } + __ENDTRY + + if (err != ERROR_SUCCESS) + WARN("CloseNotifyHandle server call failed: %u\n", err); + + CloseHandle(data->calling_thread); + HeapFree(GetProcessHeap(), 0, data); + + return 0; +} + +/****************************************************************************** + * NotifyServiceStatusChangeW (sechost.@) + */ +DWORD WINAPI DECLSPEC_HOTPATCH NotifyServiceStatusChangeW( SC_HANDLE service, DWORD mask, + SERVICE_NOTIFYW *notify_buffer ) +{ + DWORD err; + BOOL b_dummy = FALSE; + GUID g_dummy = {0}; + struct notify_data *data; + + TRACE( "%p 0x%x %p\n", service, mask, notify_buffer ); + + if (!(data = heap_alloc_zero( sizeof(*data) ))) + return ERROR_NOT_ENOUGH_MEMORY; + + data->service = service; + data->notify_buffer = notify_buffer; + if (!DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), + &data->calling_thread, 0, FALSE, DUPLICATE_SAME_ACCESS )) + { + ERR("DuplicateHandle failed: %u\n", GetLastError()); + heap_free( data ); + return ERROR_NOT_ENOUGH_MEMORY; + } + + data->params.dwInfoLevel = 2; + data->params.u.params = &data->cparams; + + data->cparams.dwNotifyMask = mask; + + EnterCriticalSection( &service_cs ); + + __TRY + { + err = svcctl_NotifyServiceStatusChange( service, data->params, &g_dummy, + &g_dummy, &b_dummy, &data->notify_handle ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + if (err != ERROR_SUCCESS) + { + WARN("NotifyServiceStatusChange server call failed: %u\n", err); + LeaveCriticalSection( &service_cs ); + CloseHandle( data->calling_thread ); + CloseHandle( data->ready_evt ); + heap_free( data ); + return err; + } + + CloseHandle( CreateThread( NULL, 0, ¬ify_thread, data, 0, NULL ) ); + + list_add_tail( ¬ify_list, &data->entry ); + + LeaveCriticalSection( &service_cs ); + + return ERROR_SUCCESS; +} + +/* thunk for calling the RegisterServiceCtrlHandler handler function */ +static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context ) +{ + LPHANDLER_FUNCTION func = context; + + func( control ); + return ERROR_SUCCESS; +} + +/****************************************************************************** + * RegisterServiceCtrlHandlerA (sechost.@) + */ +SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerA( + const char *name, LPHANDLER_FUNCTION handler ) +{ + return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler ); +} + +/****************************************************************************** + * RegisterServiceCtrlHandlerW (sechost.@) + */ +SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerW( + const WCHAR *name, LPHANDLER_FUNCTION handler ) +{ + return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler ); +} + +/****************************************************************************** + * RegisterServiceCtrlHandlerExA (sechost.@) + */ +SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerExA( + const char *name, LPHANDLER_FUNCTION_EX handler, void *context ) +{ + WCHAR *nameW; + SERVICE_STATUS_HANDLE ret; + + nameW = heap_strdupAtoW( name ); + ret = RegisterServiceCtrlHandlerExW( nameW, handler, context ); + heap_free( nameW ); + return ret; +} + +static struct service_data *find_service_by_name( const WCHAR *name ) +{ + unsigned int i; + + if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */ + return services[0]; + for (i = 0; i < nb_services; i++) + if (!wcsicmp( name, services[i]->name )) return services[i]; + return NULL; +} + +/****************************************************************************** + * RegisterServiceCtrlHandlerExW (sechost.@) + */ +SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerExW( + const WCHAR *name, LPHANDLER_FUNCTION_EX handler, void *context ) +{ + struct service_data *service; + SC_HANDLE handle = 0; + + TRACE( "%s %p %p\n", debugstr_w(name), handler, context ); + + EnterCriticalSection( &service_cs ); + if ((service = find_service_by_name( name ))) + { + service->handler = handler; + service->context = context; + handle = service->handle; + } + LeaveCriticalSection( &service_cs ); + + if (!handle) SetLastError( ERROR_SERVICE_DOES_NOT_EXIST ); + return (SERVICE_STATUS_HANDLE)handle; +} + +/****************************************************************************** + * SetServiceStatus (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH SetServiceStatus( SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status ) +{ + DWORD err; + + TRACE( "%p %#x %#x %#x %#x %#x %#x %#x\n", service, status->dwServiceType, + status->dwCurrentState, status->dwControlsAccepted, status->dwWin32ExitCode, + status->dwServiceSpecificExitCode, status->dwCheckPoint, status->dwWaitHint ); + + __TRY + { + err = svcctl_SetServiceStatus( service, status ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + if (!set_error( err )) + return FALSE; + + if (status->dwCurrentState == SERVICE_STOPPED) + { + unsigned int i, count = 0; + EnterCriticalSection( &service_cs ); + for (i = 0; i < nb_services; i++) + { + if (services[i]->handle == (SC_HANDLE)service) continue; + if (services[i]->thread) count++; + } + if (!count) + { + stop_service = TRUE; + SetEvent( service_event ); /* notify the main loop */ + } + LeaveCriticalSection( &service_cs ); + } + + return TRUE; +} + +static WCHAR *service_get_pipe_name(void) +{ + static const WCHAR format[] = L"\\\\.\\pipe\\net\\NtControlPipe%u"; + WCHAR *name; + DWORD len; + HKEY service_current_key; + DWORD service_current; + LONG ret; + DWORD type; + + ret = RegOpenKeyExW( HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", + 0, KEY_QUERY_VALUE, &service_current_key ); + if (ret != ERROR_SUCCESS) + return NULL; + + len = sizeof(service_current); + ret = RegQueryValueExW( service_current_key, NULL, NULL, &type, + (BYTE *)&service_current, &len ); + RegCloseKey(service_current_key); + if (ret != ERROR_SUCCESS || type != REG_DWORD) + return NULL; + + len = ARRAY_SIZE(format) + 10 /* strlenW("4294967295") */; + name = heap_alloc(len * sizeof(WCHAR)); + if (!name) + return NULL; + + swprintf( name, len, format, service_current ); + return name; +} + +static HANDLE service_open_pipe(void) +{ + WCHAR *pipe_name = service_get_pipe_name(); + HANDLE handle = INVALID_HANDLE_VALUE; + + do + { + handle = CreateFileW( pipe_name, GENERIC_READ|GENERIC_WRITE, + 0, NULL, OPEN_ALWAYS, 0, NULL ); + if (handle != INVALID_HANDLE_VALUE) + break; + if (GetLastError() != ERROR_PIPE_BUSY) + break; + } while (WaitNamedPipeW( pipe_name, NMPWAIT_USE_DEFAULT_WAIT )); + heap_free(pipe_name); + + return handle; +} + +static DWORD WINAPI service_thread( void *arg ) +{ + struct service_data *info = arg; + WCHAR *str = info->args; + DWORD argc = 0, len = 0; + + TRACE("%p\n", arg); + + while (str[len]) + { + len += wcslen( &str[len] ) + 1; + argc++; + } + len++; + + if (info->unicode) + { + WCHAR **argv, *p; + + argv = heap_alloc( (argc+1)*sizeof(*argv) ); + for (argc = 0, p = str; *p; p += wcslen( p ) + 1) + argv[argc++] = p; + argv[argc] = NULL; + + info->proc.w( argc, argv ); + heap_free( argv ); + } + else + { + char *strA, **argv, *p; + DWORD lenA; + + lenA = WideCharToMultiByte( CP_ACP,0, str, len, NULL, 0, NULL, NULL ); + strA = heap_alloc(lenA); + WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL); + + argv = heap_alloc( (argc+1)*sizeof(*argv) ); + for (argc = 0, p = strA; *p; p += strlen( p ) + 1) + argv[argc++] = p; + argv[argc] = NULL; + + info->proc.a( argc, argv ); + heap_free( argv ); + heap_free( strA ); + } + return 0; +} + +static DWORD service_handle_start( struct service_data *service, const void *data, DWORD data_size ) +{ + DWORD count = data_size / sizeof(WCHAR); + + if (service->thread) + { + WARN("service is not stopped\n"); + return ERROR_SERVICE_ALREADY_RUNNING; + } + + heap_free( service->args ); + service->args = heap_alloc( (count + 2) * sizeof(WCHAR) ); + if (count) memcpy( service->args, data, count * sizeof(WCHAR) ); + service->args[count++] = 0; + service->args[count++] = 0; + + service->thread = CreateThread( NULL, 0, service_thread, + service, 0, NULL ); + SetEvent( service_event ); /* notify the main loop */ + return 0; +} + +static DWORD service_handle_control( struct service_data *service, DWORD control, const void *data, DWORD data_size ) +{ + DWORD ret = ERROR_INVALID_SERVICE_CONTROL; + + TRACE( "%s control %u data %p data_size %u\n", debugstr_w(service->name), control, data, data_size ); + + if (control == SERVICE_CONTROL_START) + ret = service_handle_start( service, data, data_size ); + else if (service->handler) + ret = service->handler( control, 0, (void *)data, service->context ); + return ret; +} + +static DWORD WINAPI service_control_dispatcher( void *arg ) +{ + struct dispatcher_data *disp = arg; + + /* dispatcher loop */ + while (1) + { + struct service_data *service; + service_start_info info; + BYTE *data = NULL; + WCHAR *name; + BOOL r; + DWORD data_size = 0, count, result; + + r = ReadFile( disp->pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL ); + if (!r) + { + if (GetLastError() != ERROR_BROKEN_PIPE) + ERR( "pipe read failed error %u\n", GetLastError() ); + break; + } + if (count != FIELD_OFFSET(service_start_info,data)) + { + ERR( "partial pipe read %u\n", count ); + break; + } + if (count < info.total_size) + { + data_size = info.total_size - FIELD_OFFSET(service_start_info,data); + data = heap_alloc( data_size ); + r = ReadFile( disp->pipe, data, data_size, &count, NULL ); + if (!r) + { + if (GetLastError() != ERROR_BROKEN_PIPE) + ERR( "pipe read failed error %u\n", GetLastError() ); + heap_free( data ); + break; + } + if (count != data_size) + { + ERR( "partial pipe read %u/%u\n", count, data_size ); + heap_free( data ); + break; + } + } + + EnterCriticalSection( &service_cs ); + + /* validate service name */ + name = (WCHAR *)data; + if (!info.name_size || data_size < info.name_size * sizeof(WCHAR) || name[info.name_size - 1]) + { + ERR( "got request without valid service name\n" ); + result = ERROR_INVALID_PARAMETER; + goto done; + } + + if (info.magic != SERVICE_PROTOCOL_MAGIC) + { + ERR( "received invalid request for service %s\n", debugstr_w(name) ); + result = ERROR_INVALID_PARAMETER; + goto done; + } + + /* find the service */ + if (!(service = find_service_by_name( name ))) + { + FIXME( "got request for unknown service %s\n", debugstr_w(name) ); + result = ERROR_INVALID_PARAMETER; + goto done; + } + + if (!service->handle) + { + if (!(service->handle = OpenServiceW( disp->manager, name, SERVICE_SET_STATUS )) || + !(service->full_access_handle = OpenServiceW( disp->manager, name, + GENERIC_READ|GENERIC_WRITE ))) + FIXME( "failed to open service %s\n", debugstr_w(name) ); + } + + data_size -= info.name_size * sizeof(WCHAR); + result = service_handle_control(service, info.control, data_size ? + &data[info.name_size * sizeof(WCHAR)] : NULL, data_size); + + done: + LeaveCriticalSection( &service_cs ); + WriteFile( disp->pipe, &result, sizeof(result), &count, NULL ); + heap_free( data ); + } + + CloseHandle( disp->pipe ); + CloseServiceHandle( disp->manager ); + heap_free( disp ); + return 1; +} + +/* wait for services which accept this type of message to become STOPPED */ +static void handle_shutdown_msg(DWORD msg, DWORD accept) +{ + SERVICE_STATUS st; + SERVICE_PRESHUTDOWN_INFO spi; + DWORD i, n = 0, sz, timeout = 2000; + ULONGLONG stop_time; + BOOL res, done = TRUE; + SC_HANDLE *wait_handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SC_HANDLE) * nb_services ); + + EnterCriticalSection( &service_cs ); + for (i = 0; i < nb_services; i++) + { + res = QueryServiceStatus( services[i]->full_access_handle, &st ); + if (!res || st.dwCurrentState == SERVICE_STOPPED || !(st.dwControlsAccepted & accept)) + continue; + + done = FALSE; + + if (accept == SERVICE_ACCEPT_PRESHUTDOWN) + { + res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO, + (BYTE *)&spi, sizeof(spi), &sz ); + if (res) + { + FIXME( "service should be able to delay shutdown\n" ); + timeout = max( spi.dwPreshutdownTimeout, timeout ); + } + } + + service_handle_control( services[i], msg, NULL, 0 ); + wait_handles[n++] = services[i]->full_access_handle; + } + LeaveCriticalSection( &service_cs ); + + /* FIXME: these timeouts should be more generous, but we can't currently delay prefix shutdown */ + timeout = min( timeout, 3000 ); + stop_time = GetTickCount64() + timeout; + + while (!done && GetTickCount64() < stop_time) + { + done = TRUE; + for (i = 0; i < n; i++) + { + res = QueryServiceStatus( wait_handles[i], &st ); + if (!res || st.dwCurrentState == SERVICE_STOPPED) + continue; + + done = FALSE; + Sleep( 100 ); + break; + } + } + + HeapFree( GetProcessHeap(), 0, wait_handles ); +} + +static BOOL service_run_main_thread(void) +{ + DWORD i, n, ret; + HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS]; + UINT wait_services[MAXIMUM_WAIT_OBJECTS]; + struct dispatcher_data *disp = heap_alloc( sizeof(*disp) ); + + disp->manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT ); + if (!disp->manager) + { + ERR("failed to open service manager error %u\n", GetLastError()); + heap_free( disp ); + return FALSE; + } + + disp->pipe = service_open_pipe(); + if (disp->pipe == INVALID_HANDLE_VALUE) + { + WARN("failed to create control pipe error %u\n", GetLastError()); + CloseServiceHandle( disp->manager ); + heap_free( disp ); + SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT ); + return FALSE; + } + + service_event = CreateEventW( NULL, FALSE, FALSE, NULL ); + stop_service = FALSE; + + /* FIXME: service_control_dispatcher should be merged into the main thread */ + wait_handles[0] = __wine_make_process_system(); + wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, disp, 0, NULL ); + wait_handles[2] = service_event; + + TRACE("Starting %d services running as process %d\n", + nb_services, GetCurrentProcessId()); + + /* wait for all the threads to pack up and exit */ + while (!stop_service) + { + EnterCriticalSection( &service_cs ); + for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++) + { + if (!services[i]->thread) continue; + wait_services[n] = i; + wait_handles[n++] = services[i]->thread; + } + LeaveCriticalSection( &service_cs ); + + ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE ); + if (!ret) /* system process event */ + { + handle_shutdown_msg(SERVICE_CONTROL_PRESHUTDOWN, SERVICE_ACCEPT_PRESHUTDOWN); + handle_shutdown_msg(SERVICE_CONTROL_SHUTDOWN, SERVICE_ACCEPT_SHUTDOWN); + ExitProcess(0); + } + else if (ret == 1) + { + TRACE( "control dispatcher exited, shutting down\n" ); + /* FIXME: we should maybe send a shutdown control to running services */ + ExitProcess(0); + } + else if (ret == 2) + { + continue; /* rebuild the list */ + } + else if (ret < n) + { + i = wait_services[ret]; + EnterCriticalSection( &service_cs ); + CloseHandle( services[i]->thread ); + services[i]->thread = NULL; + LeaveCriticalSection( &service_cs ); + } + else return FALSE; + } + + return TRUE; +} + +/****************************************************************************** + * StartServiceCtrlDispatcherA (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent ) +{ + struct service_data *info; + unsigned int i; + + TRACE("%p\n", servent); + + if (nb_services) + { + SetLastError( ERROR_SERVICE_ALREADY_RUNNING ); + return FALSE; + } + while (servent[nb_services].lpServiceName) nb_services++; + if (!nb_services) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + services = heap_alloc( nb_services * sizeof(*services) ); + + for (i = 0; i < nb_services; i++) + { + DWORD len = MultiByteToWideChar( CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0 ); + DWORD sz = FIELD_OFFSET( struct service_data, name[len] ); + info = heap_alloc_zero( sz ); + MultiByteToWideChar( CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len ); + info->proc.a = servent[i].lpServiceProc; + info->unicode = FALSE; + services[i] = info; + } + + return service_run_main_thread(); +} + +/****************************************************************************** + * StartServiceCtrlDispatcherW (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent ) +{ + struct service_data *info; + unsigned int i; + + TRACE("%p\n", servent); + + if (nb_services) + { + SetLastError( ERROR_SERVICE_ALREADY_RUNNING ); + return FALSE; + } + while (servent[nb_services].lpServiceName) nb_services++; + if (!nb_services) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + services = heap_alloc( nb_services * sizeof(*services) ); + + for (i = 0; i < nb_services; i++) + { + DWORD len = wcslen( servent[i].lpServiceName ) + 1; + DWORD sz = FIELD_OFFSET( struct service_data, name[len] ); + info = heap_alloc_zero( sz ); + wcscpy( info->name, servent[i].lpServiceName ); + info->proc.w = servent[i].lpServiceProc; + info->unicode = TRUE; + services[i] = info; + } + + return service_run_main_thread(); +} diff --git a/dlls/advapi32/svcctl.idl b/dlls/sechost/svcctl.idl similarity index 100% rename from dlls/advapi32/svcctl.idl rename to dlls/sechost/svcctl.idl -- 2.26.2
[View Less]
1
0
0
0
[PATCH 1/5] quartz/vmr9: Don't expose IVMRSurfaceAllocatorNotify from the VMR9.
by Zebediah Figura
28 Apr '20
28 Apr '20
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com> --- dlls/quartz/tests/vmr9.c | 2 +- dlls/quartz/vmr9.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/dlls/quartz/tests/vmr9.c b/dlls/quartz/tests/vmr9.c index e78d20a4118..4bba6f74319 100644 --- a/dlls/quartz/tests/vmr9.c +++ b/dlls/quartz/tests/vmr9.c @@ -298,7 +298,7 @@ static void test_interfaces(void) check_interface(filter, &IID_IVMRMixerControl, FALSE); todo_wine
…
[View More]
check_interface(filter, &IID_IVMRMonitorConfig, FALSE); todo_wine check_interface(filter, &IID_IVMRMonitorConfig9, FALSE); - todo_wine check_interface(filter, &IID_IVMRSurfaceAllocatorNotify, FALSE); + check_interface(filter, &IID_IVMRSurfaceAllocatorNotify, FALSE); check_interface(filter, &IID_IVMRWindowlessControl, FALSE); check_interface(filter, &IID_IVMRWindowlessControl9, FALSE); diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index 389166db3ed..c847b9c448d 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -91,6 +91,11 @@ struct quartz_vmr HANDLE run_event; }; +static inline BOOL is_vmr9(const struct quartz_vmr *filter) +{ + return IsEqualGUID(&filter->renderer.filter.clsid, &CLSID_VideoMixingRenderer9); +} + static inline struct quartz_vmr *impl_from_video_window(struct video_window *iface) { return CONTAINING_RECORD(iface, struct quartz_vmr, baseControlWindow); @@ -435,7 +440,7 @@ static HRESULT VMR9_maybe_init(struct quartz_vmr *filter, BOOL force, const AM_M return E_FAIL; } - if (IsEqualGUID(&filter->renderer.filter.clsid, &CLSID_VideoMixingRenderer)) + if (!is_vmr9(filter)) { switch (filter->bmiheader.biBitCount) { @@ -621,7 +626,8 @@ static HRESULT vmr_query_interface(struct strmbase_renderer *iface, REFIID iid, *out = &filter->IVMRMonitorConfig_iface; else if (IsEqualGUID(iid, &IID_IVMRMonitorConfig9)) *out = &filter->IVMRMonitorConfig9_iface; - else if (IsEqualGUID(iid, &IID_IVMRSurfaceAllocatorNotify) && filter->mode == (VMR9Mode)VMRMode_Renderless) + else if (IsEqualGUID(iid, &IID_IVMRSurfaceAllocatorNotify) + && filter->mode == (VMR9Mode)VMRMode_Renderless && !is_vmr9(filter)) *out = &filter->IVMRSurfaceAllocatorNotify_iface; else if (IsEqualGUID(iid, &IID_IVMRSurfaceAllocatorNotify9) && filter->mode == VMR9Mode_Renderless) *out = &filter->IVMRSurfaceAllocatorNotify9_iface; -- 2.26.2
[View Less]
1
4
0
0
[PATCH 6/6] include: Add d3d11 video processor capability flags.
by Henri Verbeet
28 Apr '20
28 Apr '20
From: Biswapriyo Nath <nathbappai(a)gmail.com> Signed-off-by: Biswapriyo Nath <nathbappai(a)gmail.com> Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com> --- This supersedes patch 184353. include/d3d11.idl | 66 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/include/d3d11.idl b/include/d3d11.idl index 9ecb3af091a..507cfd012a0 100644 --- a/include/d3d11.idl +++ b/include/d3d11.idl @@ -360,6 +360,72 @@ typedef enum
…
[View More]
D3D11_VIDEO_PROCESSOR_ROTATION D3D11_VIDEO_PROCESSOR_ROTATION_270 = 3, } D3D11_VIDEO_PROCESSOR_ROTATION; +typedef enum D3D11_VIDEO_PROCESSOR_DEVICE_CAPS +{ + D3D11_VIDEO_PROCESSOR_DEVICE_CAPS_LINEAR_SPACE = 0x00000001, + D3D11_VIDEO_PROCESSOR_DEVICE_CAPS_xvYCC = 0x00000002, + D3D11_VIDEO_PROCESSOR_DEVICE_CAPS_RGB_RANGE_CONVERSION = 0x00000004, + D3D11_VIDEO_PROCESSOR_DEVICE_CAPS_YCbCr_MATRIX_CONVERSION = 0x00000008, + D3D11_VIDEO_PROCESSOR_DEVICE_CAPS_NOMINAL_RANGE = 0x00000010, +} D3D11_VIDEO_PROCESSOR_DEVICE_CAPS; + +typedef enum D3D11_VIDEO_PROCESSOR_FEATURE_CAPS +{ + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_ALPHA_FILL = 0x00000001, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_CONSTRICTION = 0x00000002, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_LUMA_KEY = 0x00000004, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_ALPHA_PALETTE = 0x00000008, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_LEGACY = 0x00000010, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_STEREO = 0x00000020, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_ROTATION = 0x00000040, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_ALPHA_STREAM = 0x00000080, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_PIXEL_ASPECT_RATIO = 0x00000100, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_MIRROR = 0x00000200, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_SHADER_USAGE = 0x00000400, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_METADATA_HDR10 = 0x00000800, +} D3D11_VIDEO_PROCESSOR_FEATURE_CAPS; + +typedef enum D3D11_VIDEO_PROCESSOR_FILTER_CAPS +{ + D3D11_VIDEO_PROCESSOR_FILTER_CAPS_BRIGHTNESS = 0x00000001, + D3D11_VIDEO_PROCESSOR_FILTER_CAPS_CONTRAST = 0x00000002, + D3D11_VIDEO_PROCESSOR_FILTER_CAPS_HUE = 0x00000004, + D3D11_VIDEO_PROCESSOR_FILTER_CAPS_SATURATION = 0x00000008, + D3D11_VIDEO_PROCESSOR_FILTER_CAPS_NOISE_REDUCTION = 0x00000010, + D3D11_VIDEO_PROCESSOR_FILTER_CAPS_EDGE_ENHANCEMENT = 0x00000020, + D3D11_VIDEO_PROCESSOR_FILTER_CAPS_ANAMORPHIC_SCALING = 0x00000040, + D3D11_VIDEO_PROCESSOR_FILTER_CAPS_STEREO_ADJUSTMENT = 0x00000080, +} D3D11_VIDEO_PROCESSOR_FILTER_CAPS; + +typedef enum D3D11_VIDEO_PROCESSOR_FORMAT_CAPS +{ + D3D11_VIDEO_PROCESSOR_FORMAT_CAPS_RGB_INTERLACED = 0x00000001, + D3D11_VIDEO_PROCESSOR_FORMAT_CAPS_RGB_PROCAMP = 0x00000002, + D3D11_VIDEO_PROCESSOR_FORMAT_CAPS_RGB_LUMA_KEY = 0x00000004, + D3D11_VIDEO_PROCESSOR_FORMAT_CAPS_PALETTE_INTERLACED = 0x00000008, +} D3D11_VIDEO_PROCESSOR_FORMAT_CAPS; + +typedef enum D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS +{ + D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS_DENOISE = 0x00000001, + D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS_DERINGING = 0x00000002, + D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS_EDGE_ENHANCEMENT = 0x00000004, + D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS_COLOR_CORRECTION = 0x00000008, + D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS_FLESH_TONE_MAPPING = 0x00000010, + D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS_IMAGE_STABILIZATION = 0x00000020, + D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS_SUPER_RESOLUTION = 0x00000040, + D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS_ANAMORPHIC_SCALING = 0x00000080, +} D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS; + +typedef enum D3D11_VIDEO_PROCESSOR_STEREO_CAPS +{ + D3D11_VIDEO_PROCESSOR_STEREO_CAPS_MONO_OFFSET = 0x00000001, + D3D11_VIDEO_PROCESSOR_STEREO_CAPS_ROW_INTERLEAVED = 0x00000002, + D3D11_VIDEO_PROCESSOR_STEREO_CAPS_COLUMN_INTERLEAVED = 0x00000004, + D3D11_VIDEO_PROCESSOR_STEREO_CAPS_CHECKERBOARD = 0x00000008, + D3D11_VIDEO_PROCESSOR_STEREO_CAPS_FLIP_MODE = 0x00000010, +} D3D11_VIDEO_PROCESSOR_STEREO_CAPS; + typedef enum D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS { D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BLEND = 0x01, -- 2.20.1
[View Less]
1
0
0
0
[PATCH 5/6] wined3d: Use DISCARD maps in wined3d_buffer_vk_upload_ranges() if possible.
by Henri Verbeet
28 Apr '20
28 Apr '20
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com> --- dlls/wined3d/buffer.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c index 1444ac9b633..703a8aee70e 100644 --- a/dlls/wined3d/buffer.c +++ b/dlls/wined3d/buffer.c @@ -1649,6 +1649,7 @@ static void wined3d_buffer_vk_upload_ranges(struct wined3d_buffer *buffer, struc const struct wined3d_range *range; struct wined3d_bo_address dst; unsigned
…
[View More]
int i = range_count; + uint32_t flags; void *map_ptr; if (!range_count) @@ -1657,7 +1658,10 @@ static void wined3d_buffer_vk_upload_ranges(struct wined3d_buffer *buffer, struc dst.buffer_object = buffer->buffer_object; dst.addr = NULL; - if (!(map_ptr = wined3d_context_map_bo_address(context, &dst, resource->size, WINED3D_MAP_WRITE))) + flags = WINED3D_MAP_WRITE; + if (!ranges->offset && ranges->size == resource->size) + flags |= WINED3D_MAP_DISCARD; + if (!(map_ptr = wined3d_context_map_bo_address(context, &dst, resource->size, flags))) { FIXME("Failed to map buffer.\n"); return; -- 2.20.1
[View Less]
1
0
0
0
[PATCH 4/6] wined3d: Implement WINED3D_MAP_DISCARD support in adapter_vk_map_bo_address().
by Henri Verbeet
28 Apr '20
28 Apr '20
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com> --- dlls/wined3d/adapter_vk.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c index b6a0eea7852..f9b3e4721a2 100644 --- a/dlls/wined3d/adapter_vk.c +++ b/dlls/wined3d/adapter_vk.c @@ -813,8 +813,8 @@ static void *adapter_vk_map_bo_address(struct wined3d_context *context, struct wined3d_device_vk *device_vk; VkCommandBuffer
…
[View More]
vk_command_buffer; VkBufferMemoryBarrier vk_barrier; + struct wined3d_bo_vk *bo, tmp; VkMappedMemoryRange range; - struct wined3d_bo_vk *bo; void *map_ptr; if (!(bo = (struct wined3d_bo_vk *)data->buffer_object)) @@ -826,6 +826,19 @@ static void *adapter_vk_map_bo_address(struct wined3d_context *context, if (map_flags & WINED3D_MAP_NOOVERWRITE) goto map; + if ((map_flags & WINED3D_MAP_DISCARD) && bo->command_buffer_id > context_vk->completed_command_buffer_id) + { + if (wined3d_context_vk_create_bo(context_vk, bo->size, bo->usage, bo->memory_type, &tmp)) + { + wined3d_context_vk_destroy_bo(context_vk, bo); + *bo = tmp; + + goto map; + } + + ERR("Failed to create new buffer object.\n"); + } + if (map_flags & WINED3D_MAP_READ) { if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk))) -- 2.20.1
[View Less]
1
0
0
0
[PATCH 3/6] wined3d: Add Vulkan format information for WINED3DFMT_D24_UNORM_S8_UINT.
by Henri Verbeet
28 Apr '20
28 Apr '20
On some implementations we could use VK_FORMAT_D24_UNORM_S8_UINT instead, but that's not universally supported. Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com> --- dlls/wined3d/utils.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index be3ad90107a..5e9673f2c76 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -4203,6 +4203,7 @@ static void init_vulkan_format_info(struct wined3d_format_vk *format, {
…
[View More]
WINED3DFMT_D32_FLOAT_S8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, }, {WINED3DFMT_R32_FLOAT_X8X24_TYPELESS, VK_FORMAT_D32_SFLOAT_S8_UINT, }, {WINED3DFMT_X32_TYPELESS_G8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, }, + {WINED3DFMT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, }, }; VkFormat vk_format = VK_FORMAT_UNDEFINED; VkImageFormatProperties image_properties; -- 2.20.1
[View Less]
1
0
0
0
[PATCH 2/6] wined3d: Add Vulkan format information for WINED3DFMT_X32_TYPELESS_G8X24_UINT.
by Henri Verbeet
28 Apr '20
28 Apr '20
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com> --- dlls/wined3d/utils.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index b5df4a2b106..be3ad90107a 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -4202,6 +4202,7 @@ static void init_vulkan_format_info(struct wined3d_format_vk *format, {WINED3DFMT_R9G9B9E5_SHAREDEXP, VK_FORMAT_E5B9G9R9_UFLOAT_PACK32, }, {WINED3DFMT_D32_FLOAT_S8X24_UINT,
…
[View More]
VK_FORMAT_D32_SFLOAT_S8_UINT, }, {WINED3DFMT_R32_FLOAT_X8X24_TYPELESS, VK_FORMAT_D32_SFLOAT_S8_UINT, }, + {WINED3DFMT_X32_TYPELESS_G8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, }, }; VkFormat vk_format = VK_FORMAT_UNDEFINED; VkImageFormatProperties image_properties; -- 2.20.1
[View Less]
1
0
0
0
[PATCH 1/6] wined3d: Add Vulkan format information for WINED3DFMT_R32_FLOAT_X8X24_TYPELESS.
by Henri Verbeet
28 Apr '20
28 Apr '20
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com> --- dlls/wined3d/utils.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index 0397056441f..b5df4a2b106 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -4201,6 +4201,7 @@ static void init_vulkan_format_info(struct wined3d_format_vk *format, {WINED3DFMT_BC7_UNORM_SRGB, VK_FORMAT_BC7_SRGB_BLOCK, }, {WINED3DFMT_R9G9B9E5_SHAREDEXP,
…
[View More]
VK_FORMAT_E5B9G9R9_UFLOAT_PACK32, }, {WINED3DFMT_D32_FLOAT_S8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, }, + {WINED3DFMT_R32_FLOAT_X8X24_TYPELESS, VK_FORMAT_D32_SFLOAT_S8_UINT, }, }; VkFormat vk_format = VK_FORMAT_UNDEFINED; VkImageFormatProperties image_properties; -- 2.20.1
[View Less]
1
0
0
0
← Newer
1
...
4
5
6
7
8
9
10
...
86
Older →
Jump to page:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
Results per page:
10
25
50
100
200