1. 通过设置IOCTL_STORAGE_EJECT_MEDIA

  • 通过CreateFile打开指定盘符的U盘获取设备句柄hDevice
  • 通过DeviceIoControl(hDevice,FSCTL_DISMOUNT_VOLUME…)强制关闭其他进程对设备的占用
  • 通过DeviceIoControl(hDevice,FSCTL_LOCK_VOLUME…)对设备进行加锁,防止其他进程干扰
  • 通过DeviceIoControl(hDevice,IOCTL_STORAGE_MEDIA_REMOVAL…)来禁用阻止删除多媒体设备功能
  • 通过DeviceIoControl(hDevice,IOCTL_STORAGE_EJECT_MEDIA…)来弹出设备。
    注意,此方法只是从文件浏览页面删除盘符,并不是真的弹出了设备
static int EjectLogDisk(const char *discId)
{DWORD accessMode = GENERIC_WRITE | GENERIC_READ;DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;HANDLE hDevice;long bResult = 0;DWORD retu = 0;DWORD dwError;DWORD dwBytesReturned;DWORD dwSleepAmount;int nTryCount;char szDriv[10];if(discId == NULL){return 0;}dwSleepAmount = LOCK_TIMEOUT/LOCK_RETRIES;sprintf(szDriv,"\\\\.\\%s:",discId);hDevice = CreateFile(szDriv,accessMode,shareMode,NULL,OPEN_EXISTING,0,NULL);if(hDevice == INVALID_HANDLE_VALUE){printf("uninstallusb createfile failed error:%d\n",GetLastError());return -1;}
#if 1//卸载U盘卷,不论是否在使用dwBytesReturned = 0;if(!DeviceIoControl(hDevice,FSCTL_DISMOUNT_VOLUME,NULL,0,NULL,0,&dwBytesReturned,NULL)){printf("deviceIoConrol FSCTL_DISMOUNT_VOLUME failed\n");}//此循环是用于锁定要弹出的U盘设备,如果U盘在使用,则循环等待// Do this in a loop until a timeout period has expiredfor(nTryCount = 0;nTryCount < LOCK_RETRIES;nTryCount++){if(DeviceIoControl(hDevice,FSCTL_LOCK_VOLUME,NULL,0,NULL,0,&dwBytesReturned,NULL)){break;}}
#endifdwBytesReturned = 0;PREVENT_MEDIA_REMOVAL PMRBuffer;PMRBuffer.PreventMediaRemoval = FALSE;if(!DeviceIoControl(hDevice,IOCTL_STORAGE_MEDIA_REMOVAL,&PMRBuffer,sizeof(PREVENT_MEDIA_REMOVAL),NULL,0,&dwBytesReturned,NULL)){printf("DeviceIoControl IOCTL_STORAGE_MEDIA_REMOVAL failed:%d\n",GetLastError());}bResult = DeviceIoControl(hDevice,IOCTL_STORAGE_EJECT_MEDIA,NULL,0,NULL,0,&retu,NULL);if(!bResult){CloseHandle(hDevice);printf("uninstallusb DeviceIoControl failed error:%d\n",GetLastError());return -1;}CloseHandle(hDevice);return 0;
}

2. 通过设置CM_Request_Device_Eject

此方法的作用与从右下角托盘中安全删除并弹出媒体的功能一致,设置之后,设备的错误码为47。并且设备只能通过断上电重新接入电脑才可用。

#include <winioctl.h>
#include "setupapi.h"
#include "cfgmgr32.h"
#pragma comment(lib,"setupapi.lib")  DEVINST GetDrivesDevInstByDiskNumber(long DiskNumber)
{GUID* guid = (GUID*)(void*)&GUID_DEVINTERFACE_DISK;// Get device interface info set handle for all devices attached to systemHDEVINFO 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;SP_DEVICE_INTERFACE_DATA devInterfaceData = {0};devInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);BOOL bRet = FALSE;PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd;SP_DEVICE_INTERFACE_DATA spdid;SP_DEVINFO_DATA spdd;DWORD dwSize;spdid.cbSize = sizeof(spdid);while ( true ){bRet = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, guid, dwIndex,&devInterfaceData);if (!bRet){break;}SetupDiEnumInterfaceDevice(hDevInfo, NULL, guid, dwIndex, &spdid);dwSize = 0;SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, NULL, 0, &dwSize,NULL);if ( dwSize ){pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, dwSize);if ( pspdidd == NULL ) {continue; // autsch}pspdidd->cbSize = sizeof(*pspdidd);ZeroMemory((PVOID)&spdd, sizeof(spdd));spdd.cbSize = sizeof(spdd);long res = SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid,pspdidd, dwSize, &dwSize, &spdd);if ( res ){HANDLE hDrive = CreateFile(pspdidd->DevicePath, 0,FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);if ( hDrive != INVALID_HANDLE_VALUE ){STORAGE_DEVICE_NUMBER sdn;DWORD dwBytesReturned = 0;res = DeviceIoControl(hDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER,NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL);if ( res ) {if ( DiskNumber == (long)sdn.DeviceNumber ){CloseHandle(hDrive);SetupDiDestroyDeviceInfoList(hDevInfo);return spdd.DevInst;}}CloseHandle(hDrive);}}HeapFree(GetProcessHeap(), 0, pspdidd);}dwIndex++;}SetupDiDestroyDeviceInfoList(hDevInfo);return 0;
}static int EjectUSBDisk(char *discId)
{DWORD accessMode = GENERIC_WRITE | GENERIC_READ;DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;HANDLE hDevice;long bResult = 0;DWORD retu = 0;DWORD dwError;DWORD dwBytesReturned;int nTryCount;char szDriv[10];if(discId == NULL){return 0;}sprintf(szDriv,"\\\\.\\%s:",discId);hDevice = CreateFile(szDriv,accessMode,shareMode,NULL,OPEN_EXISTING,0,NULL);if(hDevice == INVALID_HANDLE_VALUE){printf("uninstallusb createfile failed error:%d\n",GetLastError());return -1;}//使用CM_Request_Device_Eject弹出USB设备STORAGE_DEVICE_NUMBER sdn;long DiskNumber = -1;long res = DeviceIoControl(hDevice,IOCTL_STORAGE_GET_DEVICE_NUMBER,NULL,0,&sdn,sizeof(sdn),&dwBytesReturned,NULL);if(!res){printf("DeviceIoControl IOCTL_STORAGE_GET_DEVICE_NUMBER failed:%d\n",GetLastError());CloseHandle(hDevice);return -1;}CloseHandle(hDevice);DiskNumber = sdn.DeviceNumber;if(DiskNumber == -1){printf("DiskNumber == -1\n");return -1;}DEVINST DevInst = GetDrivesDevInstByDiskNumber(DiskNumber);if(DevInst == 0){printf("GetDrivesDevInstDiskNumber failed\n");return -1;}ULONG Status = 0;ULONG ProblemNumber = 0;PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown;char VetoName[MAX_PATH];bool bSuccess = false;res = CM_Get_Parent(&DevInst,DevInst,0); //disk's parent, e.g. the USB bridge, the SATA controller....res = CM_Get_DevNode_Status(&Status,&ProblemNumber,DevInst,0);bool IsRemovable = ((Status & DN_REMOVABLE) != 0);printf("isremovable:%d\n",IsRemovable);long i;// try 3 timesfor(i = 0;i < 3;i++){VetoName[0] = '\0';if(IsRemovable){res = CM_Request_Device_Eject(DevInst,&VetoType,VetoName,MAX_PATH,0);}else{res = CM_Query_And_Remove_SubTree(DevInst,&VetoType,VetoName,MAX_PATH,0);}bSuccess = (res == CR_SUCCESS && VetoName[0] == '\0');if(bSuccess){break;}else{Sleep(200);}}if(bSuccess){printf("Success\n\n");}else{printf("failed\n");}return 0;
}

Windows下两种方法弹出U盘相关推荐

  1. windows下两种方法通过cmd进入指定目录

    方法一:通过cmd cd命令进入 相同盘符下的目录可直接使用cd: 但是windows下不同于linux,不能直接跨盘符cd进入目录, 例如:从C盘进入E盘下面的目录,需要两行命令:跨盘符+跨盘符目录 ...

  2. centos下两种方法安装git

    centos 5 64位下两种方法安装git 这里来给大家介绍下编译安装和yum安装git.   系统:centos 5.5 64位   需要的软件包:git-latest.tar.gz epel-r ...

  3. 安卓开发弹窗activity风格_安卓两种底部弹出窗dialog实现方式

    [实例简介]安卓两种底部弹出窗dialog实现方式,一种是列表弹窗实现,2是灵活底部弹窗,传入布局以及控件id [实例截图] [核心代码] package com.kx.kxbottomdialog; ...

  4. [shell]两种方法写出99乘法表

    两种方法不同点主要是输入最后的换行不同: #!/usr/bin/env bash for ((i=1;i<=9;i++)) do for ((j=1;j<=i;j++)) do echo  ...

  5. linux(虚拟机中)与windows共享文件两种方法

    Windows 下用 SourceInsight 与 Linux 协作编码 习惯了用SourceInsight 读写代码,在Linux下一时没找到类似的工具,vi的操作也不熟,偶尔看看或小改动代码还行 ...

  6. 两种方法筛选出多因子量化选股模型

    多因子选股模型在模型搭建中,往往会涉及到非常多的股价影响因子,并可能导出数量极多的备选模型.因此,对于多因子选股模型的评价和筛选,就显得尤为关键. 对于专业的量化投资人而言,就需要进一步了解多因子选股 ...

  7. linux centos安装git,centos下两种方法安装git–转载

    今天下个包需要使用git,网上找了下看到大多数只有编译安装,并且编译安装还有错,不知道他们也没有实验过,这里我来给大家介绍下编译安装和yum安装git. 系统:centos 5.5 需要的软件包:gi ...

  8. 合并BIN文件的两种方法

    合并BIN文件的两种方法 在单片机的开发过程中,经常需要将两个单独的BIN文件合并成一个文件,方便烧写和生产.下面结合STM32的IAP Bootloader Code和Application Cod ...

  9. 两种方法转换U盘格式

    其实非常简单,就是把U盘常用的格式由FAT32转为NTFS格式,NTFS文件系统是Windows NT操作系统发展中的一个里程碑.它集加密.压缩.性能提升等多种优点于一身,更重要的是它的权限设置,能帮 ...

  10. 小程序设置背景图片的两种方法总结

    背景图片 我们会时常遇到设置背景图片,这里简单地总结下两种方法: 1.background-image background-image,顾名思义是背景图片的意思,设置父亲元素,然后通过backgro ...

最新文章

  1. 缓冲区溢出_在Java中使用Google的协议缓冲区
  2. 插值法补齐缺失数据_关于数据清洗的常见方式
  3. docker 发布tomcat项目_Docker部署java项目[tomcat环境]
  4. sql长整型_SQL性能优化,太太太太太太太有用了!
  5. 【数学】礼物(jzoj 2129)
  6. 飞鸽传书:webbrowser 本生是一个控件
  7. Adaptive Execution 让 Spark SQL 更高效更智能
  8. struts2学习一:搭建第一个struts2.5项目
  9. python练手经典100例-【Python精华】100个Python练手小程序
  10. html5复选框控制按钮状态,HTML5如何添加原生radio按钮和checkbox复选框转换为非常好看的滑动开关按钮的插件...
  11. sqlalchemy mysql配置中怎么设置utf8_python – 使用SQLAlchemy和pymysql,如何设置连接以使用utf8mb4?...
  12. 高等代数——大学高等代数课程创新教材(丘维声)——3.4笔记+习题
  13. 二分类变量相关性分析spss_SPSS教程 | 两个有序分类变量的相关分析及SPSS操作
  14. ALTOVA XMLSpy 2013中文版下载教程及简单运用
  15. .net扫盲-网页对话框应用
  16. Origin2021安装过程中的系列问题
  17. java中的变量是什么
  18. merge squash 和 merge rebase 区别 GIT使用
  19. CleanMyMac XMac苹果电脑专属系统优化工具
  20. 2020互联网大厂职级对应薪资一览表

热门文章

  1. 请高手指点,简单的几个数组操作方法不知道是否可以有更好的改进方法或者更简单的方法?
  2. golang服务器压力测试,压力测试 - Go语言中文网 - Golang中文社区
  3. Access denied for user ''@'localhost' to database 'mysql‘’
  4. Linux内存寻址之二:逻辑地址到虚拟地址的转换
  5. 电脑连上网,可是软件、谷歌等浏览器都显示未连接到互联网。远程计算机设备将不受连接,两个解决方法。
  6. 馈线中的VSWR电压驻波比
  7. 【eos系列】智能合约 私链激活 基本操作
  8. html静态网站基于游戏网站设计与实现共计10个页面 (仿地下城与勇士游戏网页)
  9. begintrans返回值_BeginTransaction() 方法
  10. mybatis整合Redis和ehcache实现二级缓存