Перемещение по каталогам проектов для вызова или вызова другой программы или исполняемого файла в собственном процессе - PullRequest
1 голос
/ 05 августа 2020

Я работаю в Visual Studio 2017. В моем текущем решении у меня есть 2 активных проекта. Второй проект зависит от первого проекта, а мой второй проект - это мое стартовое приложение. Когда я запускаю или компилирую свой второй проект, уже есть скомпилированный исполняемый файл моего первого проекта, который находится в моем каталоге решений ...

Вот иерархия каталогов моих решений - проекты:

  • "SolutionName/Project1/"
    • Содержит исходный код для Project1
  • "SolutionName/Project2/"
    • Это содержит исходный код для Project2
  • "SolutionName/x64/"
    • Содержит версии x64:
  • "SolutionName/x64/Debug"
    • Содержит x64 отладочные сборки и исполняемые файлы
  • "SolutionName/x64/Release"
    • Сюда входят сборки выпуска x64 и исполняемые файлы

Когда я запустите приложение со вторым проектом в качестве моего запуска ... Код компилируется и работает нормально, однако, похоже, он не выполняет исполняемый файл из 1-го проекта ...

Вот мой файл main. cpp

#include <Windows.h>
#include <exception>
#include <stdio.h>
#include <tchar.h>
#include <cstdint>
#include <iostream>

uint32_t runProgram(LPCSTR lpApplicationName) {
    STARTUPINFOA si;
    PROCESS_INFORMATION pi;

    // Set the size of the structures
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    // Run the program
    CreateProcessA(
        lpApplicationName,  // the path
        NULL,               // Command line
        NULL,               // Process handle not inheritable
        NULL,               // Thread handle not inheritable
        FALSE,              // Set handle inheritance to FALSE
        CREATE_NEW_CONSOLE, // Opens file in seperate console
        NULL,               // Use parent's environment block
        NULL,               // Use parent's starting directory
        &si,                // Pointer to STARTUPINFO structure
        &pi                 // Pointer to PROCESS_INFORMATION structure
    );

    uint32_t cache_size = 0;

    WaitForSingleObject(pi.hProcess, INFINITE);

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    return cache_size;
}

int main() {
    try {
        const uint32_t cache_size = runProgram("CacheQuerry.exe");
        std::cout << cache_size << '\n';
    }
    catch (const std::exception& e) {
        std::cerr << e.what() << "\n\n";
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

Если я создаю свое решение в режиме отладки, оба исполняемых файла находятся в одном каталоге для отладки, и если я создам свое решение в режиме выпуска, обе версии моих исполняемых файлов снова будут в одном каталоге ...

Я получаю вывод 0 в консоли, поэтому я знаю, что runProgram() вызывается и возвращается, но я ожидаю, что будет открыта другая консоль с отображаемыми результатами из вызванной программы с ее собственным дескриптором консоли из своего собственного процесса. Однако я не вижу, чтобы его вызывали или вызывали. CacheQuerry.exe это мой 1-й проект, и он, похоже, не выполняется ...

Я немного новичок в этой части Windows API, поэтому я не уверен, что Я делаю это правильно ... Мне нужно, чтобы мой второй проект вызвал и запустил 1-й проект ... Это первая часть моего вопроса. Как только я решу эту проблему и узнаю, что проект 2 вызывает и выполняет проект 1, я задам следующий вопрос о том, как получить значение, которое вызываемый исполняемый файл возвращает при выходе ...

Ответы [ 2 ]

1 голос
/ 05 августа 2020

Помимо отсутствия обработки ошибок на CreateProcessA(), вы пытаетесь запустить CacheQuerry.exe, используя относительный путь , поэтому проблема, скорее всего, заключается в том, что текущий рабочий каталог вызывающего процесса - это не то, что вы ожидаете, в результате чего CreateFileA() не работает, если не может найти CacheQuerry.exe.

Вы должны никогда полагаться на относительную paths, всегда используйте вместо этого абсолютные пути!

Предполагая, что два EXE-файла находятся в одной папке, вы можете попробовать что-то вроде этого:

#include <Windows.h>
#include <shlwapi.h>
#include <cstdio>
#include <tchar.h>
#include <cstdint>
#include <iostream>
#include <string>
#include <sstream>

#pragma comment(lib, "Shlwapi.lib")

void ThrowWin32Error(const char *funcname, DWORD errCode) {
    std::ostringstream oss;
    oss << funcname << " failed.";
    if (errCode != 0) {
        oss << " Error " << errCode;
    }
    throw std::runtime_error(oss.str());
}

void CheckWin32Error(const char *funcname, bool result) {
    if (!result) ThrowWin32Error(funcname, 0);
}

void CheckWin32ErrorCode(const char *funcname, bool result) {
    if (!result) ThrowWin32Error(funcname, GetLastError());
}

std::string getPathToCacheQuerry() {
    char path[MAX_PATH+16] = {};

    DWORD size = GetModuleFileNameA(NULL, path, MAX_PATH);
    if (size == MAX_PATH)
        ThrowWin32Error("GetModuleFileNameA", ERROR_INSUFFICIENT_BUFFER);
    else
        CheckWin32ErrorCode("GetModuleFileNameA", size > 0);

    CheckWin32Error("PathRemoveFileSpecA",
        PathRemoveFileSpecA(path)
    );

    CheckWin32Error("PathAppendA",
        PathAppendA(path, "CacheQuerry.exe")
    );

    return path;
}


uint32_t runProgram(const std::string &ApplicationName) {
    STARTUPINFOA si;
    PROCESS_INFORMATION pi;

    // Set the size of the structures
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    // Run the program
    CheckWin32ErrorCode("CreateProcessA",
        CreateProcessA(
            ApplicationName.c_str(),// the path
            NULL,                   // Command line
            NULL,                   // Process handle not inheritable
            NULL,                   // Thread handle not inheritable
            FALSE,                  // Set handle inheritance to FALSE
            CREATE_NEW_CONSOLE,     // Opens file in seperate console
            NULL,                   // Use parent's environment block
            NULL,                   // Use parent's starting directory
            &si,                    // Pointer to STARTUPINFO structure
            &pi                     // Pointer to PROCESS_INFORMATION structure
        )
    );

    uint32_t cache_size = 0;

    WaitForSingleObject(pi.hProcess, INFINITE);

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    return cache_size;
}

int main() {
    try {
        std::string path = getPathToCacheQuerry();
        const uint32_t cache_size = runProgram(path);
        std::cout << cache_size << '\n';
    }
    catch (const std::exception& e) {
        std::cerr << e.what() << "\n\n";
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}
0 голосов
/ 05 августа 2020

Попробуйте использовать это вместо CreateProcess:

#include <iostream>
#include <windows.h>

int main() {
    ShellExecute(NULL, "open", "path\\to\\file.exe", NULL, NULL, SW_SHOWDEFAULT);
}
...