Grant
Grant

Reputation: 684

why does ::CreateProcess(path,cmd,...) fail with error "File not found"?

I am trying to have a C++ program call an already made C# program to run in the background.

STARTUPINFO info = {sizeof(info)};
PROCESS_INFORMATION processinfo;
DWORD error1 = GetLastError();
bool x = ::CreateProcess((LPCWSTR)"C:\Convert_Shrink.exe", GetCommandLine(), NULL, NULL, false, 0,NULL,NULL, &info, &processinfo);
DWORD error = GetLastError();

error1 is 0 before CreateProcess error is 2 after CreateProcess

error 2:

ERROR_FILE_NOT_FOUND 2 (0x2) The system cannot find the file specified.

I've changed it to C:\ \ incase they were checking for escape sequences but I still get error 2 and I'm not sure why.

Upvotes: 1

Views: 13233

Answers (4)

Felix
Felix

Reputation: 1384

Just for the record. CreateProcessAsUser calls SearchPath internally. SearchPath uses the File System Redirector https://msdn.microsoft.com/en-us/library/windows/desktop/aa384187%28v=vs.85%29.aspx

So, if you are running a 32 bit app under WOW64 and you ask for a process using an exe in system32 dir e.g. "c:\windows\system32\myapp.exe", CreateProcessAsUser will look in syswow64 instead e.g."c:\windows\syswow64\myapp.exe". If your exe is not there you'll get a "file not found error".

Upvotes: 2

Ben Voigt
Ben Voigt

Reputation: 283624

You can:

  • Use CreateProcessA to match your ANSI file path:

    bool x = ::CreateProcessA("C:\\Convert_Shrink.exe", GetCommandLineA(), NULL, NULL, false, 0,NULL,NULL, &info, &processinfo);
    

* Provide a file path which matches the string format required by your Unicode settings:

    bool x = ::CreateProcess(_T("C:\\Convert_Shrink.exe"), GetCommandLine(), NULL, NULL, false, 0,NULL,NULL, &info, &processinfo);

or

  • Use CreateProcessW so you can pass a Unicode filepath (supports extended characters):

    bool x = ::CreateProcessW(L"C\\\Convert_Shrink.exe", GetCommandLineW(), NULL, NULL, false, 0,NULL,NULL, &info, &processinfo);
    

(as @dolphy noted, the argument has to be a writable string)

  • Provide a file path which matches the string format required by your Unicode settings:

    #if UNICODE
    std::wstring exename =
    #else
    const char* exename =
    #endif
        _T("C:\\Convert_Shrink.exe");
    bool x = ::CreateProcess(&exename[0], GetCommandLine(), NULL, NULL, false, 0,NULL,NULL, &info, &processinfo);
    

or

  • Use CreateProcessW so you can pass a Unicode filepath (supports extended characters):

    wchar_t exename[] = L"C:\\Convert_Shrink.exe";
    bool x = ::CreateProcessW(exename, GetCommandLineW(), NULL, NULL, false, 0,NULL,NULL, &info, &processinfo);
    

Upvotes: 5

Loduwijk
Loduwijk

Reputation: 1977

I just looked up GetCommandLine(), and MSDN states that it gets the command line for the current process. MSDN entry for CreateProcess() states that the second argument is the command line command that you want to be executed, if I'm reading it correctly. So you are essentially telling CreateProcess() to run another instance of the C++ program, not the C# program.

(edit) Actually, upon closer inspection, the CreateProcess() documentation does not seem to clearly explain what will happen if you supply both the first and second arguments. It says that the first specifies the module and the second specifies the command line. What's the diff?

Sorry for the inconclusive answer, I would convert this answer into a couple of comments on your question if I could.

Upvotes: 0

dolphy
dolphy

Reputation: 6498

Have you tried casting the string to LPCTSTR instead:

bool x = ::CreateProcess((LPCTSTR)"C:\Convert_Shrink.exe", GetCommandLine(), NULL, NULL, false, 0,NULL,NULL, &info, &processinfo); 

From Microsoft:

The Unicode version of this function, CreateProcessW, can modify the contents 
of this string. Therefore, this parameter cannot be a pointer to read-only 
memory (such as a const variable or a literal string). If this parameter is a 
constant string, the function may cause an access violation.

Upvotes: -2

Related Questions