jjzjj

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

coder 2024-06-18 原文

我已经设法让 C 代码在 C 代码中使用 PIPES 在 Unix 上愉快地调用 Python 脚本。我现在需要在 Windows 上执行相同的操作。

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

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

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

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

下面是我的 windows 盒子上的“ parent /发件人代码”:

#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 脚本...

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

但它永远行不通。

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

最佳答案

我的应用程序将一个字符串发送到 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

关于python - 如何在 Windows 上从 C 中的 CreateProcess 执行 Python 脚本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3675274/

有关python - 如何在 Windows 上从 C 中的 CreateProcess 执行 Python 脚本?的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  3. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  4. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  5. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  6. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  7. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  8. ruby-openid:执行发现时未设置@socket - 2

    我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass

  9. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  10. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

随机推荐