ShellExecuteEx and getexitcodeprocess - python

Using ShellExecuteEx(..) to lunch a python script and python script returning a value from python main using sys.exit(0) on success or some other error value. How to read a python script exit code?
After launching application waited to complete script by using MsgWaitForMultipleObjects (...) and then calling GetExitCodeProcess(...) some reason I always read value 1 from getExitCodeprocess(..)
Python Code:
def main():
time.sleep(10)
logger.info("************The End**********")
return (15)
if __name__ == "__main__":
sys.exit(main())
C++ Code:
SHELLEXECUTEINFO rSEI = { 0 };
rSEI.cbSize = sizeof(rSEI);
//rSEI.lpVerb = "runas";
rSEI.lpVerb = "open";
rSEI.lpFile = "python.Exe";
rSEI.lpParameters = LPCSTR(path.c_str());
rSEI.nShow = SW_NORMAL;
rSEI.fMask = SEE_MASK_NOCLOSEPROCESS;
if (ShellExecuteEx(&rSEI)) // you should check for an error here
;
else
errorMessageID = GetLastError(); //MessageBox("Error", "Status", 0);
WORD nStatus;
MSG msg; // else process some messages while waiting...
while (TRUE)
{
nStatus = MsgWaitForMultipleObjects(1, &rSEI.hProcess, FALSE, INFINITE, QS_ALLINPUT); // drop through on user activity
if (nStatus == WAIT_OBJECT_0)
{ // done: the program has ended
break;
}
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
DispatchMessage(&msg);
//MessageBox("Wait...", "Status", 0);
}
} // launched process has exited
DWORD dwCode=0;
if (!GetExitCodeProcess(rSEI.hProcess, &dwCode)) //errorvalue
{
DWORD lastError = GetLastError();
}
In this code as Python script exiting with 15, I am expecting to read 15 from dwCode from GetExitCodeProcess(rSEI.hProcess, &dwCode)?
Appreciates all of your help on this...

As the comments metioned, your python script fails.
Python Code Sample:
import sys
import time
import logging
import logging.handlers
logger = logging.getLogger("logger")
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
handler.setLevel(logging.INFO)
logger.addHandler(handler)
def main():
time.sleep(10)
logger.info("************The End**********")
return (15)
if __name__ == "__main__":
sys.exit(main())
Name your Python script file with .py as the suffix instead of .Exe, such as "python.py"
Give path value to SHELLEXECUTEINFO.lpDirectory, and set SHELLEXECUTEINFO.lpParameters to NULL here.
Or Give the path and file combination to SHELLEXECUTEINFO.lpVerb, like "Path\\python.py"
C++ Code Sample:
#include <windows.h>
#include <iostream>
#include <string>
void main()
{
int errorMessageID = 0;
std::string path = "Path";
SHELLEXECUTEINFO rSEI = { 0 };
rSEI.cbSize = sizeof(rSEI);
//rSEI.lpVerb = "runas";
rSEI.lpVerb = "open";
rSEI.lpFile = "python.py";
rSEI.lpParameters = NULL;
rSEI.lpDirectory = path.c_str();
rSEI.nShow = SW_NORMAL;
rSEI.fMask = SEE_MASK_NOCLOSEPROCESS;
if (!ShellExecuteEx(&rSEI)) // you should check for an error here
errorMessageID = GetLastError(); //MessageBox("Error", "Status", 0);
WORD nStatus;
MSG msg; // else process some messages while waiting...
while (TRUE)
{
nStatus = MsgWaitForMultipleObjects(1, &rSEI.hProcess, FALSE, INFINITE, QS_ALLINPUT); // drop through on user activity
if (nStatus == WAIT_OBJECT_0)
{ // done: the program has ended
break;
}
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
DispatchMessage(&msg);
//MessageBox("Wait...", "Status", 0);
}
} // launched process has exited
DWORD dwCode = 0;
if (!GetExitCodeProcess(rSEI.hProcess, &dwCode)) //errorvalue
{
DWORD lastError = GetLastError();
}
}

Related

Why 0xFEFF appear in recv data

i try to create a client written in c++ and a server using python flask. The task is simple, client connect and get data from server, then display it on console. I have two piece of code:
Server:
from flask import Flask
app = Flask(__name__)
#app.route('/hello')
def hello():
return "hello".encode("utf-16")
if __name__ == "__main__":
app.run(debug=True,host="127.0.0.1")
Client:
BOOL bResults = FALSE;
bool ret = false;
DWORD dwDownloaded = 0;
WCHAR wDataRecv[1024] = {0};
HINTERNET hConnect = NULL;
HINTERNET hRequest = NULL;
DWORD dwSize = 0;
HINTERNET hSession = WinHttpOpen(L"WinHTTP Example/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0); # open session to connect
hConnect = WinHttpConnect(hSession, L"localhost", (port == 0) ? INTERNET_DEFAULT_HTTP_PORT : port, 0); # connect to localhost with port 80 or custom port (this time i use port 5000)
if (!hConnect)
goto Free_And_Exit;
hRequest = WinHttpOpenRequest(hConnect, L"GET", L"/hello", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
if (hRequest) {
bResults = WinHttpSendRequest(hRequest, NULL, 0,WINHTTP_NO_REQUEST_DATA, 0,0, 0);# send GET request
}
if (bResults)
bResults = WinHttpReceiveResponse(hRequest, NULL);
if (bResults)
{
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) {
std::cout << "WinHttpQueryDataAvailable failed with code: " << GetLastError();
}
if (!WinHttpReadData(hRequest, wDataRecv, dwSize, &dwDownloaded)) {
std::cout << "WinHttpReadData failed with code: " << GetLastError();
}
std::wcout << wDataRecv; # wcout wont print anything to console
}
Free_And_Exit: #clean up
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
return ret;
I noticed that the data return from server like:
b'\xfe\xff\hello'
Why 0xFEFF is there ?
Its is BOM (byte order mark). I just need to decode from the client or use:
return "hello".encode('UTF-16LE') # not UTF-16

Migrate a "zmq_send" command to Python

I have a c function that publish data to a c++ subscriber, now I want to migrate this c function to Python:
void setup_msg_publish() {
int r;
zmqcontext = zmq_ctx_new();
datasocket = zmq_socket(zmqcontext, ZMQ_PUB);
r = zmq_bind(datasocket, "tcp://*:44000");
if (r == -1) {
printf(zmq_strerror(errno));
}
}
void publishdata(int x, int y) {
if (datasocket == 0) {
setup_msg_publish();
}
zmq_data zd;
zd.msgType = int 0;
zd.x = x;
zd.y = y;
size_t len = sizeof(zd);
int res = zmq_send(datasocket, &zd, len, NULL);
assert(res == len);
}
I've tried to implement this in Python:
import zmq
import pickle
from collections import namedtuple
Data = namedtuple("Data", "msgType x y")
def send_zmq():
data = Data("0", "1", "2")
msg = pickle.dumps(data)
context = zmq.Context()
socket = context.socket(zmq.REQ)
socket.connect("tcp://127.0.0.1:44000")
socket.send(msg)
For debug purposes I can recive the data with Python like this:
import zmq
import pickle
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://127.0.0.1:44000")
while True:
message = socket.recv()
data = pickle.loads(message)
print(data)
But I don't receive anything in my c++ code (it just prints no data):
#include "View.h"
#include <iostream>
#include <thread>
#include <chrono>
View::View() :
viewSubscriber(zmqcontext, ZMQ_SUB)
{
unsigned _int16 msgType = 0;
viewSubscriber.connect("tcp://127.0.0.1:44000");
//viewSubscriber.setsockopt(ZMQ_SUBSCRIBE, &msgType, sizeof(msgType));
viewSubscriber.setsockopt(ZMQ_SUBSCRIBE, "", 0);
std::cout << msgType;
}
void View::run() {
using namespace std;
bool received_view_data = false;
bool checkForMore = true;
zmq_view data;
while (checkForMore) {
zmq::message_t msg;
//cout << &msg;
if (viewSubscriber.recv(&msg, ZMQ_NOBLOCK)) {
received_view_data = true;
memcpy(&data, msg.data(), sizeof(data));
cout << &data.x;
}
else {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
cout << "no data \n";
}
}
}
int main(){
View *app = new View();
app -> run();
return 0;
}
Any ideas what to fix so I receive the data in the namedTuple on the c++ side? Could it be that the c++ "needs to know more" about the type of each attribute of the namedTuple (if that is the case how do I specify whether the data is a double or int etc?)?
The solution was found after testing to go from C++ -> Python thank you J_H for the idea. Instead of using a namedtuple a packed struct was used.
import zmq
import struct
def send_zmq():
struct_format = 'Idd'
msg_type = 0
x = 1.0
y = 1.0
msg = struct.pack(struct_format, msg_type, x, y)
context = zmq.Context()
socket = context.socket(zmq.REQ)
socket.connect("tcp://127.0.0.1:44000")
socket.send(msg)

Empty output when calling a python script in C# project

I would like to call a python script in my C# project , I'm using this function to do the job but unfortunately I didn't get any result and the result variable shows always an empty output. I would like to know what's the reason of this
public string RunFromCmd(string rCodeFilePath, string args)
{
string file = rCodeFilePath;
string result = string.Empty;
try
{
var info = new ProcessStartInfo(pythonPath);
info.Arguments = #"C:\Users\MyPc\ExternalScripts\HelloWorld.py" + " " + args;
info.RedirectStandardInput = false;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
info.CreateNoWindow = true;
using (var proc = new Process())
{
proc.StartInfo = info;
proc.Start();
proc.WaitForExit();
if (proc.ExitCode == 0)
{
result = proc.StandardOutput.ReadToEnd();
}
}
return result;
}
catch (Exception ex)
{
throw new Exception("R Script failed: " + result, ex);
}
}
Click Event ( Calling funtion )
private void Button1_Click(object sender, RoutedEventArgs e)
{
pythonPath = Environment.GetEnvironmentVariable("PYTHON_PATH");
RunFromCmd(pythonPath, "");
}
Python Script :
import sys
def main():
text = "Hello World"
return text
result = main()
I've fixed the issue by setting Copy if newer instead of Do Not Copy to HelloWorld.py Script

How to retrieve the full path for the foreground window in Windows 10 using the Python ctypes module?

I've decided to bite more than I could chew here. I've spent the past day attempting this through trial and error however I have yet to figure out the correct way to interact with the Windows API.
I would like to retrieve the full path for the focused window on my Windows 10 PC using Python. So far I have hot glued this together:
from ctypes import *
import sys
import time
try:
while True:
# Retrieve the handle for the foreground window
hwnd = windll.user32.GetForegroundWindow()
# Create a buffer for the GetWindowThreadProcessId function
buffer = create_string_buffer(260)
# Retrieve the full path and file name of the foreground window
windll.user32.GetWindowModuleFileName(hwnd, buffer, sizeof(buffer))
# Print the full path and file name of the foreground window
print(buffer.value)
# Sleep for 100 milliseconds
time.sleep(0.1)
except KeyboardInterrupt:
sys.exit(0)
Unfortunatly this doesn't have my desired output. When I have Command Prompt open I would expect the path to be C:\Windows\system32\cmd.exe however I get C:\Users\John\AppData\Local\Programs\Python\Python39\python.exe instead. When I open any other window I get an empty output.
GetWindowModuleFileName calls GetModuleFileName from which the MSDN doc says :
The module must have been loaded by the current process.
So you can't get the full path you want directly by calling GetWindowModuleFileName.
You can refer to this thread : How to get the Executable name of a window.
And here is an example implemented in C++, you can refer to it:
#include <Windows.h>
#include <psapi.h>
#include <iostream>
#include <tlhelp32.h>
BOOL SetPrivilege(HANDLE hToken, LPCTSTR Privilege,BOOL bEnablePrivilege)
{
TOKEN_PRIVILEGES tp = { 0 };
// Initialize everything to zero
LUID luid;
DWORD cb = sizeof(TOKEN_PRIVILEGES);
if (!LookupPrivilegeValue(NULL, Privilege, &luid))
{
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege) {
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
}
else {
tp.Privileges[0].Attributes = 0;
}
AdjustTokenPrivileges(hToken, FALSE, &tp, cb, NULL, NULL);
if (GetLastError() != ERROR_SUCCESS)
{
std::cout << "err = " << GetLastError() << std::endl;
return FALSE;
}
return TRUE;
}
int main()
{
HANDLE curHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
OpenProcessToken(curHandle, TOKEN_ADJUST_PRIVILEGES, &curHandle);
SetPrivilege(curHandle, SE_DEBUG_NAME, TRUE);
while (1)
{
TCHAR buf[MAX_PATH] = L"";
HWND hwnd = GetForegroundWindow();
DWORD pid = 0;
GetWindowThreadProcessId(hwnd, &pid);
HANDLE handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
if (handle)
{
GetModuleFileNameEx(handle, 0, buf, MAX_PATH);
std::wcout << buf << std::endl;
}
else
{
std::cout << "error = " << GetLastError() << std::endl;
}
if (handle) CloseHandle(handle);
Sleep(100);
}
return 0;
}

How to execute Python script from CreateProcess in C on Windows?

I have managed to get C code calling Python scripts happily on Unix using PIPES within the C code. I now need to do the same on Windows.
Essentially I would like to write scripts in different scripting languages like Python / Lua etc on Windows and be able to execute them using STDIN / STDOUT etc.
I have been looking at the "CreateProcess" call at:
http://msdn.microsoft.com/en-us/library/ms682425(VS.85).aspx
and although I can get it to work with a "child written in C", I cannot get it to call a Python script.
Below is the "parent / sender code" on my windows box:
#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;
}
Quite a bit of the above code is "hardcoded" just for testing purposes...essentially I passing some text like "hello from the paren" to be sent to a "child.exe"....
Here is the code for the child.c...a simple ECHO of what is sent to it
#include<windows.h>
#include<stdio.h>
#include<string.h>
void main (){
CHAR szInput[1024];
ZeroMemory(szInput,1024);
gets(szInput);
puts(szInput);
fflush(NULL);
}
To run the app I send "CallSubProcess.exe Child.exe" and it works 100%
Next I want to change "child.c" to be a PYTHON SCRIPT...
import sys
if __name__ == "__main__":
inStream = sys.stdin.read()
outStream = inStream
sys.stdout.write(outStream)
sys.stdout.flush()
So how can I change the CreateProcess call to execute this script?
if (!CreateProcess("C:\\Python26\\python.exe", "echo.py",NULL, NULL,FALSE, 0,NULL,NULL,&si,&pi)){
But it never works.
Any ideas how I can get this to work? Any help will be greatly appreciated.
My application posts a string to a python script, and the python script posts the string back to the c
application. It works well.
//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
Maybe
if (!CreateProcess("C:\\Python26\\python.exe",
"echo.py 'hello from parent'",
NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
CreateProcess is kind of tricky to use.
From the MSDN documentation:
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.
To avoid the weirdness, I recommend always passing NULL for the first argument and to pass the full command-line as the second:
CreateProcess(NULL, "\"C:\\Python26\\python.exe\" echo.py", ...);

Categories