MFC获取电脑硬盘序列号(附源码)

在新建的工程里面添加一个类

即:以下一个类

GetHDSerial.cpp

// GetHDSerial.cpp: implementation of the CGetHDSerial class.
// Download by http://www.newxing.com/
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "GetHDSerial.h"

char  m_buffer[256];
WORD  m_serial[256];
DWORD m_OldInterruptAddress;
DWORDLONG m_IDTR;

// 等待硬盘空闲
static unsigned int WaitHardDiskIdle()
{
    BYTE byTemp;

Waiting:
    _asm
    {
        mov dx, 0x1f7
        in al, dx
        cmp al, 0x80
        jb Endwaiting
        jmp Waiting
    }
Endwaiting:
    _asm
    {
        mov byTemp, al
    }
    return byTemp;
} 

//中断服务程序
void  _declspec( naked )InterruptProcess(void)
{
     int   byTemp;
     int   i;
     WORD temp;
     //保存寄存器值
     _asm
     {
         push eax
         push ebx
         push ecx
         push edx
         push esi
     }

     WaitHardDiskIdle();//等待硬盘空闲状态
     _asm
     {
         mov dx, 0x1f6
         mov al, 0xa0
         out dx, al
     }
     byTemp = WaitHardDiskIdle(); //若直接在Ring3级执行等待命令,会进入死循环
     if ((byTemp&0x50)!=0x50)
     {
        _asm  // 恢复中断现场并退出中断服务程序
        {
            pop esi
            pop edx
            pop ecx
            pop ebx
            pop eax
            iretd
        }
     }

     _asm
     {
         mov dx, 0x1f6 //命令端口1f6,选择驱动器0
         mov al, 0xa0
         out dx, al
         inc dx
         mov al, 0xec
         out dx, al //发送读驱动器参数命令
     }
     byTemp = WaitHardDiskIdle();
     if ((byTemp&0x58)!=0x58)
     {
        _asm  // 恢复中断现场并退出中断服务程序
        {
             pop esi
             pop edx
             pop ecx
             pop ebx
             pop eax
             iretd
        }
     }
     //读取硬盘控制器的全部信息
     for (i=0;i<256;i++)
     {
         _asm
         {
             mov dx, 0x1f0
             in ax, dx
             mov temp, ax
         }
         m_serial[i] = temp;
     }
     _asm
     {
         pop esi
         pop edx
         pop ecx
         pop ebx
         pop eax
         iretd
     }
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CGetHDSerial::CGetHDSerial()
{

}

CGetHDSerial::~CGetHDSerial()
{

}
// 读取硬盘序列号函数
char* CGetHDSerial::GetHDSerial()
{
  m_buffer[0]=‘\n‘;
  // 得到当前操作系统版本
  OSVERSIONINFO OSVersionInfo;
  OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  GetVersionEx( &OSVersionInfo);
  if (OSVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)
  {
      // Windows 9x/ME下读取硬盘序列号
      WORD m_wWin9xHDSerial[256];
      Win9xReadHDSerial(m_wWin9xHDSerial);
      strcpy (m_buffer, WORDToChar (m_wWin9xHDSerial, 10, 19));
  }
  else
  {
      // Windows NT/2000/XP下读取硬盘序列号
      DWORD m_wWinNTHDSerial[256];
      // 判断是否有SCSI硬盘
      if ( ! WinNTReadIDEHDSerial(m_wWinNTHDSerial))
           WinNTReadSCSIHDSerial(m_wWinNTHDSerial);
      strcpy (m_buffer, DWORDToChar (m_wWinNTHDSerial, 10, 19));
  }
  return m_buffer;
}

// Windows9X/ME系统下读取硬盘序列号
void _stdcall CGetHDSerial::Win9xReadHDSerial(WORD * buffer)
{
    int i;
    for(i=0;i<256;i++)
        buffer[i]=0;
    _asm
    {
        push eax
        //获取修改的中断的中断描述符(中断门)地址
        sidt m_IDTR
        mov eax,dword ptr [m_IDTR+02h]
        add eax,3*08h+04h
        cli
        //保存原先的中断入口地址
        push ecx
        mov ecx,dword ptr [eax]
        mov cx,word ptr [eax-04h]
        mov dword ptr m_OldInterruptAddress,ecx
        pop ecx
        //设置修改的中断入口地址为新的中断处理程序入口地址
        push ebx
        lea ebx,InterruptProcess
        mov word ptr [eax-04h],bx
        shr ebx,10h
        mov word ptr [eax+02h],bx
        pop ebx
        //执行中断,转到Ring 0(类似CIH病毒原理)
        int 3h
        //恢复原先的中断入口地址
        push ecx
        mov ecx,dword ptr m_OldInterruptAddress
        mov word ptr [eax-04h],cx
        shr ecx,10h
        mov word ptr [eax+02h],cx
        pop ecx
        sti
        pop eax
    }
    for(i=0;i<256;i++)
        buffer[i]=m_serial[i];
}

// Windows 9x/ME系统下,将字类型(WORD)的硬盘信息转换为字符类型(char)
char * CGetHDSerial::WORDToChar (WORD diskdata [256], int firstIndex, int lastIndex)
{
   static char string [1024];
   int index = 0;
   int position = 0;

   // 按照高字节在前,低字节在后的顺序将字数组diskdata 中内容存入到字符串string中
   for (index = firstIndex; index <= lastIndex; index++)
   {
      // 存入字中的高字节
      string [position] = (char) (diskdata [index] / 256);
      position++;
      // 存入字中的低字节
      string [position] = (char) (diskdata [index] % 256);
      position++;
   }
   //  添加字符串结束标志
   string [position] = ‘\0‘;

   //  删除字符串中空格
   for (index = position - 1; index > 0 && ‘ ‘ == string [index]; index--)
      string [index] = ‘\0‘;

   return string;
}

// Windows NT/2000/XP系统下,将双字类型(DWORD)的硬盘信息转换为字符类型(char)
char* CGetHDSerial::DWORDToChar (DWORD diskdata [256], int firstIndex, int lastIndex)
{
   static char string [1024];
   int index = 0;
   int position = 0;

   // 按照高字节在前,低字节在后的顺序将双字中的低字存入到字符串string中
   for (index = firstIndex; index <= lastIndex; index++)
   {
      // 存入低字中的高字节
      string [position] = (char) (diskdata [index] / 256);
      position++;
      // 存入低字中的低字节
      string [position] = (char) (diskdata [index] % 256);
      position++;
   }
   //  添加字符串结束标志
   string [position] = ‘\0‘;

   //  删除字符串中空格
   for (index = position - 1; index > 0 && ‘ ‘ == string [index]; index--)
      string [index] = ‘\0‘;

   return string;
}

// Windows NT/2000/XP下读取IDE硬盘序列号
BOOL CGetHDSerial::WinNTReadIDEHDSerial(DWORD * buffer)
{
   BYTE IdOutCmd [sizeof (SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1];
   BOOL bFlag = FALSE;
   int  drive = 0;
   char driveName [256];
   HANDLE hPhysicalDriveIOCTL = 0;    

   sprintf (driveName, "\\\\.\\PhysicalDrive%d", drive);
   //  Windows NT/2000/XP下创建文件需要管理员权限
   hPhysicalDriveIOCTL = CreateFileA (driveName,
                            GENERIC_READ | GENERIC_WRITE,
                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                            OPEN_EXISTING, 0, NULL);

   if (hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE)
   {
       GETVERSIONOUTPARAMS VersionParams;
       DWORD               cbBytesReturned = 0;

       // 得到驱动器的IO控制器版本
       memset ((void*) &VersionParams, 0, sizeof(VersionParams));
       if(DeviceIoControl (hPhysicalDriveIOCTL, IOCTL_GET_VERSION,
                               NULL, 0, &VersionParams,
                               sizeof(VersionParams),
                               &cbBytesReturned, NULL) )
       {
          if (VersionParams.bIDEDeviceMap > 0)
          {
              BYTE             bIDCmd = 0;   // IDE或者ATAPI识别命令
              SENDCMDINPARAMS  scip;

              // 如果驱动器是光驱,采用命令IDE_ATAPI_IDENTIFY, command,
              // 否则采用命令IDE_ATA_IDENTIFY读取驱动器信息
              bIDCmd = (VersionParams.bIDEDeviceMap >> drive & 0x10)?
                      IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY;

              memset (&scip, 0, sizeof(scip));
              memset (IdOutCmd, 0, sizeof(IdOutCmd));
              // 获取驱动器信息
              if (WinNTGetIDEHDInfo (hPhysicalDriveIOCTL,
                                      &scip,
                                      (PSENDCMDOUTPARAMS)&IdOutCmd,
                                      (BYTE) bIDCmd,
                                      (BYTE) drive,
                                      &cbBytesReturned))
              {
                  int m = 0;
                  USHORT *pIdSector = (USHORT *)
                             ((PSENDCMDOUTPARAMS) IdOutCmd) -> bBuffer;

                  for (m = 0; m < 256; m++)
                       buffer[m] = pIdSector [m];
                  bFlag = TRUE;  // 读取硬盘信息成功
              }
          }
       }
       CloseHandle (hPhysicalDriveIOCTL);  // 关闭句柄
   }
   return bFlag;
}

// WindowsNT/2000/XP系统下读取SCSI硬盘序列号
BOOL CGetHDSerial::WinNTReadSCSIHDSerial (DWORD * buffer)
{
      buffer[0]=‘\n‘;
      int controller = 0;
      HANDLE hScsiDriveIOCTL = 0;
      char   driveName [256];
      sprintf (driveName, "\\\\.\\Scsi%d:", controller);
     //  Windows NT/2000/XP下任何权限都可以进行
      hScsiDriveIOCTL = CreateFileA (driveName,
                               GENERIC_READ | GENERIC_WRITE,
                               FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                               OPEN_EXISTING, 0, NULL);

      if (hScsiDriveIOCTL != INVALID_HANDLE_VALUE)
      {
         int drive = 0;
         DWORD dummy;
         for (drive = 0; drive < 2; drive++)
         {
            char buffer [sizeof (SRB_IO_CONTROL) + SENDIDLENGTH];
            SRB_IO_CONTROL *p = (SRB_IO_CONTROL *) buffer;
            SENDCMDINPARAMS *pin =
                   (SENDCMDINPARAMS *) (buffer + sizeof (SRB_IO_CONTROL));
            // 准备参数
            memset (buffer, 0, sizeof (buffer));
            p -> HeaderLength = sizeof (SRB_IO_CONTROL);
            p -> Timeout = 10000;
            p -> Length = SENDIDLENGTH;
            p -> ControlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
            strncpy ((char *) p -> Signature, "SCSIDISK", 8);
            pin -> irDriveRegs.bCommandReg = IDE_ATA_IDENTIFY;
            pin -> bDriveNumber = drive;
            // 得到SCSI硬盘信息
            if (DeviceIoControl (hScsiDriveIOCTL, IOCTL_SCSI_MINIPORT,
                                 buffer,
                                 sizeof (SRB_IO_CONTROL) +
                                         sizeof (SENDCMDINPARAMS) - 1,
                                 buffer,
                                 sizeof (SRB_IO_CONTROL) + SENDIDLENGTH,
                                 &dummy, NULL))
            {
               SENDCMDOUTPARAMS *pOut =
                    (SENDCMDOUTPARAMS *) (buffer + sizeof (SRB_IO_CONTROL));
               IDSECTOR *pId = (IDSECTOR *) (pOut -> bBuffer);
               if (pId -> sModelNumber [0])
               {
                  int n = 0;
                  USHORT *pIdSector = (USHORT *) pId;

                  for (n = 0; n < 256; n++)
                      buffer[n] =pIdSector [n];
                  return TRUE;  // 读取成功
               }
            }
         }
         CloseHandle (hScsiDriveIOCTL);  // 关闭句柄
      }
   return FALSE;   // 读取失败
}

// Windows NT/2000/XP下读取IDE设备信息
BOOL CGetHDSerial::WinNTGetIDEHDInfo (HANDLE hPhysicalDriveIOCTL, PSENDCMDINPARAMS pSCIP,
                 PSENDCMDOUTPARAMS pSCOP, BYTE bIDCmd, BYTE bDriveNum,
                 PDWORD lpcbBytesReturned)
{
   // 为读取设备信息准备参数
   pSCIP -> cBufferSize = IDENTIFY_BUFFER_SIZE;
   pSCIP -> irDriveRegs.bFeaturesReg = 0;
   pSCIP -> irDriveRegs.bSectorCountReg = 1;
   pSCIP -> irDriveRegs.bSectorNumberReg = 1;
   pSCIP -> irDriveRegs.bCylLowReg = 0;
   pSCIP -> irDriveRegs.bCylHighReg = 0;

   // 计算驱动器位置
   pSCIP -> irDriveRegs.bDriveHeadReg = 0xA0 | ((bDriveNum & 1) << 4);

   // 设置读取命令
   pSCIP -> irDriveRegs.bCommandReg = bIDCmd;
   pSCIP -> bDriveNumber = bDriveNum;
   pSCIP -> cBufferSize = IDENTIFY_BUFFER_SIZE;

   // 读取驱动器信息
   return ( DeviceIoControl (hPhysicalDriveIOCTL, IOCTL_GET_DRIVE_INFO,
               (LPVOID) pSCIP,
               sizeof(SENDCMDINPARAMS) - 1,
               (LPVOID) pSCOP,
               sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1,
               lpcbBytesReturned, NULL) );
}

GetHDSerial.h

// GetHDSerial.h: interface for the CGetHDSerial class.
// Download by http://www.newxing.com/
//////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <stdio.h>

#define  SENDIDLENGTH  sizeof (SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE
#define  IDENTIFY_BUFFER_SIZE  512
#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
#define  IDE_ATAPI_IDENTIFY  0xA1  //  Returns ID sector for ATAPI.
#define  IDE_ATA_IDENTIFY    0xEC  //  Returns ID sector for ATA.
#define  IOCTL_GET_DRIVE_INFO   0x0007c088
#define  IOCTL_GET_VERSION          0x00074080
typedef struct _IDSECTOR
{
   USHORT  wGenConfig;
   USHORT  wNumCyls;
   USHORT  wReserved;
   USHORT  wNumHeads;
   USHORT  wBytesPerTrack;
   USHORT  wBytesPerSector;
   USHORT  wSectorsPerTrack;
   USHORT  wVendorUnique[3];
   CHAR    sSerialNumber[20];
   USHORT  wBufferType;
   USHORT  wBufferSize;
   USHORT  wECCSize;
   CHAR    sFirmwareRev[8];
   CHAR    sModelNumber[40];
   USHORT  wMoreVendorUnique;
   USHORT  wDoubleWordIO;
   USHORT  wCapabilities;
   USHORT  wReserved1;
   USHORT  wPIOTiming;
   USHORT  wDMATiming;
   USHORT  wBS;
   USHORT  wNumCurrentCyls;
   USHORT  wNumCurrentHeads;
   USHORT  wNumCurrentSectorsPerTrack;
   ULONG   ulCurrentSectorCapacity;
   USHORT  wMultSectorStuff;
   ULONG   ulTotalAddressableSectors;
   USHORT  wSingleWordDMA;
   USHORT  wMultiWordDMA;
   BYTE    bReserved[128];
} IDSECTOR, *PIDSECTOR;

typedef struct _DRIVERSTATUS
{
   BYTE  bDriverError;  //  Error code from driver, or 0 if no error.
   BYTE  bIDEStatus;    //  Contents of IDE Error register.
                        //  Only valid when bDriverError is SMART_IDE_ERROR.
   BYTE  bReserved[2];  //  Reserved for future expansion.
   DWORD  dwReserved[2];  //  Reserved for future expansion.
} DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS;

typedef struct _SENDCMDOUTPARAMS
{
   DWORD         cBufferSize;   //  Size of bBuffer in bytes
   DRIVERSTATUS  DriverStatus;  //  Driver status structure.
   BYTE          bBuffer[1];    //  Buffer of arbitrary length in which to store the data read from the                                                       // drive.
} SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS;
typedef struct _SRB_IO_CONTROL
{
   ULONG HeaderLength;
   UCHAR Signature[8];
   ULONG Timeout;
   ULONG ControlCode;
   ULONG ReturnCode;
   ULONG Length;
} SRB_IO_CONTROL, *PSRB_IO_CONTROL;

typedef struct _IDEREGS
{
   BYTE bFeaturesReg;       // Used for specifying SMART "commands".
   BYTE bSectorCountReg;    // IDE sector count register
   BYTE bSectorNumberReg;   // IDE sector number register
   BYTE bCylLowReg;         // IDE low order cylinder value
   BYTE bCylHighReg;        // IDE high order cylinder value
   BYTE bDriveHeadReg;      // IDE drive/head register
   BYTE bCommandReg;        // Actual IDE command.
   BYTE bReserved;          // reserved for future use.  Must be zero.
} IDEREGS, *PIDEREGS, *LPIDEREGS;

typedef struct _SENDCMDINPARAMS
{
   DWORD     cBufferSize;   //  Buffer size in bytes
   IDEREGS   irDriveRegs;   //  Structure with drive register values.
   BYTE bDriveNumber;       //  Physical drive number to send
                            //  command to (0,1,2,3).
   BYTE bReserved[3];       //  Reserved for future expansion.
   DWORD     dwReserved[4]; //  For future use.
   BYTE      bBuffer[1];    //  Input buffer.
} SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS;
typedef struct _GETVERSIONOUTPARAMS
{
   BYTE bVersion;      // Binary driver version.
   BYTE bRevision;     // Binary driver revision.
   BYTE bReserved;     // Not used.
   BYTE bIDEDeviceMap; // Bit map of IDE devices.
   DWORD fCapabilities; // Bit mask of driver capabilities.
   DWORD dwReserved[4]; // For future use.
} GETVERSIONOUTPARAMS, *PGETVERSIONOUTPARAMS, *LPGETVERSIONOUTPARAMS;

// 获取硬盘序列号的类
class CGetHDSerial
{
public:
    CGetHDSerial();
    virtual ~CGetHDSerial();
    void  _stdcall Win9xReadHDSerial(WORD * buffer);
    char* GetHDSerial();
    char* WORDToChar (WORD diskdata [256], int firstIndex, int lastIndex);
    char* DWORDToChar (DWORD diskdata [256], int firstIndex, int lastIndex);
    BOOL  WinNTReadSCSIHDSerial(DWORD * buffer);
    BOOL  WinNTReadIDEHDSerial (DWORD * buffer);
    BOOL  WinNTGetIDEHDInfo (HANDLE hPhysicalDriveIOCTL, PSENDCMDINPARAMS pSCIP,
                      PSENDCMDOUTPARAMS pSCOP, BYTE bIDCmd, BYTE bDriveNum,
                      PDWORD lpcbBytesReturned);
};

源码下载

时间: 2024-11-10 11:37:21

MFC获取电脑硬盘序列号(附源码)的相关文章

【转】百度API获取城市名地名(附源码)

在做一个软件时,用到了定位功能.网上有很多关于google 的GPS定位,但网上关于google定位都没有用, 搜索下原因:(这里建议大家在中国就尽量不使用系统自带的定位) 因为Google的服务器不在中国(就算能网上关于定位的代码能用,那也非常的慢,除非你的应用是在国外使用)    由于网络等原因所以定位一般会失败 于是转向使用百度api来定位. 所用到的百度API参考地址. 取得位置的百度官方sdk参考 Android定位SDK 由坐标获取地址方法参考 Geocoding API 的 7.逆

转:微信开发之使用java获取签名signature(贴源码,附工程)

微信开发之使用java获取签名signature(贴源码,附工程) 标签: 微信signature获取签名 2015-12-29 22:15 6954人阅读 评论(3) 收藏 举报  分类: 微信开发(5)  版权声明:本文为博主原创文章,转载注明出处http://blog.csdn.net/u013142781 目录(?)[+] 一.前言 微信接口调用验证最终需要用到的三个参数noncestr.timestamp.signature: 接下来将会给出获取这三个参数的详细代码 本文的环境ecli

opencvbase 实现opencv打开摄像头和初步处理等效果操作(附源码)

// TwoCameraOnTimer2Dlg.cpp : 实现文件 /* CvMat, Mat, IplImage之间的互相转换 IpIImage -> CvMat CvMat matheader; CvMat * mat = cvGetMat(img, &matheader); CvMat * mat = cvCreateMat(img->height, img->width, CV_64FC3); cvConvert(img, mat) IplImage -> Mat

Qt Quick 图像处理实例之美图秀秀(附源码下载)

在<Qt Quick 之 QML 与 C++ 混合编程详解>一文中我们讲解了 QML 与 C++ 混合编程的方方面面的内容,这次我们通过一个图像处理应用,再来看一下 QML 与 C++ 混合编程的威力,同时也为诸君揭开美图秀秀.魔拍之类的相片美化应用的底层原理. 项目的创建过程请参考<Qt Quick 之 Hello World 图文详解>,项目名称为 imageProcessor ,创建完成后需要添加两个文件: imageProcessor.h 和 imageProcessor.

wpf 模拟3D效果(和手机浏览图片效果相似)(附源码)

原文 wpf 模拟3D效果(和手机浏览图片效果相似)(附源码) pf的3D是一个很有意思的东西,类似于ps的效果,类似于电影动画的效果,因为动画的效果,(对于3D基础的摄像机,光源,之类不介绍,对于依赖属性也不介绍.),个人认为,依赖属性这个东西,有百分之五十是为了3D而存在.(自己写的类似于demo的东西)先上图,无图无真相这是demo的整个效果图,可以用鼠标移动,触摸屏也可以手指滑动,图片会移动,然后移动结束,会有一个回弹的判断. <Window x:Class="_3Dshow.Wi

【网站国际化必备】Asp.Net MVC 集成Paypal(贝宝)快速结账 支付接口 ,附源码demo

开篇先给大家讲段历史故事,博主是湖北襄阳人.襄阳物华天宝,人杰地灵,曾用名襄樊.在2800多年的历史文化中出现了一代名相诸葛亮(卧龙),三国名士庞统(凤雏),魏晋隐士司马徽(水镜先生),唐代大诗人孟浩然(孟襄阳),张继.杜审言,文学家皮日休,北宋著名书画家米芾(米襄阳),“允冠百王”的光武帝刘秀,东方圣人释道安等一大批历史文化名人.小说<三国演义>120回故事中有30多回提到襄阳. 相传诸葛亮的老婆黄月英黄头发黑皮肤,但知识广博.诸葛亮发明木牛流马,就是从黄月英的传授的技巧上发展出来.不仅如此

利用Java针对MySql封装的jdbc框架类 JdbcUtils 完整实现(包含增删改查、JavaBean反射原理,附源码)

最近看老罗的视频,跟着完成了利用Java操作MySql数据库的一个框架类JdbcUtils.java,完成对数据库的增删改查.其中查询这块,包括普通的查询和利用反射完成的查询,主要包括以下几个函数接口: 1.public Connection getConnection()   获得数据库的连接 2.public boolean updateByPreparedStatement(String sql, List<Object>params)throws SQLException  更新数据库

Android学习笔记(十四)——在运行时添加碎片(附源码)

在运行时添加碎片 点击获取源码 将UI分割为多个可配置的部分是碎片的优势之一,但其真正强大之处在于可在运行时动态地把它们添加到活动中. 1.使用上一篇创建的Fragments项目,在main.xml文件中注释掉两个<fragment>元素: 2.在FragmentActivity.java中添加下面的代码: FragmentManager fragmentManager = getSupportFragmentManager();//向活动添加碎片 FragmentTransaction fr

微信公众平台开发教程(四) 实例入门:机器人(附源码)

微信公众平台开发教程(四) 实例入门:机器人(附源码) 上一篇文章,写了基本框架,可能很多人会觉得晕头转向,这里提供一个简单的例子来予以说明,希望能帮你解开谜团. 一.功能介绍 通过微信公众平台实现在线客服机器人功能.主要的功能包括:简单对话.查询天气等服务. 这里只是提供比较简单的功能,重在通过此实例来说明公众平台的具体研发过程.只是一个简单DEMO,如果需要的话可以在此基础上进行扩展. 当然后续我们还会推出比较复杂的应用实例. 二.具体实现 1.提供访问接口 这里不再赘述,参照上一章,微信公