I have been trying to call adb from a C++ app and read its output, without success. adb is present on PATH.
The ReadFile call never reads anything, even if I wait.
GetLastError() returns 109 ERROR_BROKEN_PIPE.
I have tried all the solutions proposed in all existing StackOverflow questions on this matter, without any success.
Even trying to capture output from cmd /c echo Hello World doesn't work.
Code:
#include <array>
#include <string>
#include <windows.h>
int main() {
std::string adbConnectCommand = "adb connect localhost:5555";
STARTUPINFO startupInfo;
SECURITY_ATTRIBUTES secAttr;
PROCESS_INFORMATION procInfo;
HANDLE stdoutReadHandle = NULL;
HANDLE stdoutWriteHandle = NULL;
ZeroMemory(&secAttr, sizeof(secAttr));
secAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
secAttr.bInheritHandle = TRUE;
secAttr.lpSecurityDescriptor = NULL;
// Create a pipe for the child process's STDOUT
if (!CreatePipe(&stdoutReadHandle, &stdoutWriteHandle, &secAttr, 0))
return 2; // error
// Ensure the read handle to the pipe for STDOUT is not inherited
if (!SetHandleInformation(stdoutReadHandle, HANDLE_FLAG_INHERIT, 0))
return 2; // error
ZeroMemory(&startupInfo, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
startupInfo.hStdError = &stdoutWriteHandle;
startupInfo.hStdOutput = &stdoutWriteHandle;
startupInfo.dwFlags |= STARTF_USESTDHANDLES;
ZeroMemory(&procInfo, sizeof(procInfo));
// Start the child process
if (CreateProcessA(NULL, // No module name (use command line)
(TCHAR*)adbConnectCommand.c_str(), // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
TRUE, // Set handle inheritance
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&startupInfo, // Pointer to STARTUPINFO structure
&procInfo) // Pointer to PROCESS_INFORMATION structure
)
{
// Close the handles we don't need so we can read from stdoutReadHandle
CloseHandle(procInfo.hProcess);
CloseHandle(procInfo.hThread);
CloseHandle(stdoutWriteHandle);
std::array<char, 512> buffer;
std::string adbConnectOutput;
while(ReadFile(stdoutReadHandle, buffer.data(), buffer.size(), NULL, NULL))
adbConnectOutput += buffer.data();
CloseHandle(stdoutReadHandle);
if (adbConnectOutput.find("connected to localhost:5555") == std::string::npos)
return 1; // not found
m_Connected = true;
return 0; // success
}
return 2; // error
}
In this code:
HANDLEis defined as avoid*, so any pointer can be assigned to it. But not every pointer is a validHANDLEvalue. In this case,stdoutWriteHandleis aHANDLEvariable and can be assigned as-is tohStdErrorandhStdOutput, so you need to drop the&s as they don't belong there, eg:That being said, there are some other problems with your code.
In this code:
TCHAR*is the wrong type to cast to here.CreateProcessA()expectsLPSTR(akachar*) instead, butTCHAR*may or may not bechar*depending on your project configuration. So use the proper type, eg:However, you should be using the C++-style
const_castinstead of a C-style cast, eg:Alternatively, use
std::string::data()(C++17 and later) orstd::string::operator[]instead, eg:And, in this code:
The data that
ReadFile()writes to your buffer is not null-terminated, but you are appending a null-terminatedchar*pointer to your outputstd::string. You need to pay attention to the actual size thatReadFile()reports to you, especially since it doesn't require a null terminator, and it may be smaller than what you asked for, eg: