如何在Windows上的C中从CreateProcess执行Python脚本?

时间:2010-09-09 09:17:23

标签: python c windows

我已经设法在C代码中使用PIPES在Unix上快速获得C代码调用Python脚本。我现在需要在Windows上做同样的事情。

基本上我想在Windows上用不同的脚本语言编写脚本,比如Python / Lua等,并且能够使用STDIN / STDOUT等执行它们。

我一直在查看“CreateProcess”调用:

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

虽然我可以让它与“用C语言编写的孩子”一起工作,但我无法让它调用Python脚本。

以下是我的Windows框中的“父母/发件人代码”:

#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;
}

上面的代码中有相当一部分是“硬编码”的,只是出于测试目的......基本上我传递了一些文字,比如“hello from the 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调用以执行此脚本?

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

但它永远不会奏效。

我有什么想法可以让它发挥作用?任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:3)

我的应用程序将字符串发布到python脚本,python脚本将字符串发布回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

答案 1 :(得分:1)

也许

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

答案 2 :(得分:0)

CreateProcess使用起来有点棘手。

来自MSDN文档:

  

如果lpApplicationNamelpCommandLine都是非NULL,则... lpApplicationName指定要执行的模块,并且...... lpCommandLine指定命令行。用C语言编写的控制台进程可以使用argcargv参数来解析命令行。因为argv[0]是模块名称,所以C程序员通常会重复模块名称作为命令行中的第一个标记。

为避免这种奇怪现象,我建议始终将NULL传递给第一个参数,并将完整的命令行作为第二个参数传递:

CreateProcess(NULL, "\"C:\\Python26\\python.exe\" echo.py", ...);