3

With Windows, the official way of guessing if the current 32-bit process is running on a 32 or 64-bit architecture (so on WOW64 or not) is to call the IsWow64Process function from kernel32.dll, and see if it is present (as I understand the doc).

In Go we can call functions exported in dll files with the syscall package, so here is my attempt:

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)
}

Unfortunately, testing with or without a WOW64 system displays the same in stdout:

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

What do I do wrong? How to achieve a test to determine if our 32-bit Go program runs on an emulated 32-bit on a 64-bit CPU (WOW64) or on a real 32-bit Windows?

Lomanic
  • 371
  • 4
  • 15
  • 1
    Are you fully aware of the fact your code basically tests whether your Go code runs on WOW64 emulation or not, and not whether the OS is 32-bit arch or not? To answer the question *as stated,* you should call [`kernel32!GetNativeSystemInfo()`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724340) and inspect the architecture it returns. The value will be the same no matter whether you're running 32-bit Go process on a 32-bit os or 64-bit Go process on 64-bit OS or 32-bit Go process on 64-bit OS. – kostix Nov 19 '15 at 15:56
  • Thanks for your comment and clarification @kostix. Indeed you are right, I was biased by the fact I assumed it was a 32-bit compiled Go executable. Should I edit my question to reflect that I wanted to guess if we run on WOW64 or not and then re-ask a new question with the GetNativeSystemInfo function in Go? [It looks like it is the stackoverflow-way to handle this kind of situation](http://meta.stackoverflow.com/q/283408/2583075). – Lomanic Nov 19 '15 at 20:27
  • Question edited to reflect what was finally asked and answered, following @kostix comment. – Lomanic Nov 20 '15 at 16:27

3 Answers3

4

I believe the issue is the handle parameter on your proc.Call. The expected parameter for IsWow64Process is a HANDLE which is not the same as a pid. Which is why it is indicating that the handle is invalid.

The following SO question How to get process handle from process id indicates that you need to call OpenProcess passsing in the pid and it returns the handle.

EDIT: GetCurrentProcess is defined in syscall. So I think you can replace the Getpid call with the following:

handle, err := syscall.GetCurrentProcess()
Community
  • 1
  • 1
miltonb
  • 6,905
  • 8
  • 45
  • 55
  • Thanks for your answer. [Here](https://play.golang.org/p/q6YOUS58pf) is my code so far. Unfortunately I have a runtime exception ([link](http://pastebin.aquilenet.fr/?11f1a1d75a631c63#xEoHdDHc6K56GtJOzlOAUrJ7qYpC6DjJI+Vv1DN94eg=)) while running it that I can't diagnose. It occurs at the proc.Call() line. Looks like it does not like affecting the `result` var? – Lomanic Nov 19 '15 at 11:50
3

OK, so here is a working code:

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)
}

The result var will be true for a WOW64 system and false for a 32 bit system.

Lomanic
  • 371
  • 4
  • 15
1

You can also use 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)
}

Erfan Azhdari
  • 301
  • 2
  • 6