Windows API 함수(stdcall) 호출을 위한 부호 확장 규칙은 무엇입니까?이는 int 유형에 엄격한 Go에서 WInAPI를 호출하는 데 필요합니다.

StackOverflow https://stackoverflow.com//questions/24022225

문제

아, 만들면서 깜빡한 게 하나 있었네요 이 답변, 그리고 그것은 나 자신에 대해 잘 확신하지 못하고 MSDN과 Google 및 Stack Overflow 검색에서 정보를 찾을 수 없는 것 같습니다.

Windows API에는 음수를 사용하거나 부호 있는 정수에 맞지 않을 정도로 큰 숫자를 사용하는 곳이 많이 있습니다.예를 들어, CW_USEDEFAULT, INVALID_HANDLE_VALUE, GWLP_USERDATA, 등등.C의 세계에서는 모든 것이 훌륭하고 멋지다.언어의 정수 승격 규칙이 구출됩니다.

하지만 Go에서는 모든 인수를 다음과 같이 함수에 전달해야 합니다. uintptr (이것은 C와 동일합니다. uintptr_t).함수의 반환값도 이런 식으로 반환되므로 비교를 해야 합니다.Go는 정수 승격을 허용하지 않으며 컴파일 타임에 부호 있는 상수 표현식을 부호 없는 상수 표현식으로 변환하는 것을 허용하지 않습니다.

지금 당장, 나는 약간의 제리 장비 내에서 이러한 상수를 처리하기 위해 설정 UI 라이브러리. (다음은 이 솔루션이 실제로 어떻게 보이는지에 대한 예입니다.) 그러나 나는 이 솔루션에 그다지 만족하지 않습니다.그것은 ABI에 관한 것들을 가정하고 있는 것처럼 느껴지며, 나는 내가 무엇을 하고 있는지 절대적으로 확신하고 싶습니다.

그래서 내 질문은 다음과 같습니다부호 있는 값을 Windows API 함수에 전달할 때 어떻게 처리되며, 반환할 때 어떻게 처리됩니까?

내 모든 상수는 자동 생성된 (예제 출력).자동 생성기는 다음을 사용합니다. Cffi, 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() =피

위의 모든 내용은 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, 0, 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/null\n", obj.Name())
        }
        // otherwise skip
    }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top