Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Windows Registry API #6698

Conversation

straight-shoota
Copy link
Member

@straight-shoota straight-shoota commented Sep 11, 2018

This PR adds an API for accessing the Windows Registry.

Access to the Registry is required in the standard library to get proper time zone names (see Crystal::System::Time.translate_zone_name, included in this PR) and MIME type mappings (extension to #5765, not yet included).

However, the Registry API is obviously only available on win32. Previous discussions (most recently in #6668) have manifested a common understanding that the Crystal standard library should be as much cross-platform as possible.
Having a highly platform-specific Registry API conflicts that proposition. Still, the stdlib needs that API to provide an implementation on win32 for cross-platform features.

I considered stripping down the implementation and moving it to the Crystal::System namespace. This would only contain the bare minimum required to implement the missing features for accessing the time and mime databases in the registry. But they already require a huge portion of the features and thus doesn't seem to make much sense as a stripped-down version.

Looking at Go, they have the registry API in an external package golang.org/x/sys/windows/registry which needs to be imported to use it in user code. But, they also need the registry for the same stdlib implementations and thus provide a copy of that package in internal/syscall/windows/registry which is only used by the internal implementation.
We could probably go a similar way, but I'm not too happy about maintaining the same code in two repositories.
Maybe it could be somewhat manageable using git subtrees or submodules, but I don't have a clear strategy in mind.

So, before reviewing the implementation of this PR, please consider options for how to include this into the stdlib.

This is a prerequisite for registry's EXPAND_SZ data type.
This is a prerequisite for registry API.
# * `HKEY_LOCAL_MACHINE`
# * `HKEY_USERS`
# * `HKEY_CURRENT_CONFIG`
module Registry
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in a Windows namespace.

src/crystal/system/win32/time.cr Outdated Show resolved Hide resolved
src/registry.cr Show resolved Hide resolved
@straight-shoota straight-shoota force-pushed the jm/feature/windows-registry branch from b9b2aec to 94f3fbe Compare September 11, 2018 14:46
# Windows 2000: This flag is not supported.
WOW64_64KEY = 0x00100

# Combines the STANDARD_RIGHTS_WRITE, `KEY_SET_VALUE`, and `KEY_CREATE_SUB_KEY` access rights.
Copy link
Contributor

@wooster0 wooster0 Sep 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

` is missing around STANDARD_RIGHTS_WRITE.


getter value_count : UInt32
# size of the key's longest value name, in Unicode characters, not including the terminating null byte.

Copy link
Contributor

@wooster0 wooster0 Sep 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Newline between comment and getter

@RX14
Copy link
Contributor

RX14 commented Sep 11, 2018

Please make this a shard. A fully-featured registry wrapper shouldn't be required to access this for timezones, it should be possible to do this using a few raw libc calls. It'll be ugly but thats far better than implementing a purely windows API.

After all, they do that in C.

@straight-shoota
Copy link
Member Author

it should be possible to do this using a few raw libc calls.

Yes, it should be possible. But including all error handling etc. around these libc calls, such a bare-bone implementation is far from trivial and would include most of the functionality proposed in this PR. Thus it seems much better to have a full-fledged and fully tested implementation than an ugly purpose-specific one.

@RX14
Copy link
Contributor

RX14 commented Sep 11, 2018

Whatever option gets chosen, I don't want a registry or anything 100% platform-specific exposed directly to the user.

I'd even rather shell out to reg.exe than expose something like this to users outside a shard. And shelling out is a lot more reasonable on windows where paths to executables are fixed

@ysbaddaden
Copy link
Contributor

I'm fine with a Windows::Registry class only available for Windows. Ruby has Win32::Registry in stdlib, Python has _winreg in stdlib, Go has an official package golang.org/x/sys/windows/registry copied as src/internal/windows/registry in stdlib.

If we only need to read from the registry to extract data in core/stdlib, then maybe we could have a stripped down Crystal::System::Registry with only read methods.

Anyway, having a properly implemented and tested Registry class is a better idea than shelling out to reg.exe or wrapping C calls over and over (increasing bugs), whatever if it's private or public.

@RX14
Copy link
Contributor

RX14 commented Sep 11, 2018

@ysbaddaden i'm fine with whatever as long as it's in Crystal::System and undocumented, but I think it's certainly possible to have a "nice enough" interface that's very mininal: no structs with methods, no OO, just calling methods that return handles/strings and raise. This also means minimal effect on the compile time of small programs on windows.

@bew
Copy link
Contributor

bew commented Sep 11, 2018

i'm fine with whatever as long as it's in Crystal::System and undocumented

Or documented for us, but not public (please!)

@straight-shoota
Copy link
Member Author

I don't want a registry or anything 100% platform-specific exposed directly to the user.

What about UNIXSocket? 🤷‍♂️

@asterite
Copy link
Member

I'm fine with having a full binding to the windows registry in the std. It's not much code either, just 600 lines of code which include comments.

@RX14
Copy link
Contributor

RX14 commented Sep 14, 2018

@straight-shoota https://docs.microsoft.com/en-us/windows/desktop/ipc/named-pipes can substitute for unix sockets most of the time. Might be worth abstracting over both and removing unix sockets in name.

@ysbaddaden
Copy link
Contributor

  1. AF_UNIX is coming to windows;
  2. don't "abstract" something as fundamental as UNIX sockets under some shady new term just because "it's not cross platform"; that would just bring confusion;
  3. let's get back on topic: the windows registry.

@RX14
Copy link
Contributor

RX14 commented Sep 14, 2018

@ysbaddaden thanks for the info! Nice to hear that supporting real unix sockets on windows is possible. However, that further underlines my point that bringing something as intensely platform specific as a user-visible registry implementation into the stdlib, let alone the prelude would be unprecedented and unnecessary.

BINARY = 3
DWORD = 4
DWORD_LITTLE_ENDIAN = DWORD
DWORD_BIG_ENDIAN = 5
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor, but weird alignment here (though it's probably crystal tool format)... the 4 is aligned different from the 5, likely because the DWORD breaks up the 2 sequences.

# * `HKEY_CURRENT_CONFIG`
module Registry
# Information about file types and their properties.
CLASSES_ROOT = Key.new(LibC::HKEY_CLASSES_ROOT, "HKEY_CLASSES_ROOT")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious why you removed the HKEY_ prefix on the const name? As a user of this module I'd expect to find it with the HKEY_ prefix

Copy link
Member Author

@straight-shoota straight-shoota Nov 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because they're redundant. There are no namespaces in C, hence constants and functions are often prefixed by a type/library identifier (like HKEY). In Crystal it's obvious that they are registry constants because they're defined in the Registry module.

Copy link
Contributor

@Fryguy Fryguy Nov 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see your argument, but outside of the C-code context, the HKEY prefix has pervaded into everything. It's even in the GUI regedit to the point that that is the actual name of the key now. That was really the thought process behind my statement of "As a user of this module I'd expect to find it with the HKEY_ prefix"

@HertzDevil HertzDevil added kind:feature platform:windows Windows support based on the MSVC toolchain / Win32 API labels Aug 4, 2021
@straight-shoota
Copy link
Member Author

Closing.
The immediate functionality for time zone and mime db support on Windows was resolved by #11137.

If we decide to provide a public API for access to the Windows Registry in stdlib later, we can re-issue this implementation. Otherwise it may serve as a basis for a shard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind:feature platform:windows Windows support based on the MSVC toolchain / Win32 API
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants