如何在Windows上用C语言从CreateProcess执行Python脚本?

2024-10-01 07:51:09 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经设法让C代码在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;
}

上面的代码中有相当一部分是“硬编码”的,只是为了测试目的……本质上我传递一些文本,比如“来自paren的hello”发送给子级.exe".... 在

这是孩子的代码。c…是发送给它的简单回音

^{pr2}$

运行我发送的应用程序“调用子进程.exe子级.exe“而且效果100%

接下来我想把“child.c”改成PYTHON脚本。。。在

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)){

但它从来没有起作用。在

有什么办法让这个工作起来吗?任何帮助将不胜感激。在


Tags: 代码脚本truereturnifsanullhandle
3条回答

也许吧

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

CreateProcess使用起来有点棘手。在

来自MSDN文档:

If both lpApplicationName and lpCommandLine are non-NULL, ... lpApplicationName specifies the module to execute, and ... lpCommandLine specifies the command line.... Console processes written in C can use the argc and argv arguments to parse the command line. Because argv[0] is the module name, C programmers generally repeat the module name as the first token in the command line.

为了避免奇怪,我建议始终为第一个参数传递NULL,并将整个命令行作为第二个参数传递:

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

我的应用程序向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

相关问题 更多 >