Beyond whether this approach is acceptable, one thing I'd appreciate feedback on is a better name for the wine driver. winevideo.sys seems too generic and winevideoresource.sys seems too verbose. --- configure.ac | 1 + dlls/ntoskrnl.exe/ntoskrnl.c | 57 +++++- dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 2 + dlls/vulkan-1/tests/vulkan.c | 9 +- dlls/winevideo.sys/Makefile.in | 6 + dlls/winevideo.sys/winevideo.c | 284 ++++++++++++++++++++++++++ dlls/winevideo.sys/winevideo.sys.spec | 1 + dlls/winevulkan/vulkan.c | 82 +++++++- include/ddk/wdm.h | 1 + loader/wine.inf.in | 13 ++ 10 files changed, 443 insertions(+), 13 deletions(-) create mode 100644 dlls/winevideo.sys/Makefile.in create mode 100644 dlls/winevideo.sys/winevideo.c create mode 100644 dlls/winevideo.sys/winevideo.sys.spec
diff --git a/configure.ac b/configure.ac index 46bbb8a70f8..0071eeb0dd3 100644 --- a/configure.ac +++ b/configure.ac @@ -3823,6 +3823,7 @@ WINE_CONFIG_MAKEFILE(dlls/wineps16.drv16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/winepulse.drv) WINE_CONFIG_MAKEFILE(dlls/wineqtdecoder) WINE_CONFIG_MAKEFILE(dlls/wineusb.sys) +WINE_CONFIG_MAKEFILE(dlls/winevideo.sys) WINE_CONFIG_MAKEFILE(dlls/winevulkan) WINE_CONFIG_MAKEFILE(dlls/winex11.drv) WINE_CONFIG_MAKEFILE(dlls/wing.dll16,enable_win16) diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 5b84c626547..5156f3d3ab1 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -138,6 +138,10 @@ static HANDLE get_device_manager(void) struct object_header { LONG ref; + /* only blocks object from being freed, not released */ + LONG weak_ref; + /* an additional ref used to indicate whether server is done w/ obj */ + BOOL in_server; POBJECT_TYPE type; };
@@ -166,6 +170,7 @@ void *alloc_kernel_object( POBJECT_TYPE type, HANDLE handle, SIZE_T size, LONG r } SERVER_END_REQ; if (status) FIXME( "set_object_reference failed: %#x\n", status ); + else header->in_server = TRUE; }
header->ref = ref; @@ -197,7 +202,8 @@ void WINAPI ObDereferenceObject( void *obj ) { if (header->type->release) { - header->type->release( obj ); + if (!header->weak_ref) + header->type->release( obj ); } else { @@ -227,6 +233,13 @@ void ObReferenceObject( void *obj )
EnterCriticalSection( &obref_cs );
+ if (header->ref == 0 && !header->in_server) + { + ERR("Weak references may not be turned into strong references\n"); + LeaveCriticalSection( &obref_cs ); + return; + } + ref = ++header->ref; TRACE( "(%p) ref=%u\n", obj, ref ); if (ref == 1) @@ -246,7 +259,37 @@ void ObReferenceObject( void *obj ) ULONG WINAPI ObGetObjectPointerCount( void *object ) { struct object_header *header = (struct object_header *)object - 1; - return header->ref; + return header->ref + header->in_server; +} + +void CDECL wine_ob_weak_ref( void *object ) +{ + struct object_header *header = (struct object_header *) object - 1; + + EnterCriticalSection( &obref_cs ); + + header->weak_ref++; + + LeaveCriticalSection( &obref_cs ); +} + +void CDECL wine_ob_weak_deref( void *object ) +{ + struct object_header *header = (struct object_header *) object - 1; + + EnterCriticalSection( &obref_cs ); + + header->weak_ref--; + + if (!header->weak_ref && !header->ref && !header->in_server) + { + if (header->type->release) + header->type->release(object); + else + free_kernel_object(object); + } + + LeaveCriticalSection( &obref_cs ); }
/*********************************************************************** @@ -814,8 +857,16 @@ static NTSTATUS dispatch_volume( struct dispatch_context *context ) static NTSTATUS dispatch_free( struct dispatch_context *context ) { void *obj = wine_server_get_ptr( context->params.free.obj ); + struct object_header *header = (struct object_header *)obj - 1; + TRACE( "freeing %p object\n", obj ); - free_kernel_object( obj ); + + EnterCriticalSection(&obref_cs); + header->in_server = FALSE; + if (!header->weak_ref) + free_kernel_object( obj ); + LeaveCriticalSection(&obref_cs); + return STATUS_SUCCESS; }
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec index 6426bc3968a..318344fe90f 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec +++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec @@ -1688,3 +1688,5 @@
@ cdecl wine_ntoskrnl_main_loop(long) @ cdecl wine_enumerate_root_devices(wstr) +@ cdecl wine_ob_weak_ref(ptr) +@ cdecl wine_ob_weak_deref(ptr) diff --git a/dlls/vulkan-1/tests/vulkan.c b/dlls/vulkan-1/tests/vulkan.c index c1350da70ee..53df0e9a8d6 100644 --- a/dlls/vulkan-1/tests/vulkan.c +++ b/dlls/vulkan-1/tests/vulkan.c @@ -579,13 +579,10 @@ static void test_external_memory(VkInstance vk_instance, VkPhysicalDevice vk_phy import_handle_info.name = L"wine_test_buffer_export_name";
vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import); - todo_wine ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); - if (vr == VK_SUCCESS) - { - ok(vk_memory_import != vk_memory, "Expected new memory object.\n"); - vkFreeMemory(vk_device, vk_memory_import, NULL); - } + ok(vk_memory_import != vk_memory, "Expected new memory object.\n"); + + vkFreeMemory(vk_device, vk_memory_import, NULL); vkFreeMemory(vk_device, vk_memory, NULL); CloseHandle(nt_handle); } diff --git a/dlls/winevideo.sys/Makefile.in b/dlls/winevideo.sys/Makefile.in new file mode 100644 index 00000000000..ed185b9f071 --- /dev/null +++ b/dlls/winevideo.sys/Makefile.in @@ -0,0 +1,6 @@ +MODULE = winevideo.sys +IMPORTS = ntoskrnl +EXTRADLLFLAGS = -Wl,--subsystem,native -mno-cygwin + +C_SRCS = \ + winevideo.c diff --git a/dlls/winevideo.sys/winevideo.c b/dlls/winevideo.sys/winevideo.c new file mode 100644 index 00000000000..04e171bea3f --- /dev/null +++ b/dlls/winevideo.sys/winevideo.c @@ -0,0 +1,284 @@ +#include <stdarg.h> + +#define NONAMELESSUNION +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "winioctl.h" + +#include "ddk/wdm.h" + +#include "wine/debug.h" +#include "wine/server.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winevideo); + +#define IOCTL_VIDEO_RESOURCE_CREATE CTL_CODE(FILE_DEVICE_VIDEO, 0, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define IOCTL_VIDEO_RESOURCE_FIND_BY_NAME CTL_CODE(FILE_DEVICE_VIDEO, 1, METHOD_BUFFERED, FILE_READ_ACCESS) + +struct video_resource +{ + void *object; + LPWSTR name; +}; + +static struct video_resource *video_resources; +static unsigned int video_resources_size; + +extern void CDECL wine_ob_weak_ref( void *object ); +extern void CDECL wine_ob_weak_deref( void *object ); + +/* TODO: If/when ntoskrnl gets support for referencing user handles directly, remove this function */ +static void *reference_client_handle(obj_handle_t handle) +{ + HANDLE client_process, kernel_handle; + OBJECT_ATTRIBUTES attr; + void *object = NULL; + CLIENT_ID cid; + + attr.Length = sizeof(OBJECT_ATTRIBUTES); + attr.RootDirectory = 0; + attr.Attributes = OBJ_KERNEL_HANDLE; + attr.ObjectName = NULL; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + cid.UniqueProcess = PsGetCurrentProcessId(); + cid.UniqueThread = 0; + + if (NtOpenProcess(&client_process, PROCESS_ALL_ACCESS, &attr, &cid) != STATUS_SUCCESS) + return NULL; + + if (NtDuplicateObject(client_process, wine_server_ptr_handle(handle), NtCurrentProcess(), &kernel_handle, + 0, OBJ_KERNEL_HANDLE, DUPLICATE_SAME_ACCESS) != STATUS_SUCCESS) + { + NtClose(client_process); + return NULL; + } + + ObReferenceObjectByHandle(kernel_handle, 0, NULL, KernelMode, &object, NULL); + + NtClose(client_process); + NtClose(kernel_handle); + + return object; +} + +struct resource_create_in +{ + obj_handle_t handle; + WCHAR name[1]; +}; + +static NTSTATUS resource_create(void *buff, SIZE_T insize, SIZE_T outsize, IO_STATUS_BLOCK *iosb) +{ + struct resource_create_in *input = buff; + struct video_resource *resource = NULL; + int free_entry = -1; + unsigned int i; + void *object; + LPWSTR name; + + if (insize < offsetof(struct resource_create_in, name)) + return STATUS_INFO_LENGTH_MISMATCH; + + if (insize < sizeof(*input)) + name = NULL; + else if (input->name[ ((insize - offsetof(struct resource_create_in, name)) / sizeof(WCHAR)) - 1 ]) + return STATUS_INVALID_PARAMETER; + else + name = &input->name[0]; + + if (!(object = reference_client_handle(input->handle))) + return STATUS_INVALID_HANDLE; + + /* Find lowest free slot while checking for duplicate names */ + for (i = video_resources_size - 1; i < video_resources_size; i--) + { + resource = &video_resources[i]; + if (resource->object) + { + if (!ObGetObjectPointerCount(resource->object)) + { + wine_ob_weak_deref(resource->object); + if (resource->name) + { + ExFreePoolWithTag(resource->name, 0); + resource->name = NULL; + } + + free_entry = i; + } + else if (resource->object == object) + { + ObDereferenceObject(object); + return STATUS_INVALID_PARAMETER; + } + else if (resource->name && name && !wcscmp(name, resource->name)) + { + ObDereferenceObject(object); + return STATUS_OBJECT_NAME_COLLISION; + } + } + else + free_entry = i; + } + + if (free_entry == -1) + { + struct video_resource *new_resources = + ExAllocatePoolWithTag(NonPagedPool, sizeof(struct video_resource) * (video_resources_size + 1024), 0); + + if (video_resources) + { + memcpy(new_resources, video_resources, video_resources_size * sizeof(struct video_resource)); + ExFreePoolWithTag(video_resources, 0); + } + + memset(&new_resources[video_resources_size], 0, 1024 * sizeof (struct video_resource)); + + video_resources = new_resources; + free_entry = video_resources_size; + video_resources_size += 1024; + } + + resource = &video_resources[free_entry]; + + resource->object = object; + if (name) + { + resource->name = ExAllocatePoolWithTag(NonPagedPool, (wcslen(name) + 1) * sizeof(WCHAR), 0); + wcscpy(resource->name, name); + } + + wine_ob_weak_ref(object); + ObDereferenceObject(object); + + iosb->Information = 0; + return STATUS_SUCCESS; +} + +/* TODO: If/when ntoskrnl gets support for opening user handles directly, remove this function */ +static obj_handle_t open_client_handle(void *object) +{ + HANDLE client_process, kernel_handle, handle = NULL; + OBJECT_ATTRIBUTES attr; + CLIENT_ID cid; + + attr.Length = sizeof(OBJECT_ATTRIBUTES); + attr.RootDirectory = 0; + attr.Attributes = OBJ_KERNEL_HANDLE; + attr.ObjectName = NULL; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + cid.UniqueProcess = PsGetCurrentProcessId(); + cid.UniqueThread = 0; + + if (NtOpenProcess(&client_process, PROCESS_ALL_ACCESS, &attr, &cid) != STATUS_SUCCESS) + return 0; + + if (ObOpenObjectByPointer(object, 0, NULL, GENERIC_ALL, NULL, KernelMode, &kernel_handle) != STATUS_SUCCESS) + { + NtClose(client_process); + return 0; + } + + NtDuplicateObject(NtCurrentProcess(), kernel_handle, client_process, &handle, + 0, 0, DUPLICATE_SAME_ACCESS); + + NtClose(client_process); + NtClose(kernel_handle); + + return wine_server_obj_handle(handle); +} + +static NTSTATUS find_resource_by_name(void *buff, SIZE_T insize, SIZE_T outsize, IO_STATUS_BLOCK *iosb) +{ + LPCWSTR name = buff; + obj_handle_t ret; + unsigned int i; + + if (insize < sizeof(WCHAR)) + return STATUS_INVALID_PARAMETER; + if (name[(insize / sizeof(WCHAR)) - 1]) + return STATUS_INVALID_PARAMETER; + + for (i = 0; i < video_resources_size; i++) + { + if (video_resources[i].name && !wcscmp(name, video_resources[i].name)) + { + if (!ObGetObjectPointerCount(video_resources[i].object)) + break; + + if (!(ret = open_client_handle(video_resources[i].object))) + return STATUS_INTERNAL_ERROR; + + if (outsize < sizeof(obj_handle_t)) + return STATUS_INFO_LENGTH_MISMATCH; + + iosb->Information = sizeof(obj_handle_t); + *(obj_handle_t *)buff = ret; + + return STATUS_SUCCESS; + } + } + + return STATUS_OBJECT_NAME_NOT_FOUND; +} + +static NTSTATUS WINAPI winevideo_ioctl(DEVICE_OBJECT *device, IRP *irp) +{ + IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); + NTSTATUS status; + + TRACE( "ioctl %x insize %u outsize %u\n", + irpsp->Parameters.DeviceIoControl.IoControlCode, + irpsp->Parameters.DeviceIoControl.InputBufferLength, + irpsp->Parameters.DeviceIoControl.OutputBufferLength ); + + switch (irpsp->Parameters.DeviceIoControl.IoControlCode) + { + case IOCTL_VIDEO_RESOURCE_CREATE: + status = resource_create( irp->AssociatedIrp.SystemBuffer, + irpsp->Parameters.DeviceIoControl.InputBufferLength, + irpsp->Parameters.DeviceIoControl.OutputBufferLength, + &irp->IoStatus ); + break; + case IOCTL_VIDEO_RESOURCE_FIND_BY_NAME: + status = find_resource_by_name( irp->AssociatedIrp.SystemBuffer, + irpsp->Parameters.DeviceIoControl.InputBufferLength, + irpsp->Parameters.DeviceIoControl.OutputBufferLength, + &irp->IoStatus ); + break; + default: + FIXME( "ioctl %x not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode ); + status = STATUS_NOT_SUPPORTED; + break; + } + + irp->IoStatus.u.Status = status; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return status; +} + +NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) +{ + static const WCHAR device_nameW[] = L"\Device\WineVideoResourceManager"; + static const WCHAR link_nameW[] = L"\??\WineVideoResourceManager"; + UNICODE_STRING device_name, link_name; + DEVICE_OBJECT *device; + NTSTATUS status; + + driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = winevideo_ioctl; + + RtlInitUnicodeString(&device_name, device_nameW); + RtlInitUnicodeString(&link_name, link_nameW); + + if ((status = IoCreateDevice(driver, 0, &device_name, 0, 0, FALSE, &device))) + return status; + + return IoCreateSymbolicLink(&link_name, &device_name); +} diff --git a/dlls/winevideo.sys/winevideo.sys.spec b/dlls/winevideo.sys/winevideo.sys.spec new file mode 100644 index 00000000000..76421d7e35b --- /dev/null +++ b/dlls/winevideo.sys/winevideo.sys.spec @@ -0,0 +1 @@ +# nothing to export diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index e95860cb3fa..65f53aa679e 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -31,6 +31,7 @@ #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" +#include "winioctl.h" #include "winreg.h" #include "winuser.h" #include "winternl.h" @@ -502,10 +503,33 @@ static void wine_vk_device_free(struct VkDevice_T *device) free(device); }
+static HANDLE winevideo_device; + NTSTATUS CDECL __wine_init_unix_lib(HMODULE module, DWORD reason, const void *driver, void *ptr_out) { + static const WCHAR manager_nameW[] = {'\','?','?','\','W','i','n','e','V','i','d','e','o','R','e','s','o','u','r','c','e','M','a','n','a','g','e','r',0}; + UNICODE_STRING manager_name; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + NTSTATUS status; + if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS;
+ RtlInitUnicodeString(&manager_name, manager_nameW); + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.Attributes = 0; + attr.ObjectName = &manager_name; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + if ((status = NtCreateFile(&winevideo_device, GENERIC_READ | GENERIC_WRITE, &attr, &io, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, 0, NULL, 0))) + { + ERR("Failed to load the wine video-resource manager, status %#x.\n", status); + winevideo_device = NULL; + } + vk_funcs = driver; p_vkEnumerateInstanceVersion = vk_funcs->p_vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion"); *(const struct unix_funcs **)ptr_out = &loader_funcs; @@ -1958,18 +1982,68 @@ VkResult WINAPI wine_vkDebugMarkerSetObjectNameEXT(VkDevice device, const VkDebu return thunk_vkDebugMarkerSetObjectNameEXT(device, &wine_name_info); }
+#define IOCTL_VIDEO_RESOURCE_CREATE CTL_CODE(FILE_DEVICE_VIDEO, 0, METHOD_BUFFERED, FILE_WRITE_ACCESS) + +struct resource_create_in +{ + obj_handle_t handle; + WCHAR name[1]; +}; + static HANDLE create_video_resource(int fd, LPCWSTR name) { HANDLE ret = INVALID_HANDLE_VALUE; - - if (name) - FIXME("Naming video resources not supported.\n"); + struct resource_create_in *inbuff; + IO_STATUS_BLOCK iosb; + NTSTATUS status; + DWORD in_size;
wine_server_fd_to_handle(fd, GENERIC_ALL, 0, &ret);
+ if (ret != INVALID_HANDLE_VALUE && winevideo_device) + { + in_size = offsetof(struct resource_create_in, name) + (name ? (lstrlenW(name) + 1) * sizeof(WCHAR) : 0); + inbuff = malloc(in_size); + inbuff->handle = wine_server_obj_handle(ret); + if (name) + lstrcpyW(&inbuff->name[0], name); + + if ((status = NtDeviceIoControlFile(winevideo_device, NULL, NULL, NULL, &iosb, IOCTL_VIDEO_RESOURCE_CREATE, + inbuff, in_size, NULL, 0))) + ERR("Failed to create video resource, status %#x.\n", status); + + free(inbuff); + } return ret; }
+#define IOCTL_VIDEO_RESOURCE_FIND_BY_NAME CTL_CODE(FILE_DEVICE_VIDEO, 1, METHOD_BUFFERED, FILE_READ_ACCESS) + +static HANDLE open_video_resource_by_name(LPCWSTR name) +{ + obj_handle_t handle_out; + IO_STATUS_BLOCK iosb; + NTSTATUS status; + + if (!winevideo_device) + return INVALID_HANDLE_VALUE; + + if ((status = NtDeviceIoControlFile(winevideo_device, NULL, NULL, NULL, &iosb, IOCTL_VIDEO_RESOURCE_FIND_BY_NAME, + (PVOID) name, (lstrlenW(name) + 1) * sizeof(WCHAR), &handle_out, sizeof(handle_out)))) + { + ERR("Failed to open video resource by name, status %#x.\n", status); + return INVALID_HANDLE_VALUE; + } + + if (iosb.Information < sizeof(handle_out)) + { + ERR("Unexpected out size.\n"); + return INVALID_HANDLE_VALUE; + } + + return wine_server_ptr_handle(handle_out); +} + VkResult WINAPI wine_vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *allocate_info, const VkAllocationCallbacks *allocator, VkDeviceMemory *memory_out) { @@ -2061,7 +2135,7 @@ VkResult WINAPI wine_vkAllocateMemory(VkDevice device, const VkMemoryAllocateInf if (handle_import_info->handle) NtDuplicateObject( NtCurrentProcess(), handle_import_info->handle, NtCurrentProcess(), &object->handle, 0, 0, DUPLICATE_SAME_ACCESS ); else if (handle_import_info->name) - FIXME("Importing device memory by resource name not supported.\n"); + object->handle = open_video_resource_by_name( handle_import_info->name ); break; default: WARN("Invalid handle type %08x passed in.\n", handle_import_info->handleType); diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h index 1e7ce63f776..906f70b72e9 100644 --- a/include/ddk/wdm.h +++ b/include/ddk/wdm.h @@ -1803,6 +1803,7 @@ void FASTCALL ObfReferenceObject(void*); void WINAPI ObDereferenceObject(void*); USHORT WINAPI ObGetFilterVersion(void); ULONG WINAPI ObGetObjectPointerCount(void*); +NTSTATUS WINAPI ObOpenObjectByPointer(void*,ULONG,ACCESS_STATE*,ACCESS_MASK,POBJECT_TYPE,KPROCESSOR_MODE,HANDLE*); NTSTATUS WINAPI ObRegisterCallbacks(POB_CALLBACK_REGISTRATION, void**); NTSTATUS WINAPI ObReferenceObjectByHandle(HANDLE,ACCESS_MASK,POBJECT_TYPE,KPROCESSOR_MODE,PVOID*,POBJECT_HANDLE_INFORMATION); NTSTATUS WINAPI ObReferenceObjectByName(UNICODE_STRING*,ULONG,ACCESS_STATE*,ACCESS_MASK,POBJECT_TYPE,KPROCESSOR_MODE,void*,void**); diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 6ae4e96e37f..17b5db66f0d 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -165,6 +165,7 @@ AddService=Schedule,0,TaskSchedulerService AddService=Winmgmt,0,WinmgmtService AddService=wuauserv,0,wuauService AddService=NDIS,0x800,NDISService +AddService=WineVideoResources,0x800,WineVideoResourcesService
[DefaultInstall.NT.Services] AddService=BITS,0,BITSService @@ -184,6 +185,7 @@ AddService=Schedule,0,TaskSchedulerService AddService=Winmgmt,0,WinmgmtService AddService=wuauserv,0,wuauService AddService=NDIS,0x800,NDISService +AddService=WineVideoResources,0x800,WineVideoResourcesService
[DefaultInstall.ntamd64.Services] AddService=BITS,0,BITSService @@ -203,6 +205,7 @@ AddService=Schedule,0,TaskSchedulerService AddService=Winmgmt,0,WinmgmtService AddService=wuauserv,0,wuauService AddService=NDIS,0x800,NDISService +AddService=WineVideoResources,0x800,WineVideoResourcesService
[DefaultInstall.ntarm64.Services] AddService=BITS,0,BITSService @@ -222,6 +225,7 @@ AddService=Schedule,0,TaskSchedulerService AddService=Winmgmt,0,WinmgmtService AddService=wuauserv,0,wuauService AddService=NDIS,0x800,NDISService +AddService=WineVideoResources,0x800,WineVideoResourcesService
[Strings] MciExtStr="Software\Microsoft\Windows NT\CurrentVersion\MCI Extensions" @@ -3799,6 +3803,15 @@ StartType=2 ErrorControl=1 LoadOrderGroup="System Bus Extender"
+[WineVideoResourcesService] +Description="Video resource helper service" +DisplayName="Wine Video Resources" +ServiceBinary="%12%\winevideo.sys" +ServiceType=1 +StartType=2 +ErrorControl=1 +LoadOrderGroup="System Bus Extender" + [RpcSsService] Description="RPC service" DisplayName="Remote Procedure Call (RPC)"