\documentclass[11pt]{article} \usepackage{pl} \usepackage{html} \makeindex \title{Windows Console Library} \author{Jan Wielemaker \\ SWI \\ University of Amsterdam \\ Roetersstraat 15 \\ 1018 WB~~Amsterdam \\ E-mail: jan@swi.psy.uva.nl} \begin{document} \maketitle \begin{abstract} This document describes the programmers interface of the console library used by SWI-Prolog. \end{abstract} \section{Entry-Point} Windows GUI programs start at WinMain(). When using the console library, write a main() function with the conventional argc/argv calling conventions, and call rlc_main() from WinMain like this (example from SWI-Prolog \file{pl-ntmain.c}): \begin{code} int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { return rlc_main(hInstance, hPrevInstance, lpszCmdLine, nCmdShow, win32main, LoadIcon(hInstance, "SWI_Icon")); } \end{code} The descriptin of rlc_main() is: \begin{description} \cfunction{int}{rlc_main}{\cdecl{HANDLE}{hInstance}, \cdecl{HANDLE}{hPrevInstance}, \cdecl{LPSTR}{lpszCmdLine}, \cdecl{int}{nCmdShow}, \cdecl{RlcMain}{mainfunc}, \cdecl{HICON icon}} Initialises the library, creates the console, breaks the commandline and calls \arg{mainfunc}. A separate thread is created for updating the console. \arg{mainfunc} is called in the same thread that is calling rlc_main(). If \arg{mainfunc} is \const{NULL}, rlc_main() returns after initialising the console. \end{description} \section{I/O} The library defines the following functions for reading and writing the console: \begin{description} \cfunction{int}{rlc_write}{\cdecl{char *}{buf}, \cdecl{unsigned int}{count}} Output the contents of the buffer and return the number of characters written. The return value is -1 if some error occurred. The data is sent to the console thread synchronously, after which a flush request is sent to the input queue of the console thread. This library does not provide formatted or character oriented write operations. SWI-Prolog's \file{pl-stream.c}/\file{pl-stream.h} provide this layer. \cfunction{int}{rlc_read}{\cdecl{char *}{buf}, \cdecl{int}{count}} Read at most \arg{count} characters or a line. The last written incomplete line is regarded as the `prompt'. The user can edit the line using Emacs commands and browse through the command history using line up/down commands. \cfunction{int}{getch}{} Return a single character as soon as it becomes available. When switching to reading character-by-character mode, characters in the rlc_read() input buffer are returned immediately. \end{description} \section{Interrupts} Probably the most difficult issue is handling interrupts. Basically, a callback function should be registered using rlc_interrupt_hook(): \begin{description} \cfunction{RlcInterruptHook}{rlc_interrupt_hook}{\cdecl{RlcInterruptHook}{new}} Register an interrupt hook. This function is called if the user hits Control-C. Note that this function is called in the thread of the console. The application is responsible transferring the interrupt request to the main thread. There are several possibilities for doing this, but none is really asynchronous as Unix users are used to. SWI-Prolog uses the following schema. The main thread (i.e.\ the initialisation) creates a (hidden) window, implementing WM_SIGNALLED (a private message id), which calls the SWI-Prolog signal dispatcher. If the hook is executed in the main thread (which should not be the case), it will call the Prolog handler immediately. Otherwise, it will call PL_raise(), which schedules the interrupt. At each pass through the call-port, the Prolog kernel checks for scheduled signals and executes their handlers. For the case where Prolog is waiting for a (Windows) message, WM_SIGNALLED is posted to the hidden window. See SWI-Prolog's \file{pl-ntmain.c} for details. \end{description} \end{document}