USB存储设备的5种打开方式以及其关系

本文详细介绍了USB存储设备在电脑中被识别的过程,包括物理驱动器号、设备路径、卷路径的概念及其相互间的关系。同时提供了获取这些信息的代码示例,帮助读者深入理解设备标识的原理。

1. USB存储设备的标识

USB存储设备插入电脑之后,系统会给设备分配物理驱动器号、设备路径、卷路径。

1.1. 物理驱动器号

StringMeaning
\\.\PhysicalDrive0Opens the first physical drive.
\\.\PhysicalDrive1Opens the third physical drive.

1.2. 设备路径

DevicePath:
\\.\usbstor#disk&ven_usb&prod_flash_drive&rev_1.00#6&31e44d9c&3#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}

1.3. 卷路径

卷又被称为逻辑驱动器。

VolumePath:
\\.\Volume{65f4b646-a379-11e9-a35f-005056c00008}

1.3.1 卷设备名

一个卷都对应一个卷设备名。

VolumeName:
\\.\HarddiskVolume57

1.3.2 逻辑驱动器号

逻辑驱动器号它是操作系统方便用户直接访问卷而建立的一个映射。
即给卷分配挂载点(Mount Point),可以通过SetVolumeMountPoint来实现。挂载点有两种形式,一种是直接分配逻辑盘符(Logic disk letter),另一种是卷文件夹(Mounted folder)。如C盘空间不够,电脑插入一个新的硬盘,我们可以直接将这个硬盘挂载到C盘下作为C盘的一个文件夹。

Logic Disk Letter:
H:\

2. 设备标识之间的关系

2.1. 通过逻辑盘符获取物理设备号

DWORD GetPhysicalDriveFromDiskLetter(char letter)
{
    CHAR path[DISK_PATH_LEN] = {0};
    sprintf(path, "\\\\.\\%c:", letter);
 	HANDLE  hDevice = CreateFile(path,                // drive to open
                         GENERIC_READ | GENERIC_WRITE,    // access to the drive
                         FILE_SHARE_READ | FILE_SHARE_WRITE,    //share mode
                         NULL,             // default security attributes
                         OPEN_EXISTING,    // disposition
                         0,                // file attributes
                         NULL);            // do not copy file attribute
    if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
    {
        fprintf(stderr, "CreateFile() Error: %ld\n", GetLastError());
        return DWORD(-1);
    }
 
    DWORD readed = 0;                   // discard results
    STORAGE_DEVICE_NUMBER ;             //use this to get disk numbers
    BOOL result = DeviceIoControl(
                hDevice,                // handle to device
                IOCTL_STORAGE_GET_DEVICE_NUMBER, // dwIoControlCode
                NULL,                            // lpInBuffer
                0,                               // nInBufferSize
                &number,           // output buffer
                sizeof(number),         // size of output buffer
                &readed,       // number of bytes returned
                NULL      // OVERLAPPED structure
            );
    if (!result) // fail
    {
        fprintf(stderr, "IOCTL_STORAGE_GET_DEVICE_NUMBER Error: %ld\n", GetLastError());
        (void)CloseHandle(hDevice);
        return (DWORD)-1;
    }
    //printf("%d %d %d\n\n", number.DeviceType, number.DeviceNumber, number.PartitionNumber);
 
    (void)CloseHandle(hDevice);
    return number.DeviceNumber;
}

2.2. 通过卷名获取物理设备号

DWORD GetPhysicalDriveFromVolumeName(LPCSTR lpcVolumeName)
{
    CHAR path[DISK_PATH_LEN] = {0};
    sprintf(path, "\\\\.\\%s", lpcVolumeName);
    // 如:"\\.\Volume{f0a05445-2d33-11e6-9b0b-806e6f6e6963}"
 	HANDLE  hDevice = CreateFile(path,                // drive to open
                         GENERIC_READ | GENERIC_WRITE,    // access to the drive
                         FILE_SHARE_READ | FILE_SHARE_WRITE,    //share mode
                         NULL,             // default security attributes
                         OPEN_EXISTING,    // disposition
                         0,                // file attributes
                         NULL);            // do not copy file attribute
    if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
    {
        fprintf(stderr, "CreateFile() Error: %ld\n", GetLastError());
        return DWORD(-1);
    }
 
    DWORD readed = 0;                   // discard results
    STORAGE_DEVICE_NUMBER number;       //use this to get disk numbers
    BOOL result = DeviceIoControl(
                hDevice,                // handle to device
                IOCTL_STORAGE_GET_DEVICE_NUMBER, // dwIoControlCode
                NULL,                            // lpInBuffer
                0,                               // nInBufferSize
                &number,           // output buffer
                sizeof(number),         // size of output buffer
                &readed,       // number of bytes returned
                NULL      // OVERLAPPED structure
            );
    if (!result) // fail
    {
        fprintf(stderr, "IOCTL_STORAGE_GET_DEVICE_NUMBER Error: %ld\n", GetLastError());
        (void)CloseHandle(hDevice);
        return (DWORD)-1;
    }
    //printf("%d %d %d\n\n", number.DeviceType, number.DeviceNumber, number.PartitionNumber);
 
    (void)CloseHandle(hDevice);
    return number.DeviceNumber;
}

2.3 获取所有的逻辑盘符

int GetAllDisk(std::vector<CString>& vecDrives)
{
 char szbuf[MAX_PATH] = {0};
 GetLogicalDriveStringsA(MAX_PATH,szbuf);
 
 int nCount  = 0;
 char * pDrive = szbuf;
 for(int nlen =strlen(szbuf); nlen == 3 ;nCount++)
 {  
  CString strDrive = pDrive;
  vecDrives.push_back(strDrive);
  pDrive +=4;
  nlen = strlen(pDrive);
 } 
 return nCount;
}

2.4. 获取所有的卷

int GetAllVolume(vector<CString>& vstrVolume)
{
	CHAR  DeviceName[MAX_PATH] = "";
	DWORD  Error                = ERROR_SUCCESS;
	HANDLE FindHandle           = INVALID_HANDLE_VALUE;
	BOOL   Found                = FALSE;
	size_t Index                = 0;
	BOOL   Success              = FALSE;
	CHAR  VolumeName[MAX_PATH] = "";
	int nVolumeCnt = 0;
	//
	//  Enumerate all volumes in the system.
	FindHandle = FindFirstVolume(VolumeName, ARRAYSIZE(VolumeName));

	if (FindHandle == INVALID_HANDLE_VALUE)
	{
		Error = GetLastError();
		return 0;
	}

	for (;;)
	{
		//
		//  Skip the \\?\ prefix and remove the trailing backslash.
		if (VolumeName[0]     != L'\\' ||
			VolumeName[1]     != L'\\' ||
			VolumeName[2]     != L'?'  ||
			VolumeName[3]     != L'\\' ||
			VolumeName[Index] != L'\\') 
		{
			Error = ERROR_BAD_PATHNAME;
			break;
		}
		nVolumeCnt++;
		vstrVolume.push_back(VolumeName);

		//  Move on to the next volume.
		Success = FindNextVolume(FindHandle, VolumeName, ARRAYSIZE(VolumeName));

		if ( !Success ) 
		{
			Error = GetLastError();

			if (Error != ERROR_NO_MORE_FILES) 
			{
				break;
			}

			//
			//  Finished iterating
			//  through all the volumes.
			Error = ERROR_SUCCESS;
			break;
		}
	}

	FindVolumeClose(FindHandle);
	FindHandle = INVALID_HANDLE_VALUE;

	return nVolumeCnt;
}

2.5. 通过挂载点获取卷名

	char szMountPointName[MAX_PATH]="J:\\";
	char szVolumeName[MAX_PATH]="";
	GetVolumeNameForVolumeMountPoint(szMountPointName,szVolumeName,MAX_PATH);

2.6. 遍历所有的卷、卷路径、挂载点

#include <windows.h>
#include <stdio.h>

void DisplayVolumePaths(
        __in PWCHAR VolumeName
        )
{
    DWORD  CharCount = MAX_PATH + 1;
    PWCHAR Names     = NULL;
    PWCHAR NameIdx   = NULL;
    BOOL   Success   = FALSE;

    for (;;) 
    {
        //
        //  Allocate a buffer to hold the paths.
        Names = (PWCHAR) new BYTE [CharCount * sizeof(WCHAR)];

        if ( !Names ) 
        {
            //
            //  If memory can't be allocated, return.
            return;
        }

        //
        //  Obtain all of the paths
        //  for this volume.
        Success = GetVolumePathNamesForVolumeNameW(
            VolumeName, Names, CharCount, &CharCount
            );

        if ( Success ) 
        {
            break;
        }

        if ( GetLastError() != ERROR_MORE_DATA ) 
        {
            break;
        }

        //
        //  Try again with the
        //  new suggested size.
        delete [] Names;
        Names = NULL;
    }

    if ( Success )
    {
        //
        //  Display the various paths.
        for ( NameIdx = Names; 
              NameIdx[0] != L'\0'; 
              NameIdx += wcslen(NameIdx) + 1 ) 
        {
            wprintf(L"  %s", NameIdx);
        }
        wprintf(L"\n");
    }

    if ( Names != NULL ) 
    {
        delete [] Names;
        Names = NULL;
    }

    return;
}

void __cdecl wmain(void)
{
    DWORD  CharCount            = 0;
    WCHAR  DeviceName[MAX_PATH] = L"";
    DWORD  Error                = ERROR_SUCCESS;
    HANDLE FindHandle           = INVALID_HANDLE_VALUE;
    BOOL   Found                = FALSE;
    size_t Index                = 0;
    BOOL   Success              = FALSE;
    WCHAR  VolumeName[MAX_PATH] = L"";

    //
    //  Enumerate all volumes in the system.
    FindHandle = FindFirstVolumeW(VolumeName, ARRAYSIZE(VolumeName));

    if (FindHandle == INVALID_HANDLE_VALUE)
    {
        Error = GetLastError();
        wprintf(L"FindFirstVolumeW failed with error code %d\n", Error);
        return;
    }

    for (;;)
    {
        //
        //  Skip the \\?\ prefix and remove the trailing backslash.
        Index = wcslen(VolumeName) - 1;

        if (VolumeName[0]     != L'\\' ||
            VolumeName[1]     != L'\\' ||
            VolumeName[2]     != L'?'  ||
            VolumeName[3]     != L'\\' ||
            VolumeName[Index] != L'\\') 
        {
            Error = ERROR_BAD_PATHNAME;
            wprintf(L"FindFirstVolumeW/FindNextVolumeW returned a bad path: %s\n", VolumeName);
            break;
        }

        //
        //  QueryDosDeviceW does not allow a trailing backslash,
        //  so temporarily remove it.
        VolumeName[Index] = L'\0';

        CharCount = QueryDosDeviceW(&VolumeName[4], DeviceName, ARRAYSIZE(DeviceName)); 

        VolumeName[Index] = L'\\';

        if ( CharCount == 0 ) 
        {
            Error = GetLastError();
            wprintf(L"QueryDosDeviceW failed with error code %d\n", Error);
            break;
        }

        wprintf(L"\nFound a device:\n %s", DeviceName);
        wprintf(L"\nVolume name: %s", VolumeName);
        wprintf(L"\nPaths:");
        DisplayVolumePaths(VolumeName);

        //
        //  Move on to the next volume.
        Success = FindNextVolumeW(FindHandle, VolumeName, ARRAYSIZE(VolumeName));

        if ( !Success ) 
        {
            Error = GetLastError();

            if (Error != ERROR_NO_MORE_FILES) 
            {
                wprintf(L"FindNextVolumeW failed with error code %d\n", Error);
                break;
            }

            //
            //  Finished iterating
            //  through all the volumes.
            Error = ERROR_SUCCESS;
            break;
        }
    }

    FindVolumeClose(FindHandle);
    FindHandle = INVALID_HANDLE_VALUE;

    return;
}

2.7. 获取所有的磁盘设备路径


DWORD GetAllDiskDevicePath(vector<CString>& vstrDevice)
{
	GUID* guid = (GUID*)&GUID_DEVINTERFACE_DISK;

	// Get device interface info set handle
	// for all devices attached to system
	HDEVINFO hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL,
		DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);

	if ( hDevInfo == INVALID_HANDLE_VALUE )  {
		return 0;
	}

	// Retrieve a context structure for a device interface
	// of a device information set.
	DWORD dwIndex = 0;
	BOOL bRet = FALSE;

	BYTE Buf[1024];
	PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)Buf;
	SP_DEVICE_INTERFACE_DATA         spdid;
	SP_DEVINFO_DATA                  spdd;
	DWORD                            dwSize;

	spdid.cbSize = sizeof(spdid);

	while ( true )  
	{
		bRet = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, guid, dwIndex, &spdid);
		if ( !bRet )
		{
			break;
		}

		dwSize = 0;
		SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, NULL, 0, &dwSize, NULL);

		if ( dwSize!=0 && dwSize<=sizeof(Buf) ) 
		{
			pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!

			ZeroMemory((PVOID)&spdd, sizeof(spdd));
			spdd.cbSize = sizeof(spdd);

			long res = SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, pspdidd,
				dwSize, &dwSize, &spdd);
			if ( res ) 
			{
				vstrDevice.push_back(pspdidd->DevicePath);
			}
		}
		dwIndex++;
	}

	SetupDiDestroyDeviceInfoList(hDevInfo);

	return dwIndex;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值