1

I am trying to create a shell that allows a user to input "ping" commands and use CreateProcess() to execute the command based on user input. I am running into trouble getting the ping command to work when dealing with variables. For example the code below works just fine as long as I have the L in front of the string. However, the string has to be given by user input so after some research I ran across a possible substitution of the L cast in the form of a wchar_t variable.

if (strcmp(buffer, "ping") == 0 || strcmp(buffer, "ping &") == 0){
        LPCTSTR path = L"C:\\Windows\\System32\\PING.exe";
        LPTSTR link = L"-t www.yahoo.com";
        CreateProcess(path,
            link,
            NULL,
            NULL,
            0,
            0,
            NULL,
            NULL,
            &start,
            &info);
        if (strcmp(buffer, "ping") == 0){
            WaitForSingleObject(info.hProcess, INFINITE);
        }
        CloseHandle(info.hProcess);
        CloseHandle(info.hThread);

        printf("MyShell: ");
        scanf("%s", buffer);

If I do this change, it stops working (console crashes, no output).

        wchar_t wideC = "-t www.yahoo.com";
        LPCTSTR path = L"C:\\Windows\\System32\\PING.exe";
        LPTSTR link = wideC;

I've tried casting different types of variables both in the CreateProcess() arguments and outside. I don't know what else to do. How can I get the user scanf() into a variable that will work as an argument for creating a process?

TImmuh
  • 57
  • 1
  • 2
  • 10
  • Do you really believe that *"CreateProcess() doesn't work"*. You might consider how unlikely that is before asserting it quite so prominently. Clearly *your code" does not work - `CreatePorcess()' is fine - garbage-in, garbage-out. – Clifford May 07 '14 at 04:03
  • I'd dispute the duplicate mark - that is not what he asked, and is not the only solution to the problem. The question can be read as *"How can I use an ANSI character set string argument with CreateProcess()?"* – Clifford May 07 '14 at 15:00
  • @Clifford, if you think the question should be phrased like that.... edit it? – Tetsujin no Oni May 07 '14 at 15:20
  • @TetsujinnoOni : I'd rather give the OP the opportunity to do that than put words in his mouth. It is in his interest to have his question aired, not mine. – Clifford May 07 '14 at 16:56
  • @Clifford: But it's definitively in SO's interest to have question quality higher. If editing the text of the title improves that, I think it's worth the effort to edit and is not putting words in the OPs mouth if their question can be reduced to an accurate statement of the issue. – Tetsujin no Oni May 07 '14 at 17:36

1 Answers1

3

Here:

wchar_t wideC = "-t www.yahoo.com";

wideC has type wchar_t but is initialised with a literal string constant of type const char*.

This is corrected by:

const wchar_t* wideC = L"-t www.yahoo.com";
^^^^^        ^         ^

Though it is safer to use the Win32 portable string pointer types and the _T() macro in order to ensure type agreement and to support both Unicode and non-Unicode builds.

However the fatal flaw here is that the second argument of CreateProcess() cannot be a const - from the CreateProcess() documentation:

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.

Even if you don't use a const type, the literal string is still a const and cannot be modified without causing a runtime error. What you actually need is:

TCHAR wideC[] = _T( "-t www.yahoo.com" ) ;

or if you choose not to heed the portability advice:

wchar_t wideC[] = L"-t www.yahoo.com" ;

With respect to taking user input, perhaps wscanf() or better - _tscanf() are more appropriate? You cannot simply apply a cast to change string encoding, not least because strings are not first-class data types in C, and wide strings require additional storage space.

All that said, Win32 console mode has poor and ill-documented support for Unicode. It may be simpler to either enforce "ANSI" character mode for the entire build, or for this specific case use the explicitly ANSI string version of the function CreateProcessA() - CreateProcess() itslef is simply an alias for either CreateProcessW() or CreateProcessA() depending of the character set mode of the build.

    const char* path = "C:\\Windows\\System32\\PING.exe";
    char* link = "-t www.yahoo.com";
    CreateProcessA(path,
        link,
        NULL,
        NULL,
        0,
        0,
        NULL,
        NULL,
        &start,
        &info);
Clifford
  • 88,407
  • 13
  • 85
  • 165
  • Is there a way to use wscanf() to get input directly into wideC? wchar_t wideC[80]; printf("Command: ");wscanf(L"%ls", wideC); This is how I see it suggested in some online examples but in this case it doesn't work in CreateProcess(). – TImmuh May 07 '14 at 04:10
  • @TImmuh. If you want to ask a question about Unicode *input*, you really should post that as a separate question. As it stands the code in your question has errors independent of user input, and does not even have user input. It's hard to comment on code we cannot see. Note that Windows console mode does not fully support Unicode and is buggy and poorly documented - it is probably best avoided. This may help: http://alfps.wordpress.com/2011/11/22/unicode-part-1-windows-console-io-approaches/ – Clifford May 07 '14 at 04:22