在windows系统中访问安卓设备稍微有些麻烦,需要通过向adb.exe中写入指令进行控制。本篇主要描述MFC访问安卓设备的实例,在上一篇文章 “ MFC工程按USB插口显示所有USB设备及插口(包括安卓)”的基础上,顺序访问所有的安卓设备或者通过设备名称访问指定的安卓设备并且得到adb返回的数据信息。

上一篇文章 “ MFC工程按USB插口显示所有USB设备及插口(包括安卓)”地址:https://blog.csdn.net/a29562268/article/details/79606042。

下面进入主题,首先说下我的设计方式:

1.获取所有已连接的安卓设备信息与USB插口信息进行匹配:

代码中首先发送 “adb devices -l”得到所有安卓设备信息并且解析到自定义的数据结构中,使用保存在USB插口中(标记为android字段)的设备名称与得到的设备名称进行匹配,匹配成功后当前设备状态修改为已匹配,以这种形式遍历所有的设备;

2.使用重复发送指令方式,确保可以得到查询的设备信息:

代码中发送指令的速度非常快,接收数据时经常出现没有得到正确的返回信息,为了避免这种情况,采用重复发送的方式,检测得到正确的数据后再发送下一条指令;

3.发送线程与接收线程的同步:

操作adb.exe时采用的匿名管道(考虑到使用异步方式需要一些繁琐的处理)如果发送线程与接收线程不采用同步的形式将会造成接收线程堵塞,影响线程与进程的释放;

下面贴上.h文件(工程中用到的文件比较多,将会在文章最后附上工程下载地址):

#include <stdio.h>
#include <vector>//设备信息 内存结构
struct DevDataInfo
{//CString MemTotal;//CString MemFree;
};
//设备信息 电量结构
struct DevPowerInfo
{//电量百分比CString StrLevel;
};//设备类型结构
struct DevTypeInfo
{CString DevName;CString device_Product;CString model;CString device;DevDataInfo DevInfo;DevPowerInfo PowerInfo;//判断是否已经被匹配bool bIs;DevTypeInfo():bIs(0){}
};//写入指令信息
struct WriteShellInfo
{//是否登录设备进行写入 1为登录设备写入,0为不登录设备写入bool bRunadb;//需要写入adb的指令char* WriteInfo;
};//保存连接设备读取到的信息
struct ReadDevInfo
{CString DevName;//下载进度信息CString DownloadProg;//判断是否在写入bool bWrite;ReadDevInfo():bWrite(0){}
};struct Android_Info
{Android_Info();virtual ~Android_Info();//获取所有的安卓设备信息bool GetInfo(std::vector<DevTypeInfo> & data);bool GetShellInfo(CString SrcShell,CString & Shell);//写入设备文件夹地址以及本地电脑文件夹地址bool SetDevPath(CString DevPath,CString LocalPath);//指定的设备进行写入多条指令信息,开始操作设备bool WriteAllDevInfo(std::vector<CString> DevModel,std::vector<CString> ShellInfo);//指定单个设备写入多条指令设备信息bool WriteDevInfo(CString DevModel,std::vector<CString> ShellInfo);//根据数据的类型进行保存数据 1为有效数据,0为无效数据,-1为错误数据int SaveValidData(CString data);//写入查询信息函数bool WritePipeData(void * _this);//是否已经储存了设备信息bool GetDevTypeInfo();//获取需要连接的设备bool GetValidDevInfo(CString & shell);//第一个参数设备名 第二个参数在本地电脑文件夹下的文件名bool Push(CString DevName,CString FileName);//返回最后一次的错误信息 (如果出现多个错误,前面的会被覆盖掉)CString GetEndErrorInfo();//保存单条指令读取到的数据int SaveReadInfoData(CString DevName,CString data);//获取操作设备返回的所有信息bool GetReadDevAllData(std::vector<ReadDevInfo> & info);CString m_strWriteData;std::vector<CString> m_ReadData;volatile bool m_bRun;//运行模式 0为获取所有设备信息,1为开始执行获取每个设备的具体信息,比如电池剩余量、内存剩余量等volatile int m_nMode;//临时获取设备结构 并且向内部写入信息static DevTypeInfo * m_Devtype;//保存需要写入的设备信息std::vector<WriteShellInfo> m_WriteDevInfo;//保存临时adb数据char m_TempData[512];//0为不登录设备进行发送,1为登录设备进行发送int m_nSendMode;//保存访问的设备名称CString m_DevName;
private://保存所有的设备类型信息std::vector<DevTypeInfo *> m_DevType;//设备路径信息static char m_DevPath[256];//本地电脑路径信息static char m_LocalPath[256];//保存错误信息CString m_EndErrorData;//保存连接设备的读取信息std::vector<ReadDevInfo> m_ReadDevInfo;
private://初始化到adbshell文件夹 bool InitPath();//截取出一条完整的数据,包括去掉前面的空格或换行,遇到空格换行返回字符串CString MidValidData(CString data);//保存所有的设备信息bool SaveAllDevTypeInfo(CString data);//找到指定的字段对应的数据并且返回CString FindData(CString DscData,CString ValidData);//保存当前设备的内存信息bool SaveDevDataInfo(CString data);// 保存当前设备的电量信息bool SaveDevPowerInfo(CString data);//发送adb指令bool SendDevInfo(CString DevModel,char *ShellInfo,int bRunadb);//拼接adb路径与指令bool GetShellInfo_char(char * SrcShell);//获取有效的数据长度,返回0之前的长度int GetValidDataLen(const char * src);//写入读取到的数据信息bool WriteInfoData(ReadDevInfo & info,CString data);//写入错误信息bool WriteErrorInfo(CString data);//写指令信息bool WriteShellData(DevTypeInfo *info,char *ShellInfo);//截取出适合显示的信息CString MidDownLoadProg(CString data,CString condition1,CString condition2);//截取出适合显示的信息,单个判断CString MidDownLoadProg_(CString data,CString condition);//清除指令信息结构bool ClearDevInfo(std::vector<WriteShellInfo> & ShellInfo);//清除vector结构数据template<typename T>bool ClearVector(std::vector<T*> & obj){for (auto it = obj.begin();it != obj.end();it++){if (*it)delete *it;}obj.clear();return true;}
};

下面贴上.cpp文件:

#include "stdafx.h"
#include "Android_.h"//获取所有设备的判断字符串
#define AllDevInfoIndex _T("List of devices attached")
#define Device_Product  _T("device product:")
#define Model           _T("model:")
#define Device          _T("device:")//查看内存
#define QueryMemInfo   _T("MemTotal:")
//剩余内存容量
#define MeMFree        _T("MemFree:")
//获取所有设备
#define GetAllsDevInfo _T("adb devices -l")
//获取电量所有状态
#define GetPowered     _T("Current Battery Service state:")
//获取电量比例
#define Level          _T("level:")//手机内存 ,电量(使用重复发送方式,得到设备返回信息后再发送别的指令)
static char QueryDevInfo[][128] = {"dumpsys battery \r\n","cat /proc/meminfo \r\n"};
int g_nQueryDevInfo = 2;//路径信息
char Android_Info::m_DevPath[256] = {0};
char Android_Info::m_LocalPath[256] = {0};
//当前连接的设备名称
CString g_StrName;CString g_StrShellPath;//
DevTypeInfo* Android_Info::m_Devtype = 0;HANDLE hWritePipe2;
//0为未写入也未读取 1已经写入 2已经读取
int g_nWrite;
bool bRun;
//读数据计数,每次写入一条指令,等待回复后再写下一条
int g_nCount = 0;
//读取线程退出
bool g_bReadExit;
DWORD CALLBACK GetInfoThread(void *pVoid);
DWORD CALLBACK WriteThread(void *pVoid);//写入指令开始操作设备
DWORD CALLBACK ReadInfoThread(void *pVoid);
Android_Info::Android_Info():m_nMode(0)
{InitPath();
}Android_Info::~Android_Info()
{if (0 < m_DevType.size())ClearVector(m_DevType);
}bool Android_Info::GetInfo(std::vector<DevTypeInfo> & data)
{if (0 < m_DevType.size())ClearVector(m_DevType);USES_CONVERSION;m_nMode = 0;m_bRun = true;g_nWrite = 0;bRun = true;g_bReadExit = false;HANDLE handle = CreateThread(0,0,GetInfoThread,this,0,0);HANDLE Writehandle = CreateThread(0,0,WriteThread,this,0,0);CloseHandle(handle);while (bRun)Sleep(10);CloseHandle(Writehandle);for (auto it = m_DevType.begin();it != m_DevType.end();it++)data.push_back(*(*it));return (data.size() > 0 ? true : false);
}bool Android_Info::WritePipeData(void * _this)
{USES_CONVERSION;bool _bWriteRun = true;while (_bWriteRun){if (1 == m_nMode){    for (auto it = m_DevType.begin();it != m_DevType.end();it++){//修改为发送一个指令 ,然后再次登录设备发送下一个指令,防止因为发送过快或者别的原因导致接收不到处理数据int nCount = 0;while (nCount < g_nQueryDevInfo){//如果读线程已经退出,那么再次启动读线程,执行读信息操作if (!m_bRun){g_nWrite = 0;g_StrName = (*it)->DevName;m_Devtype = (*it);//SendMessage(AfxGetApp()->GetMainWnd()->GetSafeHwnd(),RunReadThread,0,0);HANDLE handle = CreateThread(0,0,GetInfoThread,_this,0,0);CloseHandle(handle);}while (!m_bRun);Sleep(10);while (1){if (1 == g_nWrite >> 30 /*&& (g_nCount == 0 ? 1 : g_nWrite == g_nCount)*/){//每次清除一下数据DWORD dwerror = 0;COMSTAT comstat;memset(&comstat,0,sizeof(comstat));ClearCommError(hWritePipe2,&dwerror,&comstat);//往adb程序里写命令:DWORD byteRead = 0;WriteFile(hWritePipe2,QueryDevInfo[nCount],strlen(QueryDevInfo[nCount]),&byteRead,NULL); Sleep(10);++nCount;++g_nWrite;break;}}m_bRun = false;while (!g_bReadExit);Sleep(100);//退出写线程_bWriteRun = false;//如果发送了指令没有获取到相应的信息 ,将再次发送if (1 == nCount){if ((*it)->PowerInfo.StrLevel.IsEmpty()){--nCount;Sleep(100);}}else if (2 == nCount){if ((*it)->DevInfo.MemTotal.IsEmpty()){--nCount;Sleep(100);}}}}if (1 == m_nMode){break;}}}bRun = false;return true;
}DWORD __stdcall WriteThread(void *pVoid)
{Android_Info *info = (Android_Info *)pVoid;info->WritePipeData(pVoid);return 0;
}DWORD __stdcall GetInfoThread(void *pVoid)
{HANDLE hReadPipe;HANDLE hReadPipe2;HANDLE hWritePipe;g_nWrite = 0;g_bReadExit = false;Android_Info *info = (Android_Info *)pVoid;SECURITY_ATTRIBUTES sat;STARTUPINFO startupinfo;PROCESS_INFORMATION pinfo;BYTE buffer[4096];DWORD byteRead;char cmdbuffer[1024];sat.nLength=sizeof(SECURITY_ATTRIBUTES);sat.bInheritHandle=true;sat.lpSecurityDescriptor=NULL;if(!CreatePipe(&hReadPipe,&hWritePipe,&sat,NULL)){return -1;}if(!CreatePipe(&hReadPipe2,&hWritePipe2,&sat,NULL)){return -1;}startupinfo.cb=sizeof(STARTUPINFO);GetStartupInfo(&startupinfo);startupinfo.hStdError=hWritePipe;startupinfo.hStdOutput=hWritePipe;startupinfo.hStdInput=hReadPipe2;startupinfo.dwFlags=STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;startupinfo.wShowWindow=SW_HIDE;CString StrPath;//0 获取所有的设备信息if (0 == info->m_nMode){info->GetShellInfo(GetAllsDevInfo,StrPath);}//1 获取每个设备的具体信息else if (1 == info->m_nMode){info->GetValidDevInfo(StrPath);}if(!CreateProcess(NULL, StrPath.GetBuffer(),NULL, NULL, TRUE, NULL, NULL, NULL,&startupinfo,&pinfo)){DWORD dwError = GetLastError();return -1;}StrPath.ReleaseBuffer();CloseHandle(hWritePipe);CloseHandle(hReadPipe2);HANDLE WritePipe2 = hWritePipe2;USES_CONVERSION;info->m_bRun = true;g_nWrite = 1;g_nWrite <<= 30;g_nCount = 0;int nExitCount = 0;while((info->m_bRun || (1 == info->m_nMode ? g_nCount < g_nWrite :  1)) && 100 > nExitCount){//等待写入数据再去读取if (g_nCount >= g_nWrite && 0 != g_nCount && 0 != info->m_nMode)continue;Sleep(10);byteRead = 0;RtlZeroMemory(buffer,4096);BOOL bread = ReadFile(hReadPipe,buffer,4096,&byteRead,NULL);if (0 != byteRead){//判断接收到的是不是输入行标识(root@设备名称:)if (info->m_Devtype && 1 == info->m_nMode){CString StrData((CString)buffer);if (StrData.Find(info->m_Devtype->device_Product) && (20 > StrData.GetLength() - info->m_Devtype->device_Product.GetLength())){continue;}else if (StrData.Find(info->m_Devtype->device) && (20 > StrData.GetLength() - info->m_Devtype->device.GetLength())){continue;}}info->SaveValidData(CString(buffer));if (0 <= CString(buffer).Find(_T("error")) || (0 <= CString(buffer).Find(_T("Error")))){break;}nExitCount = 0;    }else if ((0 == info->m_nMode && (0 == byteRead))/* || info->GetDevTypeInfo()*/){break;}else if (0 == info->m_nMode && 1 <= short(g_nCount)){break;}else{++nExitCount;continue;}if (0 == g_nCount){g_nCount = 1;g_nCount <<= 30;}++g_nCount;}CloseHandle(hReadPipe);CloseHandle(WritePipe2);//退出创建的进程//PostThreadMessage(pinfo.dwProcessId, WM_QUIT, 0, 0);TerminateProcess(pinfo.hProcess,0);CloseHandle(pinfo.hThread);CloseHandle(pinfo.hProcess);info->m_bRun = false;g_bReadExit = true;info->m_nMode = 1;return 0;
}bool Android_Info::GetValidDevInfo(CString & shell)
{if (g_StrName.IsEmpty())return false;shell.Format(_T("%sadb -s %s shell "),g_StrShellPath,g_StrName);return (shell.GetLength() > 0 ? true : false);
}
bool Android_Info::GetDevTypeInfo()
{return (m_DevType.size() > 0 ? true : false);
}//初始化到adbshell文件夹
bool Android_Info::InitPath()
{TCHAR strTemp[MAX_PATH];GetCurrentDirectory(MAX_PATH,strTemp);CString strPath =strTemp;strPath += _T("\\..\\adbShell\\");g_StrShellPath = strPath;return (g_StrShellPath.GetLength() > 0 ? true : false);
}bool Android_Info::GetShellInfo(CString SrcShell,CString & Shell)
{if (SrcShell.IsEmpty())return false;Shell = (g_StrShellPath + SrcShell);return (Shell.GetLength() > 0 ? true : false);
}
//根据数据的类型进行保存数据
int Android_Info::SaveValidData(CString data)
{//所有设备信息if (0 <= data.Find(AllDevInfoIndex)){return SaveAllDevTypeInfo(data);}else if (0 <= data.Find(QueryMemInfo)){return SaveDevDataInfo(data);}else if (0 <= data.Find(Level)){return SaveDevPowerInfo(data);}else//记录完整错误信息 由上层查看{WriteErrorInfo(data);}return -1;
}//写入错误信息
bool Android_Info::WriteErrorInfo(CString data)
{m_EndErrorData = data;return true;
}//返回最后一次的错误信息 (如果出现多个错误,前面的会被覆盖掉)
CString Android_Info::GetEndErrorInfo()
{return m_EndErrorData;
}//保存当前设备的内存信息
bool Android_Info::SaveDevDataInfo(CString data)
{if (data.IsEmpty())return false;while (data.GetLength() > 0 && (0 <= data.Find(QueryMemInfo))){m_Devtype->DevInfo.MemTotal = FindData(QueryMemInfo,data);if (!m_Devtype->DevInfo.MemTotal.IsEmpty()){data = data.Mid(data.Find(m_Devtype->DevInfo.MemTotal) + m_Devtype->DevInfo.MemTotal.GetLength());}m_Devtype->DevInfo.MemFree = FindData(MeMFree,data);if (!m_Devtype->DevInfo.MemFree.IsEmpty()){data = data.Mid(data.Find(m_Devtype->DevInfo.MemFree) + m_Devtype->DevInfo.MemFree.GetLength());}}return (m_Devtype->DevInfo.MemTotal.GetLength() > 0 ? true : false);
}// 保存当前设备的电量信息
bool Android_Info::SaveDevPowerInfo(CString data)
{if (data.IsEmpty())return false;while (data.GetLength() > 0 && (0 <= data.Find(Level))){m_Devtype->PowerInfo.StrLevel = FindData(Level,data);if (!m_Devtype->PowerInfo.StrLevel.IsEmpty()){data = data.Mid(data.Find(m_Devtype->PowerInfo.StrLevel) + m_Devtype->PowerInfo.StrLevel.GetLength());}}return (m_Devtype->PowerInfo.StrLevel.GetLength() > 0 ? true : false);
}//保存所有的设备信息
bool Android_Info::SaveAllDevTypeInfo(CString data)
{if (data.IsEmpty())return false;data = data.Mid(CString(AllDevInfoIndex).GetLength()/*,data.GetLength() - sizeof(AllDevInfoIndex)*/);//如果获取到主机信息跳过if (0 <= data.Find(_T("host")))data = data.Mid(CString(_T("host")).GetLength() + data.Find(_T("host")));while (data.GetLength() > 0 && (0 <= data.Find(Device_Product))){DevTypeInfo *info = new DevTypeInfo;info->DevName = MidValidData(data);info->device_Product = FindData(Device_Product,data);if (!info->device_Product.IsEmpty()){data = data.Mid(data.Find(info->device_Product) + info->device_Product.GetLength());}info->model = FindData(Model,data);if (!info->model.IsEmpty()){data = data.Mid(data.Find(info->model) + info->model.GetLength());}info->device = FindData(Device,data);if (!info->device.IsEmpty()){data = data.Mid(data.Find(info->device) + info->device.GetLength());}m_DevType.push_back(info);}return true;
}CString Android_Info::FindData(CString DscData,CString ValidData)
{if (0 > ValidData.Find(DscData))return _T("");CString Data;int MidLen = (ValidData.Find(DscData) + DscData.GetLength());Data = ValidData.Mid(MidLen/*,ValidData.GetLength() - MidLen*/);return MidValidData(Data);
}//截取出一条完整的数据,包括去掉前面的空格或换行,遇到空格换行返回字符串
CString Android_Info::MidValidData(CString data)
{if (data.IsEmpty())return _T("");USES_CONVERSION;char StrData[4096] = {0};memcpy(StrData,T2A(data.GetBuffer()),data.GetLength());char StrValidData[4096] = {0};int nCount = 0;//如果得到有效数据后,遇到换行 回车 换页 或者空格 直接返回数据bool bIs =false;for (int i = 0;i < data.GetLength();i++){//换行 回车 换页 空格if (StrData[i] == 0x0A || StrData[i] == 0x0D || StrData[i] == 0x0C || StrData[i] == ' '){if (bIs)return CString(StrValidData);continue;}StrValidData[nCount++] = StrData[i];bIs = true;}return CString(StrValidData);
}//写入设备文件夹地址以及本地电脑文件夹地址
bool Android_Info::SetDevPath(CString DevPath,CString LocalPath)
{if (DevPath.IsEmpty() || LocalPath.IsEmpty())return false;USES_CONVERSION;memset(m_DevPath,0,sizeof(DevPath));memset(m_LocalPath,0,sizeof(LocalPath));memcpy(m_DevPath,T2A(DevPath.GetBuffer()),DevPath.GetLength());DevPath.ReleaseBuffer();memcpy(m_LocalPath,T2A(LocalPath.GetBuffer()),LocalPath.GetLength());LocalPath.ReleaseBuffer();return true;
}//指定的设备进行写入多条指令信息,开始操作设备
bool Android_Info::WriteAllDevInfo(std::vector<CString> DevModel,std::vector<CString> ShellInfo)
{if (DevModel.size() <= 0 || ShellInfo.size() <= 0)return false;bool bIs = false;for (auto it = DevModel.begin();it != DevModel.end();it++){bIs = WriteDevInfo(*it,ShellInfo);}return bIs;
}//获取有效的数据长度,返回0之前的长度
int Android_Info::GetValidDataLen(const char * src)
{int nLen = 0;while (0 != src && 0 != *(src + nLen)){if (0 == *(src + nLen)){break;}++nLen;}return nLen;
}//指定单个设备写入多条指令设备信息
bool Android_Info::WriteDevInfo(CString DevModel,std::vector<CString> ShellInfo)
{if (DevModel.IsEmpty() || 0 >= ShellInfo.size())return false;ClearDevInfo(m_WriteDevInfo);USES_CONVERSION;for (auto it = ShellInfo.begin();it != ShellInfo.end();it++){WriteShellInfo WriteInfo;WriteInfo.WriteInfo = new char[sizeof(char) * 256];//临时转换CString数据char TempData[256] = {0};memset(WriteInfo.WriteInfo,0,sizeof(WriteInfo.WriteInfo));int nLen = 0;//等待添加新的指令if (0 != *WriteInfo.WriteInfo)m_WriteDevInfo.push_back(WriteInfo);else{delete WriteInfo.WriteInfo;WriteInfo.WriteInfo = 0;}}bool bIs = false;//根据指令进行访问设备for (auto it = m_WriteDevInfo.begin();it != m_WriteDevInfo.end();it++){bIs = SendDevInfo(DevModel,it->WriteInfo,it->bRunadb);}return true;
}//拼接adb路径与指令
bool Android_Info::GetShellInfo_char(char * SrcShell)
{if (0 == SrcShell || 0 == *SrcShell)return false;USES_CONVERSION;memset(m_TempData,0,sizeof(m_TempData));int nLen = 0;memcpy(m_TempData,T2A(g_StrShellPath.GetBuffer()),g_StrShellPath.GetLength());g_StrShellPath.ReleaseBuffer();memcpy(m_TempData,SrcShell,strlen(SrcShell));return (strlen(m_TempData) > 0 ? true : false);
}//发送adb指令
bool Android_Info::SendDevInfo(CString DevModel,char *ShellInfo,int bRunadb)
{m_DevName = DevModel;//不登录设备写入if (0 == bRunadb){memcpy(m_TempData,ShellInfo,strlen(ShellInfo) + 1);m_nSendMode = 0;m_nMode = 0;USES_CONVERSION;m_bRun = true;g_nWrite = 0;g_bReadExit = false;HANDLE handle = CreateThread(0,0,ReadInfoThread,this,0,0);CloseHandle(handle);//       while (m_bRun)
//          Sleep(10);}//登录设备写入else if (1 == bRunadb){g_StrName = DevModel;USES_CONVERSION;m_bRun = true;g_nWrite = 0;m_nMode = 1;m_nSendMode = 1;g_bReadExit = false;HANDLE handle = CreateThread(0,0,ReadInfoThread,this,0,0);CloseHandle(handle);for (auto it = m_DevType.begin();it != m_DevType.end();it++){WriteShellData(*it,ShellInfo);break;}}return true;
}//写指令信息
bool Android_Info::WriteShellData(DevTypeInfo *info,char *ShellInfo)
{USES_CONVERSION;bool _bWriteRun = true;while (_bWriteRun){
//      if (1 == m_nMode)
//      {   //如果读线程已经退出,那么再次启动读线程,执行读信息操作if (!m_bRun){g_nWrite = 0;m_Devtype = info;HANDLE handle = CreateThread(0,0,ReadInfoThread,this,0,0);CloseHandle(handle);}while (!m_bRun);while (1){if (1 == g_nWrite >> 30){//每次清除一下数据DWORD dwerror = 0;COMSTAT comstat;memset(&comstat,0,sizeof(comstat));ClearCommError(hWritePipe2,&dwerror,&comstat);//往adb程序里写命令:DWORD byteRead = 0;WriteFile(hWritePipe2,ShellInfo,strlen(ShellInfo),&byteRead,NULL); Sleep(10);++g_nWrite;break;}}m_bRun = false;while (!g_bReadExit);Sleep(10);//退出写线程_bWriteRun = false;//}}bRun = false;return true;
}//截取出适合显示的信息,单个判断
CString Android_Info::MidDownLoadProg_(CString data,CString condition)
{if (0 <= data.Find(condition)){int nCount = data.Find(condition);return data.Mid(nCount,data.GetLength() - nCount);}return _T("");
}
//截取出适合显示的信息
CString Android_Info::MidDownLoadProg(CString data,CString condition1,CString condition2)
{CString TempData1,TempData2,Temp;int nCount = 0;while (0 < data.GetLength() && (0 <= data.Find(condition1))){if (condition2.IsEmpty()){if (0 == nCount){TempData1 = data.Mid(data.Find(condition1),data.GetLength() - data.Find(condition1));data = TempData1;data = data.Mid(data.Find(condition1) + condition1.GetLength());if (0 <= TempData1.Find(condition1)){TempData1 = TempData1.Mid(0,TempData1.Find(condition1));}else{return TempData1;}++nCount;}else{TempData2 = data.Mid(data.Find(condition1),data.GetLength() - data.Find(condition1));data = TempData2;data = data.Mid(data.Find(condition1) + condition1.GetLength());if (0 <= TempData2.Find(condition1)){TempData2 = TempData2.Mid(0,TempData2.Find(condition1));TempData1 = TempData2;}else{return TempData1;}}}else{if (0 == nCount){TempData1 = data.Mid(data.Find(condition1),data.GetLength() - data.Find(condition1));TempData2 =  MidDownLoadProg_(TempData1,condition2);data = TempData1;data = data.Mid(data.Find(condition1) + condition1.GetLength());if (!TempData2.IsEmpty()){int nLen = (TempData1.Find(condition2) + condition2.GetLength());TempData1 = TempData1.Mid(0,nLen);}else{return TempData1;}++nCount;}else{Temp = data.Mid(data.Find(condition1),data.GetLength() - data.Find(condition1));TempData2 =  MidDownLoadProg_(Temp,condition2);data = Temp;data = data.Mid(data.Find(condition1) + condition1.GetLength());if (!TempData2.IsEmpty()){int nLen = (Temp.Find(condition2) + condition2.GetLength());TempData2 = Temp.Mid(0,nLen);TempData1 = TempData2;}else{return TempData1;}}}}return TempData1;
}
//写入读取到的数据信息
bool Android_Info::WriteInfoData(ReadDevInfo & info,CString data)
{int nVal = -1;if (0 <= data.Find(_T("Transferring:"))){info.DownloadProg = MidDownLoadProg(data,_T("Transferring:"),_T(")"));nVal = 1;}else if (0 <= data.Find(_T("KB/s (:"))){info.DownloadProg = data;nVal = 0;}return nVal;
}//保存单条指令读取到的数据
int Android_Info::SaveReadInfoData(CString DevName,CString data)
{int nVal = -1;bool bIs = false;for (auto it = m_ReadDevInfo.begin();it != m_ReadDevInfo.end();it++){if (it->DevName == DevName){while (1){if (!it->bWrite){it->bWrite = true;nVal = WriteInfoData(*it,data);bIs = true;it->bWrite = false;break;}}}}if (!bIs){ReadDevInfo info;info.DevName = DevName;nVal = WriteInfoData(info,data);if (-1 != nVal){m_ReadDevInfo.push_back(info);}}return nVal;
}//单条指令读线程
DWORD __stdcall ReadInfoThread(void *pVoid)
{HANDLE hReadPipe;HANDLE hReadPipe2;HANDLE hWritePipe;g_nWrite = 0;g_bReadExit = false;Android_Info *info = (Android_Info *)pVoid;SECURITY_ATTRIBUTES sat;STARTUPINFO startupinfo;PROCESS_INFORMATION pinfo;BYTE buffer[4096];DWORD byteRead;char cmdbuffer[1024];static CString DevName = info->m_DevName;sat.nLength=sizeof(SECURITY_ATTRIBUTES);sat.bInheritHandle=true;sat.lpSecurityDescriptor=NULL;if(!CreatePipe(&hReadPipe,&hWritePipe,&sat,NULL)){return -1;}if(!CreatePipe(&hReadPipe2,&hWritePipe2,&sat,NULL)){return -1;}startupinfo.cb=sizeof(STARTUPINFO);GetStartupInfo(&startupinfo);startupinfo.hStdError=hWritePipe;startupinfo.hStdOutput=hWritePipe;startupinfo.hStdInput=hReadPipe2;startupinfo.dwFlags=STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;startupinfo.wShowWindow=SW_HIDE;//保存WritePipe2句柄留着释放用 HANDLE WritePipe2 = hWritePipe2;USES_CONVERSION;CString StrPath;if (0 == info->m_nSendMode){info->GetShellInfo(A2T(info->m_TempData),StrPath);}//1 获取每个设备的具体信息else if (1 == info->m_nSendMode){info->GetValidDevInfo(StrPath);}if(!CreateProcess(NULL, StrPath.GetBuffer(),NULL, NULL, TRUE, NULL, NULL, NULL,&startupinfo,&pinfo)){return -1;}StrPath.ReleaseBuffer();CloseHandle(hWritePipe);CloseHandle(hReadPipe2);info->m_bRun = true;g_nWrite = 1;g_nWrite <<= 30;int nCount = 0;while(info->m_bRun || (1 == info->m_nSendMode ? nCount < g_nWrite :  1)){//等待写入数据再去读取if (1 == info->m_nSendMode && (nCount == g_nWrite || (nCount >= g_nWrite && 0 != nCount && 0 != info->m_nMode)))continue;byteRead = 0;RtlZeroMemory(buffer,4096);BOOL bread = ReadFile(hReadPipe,buffer,4096,&byteRead,NULL);if (0 != byteRead){int nVal = info->SaveReadInfoData(DevName,CString(buffer));if (0 == nVal || -1  == nVal){break;}}else if ((0 == info->m_nSendMode && (0 == byteRead))){break;}else{continue;}//        if (0 == info->m_nSendMode)
//      {
//          break;
//      }if (0 == nCount){nCount = 1;nCount <<= 30;continue;}++nCount;}CloseHandle(hReadPipe);
//  if (1 == info->m_nSendMode)
//  {//CloseHandle(hWritePipe2);
//  }CloseHandle(WritePipe2);//退出创建的进程TerminateProcess(pinfo.hProcess,0);CloseHandle(pinfo.hThread);CloseHandle(pinfo.hProcess);info->m_bRun = false;g_bReadExit = true;return 0;
}bool Android_Info::ClearDevInfo(std::vector<WriteShellInfo> & ShellInfo)
{for (auto it = ShellInfo.begin();it != ShellInfo.end();it++){if (it->WriteInfo){delete it->WriteInfo;it->WriteInfo = 0;}}ShellInfo.clear();return true;
}//第一个参数设备名 第二个参数在本地电脑文件夹下的文件名
bool Android_Info::Push(CString DevName,CString FileName)
{USES_CONVERSION;char WriteInfo[1024] = {0};//临时转换CString数据char TempData[256] = {0};memset(WriteInfo,0,sizeof(WriteInfo));int nLen = 0;memcpy(WriteInfo,"adb -s ",sizeof("adb -s "));nLen = GetValidDataLen(WriteInfo);memcpy(TempData,T2A(DevName),DevName.GetLength() * 2);DevName.ReleaseBuffer();memcpy(WriteInfo + nLen,TempData,strlen(TempData));nLen = GetValidDataLen(WriteInfo);memcpy(WriteInfo + nLen," push -p ",nLen);nLen = GetValidDataLen(WriteInfo);strcpy(WriteInfo + nLen,m_LocalPath);//memcpy(WriteInfo + nLen,m_LocalPath,strlen(m_LocalPath));nLen = GetValidDataLen(WriteInfo);memcpy(WriteInfo + nLen,"\\",sizeof("\\"));nLen = GetValidDataLen(WriteInfo);memset(TempData,0,sizeof(TempData));memcpy(TempData,T2A(FileName),FileName.GetLength() * 2);memcpy(WriteInfo + nLen,TempData,strlen(TempData));nLen = GetValidDataLen(WriteInfo);memcpy(WriteInfo + nLen," ",strlen(" "));nLen = GetValidDataLen(WriteInfo);memcpy(WriteInfo + nLen,m_DevPath,strlen(m_DevPath));nLen = GetValidDataLen(WriteInfo);return SendDevInfo(DevName,WriteInfo,0);
}//获取操作设备返回的所有信息
bool Android_Info::GetReadDevAllData(std::vector<ReadDevInfo> & info)
{info = m_ReadDevInfo;return (info.size() > 0 ? true : false);
}

部分使用函数及结构说明

//设备信息 内存结构
//保存当前设备的内存信息(单位kb)
struct DevDataInfo
{//内存空间总量CString MemTotal;//内存空间剩余量CString MemFree;
};//设备信息 电量结构
//保存当前设备的电量信息(单位:百分之 比如50表示百分之50)
struct DevPowerInfo
{//电量百分比CString StrLevel;
};//设备类型结构
//当前设备保存的信息(使用“adb devices -l”指令进行截取得到的数据以及设备的内存和电量信息)
struct DevTypeInfo
{CString DevName;CString device_Product;CString model;CString device;DevDataInfo DevInfo;DevPowerInfo PowerInfo;//判断是否已经被匹配bool bIs;DevTypeInfo():bIs(0){}
};//保存连接设备读取到的信息
//上层获取到的信息(比如 向设备传入文件,返回的传入数据量等)
struct ReadDevInfo
{CString DevName;//下载进度信息CString DownloadProg;//判断是否在写入bool bWrite;ReadDevInfo():bWrite(0){}
};//获取所有的安卓设备信息
//由上层调用(调用接口)
bool GetInfo(std::vector<DevTypeInfo> & data);//写入设备文件夹地址以及本地电脑文件夹地址(调用此接口设置自己选择的地址)
//第一个参数 设备SD卡内的保存路径
//第二个参数 电脑端的文件路径
bool SetDevPath(CString DevPath,CString LocalPath);//向指定设备传入文件
//第一个参数 设备名称
//第二个参数在本地电脑文件夹下的文件名(比如_T("test123456789.txt"))
bool Push(CString DevName,CString FileName);//返回最后一次的错误信息 (如果出现多个错误,前面的会被覆盖掉)
//操作失败的情况下 可以查看最后一次返回的信息
CString GetEndErrorInfo();//获取操作设备返回的所有信息
//比如上层查看所有设备传入文件的进度
bool GetReadDevAllData(std::vector<ReadDevInfo> & info);

测试部分函数操作实例

CDevInfo info;
std::vector<Usb_DevInfo> usbInfo;
//获取所有的设备信息
info.GetAllDevInfo(usbInfo);
//设置文件传入路径
info.SetDevPath(_T("/sdcard/Download"),_T("C:\Local_storage"));
for (auto it = usbInfo.begin();it != usbInfo.end();it++)
{if (!it->AndroidInfo.model.IsEmpty()){//指定设备传入文件info.Push(it->AndroidInfo.DevName,_T("test123456789.txt"));CString StrError = info.GetEndErrorInfo();}
}

下面贴上项目下载地址:https://download.csdn.net/download/a29562268/10319577!

特别说明
      如果工程出现编译无法通过的情况,请您参考上一篇文章 “ MFC工程按USB插口显示所有USB设备及插口(包括安卓)”地址:https://blog.csdn.net/a29562268/article/details/79606042,进行配置相关设置。

MFC操作多个安卓设备(发送指令)相关推荐

  1. 【案例】前端对接LED设备发送指令

    需求 需求:前端对接LED显示屏,且可以根据LED指令说明灵活性设置 了解 了解:设备LED指令是按照gb2312编码(16进制)来实现 思路 思路:需要将输入的内容转为16进制的gb2312编码格式 ...

  2. C# 怎样通过ip和端口向一台设备发送指令

    using System; using System.Collections.Generic; using System.Text; using System.Net; using System.Ne ...

  3. android+蓝牙遥控器,一种通过蓝牙遥控安卓设备的方法与流程

    本发明涉及安卓系统遥控领域,具体公开了一种通过蓝牙遥控安卓设备的方法. 背景技术: 随着数字技术的发展,人们使用的数字设备日新月异.现在最为常见的个人设备操作系统是安卓系统.对安卓设备控制的方式,最常 ...

  4. scrcpy投屏_scrcpy 使用教程:将安卓设备投屏到 PC 端

    阿拉平平 读完需要 6分钟 速读仅需 2 分钟 scrcpy 是一款开源的安卓设备投屏工具,通过 USB 或 Wi-Fi 与设备连接后就可以在 PC 端操作安卓设备,无需 root 权限且支持多平台运 ...

  5. scrcpy 使用教程:将安卓设备投屏到 PC 端

    文章首发于个人公众号:「阿拉平平」 scrcpy 是一款开源的安卓设备投屏工具,通过 USB 或 Wi-Fi 与设备连接后就可以在 PC 端操作安卓设备,无需 root 权限且支持多平台运行. 本文将 ...

  6. android接收串口发送字符,安卓串口通讯发送指令代码详解

    最近好多做安卓端跟硬件交互的,比如一些智能家居,贩卖机的. 而这些不管是485也好,232的板子也好,都会用到串口通讯,去往下位机发送指令操控.下面是我个人的一些理解,发送串口指令的方法都是一样的,各 ...

  7. 浏览器复制不进行url编码_谷歌浏览器测试版支持在PC上复制号码并操作关联安卓设备进行拨打...

    本周早些时候我们提到微软更新「你的手机」应用,可以在关联安卓设备后直接在桌面平台拨打或者接听电话等. 谷歌这边的解决方案相对来说倒是简单粗暴很多,直接在谷歌浏览器里发送号码到安卓设备后即可自动发起呼叫 ...

  8. Android蓝牙4.0开发及发送指令到蓝牙硬件设备,简单好用,方法已写好直接可用

    近日,接到需要用到蓝牙解锁硬件设备的新需求,开发过程中呢也遇到许多硬件的坑,开发协议文档较简单,几句话就完了,第一次搞得我自己一脸懵逼,本来一两个小时就能写完并测试完成的过程用了两三天.哎!默默地回到 ...

  9. 安卓设备通过USB串口与STM32单片机通讯之二

    安卓设备通过USB串口与STM32单片机通讯之二 本博文系JGB联合商务组的原创作品,引用请标明出处. 本博文接续上一篇的末尾章节. (二) APP的JAVA代码部分(使用Android Studio ...

最新文章

  1. 数据竞争(data race)问题分析的利器——valgrind的Helgrind
  2. vector、map删除当前记录
  3. android 编译之后黑屏_android 模拟器用3.18的内核无法启动,一直黑屏。
  4. 源数据文件(.csv)中的空格串和空串对pandas读取结果的影响
  5. 32边界的链码表示MPP算法MATLAB实现
  6. Java中equals、==和hashcode()
  7. HashMap深度分析
  8. 系统升级不停服务器,服务器操作系统一直升级吗
  9. leetcode 384 打乱数组
  10. java jackson unicode_如何让Jackson JSON生成的数据包含的中文以unicode方式编码
  11. 编写一个程序,将 d:\java 目录下的所有.java 文件复制到 d:\jad 目录下,并将原来文件的扩展名从.java 改为.jad。...
  12. b站用户画像2020_2020年抖音用户画像专栏报告(上)
  13. 单片机通过蜂鸣器播放任意音乐代码实现(2):音乐单片机代码自动生成
  14. java使用python爬虫,如何使用 Python 爬虫爬取 Java 题库?
  15. linux: dirent.h 使用
  16. iMazing 2.11.7 WinMac 中文版 — iOS设备管理工具
  17. Tenorshare UltData(苹果数据恢复软件)v8.5.3官方版
  18. java短信生成6位数的校验码
  19. linux系统的6000端口是什么,3种关闭linux系统端口方法
  20. tomcat启动找不到jer报错

热门文章

  1. 【高并发解决方案】5、如何设计一个秒杀系统
  2. 【JEECG技术博文】JEECG国际化介绍
  3. 数据分析 | 基于智能标签,精准管理数据
  4. SpringBoot2基础,进阶,数据库,中间件等系列文章目录分类
  5. Python中的_main_与_init_详解
  6. 如果正确看待区块链这一新型技术的未来发展?...
  7. 巧用Squid的ACL和访问列表实现高效访问控制
  8. 用组策略发布软件的简单解决办法
  9. Office2007打开文件提示“您尝试打开的文件xxx.xls的格式与文件扩展名指定的格式不一致”的解决办法...
  10. jQuery中的函数汇总1