介绍
gitee链接:https://gitee.com/lensen00/as
复刻gitee中的QTScrcpy项目(https://gitee.com/Barryda/QtScrcpy)。原项目基于QT+vs2017环境开发。
本项目基于vs2017开发。
项目进展。
使用说明
//adbPipe.h
#pragma once
#ifndef ADBPIPE_H
#define ADBPIPE_H
#include <iostream>
#include <windows.h>
#include <string>
using namespace std;
class Pipe{
public:
enum ADB_EXEC_RESULT
{
AER_ERROR_START, // 启动失败
AER_SUCCESS_START, // 启动成功
AER_SUCCESS_EXEC, // 执行成功
AER_ERROR_EXEC, // 执行失败
AER_ERROR_MISSING_BINARY, // 找不到文件
};
void loop() ; //循环
void isloop() ; //循环
const string & getError() const; //获取当前错误信息
const bool sendCommand(const char *); //执行命令
const bool sendCommand(const string &,const char *);
void setStatus(const char*); //设置错误信息
const string &getstrbuff() const;
void cleanbuffer();
ADB_EXEC_RESULT adbProcessResult();
const string getDeviceSerial();
const string getDeviceIP();
void reverse(const string &serial, const string &deviceSocketName, int localPort);
bool reverseRemove(const string &serial, const string &);
void push(const string &serial, const string &local, const string &remote);
bool removePath(const string &serial, const string &deviceSocketName);
Pipe(); //管道执行的命令
~Pipe();
private:
HANDLE hpiperead = NULL; //读入 匿名管道
HANDLE hpipewrite = NULL; //写出 匿名管道
HANDLE hpiperead2 = NULL; //读入2 匿名管道
HANDLE hpipewrite2 = NULL; //写出2 匿名管道
HANDLE hProHandle = NULL;
HANDLE hThrLoop = NULL;
HANDLE hThrisLoop = NULL;
SECURITY_ATTRIBUTES ai; //安全属性
PROCESS_INFORMATION pi; //进程信息
STARTUPINFOA si;
string errorString;
string strbuff;
ADB_EXEC_RESULT processResult;
};
#endif
//adbPipe.cpp
#include "adbPipe.h"
DWORD __stdcall ThrPipeThreadRead(void *www)
{
Pipe * pipe = (Pipe *)www;
pipe->loop();
return 0;
//创建内核对象使用完之后一定记得关闭,有可能会产生内存泄露
}
DWORD __stdcall WaitPipe(void *www)
{
Pipe * pipe = (Pipe *)www;
pipe->isloop();
return 0;
}
Pipe::Pipe(){
ai.nLength = sizeof(SECURITY_ATTRIBUTES);
ai.bInheritHandle = true;
ai.lpSecurityDescriptor = NULL;
if (!CreatePipe(&hpiperead, &hpipewrite, &ai, 0)) //创建读入管道1
{
this->setStatus("[0x01]Read 流创建失效");
processResult=AER_ERROR_START;
return;
}
if (!CreatePipe(&hpiperead2, &hpipewrite2, &ai, 0)) //创建读入管道2
{
this->setStatus("[0x02]Write 流创建失效");
processResult=AER_ERROR_START;
return;
}
GetStartupInfoA(&si); //获取当前进程的STARTUPINFO
si.cb = sizeof(STARTUPINFO);
si.hStdError = hpipewrite; //标准错误输出
si.hStdOutput = hpipewrite; //标准输出
si.hStdInput = hpiperead2; //标准写入
si.wShowWindow = SW_SHOW;
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
char com[4] = "cmd";
if (!(CreateProcessA(NULL, com, NULL, NULL, true, NULL, NULL, NULL, &si, &pi))) //创建隐藏的CMD进程
{
this->setStatus("[0x03] CreateProcess函数执行出错");
processResult=AER_ERROR_START;
return;
}
else processResult=AER_SUCCESS_START;
DWORD dwThread = FALSE;
hThrLoop = CreateThread(NULL, 0, ThrPipeThreadRead, this, 0, &dwThread);//chuangjian
if (hThrLoop == false){
processResult=AER_ERROR_START;
return;
}
hThrLoop = CreateThread(NULL, 0, WaitPipe, this, 0, &dwThread);//chuangjian
if (hThrLoop == false){
processResult=AER_ERROR_START;
return;
}
}
const bool Pipe::sendCommand(const char * com) //执行命令
{
DWORD dwWrite = 0;
// DWORD byteread;
char www[1024]="G:\\code\\c++\\AS\\AS\\AS\\adb\\adb.exe ";
strcat_s(www,com);
strcat_s(www,"\n");
if (WriteFile(hpipewrite2, www, strlen(www), &dwWrite, NULL)) {
processResult=AER_SUCCESS_EXEC ;
return TRUE;
}
else {
processResult=AER_ERROR_EXEC;
return FALSE;
}
//0x001C7796 处有未经处理的异常(在 ConsoleApplication2.exe 中): 0xC0000005: 读取位置 0x0000000C 时发生访问冲突。
}
const bool Pipe::sendCommand(const string &serial, const char *com)
{
DWORD dwWrite = 0;
string buff = "";
if (!serial.empty()){
buff = "-s " + serial + " "+com;
}
char www[1024]="G:\\code\\c++\\AS\\AS\\AS\\adb\\adb.exe ";
strcat_s(www,serial.c_str());
strcat_s(www,"\n");
if (WriteFile(hpipewrite2, www, strlen(www), &dwWrite, NULL)) {
processResult=AER_SUCCESS_EXEC ;
return true;
}
else {
processResult=AER_ERROR_EXEC;
return false;
}
}
void Pipe::loop(){
DWORD byteread;
while (true)
{
char outbuff[4096];
memset(outbuff, '\0', 4096);
if (ReadFile(this->hpiperead, outbuff, 4095, &byteread, NULL) == NULL)
{
//processResult=AER_ERROR_EXEC;
break;
}
else if (outbuff[0]=='L' && outbuff[1]=='i' )
{
strbuff = outbuff;
cout << "get devices list buffer " << strbuff << " end" << endl;
}
// if (strlen(outbuff) > 139) {
// strbuff = outbuff;
// cout << "this need buffer is size >139" << strbuff << " end" << endl;
// }
//
// if (outbuff[0]=='\n' && outbuff[1]=='\t' ){
// strbuff = outbuff;
// cout << "this need buffer " << strbuff << " end" << endl;
// }
// if (i >3 ) {
// cout << outbuff << endl;
// cout << strbuff << endl;
// }
cout << outbuff << endl;
memset(outbuff, '\0', 4096);
}
cout << "Pipe Stoped!"<<endl;
}
void Pipe::isloop()
{ //管道信息
DWORD dwRet = WaitForSingleObject(pi.hProcess, INFINITE);
while (dwRet == WAIT_TIMEOUT) //超时
{
dwRet = WaitForSingleObject(pi.hProcess, INFINITE);
}
if (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_ABANDONED) //调用失败
{
processResult=AER_ERROR_EXEC;
cout << "[END] Pipe Stoped!" << endl;
}
}
Pipe::~Pipe()
{
//创建内核对象使用完之后一定记得关闭,有可能会产生内存泄露
CloseHandle(hThrisLoop);
CloseHandle(hThrLoop);
CloseHandle(hpipewrite);
CloseHandle(hpiperead);
CloseHandle(hpiperead2);
CloseHandle(hpipewrite2);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
const string & Pipe::getError() const
{
return this->errorString;
}
void Pipe::setStatus(const char * info)
{
this->errorString = info;
}
const string &Pipe::getstrbuff() const {
return this->strbuff;
}
void Pipe::cleanbuffer()
{
strbuff = "";
}
Pipe::ADB_EXEC_RESULT Pipe::adbProcessResult()
{
return processResult;
}
// const string getDeviceSerial() {
//
// }
void Pipe::push(const string &serial, const string &local, const string &remote)
{
string arg;
char adbline[1024];
if (!serial.empty())arg = "-s " + serial + " push ";
else arg += "push ";
arg += local + " " + remote;
strcat_s(adbline, 1024, arg.c_str());
sendCommand(adbline);
free(adbline);
}
void Pipe::reverse(const string &serial, const string &deviceSocketName, int localPort) {
char adbline[1024] ;
string arg;
if (!serial.empty())arg = "-s " + serial + " reverse ";
else arg += "reverse ";
arg += deviceSocketName + " " ;
strcat_s(adbline, 1024, arg.c_str());
adbline[strlen(adbline)] = localPort;
sendCommand(adbline);
free(adbline);
};
bool Pipe::reverseRemove(const string &serial, const string &deviceSocketName)
{
char cmdline[1024];
string buff = "--remove localabstract:"+ deviceSocketName;
strcpy_s(cmdline, buff.c_str());
return sendCommand(serial, cmdline);
}
bool Pipe::removePath(const string &serial, const string &deviceSocketName)
{
string buff = "";
char cmdline[1024];
if (!serial.empty()) {
buff = "-s " + serial + " ";
}
else buff += "shell rm " + deviceSocketName;
strcpy_s(cmdline, 1024, buff.c_str());
return this->sendCommand(cmdline);
}
//server.h
#pragma once
#ifndef SERVER_H
#define SERVER_H
#include <string.h>
#include <stdio.h>
#include <direct.h>
#include "adbpipe.h"
/*
通过adb puss 将jar文件发送到手机指定位置并启动,以获取手机的显示,通过电脑建立与手机的反向代理传输回电脑
*/
//adb shell <手机路径> app_process / com.genymobile.scrcpy.Server 分辨率 比特率() 是否反向代理
// 分辨率:设置为0为手机默认分辨率 一般设置1080
// 比特率:建议8000000(8m) 值越大画面质量越高,但帧率越差 ,追求帧率可设置为2000000(2m)
// 是否反向代理:true正向代理 false反向代理(该程序设置为false)
class server {
//基于状态机编程
enum SERVER_START_STEP {
SSS_NULL, //0、空虚状态
SSS_PUSH, //1、push adb_server to android phone
SSS_ENABLE_REVERSE, //2、打开反向代理
SSS_EXECUTE_SERVER, //3、执行server
SSS_RUNNING, //4、程序已经正常运行
};
public:
server();
//启动server 手机id,反向代理的本地端口号,最大分辨率,比特率
bool start(const string &serial,int localPort,int maxSize,int bitRate);
bool serverStartResult(bool success); //back server is success or defeat
private:
void onWorkProcessResult();
private:
bool startServerByStep();
bool pushServer();
bool removeServer(); //after puse server faild run
bool enableTunnelReverse(); //反向通道
bool disableTunnelReverse();
bool execute(); //
const string getServerPath();
private:
string m_serial = "";
int m_localPort = 0;
int m_maxSize = 0;
int m_bitRate=0;
SERVER_START_STEP m_serverStartStep = SSS_NULL;
//char[4] a = "cmd";
Pipe m_workProcess;
Pipe m_serverProcess;
string m_serverPath = "";
bool m_serverCopiedToDevice = false; //app is push phone
bool m_enableReverse = false;
bool m_onExecuteAdbProcess = false; //run adb_process command
};
#endif
//server.cpp
#include "server.h"
// scrcpy-server.jar push to android of path
#define DEVICE_SERVER_PATH "/data/local/tmp/scrcpy-server.jar"
#define SOCKET_NAME "scrcpy"
server::server()
{
//start();
}
bool server::start(const string &serial, int localPort, int maxSize, int bitRate)
{
m_serial = serial;
m_localPort = localPort;
m_maxSize = maxSize;
m_bitRate = bitRate;
//start puss server
m_serverStartStep = SSS_PUSH;
return startServerByStep();
}
void server::onWorkProcessResult() {
if (!m_onExecuteAdbProcess){
if (SSS_NULL != m_serverStartStep) {
switch (m_serverStartStep) {
case SSS_PUSH:
if (Pipe::AER_SUCCESS_EXEC == m_workProcess.adbProcessResult()) {
m_serverCopiedToDevice = true; //app is push to phone
m_serverStartStep = SSS_ENABLE_REVERSE;
startServerByStep();
}
else if (Pipe::AER_SUCCESS_START != m_workProcess.adbProcessResult()) {
cout << "adb push failed" << endl;
m_serverStartStep = SSS_NULL;
//serverStartResult(false);
}
break;
case SSS_ENABLE_REVERSE:
if (Pipe::AER_SUCCESS_EXEC == m_workProcess.adbProcessResult()) {
m_enableReverse = true;
m_serverStartStep = SSS_EXECUTE_SERVER;
startServerByStep();
}
else if (Pipe::AER_SUCCESS_START != m_workProcess.adbProcessResult()) {//本步骤若失败,但push是已经成功的,需将push到手机的app移除
cout << "adb reserve failed" << endl;
m_serverStartStep = SSS_NULL;
//remove server
removeServer();
//serverStartResult(false);
}
break;
default:
break;
}
}
}
else {
if (SSS_EXECUTE_SERVER == m_serverStartStep ){
if (Pipe::AER_SUCCESS_START == m_serverProcess.adbProcessResult()){
m_serverStartStep = SSS_RUNNING;
}
else if (Pipe::AER_ERROR_START == m_serverProcess.adbProcessResult()) {
//adb process command failed
//disable reverse
disableTunnelReverse();
//remove server
cout << "adb shell start server failed" << endl;
m_serverStartStep = SSS_NULL;
removeServer();
}
}
}
}
bool server::startServerByStep()
{
bool stepSuccess = false;
//push,enable reverse, execute server
if (SSS_NULL != m_serverStartStep) {
switch (m_serverStartStep){
case SSS_PUSH: //push app to device
stepSuccess = pushServer();
onWorkProcessResult();
break;
case SSS_ENABLE_REVERSE: //creat connect to device
stepSuccess = enableTunnelReverse();
onWorkProcessResult();
break;
case SSS_EXECUTE_SERVER: //run app
stepSuccess = execute();
break;
default:
break;
}
}
return stepSuccess;
}
bool server::pushServer()
{
m_workProcess.push(m_serial,getServerPath(),DEVICE_SERVER_PATH );
return true;
}
bool server::removeServer()
{
if (!m_serverCopiedToDevice) { //app not push phone
return true;
}
Pipe *adb = new Pipe();
if (!adb){
return false;
}
if (adb->removePath(m_serial, DEVICE_SERVER_PATH)) {
delete adb;
m_serverCopiedToDevice = false;
return true;
}
else {
delete adb;
return false;
}
}
bool server::enableTunnelReverse()
{
m_workProcess.reverse(m_serial, SOCKET_NAME, m_localPort);
return true;
}
bool server::disableTunnelReverse()
{
if (!m_enableReverse) { //server not execute
return true;
}
Pipe *adb = new Pipe();
if (!adb){
return false;
}
if (adb->reverseRemove(m_serial, SOCKET_NAME)) {
delete adb;
m_enableReverse = false;
return true;
}
else {
delete adb;
return false;
}
}
bool server::execute()
{
//adb shell CLASSPATH=<手机路径> app_process / com.genymobile.scrcpy.Server 分辨率 比特率() 是否反向代理
string buff = "";
char cmdline[1024];
buff = "shell CLASSPATH=";
buff += DEVICE_SERVER_PATH;
buff += " / app_process com.genymobile.scrcpy.Server ";
strcpy_s(cmdline, buff.c_str());
cmdline[strlen(cmdline)] = m_maxSize;
cmdline[strlen(cmdline)+1] = ' ';
cmdline[strlen(cmdline)+2] = m_bitRate;
strcat_s(cmdline, 1024, "false");
m_serverProcess.sendCommand(m_serial,cmdline);
m_onExecuteAdbProcess = true;
free(cmdline);
return true;
}
const string server::getServerPath()
{
char *buffer;
if (m_serverPath.empty()){
//m_serverPath= getenv("SCRCPY_SERVER_PATH");
if (m_serverPath.empty())
{
buffer = _getcwd(NULL, 0);
strcat_s(buffer, strlen(buffer) + 25, "\\adb\\scrcpy-server.jar");
m_serverPath = buffer;
}
}
return m_serverPath;
}
//main.cpp
#include<iostream>
#include <windows.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <direct.h>
#include "adbpipe.h"
#include "server.h"
using namespace std;
int main(){
server ser;
string devices[2];
int select = 1;
while (select){
cout << "+---------select num cin---------+" << endl;
cout << "|---------0、close system--------|" << endl;
cout << "|---------1、get devices list----|" << endl;
cout << "|---------2、usb connect phone---|" << endl;
cout << "|---------3、wifi connect phone--|" << endl;
cout << "|---------4、vitual touch--------|" << endl;
cout << "+---------------END--------------+" << endl;
cout << "+----------devices list----------+" << endl;
cin >> select;
switch (select) {
case 0:
break;
case 1:
break;
case 2:
cout << "|---cin need connect phone num---|" << endl;
cout << "+----------devices list----------+" << endl;
break;
case 3:
cout << "|---cin need connect phone num---|" << endl;
cout << "+----------devices list----------+" << endl;
break;
case 4:
break;
default:
cout << "please continue enter" << endl;
break;
}
}
// string strbuffer;
// char deviceid[20] ;
// bool idend = false;
// char a[4] = "cmd";
// pipe = new Pipe(a);
//
// pipe->sendCommand("devices");
// strbuffer = getbuff();
// pipe->cleanbuffer();
// if (strbuffer[26]=='*'){
// //this->SetConnectStatus(-1, "wifi server not open");
// pipe->sendCommand("start-server");
// strbuffer = getbuff();
// pipe->cleanbuffer();
// }
//
// if (strbuffer.size()<30 || strbuffer[28] == '\0') { //未连接上
// cout << "not connect" << endl;
// //this->SetConnectStatus(-1, "device not connect");
// //return false;
// }
// else {
// for (int i = 0; i < strbuffer.length()-28; i++) {
// if (strbuffer[26 + i] != '\t' || strbuffer[26 + i] != 9) {
// if (strbuffer[26 + i - 1] == '\t' && strbuffer[26 + i] != 'd'){
// //this->SetConnectStatus(-1, "device connect error");
// cout << "connect error" << endl;
// pipe->sendCommand("kill-server");
// pipe->sendCommand("devices");
// strbuffer = getbuff();
// pipe->cleanbuffer();
// cout << strbuffer << endl;
// break;
// }
// else if (strbuffer[26 + i - 1] == '\t' && strbuffer[26 + i] == 'd'){
// //devices connect succeed
// //strcpy_s(devicestatus,8,"device");
// //this->SetConnectStatus(1);
// //this->usbconnect = true;
// break;
// }
// if (!idend){
// deviceid[i]=strbuffer[26 + i];
// cout << (int)deviceid[i] << "is" << endl;
// //cout << '\t' << "is\\t"<<'\v'<<"is\\v" << endl;
// }
// }
// else {
//
// deviceid[i] = '\0';
// cout <<deviceid<<"is"<<endl;
// idend = true;
// }
// }
// }
system("pause");
return 0;
};