develooper Front page | perl.perl6.users | Postings from January 2020

Re: stolen uint's

Thread Previous | Thread Next
Tobias Boege
January 29, 2020 08:44
Re: stolen uint's
Message ID:
On Tue, 28 Jan 2020, ToddAndMargo via perl6-users wrote:
> This all came up when I tried to match
>       RegSetValueExW(
>           _In_ HKEY hKey,
>           _In_opt_ LPCWSTR lpValueName,
>           _Reserved_ DWORD Reserved,
>           _In_ DWORD dwType,
>           _In_reads_bytes_opt_(cbData) CONST BYTE * lpData,
>           _In_ DWORD cbData
> where CbData can either be a UTF little endian C string,
> terminated by a nul or a four byte little endian
> unsigned integer (no two's complement allowed) depending
> on the value of lpValueName (REG_SZ, REG_DWORD, etc.)
> I wound up doing this:
> subset StrOrDword where Str | UInt;
> sub WinRegSetValue( WinRegHives $Hive, Str $SubKey, Str $KeyName, ValueNames
> $ValueType, StrOrDword $ValueData, Bool $Debug = False )
>                     returns DWORD is export( :WinRegSetValue ) {

Are you really 100% sure that you interpreted this API correctly? I see how
a DWORD cbData can be a four-byte unsigned integer: it gives the length of
lpData in bytes, as documented [1].

But then a DWORD is 4 bytes long. Reusing these 4 bytes for an alternative
interface where you may pass a UTF-whatever string that is at most 4 bytes
encoded, including the NUL terminator... seems too insane. And there is no
mention of that in the documentation page [1]. I do not think that cbData
is ever used for anything but to indicate the length of the buffer lpData.
It is lpData which can have a multitude of types (and serialization formats),
the intended one to be taken from the dwType argument (not lpValueName).

My advice is still the same I gave in my very first reply to this thread:
make your function a multi and write a candidate for each dwType. You have
to write different code for serializing an integer vs. a string to pass as
lpData anyway and the compiler can detect native types in multi dispatch
for you:

  multi WinRegSetValue(…, uint32 $data) {
      use experimental :pack;
      RegSetValueExW(…, REG_DWORD, pack("L", $data), 4)

  # REG_SZ
  multi WinRegSetValue(…, Str $data) {
      my $blob = "$data\0".encode
      RegSetValueExW(…, REG_SZ, $blob, $blob.bytes)

  multi WinRegSetValue(…, blob8 $data) {
      RegSetValueExW(…, REG_BINARY, $data, $data.bytes)



"There's an old saying: Don't change anything... ever!" -- Mr. Monk

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