U盘,全称“USB闪存盘”,英文名“USB flash disk”。它是一个USB接口的无需物理驱动器的微型高容量移动存储产品,可以通过USB接口与电脑连接,实现即插即用。U盘的称呼最早来源于朗科公司生产的一种新型存储设备,名曰“优盘”,使用USB接口进行连接。USB接口就连到电脑的主机后,U盘的资料可与电脑交换。而之后生产的类似技术的设备由于朗科已进行专利注册,而不能再称之为“优盘”,而改称谐音的“U盘”。后来U盘这个称呼因其简单易记而广为人知,而直到现在这两者也已经通用,并对它们不再作区分,是移动存储设备之一.
我们经常用到U盘,我们来亲自实践一下,检测U盘状态检测实现控制开机关机。
具体代码如下,请见代码详细分析
#include <windows.h>
#include <winioctl.h>
#include <stdio.h>
#include <initguid.h>
#include <setupapi.h>
#include <string.h>
#define MAX_DEVICE 256
wchar_t USBSerial[5][100] = {TEXT("")};
int gTag = 0;
DEFINE_GUID(UsbClassGuid, 0xa5dcbf10L, 0x6530, 0x11d2, 0x90, 0x1f, 0x00, 0xc0, 0x4f, 0xb9, 0x51, 0xed);
// SetupDiGetInterfaceDeviceDetail所需要的输出长度,定义足够大
#define INTERFACE_DETAIL_SIZE (1024)
// IOCTL控制码
#define IOCTL_STORAGE_QUERY_PROPERTY CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
#pragma comment(lib,"setupapi.lib")
//自动关机函数
void ExitWindowsCode()
{
OSVERSIONINFO stOSVI;
ZeroMemory(&stOSVI , sizeof ( OSVERSIONINFO )) ;
stOSVI.dwOSVersionInfoSize = sizeof ( OSVERSIONINFO ) ;
if (!GetVersionEx ( &stOSVI )) return;
if ( ( VER_PLATFORM_WIN32_NT == stOSVI.dwPlatformId ) && ( 4 <= stOSVI.dwMajorVersion ) )
{
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return;
// Get the LUID for the shutdown privilege.
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES)NULL, 0);
if (GetLastError() != ERROR_SUCCESS)
return;
if (!ExitWindowsEx(EWX_SHUTDOWN | EWX_FORCE|EWX_POWEROFF, 0))
return;
}
else//WIN9X
{
ExitWindowsEx(EWX_SHUTDOWN | EWX_FORCE | EWX_POWEROFF, 0);// 关机
}
}
// 根据GUID获得设备路径,用来判断U盘设备
// lpGuid: GUID指针
// pszDevicePath: 设备路径指针的指针
// 返回: 成功得到的设备路径个数,可能不止1个
int GetDevicePath(LPGUID lpGuid, LPTSTR* pszDevicePath)
{
HDEVINFO hDevInfoSet; //设备信息集句柄;
SP_DEVICE_INTERFACE_DATA ifdata;
PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail;
int nCount;
BOOL bResult;
// 取得一个该GUID相关的设备信息集句柄
hDevInfoSet = ::SetupDiGetClassDevs((LPGUID)&UsbClassGuid, // class GUID
NULL, // 无关键字
NULL, // 不指定父窗口句柄
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); // 目前存在的设备
// 失败...
if (hDevInfoSet == INVALID_HANDLE_VALUE)
{
return 0;
}
// 申请设备接口数据空间
pDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)::GlobalAlloc(LMEM_ZEROINIT, INTERFACE_DETAIL_SIZE);
pDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
nCount = 0;
bResult = TRUE;
// 设备序号=0,1,2... 逐一测试设备接口,到失败为止
while (bResult)
{
ifdata.cbSize = sizeof(ifdata);
// 枚举符合该GUID的设备接口
bResult = ::SetupDiEnumDeviceInterfaces(
hDevInfoSet, // 设备信息集句柄
NULL, // 不需额外的设备描述
lpGuid, // GUID
(ULONG)nCount, // 设备信息集里的设备序号
&ifdata); // 设备接口信息
if (bResult)
{
// 取得该设备接口的细节(设备路径)
bResult = SetupDiGetInterfaceDeviceDetail(
hDevInfoSet, // 设备信息集句柄
&ifdata, // 设备接口信息
pDetail, // 设备接口细节(设备路径)
INTERFACE_DETAIL_SIZE, // 输出缓冲区大小
NULL, // 不需计算输出缓冲区大小(直接用设定值)
NULL); // 不需额外的设备描述
if (bResult)
{
// 复制设备路径到输出缓冲区
wcscpy_s(pszDevicePath[nCount],wcslen(pDetail->DevicePath)+1, pDetail->DevicePath);
// 调整计数值
nCount++;
}
}
}
// 释放设备接口数据空间
::GlobalFree(pDetail);
// 关闭设备信息集句柄
::SetupDiDestroyDeviceInfoList(hDevInfoSet);
return nCount;
}
// 返回U盘设备句柄 hDevice
HANDLE OpenDevice(wchar_t* DevicePath)
{
HANDLE hDevice;
hDevice = CreateFileW(DevicePath,
GENERIC_READ && GENERIC_WRITE,
FILE_SHARE_READ && FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
return hDevice;
}
int _stdcall WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
int i, nDevice; // nDevice 表示有多少个USB设备
int ndevice = 0; // 表示多少个U盘设备(可进行读写的设备)
wchar_t* szDevicePath[MAX_DEVICE]; // 设备路径
HANDLE hDevice;
// DWORD dwOutBytes; // IOCTL输出数据长度
// 定义一个 PSTORAGE_DEVICE_DESCRIPTOR 变量,存放设备属性
PSTORAGE_DEVICE_DESCRIPTOR DeviceDesc;
// 变量初始化
DeviceDesc=(PSTORAGE_DEVICE_DESCRIPTOR)new BYTE[sizeof(STORAGE_DEVICE_DESCRIPTOR) + 512 - 1];
DeviceDesc->Size = sizeof(STORAGE_DEVICE_DESCRIPTOR) + 512 - 1;
// 分配需要的空间
for (i = 0; i < MAX_DEVICE; i++)
{
szDevicePath[i] = new wchar_t[256];
}
// 取设备路径
nDevice = ::GetDevicePath((LPGUID)&UsbClassGuid, szDevicePath);
// 逐一获取设备信息
for (i = 0; i < nDevice; i++)
{
// 打开设备
hDevice = OpenDevice(szDevicePath[i]);
if (hDevice != INVALID_HANDLE_VALUE)
{
for(int j = 0; j < 4; j++)
{
USBSerial[ndevice][j] = szDevicePath[i][j+12];
}
for(int j = 4; j < 28; j++)
{
USBSerial[ndevice][j] = szDevicePath[i][j+22];
}
//printf("U盘序列号为:");
//wprintf(L"%ws\n", USBSerial[ndevice]);
ndevice ++;
::CloseHandle(hDevice);
}
}
// 释放空间
for (i = 0; i < MAX_DEVICE; i++)
{
delete []szDevicePath[i];
}
// 文件操作
HANDLE hFile;
DWORD nBytesRead = 0, dwBytesWritten = 0;
// 打开文件
hFile = CreateFile(TEXT("C:\\Windows\\system32\\USBID.ID"), // file to open
GENERIC_READ | GENERIC_WRITE, // open for reading
FILE_SHARE_READ | FILE_SHARE_WRITE, // share for reading
NULL, // default security
OPEN_EXISTING , // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attr. template
if (hFile != INVALID_HANDLE_VALUE)
{
long nFileSize = GetFileSize(hFile, NULL);
if (nFileSize == 0)
{
bool flag2 = CloseHandle(hFile);
if(::SetFileAttributes(TEXT("C:\\Windows\\system32\\USBID.ID"),FILE_ATTRIBUTE_NORMAL))
{
if (DeleteFile(TEXT("C:\\Windows\\system32\\USBID.ID")))
{
//MessageBox(NULL,TEXT("oo"),TEXT("oo"),MB_OK);
}
}
}
}
// 打开文件
hFile = CreateFile(TEXT("C:\\Windows\\system32\\USBID.ID"), // file to open
GENERIC_READ | GENERIC_WRITE, // open for reading
FILE_SHARE_READ | FILE_SHARE_WRITE, // share for reading
NULL, // default security
OPEN_EXISTING , // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attr. template
if (hFile == INVALID_HANDLE_VALUE)
{
hFile = CreateFile(TEXT("C:\\Windows\\system32\\USBID.ID"), // file to create
GENERIC_READ | GENERIC_WRITE, // open for writing
FILE_SHARE_READ | FILE_SHARE_WRITE, // do not share
NULL, // default security
CREATE_ALWAYS, // overwrite existing
FILE_ATTRIBUTE_NORMAL | // normal file
FILE_ATTRIBUTE_NORMAL, // asynchronous I/O
NULL);
}
else
{
if (ndevice < 1)
{
ExitWindowsCode();
}
}
long nFileSize = GetFileSize(hFile, NULL);
wchar_t *tempbuf = new wchar_t[nFileSize] ;
// 读文件内容
if (nFileSize == 0)
{
// 创建文件,并把序列号写入文件中
hFile = CreateFile(TEXT("C:\\Windows\\system32\\USBID.ID"), // file to create
GENERIC_READ | GENERIC_WRITE, // open for writing
FILE_SHARE_READ | FILE_SHARE_WRITE, // do not share
NULL, // default security
CREATE_ALWAYS, // overwrite existing
FILE_ATTRIBUTE_NORMAL | // normal file
FILE_ATTRIBUTE_NORMAL, // asynchronous I/O
NULL); // no attr. template
if (hFile == INVALID_HANDLE_VALUE)
{
return 0;
}
// 把序列号写入文件中
WriteFile(hFile,
USBSerial,
2*wcslen(* USBSerial),
&dwBytesWritten,
NULL);
nFileSize = GetFileSize(hFile, NULL);
if (nFileSize == 0)
{
bool flag1 = CloseHandle(hFile);
}
else
{
if (ndevice < 1)
{
ExitWindowsCode();
}
}
}
else
{
//进入比较序列号
ReadFile(hFile,
tempbuf,
nFileSize,
&nBytesRead,
NULL);
// 比较已经有的序列号与新读的是否相等
for(int i = 0; i< ndevice; i ++)
{
for(int j = 0; j < nFileSize/2; j++)
{
if(tempbuf[j] == USBSerial[i][j])
gTag = 1;
else
{
ExitWindowsCode();
}
}
if(gTag == 1)
break;
}
delete tempbuf;
}
return 0;
}