Thread: CreateProcess with arguments

  1. #1
    Registered User
    Join Date
    Mar 2005
    Location
    Juneda
    Posts
    291

    CreateProcess with arguments

    Hello, I have problems using the 'CreateProcess' win32api function. I have been searching a bit here but I'm not able to make it run.

    The scenario: I have a very simple server program and I would like to enable it to work with php; I also have php5 (php-cgi.exe); I'm trying to call the php-cgi.exe to interpret the php files and dump the result on a temporary file in my server's temporary folder, but I need to know when the interpret have finishet the job. I have created a simple CreateProcess demo to test it (and to not post the whole code here) and that's it

    Code:
    #include <windows.h>
    #include <stdio.h>
    
    int main()
    {
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    char bff[512];
    
    //init the STARTUPINFO struct
    memset(&si,0,sizeof(si));
    si.cb=sizeof(si);
    
    //setup the command line arguments
    sprintf(bff,"-f \"C:\\Documents and Settings\\Aeiou\\SERVIDOR\\dirweb\\demo.php\" >\"C:\\Documents and Settings\\Aeiou\\SERVIDOR\\dirtmp\\out00.txt\");
    
    //create the proc with those args
    if(!CreateProcess("C:\\PHP\\php-cgi.exe",bff,NULL,NULL,0,0,NULL,NULL,&si,&pi))
        {
        printf("ERROR");
        getchar();
        return 0;
        }
    
    //wait till the proc ends
    WaitForSingleObject(pi.hProcess,INFINITE);
    
    //close all
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    getchar();
    return 0;
    }
    The "C:\\PHP\\php-cgi.exe" is the path to the php interpret, the "C:\\Documents and Settings\\Aeiou\\SERVIDOR\\dirweb\\demo.php" is the path to the client request (ok, for that sample is a fixed request file), and the "C:\\Documents and Settings\\Aeiou\\SERVIDOR\\dirtmp\\out00.txt" will be the dumped result.

    If I runt that code, instead of getting the output file, create it and dumping the result, it shows the result (or the errors if there's any) on the command prompt, so there's no output file. But if I work manually from the command prompt with files in the same folder as the php interpret it works well (obviously that isn't what I look for).

    I have also tried specifiyng the working directory

    Code:
    CreateProcess("C:\\PHP\\php-cgi.exe",bff,NULL,NULL,0,0,NULL,"C:\\PHP",&si,&pi)
    but the result is the same, it dumps the result to the command prompt and there's no output file. Finally I have also tryed to call the interpret with all the arguments (argument #0 = path to the interpret + arguments, argument#1 = null, etc...) but the result is an uppercase ERROR on the command line prompt.


    How can I do that?


    Thank's in advance,
    Niara

  2. #2
    Registered Abuser
    Join Date
    Jun 2006
    Location
    Toronto
    Posts
    591
    From first glance, I'd be willing to bet that output redirection via ">" doesn't work as intended unless using it directly from the console window (or at the very least, in the case of trying to specifiy it in the lpCommandLine argument of CreateProcess).
    According to STARTUPINFO, you can specify the STARTF_USESTDHANDLES flag in dwFlags to direct input/output/error to handles you supply. You could then try setting hStdOutput to a file you've opened through CreateFile (from your example, out00.txt).

    If CreateProcess in general is just being stubborn, you could also try using ShellExecuteEx, however this has a similar argument structure to CreateProcess, so would probably have similar limitations.

  3. #3
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    CreateProcess() doesn't understand I/O redirection ">".

    A simple solution would be to put the entire command into a batch file (.bat, .cmd) and CreateProcess() on the batch file. You may have to use "start /wait" so that the batch file doesn't "return" early.

    The more complicated solution is to do your own I/O redirection.

    [edit]Almost forgot the simplest of all, system(), which does understand I/O redirection.[/edit]

    gg
    Last edited by Codeplug; 09-06-2007 at 02:37 PM. Reason: more info

  4. #4
    Registered User
    Join Date
    Mar 2005
    Location
    Juneda
    Posts
    291
    Hello @nthony and Codeplug, thank's both for your time and help.

    @nthony: I didn't realized about that point on the STARTUPINFO struct, I'll have to try that. And I have already thought using the ShellExecute, but I'm not sure on how to wait till the proc ends (on the Win32 API Manual Ref. says that the 'WaitForSingleObject' function only works for 'CreateProcess' and for 'CreateThread' -also others I think not related to that- ), so I can't use it with the ShellExecute.

    Codeplug: I have been searching some information about the php arguments and the only I found is that std prompt redirection, so I thought that would work. About the idea on creating a batch file: I don't like at all, because the server serves in mulithreaded mode, so for each request I wuold have to create a new temporary batch, execute it using another temporary result file and finally delete both; since I have the method to create the temporary result file won't be difficult to create anotgher for the bat, but I was thinking that php can have some 'auto create result file'. For the own I/O redirection I'll take a look.

    I'll try some of that and I'll post what I get.

    Niara

  5. #5
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Batch files can take parameters too:
    Code:
    @echo off
    
    echo param 1 is &#37;1
    echo param 2 is %2
    gg

  6. #6
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Or more specifically:
    Code:
    @echo off
    set phpfile="C:\Documents and Settings\Aeiou\SERVIDOR\dirweb\demo.php"
    
    start "" /wait "C:\PHP\php-cgi.exe" -f %phpfile% > %1
    gg

  7. #7
    Registered User
    Join Date
    Mar 2005
    Location
    Juneda
    Posts
    291
    Hello Codeplug, thank's for that last apport. I already know a little the usage of batch files but thank's for the code sample.

    I have tested with the stdhandles on the startup info, and also with the batch file, but I think that I should have a misconfiguration on the php module because the output file is created (well, in the first case I create it in write_shared mode), but after the interpretation the size is 0 bytes (the interpret doesn't dump any data to the file, nor to the command prompt).

    That's all I have been using. First an easy php script

    Code:
    <?php echo "That's working!"; ?>
    Now using the STARTUPINFO struct for the redirection, that's the code
    Code:
    #include <windows.h>
    #include <stdio.h>
    
    int main()
    {
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    HANDLE res;
    char bff[512];
    
    //create the output file on the server's tmp folder
    if((res=CreateFile("C:\\Documents and Settings\\Aeiou\\SERVIDOR\\dirtmp\\output.html",GENERIC_WRITE|GENERIC_READ,
    FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL))==INVALID_HANDLE_VALUE)
        {
        printf("ERROR %d, %d\n",GetLastError(),ERROR_INVALID_NAME);
        getchar();
        return 0;
        }
    
    //init the STARTUPINFO struct
    memset(&si,0,sizeof(si));
    si.cb=sizeof(si);
    
    //setup the redirection
    si.dwFlags=STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
    si.hStdOutput=res;//for writing
    si.hStdError=res;//for the errors, to the same file
    
    //the requested file
    sprintf(bff,"-f \"C:\\Documents and Settings\\Aeiou\\SERVIDOR\\dirweb\\demo.php\"");
    
    //create the proc
    if(!CreateProcess("C:\\PHP\\php-cgi.exe",bff,NULL,NULL,0,0,NULL,NULL,&si,&pi))
        {
        CloseHandle(res);
        printf("ERROR 1\n");
        getchar();
        return 0;
        }
    
    //wait till the proc ends
    WaitForSingleObject(pi.hProcess,INFINITE);
    
    //close all
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    CloseHandle(res);
    getchar();
    return 0;
    }
    The output size at the end is 0 bytes, there's no errors from the interpret (I have veryfied that the php file is at the folder specifyed, so synthax-errors on the path won't be the problem -I think- ). I have also tryed to setup the stdinput param of the STARTUPINFO struct to a handle on the request file (opened with 'CreateFile' for read|write), but the result is the same.

    And for the method of batch files, I have the same php input file, and the bat looks like the last Codeplug post
    Code:
    @echo off
    set phpfile="C:\Documents and Settings\Aeiou\SERVIDOR\dirweb\demo.php"
    start "" /wait C:\PHP\php-cgi.exe -f %phpfile% >C:\output.html
    When I run it, the php prompt is showed (only a flash, but that means that the call is right), the output file is created, but there's nothing inside.

    I'm totaly lost, I will have to take a deeper look at the php reference, maybe I have missed something.

    Niara

  8. #8
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    For the batch file, you can try removing the [start "" /wait] part to see if that is causing the I/O redireciton not to work correctly.

    For doing your own I/O redirection, read up here: http://msdn2.microsoft.com/en-us/library/ms682499.aspx

    gg

  9. #9
    Registered User
    Join Date
    Mar 2005
    Location
    Juneda
    Posts
    291
    Hey hello Codeplug: yes, the 'start ""/wait' is the trouble, but the '\wait' is also a solution for me because I will create the bat process wint 'CreateProcess' and I need to know when have been finished ('WaitForSingleObject'), so the '/wait' will ensure that the bat proc won't be finished before the child php-interpret's process.

    For the own I/O redirection I have seen it on your first post, but on getting the stdout of my proc since the server program runs as multithreaded services, I'm afraid that some data could be mixed in some way. Althought I will take a look because it seems that can be the only way to solve that problem.

    Thank's.
    Niara

  10. #10
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    You can try replacing the [start "" /wait] with [call]. If php-cgi.exe is a regular console app, then it shouldn't return until php-cgi.exe returns.

    The article doesn't redirect output to a file, but a simple change would make it do so. Everywhere you see "hStdout", use your output file handle.

    gg

  11. #11
    Registered User
    Join Date
    Mar 2005
    Location
    Juneda
    Posts
    291
    Hi, thank's Codeplug for the time you spent with my boring question

    1-. I think that php-cgi isn't a regular console application, but when I provide a file to interpret it works as it be a console app. However I will tray that, and I'll post the results.

    2-. I have read the article and compiled the sample code, and I already have thought that the 'hStdout' since is HANDLE variable will work exactly as the HANDLE vars on the STARTUPINFO struct used to call 'CreateProcess' where I can (or I should be able to) (better, I would like to be able to) redirect the output to my own file handler.

    And still not working; why is so difficult??? Maybe tomorrow some divine inspiration will come to me...

    More thank's.
    Niara

  12. #12
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    You don't change any of the STARTUPINFO members from the example. You copy the code exactly and only change where the data is being redirected.
    Code:
       for (;;) 
       { 
          // Read from standard input. 
          fSuccess = ReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL); 
          if (! fSuccess || dwRead == 0) 
             break; 
     
          // Write to standard output. 
          fSuccess = WriteFile(hStdout /*replace with file handle*/, chBuf, dwRead, &dwWritten, NULL); 
          if (! fSuccess) 
             break; 
       }
    gg

  13. #13
    Registered Abuser
    Join Date
    Jun 2006
    Location
    Toronto
    Posts
    591
    I probably should have pointed this out before, but I figured it would have been evident from the MSDN page: the Standard Handles must be inheritable and bInheritHandles must be set to TRUE in CreateProcess.
    So you must specify bInheritHandle as TRUE in the SECURITY_ATTRIBUTES struct for CreateFile, as well you must also specify it TRUE for CreateProcess.
    Quote Originally Posted by STARTUPINFO
    If this flag is specified when calling one of the process creation functions, the handles must be inheritable and the function's bInheritHandles parameter must be set to TRUE. For more information, see Handle Inheritance.

  14. #14
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    Just to add some confusion, another option is to call the command interpreter with CreateProcess.

  15. #15
    Registered User
    Join Date
    Mar 2005
    Location
    Juneda
    Posts
    291
    Yeah, now are working all the methods!!! Thank's you 3 for the help

    Codeplug: using the 'call' instead the 'start /wait' have been solving the problem for the use of a bat file. That will be the default bat file for all the php interpret calls

    Code:
    @echo off
    set php=%1
    set font=%2
    set out=%3
    call %php% -f %font% >%out%
    and the CreateProcess (without the inheritance changes) will be a simple
    Code:
    ...
    //here the structures setup are the same as on my last 3rd post
    //because the problem was on the bat file
    CreateProcess("mybatforphp.bat","path_to_php.exe path_to_font.php path_to_tmpoutput.html",NULL,NULL,0,0,NULL,NULL,&si,
    &pi);
    WaitForSingleObject(pi.hProcess,INFINITE);
    //the bat have finished, so here I can access the output
    ...
    So with that I can launch the bat file with some args that will call the php interpret, the bat will wait till the php interpret ends its job, and I'm able to wait till the bat ends its own.



    @nthony: sure that the explanations on win32api man.ref. are right, but sometimes people reads between lines to speed up the job (and to obtain more errors and problems, like my case). I have made the corrections you point and now that method also works well:
    Code:
    #include <windows.h>
    #include <stdio.h>
    
    int main()
    {
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sap,sat,sao;
    HANDLE out;
    char bff[512];
    
    //sec attributes for the output file
    sao.nLength=sizeof(SECURITY_ATTRIBUTES);
    sao.lpSecurityDescriptor=NULL;
    sao.bInheritHandle=1;
    
    //open the output file on the server's tmp folder (for that test will be on the C:/ root)
    if((out=CreateFile("C:/output.html",GENERIC_WRITE|GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,
    &sao,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL))==INVALID_HANDLE_VALUE)
        {
        printf("ERROR 0\n");
        getchar();
        return 0;
        }
    
    //init the STARTUPINFO struct
    memset(&si,0,sizeof(si));
    si.cb=sizeof(si);
    
    //setup the redirection
    si.dwFlags=STARTF_USESTDHANDLES;
    si.hStdOutput=out;//for writing
    si.hStdError=out;//for the errors, to the same file
    
    //proc sec attributes
    sap.nLength=sizeof(SECURITY_ATTRIBUTES);
    sap.lpSecurityDescriptor=NULL;
    sap.bInheritHandle=1;
    
    //thread sec attributes
    sat.nLength=sizeof(SECURITY_ATTRIBUTES);
    sat.lpSecurityDescriptor=NULL;
    sat.bInheritHandle=1;
    
    //the requested file
    sprintf(bff,"-f \"C:\\Documents and Settings\\Aeiou\\SERVIDOR\\dirweb\\demo.php\"");
    
    //create the proc
    if(!CreateProcess("C:\\PHP\\php-cgi.exe",bff,&sap,&sat,1,0,NULL,NULL,&si,&pi))
        {
        CloseHandle(out);
        printf("ERROR 1\n");
        getchar();
        return 0;
        }
    
    //wait till the proc ends
    WaitForSingleObject(pi.hProcess,INFINITE);
    
    //close all
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    CloseHandle(out);
    getchar();
    return 0;
    }


    anonytmouse: I'll have 'stolen' a trick from your code on the link you posted, the 'CREATE_NO_WINDOW' flag. What's that? Another non-documented win value? It doesn't appears on my copy of Win32PI Man.Ref, but it works.



    If you don't mind, I'll use the CreateProcess with the inheritance flags on because in that way only 2 programs will run (the server and the php interpret, in the other case will be running the server, the bat and the php).


    So, more thank's to that geat help.
    Niara

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Beginner Needs help in Dev-C++
    By Korrupt Lawz in forum C++ Programming
    Replies: 20
    Last Post: 09-28-2010, 01:17 AM
  2. command line arguments
    By vurentjie in forum C Programming
    Replies: 3
    Last Post: 06-22-2008, 06:46 AM
  3. Replies: 10
    Last Post: 09-27-2005, 12:49 PM
  4. NULL arguments in a shell program
    By gregulator in forum C Programming
    Replies: 4
    Last Post: 04-15-2004, 10:48 AM
  5. registry, services & command line arguments.. ?
    By BrianK in forum Windows Programming
    Replies: 3
    Last Post: 03-04-2003, 02:11 PM