Navigating through project directories to call or invoke another program or executable within its own process

牧云@^-^@ 提交于 2020-08-10 13:07:55

问题


I'm working in Visual Studio 2017. In my current solution, I have 2 active projects. The 2nd project depends on the 1st project and my 2nd project is my startup application. When I run or compile my 2nd project, there is already a compiled executable of my 1st project that is within my solutions directory...

Here is the directory hierarchy of my solutions - projects:

  • "SolutionName/Project1/"
    • This contains the source code for Project1
  • "SolutionName/Project2/"
    • This contains the source code for Project2
  • "SolutionName/x64/"
    • This contains the x64 versions:
  • "SolutionName/x64/Debug"
    • This contains the x64 debug builds and executables
  • "SolutionName/x64/Release"
    • This contains the x64 release builds and executables

When I run the application with the 2nd project as my startup... The code compiles and runs fine, however, it doesn't appear to be executing the executable from the 1st project...

Here is my 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;
}

If I build my solution in Debug mode, both executables are in the same directory for Debug and if I build my solution in Release mode, again both release versions of my executables are in the same directory...

I am getting an output of 0 in the console so I know that runProgram() is being called and returning, but I'm expecting another console to be opened with the displayed results from the invoked program with its own console handle from its own process. However, I'm not seeing it being invoked or called. CacheQuerry.exe which is my 1st project and it doesn't seem to be executed...

I'm a bit new to this part of the Windows API, so I'm not sure if I'm doing this correctly... I need for my second project to call and run the 1st project... This is part 1 of my question. Once I get this resolved and know that project 2 is calling and executing project 1, then I'll ask my next question about how to retrieve the value that the called executable returns upon exit...


回答1:


Aside from the lack of any error handling on CreateProcessA(), you are trying to launch CacheQuerry.exe using a relative path, so the issue is most likely that the current working directory of the calling process is not what you are expecting it to be, causing CreateFileA() to fail if it can't find CacheQuerry.exe.

You should never rely on relative paths, always use absolute paths instead!

Assuming the two EXE files are in the same folder, then you can try something like this:

#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;
}



回答2:


Try with this instead of CreateProcess:

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

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


来源:https://stackoverflow.com/questions/63256524/navigating-through-project-directories-to-call-or-invoke-another-program-or-exec

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!