From: Aric Stewart Subject: [PATCH 2/5] winehidminidriver.sys: add OS/X Minidriver Message-Id: <563371EE.7000603@codeweavers.com> Date: Fri, 30 Oct 2015 08:34:38 -0500 Signed-off-by: Aric Stewart --- dlls/winehidminidriver.sys/Makefile.in | 4 +- dlls/winehidminidriver.sys/hid.h | 20 ++ dlls/winehidminidriver.sys/main.c | 12 + dlls/winehidminidriver.sys/minidriver_osx.c | 515 ++++++++++++++++++++++++++++ 4 files changed, 550 insertions(+), 1 deletion(-) create mode 100644 dlls/winehidminidriver.sys/hid.h create mode 100644 dlls/winehidminidriver.sys/minidriver_osx.c diff --git a/dlls/winehidminidriver.sys/Makefile.in b/dlls/winehidminidriver.sys/Makefile.in index 1d90c0e..b2ad5b5 100644 --- a/dlls/winehidminidriver.sys/Makefile.in +++ b/dlls/winehidminidriver.sys/Makefile.in @@ -1,6 +1,8 @@ MODULE = winehidminidriver.sys IMPORTS = ntoskrnl.exe hidclass EXTRADLLFLAGS = -Wb,--subsystem,native +EXTRALIBS = $(IOKIT_LIBS) C_SRCS = \ - main.c + main.c \ + minidriver_osx.c diff --git a/dlls/winehidminidriver.sys/hid.h b/dlls/winehidminidriver.sys/hid.h new file mode 100644 index 0000000..4388620 --- /dev/null +++ b/dlls/winehidminidriver.sys/hid.h @@ -0,0 +1,20 @@ +/* + * Copyright 2015 Aric Stewart + * + * 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 + */ + +/* Minidrivers */ +NTSTATUS WINAPI osx_DriverInit(DRIVER_OBJECT *driver, UNICODE_STRING *RegistryPath) DECLSPEC_HIDDEN; diff --git a/dlls/winehidminidriver.sys/main.c b/dlls/winehidminidriver.sys/main.c index ffe8974..2efbdec 100644 --- a/dlls/winehidminidriver.sys/main.c +++ b/dlls/winehidminidriver.sys/main.c @@ -28,9 +28,21 @@ #include "winternl.h" #include "ddk/wdm.h" #include "wine/unicode.h" +#include "wine/debug.h" +#include "hid.h" + +WINE_DEFAULT_DEBUG_CHANNEL(hid_minidriver); /* main entry point for the driver */ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) { + static const WCHAR osxhidW[] = {'\\','D','r','i','v','e','r','\\','O','S','X','H','i','d',0}; + UNICODE_STRING nameW; + + ERR( "%s\n", debugstr_w(path->Buffer) ); + + RtlInitUnicodeString( &nameW, osxhidW); + IoCreateDriver(&nameW, osx_DriverInit); + return STATUS_SUCCESS; } diff --git a/dlls/winehidminidriver.sys/minidriver_osx.c b/dlls/winehidminidriver.sys/minidriver_osx.c new file mode 100644 index 0000000..3b02bd6 --- /dev/null +++ b/dlls/winehidminidriver.sys/minidriver_osx.c @@ -0,0 +1,515 @@ +/* HID pseudo-mindriver connections for Mac OS/X + * + * Copyright 2015 CodeWeavers, Aric Stewart + * + * 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 + */ + +#include "config.h" +#include "wine/port.h" + +#include + +#if defined(HAVE_IOKIT_HID_IOHIDLIB_H) +#define DWORD UInt32 +#define LPDWORD UInt32* +#define LONG SInt32 +#define LPLONG SInt32* +#define E_PENDING __carbon_E_PENDING +#define ULONG __carbon_ULONG +#define E_INVALIDARG __carbon_E_INVALIDARG +#define E_OUTOFMEMORY __carbon_E_OUTOFMEMORY +#define E_HANDLE __carbon_E_HANDLE +#define E_ACCESSDENIED __carbon_E_ACCESSDENIED +#define E_UNEXPECTED __carbon_E_UNEXPECTED +#define E_FAIL __carbon_E_FAIL +#define E_ABORT __carbon_E_ABORT +#define E_POINTER __carbon_E_POINTER +#define E_NOINTERFACE __carbon_E_NOINTERFACE +#define E_NOTIMPL __carbon_E_NOTIMPL +#define S_FALSE __carbon_S_FALSE +#define S_OK __carbon_S_OK +#define HRESULT_FACILITY __carbon_HRESULT_FACILITY +#define IS_ERROR __carbon_IS_ERROR +#define FAILED __carbon_FAILED +#define SUCCEEDED __carbon_SUCCEEDED +#define MAKE_HRESULT __carbon_MAKE_HRESULT +#define HRESULT __carbon_HRESULT +#define STDMETHODCALLTYPE __carbon_STDMETHODCALLTYPE +#include +#include +#undef ULONG +#undef E_INVALIDARG +#undef E_OUTOFMEMORY +#undef E_HANDLE +#undef E_ACCESSDENIED +#undef E_UNEXPECTED +#undef E_FAIL +#undef E_ABORT +#undef E_POINTER +#undef E_NOINTERFACE +#undef E_NOTIMPL +#undef S_FALSE +#undef S_OK +#undef HRESULT_FACILITY +#undef IS_ERROR +#undef FAILED +#undef SUCCEEDED +#undef MAKE_HRESULT +#undef HRESULT +#undef STDMETHODCALLTYPE +#undef DWORD +#undef LPDWORD +#undef LONG +#undef LPLONG +#undef E_PENDING +#endif /* HAVE_IOKIT_HID_IOHIDLIB_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 "hidusage.h" +#include "ddk/hidtypes.h" +#include "ddk/hidclass.h" +#include "ddk/hidport.h" +#include "wine/debug.h" +#include "wine/unicode.h" +#include "wine/list.h" +#include "hid.h" + +WINE_DEFAULT_DEBUG_CHANNEL(hid_minidriver); + +#ifdef HAVE_IOHIDMANAGERCREATE +WINE_DECLARE_DEBUG_CHANNEL(hid_report); + +typedef struct _OSX_DEVICE_EXTENSTION { + uint8_t *last_report; + int report_size; + + IOHIDDeviceRef hid_device; + + LIST_ENTRY osx_irp_queue; +} OSX_DEVICE_EXTENSION; + +static DRIVER_OBJECT *osx_driver_obj = NULL; +static IOHIDManagerRef hid_manager; +static HID_MINIDRIVER_REGISTRATION registration; + +static CFRunLoopRef run_loop; +static HANDLE run_loop_handle; + +static const char* debugstr_cf(CFTypeRef t) +{ + CFStringRef s; + const char* ret; + + if (!t) return "(null)"; + + if (CFGetTypeID(t) == CFStringGetTypeID()) + s = t; + else + s = CFCopyDescription(t); + ret = CFStringGetCStringPtr(s, kCFStringEncodingUTF8); + if (ret) ret = debugstr_a(ret); + if (!ret) + { + const UniChar* u = CFStringGetCharactersPtr(s); + if (u) + ret = debugstr_wn((const WCHAR*)u, CFStringGetLength(s)); + } + if (!ret) + { + UniChar buf[200]; + int len = min(CFStringGetLength(s), sizeof(buf)/sizeof(buf[0])); + CFStringGetCharacters(s, CFRangeMake(0, len), buf); + ret = debugstr_wn(buf, len); + } + if (s != t) CFRelease(s); + return ret; +} + +static const char* debugstr_device(IOHIDDeviceRef device) +{ + return wine_dbg_sprintf("", device, + debugstr_cf(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)))); +} + +static void CFStringToWSTR(CFStringRef cstr, LPWSTR wstr, int length) +{ + int len = min(CFStringGetLength(cstr), length-1); + CFStringGetCharacters(cstr, CFRangeMake(0, len), wstr); + wstr[len] = 0; +} + +static DWORD CFNumberToDWORD(CFNumberRef num) +{ + DWORD dwNum = 0; + if (num) + CFNumberGetValue(num, kCFNumberIntType, &dwNum); + return dwNum; +} + +static void CleanupDevice(DEVICE_OBJECT *device) +{ + IRP *irp; + LIST_ENTRY *entry; + OSX_DEVICE_EXTENSION *ext = (OSX_DEVICE_EXTENSION*)(((HID_DEVICE_EXTENSION*)device->DeviceExtension)->MiniDeviceExtension); + + /* Clean up our extension information */ + entry = RemoveHeadList(&ext->osx_irp_queue); + while(entry != &ext->osx_irp_queue) + { + irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry); + irp->IoStatus.u.Status = STATUS_CANCELLED; + irp->IoStatus.Information = 0; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + entry = RemoveHeadList(&ext->osx_irp_queue); + } + HeapFree(GetProcessHeap(), 0, ext->last_report); +} + +static NTSTATUS WINAPI osx_internal_ioctl( DEVICE_OBJECT *device, IRP *irp ) +{ + NTSTATUS rc = STATUS_SUCCESS; + IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); + OSX_DEVICE_EXTENSION *extension = (OSX_DEVICE_EXTENSION*)(((HID_DEVICE_EXTENSION*)device->DeviceExtension)->MiniDeviceExtension); + + irp->IoStatus.Information = 0; + + switch (irpsp->Parameters.DeviceIoControl.IoControlCode) + { + case IOCTL_GET_PHYSICAL_DESCRIPTOR: + TRACE("IOCTL_GET_PHYSICAL_DESCRIPTOR\n"); + break; + case IOCTL_HID_ACTIVATE_DEVICE: + TRACE("IOCTL_HID_ACTIVATE_DEVICE\n"); + break; + case IOCTL_HID_DEACTIVATE_DEVICE: + TRACE("IOCTL_HID_DEACTIVATE_DEVICE\n"); + break; + case IOCTL_HID_GET_DEVICE_ATTRIBUTES: + { + PHID_DEVICE_ATTRIBUTES attr = (PHID_DEVICE_ATTRIBUTES)irp->UserBuffer; + CFNumberRef num; + + TRACE("IOCTL_HID_GET_DEVICE_ATTRIBUTES\n"); + + RtlZeroMemory(attr, sizeof(HID_DEVICE_ATTRIBUTES)); + attr->Size = sizeof(HID_DEVICE_ATTRIBUTES); + num = IOHIDDeviceGetProperty(extension->hid_device, CFSTR(kIOHIDVendorIDKey)); + attr->VendorID = CFNumberToDWORD(num); + num = IOHIDDeviceGetProperty(extension->hid_device, CFSTR(kIOHIDProductIDKey)); + attr->ProductID = CFNumberToDWORD(num); + num = IOHIDDeviceGetProperty(extension->hid_device, CFSTR(kIOHIDVersionNumberKey)); + attr->VersionNumber = CFNumberToDWORD(num); + irp->IoStatus.u.Status = STATUS_SUCCESS; + irp->IoStatus.Information = sizeof(HID_DEVICE_ATTRIBUTES); + break; + } + case IOCTL_HID_GET_DEVICE_DESCRIPTOR: + { + CFDataRef data = IOHIDDeviceGetProperty(extension->hid_device, CFSTR(kIOHIDReportDescriptorKey)); + DWORD length = CFDataGetLength(data); + HID_DESCRIPTOR *descriptor = (HID_DESCRIPTOR*)irp->UserBuffer; + + TRACE("IOCTL_HID_GET_DEVICE_DESCRIPTOR\n"); + if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_DESCRIPTOR)) + { + irp->IoStatus.u.Status = STATUS_BUFFER_TOO_SMALL; + break; + } + ZeroMemory(descriptor, sizeof(*descriptor)); + descriptor->bLength = sizeof(*descriptor); + descriptor->bDescriptorType = HID_HID_DESCRIPTOR_TYPE; + descriptor->bcdHID = HID_REVISION; + descriptor->bCountry = 0; + descriptor->bNumDescriptors = 1; + descriptor->DescriptorList[0].bReportType = HID_REPORT_DESCRIPTOR_TYPE; + descriptor->DescriptorList[0].wReportLength = length; + + irp->IoStatus.Information = sizeof(*descriptor); + irp->IoStatus.u.Status = STATUS_SUCCESS; + break; + } + + case IOCTL_HID_GET_FEATURE: + TRACE("IOCTL_HID_GET_FEATURE\n"); + break; + case IOCTL_HID_GET_INDEXED_STRING: + TRACE("IOCTL_HID_GET_INDEXED_STRING\n"); + break; + case IOCTL_HID_GET_INPUT_REPORT: + TRACE_(hid_report)("IOCTL_HID_GET_INPUT_REPORT\n"); + ZeroMemory(((PHID_XFER_PACKET)(irp->UserBuffer))->reportBuffer, + ((PHID_XFER_PACKET)(irp->UserBuffer))->reportBufferLen); + memcpy(irp->UserBuffer, extension->last_report, extension->report_size); + irp->IoStatus.u.Status = STATUS_SUCCESS; + irp->IoStatus.Information = sizeof(HID_XFER_PACKET); + break; + case IOCTL_HID_GET_REPORT_DESCRIPTOR: + { + CFDataRef data = IOHIDDeviceGetProperty(extension->hid_device, CFSTR(kIOHIDReportDescriptorKey)); + DWORD length = CFDataGetLength(data); + const UInt8 *ptr = CFDataGetBytePtr(data); + + TRACE("IOCTL_HID_GET_REPORT_DESCRIPTOR\n"); + if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < length) + { + irp->IoStatus.u.Status = STATUS_BUFFER_TOO_SMALL; + break; + } + memcpy(irp->UserBuffer, ptr, length); + irp->IoStatus.Information = length; + irp->IoStatus.u.Status = STATUS_SUCCESS; + break; + } + case IOCTL_HID_GET_STRING: + { + DWORD index = (DWORD)irpsp->Parameters.DeviceIoControl.Type3InputBuffer; + + CFStringRef str = NULL; + + TRACE("IOCTL_HID_GET_STRING: %i\n",index); + + switch (index) + { + case HID_STRING_ID_IPRODUCT: + str = IOHIDDeviceGetProperty(extension->hid_device, CFSTR(kIOHIDProductKey)); + break; + case HID_STRING_ID_IMANUFACTURER: + str = IOHIDDeviceGetProperty(extension->hid_device, CFSTR(kIOHIDManufacturerKey)); + break; + case HID_STRING_ID_ISERIALNUMBER: + str = IOHIDDeviceGetProperty(extension->hid_device, CFSTR(kIOHIDSerialNumberKey)); + break; + default: + ERR("Unknown string index\n"); + } + + if (str) + { + WCHAR *buffer = (WCHAR*)(irp->UserBuffer); + int length = irpsp->Parameters.DeviceIoControl.OutputBufferLength/sizeof(WCHAR); + CFStringToWSTR(str, buffer, length); + irp->IoStatus.Information = (lstrlenW(buffer)+1) * sizeof(WCHAR); + } + + irp->IoStatus.u.Status = STATUS_SUCCESS; + break; + } + case IOCTL_HID_READ_REPORT: + { + TRACE_(hid_report)("IOCTL_HID_READ_REPORT\n"); + InsertTailList(&extension->osx_irp_queue, &irp->Tail.Overlay.ListEntry); + rc = STATUS_PENDING; + break; + } + case IOCTL_HID_SET_FEATURE: + TRACE("IOCTL_HID_SET_FEATURE\n"); + break; + case IOCTL_HID_SET_OUTPUT_REPORT: + TRACE("IOCTL_HID_SET_OUTPUT_REPORT\n"); + break; + case IOCTL_HID_WRITE_REPORT: + TRACE("IOCTL_HID_WRITE_REPORT\n"); + break; + default: + { + ULONG code = irpsp->Parameters.DeviceIoControl.IoControlCode; + FIXME("Unsupported ioctl %s %x (device=%x access=%x func=%x method=%x)\n", + debugstr_device(extension->hid_device), code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3); + irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED; + rc = STATUS_UNSUCCESSFUL; + break; + } + } + + if (rc != STATUS_PENDING) + IoCompleteRequest( irp, IO_NO_INCREMENT ); + + return rc; +} + +static NTSTATUS WINAPI osx_pnp( DEVICE_OBJECT *device, IRP *irp ) +{ + IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); + + switch(irpsp->MinorFunction) + { + case IRP_MN_START_DEVICE: + TRACE("IRP_MN_START_DEVICE\n"); + irp->IoStatus.u.Status = STATUS_SUCCESS; + break; + case IRP_MN_REMOVE_DEVICE: + TRACE("IRP_MN_REMOVE_DEVICE\n"); + CleanupDevice(device); + irp->IoStatus.u.Status = STATUS_SUCCESS; + break; + } + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_SUCCESS; +} + +static NTSTATUS WINAPI osx_power( DEVICE_OBJECT *device, IRP *irp ) +{ + IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); + TRACE("Device entering power state %i\n", + irpsp->Parameters.Power.State.DeviceState); + irp->IoStatus.u.Status = STATUS_SUCCESS; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return STATUS_SUCCESS; +} + +static void Handle_IOHIDDeviceIOHIDReportCallback( + void * inContext, + IOReturn inResult, + void * inSender, + IOHIDReportType inType, + uint32_t inReportID, + uint8_t * inReport, + CFIndex inReportLength) +{ + IRP *irp; + LIST_ENTRY *entry; + DEVICE_OBJECT *device = (DEVICE_OBJECT*)inContext; + OSX_DEVICE_EXTENSION *extension = (OSX_DEVICE_EXTENSION*)(((HID_DEVICE_EXTENSION*)device->DeviceExtension)->MiniDeviceExtension); + + if (inResult) + { + WARN("Error getting report callback(%x)\n",inResult); + return; + } + + entry = RemoveHeadList(&extension->osx_irp_queue); + while(entry != &extension->osx_irp_queue) + { + TRACE_(hid_report)("Processing Request\n"); + irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry); + + memcpy(irp->UserBuffer, inReport, inReportLength); + irp->IoStatus.Information = inReportLength; + irp->IoStatus.u.Status = STATUS_SUCCESS; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + entry = RemoveHeadList(&extension->osx_irp_queue); + } +} + +VOID WINAPI osx_Unload(DRIVER_OBJECT *driver) +{ + TRACE("OS/X Driver Unload\n"); + IOHIDManagerUnscheduleFromRunLoop(hid_manager, run_loop, kCFRunLoopDefaultMode); + CFRelease(hid_manager); + CFRunLoopStop(run_loop); + WaitForSingleObject(run_loop_handle, INFINITE); +} + +NTSTATUS WINAPI osx_AddDevice(DRIVER_OBJECT *driver, DEVICE_OBJECT *device) +{ + OSX_DEVICE_EXTENSION *ext; + HID_DEVICE_EXTENSION *bext; + CFNumberRef num; + + TRACE("OS/X Driver AddDevice\n"); + + bext = (HID_DEVICE_EXTENSION*)device->DeviceExtension; + ext = (OSX_DEVICE_EXTENSION*)(((HID_DEVICE_EXTENSION*)device->DeviceExtension)->MiniDeviceExtension); + + ext->hid_device = (IOHIDDeviceRef)bext->NextDeviceObject; + + InitializeListHead(&ext->osx_irp_queue); + + num = IOHIDDeviceGetProperty(ext->hid_device, CFSTR(kIOHIDMaxInputReportSizeKey)); + ext->report_size = CFNumberToDWORD(num); + ext->last_report = HeapAlloc(GetProcessHeap(), 0, ext->report_size); + + IOHIDDeviceRegisterInputReportCallback(ext->hid_device, ext->last_report, + ext->report_size, Handle_IOHIDDeviceIOHIDReportCallback, device); + + return STATUS_SUCCESS; +} + +/* This puts the relevent run loop for event handleing into a WINE thread */ +static DWORD CALLBACK runloop_thread(VOID *args) +{ + HANDLE *events = (HANDLE*)args; + + run_loop = CFRunLoopGetCurrent(); + SetEvent(events[0]); + WaitForSingleObject(events[1], INFINITE); + CloseHandle(events[1]); + CFRunLoopRun(); + TRACE("Run Loop exiting\n"); + return 1; +} + +NTSTATUS WINAPI osx_DriverInit(DRIVER_OBJECT *driver, UNICODE_STRING *RegistryPath) +{ + HANDLE events[2]; + + TRACE("OS/X Driver Init\n"); + + events[0] = CreateEventW(NULL, FALSE, FALSE, NULL); + events[1] = CreateEventW(NULL, FALSE, FALSE, NULL); + + run_loop_handle = CreateThread(NULL, 0, runloop_thread, events, 0, NULL); + + osx_driver_obj = driver; + driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = osx_internal_ioctl; + driver->MajorFunction[IRP_MJ_PNP] = osx_pnp; + driver->MajorFunction[IRP_MJ_POWER] = osx_power; + + driver->DriverUnload = osx_Unload; + driver->DriverExtension->AddDevice = osx_AddDevice; + + registration.DriverObject = driver; + registration.RegistryPath = RegistryPath; + registration.DeviceExtensionSize = sizeof(OSX_DEVICE_EXTENSION) + sizeof(HID_DEVICE_EXTENSION); + registration.DevicesArePolled = FALSE; + HidRegisterMinidriver(®istration); + + hid_manager = IOHIDManagerCreate( kCFAllocatorDefault, 0L ); + + WaitForSingleObject(events[0], INFINITE); + IOHIDManagerScheduleWithRunLoop(hid_manager, run_loop, kCFRunLoopDefaultMode); + SetEvent(events[1]); + CloseHandle(events[0]); + + if (IOHIDManagerOpen( hid_manager, 0 ) != kIOReturnSuccess) + { + ERR("Couldn't open IOHIDManager.\n"); + IOHIDManagerUnscheduleFromRunLoop(hid_manager, run_loop, kCFRunLoopDefaultMode); + CFRelease(hid_manager); + CFRunLoopStop(run_loop); + return STATUS_SUCCESS; + } + + return STATUS_SUCCESS; +} + +#else + +NTSTATUS WINAPI osx_DriverInit(DRIVER_OBJECT *driver, UNICODE_STRING *RegistryPath) +{ + TRACE("Dummy OS/X Driver Init\n"); + return STATUS_SUCCESS; +} + +#endif /* HAVE_IOHIDMANAGERCREATE */