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

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

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

我一直在看“CreateProcess”调用:

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

尽pipe我可以用“用C编写的孩子”来工作,但我无法调用Python脚本。

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

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

相当一部分上面的代码是“硬编码”,仅用于testing目的…本质上,我传递一些文本,如“你好从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)){ 

但它从来没有工作。

任何想法,我可以得到这个工作? 任何帮助将不胜感激。

我的应用程序将一个字符串传递给一个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 

也许

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

CreateProcess是有点棘手的使用。

从MSDN文档:

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

为了避免怪异,我建议总是传递NULL作为第一个参数,并传递完整的命令行作为第二个参数:

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