O que são sinal de regras de extensão para chamar funções da API do Windows (stdcall)?Isto é necessário para chamar WInAPI de Ir, que é rigoroso sobre tipos int

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

Pergunta

Ops, não era uma coisa que eu esqueci que quando eu fiz esta resposta, e é algo de que eu sou não tem certeza sobre mim e que eu não consigo encontrar informações no MSDN e o Google e o Estouro de Pilha de pesquisa.

Há um número de lugares na API do Windows, onde você utilize um número negativo, ou um número muito grande para caber em um número inteiro assinado;por exemplo, CW_USEDEFAULT, INVALID_HANDLE_VALUE, GWLP_USERDATA, e assim por diante.No mundo de C, está tudo lindo e perfeito:a linguagem inteiro promoção de regras de vir para o resgate.

Mas Vá, eu tenho que passar todos os meus argumentos para funções como uintptr (o que é equivalente a C uintptr_t).O valor de retorno da função é também devolvida a esta forma e, em seguida, será preciso comparar.Vá não permite inteiro promoção, e ele não permite que você para converter uma assinado expressão constante em um não assinados em tempo de compilação.

Agora, eu tenho um pouco mais de um jerry-rig conjunto para tratar essas constantes em minha Biblioteca de INTERFACE. (Aqui está um exemplo do que esta solução parece em ação. No entanto, eu não estou muito satisfeito com essa solução;parece-me como se fosse assumindo coisas sobre a ABI, e eu quero ter a certeza absoluta do que estou fazendo.

Então a minha pergunta é:como são valores assinados tratados ao passá-los para funções de API do Windows e como eles são tratados quando retornar?

Todos os meus constantes são gerado automaticamente (exemplo de saída).O autogenerator usa um ffi C, que eu prefiro não usar para o projeto principal, pois eu posso chamar DLLs diretamente (isto também faz cross-compilação mais fácil pelo menos para o resto do ano).Se eu pudesse de alguma forma de alavancagem que, por exemplo, fazendo tudo dentro de um C-variável do lado do formulário

uintptr_t x_CONST_NAME = (uintptr_t) (CONST_NAME);

que seria útil.Mas eu não posso fazer isso sem essa resposta.

Obrigado!

Atualização

Alguém no IRC colocá-lo de forma diferente (reformatada para evitar a rolagem horizontal):

[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

Basicamente isso, mas especificamente para o Windows API de interoperabilidade, para os parâmetros passados, e independentemente de uintptr tamanho.

Foi útil?

Solução

@twotwotwo comentários à minha pergunta me apontou a direção certa.Se o Estouro de Pilha permitida a marcação de comentários, respostas e ter várias respostas marcadas, eu faria isso.

tl;dr versão:o que eu tenho agora é corrigir depois de tudo.

Eu escrevi um programa (abaixo) que simplesmente despejado todas as constantes do pacote syscall e olhou para constantes que foram negativos, mas não == -1 (como que poderia ser apenas ^0).O padrão de identificadores de arquivo (STD_ERROR_HANDLE, STD_INPUT_HANDLE, e STD_OUTPUT_HANDLE) são (-12, -10, e -11, respectivamente).O código no pacote syscall passa essas constantes como o único argumento de getStdHandle(h int), que produz o necessário identificador de ficheiro para o pacote de sistema operacional. getStdHandle() passa este int para um geradas automaticamente a função de GetStdHandle(stdhandle int) que envolve uma chamada para o GetStdHandle() chamada de sistema. GetStdHandle() leva o int e simplesmente converte-lo para uintptr para passar para syscall.Syscall().Embora nenhuma explicação é dada no autogenerator de origem (mksyscall_windows.go), se este não trabalho, nem seria fmt.Println() =P

Todos os itens acima é idêntico em ambos os windows/386 e windows/amd64;a única coisa em um processador específico do arquivo é GetStdHandle(), mas o código é idêntico.

Meu negConst() a função já está fazendo a mesma coisa, apenas mais diretamente.Como tal, posso presumir com segurança que ele está correto.

Obrigado!

// 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
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top