转自:http://blog.csdn.net/flyyyri/article/details/5480347

理论:
    对于USB接口的设备,现在越来越多了。本篇我们就通过获取一个USB扫描仪设备中的序列号,来介绍如何获取usb设备的一些硬件信息。对于usb设备都是采用HCD0,HCD1,HCD2,HCD3等符号描述的。如下图:

因此,有了这个名字,我们就可以使用CreateFile来打开usb设备。然后使用DeviceIoControl函数与usb设备通讯了。HCD是host controller driver的简写。需要了解详情的,还要仔细的阅读usb协议。
usb的通讯基本步骤如下图所示:

基本步骤:
    1)打开HCD%X
    2) 得到上面的USB root hub
    3) 遍历usb root hub上连接的usb 设备。获取信息
    4)如果有多个usb口,循环前3步。

下面介绍通讯用的几个IOCTL:
1)USB_HCD_DRIVERKEY_NAME ,用于获取USB设备驱动在注册表中的键名。相应的一个结构体是:
typedef struct _USB_HCD_DRIVERKEY_NAME 
{
   ULONG   ActualLength;
   WCHAR   DriverKeyName[1];
} USB_HCD_DRIVERKEY_NAME, *PUSB_HCD_DRIVERKEY_NAME;

2)IOCTL_USB_GET_ROOT_HUB_NAME,用于获取root hub 键名。使用的结构体,跟上面一样。
typedef struct _USB_ROOT_HUB_NAME 
{
    ULONG ActualLength; 
    WCHAR RootHubName[1]; 
} USB_ROOT_HUB_NAME, *PUSB_ROOT_HUB_NAME;

3)IOCTL_USB_GET_NODE_INFORMATION,用于获取连接在root hub上的节点设备信息。也就是我们接在usb口上的所有usb设备的信息,对应的结构体:
typedef struct _USB_NODE_INFORMATION 
{
    USB_HUB_NODE NodeType;    
    union {
        USB_HUB_INFORMATION HubInformation;
        USB_MI_PARENT_INFORMATION MiParentInformation;
    } u;
} USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION;

typedef struct _USB_MI_PARENT_INFORMATION 
{
    ULONG NumberOfInterfaces;
} USB_MI_PARENT_INFORMATION, *PUSB_MI_PARENT_INFORMATION;

typedef struct _USB_HUB_INFORMATION
{
    USB_HUB_DESCRIPTOR HubDescriptor;

BOOLEAN HubIsBusPowered;

} USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION;

typedef struct _USB_HUB_DESCRIPTOR
{
    UCHAR        bDescriptorLength;      // Length of this descriptor
    UCHAR        bDescriptorType;        // Hub configuration type
    UCHAR        bNumberOfPorts;         // number of ports on this hub
    USHORT       wHubCharacteristics;    // Hub Charateristics
    UCHAR        bPowerOnToPowerGood;    // port power on till power good in 2ms
    UCHAR        bHubControlCurrent;     // max current in mA
    //
    // room for 255 ports power control and removable bitmask
    UCHAR        bRemoveAndPowerMask[64];       
} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR;

4) IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, 用于获取接在usb口上的单个usb设备的信息,对应的结构体:

typedef struct _USB_NODE_CONNECTION_INFORMATION 
{
    ULONG ConnectionIndex;
    USB_DEVICE_DESCRIPTOR DeviceDescriptor;
    UCHAR CurrentConfigurationValue;
    BOOLEAN LowSpeed;

BOOLEAN DeviceIsHub;

USHORT DeviceAddress;

ULONG NumberOfOpenPipes;

USB_CONNECTION_STATUS ConnectionStatus;
    USB_PIPE_INFO PipeList[0];
} USB_NODE_CONNECTION_INFORMATION, *PUSB_NODE_CONNECTION_INFORMATION;

4)IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, 用于获取usb设备的描述信息。
typedef struct _USB_DEVICE_DESCRIPTOR 
{
    UCHAR bLength;
    UCHAR bDescriptorType;
    USHORT bcdUSB;
    UCHAR bDeviceClass;
    UCHAR bDeviceSubClass;
    UCHAR bDeviceProtocol;
    UCHAR bMaxPacketSize0;
    USHORT idVendor;
    USHORT idProduct;
    USHORT bcdDevice;
    UCHAR iManufacturer;
    UCHAR iProduct;
    UCHAR iSerialNumber;
    UCHAR bNumConfigurations;
} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;

typedef struct _USB_DEVICE_DESCRIPTOR 
{
    UCHAR bLength;
    UCHAR bDescriptorType;
    USHORT bcdUSB;
    UCHAR bDeviceClass;
    UCHAR bDeviceSubClass;
    UCHAR bDeviceProtocol;
    UCHAR bMaxPacketSize0;
    USHORT idVendor;
    USHORT idProduct;
    USHORT bcdDevice;
    UCHAR iManufacturer;
    UCHAR iProduct;
    UCHAR iSerialNumber;
    UCHAR bNumConfigurations;
} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;

typedef enum _USB_CONNECTION_STATUS 
{
    NoDeviceConnected,
    DeviceConnected,

/* failure codes, these map to fail reasons */
    DeviceFailedEnumeration,
    DeviceGeneralFailure,
    DeviceCausedOvercurrent,
    DeviceNotEnoughPower,
    DeviceNotEnoughBandwidth,
    DeviceHubNestedTooDeeply,
    DeviceInLegacyHub
} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS;

typedef struct _USB_PIPE_INFO
{
    USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
    ULONG ScheduleOffset;
} USB_PIPE_INFO, *PUSB_PIPE_INFO;

typedef struct _USB_ENDPOINT_DESCRIPTOR
{
    UCHAR bLength;
    UCHAR bDescriptorType;
    UCHAR bEndpointAddress;
    UCHAR bmAttributes;
    USHORT wMaxPacketSize;
    UCHAR bInterval;
} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR;

需要注意一点,如果要得到pid,vid,则直接从USB_DEVICE_DESCRIPTOR结构中取出idVendor,idProduct这两项的值就行了。如果要得到序列号,则不是取出 iSerialNumber就可以的。这里的 iSerialNumber仅仅是一个索引值。如果想得到序列号,就需要定义一个结构,然后给设备发送个请求。请求的结构如下图:

代码参照GetStringDescriptor函数。可以根据iSerialNumber偏移,取出其对应的字符串,存放在上图USB_STRING_DESCRIPTOR结构中。
#include "windows.h"
#include "PlkUsbIo.h"
#include <malloc.h>

#define NUM_HCS_TO_CHECK 10

/******************************************************************/
bool EnumUsbDevice();
PCHAR GetDriverKeyName(HANDLE Hub, ULONG ConnectionIndex);
PCHAR GetHCDDriverKeyName(HANDLE HCD);
PCHAR GetRootHubName(HANDLE HostController);
PCHAR WideStrToMultiStr(PWCHAR WideStr);
bool GetStringDescriptor (
        HANDLE hHubDevice,
        ULONG   ConnectionIndex,
        UCHAR   DescriptorIndex    ,
        CHAR * outBuff);
    
/******************************************************************/

int main(int argc, char* argv[])
{
    EnumUsbDevice();
    return 0;
}

bool EnumUsbDevice()
{
    char        HCName[16];
    int         HCNum;
    HANDLE      hHCDev;
    PCHAR       rootHubName;

ULONG       index;
    BOOL        success;

PUSB_NODE_CONNECTION_INFORMATION    connectionInfo;
    HANDLE hHubDevice;

for (HCNum = 0; HCNum < NUM_HCS_TO_CHECK; HCNum++)
    {
        wsprintf(HCName, "////.//HCD%d", HCNum);
        hHCDev = CreateFile(HCName,
            GENERIC_WRITE,
            FILE_SHARE_WRITE,
            NULL,
            OPEN_EXISTING,
            0,
            NULL);
        if (hHCDev == INVALID_HANDLE_VALUE)    
            break;
        
        PCHAR driverKeyName, deviceDesc;
        driverKeyName = GetHCDDriverKeyName(hHCDev);
        if(driverKeyName == NULL)
            goto end;    
        
    
        ULONG nBytes;
        rootHubName =(char*) GetRootHubName(hHCDev);
        if(rootHubName==NULL)
            goto end;
    
        PUSB_NODE_INFORMATION HubInfo;
        HubInfo = (PUSB_NODE_INFORMATION)malloc(sizeof(USB_NODE_INFORMATION));
        PCHAR deviceName;
        deviceName = (PCHAR)malloc(strlen(rootHubName) + sizeof("////.//"));
        if (rootHubName != NULL)
        {
            strcpy(deviceName, "////.//");
            strcpy(deviceName + sizeof("////.//") - 1, rootHubName);
            hHubDevice = CreateFile(deviceName,
                GENERIC_WRITE,
                FILE_SHARE_WRITE,
                NULL,
                OPEN_EXISTING,
                0,
                NULL);
            free(deviceName);
            if (hHubDevice == INVALID_HANDLE_VALUE)
                goto end;
            
            success = DeviceIoControl(hHubDevice,
                IOCTL_USB_GET_NODE_INFORMATION,
                HubInfo,
                sizeof(USB_NODE_INFORMATION),
                HubInfo,
                sizeof(USB_NODE_INFORMATION),
                &nBytes,
                NULL);
            if (!success)
                goto end;

}

int port;
        port=HubInfo->u.HubInformation.HubDescriptor.bNumberOfPorts;
        for (index=1; index <= port; index++)
        {
            ULONG nBytes;
            nBytes = sizeof(USB_NODE_CONNECTION_INFORMATION) +
                sizeof(USB_PIPE_INFO) * 30;
            connectionInfo = (PUSB_NODE_CONNECTION_INFORMATION)malloc(nBytes);
            if (connectionInfo == NULL)
                goto end;
            
            connectionInfo->ConnectionIndex = index;
            success = DeviceIoControl(hHubDevice,
                IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,
                connectionInfo,
                nBytes,
                connectionInfo,
                nBytes,
                &nBytes,
                NULL);
            if (!success)
            {
                free(connectionInfo);
                goto end;
            }

deviceDesc = NULL;
            if (connectionInfo->ConnectionStatus != NoDeviceConnected)
            {
                driverKeyName = GetDriverKeyName(hHubDevice,
                    index);
                if (driverKeyName)
                {
                    free(driverKeyName);
                }
            }

if (connectionInfo->ConnectionStatus == DeviceConnected)
            {
                //取出序列号索引
                UCHAR nSerialno = connectionInfo->DeviceDescriptor.iSerialNumber;
                CHAR OutBuff[20] = {0};
                GetStringDescriptor(hHubDevice,connectionInfo->ConnectionIndex,nSerialno,OutBuff);

//判断序列号是否有效
                if(序列号是否有效)
                {
                      CloseHandle(hHubDevice);
                      CloseHandle(hHCDev);
                     return true;
                }
            }

}
end:; 
    }

CloseHandle(hHubDevice);
    CloseHandle(hHCDev);
    return false;
}

PCHAR GetDriverKeyName(HANDLE Hub, ULONG ConnectionIndex)
{
    BOOL                                success;
    ULONG                               nBytes;
    USB_NODE_CONNECTION_DRIVERKEY_NAME driverKeyName;
    PUSB_NODE_CONNECTION_DRIVERKEY_NAME driverKeyNameW;
    PCHAR                               driverKeyNameA;

driverKeyNameW = NULL;
    driverKeyNameA = NULL;

driverKeyName.ConnectionIndex = ConnectionIndex;

success = DeviceIoControl(Hub,
        IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME,
        &driverKeyName,
        sizeof(driverKeyName),
        &driverKeyName,
        sizeof(driverKeyName),
        &nBytes,
        NULL);

if (!success)
    {
        goto GetDriverKeyNameError;
    }

nBytes = driverKeyName.ActualLength;

if (nBytes <= sizeof(driverKeyName))
    {
        goto GetDriverKeyNameError;
    }

driverKeyNameW = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)malloc(nBytes);

if (driverKeyNameW == NULL)
    {
        goto GetDriverKeyNameError;
    }

driverKeyNameW->ConnectionIndex = ConnectionIndex;

success = DeviceIoControl(Hub,
        IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME,
        driverKeyNameW,
        nBytes,
        driverKeyNameW,
        nBytes,
        &nBytes,
        NULL);

if (!success)
    {
        goto GetDriverKeyNameError;
    }
    driverKeyNameA = WideStrToMultiStr(driverKeyNameW->DriverKeyName);
    free(driverKeyNameW);

return driverKeyNameA;

GetDriverKeyNameError:
    if (driverKeyNameW != NULL)
    {
        free(driverKeyNameW);
        driverKeyNameW = NULL;
    }

return NULL;
}
PCHAR GetRootHubName(HANDLE HostController)
{
    BOOL                success;
    ULONG               nBytes;
    USB_ROOT_HUB_NAME   rootHubName;
    PUSB_ROOT_HUB_NAME rootHubNameW;
    PCHAR               rootHubNameA;

rootHubNameW = NULL;
    rootHubNameA = NULL;

success = DeviceIoControl(HostController,
        IOCTL_USB_GET_ROOT_HUB_NAME,
        0,
        0,
        &rootHubName,
        sizeof(rootHubName),
        &nBytes,
        NULL);

if (!success)
    {
        goto GetRootHubNameError;
    }

nBytes = rootHubName.ActualLength;

rootHubNameW =(PUSB_ROOT_HUB_NAME) malloc(nBytes);

if (rootHubNameW == NULL)
    {

goto GetRootHubNameError;
    }

success = DeviceIoControl(HostController,
        IOCTL_USB_GET_ROOT_HUB_NAME,
        NULL,
        0,
        rootHubNameW,
        nBytes,
        &nBytes,
        NULL);

if (!success)
    {
        goto GetRootHubNameError;
    }

rootHubNameA = WideStrToMultiStr(rootHubNameW->RootHubName);
    free(rootHubNameW);

return rootHubNameA;

GetRootHubNameError:
    if (rootHubNameW != NULL)
    {
        free(rootHubNameW);
        rootHubNameW = NULL;
    }

return NULL;
}
PCHAR GetHCDDriverKeyName(HANDLE HCD)
{
    BOOL                    success;
    ULONG                   nBytes;
    USB_HCD_DRIVERKEY_NAME driverKeyName;
    PUSB_HCD_DRIVERKEY_NAME driverKeyNameW;
    PCHAR                   driverKeyNameA;

driverKeyNameW = NULL;
    driverKeyNameA = NULL;

success = DeviceIoControl(HCD,
        IOCTL_GET_HCD_DRIVERKEY_NAME,
        &driverKeyName,
        sizeof(driverKeyName),
        &driverKeyName,
        sizeof(driverKeyName),
        &nBytes,
        NULL);

if (!success)
    {
        goto GetHCDDriverKeyNameError;
    }

nBytes = driverKeyName.ActualLength;

if (nBytes <= sizeof(driverKeyName))
    {
        goto GetHCDDriverKeyNameError;
    }

driverKeyNameW =(PUSB_HCD_DRIVERKEY_NAME) malloc(nBytes);

if (driverKeyNameW == NULL)
    {
        goto GetHCDDriverKeyNameError;
    }

success = DeviceIoControl(HCD,
        IOCTL_GET_HCD_DRIVERKEY_NAME,
        driverKeyNameW,
        nBytes,
        driverKeyNameW,
        nBytes,
        &nBytes,
        NULL);

if (!success)
    {
        goto GetHCDDriverKeyNameError;
    }

driverKeyNameA = WideStrToMultiStr(driverKeyNameW->DriverKeyName);
    free(driverKeyNameW);

return driverKeyNameA;

GetHCDDriverKeyNameError:
    if (driverKeyNameW != NULL)
    {
        free(driverKeyNameW);
        driverKeyNameW = NULL;
    }

return NULL;
}

PCHAR WideStrToMultiStr(PWCHAR WideStr)
{
    ULONG nBytes;
    PCHAR MultiStr;
    nBytes = WideCharToMultiByte(
        CP_ACP,
        0,
        WideStr,
        -1,
        NULL,
        0,
        NULL,
        NULL);

if (nBytes == 0)
    {
        return NULL;
    }
    MultiStr =(PCHAR) malloc(nBytes);

if (MultiStr == NULL)
    {
        return NULL;
    }
    nBytes = WideCharToMultiByte(
        CP_ACP,
        0,
        WideStr,
        -1,
        MultiStr,
        nBytes,
        NULL,
        NULL);

if (nBytes == 0)
    {
        free(MultiStr);
        return NULL;
    }

return MultiStr;
}

bool    GetStringDescriptor (
        HANDLE hHubDevice,
        ULONG   ConnectionIndex,
        UCHAR   DescriptorIndex    ,
        CHAR * outBuff
        )
    {
        BOOL    success;
        ULONG   nBytes;
        ULONG   nBytesReturned;

UCHAR   stringDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST) + MAXIMUM_USB_STRING_LENGTH];

PUSB_DESCRIPTOR_REQUEST stringDescReq;
        PUSB_STRING_DESCRIPTOR stringDesc;

nBytes = sizeof(stringDescReqBuf);

stringDescReq = (PUSB_DESCRIPTOR_REQUEST)stringDescReqBuf;
        stringDesc = (PUSB_STRING_DESCRIPTOR)(stringDescReq+1);

::ZeroMemory(stringDescReq,nBytes);
        stringDescReq->ConnectionIndex = ConnectionIndex;
        stringDescReq->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) | DescriptorIndex;
        stringDescReq->SetupPacket.wIndex = GetSystemDefaultLangID();
        stringDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST));

success = DeviceIoControl(hHubDevice,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
                                stringDescReq,nBytes,
                                stringDescReq,nBytes,
                                &nBytesReturned,NULL);

if (!success || nBytesReturned < 2)
            return false;

if (stringDesc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE)
            return false;

if (stringDesc->bLength != nBytesReturned - sizeof(USB_DESCRIPTOR_REQUEST))
            return false;

if (stringDesc->bLength % 2 != 0)
            return false;

WCHAR * wChar = new WCHAR[stringDesc->bLength + 1];
        memcpy(wChar,stringDesc->bString,stringDesc->bLength);
        char *szTemp = WideStrToMultiStr(wChar);
        lstrcpy(outBuff, szTemp);
        
        if(szTemp)
        delete []szTemp;
        
        if(wChar)
        delete []wChar;
        return true;
    }

分析:

1)首先假定有10个usb接口
    #define NUM_HCS_TO_CHECK 10

2)循环打开这10个usb端口,如果端口没有这么多,调用CreateFile,就会返回 INVALID_HANDLE_VALUE。
    for (HCNum = 0; HCNum < NUM_HCS_TO_CHECK; HCNum++)
    {
        wsprintf(HCName, "////.//HCD%d", HCNum);
        hHCDev = CreateFile(HCName,
            GENERIC_WRITE,
            FILE_SHARE_WRITE,
            NULL,
            OPEN_EXISTING,
            0,
            NULL);
        if (hHCDev == INVALID_HANDLE_VALUE)    
            break;

3)获取root hub
       ULONG nBytes;
        rootHubName =(char*) GetRootHubName(hHCDev);
        if(rootHubName==NULL)
            goto end;

4) 遍历连接在root hub上的节点
        int port;
        port=HubInfo->u.HubInformation.HubDescriptor.bNumberOfPorts;
        for (index=1; index <= port; index++)
        {
            ULONG nBytes;
            nBytes = sizeof(USB_NODE_CONNECTION_INFORMATION) +
                sizeof(USB_PIPE_INFO) * 30;
            connectionInfo = (PUSB_NODE_CONNECTION_INFORMATION)malloc(nBytes);
            if (connectionInfo == NULL)
                goto end;
            
            connectionInfo->ConnectionIndex = index;
            success = DeviceIoControl(hHubDevice,
                IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,
                connectionInfo,
                nBytes,
                connectionInfo,
                nBytes,
                &nBytes,
                NULL);
            if (!success)
            {
                free(connectionInfo);
                goto end;
            }

5)根据节点的连接状态,获取节点信息,得到序列号。
    if (connectionInfo->ConnectionStatus == DeviceConnected)
            {
                //取出序列号索引
                UCHAR nSerialno = connectionInfo->DeviceDescriptor.iSerialNumber;
                CHAR OutBuff[20] = {0};
                GetStringDescriptor(hHubDevice,connectionInfo->ConnectionIndex,nSerialno,OutBuff);

6)得到序列号的方法在理论部分已经详细说明了,对应的函数是GetStringDescriptor,这里不再重复。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jtujtujtu/archive/2009/11/19/4836900.aspx

遍历 USB devcie,读取设备描述符 device descriptor【转】的更多相关文章

  1. usb协议分析-设备描述符配置包-描述符

    /* usb协议分析仅供大家参考---设备描述符配置包,设备描述符, 地址设置, 配置描述符, 字符串描述符 */ /* -1- usb设备描述符配置包 */ typedef struct _USB_ ...

  2. USB系列之二:读取USB设备的描述符

    在前面的文章中,我们已经给出了USB协议的链接地址,从这篇文章起,我们会涉及到许多USB 1.1的内容,我们的指导思想是先从熟悉USB 1.1协议入手,先使用现成的HCD和USBD,直接面对客户端驱动 ...

  3. Win10 设备管理器一个USB设备描述符请求失败解决方法

    问题:进入设备管理器,发现[通用串行总线控制器]下有一项带有黄色[!]未知USB设备(设备描述符请求失败). 或者 解决方法如下: 1.点击Windows键 +R或者(点击系统桌面左下角[开始],在开 ...

  4. Qt下libusb-win32的使用(一)打印设备描述符

    主要是在前一篇的基础上,学习libusb-win32的API使用.程序很简单,就是打印指定USB设备的设备描述符(当然其他描述符也是可以的). #include "testlibusb.h& ...

  5. usb驱动开发9之设备描述符

    前面分析了usb的四大描述符之端点描述符,接口描述符(每一个接口对应一个功能,与之配备相应驱动),配置描述符,最后分析设备如何包括这些描述符.首先记住,在usb的世界里,设备大于配置,配置大于接口,接 ...

  6. USB设备描述符

    /* USB Standard Device Descriptor */ const u8 Virtual_Com_Port_DeviceDescriptor[] = { 0x12, /* bLeng ...

  7. STM32 USB设备描述符、配置描述符、端点描述符含义

    查了一整天的资料,自己把不懂的全部试了一遍 一下是程序以及注释 /* USB设备描述符*/ const uint8_t CustomHID_DeviceDescriptor[CUSTOMHID_SIZ ...

  8. qq2440启动linux后插入u盘出现usb 1-1: device descriptor read/64, error -110,usb 1-1: device not accepting address 8, error -110

    上位机:ubuntu14.04 64bit 下位机:qq2440 交叉编译器:arm-linux-gcc 3.4.1 下位机使用的linux内核版本:kernel2.6.13 1.插入u盘时错误信息如 ...

  9. USB设备描述符和请求命令

    USB设备描述符和请求命令 介绍标准的USB设备描述符和请求命令. 标准的USB描述符 当USB设备第一次连接到主机上时,要接收主机的枚举和配置,目的就是让主机知道该设备具有什么功能.是哪一类的USB ...

随机推荐

  1. DAY3-Flask项目

    1.jsonify: 得到了从API获得的数据并返回,API返回的json数据被转化成dict,我们还需要把dict序列化: return json.dump(result), 200, {'cont ...

  2. springboot整合spring @Cache和Redis

    转载请注明出处:https://www.cnblogs.com/wenjunwei/p/10779450.html spring基于注解的缓存 对于缓存声明,spring的缓存提供了一组java注解: ...

  3. Longest Word in Dictionary through Deleting - LeetCode

    目录 题目链接 注意点 解法 小结 题目链接 Longest Word in Dictionary through Deleting - LeetCode 注意点 长度一样的字符串要按字典序返回较小的 ...

  4. 【Learning】矩阵树定理 Matrix-Tree

    矩阵树定理 Matrix Tree ​ 矩阵树定理主要用于图的生成树计数. 看到给出图求生成树的这类问题就大概要往这方面想了. 算法会根据图构造出一个特殊的基尔霍夫矩阵\(A\),接着根据矩阵树定理, ...

  5. 【bzoj2594】 Wc2006—水管局长数据加强版

    http://www.lydsy.com/JudgeOnline/problem.php?id=2594 (题目链接) 题意 给出一个带边权的无向简单,要求维护两个操作,删除${u,v}$之间的连边: ...

  6. 【codeforces 553E】 Kyoya and Train

    http://codeforces.com/problemset/problem/553/E (题目链接) 艹尼玛,CF还卡劳资常数w(゚Д゚)w!!系统complex被卡TLE了T_T,劳资写了一天 ...

  7. Web Service(上)

    1.XML CDATA指不应由XML解析器进行解析的文本数据. 在XML元素中,<和&是非法的.解析器会把字符<解释为新元素的开始,把字符&解释为字符实体的开始. 某些文本 ...

  8. Java的容器类

    程序总是根据运行时才知道的某些条件去创建新对象.需要在任意时刻和任意位置创建任意数量的对象. 如果你想保存一组基本数据类型数据,建议使用数组,但是数组有固定的尺寸. 一般情况下,你在写程序时并不知道将 ...

  9. APK反编译之二:工具介绍

    前面一节我们说过,修改APK最终是通过修改smali来实现的,所以我们接下来介绍的工具就是如何把APK中的smali文件获取出来,当然同时也需要得到AndroidManifest.xml等文件.直接修 ...

  10. Hadoop生态圈-phoenix的视图(view)管理

    Hadoop生态圈-phoenix的视图(view)管理 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.