[英]How to execute Python script from CreateProcess in C on 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;
}
相當一部分上面的代碼是“硬編碼”只是為了測試目的...基本上我傳遞一些文本,如“你好,從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文檔:
如果
lpApplicationName
和lpCommandLine
都是非NULL,則...lpApplicationName
指定要執行的模塊,並且...lpCommandLine
指定命令行....用C編寫的控制台進程可以使用argc
和argv
參數來解析命令行。 因為argv[0]
是模塊名稱,所以C程序員通常會重復模塊名稱作為命令行中的第一個標記。
為了避免這種怪異,我建議總是為第一個參數傳遞NULL
並將第二個完整的命令行傳遞給:
CreateProcess(NULL, "\"C:\\Python26\\python.exe\" echo.py", ...);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.