Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Create MSWindows Registry REG_EXPAND_SZ entry

by Intrepid (Deacon)
on Jul 02, 2003 at 09:47 UTC ( #270750=CUFP: print w/ replies, xml ) Need Help??

Hi, Monks. I've been trying to add a MS Windows shell context entry to enable me to alternate-mouse click on a file or folder in Windows Explorer GUI, and have the file name as Cygwin sees it placed on the Clipboard. Because the Perl tool I wrote to help me accomplish this was used it for enhancing my enjoyment of Cygwin, this qualifies in my book as a CUFP.

This (context-menu access to the Cygwin-mode filename) has been invented before, but TTBOMK nobody has shown how to make it portable across different people's systems without editing the .reg file manually.

BTW, to get this to work I used what's already defined in my master Windows ENV, a variable %CYGROOT% which points to the MSWin32 mode path spec of the top of my Cygwin installation tree.

Substitute your own different software installation needs and you may agree that this could be pretty useful once in a while.

Update:
Except that you cannot get Win95, 98, prob. ME to import such a key value-data type into the Registry. I have just found out that the inferior REGEDIT tool supplied with these inferior versions of Windows is incapable of doing this. The later NT4/5-derived Windows can do so.

There's really some Perl coming soon, I promise. I just dislike very incomplete and puzzling explanations that people sometimes give about software I am unfamiliar with, that leaves me totally in the dark about why they bothered. So here's the rest of the set-up...

There are several "DATA TYPES" (Microsoft terminology) possible for MS Win Registry entries. The type most of us would call a "C string" is called a REG_SZ and is formatted as a simple string (but with some complex quoting and escaping rules). There's a logically and semantically (since "SZ" is is Microsoft-speak for "null-terminated string") related Registry data type called a REG_EXPAND_SZ that can contain a level of "indirection" in the form of a system variable that can be resolved at the time of use of the entry. For example:


   "SoMeThIng"="%WINDIR%\\system32"
could in our naive imagination be a Registry .REG -file line indicating a directive to insert a value-data pair into a key, except that REG_EXPAND_SZ data must be presented as what MS calls a *binary* data type (subtype "2"), so the value must be formatted in a kind of hexidecimal format, comma-delimited, two tokens per byte (padded with zeros), with a terminating null byte of course (and further explanation is obviously far beyond the scope of this article, and the author won't be held responsible for anyone's misuse of the incomplete information given thus far). So the line above will not work but indicates the end result I wanted to achieve. As a real working .REG -file entry the example above must be rendered as:

  "SoMeThIng"=hex(2):22,25,57,49,4e,44,49,52,25,5c,5c,73,79,73,74,65,6d,33,32,22,00
Finally we get to the Perl. Perl does what's needed here with such elegance and efficiency, <sigh>. Given a "Registry psuedo-code" string that *describes* what we want the "decoded" string to look like, like that shown earlier, Perl can generate the kind of hex format needed for inclusion of the line in a REGEDIT .REG file:

UPDATE: Ooops. I forget to chomp() the newline before encoding it when taking data from <STDIN>. Fixed now. Well, classic CRLF vs. LF gotcha. NOW is fixed.

UPDATE: Ooops, again. Not showing sterling recall of my sprintf() style ;-). Need to pad to two tokens per byte, format: "%02x". Debugging continues.

UPDATE (July 06, 2003): Apparently, REGEDIT5 (e.g., on Win XP) exports such REG_EXPAND_SZ data with a null byte 00 after every real byte. These tools here will clearly fail to create or decode such a stream and therefore are limited to handling REGEDIT4 -style .REG files.

#!/usr/bin/perl -w # "REGexpandSZgen" - generate the formatted hex string from a normal # ascii input string- for a REGEDIT file; to enter a REG_EXPAND_SZ # data-type entry into the MS Windows Registry. use strict; my $encme = pop(@ARGV) || <STDIN>; $encme =~s% (\x{0d}|\x{0a}{1,2})\Z %%x; if($encme =~m{^("[^"]+"|\@)\=(.*)$}) { # " does not appear where "entry"= @ $encme = [$1, $2]; } my $cvtd = [ map { sprintf "%02x",ord } split('', ref $encme ? $encme->[1]:$encme) ]; if(not $ARGV[0]) { print '', (ref $encme ? "$encme->[0]=":""), "hex(2):", join(',',@$cvtd,'00'), "\n"; } else { # any prepended arg causes us to # debug / test / verify the string. print "\n IN: ",(ref $encme ? $encme->[1]:$encme),"\nOUT: " , pack("c*", map(hex, @$cvtd[0..(@$cvtd - 0x1)])) , "\n"; } __END__ This Program is Free Software, (C)2003 Soren Andersen <somian -AT- pobox -DOT- com> it may be used under the same terms as Perl itself.


I needed a debugging tool, so I whipped up a decoder too...

#! /usr/bin/perl -wl # "REGdecodeSZ" - decode Microsoft .REG -style null-terminated # strings encoded as comma-delimited sequences of hex bytes. use strict; my ($instr, @barr); chomp($instr = <STDIN>) unless( $instr = $ARGV[0x0] ); my $to = 0x1 * (@barr=split q/,/ , $instr); print join '', ( map { chr hex } @barr[ 0x0 .. ($to ? $to - 0x2 : $to) ] ); __END__ This Program is Free Software, (C)2003 Soren Andersen <somian -AT- pobox -DOT- com> and it may be used under the same terms as Perl itself.

I haven't shown all the pieces -- particularly the .REG file which actually modifies the Registry, because that isn't Perl and doesn't really pertain to the broader concept. The reader who is left wanting a look at the rest of the pieces of this, my excuse-for-the-evening to crank out some Perl hacks, is encouraged to check the Cygwin mailing List archives (from the Cygwin site) for the recent and many past discussions relating to this specific idea.

Comment on Create MSWindows Registry REG_EXPAND_SZ entry
Select or Download Code
Re: Create MSWindows Registry REG_EXPAND_SZ entry
by Anonymous Monk on Jul 03, 2003 at 11:19 UTC

    You can also let Win32::TieRegistry handle REG_EXPAND_SZ for you:

    $reg_key->SetValue('FOO', '%PATH%', 'REG_EXPAND_SZ');

    Useless if you want to use a .reg file, but you could give your script a -install option to set the registry values itself

      Hey, thanks -- but why weren't you logged in so that I could give you some XP? ;-)

      I knew that there was a module-based way to handle this kind of Registry data, but I wasn't blessed with enough time at present to go find out which modules, where.

      This will be helpful for future improvements.

         Soren A.

Re: Create MSWindows Registry REG_EXPAND_SZ entry
by ant9000 (Monk) on Jul 07, 2003 at 15:05 UTC
    I like the idea, ++ for you. About your last update: null byte after every byte smells badly of multibyte character encoding... IIRC, XP does Unicode - that should explain the second (always null) byte if you are dealing with standard ASCII chars. Trying to manage Regedit5 strings with Perl Unicode support should work, I guess...

      About your last update: null byte after every byte smells badly of multibyte character encoding... IIRC, XP does Unicode - that should explain the second (always null) byte if you are dealing with standard ASCII chars. Trying to manage Regedit5 strings with Perl Unicode support should work, I guess...

      Yes, I have garnered more information since that update. This is the situation: There is more than one "REGEDIT". The older Regedt32 tool that came with Windows3.x was removed for Windows9x, but restored with WinNT and its decendants. Furthermore the regedit tool with WinXP is a very different creature than the one with 9x: it seems to combine the better features of both Regedit and Regedt32. This is "Registry Editor Version 5".

      So the crucial thing is which version of Regedit are we talking about. It's not so much which Windows but which Regedit. After all, just saying "XP does Unicode" isn't stating anything particularly informative or relevent. So does NT, 2K, Me, even 98 and 95 if extra software from Microsoft is added. All M$ OSes "do Unicode" (at least potentially).

      What changed with Regedit ver 5 (? - or already existed) is that there came into being a new type of string datum for .REG files, and of course you and others guessed right, it is a multi-byte character Unicode string type. So there are ANSI .REG files and Unicode .REG files.

      The thing that's irritating is that even though we can create perfectly valid REG_EXPAND_SZ entries for a .REG file with Perl's help, we cannot enter them into the Registry on 95/98 because of bugs or limitations (reports vary on which this is) in the REGEDIT tool in those OSes. This goes for either ANSI or Unicode entries, BTW, no difference wrt this issue.
         Soren A.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: CUFP [id://270750]
Approved by particle
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (7)
As of 2014-09-21 13:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (171 votes), past polls