Sorry for the lousy title, "InterProcess Communication" was too long

Basically, I'm looking to use the native _winapi and msvcrt modules to launch an integrated python interpreter and communicate with it over pipes
I can't find anything on Google or DDG, and I've been searching for days, but nobody uses these modules for some reason...

I already have the foundation with a 1-way Parent->Child pipe that works, but it's giving me a few issues:
1: I can't seem to get a 2nd Child->Parent pipe to run without the program hanging
2: the output of the subprocess only prints after the main process is closed (tbh though I rather want the main process to actively print through subprocess feedback, even if it's delayed a few ns)

Note that the code came from the CPU-heavy multiprocessing module.
(I just reduced the processing, so this code wastes MUCH less CPU cycles)

# -*- coding: utf-8 -*-

from _winapi import CreatePipe, CreateProcess, CloseHandle
from msvcrt import open_osfhandle
import _winapi, msvcrt
from nt import getpid

# this is just a mock-up path to a local interpreter, since __file__ doesn't include the drive letter on wine
CWD = 'Z:%s'%__file__.replace('test.py','').replace('\\','/')
exec_path = '%sapp/'%CWD
executable = '%spython.exe'%exec_path

rhandle, whandle = CreatePipe(None, 0) # Parent to Child

prog = '''
from _winapi import OpenProcess, DuplicateHandle, GetCurrentProcess, CloseHandle
from _winapi import PROCESS_DUP_HANDLE, DUPLICATE_SAME_ACCESS, DUPLICATE_CLOSE_SOURCE
from msvcrt import open_osfhandle
import sys
sys.path = ['.\\DLLs','%s'] # because -I doesn't "Isolate" as well as it's supposed to, and we still have environment paths here.

source_process_handle = OpenProcess(PROCESS_DUP_HANDLE, False, %s)
try:
    handle = DuplicateHandle( source_process_handle, %s, GetCurrentProcess(), 0, False, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)
    from_parent = open( open_osfhandle( handle, 0 ), 'rb', closefd=True ) # not using `with` because I intend to open a 2nd pipe to write to

    exec(from_parent.read())

    from_parent.close()
    sys.exit(0)
finally:
    CloseHandle(source_process_handle)'''%(exec_path, getpid(), rhandle)

cmd = '%s -I -S -c "%s" --multiprocessing-fork'%(executable, prog)

to_child = open( open_osfhandle( whandle, 0 ), 'wb', closefd=True ) # not using `with` because I intend to open a 2nd pipe to read from

# start process
try:
    subprocess_handle, thread_handle, pid, tid = CreateProcess( executable, cmd, None, None, False, 0, None, None, None)
    CloseHandle(thread_handle)
except:
    CloseHandle(rhandle)
    raise

# send information to child
to_child.write(b'print("success!")')

for i in range(10000000): i+i+1 # give the subprocess enough time to complete

input('Press Enter to Exit...\n\n')

CloseHandle(subprocess_handle)
to_child.close()

Is there any way I can introduce a 2nd pipe to have proper interprocess communication??

EDIT:
btw, to those looking to use this as an example, I highly recommend you NOT send raw python code through the pipe like I'm doing here with to_child.write(b'print("success!")')
What I'm doing is for testing purposes only, and should not be used in practical cases as it's extremely insecure!

the multiprocessing module uses the pickle module, but that's a joke because you can easily get the authstring to unpickle the pipe...
see this image:
https://lh3.googleusercontent.com/R8vYH1reL4GF4KTc2GrO88CsMrIVshMhZVTmYOG5naZAmhDH-NACHSB7XOIzriFrNi8YiyD4ic1crLFV5sRu32ELSTw-gU4O-DVnm8H0wtmZAvzmDM5qhnmR5klDfDIxIy5aNgYWG-7vVHq9uTMZp-uRLAdYdzSEs_urbOLB6tfiDFbelCSpPXdiH10xs9bj_EnCIjTrcQS06qPtNSiZR1BvmruxEd_24qaqcQODtiBCPB0MPxD3G_-73xGFk3QRqYr0JJpgNSZk7eaVRmED3QooxY245k9jv_g-xeiRvTGqVMWGbQMDzDjsiRLOFdB4l42370Gf-m9rWTNISfuVA0H_6FoZxdrYh6MzX8tz3j6bztHc51h_PLyGHaWlk70JOsXcvG5OF-3TJridaUTldwbyqNUTmz-sPFUOghPdzmYc5WBocNzaiONiHcfCVsDTJOV3dYWKii-qs_aroQKE3ZpdkcjGuw2t0VCuDvrN96ZtCO1YYbRCTKi-97wVUFXS26v9NeikAVCiTazAwdyTr98byg6WORCel6dZ2cZaAgG6vHQCr7OpLKhJpUQ3lNmmzTcNFpPW1m-MljOn1bFotn70Fuz2hs0p4M4LxKzWTI-0ps6-y5uvYFms6DUpLrQ77RMlUqHDHuNZtFOaFSrekr84hFXcka0MkFsnNMZU_omaqQXJ2pOZiNsr=w896-h267-no

so it's essentially just wasting a ton of CPU cycles to send code over the pipe.

also, fun fact
from the image, you can use cp.__class__ or type(cp) to gain access to the deleted class MainProcess(BaseProcess): class.

But to get back on topic, what you should do is define code in the subprocess that analyzes the input read from the pipe and interprets commands from it that are specific to your app with the supplied data.

I should probably note, the interpreter I'm using is a portable Anaconda 2.3.0 (need to upgrade to 2.5.0) interpreter specifically tailored to work with my API, and as such is designed to be as minimal as possible (only 10.8 MiB in app/ folder size).
it does NOT include the standard library (so no os module), nor does it include builtin C modules I won't be using (such as _tkinter).

all it has is 2 standard modules being io (modified to remove abc and _weakrefset), and codecs (includes the encodings/ module (folder))

the app/ folder root looks like this:
https://cdn.discordapp.com/attachments/161204326218465280/491923337434628096/unknown.png

and to show the only modules I have to work with:
https://cdn.discordapp.com/attachments/161204326218465280/492146476760301578/unknown.png

everything here is either built in C if not built into python34
it's enough to start a subprocess though and import what I need, as it works with the above code, and I've already reimplemented most of what's actually needed from the standard library in my API.

so yeah, know that I can't use os or any of that stuff. ;)
(most of the standard library is CPU-heavy anyways, which is why it was removed from my API's environment)
^ regardless, it shouldn't be needed as my API implements better automated detection for it's libs and plugins.

EDIT: it's official, image support is broken.

so just to show exactly what I'm trying to do (this code hangs):

# -*- coding: utf-8 -*-
from _winapi import CreatePipe, CreateProcess, CloseHandle
from msvcrt import open_osfhandle
from nt import getpid

# this is just a mock-up path to a local interpreter, since __file__ doesn't include the drive letter on wine
CWD = 'Z:%s'%__file__.replace('test.py','').replace('\\','/')
exec_path = '%sapp/'%CWD
executable = '%spython.exe'%exec_path

crhandle, pwhandle = CreatePipe(None, 0) # parent -> child (input pipe)
prhandle, cwhandle = CreatePipe(None, 0) # child -> parent (output pipe)

subprocess_code = '''
from _winapi import OpenProcess, DuplicateHandle, GetCurrentProcess, CloseHandle
from _winapi import PROCESS_DUP_HANDLE, DUPLICATE_SAME_ACCESS, DUPLICATE_CLOSE_SOURCE
from msvcrt import open_osfhandle
import sys
sys.path = ['.\\DLLs','%s'] # because -I doesn't remove all C:/PythonXX paths (where this interpreter is in ./app/)

source_process_handle = OpenProcess(PROCESS_DUP_HANDLE, False, %s)
try:
    rhandle = DuplicateHandle( source_process_handle, %s, GetCurrentProcess(), 0, False, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)
    from_parent = open( open_osfhandle( rhandle, 0 ), 'rb', closefd=True )

    whandle = DuplicateHandle( source_process_handle, %s, GetCurrentProcess(), 0, False, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)
    to_parent = open( open_osfhandle( whandle, 0 ), 'wb', closefd=True )

    feedback = from_parent.read() # I'd like to run this in a while loop

    to_parent.write(b'Parent told me to say ' + feedback)

    to_parent.close()
    from_parent.close()
    sys.exit(0)
finally:
    CloseHandle(source_process_handle)'''%(exec_path, getpid(), crhandle, cwhandle)

to_child = open( open_osfhandle( pwhandle, 0 ), 'wb', closefd=True )

cmd = '%s -I -S -c "%s" --multiprocessing-fork'%(executable, subprocess_code)
# start process
try:
    subprocess_handle, thread_handle, pid, tid = CreateProcess( executable, cmd, None, None, False, 0, None, None, None)
    CloseHandle(thread_handle)
except:
    CloseHandle(crhandle)
    raise

# send information to child
to_child.write(b'success!') # don't send raw data, these pipes can easily be hacked, especially with python

for i in range(10000000): i+i+1 # give the subprocess enough time to write to the output pipe

from_child = open( open_osfhandle( prhandle, 0 ), 'rb', closefd=True )

feedback = from_child.read() # I'd like to run this in a while loop
print( b'Child said: %s'%feedback )

#input('Press Enter to Exit...\n\n')

CloseHandle(subprocess_handle)
to_child.close()

Does anyone know how to get this working??

I'm going to write "This is why I stopped using pipes and started using sockets." Also, with sockets I can scale across computers in the network.

commented: it's a good suggestion, but not what I'm looking to achieve ;) +4

I don't always wanna be 100% open to the network
plus sockets are super slow as demonstraited by IDLE
(though I could work my magic on that and do things more appropriately rather than use an RPC proxy interface)

My second method. Not as scalable is to pass a boatload of information via a file. I've used the IP methods and files for years for communications among threads or apps. The problem with IPC is as you noted but for me I needed my systems to be agnostic about the OS. So once the IP or file method is known the apps can be on almost any OS or spread across a collection of computers without being locked to any specific OS.

Be aware I am sharing here and not engaging or attempting to tackle your IPC woes.

PS. Added with edit. For me I've never found IP communication to be slow. Since it can be local, it happens without any traversal to the external network.

I've never found IP communication to be slow

you're probably smart and not using python like I am ;)

I needed my systems to be agnostic about the OS.

there's not much I need to worry about
all I really need is the process and pipe creation mechanics for each OS and I can make a simple class that manages everything.

everything in python has the extremely bad habit of extreme abstraction, just look at threading, subprocess, and multiprocessing...
those modules could do the exact same thing and be written with FAR less code.

and then there's modules like watchdog which brutaly abstract these much MUCH farther.
and here I've written (still working on) a single file watcher module that's not even 1000 lines.
(yes this is also part of my API)

to put it short, I'm trying to use "good python", which nobody uses:

  • performative
  • secure
  • memory friendly
  • readable (if you understand how python's mechanics work)

but anyways

not engaging or attempting to tackle your IPC woes.

that's fine, thanks for the advice ;)
I do plan to use sockets, but indirectly to pipes whenever a network session occures.

if anyone else wants to chime in, I do still need this.
I've given up looking for a solution for a time as I'm now working on another section of my API...
but I do intend to get back to this, and still need this method to work.

heck, at the very least provide info, cause I can't seem to find any...
DDG sucks here, and Google's results have been questionable...
Nullege is down, and GitHub just provides 100 pages of copies of subprocess and multiprocessing...
meanwhile other source engines hardly provide good results.

so yeah... I'll bother with this later...
I'm not blowing my brains out on it any longer...
I've already spent too much time on it. (take the discussion span of this post and add 2 days)

interesting
I only just skimmed over it, but it uses all standard library design principals, and doesn't really mention using pipes for syncing, but yeah, I'll give it a look through a few times over.

I think I might be a little more advance than it, cause I'll be using both multiprocessing and multithreading where appropriate ;)

my API has been in design since probably around 2013-2014, and I've learned alot within that time to now :)
going back and re-looking at stuff is always good though.

I know it's been about a year, but I was hoping others would reply in that time...
I'm now getting back to the area of my main project I needed this for, and I still don't know how to create a pipe duplex (tx/rx) between 2 processes.

and yes @rproffitt, I did read what you posted ;)
I don't intend to use files for this because they're not a secure connection like I need
I've actually invented private attributes for python just to have a secure communication standard within my API...
(but this is only within an existing process and is still exposed in RAM)
sockets are actually better than files as they're not as viewable (but still as open), but files are more similar to pipes

pipes are more secure because they're basically hidden with the only access being an ID/pointer
I don't intend to do what the multiprocessing module does using stdin and stdout because that's less secure

in the OP I can successfully create the tx pipe, but the rx pipe fails
doesn't anyone know how to create piped IPC??

I'm sure someone with C knowledge knows...
I mean heck, I'm basically using the C windows calls

Good to see you still working (in the mine?) on this. I think https://docs.microsoft.com/en-us/windows/win32/ipc/pipes is the defacto source on pipes for Windows.

But. The last time we (at an office with fellow programmers) tried to build around Microsoft Pipes it failed so we moved on. In the long run it was a good thing as it gave the app legs to work across networks and even Linux.

As to your comment about security, that's up to us to send messages that are encrypted if need be.

idk about mine... lol
I think the best result there would be down hacking some brute-force method of getting things working
but I'm not quite there yet :)
just trying 1 last attempt to see if anyone knows anything
you know it doesn't always have to be you who answers right? XD
I think you've proven enough you're about as ignorant as I am on this topic :)
(if you're interested though, I could hit you up with a link as soon as this is answered)

lol in any case, I did check out that resource a while back
but it looked rather complex and convoluted to simply understand (that's Microsoft for ya)
I suppose I could give it another look now that I'm older and a bit wiser... :P

but yeah regarding my API and networks, I intend to have another section manage that stuff
through my own root network protocol though because TCP/IP is a joke.
no I'm not rebuilding everything (at least I shouldn't have to)
all I need is access the raw network devices before TCP/IP assigns names like 's0' or 'eth0'
from there I can work on structuring my own packets and providing my own secure virtual space (yes VLAN like, but better)

and regarding security, encryption isn't everything needed to make a secure connection
there's a reason /tmp/ isn't used for establishing secure connections between processes.
but yes, while the pipe I intend to create would be barely accessible (private RAM space), multi-layer encryption is still needed as a breach precaution.
but I've got that covered, I am designing a network protocol to replace Tor after all ;)

why use a pipe if a network protocol does the same thing?
you wouldn't use a monkey wrench just to tighten a screw on your PSU
while you CAN do it, a Phillips-head screw-driver is the proper tool for the job (unless it's a Dell, Compaq, or HP PC, which needs a Torx)

EDIT:
what makes a network socket sound even dumber is that
the public portion of my API launches a private interpreter to manage it's bubble
this is where the pipes are used for the process proxy to communicate with the private subprocess.
a socket doesn't sound very viable here does it ;)

just looked through that resource again, and yeah, all the examples talk about named pipes, not anonymous pipes like I'm working with:
https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe

I'm starting to think Microsoft themselves don't even know how to create anonymous pipes :P
but anyways, I'll try finding a few examples again, maybe something has actually cropped up after 1 year's wait, who knows /shrug

and yeah, I'm not looking for server and client API wrapper junk
just something simple, like the code I have above. :P

EDIT:
ooooh so that's where 1 issue is
_winapi.CreatePipe is not the same as the kernel32 function
https://searchcode.com/codesearch/view/119842938/
the attributes aren't even used... WTF!?

So Microsoft does have what looks to be a working anon pipe at https://docs.microsoft.com/en-us/dotnet/standard/io/how-to-use-anonymous-pipes-for-local-interprocess-communication

It's a shame we can't have lunch and share our stories. It's not as if we (myself and others at the office) didn't try but at the time there was something busted and we were not going to wait for Microsoft to patch it up. Yes it was over a decade ago.

Sorry if I can't give you what you need here. But you did give me a seizure recalling that month of WTH is going on with Microsoft pipes.

oof, sorry, I wasn't trying to push and shove, I'm not THAT impatient :)
(if I can wait a year for an answer, I can certainly wait longer if need be... lol)

I was just doing my own research based on what you provided and learned some new things is all
and then maybe running my mouth a bit aboug blah blah security, blah blah stuff and stuff...
I have a bad habit of doing that around knowledgable people because I'm so used to talking to the uneducated :P

yeah I wasn't trying to induce trama or anything, sorry for the trouble :)
thanks for the resource and absolute credit to you in my API for helping ;D

EDIT:
oh boy... .NET x.x
well, I can at least see how that would be seizure inducing... lmao

EDIT2:
erg >.<
wrappers pipeClient and pipeServer
Microsoft, stop locking my answer behind a stone door >.<

commented: I was searching for a word there and settled on seizure. Anyhow, let's hope a Windows Plumber comes along. +15

@rproffitt lmao I think this job needs a full-on construction crew with how complicated this mess is XD

but anyways, I think once I'm done here, I'll create an actual snippet just to shed some light on this (deliborately?) hidden area.
and of course I'll give you credit for helping :)

better yet, I won't just create a snippet, I'll go full out Tcll-style with _ctypes on 'kernel32.dll'
I ain't working on cbin for nothing ;)
(I've been busy over the past year, I've even overhauled PyWatchDog with far more support in <1000 lines (excluding Mac support))

I don't have cbin or pywatcher in the public yet...
I did at one point, but GitLab kinda screwed me a bit (attempted telemetry and failed), so I pulled my projects and now only have an issue tracker there... :P
once I can host my own git, I'll have them back up ;)

what exactly is Tcll-style code?
it's basically an attempt to get as close to Python-C code (or in other words as performant and efficient) as possible without sacrificing functionality or readability
for example, cbin.Structure overhauls _ctypes.Structure (not ctypes.Structure) with an optimized runtime disassembler that removes the need for the messy attributes like _fields_ or _anonymous_, for example:

class mystruct(Structure):
    attr = c_short

    class u1(AUnion): # anonymous (name is ignored)
        class s1(AStructure):
            a = c_int

        class s2(AStructure):
            a = c_short
            b = c_short

    attr2 = c_short

yes everything will be parsed in order when mystruct is defined
while Gribouillis didn't help me here, he still gets credit for helping me understand how metaclasses work.

EDIT:
what's the sacrifice for this clean code?
only a very small amount (not in Apple terms) of load time, as the metaclass-bound disassembler quickly fills _fields_ and _anonymous_ appropriately using a for loop with a probed iterator.

just to notify, I was slightly wrong about something prior, and have actually been wrong on it since I started this thread >.>
I've been busy with life so it took a few days to look into it, but yeah, that link I posted previously regarding using stdin and stdout
I wrongfully assumed it was "redirecting" pipes to stdin and stdout much like the multiprocessing module does, making the pipes as openly accessible as possible.
(yes python's multiprocessing is false advertising)

no instead what happens is this:

// Set up members of the STARTUPINFO structure. 
// This structure specifies the STDIN and STDOUT handles for redirection.

   ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
   siStartInfo.cb = sizeof(STARTUPINFO); 
   siStartInfo.hStdError = g_hChildStd_OUT_Wr;
   siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
   siStartInfo.hStdInput = g_hChildStd_IN_Rd;
   siStartInfo.dwFlags |= STARTF_USESTDHANDLES;

or in english, it redirects the handles of stdin and stdout to the private pipes during process creation
rather than using 0 handles like python's multiprocessing does
meaning literally everything can be contained and secured with no unused entry point! :D

as much as I hate to say this, I actually have to give Microsoft a +1 here
... though of course this was the Win2000 era of code when they were actually doing good,
so it's at least justified over the scandalous crap they've recently been doing since Vista.
unless they've changed the code of the CreateProcessW() call to be less secure and expose the handles,
which wouldn't surprise me... :smirk:

EDIT:
for others to recap when I talk about security
I know it's not perfect and you can easily get the pipe handles by hacking the process memory space in RAM with something like CheatEngine.
but this is a base I need to provide even further security within my process so my process can dictate what's allowed to connect to a subprocess.
rather than everything being able to connect to it like in previous suggestions.

yes I still need to encrypt the pipe and ensure secure communication
maybe by updating the pipe handles at random and detecting when an intrusion is made
much like I plan to do with something else I'm working on. ;)

EDIT2: ok maybe I'm stupid and hackers can just easily request the stdin handle from the subprocess...
I was thinking this would invalidate that for whatever reason

no it's better if hackers request unused handles that don't do anything (front door reveals a brick wall)
and make them work for the actual handles (back door behind a jail fence)

commented: "Another brick in the wall." Security wasn't implemented in one day but can be broken in less time. +15

rproffitt commented: "Another brick in the wall." Security wasn't implemented in one day but can be broken in less time.

lol so true, I really wish I could upvote that XD
(I made a suggestion to Dani, which included hierarchical collapsible threads, who said it'd be a huge project unfortunately)

but yeah, if I can encrypt the RAM space for my program, and encrypt pipe
I'll have a powerful opaque force-field rather than a ghetto electic jail fence
as for the pipe(s), since the handle will actually be hidden, the connection will be done through quantum entanglement, rather than a suspended wire XD