Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris

pack()ing Win32 Structures

by mothra (Hermit)
on May 06, 2002 at 00:33 UTC ( #164195=perlquestion: print w/replies, xml ) Need Help??
mothra has asked for the wisdom of the Perl Monks concerning the following question:

I'm confused.

I'm trying to pack() the Win32 structure TIME_ZONE_INFORMATION and the seemingly much simpler SYSTEMTIME structure within that. The purpose for this is to preallocate the memory for the parameters to pass to GetTimeZoneInformation (which I'm accessing via Win32::GUI) to pull out both the timezone string (e.g. "CST") and the time bias from UTC.

Currently, I'm using the following code:

sub convertUTC2LocalTime { # convert the time passed to the timezone of the machine my $utc = shift; my $return; my $systime_struct; my $tz_struct; $systime_struct = pack("S8", 0, 0, 0, 0, 0, 0, 0, 0); $tz_struct = pack("Lu32PLu32PL", 0, " " x 32, $systime_struct, 0, " " x 32, $systime_struct, +0); print "$systime_struct\n"; print "$tz_struct\n"; my $GetTimeZoneInformation = new Win32::API( "kernel32", "GetTimeZoneInformation", "P", "N" ); die "Failed to import API GetTimeZoneInformation: $!" unless defined($GetTimeZoneInformation); $return = $GetTimeZoneInformation->Call($tz_struct); $bias = (unpack("Lu32PLu32PL", $tz_struct))[0]; print $bias; }

However, when I run this code, I get an error like "Perl has caused an error in MSVCRT.DLL. Perl will now close."

I'm almost sure the bug is in the pack()ing. What would be the proper pack() template for this structure?

Replies are listed 'Best First'.
Re: pack()ing Win32 Structures
by JayBonci (Curate) on May 06, 2002 at 01:58 UTC
    Good evening. It sounds like you have a good one there. Lemme see what I can do to help. I'm not a pack ninja, but I see a few things that might be wrong. From the MSDN documentation of TIME_ZONE_INFORMATION,
    typedef struct _TIME_ZONE_INFORMATION { LONG Bias; WCHAR StandardName[ 32 ]; SYSTEMTIME StandardDate; LONG StandardBias; WCHAR DaylightName[ 32 ]; SYSTEMTIME DaylightDate; LONG DaylightBias; } TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION;
    You're looking at Long, 32 Unicode characters, a structure, Long, 32 Unicode Characters, a structure, Long. The SYSTEMTIME structure is 8x16 bits, and that pack stucture looks right. However, where you seem to be going wrong is that you are packing a string where you should be packing the structure itself. Therefore, you are passing a packed string to the API function, and that probably isn't correct. Should your pack string look like this:
    $tz_struct = pack("LU32S8LU32S8L", 0, " " x 32, unpack("S8",$systime_struct),0, " " x 32, unpack("S8",$systime_struct),0);
    I think you might also want to use capital U in pack instead of lowercase u, meaning 32 characters, and not 32 strings, but I could be reading the doc wrong. Another way to test it might be to pack yourself a gigantic structure of zeros, and see if it still crashes. Where is it dying (what's the last statement that runs before it rolls over)? Good luck.

Re: pack()ing Win32 Structures
by jsprat (Curate) on May 06, 2002 at 02:06 UTC
    A couple of things -

    1. 'u' in the pack template is UUEncoded text, I think you want 'U' for unicode, right? The template you are looking for should be "LU32PLU32PL"
    2. Instead of " " x 32, pass a list of 32 32's, for example:
      push @splist, 32 for (1 .. 32); $tz_struct = pack("LU32PLU32PL", 0, @splist, $systime_struct, 0, @splist, $systime_struct, 0 +);
    3. 'P' and 'N' are constants defined in Win32::API, not strings. The third parameter to new Win32::API should be an anonymous list or an array reference, not a string literal
      'GetTimeZoneInformation', [P], N
    4. Have fun unpacking the unicode string! If all you are interested in is the bias, try "LS64PLS64PL" for the template.


    Updated my Win32::API, and updated #3 above. Thanks mothra:-)
    BTW, $bias returns 480 after making the above modifications (UTC -8)
      'P' and 'N' are constants defined in Win32::API, not strings. The third parameter to new Win32::API should be an anonymous list or an array reference, not a string literal
      'GetTimeZoneInformation', [P], N
      FWIW, according to the documentation, string literals are allowed for specifying the types of the parameters.
        You must have a newer version of Win32::API than I do. The docs in mine say:

        The third parameter, the input parameter list, specifies how many arguments the function wants, and their types. It MUST be passed as a list reference.

OT: Re: pack()ing Win32 Structures
by mdillon (Priest) on May 06, 2002 at 02:02 UTC
    I'm confused. Why do you keep front-paging your own nodes? You front-paged your own node last time you posted a top-level node and again this time. All your previous top-level nodes are previous to when the front-paging user was recorded, so I don't know if you did it before that change was made and the "front-page messages" in the Chatterbox went away.

    It is generally considered taboo to front-page one's own nodes, so why do you continue to do it?

      I don't "keep front-paging my own nodes". I've done so twice. Ever.

      Further, I didn't realize this was considered taboo. I operate on the logic that if a question looks interesting, instructive, and the problem is relatively generic enough to appeal to a broad audience, I front-page it. The last two times, these happened to be my own nodes.

      In future, and to preclude such attacks, I'll be sure to let others moderate my nodes as applicable.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://164195]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (5)
As of 2017-03-28 05:27 GMT
Find Nodes?
    Voting Booth?
    Should Pluto Get Its Planethood Back?

    Results (327 votes). Check out past polls.