std::string msgDebugEngineComResult(HRESULT hr) { switch (hr) { case S_OK: return std::string("S_OK"); case S_FALSE: return std::string("S_FALSE"); case E_FAIL: break; case E_INVALIDARG: return std::string("E_INVALIDARG"); case E_NOINTERFACE: return std::string("E_NOINTERFACE"); case E_OUTOFMEMORY: return std::string("E_OUTOFMEMORY"); case E_UNEXPECTED: return std::string("E_UNEXPECTED"); case E_NOTIMPL: return std::string("E_NOTIMPL"); } if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) return std::string("ERROR_ACCESS_DENIED");; if (hr == HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT)) return std::string("STATUS_CONTROL_C_EXIT"); return std::string("E_FAIL ") + winErrorMessage(HRESULT_CODE(hr)); }
bool VirtualSerialDevice::waitForBytesWritten(int msecs) { QMutexLocker locker(&lock); if (pendingWrites.count() == 0) return false; if (QThread::currentThread() != thread()) { // Wait for signal from main thread unsigned long timeout = msecs; if (msecs == -1) timeout = ULONG_MAX; if (waiterForBytesWritten == NULL) waiterForBytesWritten = new QWaitCondition; return waiterForBytesWritten->wait(&lock, timeout); } DWORD waitTime = msecs; if (msecs == -1) waitTime = INFINITE; // Ok these are probably bitwise the same, but just to prove I've thought about it... DWORD result = WaitForSingleObject(d->writeOverlapped.hEvent, waitTime); // Do I need WaitForSingleObjectEx and worry about alertable states? if (result == WAIT_TIMEOUT) { return false; } else if (result == WAIT_OBJECT_0) { DWORD bytesWritten; BOOL ok = GetOverlappedResult(d->portHandle, &d->writeOverlapped, &bytesWritten, TRUE); if (!ok) { setErrorString(tr("An error occurred while syncing on waitForBytesWritten for %1: %2"). arg(portName, winErrorMessage(GetLastError()))); return false; } Q_ASSERT(bytesWritten == (DWORD)pendingWrites.first().length()); doWriteCompleted(locker); return true; } else { setErrorString(QString("An error occurred in waitForBytesWritten() for %1: %2"). arg(portName, winErrorMessage(GetLastError()))); return false; } }
qint64 VirtualSerialDevice::writeNextBuffer(QMutexLocker& locker) { Q_UNUSED(locker) // Must be locked on entry qint64 bufLen = pendingWrites[0].length(); BOOL ok = WriteFile(d->portHandle, pendingWrites[0].constData(), bufLen, NULL, &d->writeOverlapped); if (ok || GetLastError() == ERROR_IO_PENDING) { // Apparently it can return true for a small asynchronous write... // Hopefully it still gets signalled in the same way! // Wait for signal via writeCompleted return bufLen; } else { setErrorString(tr("An error occurred while writing to %1: %2"). arg(portName, winErrorMessage(GetLastError()))); pendingWrites.removeFirst(); return -1; } }
bool TrkDevice::write(const QByteArray &data, QString *errorMessage) { if (verbose()) logMessage("XWRITE " + data.toHex()); #ifdef Q_OS_WIN DWORD charsWritten; if (!WriteFile(d->hdevice, data.data(), data.size(), &charsWritten, NULL)) { *errorMessage = QString::fromLatin1("Error writing data: %1").arg(winErrorMessage(GetLastError())); return false; } FlushFileBuffers(d->hdevice); return true; #else if (d->file.write(data) == -1 || !d->file.flush()) { *errorMessage = QString::fromLatin1("Cannot write: %1").arg(d->file.errorString()); return false; } return true; #endif }
qint64 VirtualSerialDevice::readData(char *data, qint64 maxSize) { QMutexLocker locker(&lock); // We do our reads synchronously OVERLAPPED readOverlapped; memset(&readOverlapped, 0, sizeof(OVERLAPPED)); DWORD bytesRead; BOOL done = ReadFile(d->portHandle, data, maxSize, &bytesRead, &readOverlapped); if (done) return (qint64)bytesRead; if (GetLastError() == ERROR_IO_PENDING) { // Note the TRUE to wait for the read to complete done = GetOverlappedResult(d->portHandle, &readOverlapped, &bytesRead, TRUE); if (done) return (qint64)bytesRead; } // If we reach here an error has occurred setErrorString(tr("An error occurred while reading from %1: %2"). arg(portName, winErrorMessage(GetLastError()))); return -1; }
QTCREATOR_UTILS_EXPORT QString winGetDLLVersion(WinDLLVersionType t, const QString &name, QString *errorMessage) { // Resolve required symbols from the version.dll typedef DWORD (APIENTRY *GetFileVersionInfoSizeProtoType)(LPCTSTR, LPDWORD); typedef BOOL (APIENTRY *GetFileVersionInfoWProtoType)(LPCWSTR, DWORD, DWORD, LPVOID); typedef BOOL (APIENTRY *VerQueryValueWProtoType)(const LPVOID, LPWSTR lpSubBlock, LPVOID, PUINT); const char *versionDLLC = "version.dll"; QLibrary versionLib(QLatin1String(versionDLLC), 0); if (!versionLib.load()) { *errorMessage = msgCannotLoad(versionDLLC, versionLib.errorString()); return QString(); } // MinGW requires old-style casts GetFileVersionInfoSizeProtoType getFileVersionInfoSizeW = (GetFileVersionInfoSizeProtoType)(versionLib.resolve("GetFileVersionInfoSizeW")); GetFileVersionInfoWProtoType getFileVersionInfoW = (GetFileVersionInfoWProtoType)(versionLib.resolve("GetFileVersionInfoW")); VerQueryValueWProtoType verQueryValueW = (VerQueryValueWProtoType)(versionLib.resolve("VerQueryValueW")); if (!getFileVersionInfoSizeW || !getFileVersionInfoW || !verQueryValueW) { *errorMessage = msgCannotResolve(versionDLLC); return QString(); } // Now go ahead, read version info resource DWORD dummy = 0; const LPCTSTR fileName = reinterpret_cast<LPCTSTR>(name.utf16()); // MinGWsy const DWORD infoSize = (*getFileVersionInfoSizeW)(fileName, &dummy); if (infoSize == 0) { *errorMessage = QString::fromLatin1("Unable to determine the size of the version information of %1: %2").arg(name, winErrorMessage(GetLastError())); return QString(); } QByteArray dataV(infoSize + 1, '\0'); char *data = dataV.data(); if (!(*getFileVersionInfoW)(fileName, dummy, infoSize, data)) { *errorMessage = QString::fromLatin1("Unable to determine the version information of %1: %2").arg(name, winErrorMessage(GetLastError())); return QString(); } VS_FIXEDFILEINFO *versionInfo; const LPCWSTR backslash = TEXT("\\"); UINT len = 0; if (!(*verQueryValueW)(data, const_cast<LPWSTR>(backslash), &versionInfo, &len)) { *errorMessage = QString::fromLatin1("Unable to determine version string of %1: %2").arg(name, winErrorMessage(GetLastError())); return QString(); } QString rc; switch (t) { case WinDLLFileVersion: QTextStream(&rc) << HIWORD(versionInfo->dwFileVersionMS) << '.' << LOWORD(versionInfo->dwFileVersionMS); break; case WinDLLProductVersion: QTextStream(&rc) << HIWORD(versionInfo->dwProductVersionMS) << '.' << LOWORD(versionInfo->dwProductVersionMS); break; } return rc; }
QString msgFunctionFailed(const char *f, unsigned long error) { return QString::fromLatin1("\"%1\" failed: %2").arg(QLatin1String(f), winErrorMessage(error)); }
bool getPDBFiles(const QString &peExecutableFileName, QStringList *rc, QString *errorMessage) { HANDLE hFile = NULL; HANDLE hFileMap = NULL; void *fileMemory = 0; bool success = false; rc->clear(); do { // Create a memory mapping of the file hFile = CreateFile(reinterpret_cast<const WCHAR*>(peExecutableFileName.utf16()), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE || hFile == NULL) { *errorMessage = QString::fromLatin1("Cannot open '%1': %2").arg(peExecutableFileName, winErrorMessage(GetLastError())); break; } hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if (hFileMap == NULL) { *errorMessage = QString::fromLatin1("Cannot create file mapping of '%1': %2").arg(peExecutableFileName, winErrorMessage(GetLastError())); break; } fileMemory = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0); if (!fileMemory) { *errorMessage = QString::fromLatin1("Cannot map '%1': %2").arg(peExecutableFileName, winErrorMessage(GetLastError())); break; } IMAGE_NT_HEADERS *ntHeaders = getNtHeader(fileMemory, errorMessage); if (!ntHeaders) break; int debugSectionCount; IMAGE_DEBUG_DIRECTORY *debugDir; if (!getDebugDirectory(ntHeaders, fileMemory, &debugDir, &debugSectionCount, errorMessage)) return false; if (debugSectionCount) collectPDBfiles(fileMemory, debugDir, debugSectionCount, rc); success = true; } while(false); if (fileMemory) UnmapViewOfFile(fileMemory); if (hFileMap != NULL) CloseHandle(hFileMap); if (hFile != NULL && hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); return success; }
bool VirtualSerialDevice::open(OpenMode mode) { Q_ASSERT(QThread::currentThread() == thread()); if (isOpen()) return true; d->portHandle = CreateFileA(windowsPortName(portName).toAscii(), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (d->portHandle == INVALID_HANDLE_VALUE) { setErrorString(tr("The port %1 could not be opened: %2"). arg(portName, winErrorMessage(GetLastError()))); return false; } DCB commState; memset(&commState, 0, sizeof(DCB)); commState.DCBlength = sizeof(DCB); bool ok = GetCommState(d->portHandle, &commState); if (ok) { commState.BaudRate = CBR_115200; commState.fBinary = TRUE; commState.fParity = FALSE; commState.fOutxCtsFlow = FALSE; commState.fOutxDsrFlow = FALSE; commState.fInX = FALSE; commState.fOutX = FALSE; commState.fNull = FALSE; commState.fAbortOnError = FALSE; commState.fDsrSensitivity = FALSE; commState.fDtrControl = DTR_CONTROL_DISABLE; commState.ByteSize = 8; commState.Parity = NOPARITY; commState.StopBits = ONESTOPBIT; ok = SetCommState(d->portHandle, &commState); } if (!ok) { qWarning("%s setting comm state", qPrintable(winErrorMessage(GetLastError()))); } // http://msdn.microsoft.com/en-us/library/aa363190(v=vs.85).aspx says this means // "the read operation is to return immediately with the bytes that have already been received, even if no bytes have been received" COMMTIMEOUTS timeouts; timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.ReadTotalTimeoutConstant = 0; timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = 0; SetCommTimeouts(d->portHandle, &timeouts); d->writeOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); d->writeCompleteNotifier = new QWinEventNotifier(d->writeOverlapped.hEvent, this); connect(d->writeCompleteNotifier, SIGNAL(activated(HANDLE)), this, SLOT(writeCompleted())); // This is how we implement readyRead notifications d->commEventOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); d->commEventNotifier = new QWinEventNotifier(d->commEventOverlapped.hEvent, this); connect(d->commEventNotifier, SIGNAL(activated(HANDLE)), this, SLOT(commEventOccurred())); if (!SetCommMask(d->portHandle, EV_RXCHAR)) { // What to do? qWarning("%s: Could not set comm mask, err=%d", Q_FUNC_INFO, (int)GetLastError()); } bool result = WaitCommEvent(d->portHandle, &d->commEventMask, &d->commEventOverlapped); Q_ASSERT(result == false); // Can't see how it would make sense to be anything else... (void)result; // For release build if (GetLastError() != ERROR_IO_PENDING) { setErrorString(tr("An error occurred while waiting for read notifications from %1: %2"). arg(portName, winErrorMessage(GetLastError()))); close(); return false; } ok = QIODevice::open(mode); if (!ok) close(); return ok; }
std::string winErrorMessage() { return winErrorMessage(GetLastError()); }
bool Win_WindowManager::sendCloseEventImpl(const QString &winId, Q_PID, QString *errorMessage) { // Convert window back. quintptr winIdIntPtr; QTextStream str(const_cast<QString*>(&winId), QIODevice::ReadOnly); str.setIntegerBase(16); str >> winIdIntPtr; if (str.status() != QTextStream::Ok) { *errorMessage = QString::fromLatin1("Invalid win id %1.").arg(winId); return false; } if (!PostMessage(reinterpret_cast<HWND>(winIdIntPtr), WM_CLOSE, 0, 0)) { *errorMessage = QString::fromLatin1("Cannot send event to 0x%1: %2").arg(winIdIntPtr, 0, 16).arg(winErrorMessage(GetLastError())); return false; } return true; }
// Read a PE executable and determine dependent libraries, word size // and debug flags. bool readPeExecutable(const QString &peExecutableFileName, QString *errorMessage, QStringList *dependentLibrariesIn, unsigned *wordSizeIn, bool *isDebugIn, bool isMinGW) { bool result = false; HANDLE hFile = NULL; HANDLE hFileMap = NULL; void *fileMemory = 0; if (dependentLibrariesIn) dependentLibrariesIn->clear(); if (wordSizeIn) *wordSizeIn = 0; if (isDebugIn) *isDebugIn = false; do { // Create a memory mapping of the file hFile = CreateFile(reinterpret_cast<const WCHAR*>(peExecutableFileName.utf16()), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE || hFile == NULL) { *errorMessage = QString::fromLatin1("Cannot open '%1': %2").arg(peExecutableFileName, winErrorMessage(GetLastError())); break; } hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if (hFileMap == NULL) { *errorMessage = QString::fromLatin1("Cannot create file mapping of '%1': %2").arg(peExecutableFileName, winErrorMessage(GetLastError())); break; } fileMemory = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0); if (!fileMemory) { *errorMessage = QString::fromLatin1("Cannot map '%1': %2").arg(peExecutableFileName, winErrorMessage(GetLastError())); break; } const IMAGE_NT_HEADERS *ntHeaders = getNtHeader(fileMemory, errorMessage); if (!ntHeaders) break; const unsigned wordSize = ntHeaderWordSize(ntHeaders); if (wordSizeIn) *wordSizeIn = wordSize; bool debug = false; if (wordSize == 32) { const IMAGE_NT_HEADERS32 *ntHeaders32 = reinterpret_cast<const IMAGE_NT_HEADERS32 *>(ntHeaders); if (!isMinGW) { debug = ntHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; } else { // Use logic that's used e.g. in objdump / pfd library debug = !(ntHeaders32->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED); } if (dependentLibrariesIn) *dependentLibrariesIn = readImportSections(ntHeaders32, fileMemory, errorMessage); } else { const IMAGE_NT_HEADERS64 *ntHeaders64 = reinterpret_cast<const IMAGE_NT_HEADERS64 *>(ntHeaders); if (!isMinGW) { debug = ntHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; } else { // Use logic that's used e.g. in objdump / pfd library debug = !(ntHeaders64->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED); } if (dependentLibrariesIn) *dependentLibrariesIn = readImportSections(ntHeaders64, fileMemory, errorMessage); } if (isDebugIn) *isDebugIn = debug; result = true; if (optVerboseLevel > 1) std::wcout << __FUNCTION__ << ": " << peExecutableFileName << ' ' << wordSize << " bit, debug: " << debug << '\n'; } while (false); if (fileMemory) UnmapViewOfFile(fileMemory); if (hFileMap != NULL) CloseHandle(hFileMap); if (hFile != NULL && hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); return result; }
// runProcess: Run a command line process (replacement for QProcess which // does not exist in the bootstrap library). bool runProcess(const QString &binary, const QStringList &args, const QString &workingDirectory, unsigned long *exitCode, QByteArray *stdOut, QByteArray *stdErr, QString *errorMessage) { if (exitCode) *exitCode = 0; STARTUPINFO si; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); STARTUPINFO myInfo; GetStartupInfo(&myInfo); si.hStdInput = myInfo.hStdInput; si.hStdOutput = myInfo.hStdOutput; si.hStdError = myInfo.hStdError; PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); const QChar backSlash = QLatin1Char('\\'); QString nativeWorkingDir = QDir::toNativeSeparators(workingDirectory.isEmpty() ? QDir::currentPath() : workingDirectory); if (!nativeWorkingDir.endsWith(backSlash)) nativeWorkingDir += backSlash; if (stdOut) { si.hStdOutput = createInheritableTemporaryFile(); if (si.hStdOutput == INVALID_HANDLE_VALUE) { if (errorMessage) *errorMessage = QStringLiteral("Error creating stdout temporary file"); return false; } si.dwFlags |= STARTF_USESTDHANDLES; } if (stdErr) { si.hStdError = createInheritableTemporaryFile(); if (si.hStdError == INVALID_HANDLE_VALUE) { if (errorMessage) *errorMessage = QStringLiteral("Error creating stderr temporary file"); return false; } si.dwFlags |= STARTF_USESTDHANDLES; } // Create a copy of the command line which CreateProcessW can modify. QString commandLine; appendToCommandLine(binary, &commandLine); foreach (const QString &a, args) appendToCommandLine(a, &commandLine); if (optVerboseLevel > 1) std::wcout << "Running: " << commandLine << '\n'; QScopedArrayPointer<wchar_t> commandLineW(new wchar_t[commandLine.size() + 1]); commandLine.toWCharArray(commandLineW.data()); commandLineW[commandLine.size()] = 0; if (!CreateProcessW(0, commandLineW.data(), 0, 0, /* InheritHandles */ TRUE, 0, 0, (wchar_t *)nativeWorkingDir.utf16(), &si, &pi)) { if (stdOut) CloseHandle(si.hStdOutput); if (stdErr) CloseHandle(si.hStdError); if (errorMessage) *errorMessage = QStringLiteral("CreateProcessW failed: ") + winErrorMessage(GetLastError()); return false; } WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hThread); if (exitCode) GetExitCodeProcess(pi.hProcess, exitCode); CloseHandle(pi.hProcess); if (stdOut) readTemporaryProcessFile(si.hStdOutput, stdOut); if (stdErr) readTemporaryProcessFile(si.hStdError, stdErr); return true; }
bool TrkDevice::open(const QString &port, QString *errorMessage) { close(); #ifdef Q_OS_WIN d->hdevice = CreateFile(port.toStdWString().c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == d->hdevice) { *errorMessage = QString::fromLatin1("Could not open device '%1': %2").arg(port, winErrorMessage(GetLastError())); return false; } d->timerId = startTimer(TimerInterval); return true; #else d->file.setFileName(port); if (!d->file.open(QIODevice::ReadWrite|QIODevice::Unbuffered)) { *errorMessage = QString::fromLatin1("Cannot open %1: %2").arg(port, d->file.errorString()); return false; } struct termios termInfo; if (tcgetattr(d->file.handle(), &termInfo) < 0) { *errorMessage = QString::fromLatin1("Unable to retrieve terminal settings: %1 %2").arg(errno).arg(QString::fromAscii(strerror(errno))); return false; } // Turn off terminal echo as not get messages back, among other things termInfo.c_cflag|=CREAD|CLOCAL; termInfo.c_lflag&=(~(ICANON|ECHO|ECHOE|ECHOK|ECHONL|ISIG)); termInfo.c_iflag&=(~(INPCK|IGNPAR|PARMRK|ISTRIP|ICRNL|IXANY)); termInfo.c_oflag&=(~OPOST); termInfo.c_cc[VMIN]=0; termInfo.c_cc[VINTR] = _POSIX_VDISABLE; termInfo.c_cc[VQUIT] = _POSIX_VDISABLE; termInfo.c_cc[VSTART] = _POSIX_VDISABLE; termInfo.c_cc[VSTOP] = _POSIX_VDISABLE; termInfo.c_cc[VSUSP] = _POSIX_VDISABLE; if (tcsetattr(d->file.handle(), TCSAFLUSH, &termInfo) < 0) { *errorMessage = QString::fromLatin1("Unable to apply terminal settings: %1 %2").arg(errno).arg(QString::fromAscii(strerror(errno))); return false; } d->timerId = startTimer(TimerInterval); return true; #endif }