2021-07-15

介绍
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;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值