Определение того, работает ли текущий процесс в WOW64 или нет в Go

В Windows официальный способ угадать, работает ли текущий 32-разрядный процесс на 32- или 64-разрядной архитектуре (то есть на WOW64 или нет), - это вызвать IsWow64Process из kernel32.dll и посмотрите, присутствует ли она (как я понимаю документ).

В Go мы можем вызывать функции, экспортированные в файлы dll, с помощью пакета syscall, поэтому вот моя попытка:

package main

import (
    "fmt"
    "os"
    "syscall"
)

func main() {
    dll, err := syscall.LoadDLL("kernel32.dll")
    if err != nil {
        fmt.Println(err)
    }
    defer dll.Release()
    proc, err := dll.FindProc("IsWow64Process")
    if err != nil {
        fmt.Println("Proc not found") // not a WOW64 so a 32 bit system?
        fmt.Println(err)
    }
    fmt.Printf("%v\n", proc)

    var handle uintptr = uintptr(os.Getpid())

    var result uintptr
    v, x, y := proc.Call(handle, result)

    fmt.Printf("%v %v %v\n", v, x, y)
    fmt.Printf("%v\n", result)
}

К сожалению, тестирование с системой WOW64 или без нее отображает то же самое в стандартном выводе:

&{0x10ada110 IsWow64Process 2088961457}
0 7 The handle is invalid.
0

Что я делаю не так? Как провести тест, чтобы определить, работает ли наша 32-битная программа Go на эмулируемой 32-битной на 64-битном процессоре (WOW64) или на реальной 32-битной Windows?


person Lomanic    schedule 18.11.2015    source источник
comment
Полностью ли вы осведомлены о том, что ваш код в основном проверяет, работает ли ваш код Go с эмуляцией WOW64 или нет, а не является ли ОС 32-разрядной архитектурой или нет? Чтобы ответить на вопрос, как указано, вы должны вызвать kernel32!GetNativeSystemInfo() и осмотрите возвращаемую архитектуру. Значение будет одинаковым независимо от того, запускаете ли вы 32-битный процесс Go в 32-битной ОС или 64-битный процесс Go в 64-битной ОС или 32-битный процесс Go в 64-битной ОС.   -  person kostix    schedule 19.11.2015
comment
Спасибо за комментарий и разъяснения @kostix. В самом деле, вы правы, я был предвзято относился к тому факту, что я предполагал, что это 32-битный скомпилированный исполняемый файл Go. Следует ли мне отредактировать свой вопрос, чтобы отразить, что я хотел угадать, работаем ли мы на WOW64 или нет, а затем повторно задать новый вопрос с помощью функции GetNativeSystemInfo в Go? Похоже, это способ решения такой ситуации с помощью stackoverflow.   -  person Lomanic    schedule 19.11.2015
comment
Вопрос отредактирован, чтобы отразить окончательный вопрос и ответ после комментария @kostix.   -  person Lomanic    schedule 20.11.2015


Ответы (3)


Я считаю, что проблема заключается в параметре дескриптора вашего proc.Call. Ожидаемый параметр для IsWow64Process - РУЧКА, которая не совпадает с pid. Вот почему это указывает на то, что дескриптор недействителен.

Следующий вопрос SO: Как получить дескриптор процесса из идентификатора процесса указывает, что вам нужно вызвать OpenProcess passsing в pid, и возвращает дескриптор.

РЕДАКТИРОВАТЬ: GetCurrentProcess определяется в syscall. Поэтому я думаю, что вы можете заменить вызов Getpid следующим:

handle, err := syscall.GetCurrentProcess()
person miltonb    schedule 18.11.2015
comment
Спасибо за Ваш ответ. Вот мой код на данный момент. К сожалению, у меня есть исключение во время выполнения ( - person Lomanic; 19.11.2015

Хорошо, вот рабочий код:

package main

import (
    "syscall"
    "fmt"
    "unsafe"
)
func main() {
    dll, err := syscall.LoadDLL("kernel32.dll")
    if err != nil {
        fmt.Println("Can't load kernel32")
        fmt.Println(err)
    }
    defer dll.Release()
    proc, err := dll.FindProc("IsWow64Process")
    if err != nil {
        fmt.Println("Proc not found")
        fmt.Println(err)
    }
    fmt.Printf("%v\n",proc)

    handle, err := syscall.GetCurrentProcess()  
    if err != nil {
        fmt.Println("Handle not found")
        fmt.Println(err)
    }
    fmt.Printf("%v\n",handle)

    var result bool

    v, x, y := proc.Call(uintptr(handle), uintptr(unsafe.Pointer(&result)))

    fmt.Printf("%v %v %v\n",v,x,y)
    fmt.Printf("%v\n",result)
}

result var будет истинным для системы WOW64 и ложным для 32-битной системы.

person Lomanic    schedule 19.11.2015

Вы также можете использовать golang.org/x/sys/windows

package main

import (
    "fmt"
    "golang.org/x/sys/windows"
)

func main() {
    handle := windows.CurrentProcess()
    var isWow64 bool
    err := windows.IsWow64Process(handle, &isWow64)
    if err != nil {
        panic(err)
    }
    fmt.Println(isWow64)
}

person Erfan Azhdari    schedule 13.12.2020