$OPTIMIZE ON
$APPTYPE CONSOLE
$TYPECHECK ON
$ESCAPECHARS ON

Const GMEM_FIXED=0
Const GMEM_MOVEABLE=2
Const GMEM_ZEROINIT=64
Const GMEM_INVALID_HANDLE=&H8000
Const STD_INPUT_HANDLE = -10&
Const STD_OUTPUT_HANDLE = -11&
Const STD_ERROR_HANDLE = -12&
Const INVALID_HANDLE_VALUE=-1
Const DUPLICATE_CLOSE_SOURCE=1
Const DUPLICATE_SAME_ACCESS=2
Const DUPLICATE_IREAD_HANDLE=0
Const DUPLICATE_IWRITE_HANDLE=1
Const DUPLICATE_OREAD_HANDLE=2
Const DUPLICATE_OWRITE_HANDLE=3
Const CREATE_SUSPENDED=4
Const INFINITE_TIMEOUT=&HFFFF
Const WAIT_OBJECT_0=0
Const WAIT_ABANDONED_0=128
Const WAIT_TIMEOUT=258
Const WAIT_FAILED=&HFFFFFFFF

Declare Function CloseHandle Lib "kernel32.dll" Alias "CloseHandle" (hObject As Long) As Long
Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByVal dest As LONG, ByVal source As LONG, ByVal numBytes As LONG)
Declare Function CreatePipe Lib "kernel32.dll" Alias "CreatePipe" (hReadPipe As Long, hWritePipe As Long, pipeAttrs As Long, bufSize As Long) As Long
Declare Function CreateThread Lib "kernel32.dll" Alias "CreateThread" (attrs As Long, stackSize As Long, startAddress As Long, parameter As Long, flags As Long, id As Long) As Long
Declare Function DuplicateHandle Lib "kernel32.dll" Alias "DuplicateHandle" (hProcess As Long, hDuplicate As Long, hProcess1 As Long, duplicate As Long, access As Long, inherit As Long, options As Long) As Long
Declare Function GetCurrentProcess Lib "kernel32.dll" Alias "GetCurrentProcess" () As Long
Declare Function GetLastError Lib "kernel32.dll" Alias "GetLastError" () As Long
Declare Function GetStdHandle Lib "kernel32.dll" Alias "GetStdHandle" (hType As Long) As Long
Declare Function GlobalAlloc Lib "kernel32.dll" Alias "GlobalAlloc" (flags As Long, numBytes As Long) As Long
Declare Function GlobalFree Lib "kernel32.dll" Alias "GlobalFree" (hMem As Long) As Long
Declare Function GlobalLock Lib "kernel32.dll" Alias "GlobalLock" (hMem As Long) As Long
Declare Function GlobalUnlock Lib "kernel32.dll" Alias "GlobalUnlock" (hMem As Long) As Long
Declare Function ReadFile Lib "kernel32.dll" Alias "ReadFile" (hFile As Long, buffer As Long, bytesToRead As Long, bytesRead As Long, overlapped As Long) As Long
Declare Function ResumeThread Lib "kernel32.dll" Alias "ResumeThread" (hThread As Long) As Long
Declare Function SetStdHandle Lib "kernel32.dll" Alias "SetStdHandle" (hType As Long, handle As Long) As Long
Declare Function WaitForSingleObject Lib "kernel32.dll" Alias "WaitForSingleObject" (handle As Long, timeout As Long) As Long
Declare Function WriteFile Lib "kernel32.dll" Alias "WriteFile" (hFile As Long, buffer As Long, bytesToWrite As Long, bytesWritten As Long, overlapped As Long) As Long
Declare Function thread_routine () AS LONG

' Pipe Variables.
DIM iread_Handle AS LONG, iwrite_Handle AS LONG
DIM oread_Handle AS LONG, owrite_Handle AS LONG
DIM duplicate_Handles(0 TO 9) AS LONG
DIM isecurity(0 TO 2) AS LONG, osecurity(0 TO 2) AS LONG
DIM input_Handle AS LONG, output_Handle AS LONG, error_Handle AS LONG
DIM mem_Lock AS LONG, mem_Memory AS LONG, mem_Default AS LONG
DIM mem_Offset AS LONG
DIM thread_Address AS LONG, threadID AS LONG, thread_Handle AS LONG

' Generic Variables.
DIM rtn AS LONG, rtnval AS LONG, stg$ AS STRING, count AS LONG
DIM FLong AS LONG, FWord AS WORD, FByte AS BYTE, FDWord AS LONG

isecurity(0)=12
isecurity(1)=0
isecurity(2)=1

osecurity(0)=12
osecurity(1)=0
osecurity(2)=1

SUB UnLock_DefaultMemory
IF mem_Lock<>0 THEN
rtn=GlobalUnlock(mem_Lock)
IF ((rtn=0) AND (GetLastError()=0)) THEN
'MEM UNLOCKED
ELSE
'MEM NOT UNLOCK
END IF
END IF
END SUB

SUB Free_DefaultMemory
IF mem_Memory<>0 THEN
rtn=GlobalFree(mem_Memory)
IF rtn=0 THEN
'MEM FREED
ELSE
'MEM NOT FREED
END IF
END IF
END SUB

SUB Alloc_DefaultMemory(bufsize AS LONG)
mem_Lock=0
mem_Memory=0
mem_Default=0
mem_Memory=GlobalAlloc(GMEM_MOVEABLE OR GMEM_ZEROINIT, bufsize)
IF mem_Memory<>0 THEN
mem_Lock=GlobalLock(mem_Memory)
IF mem_Lock<>0 THEN
mem_Default=mem_Lock

END IF
END IF
END SUB

SUB Close_Handle(handle AS LONG)
IF handle<>0 THEN
rtn=CloseHandle(handle)
IF rtn<>0 THEN
PRINT "Handle - Closed"
ELSE
PRINT "Handle - NOT Closed"
END IF
END IF
END SUB

SUB Duplicate_Handle(handle AS LONG, hType AS BYTE)
IF handle<>0 THEN
rtn=DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), VarPtr(duplicate_Handles(hType)), 0, 0, DUPLICATE_SAME_ACCESS)
IF rtn<>0 THEN
PRINT "Handle Duplicated"
ELSE
PRINT "Duplicate Failed"
END IF
END IF
END SUB

SUB Set_Handle(hType AS LONG, handle AS LONG)
IF handle<>0 THEN
rtn=SetStdHandle(hType, handle)
IF rtn<>0 THEN
PRINT "Set Handle - Done)"
ELSE
PRINT "Set Handle - Error: "+str$(getlasterror())
END IF
END IF
END SUB

SUB Get_ErrorHandle
error_Handle=GetStdHandle(STD_ERROR_HANDLE)
IF error_Handle<>INVALID_HANDLE_VALUE THEN
PRINT "Get Error Handle - Done)"
ELSE
PRINT "Get Error Handle - Error: "+str$(getlasterror())
END IF
END SUB

SUB Get_OutputHandle
output_Handle=GetStdHandle(STD_OUTPUT_HANDLE)
IF output_Handle<>INVALID_HANDLE_VALUE THEN
PRINT "Get Output Handle - Done)"
ELSE
PRINT "Get Output Handle - Error: "+str$(getlasterror())
END IF
END SUB

SUB Get_InputHandle
input_Handle=GetStdHandle(STD_INPUT_HANDLE)
IF input_Handle<>INVALID_HANDLE_VALUE THEN
PRINT "Get Input Handle - Done)"
ELSE
PRINT "Get Input Handle - Error: "+str$(getlasterror())
END IF
END SUB

SUB Read_Pipe(handle AS LONG, bufSize AS LONG)
IF handle<>0 THEN
rtn=ReadFile(handle, mem_Default, bufSize, VarPtr(rtnval), 0)
IF rtn<>0 THEN
print "read"
ELSE
print str$(getlasterror())
END IF
END IF
END SUB

SUB Write_Pipe(handle AS LONG, bufSize AS LONG)
IF handle<>0 THEN
rtn=WriteFile(handle, mem_Default, bufSize, VarPtr(rtnval), 0)
IF rtn<>0 THEN
print "written"
ELSE
print str$(getlasterror())
END IF
END IF
END SUB

SUB Create_InputPipe(bufSize AS LONG)
rtn=CreatePipe(VarPtr(iread_Handle), VarPtr(iwrite_Handle), @isecurity(0), bufSize)
IF rtn<>0 THEN
PRINT "PIPE - Created"
ELSE
PRINT "PIPE - Error: "+str$(getlasterror())
END IF
END SUB

SUB Create_OutputPipe(bufSize AS LONG)
rtn=CreatePipe(VarPtr(oread_Handle), VarPtr(owrite_Handle), @osecurity(0), bufSize)
IF rtn<>0 THEN
PRINT "PIPE - Created"
ELSE
PRINT "PIPE - Error: "+str$(getlasterror())
END IF
END SUB

SUB Wait_ForThread(handle AS LONG, timeout AS LONG)
IF handle<>0 THEN
rtn=WaitForSingleObject(handle, INFINITE_TIMEOUT)
IF rtn<>WAIT_FAILED THEN
PRINT "Thread - Signalled"
ELSE
PRINT "Wait - Failed"
END IF
END IF
END SUB

SUB Resume_Thread
rtn=ResumeThread(thread_Handle)
IF rtn<>&HFFFFFFFF THEN
PRINT "Thread - Resumed"
ELSE
PRINT "Thread - Failed"
END IF
END SUB

SUB Create_Thread
thread_Handle=CreateThread(0, 0, thread_Address, 0, CREATE_SUSPENDED, VarPtr(threadID))
IF thread_Handle<>0 THEN
PRINT "Thread - Created/Paused"
ELSE
PRINT "Thread - Failed"
END IF
END SUB

FUNCTION thread_routine () AS LONG
Read_Pipe(duplicate_Handles(2), 10)
print VarPtr$(mem_Default)
Result=1
END FUNCTION

' Allocate a default buffer for General Use.
Alloc_DefaultMemory(3000)

' Get the current Input, Output and Error Handles.
Get_InputHandle
Get_OutputHandle
Get_ErrorHandle

' Create PIPE 1.
Create_OutputPipe(4096)
' Set the Standard Output Handle to the write handle of PIPE 1.
Set_Handle(STD_OUTPUT_HANDLE, owrite_Handle)
' Duplicate the Read Handle of PIPE 1 and give it Inheritance Access,
' so another Process/Thread can access/read the written data.
Duplicate_Handle(oread_Handle, DUPLICATE_OREAD_HANDLE)

' Create a PIPE for reading from.
'Create_InputPipe(4096)
' Set the Standard Input Handle to the read handle of the read pipe.
'Set_Handle(STD_INPUT_HANDLE, iread_Handle)
' Duplicate the Write Handle of the read pipe.
'Duplicate_Handle(iwrite_Handle, DUPLICATE_IWRITE_HANDLE)
' Close the Write Handle of the read pipe - It is no longer needed
' as it has been duplicated.
'Close_Handle(iwrite_Handle)

' Create a Thread (but don`t execute it yet as it will read the data
' to early).
thread_Address=CODEPTR(thread_routine)
Create_Thread

' Write to PIPE 1.
stg$="Hello. I am PIPE 1."+CHR$(0)+CHR$(0)
CopyMemory mem_Default, VarPtr(stg$), LEN(stg$)
Write_Pipe(owrite_Handle, LEN(stg$))

' Now something has been written you can turn on the Thread.
Resume_Thread

' Wait for the thread to (Signal) finished.
Wait_ForThread(thread_Handle, INFINITE_TIMEOUT)

' Close the Read Handle of PIPE 1.
Close_Handle(oread_Handle)

' Close the Write Handle of PIPE 1.
Close_Handle(owrite_Handle)

' Set the Standard Input and Output Handles back to their original (The
' Console).
Set_Handle(STD_INPUT_HANDLE, input_Handle)
Set_Handle(STD_OUTPUT_HANDLE, output_Handle)

UnLock_DefaultMemory
Free_DefaultMemory

Sleep 4444
