C Hardware Info Code Generator
Generated C Code
Complete Guide: Lấy Thông Tin Phần Cứng Máy Tính Bằng C
Việc lấy thông tin phần cứng máy tính bằng ngôn ngữ C là một kỹ thuật quan trọng trong lập trình hệ thống. Bài viết này sẽ hướng dẫn chi tiết cách thu thập thông tin về CPU, RAM, ổ đĩa và các thành phần phần cứng khác trên các hệ điều hành phổ biến.
1. Cơ Bản Về Truy Cập Phần Cứng Trong C
Ngôn ngữ C cung cấp khả năng tương tác trực tiếp với phần cứng thông qua:
- Các hàm hệ thống (system calls)
- Truy cập trực tiếp vào các file đặc biệt trong hệ thống
- Sử dụng các thư viện chuyên dụng
#include <stdlib.h>
int main() {
// Code lấy thông tin phần cứng sẽ được đặt ở đây
return 0;
}
2. Lấy Thông Tin CPU
2.1 Trên Hệ Điều Hành Windows
Sử dụng Windows API thông qua thư viện <windows.h>:
#include <stdio.h>
void getCPUInfo() {
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
printf(“Number of processors: %d\n”, sysInfo.dwNumberOfProcessors);
printf(“Processor type: %d\n”, sysInfo.dwProcessorType);
}
2.2 Trên Hệ Điều Hành Linux
Đọc file /proc/cpuinfo:
void getCPUInfo() {
FILE *fp = fopen(“/proc/cpuinfo”, “r”);
if (fp == NULL) {
perror(“Error opening file”);
return;
}
char buffer[1024];
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
printf(“%s”, buffer);
}
fclose(fp);
}
3. Lấy Thông Tin RAM
3.1 Phương Pháp Chung
Sử dụng các hàm hệ thống để lấy thông tin bộ nhớ:
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/sysinfo.h>
#endif
void getRAMInfo() {
#ifdef _WIN32
MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
GlobalMemoryStatusEx(&memInfo);
printf(“Total RAM: %llu MB\n”, memInfo.ullTotalPhys / 1024 / 1024);
#else
struct sysinfo memInfo;
sysinfo(&memInfo);
printf(“Total RAM: %lu MB\n”, memInfo.totalram / 1024 / 1024);
#endif
}
3.2 Thông Tin Chi Tiết Về RAM
Để lấy thông tin chi tiết hơn như loại RAM, tốc độ bus:
- Trên Windows: Sử dụng WMI (Windows Management Instrumentation)
- Trên Linux: Đọc file /proc/meminfo
- Trên macOS: Sử dụng lệnh system_profiler
4. Lấy Thông Tin Ổ Đĩa
4.1 Thông Tin Cơ Bản Về Ổ Đĩa
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/statvfs.h>
#endif
void getDiskInfo() {
#ifdef _WIN32
ULARGE_INTEGER freeBytes, totalBytes;
GetDiskFreeSpaceEx(“C:\\\”, &freeBytes, &totalBytes, NULL);
printf(“Total disk space: %llu GB\n”, totalBytes.QuadPart / 1024 / 1024 / 1024);
#else
struct statvfs stat;
statvfs(“/”, &stat);
unsigned long blockSize = stat.f_bsize;
unsigned long totalBlocks = stat.f_blocks;
printf(“Total disk space: %lu GB\n”, (blockSize * totalBlocks) / 1024 / 1024 / 1024);
#endif
}
4.2 Thông Tin Chi Tiết Về Phân Vùng
Để lấy thông tin chi tiết về các phân vùng đĩa:
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
#endif
void listDrives() {
#ifdef _WIN32
DWORD drives = GetLogicalDrives();
for (int i = 0; i < 26; i++) {
if (drives & (1 << i)) {
char driveLetter = ‘A’ + i;
printf(“Drive %c:\\\n”, driveLetter);
}
}
#else
system(“lsblk”); // Linux command to list block devices
#endif
}
5. Lấy Thông Tin GPU
Lấy thông tin card đồ họa đòi hỏi các phương pháp khác nhau trên mỗi hệ điều hành:
5.1 Trên Windows
#include <stdio.h>
#include <dxgi.h>
#include <d3d11.h>
#pragma comment(lib, “dxgi.lib”)
#pragma comment(lib, “d3d11.lib”)
void getGPUInfo() {
IDXGIFactory *factory = NULL;
if (FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory))) {
printf(“Failed to create DXGI factory\n”);
return;
}
IDXGIAdapter *adapter = NULL;
int index = 0;
while (factory->EnumAdapters(index, &adapter) != DXGI_ERROR_NOT_FOUND) {
DXGI_ADAPTER_DESC desc;
adapter->GetDesc(&desc);
wprintf(L”GPU %d: %s\n”, index + 1, desc.Description);
printf(” Dedicated Video Memory: %lu MB\n”, (unsigned long)desc.DedicatedVideoMemory / 1024 / 1024);
adapter->Release();
index++;
}
factory->Release();
}
5.2 Trên Linux
Sử dụng lệnh lspci hoặc đọc file /proc:
void getGPUInfo() {
FILE *fp = popen(“lspci | grep -i vga”, “r”);
if (fp == NULL) {
perror(“Failed to run command”);
return;
}
char buffer[1024];
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
printf(“GPU: %s”, buffer);
}
pclose(fp);
}
6. Code Hoàn Chỉnh Lấy Toàn Bộ Thông Tin Phần Cứng
Dưới đây là ví dụ code hoàn chỉnh lấy tất cả thông tin phần cứng trên Linux:
#include <stdlib.h>
#include <string.h>
#include <sys/sysinfo.h>
#include <sys/utsname.h>
void getSystemInfo() {
struct utsname unameData;
uname(&unameData);
printf(“System Information:\n”);
printf(” System Name: %s\n”, unameData.sysname);
printf(” Node Name: %s\n”, unameData.nodename);
printf(” Release: %s\n”, unameData.release);
printf(” Version: %s\n”, unameData.version);
printf(” Machine: %s\n”, unameData.machine);
}
void getCPUInfo() {
printf(“\nCPU Information:\n”);
FILE *fp = fopen(“/proc/cpuinfo”, “r”);
if (fp == NULL) {
perror(“Error opening /proc/cpuinfo”);
return;
}
char buffer[1024];
int processorCount = 0;
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
if (strstr(buffer, “processor”) != NULL) {
processorCount++;
}
if (strstr(buffer, “model name”) != NULL ||
strstr(buffer, “cpu MHz”) != NULL ||
strstr(buffer, “cache size”) != NULL) {
printf(” %s”, buffer);
}
}
printf(” Number of processors: %d\n”, processorCount);
fclose(fp);
}
void getRAMInfo() {
printf(“\nRAM Information:\n”);
FILE *fp = fopen(“/proc/meminfo”, “r”);
if (fp == NULL) {
perror(“Error opening /proc/meminfo”);
return;
}
char buffer[1024];
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
if (strstr(buffer, “MemTotal”) != NULL ||
strstr(buffer, “MemFree”) != NULL ||
strstr(buffer, “Buffers”) != NULL ||
strstr(buffer, “Cached”) != NULL) {
printf(” %s”, buffer);
}
}
fclose(fp);
}
void getDiskInfo() {
printf(“\nDisk Information:\n”);
FILE *fp = popen(“lsblk -o NAME,SIZE,TYPE,MOUNTPOINT”, “r”);
if (fp == NULL) {
perror(“Failed to run lsblk command”);
return;
}
char buffer[1024];
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
printf(” %s”, buffer);
}
pclose(fp);
}
int main() {
getSystemInfo();
getCPUInfo();
getRAMInfo();
getDiskInfo();
return 0;
}
7. So Sánh Các Phương Pháp Lấy Thông Tin Phần Cứng
| Phương Pháp | Windows | Linux | macOS | Độ Phức Tạp | Thông Tin Chi Tiết |
|---|---|---|---|---|---|
| System Calls | ✓ (Windows API) | ✓ (syscalls) | ✓ (IOKit) | Trung bình | Cao |
| Đọc file hệ thống | ✗ | ✓ (/proc, /sys) | ✓ (system_profiler) | Thấp | Trung bình |
| Thư viện bên thứ 3 | ✓ | ✓ | ✓ | Cao | Rất cao |
| Lệnh hệ thống | ✓ (wmic, systeminfo) | ✓ (lshw, lscpu) | ✓ (system_profiler) | Thấp | Trung bình |
8. Thư Viện Hữu Ích Cho Việc Lấy Thông Tin Phần Cứng
| Thư Viện | Nền Tảng | Ngôn Ngữ | Tính Năng Chính | Link |
|---|---|---|---|---|
| libcpuid | Cross-platform | C/C++ | Lấy thông tin CPU chi tiết | GitHub |
| Open Hardware Monitor | Windows | C# | Monitor toàn diện phần cứng | Website |
| libstatgrab | Linux/Unix | C | Lấy thống kê hệ thống | Website |
| WMI (Windows Management Instrumentation) | Windows | C++/C# | Truy cập toàn diện thông tin hệ thống | Microsoft Docs |
9. Các Lưu Ý Khi Lấy Thông Tin Phần Cứng
- Quyền truy cập: Nhiều thông tin phần cứng đòi hỏi quyền admin/root để truy cập
- Tính cross-platform: Code viết cho Windows thường không chạy được trên Linux và ngược lại
- Hiệu suất: Tránh lấy thông tin phần cứng quá thường xuyên trong các ứng dụng thời gian thực
- Bảo mật: Không lưu trữ hoặc truyền tải thông tin phần cứng nhạy cảm
- Tính tương thích: Kiểm tra trên nhiều phiên bản hệ điều hành khác nhau
10. Tài Nguyên Hữu Ích
Các tài nguyên chính thức và uy tín để tìm hiểu thêm:
- Tài liệu nhân Linux (kernel.org) – Thông tin chi tiết về các file trong /proc và /sys
- Windows API Documentation (Microsoft) – Tài liệu chính thức về các hàm Windows API
- Apple Developer Documentation – Tài liệu về IOKit và các API hệ thống của macOS
11. Ví Dụ Nâng Cao: Lấy Thông Tin Nhiệt Độ CPU
Lấy thông tin nhiệt độ CPU đòi hỏi các phương pháp đặc biệt trên từng hệ điều hành:
11.1 Trên Linux
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
void getCPUTemperature() {
DIR *dir;
struct dirent *entry;
char path[1024];
FILE *fp;
char buffer[1024];
int found = 0;
dir = opendir(“/sys/class/thermal/”);
if (dir == NULL) {
perror(“Error opening thermal directory”);
return;
}
while ((entry = readdir(dir)) != NULL) {
if (strstr(entry->d_name, “thermal_zone”) != NULL) {
snprintf(path, sizeof(path), “/sys/class/thermal/%s/temp”, entry->d_name);
fp = fopen(path, “r”);
if (fp != NULL) {
if (fgets(buffer, sizeof(buffer), fp) != NULL) {
int temp = atoi(buffer) / 1000;
printf(“CPU Temperature: %d°C\n”, temp);
found = 1;
}
fclose(fp);
}
}
}
closedir(dir);
if (!found) {
printf(“Could not read CPU temperature\n”);
}
}
11.2 Trên Windows
Trên Windows, bạn cần sử dụng WMI hoặc các thư viện bên thứ 3 như Open Hardware Monitor:
#include <windows.h>
#include <comdef.h>
#include <Wbemidl.h>
#pragma comment(lib, “wbemuuid.lib”)
void getCPUTemperature() {
HRESULT hres;
// Initialize COM
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres)) {
printf(“Failed to initialize COM library. Error code = 0x%x\n”, hres);
return;
}
// Initialize security
hres = CoInitializeSecurity(
NULL,
-1,
NULL,
NULL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE,
NULL
);
if (FAILED(hres)) {
printf(“Failed to initialize security. Error code = 0x%x\n”, hres);
CoUninitialize();
return;
}
// Create WMI locator
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *)&pLoc);
if (FAILED(hres)) {
printf(“Failed to create IWbemLocator object. Error code = 0x%x\n”, hres);
CoUninitialize();
return;
}
// Connect to WMI
IWbemServices *pSvc = NULL;
hres = pLoc->ConnectServer(
_bstr_t(L”ROOT\\CIMV2″),
NULL,
NULL,
0,
NULL,
0,
0,
&pSvc
);
if (FAILED(hres)) {
printf(“Could not connect to WMI. Error code = 0x%x\n”, hres);
pLoc->Release();
CoUninitialize();
return;
}
// Set security levels
hres = CoSetProxyBlanket(
pSvc,
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_NONE,
NULL,
RPC_C_AUTHN_LEVEL_CALL,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE
);
if (FAILED(hres)) {
printf(“Could not set proxy blanket. Error code = 0x%x\n”, hres);
pSvc->Release();
pLoc->Release();
CoUninitialize();
return;
}
// Execute query
IEnumWbemClassObject* pEnumerator = NULL;
hres = pSvc->ExecQuery(
bstr_t(“WQL”),
bstr_t(“SELECT * FROM MSAcpi_ThermalZoneTemperature”),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);
if (FAILED(hres)) {
printf(“Query for temperature failed. Error code = 0x%x\n”, hres);
pSvc->Release();
pLoc->Release();
CoUninitialize();
return;
}
// Get data from query
IWbemClassObject *pclsObj = NULL;
ULONG uReturn = 0;
int tempFound = 0;
while (pEnumerator) {
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
if (uReturn == 0) break;
VARIANT vtProp;
hr = pclsObj->Get(L”CurrentTemperature”, 0, &vtProp, 0, 0);
if (SUCCEEDED(hr)) {
int temp = (vtProp.intVal / 10) – 273; // Convert from deci-Kelvin to Celsius
printf(“CPU Temperature: %d°C\n”, temp);
tempFound = 1;
}
VariantClear(&vtProp);
pclsObj->Release();
}
if (!tempFound) {
printf(“Could not read CPU temperature\n”);
}
// Cleanup
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
CoUninitialize();
}
12. Kết Luận
Việc lấy thông tin phần cứng bằng ngôn ngữ C đòi hỏi hiểu biết sâu về hệ điều hành và các API hệ thống. Mỗi hệ điều hành có cách tiếp cận riêng:
- Windows: Sử dụng Windows API và WMI
- Linux: Đọc các file trong /proc và /sys
- macOS: Sử dụng IOKit framework
Để phát triển các ứng dụng cross-platform, bạn nên cân nhắc:
- Sử dụng các thư viện bên thứ 3 như libcpuid
- Triển khai code riêng cho từng nền tảng với các macro điều kiện
- Tạo một lớp trừu tượng (abstraction layer) để ẩn đi sự khác biệt giữa các nền tảng
Với kiến thức từ bài viết này, bạn đã có thể bắt đầu phát triển các ứng dụng giám sát phần cứng chuyên nghiệp bằng ngôn ngữ C.