Q 用IOCTL_DISK_GET_DRIVE_GEOMETRY IOCTL_STORAGE_GET_MEDIA_TYPES_EX只能得到很少的磁盘参数,我想获得包括硬盘序列号在内的更加详细的信息,有什么办法呀?

A 确实,用你所说的I/O控 制码,只能得到最基本的磁盘参数。获取磁盘出厂信息的I/O控制码,微软在VC/MFC环境中没有开放,在DDK中可以发现一些线索。早先,Lynn McGuire写了一个很出名的获取IDE硬盘详细信息的程序DiskID32 ,下面的例子是在其基础上经过增删和改进而成的。
本例中,我们要用到ATA/APAPI的IDENTIFY DEVICE指令。ATA/APAPI是国际组织T13起草和发布的IDE/EIDE/UDMA硬盘及其它可移动存储设备与主机接 口的标准,至今已经到了ATA/APAPI-7版本。该接口标准规定了ATA/ATAPI 设备的输入输出寄存器和指令 集。欲了解更详细的ATA/ATAPI技术资料,可访问T13的站点。
 
用到的常量及数据结构有以下一些 :
// IOCTL控制码
// #define DFP_SEND_DRIVE_COMMAND  0x0007c084
#define  DFP_SEND_DRIVE_COMMAND  CTL_CODE(IOCTL_DISK_BASE, 0x0021,
METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
// #define DFP_RECEIVE_DRIVE_DATA  0x0007c088
#define  DFP_RECEIVE_DRIVE_DATA  CTL_CODE (IOCTL_DISK_BASE, 0x0022,
METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define  FILE_DEVICE_SCSI     0x0000001b
#define  IOCTL_SCSI_MINIPORT_IDENTIFY    ((FILE_DEVICE_SCSI << 16) + 0x0501)
#define  IOCTL_SCSI_MINIPORT 0x0004D008 //  see NTDDSCSI.H for definition
// ATA/ATAPI指令
#define  IDE_ATA_IDENTIFY   0xEC  //  ATA的ID指令(IDENTIFY DEVICE)
 
// IDE命令 寄存器
typedef struct _IDEREGS
{
  BYTE bFeaturesReg;    // 特征寄存器 (用于SMART 命令)   BYTE bSectorCountReg;   // 扇区数目寄存器
  BYTE bSectorNumberReg;  // 开始扇区寄存器
  BYTE bCylLowReg;     // 开始柱面低字节 寄存器
  BYTE bCylHighReg;     // 开始柱面高字节寄存器
  BYTE bDriveHeadReg;    // 驱动器/磁头寄存器
  BYTE bCommandReg;     // 指令寄存器 
  BYTE bReserved;      // 保留
} IDEREGS, *PIDEREGS, *LPIDEREGS;
// 从驱动程序返回的状态
typedef struct _DRIVERSTATUS
{
  BYTE  bDriverError;     // 错误码
  BYTE  bIDEStatus;     // IDE状态寄存器
  BYTE  bReserved[2];    // 保留
  DWORD  dwReserved[2];   // 保留
} DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS;
// IDE设备IOCTL输入数据结构
typedef struct _SENDCMDINPARAMS
{
  DWORD   cBufferSize;  // 缓冲区字节 数
  IDEREGS  irDriveRegs;  // IDE寄存器组
  BYTE bDriveNumber;    // 驱动器号
  BYTE bReserved[3];    // 保留
  DWORD   dwReserved[4]; // 保留
  BYTE    bBuffer[1];   // 输入缓冲区(此处象征性地包含1字节)
} SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS;
// IDE设备IOCTL输出数据结构
typedef struct _SENDCMDOUTPARAMS
{
  DWORD     cBufferSize;  // 缓冲区 字节数
  DRIVERSTATUS  DriverStatus;  // 驱动程序返回状态
  BYTE      bBuffer[1];   // 输入缓冲区(此处象征性地包含1字节)
} SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS;
// IDE的ID命令返回的数据
// 共512字节 (256个WORD),这里仅定义了一些感兴趣的项(基本上依据ATA/ATAPI-4)
typedef struct _IDINFO
{
USHORT  wGenConfig;   // WORD 0: 基本信息字
USHORT  wNumCyls;    // WORD 1: 柱面数
USHORT  wReserved2;   // WORD 2: 保留
USHORT  wNumHeads;   // WORD 3: 磁头数 USHORT  wReserved4;     // WORD 4: 保留
USHORT   wReserved5;     // WORD 5: 保留
USHORT  wNumSectorsPerTrack; // WORD 6: 每磁 道扇区数
USHORT  wVendorUnique[3];  // WORD 7-9: 厂家设定值
CHAR   sSerialNumber[20];  // WORD 10-19:序列号
USHORT  wBufferType;  // WORD 20: 缓冲类 型
USHORT  wBufferSize;  // WORD 21: 缓冲大小
USHORT  wECCSize;   // WORD 22: ECC校验大小
CHAR   sFirmwareRev[8];  // WORD 23-26: 固件版本
CHAR   sModelNumber[40];  // WORD 27-46: 内部型号
USHORT  wMoreVendorUnique;  // WORD 47: 厂家设定值
USHORT  wReserved48;  // WORD 48: 保留
struct {
 USHORT  reserved1:8;
 USHORT  DMA:1;   // 1=支持DMA
 USHORT  LBA:1;   // 1=支持 LBA
 USHORT  DisIORDY:1;  // 1=可不使用IORDY
 USHORT  IORDY:1;  // 1=支持 IORDY
 USHORT  SoftReset:1;  // 1=需要ATA软启动
 USHORT  Overlap:1;  // 1= 支持重叠操作
 USHORT  Queue:1;  // 1=支持命令队列
 USHORT  InlDMA:1;  // 1=支持交叉存取DMA
} wCapabilities;   // WORD 49: 一般能力
USHORT  wReserved1;    // WORD 50: 保留
USHORT  wPIOTiming;   // WORD 51: PIO时序
USHORT  wDMATiming;   // WORD 52: DMA时序
struct {
 USHORT  CHSNumber:1;  // 1=WORD 54-58有效
 USHORT  CycleNumber:1;  // 1=WORD 64-70有效
 USHORT  UnltraDMA:1;   // 1=WORD 88有效
 USHORT  reserved:13;
} wFieldValidity;   // WORD 53: 后 续字段有效性标志
USHORT  wNumCurCyls;  // WORD 54: CHS可寻址的柱面数
USHORT  wNumCurHeads;  // WORD 55: CHS可寻址的磁头数
USHORT  wNumCurSectorsPerTrack; // WORD 56: CHS可寻址每磁道扇区数
USHORT  wCurSectorsLow;  // WORD 57: CHS可寻址的扇区 数低位字
USHORT  wCurSectorsHigh;  // WORD 58: CHS可寻址的扇区数高位字
struct {
 USHORT  CurNumber:8;  // 当前一次性可读写扇区数
 USHORT  Multi:1;  // 1=已选择多扇区读写
 USHORT  reserved1:7;
} wMultSectorStuff;   // WORD 59: 多 扇区读写设定
ULONG  dwTotalSectors;  // WORD 60-61: LBA可寻址的扇区数
USHORT  wSingleWordDMA;  // WORD 62: 单字节DMA支持能力 struct {
 USHORT  Mode0:1;  // 1=支持模式0 (4.17Mb/s)
 USHORT  Mode1:1;  // 1=支持模式1 (13.3Mb/s)
 USHORT   Mode2:1;  // 1=支持模式2 (16.7Mb/s)
 USHORT  Reserved1:5;
 USHORT  Mode0Sel:1;  // 1=已选择模式0
 USHORT  Mode1Sel:1;  // 1=已选择模式1
  USHORT  Mode2Sel:1;  // 1=已选择模式2
 USHORT  Reserved2:5;
} wMultiWordDMA;    // WORD 63: 多字节DMA支持能力
struct {
 USHORT  AdvPOIModes:8;  // 支持高 级POI模式数
 USHORT  reserved:8;
} wPIOCapacity;   // WORD 64: 高级PIO支持能 力
USHORT  wMinMultiWordDMACycle; // WORD 65: 多字节DMA传输周期的最小值
USHORT   wRecMultiWordDMACycle; // WORD 66: 多字节DMA传输周期的建议值
USHORT  wMinPIONoFlowCycle;  // WORD 67: 无流控制时PIO传输周期的最小值
USHORT  wMinPOIFlowCycle;  // WORD 68: 有流控制时PIO传输周期的最小值
USHORT  wReserved69 [11];  // WORD 69-79: 保留
struct {
 USHORT  Reserved1:1;
 USHORT  ATA1:1;   // 1=支持ATA-1
 USHORT  ATA2:1;   // 1=支持ATA-2
 USHORT  ATA3:1;   // 1=支持ATA-3
 USHORT  ATA4:1;   // 1=支持ATA/ATAPI-4
 USHORT  ATA5:1;   // 1=支持ATA/ATAPI-5
 USHORT  ATA6:1;   // 1=支持ATA/ATAPI-6
  USHORT  ATA7:1;   // 1=支持ATA/ATAPI-7
 USHORT  ATA8:1;   // 1=支持ATA/ATAPI- 8
 USHORT  ATA9:1;   // 1=支持ATA/ATAPI-9
 USHORT  ATA10:1;  // 1=支持 ATA/ATAPI-10
 USHORT  ATA11:1;  // 1=支持ATA/ATAPI-11
 USHORT  ATA12:1;   // 1=支持ATA/ATAPI-12
 USHORT  ATA13:1;  // 1=支持ATA/ATAPI-13
 USHORT  ATA14:1;  // 1=支持ATA/ATAPI-14
 USHORT  Reserved2:1;
} wMajorVersion;   // WORD 80: 主版本
USHORT  wMinorVersion;  // WORD 81: 副版本
USHORT  wReserved82[6];  // WORD 82-87: 保留
struct {
 USHORT  Mode0:1;  // 1=支持 模式0 (16.7Mb/s)
 USHORT  Mode1:1;  // 1=支持模式1 (25Mb/s)
 USHORT  Mode2:1;  // 1=支持模式2 (33Mb/s)
 USHORT  Mode3:1;  // 1=支持模式3 (44Mb/s)  USHORT  Mode4:1;  // 1=支持模式4 (66Mb/s)
 USHORT  Mode5:1;  // 1=支持模式5 (100Mb/s)
 USHORT  Mode6:1;  // 1=支持模式6 (133Mb/s)
 USHORT  Mode7:1;   // 1=支持模式7 (166Mb/s) ???
 USHORT  Mode0Sel:1;  // 1=已选择模式0
 USHORT   Mode1Sel:1;  // 1=已选择模式1
 USHORT  Mode2Sel:1;  // 1=已选择模式2
  USHORT  Mode3Sel:1;  // 1=已选择模式3
 USHORT  Mode4Sel:1;  // 1=已选择模式4
 USHORT  Mode5Sel:1;  // 1=已选择模式5
 USHORT  Mode6Sel:1;  // 1=已选择模式 6
 USHORT  Mode7Sel:1;  // 1=已选择模式7
} wUltraDMA;   // WORD 88:  Ultra DMA支持能力
USHORT   wReserved89[167];  // WORD 89-255
} IDINFO, *PIDINFO;
// SCSI驱动所需的输入输出共用的结构
typedef struct _SRB_IO_CONTROL
{
  ULONG HeaderLength; // 头长度
  UCHAR Signature[8]; // 特征名称
  ULONG Timeout;  // 超时时间
  ULONG ControlCode; // 控制码
  ULONG ReturnCode; // 返回码
  ULONG Length;  // 缓冲区长度
} SRB_IO_CONTROL, *PSRB_IO_CONTROL;
 
需要引起注意的是IDINFO第57-58 WORD (CHS可寻址的扇区数),因为不满足32位对齐的要求,不可定 义为一个ULONG 字段。 Lynn McGuire的程序里正是由于定义为一个ULONG字段,导致该结构不可用。
以下是核心代码:
 
// 打开设备
// filename: 设备的“文件名 ”
HANDLE OpenDevice(LPCTSTR filename)
{
HANDLE hDevice;
// 打开设 备
hDevice= ::CreateFile(filename,  // 文件名
 GENERIC_READ | GENERIC_WRITE,  // 读写方式
 FILE_SHARE_READ | FILE_SHARE_WRITE, // 共享方式
 NULL,   // 默 认的安全描述符
 OPEN_EXISTING,  // 创建方式  0,   // 不需设置文件属性
  NULL);   // 不需参照模板文件
return hDevice;
}
// 向驱动发“IDENTIFY DEVICE”命令,获得设备信息
// hDevice: 设备句柄
// pIdInfo: 设备信息结构指 针
BOOL IdentifyDevice(HANDLE hDevice, PIDINFO pIdInfo)
{
PSENDCMDINPARAMS pSCIP; // 输入数据结构指针
PSENDCMDOUTPARAMS pSCOP; // 输出数据结构指针
DWORD dwOutBytes;  // IOCTL输出数据长度
BOOL bResult;  // IOCTL返回值
// 申请输入/输 出数据结构空间
   pSCIP = (PSENDCMDINPARAMS)::GlobalAlloc(LMEM_ZEROINIT,
sizeof(SENDCMDINPARAMS)-1);
   pSCOP = (PSENDCMDOUTPARAMS)::GlobalAlloc (LMEM_ZEROINIT,
sizeof(SENDCMDOUTPARAMS)+sizeof(IDINFO)-1);
// 指定ATA/ATAPI命令 的寄存器值
// pSCIP->irDriveRegs.bFeaturesReg = 0;
// pSCIP- >irDriveRegs.bSectorCountReg = 0;
// pSCIP->irDriveRegs.bSectorNumberReg = 0;
// pSCIP->irDriveRegs.bCylLowReg = 0;
// pSCIP->irDriveRegs.bCylHighReg = 0;
// pSCIP->irDriveRegs.bDriveHeadReg = 0;
pSCIP->irDriveRegs.bCommandReg = IDE_ATA_IDENTIFY;
// 指定输入/输出数据缓冲区大小
pSCIP->cBufferSize = 0;
pSCOP->cBufferSize = sizeof(IDINFO);
// IDENTIFY DEVICE
bResult = ::DeviceIoControl(hDevice, // 设备句柄
 DFP_RECEIVE_DRIVE_DATA,  // 指定IOCTL
 pSCIP, sizeof(SENDCMDINPARAMS) - 1, // 输入数据缓冲区
 pSCOP, sizeof (SENDCMDOUTPARAMS) + sizeof(IDINFO) - 1, // 输出数据缓冲区
 &dwOutBytes,  // 输 出数据长度
 (LPOVERLAPPED)NULL);  // 用同步I/O
// 复制设备参数结构
::memcpy(pIdInfo, pSCOP->bBuffer, sizeof(IDINFO)); // 释放输入/输出数据空间
::GlobalFree(pSCOP);
::GlobalFree(pSCIP);
return bResult;
}
// 向SCSI MINI-PORT 驱动发“IDENTIFY DEVICE”命令,获得设备信息
// hDevice: 设备句柄 
// pIdInfo: 设备信息结构指针
BOOL IdentifyDeviceAsScsi(HANDLE hDevice, int nDrive, PIDINFO pIdInfo)
{
PSENDCMDINPARAMS pSCIP; // 输入数据结构指针
PSENDCMDOUTPARAMS pSCOP; // 输出数据结构指针
PSRB_IO_CONTROL pSRBIO; // SCSI输入输 出数据结构指针
DWORD dwOutBytes;  // IOCTL输出数据长度
BOOL bResult;  // IOCTL 返回值
// 申请输入/输出数据结构空间
   pSRBIO = (PSRB_IO_CONTROL)::GlobalAlloc (LMEM_ZEROINIT,
sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDOUTPARAMS)+sizeof(IDINFO)-1);
   pSCIP = (PSENDCMDINPARAMS)((char *)pSRBIO+sizeof(SRB_IO_CONTROL));
   pSCOP = (PSENDCMDOUTPARAMS)((char *)pSRBIO+sizeof(SRB_IO_CONTROL));
// 填充输入/输出数据
pSRBIO->HeaderLength = sizeof(SRB_IO_CONTROL);
pSRBIO->Timeout = 10000;
pSRBIO->Length = sizeof(SENDCMDOUTPARAMS)+sizeof(IDINFO)-1;
pSRBIO- >ControlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
::strncpy ((char *)pSRBIO- >Signature, SCSIDISK, 8);
// 指定ATA/ATAPI命令的寄存器值
// pSCIP- >irDriveRegs.bFeaturesReg = 0;
// pSCIP->irDriveRegs.bSectorCountReg = 0;
// pSCIP->irDriveRegs.bSectorNumberReg = 0;
// pSCIP->irDriveRegs.bCylLowReg = 0;
// pSCIP->irDriveRegs.bCylHighReg = 0;
// pSCIP- >irDriveRegs.bDriveHeadReg = 0;
pSCIP->irDriveRegs.bCommandReg = IDE_ATA_IDENTIFY;
pSCIP->bDriveNumber = nDrive;
// IDENTIFY DEVICE
bResult = ::DeviceIoControl(hDevice, // 设备句柄
 IOCTL_SCSI_MINIPORT,  // 指定 IOCTL
 pSRBIO, sizeof(SRB_IO_CONTROL) +sizeof(SENDCMDINPARAMS) - 1, // 输入数据缓冲区   pSRBIO, sizeof(SRB_IO_CONTROL) +sizeof(SENDCMDOUTPARAMS) + sizeof(IDINFO) - 1, // 输出 
数据缓冲区
 &dwOutBytes, // 输出数据长度
 (LPOVERLAPPED)NULL); // 用 同步I/O
// 复制设备参数结构
::memcpy(pIdInfo, pSCOP->bBuffer, sizeof (IDINFO));
// 释放输入/输出数据空间
::GlobalFree(pSRBIO);
return bResult;
}
// 将串中的字符两两颠倒
// 原因是ATA/ATAPI中的WORD,与Windows采用的字节顺序相 反
// 驱动程序中已经将收到的数据全部反过来,我们来个负负得正
void AdjustString (char* str, int len)
{
char ch;
int i;
// 两两颠倒
for (i=0;i<len;i+=2)
{
 ch = str[i];
 str[i] = str[i+1];
 str[i+1] = ch;
}
// 若是右对齐的,调整为左对齐 (去掉左边的空格)
i=0;
while (i<len && str[i]==' ') i++;
::memmove(str, &str[i], len-i);
// 去掉右边的空格
i = len - 1;
while(i>=0 && str[i]==' ')
{
 str[i] = '\\0';
 i--;
}
}
// 读取IDE硬盘的设备信息,必须有 足够权限
// nDrive: 驱动器号(0=第一个硬盘,1=0=第二个硬盘,......)
// pIdInfo: 设 备信息结构指针
BOOL GetPhysicalDriveInfoInNT(int nDrive, PIDINFO pIdInfo)
{
HANDLE hDevice;  // 设备句柄
BOOL bResult;  // 返回结果
char szFileName[20]; // 文件名
::sprintf(szFileName,\\\\\\\\.\\\\PhysicalDrive%d, nDrive);
hDevice = ::OpenDevice (szFileName);
if(hDevice == INVALID_HANDLE_VALUE)
{
 return FALSE;
// IDENTIFY DEVICE
bResult = ::IdentifyDevice(hDevice, pIdInfo);
if (bResult)
{
 // 调整字符串
 ::AdjustString(pIdInfo->sSerialNumber, 20);
 ::AdjustString(pIdInfo->sModelNumber, 40);
 ::AdjustString(pIdInfo- >sFirmwareRev, 8);
}
::CloseHandle (hDevice);
return bResult;
}
// 用SCSI驱动读取IDE硬盘的设备信息,不受权限制约
// nDrive: 驱动器号(0=Primary Master, 1=Promary Slave, 2=Secondary master, 3=Secondary slave)
// pIdInfo: 设备信息结 构指针
BOOL GetIdeDriveAsScsiInfoInNT(int nDrive, PIDINFO pIdInfo)
{
HANDLE hDevice;  // 设备句柄
BOOL bResult;  // 返回结果
char szFileName[20]; // 文件名 
::sprintf(szFileName,\\\\\\\\.\\\\Scsi%d:, nDrive/2); hDevice = ::OpenDevice(szFileName);
if(hDevice == INVALID_HANDLE_VALUE)
{
 return FALSE;
}
// IDENTIFY DEVICE
bResult = ::IdentifyDeviceAsScsi(hDevice, nDrive%2, pIdInfo);
// 检查是不 是空串
if(pIdInfo->sModelNumber[0]=='\\0')
{
 bResult = FALSE;
}
if(bResult)
{
 // 调整字符串
 ::AdjustString(pIdInfo- >sSerialNumber, 20);
 ::AdjustString(pIdInfo->sModelNumber, 40);
 ::AdjustString(pIdInfo->sFirmwareRev, 8);
}
return bResult;
}
Q 我注意到ATA/ATAPI里,以及DiskID32里,有一个“IDENTIFY PACKET DEVICE”指令,与“IDENTIFYDEVICE”有什么区别?
A IDENTIFY DEVICE专门用 于固定硬盘,而IDENTIFY PACKET DEVICE用于可移动存储设备如CDROM、 CF、 MO、 ZIP、 TAPE等。因 为驱动程序的原因,实际上用本例的方法,不管是IDENTIFY DEVICE也好,IDENTIFY PACKET DEVICE也好 ,获取可移动存储设备的详细信息,一般是做不到的。而且除了IDE硬盘,对SCSI、USB等接口的硬盘也 不起作用。除非厂商提供的驱动支持这样的功能。
Q ATA/ATAPI有很多指令,如READ SECTORS, WRITE SECTORS, SECURITY, SLEEP, STANDBY等,利用上述方法,是否可进行相应操作?
A 应该 没问题。但切记,要慎重慎重再慎重! 
Q 关于权限问题,请解释一下好吗?
A 在 NT/2000/XP下,administrator可以管理设备,上述两种访问驱动的方法都行。但在user身份下,或者登 录到域后,用户无法访问PhysicalDrive驱动的核心层,但SCSI MINI-PORT 驱动却可以。目前是可以, 不知道Windows以后的版本是否支持。因为这肯定是一个安全隐患。
另外,我们着重讨论 NT/2000/XP 中DeviceIoControl的应用,如果需要在98/ME中得到包括硬盘序列号在内的更加详细的信息 ,请参考DiskID32。
 
 
 
 
 
 
 
 

实战DeviceIoControl系列之四:获取硬盘的详细信息的更多相关文章

  1. 实战DeviceIoControl 之四:获取硬盘的详细信息

    Q 用IOCTL_DISK_GET_DRIVE_GEOMETRY或IOCTL_STORAGE_GET_MEDIA_TYPES_EX只能得到很少的磁盘参数,我想获得包括硬盘序列号在内的更加详细的信息,有 ...

  2. 微信公众号开发《一》OAuth2.0网页授权认证获取用户的详细信息,实现自动登陆

    原创声明:本文为本人原创作品,绝非他处转账,转载请联系博主 从接触公众号到现在,开发维护了2个公众号,开发过程中遇到很多问题,现在把部分模块功能在这备案一下,做个总结也希望能给其他人帮助 工欲善其事, ...

  3. Jsp调用淘宝IP地址库获取来访IP详细信息

    Jsp调用淘宝IP地址库获取来访IP详细信息   示例网页点击:www.trembler.cn/ipinfo/ipinfo(服务器有其他用处,页面已失效) String ip = request.ge ...

  4. 获取数据库表详细信息、存储过程、视图、的sql

    select s.[name] + '.' + t.[name] as tablename from sys.tables as t,sys.schemas as s where t.schema_i ...

  5. C++ 通过WIN32 API 获取逻辑磁盘详细信息

    众所周知,在微软的操作系统下编写应用程序,最主要的还是通过windows所提供的api函数来实现各种操作的,这些函数通常是可以直接使用的,只要包含windows.h这个头文件, 下载源文件 今天我们主 ...

  6. Unix/Linux获取进程的详细信息

    Linux的进程的信息都记录在/proc/<pid>/下面,其实常用的ps.top命令也是从这里读取信息的.常用的信息有: cmd(命令).cmdline(完整的命令行参数).envrio ...

  7. C++通过WIN32 API获取逻辑磁盘详细信息

      众所周知,在微软的操作系统下编写应用程序,最主要的还是通过windows所提供的api函数来实现各种操作的,这些函数通常是可以直接使用的,只要包含windows.h这个头文件. 今天我们主要介绍的 ...

  8. 01.阿里云SDK调用,获取ESC主机详细信息

    一:通过python SDK获取云主机的详细信息 1.创建Accessky码(不做展示) 2.通过pip安装SDK模块,这个阿里云帮助里面有,也不做详细展示. 3.详细使用方法看代码 我下面展示的返回 ...

  9. 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-7.授权登录获取微信用户个人信息实战

    笔记 7.授权登录获取微信用户个人信息实战         简介:讲解使用授权码code获取用户个人信息接口 关键点:看微信文档,字段尽量用拷贝 1.通过code获取access_token      ...

随机推荐

  1. RTL8188EUS带天线的WiFi模块

    http://www.liuliutech.com/ProductShow.asp?ID=121 一,公司介绍瑞昱(REALTEK)半导体成立于1987年,位于台湾[硅谷]的新竹科学园区.凭借着7位创 ...

  2. LINQ中的动态排序

    使用Linq动态属性排序 使用反射: public static Func<T,Tkey> DynamicLambda<T, Tkey>(string propertyName ...

  3. linux开发node相关的工具

    epel-release yum install epel-release node yum install nodejs mongodb 安装mongodb服务器端 yum install mong ...

  4. 使用 JMeter 完成常用的压力测试

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...

  5. 【redis】spring boot中 使用redis hash 操作 --- 之 使用redis实现库存的并发有序操作

    示例: @Autowired StringRedisTemplate redisTemplate; @Override public void dealRedis(Dealer dealer) { d ...

  6. iOS:搜索栏控件UISearchBar and SearchDisplayController的使用

    UISearchBar and SearchDisplayController控件: 这是一个带搜索栏和搜索显示控制器的控件,前面的SearchBar是一个搜索栏,它提供一个输入搜索条件的类似于文本框 ...

  7. Qt Creator的安装与Qt交叉编译的配置

    Qt Creator 的安装 到Qt官网下载Qt Creator  https://www.qt.io/download-open-source/ 其它旧版本点击Achieve连接下载 或登录http ...

  8. IP addr命令

    我们都知道Windows上查看IP地址是ipconfig, Linux上是ifconfig,但是Linux上还有一个命令叫ip addr可以查看IP地址. 如上图所示命令显示了机器上的所有网卡,大部分 ...

  9. 解决 PowerDesigner 错误 The generation has been cancelled because errors have been found by the check model.

    在通过概念数据模型生成为物理数据模型时出现错误“The generation has been cancelled because errors have been found by the chec ...

  10. 【Linux】linux bash shell之变量替换::=句法、=句法、:-句法、-句法、=?句法、?句法、:+句法、+句法

    linux bash shell之变量替换::=句法.=句法.:-句法.-句法.=?句法.?句法.:+句法.+句法   linux bash shell之变量替换::=句法.=句法.:-句法.-句法. ...