brahn
March 16, 2018, 10:19am
1
Today I was inspired to respond to a StackOverflow question and pulled this example together from pieces I found on the newsgroup
Compile the program, run it from a command line and mash the button!
PROGRAM
HANDLE EQUATE(UNSIGNED)
DWORD EQUATE(ULONG)
BOOL EQUATE(BYTE)
VOID EQUATE(LONG)
LPVOID EQUATE(ULONG)
LPDWORD EQUATE(ULONG)
ATTACH_PARENT_PROCESS EQUATE(-1)
STD_OUTPUT_HANDLE EQUATE(-11)
MAP
MODULE('API')
AttachConsole(DWORD dwProcessId),BYTE,PASCAL,RAW
FreeConsole(),BYTE,PROC,PASCAL,RAW
GetStdHandle(DWORD nStdHandle),LONG,PASCAL,RAW
WriteConsoleA( |
HANDLE hConsoleOutput, |
VOID lpBuffer, |
DWORD nNumberOfCharsToWrite, |
*LPDWORD lpNumberOfCharsWritten, |
LPVOID lpReserved),BYTE,PASCAL,RAW,PROC
END
WriteLine PROCEDURE(STRING pMessage)
END
Window WINDOW('Test WriteConsole'),AT(,,101,43),GRAY,FONT('Microsoft Sans Serif',8)
BUTTON('Write To Stdout'),AT(17,12),USE(?ButtonTest)
END
CODE
Open(Window)
ACCEPT
IF Event() = EVENT:Accepted AND Accepted() = ?ButtonTest
WriteLine('Hi!')
END
END
WriteLine PROCEDURE(STRING pMessage)
conHandle HANDLE
outLen LPDWORD
bufferStr &CSTRING
CODE
bufferStr &= New(CSTRING(Len(pMessage)+2))
bufferStr = pMessage & '<10><0>'
IF AttachConsole(ATTACH_PARENT_PROCESS)
conHandle = GetStdHandle(STD_OUTPUT_HANDLE)
WriteConsoleA(conHandle,Address(bufferStr),LEN(bufferStr),outLen,0)
FreeConsole()
END
Dispose(bufferStr)
RETURN
3 Likes
Hi Brahn,
Interesting, note you don’t need the string reference with it’s new and dispose you can just use LEN to create a cstring of the required length, as in …
WriteLine PROCEDURE(STRING pMessage)
conHandle HANDLE
outLen LPDWORD
bufferStr CSTRING(LEN(pMessage)+2)
CODE
bufferStr = pMessage & '<10><0>'
IF AttachConsole(ATTACH_PARENT_PROCESS)
conHandle = GetStdHandle(STD_OUTPUT_HANDLE)
WriteConsoleA(conHandle,Address(bufferStr),LEN(bufferStr),outLen,0)
FreeConsole()
END
RETURN
1 Like
brahn
March 17, 2018, 9:41am
3
Oh neat, I forgot about that!
I’m not sure how necessary the FreeConsole() is either but I was trying it out.
FreeConsole() is needed, i tried to remove it but then there was no output.
n.b. Used it in a small app writing a few lines to the console and exiting directly after. it does not return to show the command prompt again, but it’s ready and you can type a new command.
In case anyone is interested: this example will compile just fine as-is under Clarion 11. Clarion 9.1 must have a bit of a bug.
Under Clarion 9.1:
If you are compiling in DLL mode , you have to use LibMaker.exe to create a .lib file that contains just the AttachConsole entry point from C:\WINDOWS\System32\kernel32.dll
If you’re compiling in LIB mode , you do not need to make this custom .lib file, or do anything special to include the AttachConsole entry point lib
Thanks to Rick Martin for helping me solve that one.
jslarve
September 29, 2021, 3:45pm
7
There has been some maneuvering of stuff in the shipping WIN32.LIB and other libs. AttachConsole is in there now, but was not in 9.1.
Used this today. Works great.
1 Like
Brahn did create a ConsoleSupport Class
and an example on GitHub. IIRC on my Laptop I have an enhanced version I’ll try to find.
This is the Console INC file Class to give an idea of methods in the CLW file .
ConsoleSupport Class(),Type,Module('ConsoleSupport.Clw'),LINK('ConsoleSupport.Clw',1)
! Properties
inputHandle HANDLE
outputHandle HANDLE
textBuffer CSTRING(2048)
outBuffer CSTRING(2048)
inBuffer CSTRING(2048)
bytesWritten LONG
bytesRead LONG
prefix CSTRING(21)
! Methods
Construct PROCEDURE
Destruct PROCEDURE(),VIRTUAL
Init PROCEDURE(),BYTE,PROC,VIRTUAL
WriteLine PROCEDURE(STRING pText),BYTE,PROC,VIRTUAL
ReadKey PROCEDURE(),STRING,PROC,VIRTUAL
GetLastSystemError PROCEDURE ( LONG pLastErr=0 ),STRING
END
One important setting is the Project EXP file must have the First line end with CUI not GUI . You’ll see this in his Console Test project EXP file .
NAME 'CONSOLETEST' CUI
It’s probably appropriate for someone to fork and maintain that repo given that fushnisoft was @brahnp / @brahn and he has passed away.
mriffey
February 1, 2024, 11:12pm
12