Wednesday 8 December 2021

Serial Perl Revisited

I'd posted this item on creating a custom serial driver / interface in  PERL a few years ago, and needing to revisit it for another project, I found that there was now an issue with running the Win32::Serial module on 64-bit Windows, Windows 10 specifically.

The problem was, when I ran some Perl that previously worked for me, it now failed when querying a serial port with an error like this;

error: Second Read attempted before First is done at xantech.pl line 47.

Some Google-Fu later, I found a reference to the issue on PerlMonks, and a link by user cr8josh to the fix by Christopher Oicles which is published here.

It looks like there's a risk that the rt.cpan site will close, so I'm reproducing the fix here for my own future sanity;

The only problem with this module on 64-bit windows is the layout of the OVERLAPPED struct.  The 32-bit version of this struct has a size of 20 bytes, but the 64-bit version is 32 bytes, because the fields “Internal”, “InternalHigh” and “hEvent” are all quadwords instead of doublewords (“Pointer” also becomes a quadword, but it is part of a union which is quadword-sized in both 32- and 64-bit versions, and it is not used in Win32API::CommPort).

The fix is trivial, and allows both bitnesses to share the same Perl Module.  Here are the edits I made to CommPort.pm which got it working:

Line 467

Original:

    my $OVERLAPPEDformat="LLLLL";

Edited:

    my $OVERLAPPEDformat = (length pack 'P') * 8 == 32 ? "LLLLL" : "QQLLQ";

    # “length pack 'P'” gives you the size of a null pointer, then I multiply by 8 to get a bit count, just for clarity.

 

Lines 768 and 769

Original:

    $self->{"_R_OVERLAP"}            = " "x24;

    $self->{"_W_OVERLAP"}          = " "x24;

Edited:

    $self->{"_R_OVERLAP"}            = " "x32;

    $self->{"_W_OVERLAP"}          = " "x32;

 

# These lines populate the fields with some default (and invalid) bytes.  It really doesn’t look like over-allocating these by a few bytes can cause problems, so I just unconditionally set these to the 64-bit version of the stuct’s length (but I didn’t test under 32-bit after this change, so someone should verify the exposure).

 

(for me, the CommPort.pm is in C:\Strawberry\perl\vendor\lib\Win32API)





1 comment:

Anna said...

Interesting post, thanks for sharing.