develooper Front page | perl.perl5.porters | Postings from February 2006

[cpan #17773] Term::ReadLine, CON: and Term::ReadKey on Win32

Thread Next
Jonathan Stowe
February 28, 2006 06:08
[cpan #17773] Term::ReadLine, CON: and Term::ReadKey on Win32
Message ID:
I've had a few bug reports on Term::ReadKey on Windows where people are
getting stuff like:

   SetConsoleMode failed, LastError=|6| at C:/perl/site/lib/Term/ line 265.

(Where SetConsoleMode is the windows API function being called at the
time and the error 6 means 'invalid handle.) I've put these down in the
past to packaging problems or a CRT mismatch (see previous discussion
here on the rĂ´le of mismatched runtimes between Perl and XS modules with
regard to filehandles.)

Anyhow in examining the reports like the above I had completely failed
to notice that it was SetConsoleMode() and not GetConsoleMode() which is
called earlier in the ReadMode() implementation that is failing - if the
OS handle that gets passed to one is invalid it should be invalid when
it gets passed to the first one as well.

Also I hadn't really considered that the reports I was getting were from
when people were using either the debugger or the CPAN shell on the
whole, what these have in common is that they use Term::ReadLine (and
thence Term::ReadLine::readline ).

Anyway it seems to boil down to Term::ReadLines use of 'con' as the
console device on Windows:

    if ($^O eq 'MacOS') {
        $console = "Dev:Console";
    } elsif (-e "/dev/tty") {
	$console = "/dev/tty";
    } elsif (-e "con" or $^O eq 'MSWin32') {
	$console = "con";
    } else {
	$console = "sys\$command";

Now opening CON: as a file works fine for both reading and writing in
Perl programs; it just seems that it doesn't work when you pass a
filehandle opened to it to Term::ReadKey::ReadMode, however I'm pretty
certain that there is nothing that either Perl or Term::ReadKey is doing
wrong and that it is Windows behaviour as exemplified by the result of:

#include <windows.h>
#include <stdio.h>

int main (int argc, char **argv)
	DWORD mode;


		printf("CreateFile failed: %d\n", GetLastError());

	if (! GetConsoleMode(h,&mode) )
		printf("GetConsoleMode failed: %d\n", GetLastError());
	if (! SetConsoleMode(h,mode) )
		printf("SetConsoleMode failed: %d\n", GetLastError());

	return 0;

Which shows the failure in SetConsoleMode() with the same error code as
in the ReadMode failure.

Anyway, to cut to the point, should the use of 'CON:' be changed in
Term::ReadLine?  At simplest we could just set $console to undef in the
above snippet, which works (setting the input and output handles to
STDIN and STDOUT respectively), but some testing with
Term::ReadLine::Perl seems to indicate there might be some blocking (at
least in the tests) and I haven't had time to delve to far into that. An
alternative would be to further special case Win32 in
Term::ReadLine::getConsole and have it sysopen CONIN$ and CONOUT$ as
appropriate as they don't seem to be afflicted with the same problem
that CON: has.  If people want to do that I'll be happy to work up a
patch.  Or maybe someone has a better idea.

I'm also interested in hearing any ideas about the reason for this
problem at the windows level - I can't find any reference to it on MSDN
or with some light googling and I'm not really sure whether it is a bug
or whether it is just an artefact of CON: being there for backward
compatibility with MS-DOS 3.0 .



This e-mail is sponsored by

Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About