现在的位置: 首页 > 综合 > 正文

在程序中移除U盘

2013年05月14日 ⁄ 综合 ⁄ 共 6177字 ⁄ 字号 评论关闭
文章目录

 

转载请标明是引用于 http://blog.csdn.net/chenyujing1234 

欢迎大家拍砖

 

代码下载(VS2008编译器):http://www.rayfile.com/zh-cn/files/4e98c7cf-25c4-11e2-aeea-0015c55db73d/

一、实现方法

说明:

cr = CM_Request_Device_Eject( DeviceInfoData.DevInst, &pnpvietotype, vetoname, len, 0 ); //没有气泡提示
cr = CM_Request_Device_Eject( DeviceInfoData.DevInst, &pnpvietotype, NULL, 0, 0 ); //这样就有气泡提示了。

对于CM_Request_Device_Eject这类在DDK中的函数,可以有如下几种方法:
1.把DDK的头文件路径和库包含进来,但头文件包含必须使用

extern "C"
{
#include "hidsdi.h"
}

2. 把DDK里的相关文件拷到工程里来
3. 用GetProcAddress从相关DLL中取得函数来执行。

这里我们选择第1与第2种方法结合起来的方式。以下给出两个版本的源码:

 

第一版:

里面include及导入的lib是我们从DDK中拷过来放到工程下面的

extern "C" {
#include "hidsdi.h"
}
// 需加入hid.lib
#pragma comment(lib,"hid.lib")
#pragma comment(lib,"setupapi.lib")
#pragma comment(lib,"cfgmgr32.lib")

#include "setupapi.h"
#include "cfgmgr32.h"
#include "usbiodef.h"


#define DWORD_PTR DWORD
#define ULONG_PTR DWORD



// /* A5DCBF10-6530-11D2-901F-00C04FB951ED */
DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, \
			0xC0, 0x4F, 0xB9, 0x51, 0xED);
#define GUID_CLASS_USB_DEVICE GUID_DEVINTERFACE_USB_DEVICE

int main(int argc, _TCHAR* argv[])
{
	HDEVINFO hDevInfo;

	SP_DEVINFO_DATA DeviceInfoData;
	DWORD i;

	//--------------------------------------------------------------------------
	// 获取设备信息
	hDevInfo = SetupDiGetClassDevs((LPGUID)&GUID_CLASS_USB_DEVICE,
		0, // Enumerator
		0,
		DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );
	if (hDevInfo == INVALID_HANDLE_VALUE)
	{
		// 查询信息失败
		printf("ERROR - SetupDiGetClassDevs()\n");
		return 1;
	}
	//--------------------------------------------------------------------------

	// 枚举每个USB设备
	DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
	for (i=0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++)
	{
		LPTSTR buffer = NULL;
		PVOID buffer2 = NULL;
		DWORD buffersize = 0;
		ULONG len;
		CONFIGRET cr;
		PNP_VETO_TYPE pnpvietotype;
		CHAR vetoname[MAX_PATH];
		ULONG ulStatus;
		ULONG ulProblemNumber;

		cr = CM_Get_DevNode_Status( &ulStatus,
									&ulProblemNumber,
									DeviceInfoData.DevInst,
									0);
		if ( CR_SUCCESS == cr ) 
		{
			printf("OK - CM_Get_DevNode_Status()[%d]\n", cr);
			printf("OK - CM_Get_DevNode_Status() sts [%x]\n", ulStatus);
			printf("OK - CM_Get_DevNode_Status() pro [%x]\n", ulProblemNumber);
		} 
		else
		{
			printf("ERROR - CM_Get_DevNode_Status()[%d]/n", cr);
			printf("ERROR - CM_Get_DevNode_Status()[%d]/n", GetLastError());
		}
		// DN_DISABLEABLE or DN_REMOVABLE
		if ((DN_DISABLEABLE & ulStatus ) != 0 ) 
		{
			printf("HAS - DN_DISABLEABLE()[%x]/n", DN_DISABLEABLE & ulStatus);
		} 
		else 
		{
			continue;
		}
		if ((DN_REMOVABLE & ulStatus ) != 0 )
		{
			printf("HAS - DN_REMOVABLE()[%x]/n", DN_REMOVABLE & ulStatus);
		} 
		else 
		{
			continue;
		}

		len = MAX_PATH;
		// pnpvietotype = PNP_VetoDevice;
		cr = CM_Request_Device_Eject(DeviceInfoData.DevInst,
									&pnpvietotype,
									vetoname,
									len,
									0
									);
		if ( CR_SUCCESS == cr ) 
		{
			printf("OK - CM_Request_Device_Eject()[%d]/n", cr);
		} 
		else
		{
			printf("ERROR - CM_Request_Device_Eject()[%d]/n", cr);
			printf("ERROR - CM_Request_Device_Eject()[%d]/n", GetLastError());
		}

	}


	if ( GetLastError()!=NO_ERROR &&
		GetLastError()!=ERROR_NO_MORE_ITEMS )
	{
		// Insert error handling here.
		return 1;
	}

	// Cleanup
	SetupDiDestroyDeviceInfoList(hDevInfo);

	return 0;
}

 

编译通不过,提示以下出错

1>正在链接...
1>main.obj : error LNK2001: 无法解析的外部符号 _GUID_DEVINTERFACE_USB_DEVICE
1>C:\Documents and Settings\Administrator\桌面\test\Debug\test.exe : fatal error LNK1120: 1 个无法解析的外部命令

 

出错原因:变量GUID_DEVINTERFACE_USB_DEVICE无法被识别到。

 

第二版:

偿试方法

上面报错的GUID_DEVINTERFACE_USB_DEVICE变量的定义其实在DDK就有定义了,在usbiodef.h文件中,它也是与我们代码中的定义是一样的:

/* A5DCBF10-6530-11D2-901F-00C04FB951ED */
DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, \
             0xC0, 0x4F, 0xB9, 0x51, 0xED);

然后我们去查看DEFINE_GUID的定义:

#ifdef INITGUID
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
        EXTERN_C const GUID DECLSPEC_SELECTANY name \
                = { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }
#else
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
    EXTERN_C const GUID FAR name
#endif // INITGUID

会不会是没定义INITGUID呢?于是我在代码中加

#define INITGUID

也是一样报错。

正确解决方法

将定义

// /* A5DCBF10-6530-11D2-901F-00C04FB951ED */
DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, \
			0xC0, 0x4F, 0xB9, 0x51, 0xED);

修改为:

EXTERN_C const GUID DECLSPEC_SELECTANY GUID_DEVINTERFACE_USB_DEVICE \
= { 0xA5DCBF10L, 0x6530, 0x11D2, { 0x90, 0x1F,  0x00,  0xC0,  0x4F,  0xB9,  0x51,  0xED } };

哈哈,编译通过了 ^-^^^^^^^=======

 

 

二、测试效果

我的电脑上接着U盘与USB鼠标;编译后的可执行文件就一个(不需要加入其他dll)。运行程序后U盘成功退出。哈哈有效果了。

从下图可以看出找到了两个USB设备,且调用CM_Request_Device_Eject都成功了。

 三、API说明

如果此设备是可移除的CM_Request_Device_Eject 函数为安全的先移除准备一个本地的设备实现,如果设备能物理移除,那么它将会物理移除

 

CMAPI
CONFIGRET
WINAPI CM_Request_Device_Eject(
  _In_       DEVINST dnDevInst,
  _Out_opt_  PPNP_VETO_TYPE pVetoType,
  _Out_opt_  LPTSTR pszVetoName,
  _In_       ULONG ulNameLength,
  _In_       ULONG ulFlags
);

 

Parameters

dnDevInst [in]

绑定到机器上的调用者支持的设备实现句柄.

pVetoType [out, optional]

(Optional.) If not NULL, this points to a location that, 如果可移除的请求失败,那么它接收一个PNP_VETO_TYPE类型的值,此值表明失败的原因。

pszVetoName [out, optional]

(Optional.) If not NULL, this is a caller-supplied pointer to a string buffer that receives a text string. The type of information this string provides is dependent on the value received by
pVetoType. For information about these strings, see
PNP_VETO_TYPE
.

ulNameLength [in]

(Optional.) Caller-supplied value representing the length of the string buffer supplied by
pszVetoName. This should be set to MAX_PATH.

ulFlags [in]

Not used.

Return value

If the operation succeeds, the function returns CR_SUCCESS. Otherwise, it returns one of the CR_-prefixed error codes defined in
Cfgmgr32.h.

Remarks

If pszVetoName is NULL, the PnP manager displays a message to the user indicating the device was removed or, if the request failed, identifying the reason for the failure. If
pszVetoName is not NULL, the PnP manager does not display a message. (Note, however, that for Microsoft Windows 2000 only, the PnP manager displays a message even if
pszVetoName is not NULL, if the device's CM_DEVCAP_DOCKDEVICE capability is set.)

Callers of CM_Request_Device_Eject sometimes require
SeUndockPrivilege
or SeLoadDriverPrivilege, as follows:

  • If the device's CM_DEVCAP_DOCKDEVICE capability is set (the device is a "dock" device), callers must have
    SeUndockPrivilege. (SeLoadDriverPrivilege is not required.)

  • If the device's CM_DEVCAP_DOCKDEVICE capability is not set (the device is not a "dock" device),
    and if the calling process is either not interactive or is running in a multi-user environment in a session not attached to the physical console (such as a remote Terminal Services session), callers of this function must have
    SeLoadDriverPrivilege.

Privileges are described in the Microsoft Windows SDK documentation.

For information about using device instance handles that are bound to the local machine, see
CM_Get_Child.

Requirements

Version

Available in Microsoft Windows 2000 and later versions of Windows.

Header

Cfgmgr32.h (include Cfgmgr32.h)

Library

Contained in Cfgmgr32.lib. Link to Cfgmgr32.lib.

抱歉!评论已关闭.