DWORD GetDeviceCapabilities( DeviceType device_type, UINT device_id, DWORD_PTR capabilities, DWORD capabilities_size) { MMRESULT result; DWORD ioctl; HANDLE handle; DWORD bytes_returned; BOOL device_io_result; ASSERT(capabilities); /* Choose the right IOCTL for the job */ if ( IsWaveDevice(device_type) ) ioctl = IOCTL_WAVE_GET_CAPABILITIES; else if ( IsMidiDevice(device_type) ) ioctl = IOCTL_MIDI_GET_CAPABILITIES; else if ( IsAuxDevice(device_type) ) return MMSYSERR_NOTSUPPORTED; /* TODO */ else return MMSYSERR_NOTSUPPORTED; result = OpenKernelDevice(device_type, device_id, GENERIC_READ, &handle); if ( result != MMSYSERR_NOERROR ) { DPRINT("Failed to open kernel device\n"); return result; } device_io_result = DeviceIoControl(handle, ioctl, NULL, 0, (LPVOID) capabilities, capabilities_size, &bytes_returned, NULL); /* Translate result */ if ( device_io_result ) result = MMSYSERR_NOERROR; else result = ErrorToMmResult(GetLastError()); /* Clean up and return */ CloseKernelDevice(handle); return result; }
MMRESULT OpenKernelDevice( DeviceType device_type, UINT device_id, DWORD access, HANDLE* handle) { MMRESULT result; WCHAR device_name[MAX_DEVICE_NAME_LENGTH]; DWORD open_flags = 0; ASSERT(handle); /* Glue the base device name and the ID together */ result = CobbleDeviceName(device_type, device_id, device_name); DPRINT("Opening kernel device %ls\n", device_name); if ( result != MMSYSERR_NOERROR ) return result; /* We want overlapped I/O when writing */ if ( access != GENERIC_READ ) open_flags = FILE_FLAG_OVERLAPPED; /* Now try opening... */ *handle = CreateFile(device_name, access, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, open_flags, NULL); if ( *handle == INVALID_HANDLE_VALUE ) return ErrorToMmResult(GetLastError()); return MMSYSERR_NOERROR; }
MMRESULT GetDeviceData( HANDLE device_handle, DWORD ioctl, PBYTE output_buffer, DWORD buffer_size) { OVERLAPPED overlap; DWORD bytes_returned; BOOL success; DWORD transfer; DPRINT("GetDeviceData\n"); memset(&overlap, 0, sizeof(overlap)); overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if ( ! overlap.hEvent ) return MMSYSERR_NOMEM; success = DeviceIoControl(device_handle, ioctl, NULL, 0, output_buffer, buffer_size, &bytes_returned, &overlap); if ( ! success ) { if ( GetLastError() == ERROR_IO_PENDING ) { if ( ! GetOverlappedResult(device_handle, &overlap, &transfer, TRUE) ) { CloseHandle(overlap.hEvent); return ErrorToMmResult(GetLastError()); } } else { CloseHandle(overlap.hEvent); return ErrorToMmResult(GetLastError()); } } while ( TRUE ) { SetEvent(overlap.hEvent); if ( WaitForSingleObjectEx(overlap.hEvent, 0, TRUE) != WAIT_IO_COMPLETION ) { break; } } CloseHandle(overlap.hEvent); return MMSYSERR_NOERROR; }