在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,进行配置相关设置。