jerblack
jerblack

Reputation: 1295

Is it possible to detect if Go binary was compiled with -H=windowsgui at runtime

I built a tool that can be run from the console or run in the system tray if the flag -tray is passed at start. Just running go build <list of go files> with no build flags will create a binary that can be run in the system tray, but it also spawns a console window. If I pass the build flag -H=windowsgui then the console window will be hidden, but I still need to pass -tray to get it to actually run in the system tray.

Is there a way at runtime to detect that the binary was built with the flag -H=windowsgui so I can automatically do the right thing and enable the tray without the need for the -tray flag to have been passed?

Upvotes: 1

Views: 1095

Answers (1)

ymonad
ymonad

Reputation: 12120

According to the Go source, it seems to set Subsystem of OptionalHeader when linking.

Therefore, you can obtain it by using debug/pe.

Following code will print it is windows GUI when compiled with go build -ldflags "-H windowsgui", and print it is windows CUI otherwise.

Note that os.Executable() may return path for symbolic link, so may not be reliable. Refer to: the document of os.Executable()

package main

import (
    "debug/pe"
    "fmt"
    "os"
)

// these constants are copied from https://github.com/golang/go/blob/6219b48e11f36329de801f62f18448bb4b1cd1a5/src/cmd/link/internal/ld/pe.go#L92-L93  
const (
    IMAGE_SUBSYSTEM_WINDOWS_GUI = 2
    IMAGE_SUBSYSTEM_WINDOWS_CUI = 3
)

func main() {
    fileName, err := os.Executable()
    if err != nil {
        panic(err)
    }
    fl, err := pe.Open(fileName)
    if err != nil {
        panic(err) // maybe not windows binary, or unreadable for some reasons
    }
    defer fl.Close()

    var subsystem uint16
    if header, ok := fl.OptionalHeader.(*pe.OptionalHeader64); ok {
        subsystem = header.Subsystem
    } else if header, ok := fl.OptionalHeader.(*pe.OptionalHeader32); ok {
        subsystem = header.Subsystem
    }

    if subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI {
        fmt.Println("it is windows GUI")
    } else if subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI {
        fmt.Println("it is windows CUI")
    } else {
        fmt.Println("binary type unknown")
    }
}

Upvotes: 4

Related Questions