/// <summary> /// Sends the command to the driver and gets the response. /// </summary> /// <typeparam name="TResponse">Type of the response.</typeparam> /// <param name="command">Command to be sent to the driver.</param> /// <returns>Response received from the driver.</returns> /// <exception cref="ArgumentNullException"><paramref name="command"/> is <see langword="null"/>.</exception> /// <exception cref="ArgumentException"><typeparamref name="TResponse"/> type is not a structure type.</exception> /// <exception cref="InvalidOperationException"> /// Memory for the command could not be allocated. /// <para>-or-</para> /// Memory for the response could not be allocated. /// <para>-or-</para> /// Message was not sent to the driver. /// </exception> /// <remarks> /// This method should be called from a synchronized context. /// </remarks> public TResponse ExecuteCommand <TResponse>(IDriverCommand command) where TResponse : struct { return((TResponse)this.ExecuteCommand(command, typeof(TResponse))); }
/// <summary> /// Sends the command to the driver. /// </summary> /// <param name="command">Command to be sent to the driver.</param> /// <param name="responseType">Type of the response. This parameter may be <see langword="null"/>.</param> /// <returns>Response received from the driver, or <see langword="null"/>, if the <paramref name="responseType"/> is <see langword="null"/>.</returns> /// <exception cref="ArgumentNullException"><paramref name="command"/> is <see langword="null"/>.</exception> /// <exception cref="ArgumentException"><paramref name="responseType"/> is not a structure type.</exception> /// <exception cref="InvalidOperationException"> /// Client is not connected. /// <para>-or-</para> /// Memory for the command or response was not allocated. /// <para>-or-</para> /// Message was not sent to the driver. /// </exception> private object ExecuteCommand(IDriverCommand command, Type responseType) { if (command == null) { throw new ArgumentNullException(nameof(command)); } if (responseType != null && (!responseType.IsValueType || responseType.IsPrimitive)) { throw new ArgumentException("Response type is not a structure type.", nameof(responseType)); } lock (this.syncRoot) { if (this.state != ConnectionState.Connected) { throw new InvalidOperationException("Client is not connected."); } // We want to have two separate buffers, because the driver can update the response buffer // while parsing the command. IntPtr commandBuffer = IntPtr.Zero; IntPtr responseBuffer = IntPtr.Zero; try { // Allocate buffer for the command. // Command header contains 'Type' and 'DataLength' (Int32) values. // See the 'DRIVER_COMMAND' structure in the 'CommunicationData.h' for details. int commandHeaderSize = Marshal.SizeOf(command.Type) + Marshal.SizeOf(typeof(int)); int commandDataSize = command.Data?.Length ?? 0; int commandSize = commandHeaderSize + commandDataSize; try { commandBuffer = Marshal.AllocHGlobal(commandSize); } catch (OutOfMemoryException oom) { string message = "Unable to allocate memory for the command."; DriverClientBase.Logger.Error(message, oom); throw new InvalidOperationException(message, oom); } // Marshal command to the buffer allocated, if the command.Data is NULL, it'll be ignored. MarshalingHelper.MarshalObjectsToPointer(commandBuffer, commandSize, command.Type, commandDataSize, command.Data); // // Allocate the response buffer, if needed. // int responseSize = 0; if (responseType != null) { responseSize = Marshal.SizeOf(responseType); try { responseBuffer = Marshal.AllocHGlobal(responseSize); } catch (OutOfMemoryException oom) { string message = "Unable to allocate memory for the response."; DriverClientBase.Logger.Error(message, oom); throw new InvalidOperationException(message, oom); } } // // Send command to the driver. // uint bytesReceived; uint hr = NativeMethods.FilterSendMessage(this.filterPortHandle, commandBuffer, (uint)commandSize, responseBuffer, (uint)responseSize, out bytesReceived); if (hr != NativeMethods.Ok) { string message = string.Format(CultureInfo.InvariantCulture, "Unable to send message to the driver: 0x{0:X8}", hr); Exception innerException = Marshal.GetExceptionForHR((int)hr); DriverClientBase.Logger.Error(innerException, message); throw new InvalidOperationException(message, innerException); } // Return NULL, if response type is not specified. return(responseType == null ? null : Marshal.PtrToStructure(responseBuffer, responseType)); } catch { this.Disconnect(); this.state = ConnectionState.Faulted; throw; } finally { if (commandBuffer != IntPtr.Zero) { Marshal.FreeHGlobal(commandBuffer); } if (responseBuffer != IntPtr.Zero) { Marshal.FreeHGlobal(responseBuffer); } } } }
/// <summary> /// Sends the command to the driver. /// </summary> /// <param name="command">Command to be sent to the driver.</param> /// <exception cref="ArgumentNullException"><paramref name="command"/> is <see langword="null"/>.</exception> /// <exception cref="InvalidOperationException"> /// Memory for the command could not be allocated. /// <para>-or-</para> /// Memory for the response could not be allocated. /// <para>-or-</para> /// Message was not sent to the driver. /// </exception> /// <remarks> /// This method should be called from a synchronized context. /// </remarks> public void ExecuteCommand(IDriverCommand command) { this.ExecuteCommand(command, null); }