Python output to System.Console

Hi @TomTom,

This is regarding your proposal here:

When I run this code a few times in a row I get an error and can no longer run it.

# output from Rhino Python to Command Prompt
# by TomTom
import System
import System.IO as io
from System import Console
import Microsoft.Win32.SafeHandles as sh
import ctypes as ct

stdOutputHandle = ct.c_int(-11)
ct.windll.kernel32.AllocConsole()
intPt = ct.windll.kernel32.GetStdHandle(stdOutputHandle)
stdHandle = System.IntPtr(intPt)
safeFileHandle = sh.SafeFileHandle(stdHandle, True)
fileStream = io.FileStream(safeFileHandle, io.FileAccess.Write)
encoding = System.Text.Encoding.GetEncoding(437)
standardOutput = io.StreamWriter(fileStream, encoding)
standardOutput.AutoFlush = True
Console.SetOut(standardOutput)
Console.WriteLine("This is a console window")

Any idea what is the issue?

Also how can I close the console without closing Rhino?

Thanks in advance.

Well this was kind of a proof of concept, I just threw in that discussion. Because I know about the possibility to open up consoles in Gui projects. I‘ll have a look at it. I think you need to make sure to execute the console invokation only once. So the console needs to be open from the Rhino python script, not within grasshopper. My first guess, maybe the garbage collection cleans things up after a while. So encapsulating it in a class, and attaching an singleton instance to the sticky may already solve the issue?! I‘ll test…

1 Like

You’ll need to test that…My tests work…

import System
import System.IO as io
from System import Console
import Microsoft.Win32.SafeHandles as sh 
import ctypes as ct
import scriptcontext


class ConsoleInvocator():
    def __init__(self):
        self.consoleHandle = None
        self.fileStream = None
        self.standardOutput = None
        
        # for primitive unittesting
        self.triedToOpenMultipleTimes = False;
        
        if scriptcontext.sticky.has_key("console"):
            print ("Console already running... Abort")
            self.triedToOpenMultipleTimes = True;
            return
            
        print ("A new console gets invocated...")
        self.__initConsole()
        scriptcontext.sticky["console"] = self

    def __initConsole(self):
        ct.windll.kernel32.AllocConsole() 
        intPt = ct.windll.kernel32.GetStdHandle(ct.c_int(-11))
        
        self.consoleHandle = sh.SafeFileHandle(System.IntPtr(intPt), True) 
        
        self.fileStream = io.FileStream(
            self.consoleHandle, io.FileAccess.Write)
            
        encoding = System.Text.Encoding.GetEncoding(437)
        self.standardOutput = io.StreamWriter(self.fileStream, encoding) 
        self.standardOutput.AutoFlush = True  
        
        Console.SetOut(self.standardOutput) 

ConsoleInvocator()
1 Like

Thanks @TomTom, it does work with the “sticky protection”. :slight_smile:

I’ll try to figure out a way to close this console window without crashing Rhino.