-1

I'm working on Windows, using Visual studio 2019 community. I'm writing an MFC application in c++ and I'm trying to pass the following command line txt2pdf -i\".\textfile.txt\" -o\".\pdfout.pdf\" to the cmd.

For this pupose, I'm using CreateProcess() function, the documentation is here and this is an example of usage. My code is given below:

void CMFCApplication4Dlg::OnBnClickedButton1()
{
    PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter

    STARTUPINFO StartupInfo; //This is an [in] parameter

    ZeroMemory(&StartupInfo, sizeof(StartupInfo));
    StartupInfo.cb = sizeof StartupInfo; //Only compulsory field

    LPWSTR cmd_args = (LPWSTR)"txt2pdf.exe - i\".textfile.txt\" -o\".pdfout.pdf\"";

    if (!CreateProcess(NULL, cmd_args, NULL, NULL, FALSE, 0, NULL,
        NULL, &StartupInfo, &ProcessInfo))
    {
        WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
        CloseHandle(ProcessInfo.hThread);
        CloseHandle(ProcessInfo.hProcess);

        MessageBox(L"Success");
    }
    else
    {
        MessageBox(L"The process could not be started...");
    }
}

I've seen many solutions and examples on how to call CreateProcess() function, I've listed them below, but for some reason, none of them works, I always get the same error message:

Exception thrown at 0x759FF4BB (KernelBase.dll) in MFCApplication4.exe: 0xC0000005: Access violation writing location 0x00257960.

and when I look it up online, I don't find anything that is related to my code.

Other solutions I've tried:

  1. solution01
  2. solution02
  3. solution03
  4. solution04

How can I fix my code?

halfer
  • 19,824
  • 17
  • 99
  • 186
E. Ginzburg
  • 253
  • 2
  • 9
  • It seems like you do not understand your code. Contrary to your question, you aren't actually passing anything to the command processor (and you shouldn't either). Regardless, *"it doesn't work"* is not an actionable problem statement. Do note that your call to `CreateProcess` is wrong. The second argument needs to be a pointer to a **non-const** character string. – IInspectable Aug 29 '21 at 07:34
  • The error you observe is the result of violating the [documented](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw) contract: *"`lpCommandLine`: \[...\] 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."* – IInspectable Aug 29 '21 at 07:52
  • There are *lots* of other issues, like using `\t` (which encodes a TAB character), or relying on the current working directory. – IInspectable Aug 29 '21 at 07:54
  • @IInspectable thank you for your comment, I've updated the code, but I still get the same error. I'm having trouble passing the parameters, perhaps I don't fully understand how to make the string non-const and how to encode the `"` characters which are needed for the cmd but are problematic when used in the code. is there any chance you could advise me on how to pass those parameters? thank you – E. Ginzburg Aug 29 '21 at 08:03
  • Blindly casting away const-ness isn't going to solve anything. It's merely silencing the compiler, tricking it into accepting a lie. It's still a lie, and the OS will let you know. Also, changing `.\t` to `.t` isn't what you meant to do. You should have escaped the backslash instead, e.g. `.\\t`. Though, again, relying on the current working directory isn't going to be a tractable solution to any problem. If you want to solve your access violation, there are lots of Q&A's here that go over that already. – IInspectable Aug 29 '21 at 08:06
  • Use absolute path. See this working video tutorial on CreateProcess: https://youtu.be/v6I6tGvuw5c – seccpur Aug 29 '21 at 08:11
  • This question is closed now, so I'm answering here: 1) Put the cmdline in a writable string (char array), probably this causes the AV 2) If the function succeeds call `GetExitCodeProcess(ProcessInfo.hProcess)` after `WaitForSingleObject()` to get its return code, eg if conversion was successful 3) Better use fully qualified paths for the exe as well as both the input and output files and don't rely on the "current" directory 4) file-paths containing spaces must be enclosed in double quotations marks ("") 5) If the function fails call `GetLastError()`. – Constantine Georgiou Aug 29 '21 at 09:44
  • 6) Try executing the cmdline from a shortcut first, to see how the app works. – Constantine Georgiou Aug 29 '21 at 09:44
  • 7) Forgot to mention, you can use the `CREATE_NO_WINDOW` flag in the `dwCreationFlags` parameter, to avoid popping CMD windows when the app runs. – Constantine Georgiou Aug 29 '21 at 09:56

1 Answers1

0

as documented, if lpApplicationName is null, then it's provided in lpCommandLine
and it's white-space delimeted

CreateProcess(NULL, _T(" txt2pdf -i\".\textfile.txt\" -o\".\pdfout.pdf\""), // <-- white space is the first char

which means that the appName is missing only arguments
remove white space from the beginning of args
provide lpApplicationName first then white space then arguments as follows:

CreateProcess(NULL, _T("txt2pdf.exe -i\".\textfile.txt\" -o\".\pdfout.pdf\""),
// lpApplicationName----^^^^^^^^^  ^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// white space delimiter-----------|  |
// arguments--------------------------|

make sure that lpCommandLine is non-const, because the function can modify it

TCHAR cmd_args[] = _T("txt2pdf.exe -i\".\textfile.txt\" -o\".\pdfout.pdf\"");
CreateProcess(NULL, cmd_args,
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Errorist
  • 224
  • 2
  • 6
  • thank you for your answer, unfortunately I'm till getting the same type of error which states `Exception thrown at 0x759FF4BB (KernelBase.dll) in MFCApplication4.exe: 0xC0000005: Access violation writing location 0x00098F4E.` perhaps you have any idea what does that mean? – E. Ginzburg Aug 29 '21 at 07:54
  • @E.Ginzburg are you compiling for UNICODE? Given your original example is typecasting to `LPWSTR`, I suspect you are, in which case Errorist's example shouldn't even compile in C++ as the 2nd parameter of `CreateProcess()` needs to be a pointer to a **writable** memory buffer, not a string literal. – Remy Lebeau Aug 29 '21 at 21:44
  • @E.Ginzburg Read the [documentation](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw): "*The Unicode version of this function, CreateProcessW, can modify the contents of this [lpCommandLine] string. **Therefore, this [lpCommandLine] parameter cannot be a pointer to read-only memory (such as a const variable or a literal string).** If this [lpCommandLine] parameter is a constant string, the function may cause an access violation."* – Remy Lebeau Aug 29 '21 at 21:49