Skip to content

x/sys/windows: non-constant GUID constants #32248

@zx2c4

Description

@zx2c4

I intend to add the SHGetKnownFolderPath API to x/sys/windows, because it's the right way for looking up things like where an application should store its configuration or where various other standard folders are located. That's kind of boring. The function takes some constant enumeration parameter indicating which folder type to return. Usually in x/sys/windows for this, we import the symbolic names to make that easier. For example, for CreateWellKnownSid, we have something like this:

const (
        WinNullSid                                    = 0
        WinWorldSid                                   = 1
        WinLocalSid                                   = 2
        WinCreatorOwnerSid                            = 3
        WinCreatorGroupSid                            = 4
        ...
)

And then users get to call CreateWellKnownSid(WinCreatorGroupSid) or something.

So far so good.

What's interesting is that the SHGetKnownFolderPath API is one that, rather than taking a numerical constant, takes a GUID constant. In C, this generally amounts to the Windows headers declaring a macro that expands to the curly braces defining the complex object, so you only have them in the resultant binary if you use them. In Go, it seems like it might be another story.

There are a few of these types of constant-GUID-taking APIs in x/sys/windows already, and they declare the "constant" GUID as a global variable. For example:

type GUID struct {
        Data1 uint32
        Data2 uint16
        Data3 uint16
        Data4 [8]byte
}
var WSAID_CONNECTEX = GUID{
        0x25a207b9,
        0xddf3,
        0x4660,
        [8]byte{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e},
}
var WSAID_WSASENDMSG = GUID{
        0xa441e712,
        0x754f,
        0x43ca,
        [8]byte{0x84, 0xa7, 0x0d, 0xee, 0x44, 0xcf, 0x60, 0x6d},
}
var WSAID_WSARECVMSG = GUID{
        0xf689d7c8,
        0x6f1f,
        0x436b,
        [8]byte{0x8a, 0x53, 0xe5, 0x4f, 0xe3, 0x51, 0xc3, 0x22},
}

Two things immediately leap out at me:

  1. Users of the library can modify the value of these at runtime; they're not read-only.
  2. These aren't actually constants, but runtime global variables that I assume are initialized at startup or if the compiler is smart held in some section of the binary.

This seems somewhat bad. Maybe the compiler optimizes (2) away if it's not used? But maybe it doesn't? Does anybody know? I sort of suspect it doesn't.

Getting back to the API I'd like to add, there are quite a few constant GUIDs that will be added as "constants". Due to (1) and (2) above, and the large quantity of these, it seems like declaring them as a var like that would be a really bad idea.

But I don't know of a language construct in Go that would actually fix this the right way, or whether the existing one is fine and the compiler does something smart with it. Does anybody know?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions