加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Windows > 正文

调用Windows API函数(stdcall)的符号扩展规则是什么?这需要从Go

发布时间:2020-12-14 02:17:33 所属栏目:Windows 来源:网络整理
导读:哎呀,当我制作 this answer时,有一件事我忘记了,而且我对自己并不是很确定,而且我似乎无法在MSDN和Google以及Stack Overflow搜索中找到相关信息. Windows API中有许多地方使用负数,或者数字太大而无法使用有符号整数;例如,CW_USEDEFAULT,INVALID_HANDLE_VALU
哎呀,当我制作 this answer时,有一件事我忘记了,而且我对自己并不是很确定,而且我似乎无法在MSDN和Google以及Stack Overflow搜索中找到相关信息.

Windows API中有许多地方使用负数,或者数字太大而无法使用有符号整数;例如,CW_USEDEFAULT,INVALID_HANDLE_VALUE,GWLP_USERDATA等.在C的世界里,一切都很好,花花公子:语言的整数提升规则得到了拯救.

但在Go中,我必须将所有参数作为uintptr传递给函数(这相当于C的uintptr_t).函数的返回值也以这种方式返回,然后我需要进行比较. Go不允许整数提升,并且它不允许您在编译时将有符号常量表达式转换为无符号表达式.

现在,我在UI library中设置了bit of a jerry-rig用于处理这些常量.(Here’s an example of what this solution looks like in action.)但是,我对这个解决方案并不满意;我觉得它喜欢ABI的事情,我想要完全确定我在做什么.

所以我的问题是:将签名值传递给Windows API函数时如何处理?返回时如何处理?

我所有的常数都是autogenerated(example output).自动生成器使用a C ffi,我宁愿不用于主项目,因为我可以直接调用DLL(这也使得交叉编译至少在一年中的其他时间更容易).如果我可以以某种方式利用它,例如通过将所有内容都变成表单的C端变量

uintptr_t x_CONST_NAME = (uintptr_t) (CONST_NAME);

这会有所帮助.但如果没有这个答案我就不能这样做.

谢谢!

更新

IRC上的某个人将其改为不同(重新格式化以避免水平滚动):

[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

基本上这个,但专门用于Windows API互操作,传入的参数,无论uintptr大小.

解决方法

@ twotwotwo对我的问题的评论指出了我正确的方向.如果Stack Overflow允许将注释标记为答案并标记多个答案,那么我会这样做.

tl; dr版本:毕竟我现在拥有的是正确的.

我编写了一个程序(下面),简单地从包syscall中转储所有常量,并查找负数但不是== -1的常量(因为它只是^ 0).标准文件句柄(STD_ERROR_HANDLE,STD_INPUT_HANDLE和STD_OUTPUT_HANDLE)分别为(-12,-10和-11).包syscall中的代码将这些常量作为getStdHandle(h int)的唯一参数传递,它为包os生成所需的文件句柄. getStdHandle()将此int传递给自动生成的函数GetStdHandle(stdhandle int),该函数包装对GetStdHandle()系统调用的调用. GetStdHandle()获取int并仅将其转换为uintptr以传入syscall.Syscall().虽然自动生成器的源代码(mksyscall_windows.go)没有给出解释,如果这不起作用,fmt.Println()= P也不会

所有上述内容在windows / 386和windows / amd64上都是相同的;处理器特定文件中唯一的东西是GetStdHandle(),但相关代码是相同的.

我的negConst()函数已经做了同样的事情,只是更直接.因此,我可以放心地认为它是正确的.

谢谢!

// 4 june 2014
// based on code from 24 may 2014
package main

import (
    "fmt"
    "os"
    "strings"
    "go/token"
    "go/ast"
    "go/parser"
    "code.google.com/p/go.tools/go/types"
    _ "code.google.com/p/go.tools/go/gcimporter"
)

var arch string

func getPackage(path string) (typespkg *types.Package,pkginfo types.Info) {
    var pkg *ast.Package

    fileset := token.NewFileSet()       // parser.ParseDir() actually writes to this; not sure why it doesn't return one instead
    filter := func(i os.FileInfo) bool {
        if strings.Contains(i.Name(),"_windows") &&
            strings.Contains(i.Name(),"_" + arch) &&
            strings.HasSuffix(i.Name(),".go") {
            return true
        }
        if i.Name() == "race.go" ||     // skip these
            i.Name() == "flock.go" {
            return false
        }
        return strings.HasSuffix(i.Name(),"_windows.go") ||
            (!strings.Contains(i.Name(),"_"))
    }
    pkgs,err := parser.ParseDir(fileset,path,filter,parser.AllErrors)
    if err != nil {
        panic(err)
    }
    for k,_ := range pkgs {        // get the sole key
        if pkgs[k].Name == "syscall" {
            pkg = pkgs[k]
            break
        }
    }
    if pkg == nil {
        panic("package syscall not found")
    }
    // we can't pass pkg.Files directly to types.Check() because the former is a map and the latter is a slice
    ff := make([]*ast.File,len(pkg.Files))
    for _,v := range pkg.Files {
        ff = append(ff,v)
    }
    // if we don't make() each map,package types won't fill the structure
    pkginfo.Defs = make(map[*ast.Ident]types.Object)
    pkginfo.Scopes = make(map[ast.Node]*types.Scope)
    typespkg,err = new(types.Config).Check(path,fileset,ff,&pkginfo)
    if err != nil {
        panic(err)
    }
    return typespkg,pkginfo
}

func main() {
    pkgpath := "/home/pietro/go/src/pkg/syscall"
    arch = os.Args[1]

    pkg,_ := getPackage(pkgpath)
    scope := pkg.Scope()
    for _,name := range scope.Names() {
        obj := scope.Lookup(name)
        if obj == nil {
            panic(fmt.Errorf("nil object %q from scope %v",name,scope))
        }
        if !obj.Exported() {        // exported names only
            continue
        }
        if _,ok := obj.(*types.Const); ok {
            fmt.Printf("egrep -rh '#define[     ]+%s' ~/winshare/Include/ 2>/dev/nulln",obj.Name())
        }
        // otherwise skip
    }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读