Was sind die Vorzeichenerweiterungsregeln für den Aufruf von Windows-API-Funktionen (stdcall)?Dies ist erforderlich, um WInAPI von Go aus aufzurufen, das hinsichtlich int-Typen streng ist

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

Frage

Hoppla, eines habe ich bei der Zubereitung vergessen diese Antwort, und es ist etwas, bei dem ich mir selbst nicht ganz sicher bin und zu dem ich anscheinend keine Informationen auf MSDN, Google und der Stack Overflow-Suche finden kann.

Es gibt eine Reihe von Stellen in der Windows-API, an denen Sie eine negative Zahl oder eine Zahl verwenden, die zu groß ist, um in eine Ganzzahl mit Vorzeichen zu passen.zum Beispiel, CW_USEDEFAULT, INVALID_HANDLE_VALUE, GWLP_USERDATA, und so weiter.In der Welt von C ist alles in Ordnung:Abhilfe schaffen die Integer-Promotion-Regeln der Sprache.

Aber in Go muss ich alle meine Argumente an Funktionen als übergeben uintptr (was C entspricht uintptr_t).Auf diese Weise wird auch der Rückgabewert der Funktion zurückgegeben, und dann muss ich vergleichen.Go erlaubt keine Integer-Hochstufung und erlaubt Ihnen nicht, einen vorzeichenbehafteten konstanten Ausdruck zur Kompilierungszeit in einen vorzeichenlosen umzuwandeln.

Im Moment habe ich eine ein bisschen wie ein Kanister für den Umgang mit diesen Konstanten in meinem eingerichtet UI-Bibliothek. (Hier ist ein Beispiel dafür, wie diese Lösung in Aktion aussieht.) Allerdings bin ich mit dieser Lösung nicht ganz zufrieden;Für mich fühlt es sich so an, als ob es sich um Vermutungen über den ABI handelt, und ich möchte absolut sicher sein, was ich tue.

Meine Frage ist also:Wie werden vorzeichenbehaftete Werte bei der Übergabe an Windows-API-Funktionen und bei der Rückgabe behandelt?

Alle meine Konstanten sind automatisch generiert (Beispielausgabe).Der Autogenerator verwendet ein C ffi, den ich lieber nicht für das Hauptprojekt verwenden würde, da ich die DLLs direkt aufrufen kann (das erleichtert auch die Cross-Compilierung zumindest für den Rest des Jahres).Wenn ich das irgendwie nutzen könnte, indem ich zum Beispiel alles in eine C-seitige Variable des Formulars umwandele

uintptr_t x_CONST_NAME = (uintptr_t) (CONST_NAME);

das wäre hilfreich.Aber ohne diese Antwort kann ich das nicht tun.

Danke!

Aktualisieren

Jemand im IRC hat es anders ausgedrückt (neu formatiert, um horizontales Scrollen zu vermeiden):

[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

Grundsätzlich gilt dies, aber speziell für die Windows-API-Interop, für übergebene Parameter und unabhängig von der uintptr-Größe.

War es hilfreich?

Lösung

Die Kommentare von @twotwotwo zu meiner Frage haben mir die richtige Richtung gezeigt.Wenn Stack Overflow das Markieren von Kommentaren als Antworten und das Markieren mehrerer Antworten erlauben würde, würde ich das tun.

Tl;dr-Version:Was ich jetzt habe, ist doch richtig.

Ich habe ein Programm (unten) geschrieben, das einfach alle Konstanten aus dem Paket syscall entsorgt und nach Konstanten gesucht hat, die negativ waren, aber nicht == -1 (was einfach der Fall wäre). ^0).Die Standard-Dateihandles (STD_ERROR_HANDLE, STD_INPUT_HANDLE, Und STD_OUTPUT_HANDLE) sind (-12, -10 bzw. -11).Der Code im Paket syscall übergibt diese Konstanten als einziges Argument von getStdHandle(h int), wodurch das erforderliche Dateihandle für das Paketbetriebssystem erstellt wird. getStdHandle() übergibt dieses int an eine automatisch generierte Funktion GetStdHandle(stdhandle int) das schließt einen Anruf an die ein GetStdHandle() Systemaufruf. GetStdHandle() nimmt das int und wandelt es lediglich in um uintptr zum Hinübergehen syscall.Syscall().In der Quelle des Autogenerators (mksyscall_windows.go) wird jedoch keine Erklärung gegeben, ob dies der Fall ist nicht funktionieren, würde es auch nicht tun fmt.Println() =P

Alles oben Genannte ist unter Windows/386 und Windows/amd64 identisch;Das einzige, was in einer prozessorspezifischen Datei enthalten ist, ist GetStdHandle(), aber der entsprechende Code ist identisch.

Mein negConst() Funktion macht bereits das Gleiche, nur direkter.Daher kann ich mit Sicherheit davon ausgehen, dass es richtig ist.

Danke!

// 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
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top