Как выполнить скрипт Python из CreateProcess в C на Windows?

1

Мне удалось получить код C, вызывающий сценарии Python с радостью в Unix, используя PIPES в коде C. Теперь мне нужно сделать то же самое в Windows.

По сути, я хотел бы писать сценарии на разных языках сценариев, таких как Python/Lua и т.д. в Windows, и выполнять их с помощью STDIN/STDOUT и т.д.

Я смотрю вызов "CreateProcess" по адресу:

http://msdn.microsoft.com/en-us/library/ms682425(VS.85).aspx

и хотя я могу заставить его работать с "ребенком, написанным на C", я не могу заставить его вызвать Python script.

Ниже находится "родительский/отправивший код" в окне окна:

#include<windows.h>
#include <stdio.h>
#include <stdlib.h>

#pragma comment(lib, "User32.lib")
void DisplayError(char *pszAPI);
void readFromPipe(HANDLE hPipeRead);
void createChildProcess(char *commandLine,
                        HANDLE hChildStdOut,
                        HANDLE hChildStdIn,
                        HANDLE hChildStdErr);
DWORD WINAPI writeToPipe(LPVOID lpvThreadParam);

HANDLE hChildProcess = NULL;
HANDLE hStdIn = NULL;
BOOL bRunThread = TRUE;
char *inputStream;

int main(int argc, char *argv[]){
  HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
  HANDLE hInputWriteTmp,hInputRead,hInputWrite;
  HANDLE hErrorWrite;
  HANDLE hThread;
  DWORD ThreadId;
  SECURITY_ATTRIBUTES sa;
  int streamLen;

  sa.nLength= sizeof(SECURITY_ATTRIBUTES);
  sa.lpSecurityDescriptor = NULL;
  sa.bInheritHandle = TRUE;

  if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0))
     return 1;

  if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite,
                       GetCurrentProcess(),&hErrorWrite,0,
                       TRUE,DUPLICATE_SAME_ACCESS))
     return 1;

  if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0))
     return 1;

  if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp,
                       GetCurrentProcess(),
                       &hOutputRead,
                       0,FALSE,
                       DUPLICATE_SAME_ACCESS))
     return 1;

  if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp,
                       GetCurrentProcess(),
                       &hInputWrite,
                       0,FALSE,
                       DUPLICATE_SAME_ACCESS))
  return 1;

  if (!CloseHandle(hOutputReadTmp)) return 1;;
  if (!CloseHandle(hInputWriteTmp)) return 1;;

  if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE )
     return 1;

  if (argc == 2){
    createChildProcess(argv[1], hOutputWrite,hInputRead,hErrorWrite);
  }else{
    puts("No process name / input stream specified\n");
    return 1;
  }


  if (!CloseHandle(hOutputWrite)) return 1;;
  if (!CloseHandle(hInputRead )) return 1;;
  if (!CloseHandle(hErrorWrite)) return 1;;

  hThread = CreateThread(NULL,0,writeToPipe,
                          (LPVOID)hInputWrite,0,&ThreadId);
  if (hThread == NULL)
    return 1;;

  readFromPipe(hOutputRead);

  if (!CloseHandle(hStdIn))
     return 1;
  bRunThread = FALSE;

  if (WaitForSingleObject(hThread,INFINITE) == WAIT_FAILED)
     return 1;;

  if (!CloseHandle(hOutputRead)) return 1;;
  if (!CloseHandle(hInputWrite)) return 1;;
}

void createChildProcess(char *commandLine,
                        HANDLE hChildStdOut,
                        HANDLE hChildStdIn,
                        HANDLE hChildStdErr){
  PROCESS_INFORMATION pi;
  STARTUPINFO si;

  ZeroMemory(&si,sizeof(STARTUPINFO));
  si.cb = sizeof(STARTUPINFO);
  si.dwFlags = STARTF_USESTDHANDLES;
  si.hStdOutput = hChildStdOut;
  si.hStdInput  = hChildStdIn;
  si.hStdError  = hChildStdErr;

  if (!CreateProcess(NULL,commandLine,NULL,NULL,TRUE,
                     NULL,NULL,NULL,&si,&pi))
    hChildProcess = pi.hProcess;
  if (!CloseHandle(pi.hThread)) return 1;;
}

void readFromPipe(HANDLE hPipeRead)
{
  CHAR lpBuffer[256];
  DWORD nBytesRead;
  DWORD nCharsWritten;

  while(TRUE)
  {
     if (!ReadFile(hPipeRead,lpBuffer,sizeof(lpBuffer),
                                      &nBytesRead,NULL) || !nBytesRead)
     {
        if (GetLastError() == ERROR_BROKEN_PIPE)
           break; // pipe done - normal exit path.
        else
           return 1; // Something bad happened.
     }
     if (!WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),lpBuffer,
                       nBytesRead,&nCharsWritten,NULL))
        return 1;;
  }
}

DWORD WINAPI writeToPipe(LPVOID lpvThreadParam)
{
  CHAR read_buff[256];
  DWORD nBytesRead,nBytesWrote;
  HANDLE hPipeWrite = (HANDLE)lpvThreadParam;

  while (bRunThread){
     nBytesRead = 21;
     strncpy(read_buff, "hello from the paren\n",21);
     read_buff[nBytesRead] = '\0';

     if (!WriteFile(hPipeWrite,read_buff,nBytesRead,&nBytesWrote,NULL)){
        if (GetLastError() == ERROR_NO_DATA)
           break; //Pipe was closed (normal exit path).
        else
        return 1;;
     }
  }
  return 1;
}

Довольно немного вышеприведенного кода является "жестко запрограммированным" только для целей тестирования... по сути, я передаю некоторый текст, например "привет из paren", который нужно отправить в "child.exe"....

Вот код для child.c... простой ECHO того, что ему отправлено

#include<windows.h>
#include<stdio.h>
#include<string.h>

void main (){
    CHAR szInput[1024];
    ZeroMemory(szInput,1024);   
    gets(szInput);
    puts(szInput);
    fflush(NULL);   
}

Чтобы запустить приложение, я отправляю "CallSubProcess.exe Child.exe", и он работает на 100%

Далее я хочу изменить "child.c" как PYTHON script...

import sys

if __name__ == "__main__":
   inStream = sys.stdin.read()   
   outStream = inStream 
   sys.stdout.write(outStream)
   sys.stdout.flush()

Итак, как я могу изменить вызов CreateProcess для выполнения этого script?

if (!CreateProcess("C:\\Python26\\python.exe", "echo.py",NULL, NULL,FALSE, 0,NULL,NULL,&si,&pi)){

Но он никогда не работает.

Любые идеи, как я могу заставить это работать? Любая помощь будет принята с благодарностью.

  • 2
    Ой! Никогда, никогда не используйте gets() !
  • 0
    Я знаю, что это шестилетний вопрос, но вы когда-нибудь находили что-нибудь, что сработало? Там нет принятого ответа.
Теги:

3 ответа

3

Мое приложение отправляет строку в python script, а python script отправляет строку обратно в c  выражение. Он работает хорошо.

//c code
#pragma comment(lib, "json_vc71_libmtd.lib")
#include <windows.h>
#include <iostream>
#include <io.h>
#include "./json/json.h"

using namespace std;

DWORD WINAPI threadproc(PVOID pParam);
HANDLE hRead, hWrite, hRead1, hWrite1;
int main()
{
    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;
    if (!CreatePipe(&hRead, &hWrite, &sa, 0)){
        ::MessageBox(NULL, L"can't create pipe", L"error", MB_OK);
        return -1;
    }
    if (!CreatePipe(&hRead1, &hWrite1, &sa, 0)){
        ::MessageBox(NULL, L"can't create pipe1", L"error", MB_OK);
        return -1;
    }
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    GetStartupInfo(&si);
    si.cb = sizeof(STARTUPINFO);
    si.hStdError = hWrite;
    si.hStdOutput = hWrite;
    si.hStdInput = hRead1;
    si.wShowWindow = SW_SHOW;
    si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    WCHAR szCmdLine[] = L"\"D:\\tools\\python\\python.exe\" D:\\code\\test\\pipeCallCore\\pipeCallCore\\json_wraper.py";
    if (!CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)){
        ::MessageBox(NULL, L"can't create process", L"error", MB_OK);
        return -1;
    }
    CloseHandle(hWrite);
    CloseHandle(hRead1);
    const int cBufferSize = 4096;
    char buffer[cBufferSize] = {0};
    DWORD bytes;
    int i = 0;
    while (true){
        cout << "come !" << endl;
        ZeroMemory(buffer, sizeof(buffer));
        sprintf(buffer, "{\"write\":%d}\n", i ++);
        if (NULL == WriteFile(hWrite1, buffer, strlen(buffer), &bytes, NULL)){
            ::MessageBox(NULL, L"write file failed!", L"error", MB_OK);
            break;
        }
        ZeroMemory(buffer, sizeof(buffer));
        if (NULL == ReadFile(hRead, buffer, cBufferSize - 1, &bytes, NULL)){
            ::MessageBox(NULL, L"readfile failed", L"error", MB_OK);
            return -1;
        }
        cout <<"yes " << buffer << endl;
        Sleep(2000);
    }
    return 0;
}


//python code
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys

while True:
    try:
       s = sys.stdin.readline()
       sys.stdout.write(s)
       sys.stdout.flush()
    except EOFError, KeyboardInterrupt:
        break
  • 0
    Вам когда-нибудь приходилось писать в файл из сценария Python, который вы так назвали? Думаю, у меня возникли проблемы с разрешениями.
1

Может

if (!CreateProcess("C:\\Python26\\python.exe",
            "echo.py 'hello from parent'",
            NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
  • 0
    Привет, спасибо за предложение, но я хочу отправить поток в PIPE, а не передавать его скрипту Python в качестве параметра? У меня то же самое работает с Unix ... только этот CreateProcess, кажется, дает мне большие трудности ;-( Какие-нибудь другие предложения?
0

CreateProcess довольно сложно использовать.

Из документации MSDN:

Если оба lpApplicationName и lpCommandLine не являются NULL,... lpApplicationName указывает исполняемый модуль и... lpCommandLine указывает командную строку... Консольные процессы, написанные на C, могут используйте аргументы argc и argv для синтаксического анализа командной строки. Поскольку argv[0] - это имя модуля, программисты C обычно повторяют имя модуля в качестве первого токена в командной строке.

Чтобы избежать странности, я рекомендую всегда передавать NULL для первого аргумента и передавать полную командную строку как вторую:

CreateProcess(NULL, "\"C:\\Python26\\python.exe\" echo.py", ...);
  • 0
    Привет, я попробовал ваше предложение и все еще не повезло ;-( Есть еще идеи?
  • 0
    @lyntongrice: Я думаю, что я мог неправильно понять вашу проблему. Это то, что вы не можете заставить скрипт выполняться или вы не можете прочитать его вывод?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню