in reply to Win32::API getting a listing of available serial ports
This is one of those really awkward apis to locate, call and decode.
The docs tell the c-programmer the names of the header file and library to use, but that doesn't translate into the name of the dll to load.
Having encountered the problem of mapping apis to the exporting dlls on many occasions, I have a huge file that contains the export list (via dumpbin /exports) of all the dlls in my system32 directory. Searching this for EnumPorts turns up several candidates:
The most obvious candidate is SPOOLSS.DLL, and it is possible to import that entrypoint using Win32::API, but calling it does that most annoying of failures, it simply terminates the perl executable without any error message, trap dialog or anything else. I've encountered this before with other of my hazard-a-guess attempts at calling apis and I've generally found another DLL that does work, so I've learnt to not try and debug the problem, just move on.
Next I tried unicows.dll. Interesting name, though I haven't a clue what it might mean. Most interestingly, I can call this one and get data returned.
The docs above suggest that there is also a EnumPortsA varient of this call somewhere, but it doesn't appear in my big list anywhere.
The problem with pointers to null-terminated unicode/wide character strings is that Perl doesn't have a method for indirecting through them.
unpack has 'P' and 'p' templates for accessing data through arbitrary pointers, but the former requires that you know how long the data is, and the latter only handles null-terminated ASCII data.
In MS's wide character strings (basically utf16le), ASCII bytes are 'padded' with null bytes, which the 'p' template will take as the end-of-string marker, so you only get 1 character strings returned.
A bodge-it and see way around this is to use the 'P' template with a guess at the length of the data and hope that you don't walk off the end of the buffer somwhere.
If anyone wants to teach this old dog a new trick, please feel free to do so. Actually, if you like you could feel obliged :)
Upshot: This is what I got as far as it goes. It shows that I have successfully retrieved the data, but the mechanism for accessing it leaves much to be desired. This would probably be easier to do vis Inline::C.
HTH.
#! perl -slw use strict; use Win32::API::Prototype; ApiLink( 'unicows', q[ BOOL EnumPortsW( LPTSTR pName, DWORD Level, LPBYTE pPorts, DWO +RD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned ) ], ) or die $^E; my $bytesNeeded = pack 'V', 0; my $portsRecvd = pack 'V', 0; my $buf = chr(0) x 2000; print '?',EnumPortsW( 0, 1, $buf, 2000, $bytesNeeded, $portsRecvd );# +or print $^E; $bytesNeeded = unpack 'V', $bytesNeeded; $portsRecvd = unpack 'V', $portsRecvd; print "b:$bytesNeeded p:$portsRecvd"; my @pointers = unpack "V$portsRecvd", $buf; printf "%08x\n", $_ for @pointers; print unpack 'P12', $_ for unpack '(a4)10', $buf; __END__ C:\test>junk9 ?1 b:160 p:10 019190e6 019190da 019190ce 019190c2 019190b6 019190aa 0191909e 01919092 01919086 0191907c U S B 0 0 1 C O M 1 : C O M 2 : C O M 3 : C O M 4 : F I L E : L P T 1 : L P T 2 : L P T 3 : N U L : L
Considered: BrowserUk: "Could be deleted." Vote was: Keep: 10, Edit: 0, Reap: 5.
Unconsidered: davido: Positive node rep and sufficient keep votes prevent reaping.
|
|---|