原文地址:http://blog.csdn.net/cenewman/article/details/6822173 今天遇到一个比较特殊的客户要求,需要应用程序可以控制USB从设备,只有在应用程序使能之后,用户才能连接到电脑,说是怕用户随意拷贝或者破坏设备里存储的资料,当然界面是封装的,可不能避免用户通过连接电脑进行拷贝等操作。目前设备连接电脑有两种方式,同步方式(Active Sync)和U盘模式(Mass Storage)。当初想着从USB设备是通过ENT2外部中断来获取连接线状态,到时把这个中断消息在系统中广播,应用程序接收后可通过事件的方式来控制连接与否,从而达到控制的目标,于是答应了客户说可以做到。可到了要修改时才发现,这个外部中断的作用只是用来切断USB连接,即使是把这个中断的电路去掉,插入USB照样连接到电脑,只是拨掉USB线后电脑已经检测到断开连接,设备因为无法检测,依然的连接中而已。最终才发现这个USB连接中断是通过硬件检测数据线(D+、D-)的电平来实现,哎~。真的没有办法实现了吗?突然灵光一闪,把客户驱动切换到RNDIS模式,而这个模式我们设备中并没有加载这个驱动,设备就不能连接到电脑了。于是写了一个应用程序尝试控制,可以得到想要的效果,于是记录于下: //evc code: //#include "usbfnioctl.h"
//#include #include "winioctl.h"
#define _UFN_ACCESS_CTL_CODE(_Function) \
CTL_CODE(FILE_DEVICE_UNKNOWN, _Function, METHOD_BUFFERED, FILE_ANY_ACCESS) #define UFN_CLIENT_NAME_MAX_CHARS 128
#define UFN_CLIENT_DESCRIPTION_MAX_CHARS 250 typedef struct _UFN_CLIENT_INFO {
TCHAR szName[UFN_CLIENT_NAME_MAX_CHARS];
TCHAR szDescription[UFN_CLIENT_DESCRIPTION_MAX_CHARS];
} UFN_CLIENT_INFO, *PUFN_CLIENT_INFO; typedef struct _UFN_CLIENT_NAME {
TCHAR szName[UFN_CLIENT_NAME_MAX_CHARS];
} UFN_CLIENT_NAME, *PUFN_CLIENT_NAME;
#define SVSUTIL_GUID_FORMAT_W L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"
#define SVSUTIL_GUID_FORMAT SVSUTIL_GUID_FORMAT_W
#define SVSUTIL_PGUID_ELEMENTS(p) \
p->Data1, p->Data2, p->Data3,\
p->Data4[0], p->Data4[1], p->Data4[2], p->Data4[3],\
p->Data4[4], p->Data4[5], p->Data4[6], p->Data4[7] #define IOCTL_UFN_CHANGE_CURRENT_CLIENT _UFN_ACCESS_CTL_CODE(4)
#define USB_RNDIS 0 //Note that X11 don't support this client mode
#define USB_Serial 1
#define USB_MSF 2
UINT GetClientMode()
{
UINT ret = USB_MSF; // USB_MSF is default class
DWORD dwType = REG_SZ;
HKEY hkDevice = NULL;
HKEY hKey = NULL;
DWORD dwTmp;
WCHAR Data[20];
DWORD cbData;
cbData = sizeof( Data );
dwTmp = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("Drivers\\USB\\FunctionDrivers"), 0, 0, &hKey ); if( dwTmp == ERROR_SUCCESS )
{
dwTmp = RegQueryValueEx( hKey, TEXT("DefaultClientDriver"), NULL, &dwType, (LPBYTE)Data, &cbData );
if( dwTmp == ERROR_SUCCESS && dwType == REG_SZ )
{
if( wcscmp(Data, TEXT("RNDIS")) == 0 )
{
//USB RNDIS Function Class Enabled
ret = USB_RNDIS;
}
else if( wcscmp(Data, TEXT("Serial_Class")) == 0 )
{
//USB Serial Function Class Enabled
ret = USB_Serial;
}
else if( wcscmp(Data, TEXT("Mass_Storage_Class")) == 0 )
{
//USB MSF Function Class Enabled
ret = USB_MSF;
}
} RegCloseKey( hKey );
}
return ret;
}
BOOL SetClientMode(UINT mode)
{
BOOL dwRet = TRUE;
UFN_CLIENT_NAME uClientName;
int iErr;
HANDLE hUfn = NULL;
HANDLE hf;
BYTE bGuidBuffer[sizeof(GUID) + 4];
LPGUID pGuidBus;
LPCTSTR pszBusGuid = _T("E2BDC372-598F-4619-BC50-54B3F7848D35");
DEVMGR_DEVICE_INFORMATION devInfo; LPCTSTR szNewDriverName = NULL;
static const TCHAR c_szRndisFnName[] = TEXT("RNDIS");
static const TCHAR c_szUsbSerialFnName[] = TEXT("Serial_Class");
static const TCHAR c_szMassStorageFnName[] = TEXT("Mass_Storage_Class"); HKEY hKey;
DWORD dwSize, dwValue;
TCHAR strValue[MAX_PATH] = {0}; // save to registry
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Drivers\\USB\\FunctionDrivers"), 0, 0, &hKey))
{
switch(mode)
{
case USB_RNDIS:
dwSize = (wcslen( c_szRndisFnName)+1)*sizeof(WCHAR);
RegSetValueEx(hKey, TEXT("DefaultClientDriver"), NULL, REG_SZ, (BYTE *)c_szRndisFnName, dwSize);
szNewDriverName = c_szRndisFnName;
RegCloseKey(hKey); // to avoid the system error "Comunicatoin Error", disable the flowing setting:
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("ControlPanel\\Comm"), 0, 0, &hKey))
{
dwSize = sizeof(DWORD);
dwValue = 0;
RegSetValueEx(hKey, TEXT("AutoCnct"), 0, REG_DWORD, (LPBYTE)&dwValue, dwSize);
RegCloseKey(hKey);
}
break;
case USB_Serial:
dwSize = (wcslen( c_szUsbSerialFnName)+1)*sizeof(WCHAR);
RegSetValueEx(hKey, TEXT("DefaultClientDriver"), NULL, REG_SZ, (BYTE *)c_szUsbSerialFnName, dwSize);
szNewDriverName = c_szUsbSerialFnName;
RegCloseKey(hKey); // to avoid the system error "Comunicatoin Error", disable the flowing setting, and now reset it
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("ControlPanel\\Comm"), 0, 0, &hKey))
{
dwSize = sizeof(DWORD);
dwValue = 1;
RegSetValueEx(hKey, TEXT("AutoCnct"), 0, REG_DWORD, (LPBYTE)&dwValue, dwSize);
RegCloseKey(hKey);
}
break;
case USB_MSF:
dwSize = (wcslen( c_szMassStorageFnName)+1)*sizeof(WCHAR);
RegSetValueEx(hKey, TEXT("DefaultClientDriver"), NULL, REG_SZ, (BYTE *)c_szMassStorageFnName, dwSize);
szNewDriverName = c_szMassStorageFnName;
RegCloseKey(hKey); // to avoid the system error "Comunicatoin Error", disable the flowing setting:
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("ControlPanel\\Comm"), 0, 0, &hKey))
{
dwSize = sizeof(DWORD);
dwValue = 0;
RegSetValueEx(hKey, TEXT("AutoCnct"), 0, REG_DWORD, (LPBYTE)&dwValue, dwSize);
RegCloseKey(hKey);
}
break;
}
}
// Change mode
// Parse the GUID
pGuidBus = (LPGUID)bGuidBuffer;
iErr = _stscanf(pszBusGuid, SVSUTIL_GUID_FORMAT, SVSUTIL_PGUID_ELEMENTS(&pGuidBus));
if (iErr == 0 || iErr == EOF)
{
return FALSE;
} // Get a handle to the bus driver
memset(&devInfo, 0, sizeof(devInfo));
devInfo.dwSize = sizeof(devInfo);
hf = FindFirstDevice(DeviceSearchByGuid, pGuidBus, &devInfo);
if (hf != INVALID_HANDLE_VALUE)
{
hUfn = CreateFile(devInfo.szBusName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if( hUfn != INVALID_HANDLE_VALUE)
{
_tcscpy(uClientName.szName, szNewDriverName);
dwRet = DeviceIoControl(hUfn, IOCTL_UFN_CHANGE_CURRENT_CLIENT, &uClientName, sizeof(uClientName), NULL, 0, NULL, NULL);
CloseHandle(hUfn);
}
CloseHandle(hf);
} return dwRet;
}
BOOL CClientModeDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
CenterWindow(GetDesktopWindow()); // center to the hpc screen // TODO: Add extra initialization here
m_nClient = (int)GetClientMode();//m_nClient 是一个COMBO_BOX变量
m_strStatus = TEXT("Ready.");
UpdateData(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
}
void CClientModeDlg::OnButtonSwitch()
{
// TODO: Add your control notification handler code here
UpdateData();
SetClientMode(m_nClient);
switch(m_nClient)
{
case USB_RNDIS:
m_strStatus.Format(TEXT("Client Mode: RNDIS"));
break;
case USB_Serial:
m_strStatus.Format(TEXT("Client Mode: Serial"));
break;
case USB_MSF:
m_strStatus.Format(TEXT("Client Mode: Mass Storage"));
break;
}
UpdateData(FALSE);
}
|