Introduction to I/O Devices
The Windows operating system provides a comprehensive set of APIs for interacting with various input/output (I/O) devices. These APIs allow applications to communicate with hardware such as disks, keyboards, mice, printers, network adapters, and specialized peripherals.
Understanding how to manage and utilize I/O devices is crucial for developing robust and efficient Windows applications. This section covers the fundamental concepts and key APIs related to device management, data transfer, and error handling.
Key Concepts
- Device Drivers: Software components that translate generic I/O requests from the operating system into specific commands for hardware devices.
- I/O Request Packets (IRPs): Structures used by the operating system to communicate I/O operations to device drivers.
- File Handles: Abstract representations of open devices or files, used to perform I/O operations.
- Input/Output Control (IOCTL): A mechanism for applications to send custom commands directly to device drivers.
- Asynchronous I/O: Allows an application to initiate an I/O operation and continue processing without waiting for the operation to complete.
Core APIs
The following Win32 APIs are fundamental for working with I/O devices:
Device Management
CreateFile: Opens an existing file or creates a new file. It can also open existing devices, specify desired access, and share modes.CloseHandle: Closes an open object handle, such as a file or device handle.DeviceIoControl: Sends a custom control code directly to a specified device driver, allowing for device-specific operations.SetupDiGetDeviceInterfaceList,SetupDiEnumDeviceInfo,SetupDiGetDeviceRegistryProperty: APIs for enumerating devices and retrieving their properties.
Data Transfer
ReadFile: Reads data from a file or device.WriteFile: Writes data to a file or device.ReadFileEx,WriteFileEx: Asynchronous versions ofReadFileandWriteFile, which use I/O completion routines.
Error Handling
GetLastError: Retrieves the last error code set by a function. Common error codes for I/O operations includeERROR_IO_PENDING(for asynchronous operations),ERROR_FILE_NOT_FOUND, andERROR_DEVICE_DOES_NOT_EXIST.
Important Note on Device Access
Accessing raw hardware devices often requires administrative privileges. Applications designed for general users should typically interact with devices through higher-level abstractions like file system APIs or COM interfaces rather than directly manipulating device drivers.
Example: Reading from a Serial Port
This example demonstrates a simplified approach to reading data from a serial port using CreateFile and ReadFile.
#include <windows.h>
#include <iostream>
int main() {
HANDLE hSerial = CreateFile(
L"\\\\.\\COM1", // Port name
GENERIC_READ | GENERIC_WRITE, // Read and write access
0, // No sharing
NULL, // Default security attributes
OPEN_EXISTING, // Open only if it exists
FILE_ATTRIBUTE_NORMAL,// Normal file attributes
NULL // No template file
);
if (hSerial == INVALID_HANDLE_VALUE) {
std::cerr << "Error opening serial port: " << GetLastError() << std::endl;
return 1;
}
std::cout << "Serial port opened successfully." << std::endl;
// Configuration (omitted for brevity, involves GetCommState, SetCommState, etc.)
BYTE buffer[256];
DWORD bytesRead;
// Example read operation
if (ReadFile(hSerial, buffer, sizeof(buffer) - 1, &bytesRead, NULL)) {
buffer[bytesRead] = '\0'; // Null-terminate the string
std::cout << "Read " << bytesRead << " bytes: " << buffer << std::endl;
} else {
std::cerr << "Error reading from serial port: " << GetLastError() << std::endl;
}
CloseHandle(hSerial);
std::cout << "Serial port closed." << std::endl;
return 0;
}