Oops, there was one thing I forgot when I made this answer, and it's something that I'm both not quite sure on myself and that I can't seem to find information for on MSDN and Google and the Stack Overflow search.
There are a number of places in the Windows API where you use a negative number, or a number too large to fit in a signed integer; for instance, CW_USEDEFAULT
, INVALID_HANDLE_VALUE
, GWLP_USERDATA
, and so on. In the world of C, everything is all fine and dandy: the language's integer promotion rules come to the rescue.
But in Go, I have to pass all my arguments to functions as uintptr
(which is equivalent to C's uintptr_t
). The return value from the function is also returned this way, and then I will need to compare. Go doesn't allow integer promotion, and it doesn't allow you to convert a signed constant expression into an unsigned one at compile-time.
Right now, I have a bit of a jerry-rig set up for handling these constants in my UI library. (Here's an example of what this solution looks like in action.) However, I'm not quite satisfied with this solution; it feels to me like it's assuming things about the ABI, and I want to be absolutely sure of what I'm doing.
So my question is: how are signed values handled when passing them to Windows API functions and how are they handled when returning?
All my constants are autogenerated (example output). The autogenerator uses a C ffi, which I'd rather not use for the main project since I can call the DLLs directly (this also makes cross-compilation easier at least for the rest of the year). If I could somehow leverage that, for instance by making everything into a C-side variable of the form
uintptr_t x_CONST_NAME = (uintptr_t) (CONST_NAME);
that would be helpful. But I can't do that without this answer.
Thanks!
Update
Someone on IRC put it differently (reformatted to avoid horizontal scrolling):
[19:13] <FraGag> basically, you're asking whether an int with a value of -1
will be returned as 0x00000000FFFFFFFF or as 0xFFFFFFFFFFFFFFFF
if an int is 4 bytes and an uintptr is 8 bytes
Basically this, but specifically for Windows API interop, for parameters passed in, and regardless of uintptr size.
@twotwotwo's comments to my question pointed me in the right direction. If Stack Overflow allowed marking comments as answers and having multiple answers marked, I'd do that.
tl;dr version: what I have now is correct after all.
I wrote a program (below) that simply dumped all the constants from package syscall and looked for constants that were negative, but not == -1 (as that would just be
^0
). The standard file handles (STD_ERROR_HANDLE
,STD_INPUT_HANDLE
, andSTD_OUTPUT_HANDLE
) are (-12, -10, and -11, respectively). The code in package syscall passes these constants as the sole argument ofgetStdHandle(h int)
, which produces the required file handle for package os.getStdHandle()
passes this int to an autogenerated functionGetStdHandle(stdhandle int)
that wraps a call to theGetStdHandle()
system call.GetStdHandle()
takes the int and merely converts it touintptr
for passing intosyscall.Syscall()
. Though no explanation is given in the autogenerator's source (mksyscall_windows.go), if this didn't work, neither wouldfmt.Println()
=PAll of the above is identical on both windows/386 and windows/amd64; the only thing in a processor-specific file is
GetStdHandle()
, but the relevant code is identical.My
negConst()
function is already doing the same thing, just more directly. As such, I can safely assume that it is correct.Thanks!