[RFC PATCH 3/4] winevulkan: Add support for named video resources.

Derek Lesho dlesho at codeweavers.com
Mon May 3 11:49:12 CDT 2021


On 5/3/21 12:46 PM, Derek Lesho wrote:

> 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.

Email cut off the first paragraph of my message, resending it here:

This patch adds a some amount of infrastructure allowing a custom wine 
driver
to store extra information about video resource objects.  To do this without
adding any custom fields to object structures in wineserver or ntoskrnl, new
functionality is added to ntoskrnl which allows wine drivers to keep weak
references to kernel objects: that is, references which don't block the 
server
from destroying the object.  Using this, the driver stores a table of video
resource objects with the extra data the client may need, and, by using
ObGetObjectPointerCount, which doesn't include weak references, knows when
to free up slots in the resource table, preventing leaks and pointer 
aliasing
issues.

> ---
>   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)"



More information about the wine-devel mailing list