// Copyright (c) Microsoft Corporation. // Licensed under the MIT license. #include "precomp.h" #include "ConDrvDeviceComm.h" ConDrvDeviceComm::ConDrvDeviceComm(_In_ HANDLE Server) : _Server(Server) { THROW_HR_IF(E_HANDLE, Server == INVALID_HANDLE_VALUE); } ConDrvDeviceComm::~ConDrvDeviceComm() { } // Routine Description: // - Needs to be called once per server session and typically as the absolute first operation. // - This sets up the driver with the input event that it will need to coordinate with when client // applications attempt to read data and need to be blocked. (It will be the signal to unblock those clients.) // Arguments: // - pServerInfo - Structure containing information required to initialize driver state for this console connection. // Return Value: // - HRESULT S_OK or suitable error. [[nodiscard]] HRESULT ConDrvDeviceComm::SetServerInformation(_In_ CD_IO_SERVER_INFORMATION* const pServerInfo) const { return _CallIoctl(IOCTL_CONDRV_SET_SERVER_INFORMATION, pServerInfo, sizeof(*pServerInfo), nullptr, 0); } // Routine Description: // - Retrieves a packet message from the driver representing the next action/activity that should be performed. // Arguments: // - pCompletion - Optional completion structure from the previous activity (can be used in lieu of calling CompleteIo separately.) // - pMessage - A structure to hold the message data retrieved from the driver. // Return Value: // - HRESULT S_OK or suitable error. [[nodiscard]] HRESULT ConDrvDeviceComm::ReadIo(_In_opt_ PCONSOLE_API_MSG const pReplyMsg, _Out_ CONSOLE_API_MSG* const pMessage) const { HRESULT hr = _CallIoctl(IOCTL_CONDRV_READ_IO, pReplyMsg == nullptr ? nullptr : &pReplyMsg->Complete, pReplyMsg == nullptr ? 0 : sizeof(pReplyMsg->Complete), &pMessage->Descriptor, sizeof(CONSOLE_API_MSG) - FIELD_OFFSET(CONSOLE_API_MSG, Descriptor)); if (hr == HRESULT_FROM_WIN32(ERROR_IO_PENDING)) { WaitForSingleObjectEx(_Server.get(), 0, FALSE); hr = S_OK; // TODO: MSFT: 9115192 - ??? This isn't really relevant anymore with a switch from NtDeviceIoControlFile to DeviceIoControl... } return hr; } // Routine Description: // - Marks an action/activity as completed to the driver so control/responses can be returned to the client application. // Arguments: // - pCompletion - Completion structure from the previous activity (can be used in lieu of calling CompleteIo separately.) // Return Value: // - HRESULT S_OK or suitable error. [[nodiscard]] HRESULT ConDrvDeviceComm::CompleteIo(_In_ CD_IO_COMPLETE* const pCompletion) const { return _CallIoctl(IOCTL_CONDRV_COMPLETE_IO, pCompletion, sizeof(*pCompletion), nullptr, 0); } // Routine Description: // - Used to retrieve any buffered input data related to an action/activity message. // Arguments: // - pIoOperation - Structure containing the identifier matching the action/activity message and containing a suitable buffer space // to hold retrieved buffered input data from the client application. // Return Value: // - HRESULT S_OK or suitable error. [[nodiscard]] HRESULT ConDrvDeviceComm::ReadInput(_In_ CD_IO_OPERATION* const pIoOperation) const { return _CallIoctl(IOCTL_CONDRV_READ_INPUT, pIoOperation, sizeof(*pIoOperation), nullptr, 0); } // Routine Description: // - Used to return any buffered output data related to an action/activity message. // Arguments: // - pIoOperation - Structure containing the identifier matching the action/activity message and containing a suitable buffer space // to hold buffered output data to be sent to the client application. // Return Value: // - HRESULT S_OK or suitable error. [[nodiscard]] HRESULT ConDrvDeviceComm::WriteOutput(_In_ CD_IO_OPERATION* const pIoOperation) const { return _CallIoctl(IOCTL_CONDRV_WRITE_OUTPUT, pIoOperation, sizeof(*pIoOperation), nullptr, 0); } // Routine Description: // - To be called when the console instantiates UI to permit low-level UIAccess patterns to be used for retrieval of // accessibility data from the console session. // Arguments: // - // Return Value: // - HRESULT S_OK or suitable error. [[nodiscard]] HRESULT ConDrvDeviceComm::AllowUIAccess() const { return _CallIoctl(IOCTL_CONDRV_ALLOW_VIA_UIACCESS, nullptr, 0, nullptr, 0); } // Routine Description: // - For internal use. This function will send the appropriate control code verb and buffers to the driver and return a result. // - Usage of the optional buffers depends on which verb is sent and is specific to the particular driver and its protocol. // Arguments: // - dwIoControlCode - The action code to send to the driver // - pInBuffer - An optional buffer to send as input with the verb. Usage depends on the control code. // - cbInBufferSize - The length in bytes of the optional input buffer. // - pOutBuffer - An optional buffer to send as output with the verb. Usage depends on the control code. // - cbOutBufferSize - The length in bytes of the optional output buffer. // Return Value: // - HRESULT S_OK or suitable error. [[nodiscard]] HRESULT ConDrvDeviceComm::_CallIoctl(_In_ DWORD dwIoControlCode, _In_reads_bytes_opt_(cbInBufferSize) PVOID pInBuffer, _In_ DWORD cbInBufferSize, _Out_writes_bytes_opt_(cbOutBufferSize) PVOID pOutBuffer, _In_ DWORD cbOutBufferSize) const { // See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363216(v=vs.85).aspx // Written is unused but cannot be nullptr because we aren't using overlapped. DWORD cbWritten = 0; RETURN_IF_WIN32_BOOL_FALSE(DeviceIoControl(_Server.get(), dwIoControlCode, pInBuffer, cbInBufferSize, pOutBuffer, cbOutBufferSize, &cbWritten, nullptr)); return S_OK; } // Routine Description: // - Implements IDeviceComm handle exchange for ConDrv. // - "Translates" a pointer to an object into a handle value // that the driver can use to identify objects in a console // session. // - The opposite of GetHandle [[nodiscard]] ULONG_PTR ConDrvDeviceComm::PutHandle(const void* handle) { // ConDrv will pass back whatever large integer we send it, as an opaque data blob // We'll use that to smuggle the actual pointer value to the handle. return reinterpret_cast(handle); } // Routine Description: // - Implements IDeviceComm handle exchange for ConDrv. // - "Translates" an object handle from ConDrv into // a pointer to an object // - The opposite of PutHandle [[nodiscard]] void* ConDrvDeviceComm::GetHandle(ULONG_PTR handleId) const { return reinterpret_cast(handleId); } // Routine Description: // - Provides access to the raw server handle so it can be used to hand off // the session to another console host server. [[nodiscard]] HRESULT ConDrvDeviceComm::GetServerHandle(_Out_ HANDLE* pHandle) const { *pHandle = _Server.get(); return S_OK; }