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: # REG_DWORD 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) } # REG_BINARY multi WinRegSetValue(…, blob8 $data) { RegSetValueExW(…, REG_BINARY, $data, $data.bytes) } Regards, Tobias [1] https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regsetvalueexw -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk