winres

package module
v0.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 15, 2023 License: 0BSD Imports: 20 Imported by: 0

README

winres

Go Reference codecov Go Report

Package winres provides functions for embedding resources in a Windows executable built with Go.

Most often, you'll want to embed an application icon, a manifest, and "version information", which is what you can see in the Details tab of file properties.

Command line tool

If you are looking for a command line tool, please head to go-winres.

Alternatives

This project is similar to akavel/rsrc and josephspurrier/goversioninfo.

Limitations

This is not a real resource compiler, which means it won't help you embed these UI definitions:

  • ACCELERATORS
  • DIALOGEX
  • MENUEX
  • POPUP

If you ever need them, which is unlikely, use one of those tools instead:

  • rc.exe and cvtres.exe from Visual Studio
  • windres from GNU Binary Utilities
  • llvm-rc and llvm-cvtres from LLVM tools

See Resource Compiler for more information.

Usage

To embed resources, you need an .rsrc section in your executable. Winres provides functions to compile this .rsrc section into a COFF object file.

Put this file in your project directory, name it "something.syso" or, preferably, "something_windows_amd64.syso", and you're done : the go build command will detect it and automatically use it.

You should have a look at the command line tool to try it. Using the library gives you more control, though.

Here is a quick example:

package main

import (
	"io/ioutil"
	"os"

	"github.com/tc-hib/winres"
)

func main() {
	// Start by creating an empty resource set
	rs := winres.ResourceSet{}

	// Add resources
	// This is a cursor named ID(1)
	cursorData, _ := ioutil.ReadFile("cursor.cur")
	rs.Set(winres.RT_CURSOR, winres.ID(1), 0, cursorData)

	// This is a custom data type, translated in english (0x409) and french (0x40C)
	// You can find more language IDs by searching for LCID
	rs.Set(winres.Name("CUSTOM"), winres.Name("COOLDATA"), 0x409, []byte("Hello World"))
	rs.Set(winres.Name("CUSTOM"), winres.Name("COOLDATA"), 0x40C, []byte("Bonjour Monde"))

	// Compile to a COFF object file
	// It is recommended to use the target suffix "_window_amd64"
	// so that `go build` knows when not to include it.
	out, _ := os.Create("rsrc_windows_amd64.syso")
	rs.WriteObject(out, winres.ArchAMD64)
}

Thanks

Many thanks to akavel for his help.

This project uses these very helpful libs:

Documentation

Overview

Package winres provides functions to create a resource section for Windows executables. This is where the application's icon, manifest, and version information are stored.

Basic usage

Create an empty ResourceSet, call the Set method to add resources to it and then use the WriteObject method to produce an object file.

Each resource must be named, so it can later be accessed with FindResource, LoadImage, etc. To name a resource, you may use an int that you cast to winres.ID, or a string that you cast to winres.Name.

rs := winres.ResourceSet{}
rs.Set(winres.RT_RCDATA, winres.Name("MYDATA"), 0, 0, []byte("some data"))
rs.WriteObject(someFile, winres.ArchAMD64)
rs.WriteObject(anotherFile, winres.ArchI386)

Embedding resources in a Go built application

winres produces a linkable COFF object. Save it in your project's root directory with extension “syso” and it will be automatically included by “go build”.

It is recommended to name this object with target suffixes, so that the “go build” command automatically links the proper object for each target.

For example:

rsrc_windows_amd64.syso
rsrc_windows_386.syso

Example

Embedding an icon, version information, and a manifest:

 import (
	"image"
	"log"
	"os"

	"github.com/tc-hib/winres"
	"github.com/tc-hib/winres/version"
 )

 func main() {
	// First create an empty resource set
	rs := winres.ResourceSet{}

	// Make an icon group from a png file
	f, err := os.Open("icon.png")
	if err != nil {
		log.Fatalln(err)
	}
	defer f.Close()
	img, _, err := image.Decode(f)
	if err != nil {
		log.Fatalln(err)
	}
	f.Close()
	icon, _ := winres.NewIconFromResizedImage(img, nil)

	// Add the icon to the resource set, as "APPICON"
	rs.SetIcon(winres.Name("APPICON"), icon)

	// Make a VersionInfo structure
	vi := version.Info{
		FileVersion:    [4]uint16{1, 0, 0, 0},
		ProductVersion: [4]uint16{1, 0, 0, 1},
	}
	vi.Set(0, version.ProductName, "A Windows Application")
	vi.Set(0, version.ProductVersion, "v1.0.0.1")

	// Add the VersionInfo to the resource set
	rs.SetVersionInfo(vi)

	// Add a manifest
	rs.SetManifest(winres.AppManifest{
		ExecutionLevel:      RequireAdministrator,
		DPIAwareness:        DPIPerMonitorV2,
		UseCommonControlsV6: true,
	})

	// Create an object file for amd64
	out, err := os.Create("rsrc_windows_amd64.syso")
	defer out.Close()
	if err != nil {
		log.Fatalln(err)
	}
	err = rs.WriteObject(out, winres.ArchAMD64)
	if err != nil {
		log.Fatalln(err)
	}
 }

Localization

You can provide different resources depending on the user's langage.

To do so, you should provide a language code identifier (LCID) to the Set method.

A list of LCIDs is available there: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/

As an example, the LCID for en-US is 0x0409.

Other functions

winres can do a few more things: extract resources from an executable, replace resources in an executable, export cursors or icons...

Index

Constants

View Source
const (
	// ErrorIfSigned means winres won't patch a signed executable.
	ErrorIfSigned authenticodeHandling = 0
	// RemoveSignature means winres will patch a signed executable,
	// and remove the signature.
	RemoveSignature authenticodeHandling = 1
	// IgnoreSignature means winres will patch a signed executable,
	// and leave the now invalid signature as is.
	IgnoreSignature authenticodeHandling = 2
)
View Source
const (
	LCIDNeutral = 0
	LCIDDefault = 0x409 // en-US is default
)

Variables

View Source
var DefaultIconSizes = []int{256, 64, 48, 32, 16}
View Source
var ErrNoResources = errors.New(errNoRSRC)

ErrNoResources is the error returned by LoadFromEXE when it didn't find a .rsrc section.

View Source
var ErrSignedPE = errors.New(errSignedPE)

ErrSignedPE is the error returned by WriteToEXE when it refused to touch signed code. (Authenticode)

Functions

func ForceCheckSum

func ForceCheckSum() exeOption

ForceCheckSum forces updating the PE checksum, even when the original file didn't have one

func IsSignedEXE

func IsSignedEXE(exe io.ReadSeeker) (bool, error)

IsSignedEXE helps knowing if an exe file is signed before encountering an error with WriteToEXE.

func WithAuthenticode

func WithAuthenticode(handling authenticodeHandling) exeOption

WithAuthenticode allows patching signed executables, either by removing the signature or by ignoring it (and making it wrong)

Types

type AppManifest

type AppManifest struct {
	Identity                          AssemblyIdentity `json:"identity"`
	Description                       string           `json:"description"`
	Compatibility                     SupportedOS      `json:"minimum-os"`
	ExecutionLevel                    ExecutionLevel   `json:"execution-level"`
	UIAccess                          bool             `json:"ui-access"` // Require access to other applications' UI elements
	AutoElevate                       bool             `json:"auto-elevate"`
	DPIAwareness                      DPIAwareness     `json:"dpi-awareness"`
	DisableTheming                    bool             `json:"disable-theming"`
	DisableWindowFiltering            bool             `json:"disable-window-filtering"`
	HighResolutionScrollingAware      bool             `json:"high-resolution-scrolling-aware"`
	UltraHighResolutionScrollingAware bool             `json:"ultra-high-resolution-scrolling-aware"`
	LongPathAware                     bool             `json:"long-path-aware"`
	PrinterDriverIsolation            bool             `json:"printer-driver-isolation"`
	GDIScaling                        bool             `json:"gdi-scaling"`
	SegmentHeap                       bool             `json:"segment-heap"`
	UseCommonControlsV6               bool             `json:"use-common-controls-v6"` // Application requires Common Controls V6 (V5 remains the default)
}

AppManifest describes an application manifest.

Its zero value corresponds to the most common case.

func AppManifestFromXML

func AppManifestFromXML(data []byte) (AppManifest, error)

AppManifestFromXML makes an AppManifest from an xml manifest, trying to retrieve as much valid information as possible.

If the xml contains other data, they are ignored.

This function can only return xml syntax errors, other errors are ignored.

type Arch

type Arch string

Arch defines the target architecture. Its value can be used as a target suffix too: "rsrc_windows_"+string(arch)+".syso"

const (
	ArchI386  Arch = "386"
	ArchAMD64 Arch = "amd64"
	ArchARM   Arch = "arm"
	ArchARM64 Arch = "arm64"
)

type AssemblyIdentity

type AssemblyIdentity struct {
	Name    string
	Version [4]uint16
}

AssemblyIdentity defines the side-by-side assembly identity of the executable.

It should not be needed unless another assembly depends on this one.

If the Name field is empty, the <assemblyIdentity> element will be omitted.

func (AssemblyIdentity) MarshalJSON

func (ai AssemblyIdentity) MarshalJSON() ([]byte, error)

func (*AssemblyIdentity) UnmarshalJSON

func (ai *AssemblyIdentity) UnmarshalJSON(b []byte) error

type Cursor

type Cursor struct {
	// contains filtered or unexported fields
}

Cursor describes a mouse cursor.

This structure must only be created by constructors: NewCursorFromImages, LoadCUR

func LoadCUR

func LoadCUR(cur io.ReadSeeker) (*Cursor, error)

LoadCUR loads a CUR file and returns a cursor, ready to embed in a resource set.

func NewCursorFromImages

func NewCursorFromImages(images []CursorImage) (*Cursor, error)

NewCursorFromImages makes a cursor from a list of images and hot spots.

func (*Cursor) SaveCUR

func (cursor *Cursor) SaveCUR(ico io.Writer) error

SaveCUR saves a cursor as a CUR file.

type CursorImage

type CursorImage struct {
	Image   image.Image
	HotSpot HotSpot
}

CursorImage defines an image to import into a cursor.

It is an Image with hot spot coordinates.

type DPIAwareness

type DPIAwareness int

DPIAwareness is an enumeration which corresponds to the <dpiAware> and the <dpiAwareness> elements.

When it is set to DPIPerMonitorV2, it will fallback to DPIAware if the OS does not support it.

DPIPerMonitor would not scale windows on secondary monitors.

const (
	DPIAware DPIAwareness = iota
	DPIUnaware
	DPIPerMonitor
	DPIPerMonitorV2
)

func (DPIAwareness) MarshalText

func (a DPIAwareness) MarshalText() ([]byte, error)

func (*DPIAwareness) UnmarshalText

func (a *DPIAwareness) UnmarshalText(b []byte) error

type ExecutionLevel

type ExecutionLevel int

ExecutionLevel is used in an AppManifest to set the required execution level.

const (
	AsInvoker ExecutionLevel = iota
	HighestAvailable
	RequireAdministrator
)

func (ExecutionLevel) MarshalText

func (level ExecutionLevel) MarshalText() ([]byte, error)

func (*ExecutionLevel) UnmarshalText

func (level *ExecutionLevel) UnmarshalText(b []byte) error

type HotSpot

type HotSpot struct {
	X uint16
	Y uint16
}

HotSpot is the coordinates of a cursor's hot spot.

type ID

type ID uint16

ID is the type of a resource id, or resource type id.

const (
	RT_CURSOR       ID = 1
	RT_BITMAP       ID = 2
	RT_ICON         ID = 3
	RT_MENU         ID = 4
	RT_DIALOG       ID = 5
	RT_STRING       ID = 6
	RT_FONTDIR      ID = 7
	RT_FONT         ID = 8
	RT_ACCELERATOR  ID = 9
	RT_RCDATA       ID = 10
	RT_MESSAGETABLE ID = 11
	RT_GROUP_CURSOR ID = 12
	RT_GROUP_ICON   ID = 14
	RT_VERSION      ID = 16
	RT_PLUGPLAY     ID = 19
	RT_VXD          ID = 20
	RT_ANICURSOR    ID = 21
	RT_ANIICON      ID = 22
	RT_HTML         ID = 23
	RT_MANIFEST     ID = 24
)

Standard type IDs from https://docs.microsoft.com/en-us/windows/win32/menurc/resource-types

type Icon

type Icon struct {
	// contains filtered or unexported fields
}

Icon describes a Windows icon.

This structure must only be created by constructors: NewIconFromImages, NewIconFromResizedImage, LoadICO

func LoadICO

func LoadICO(ico io.ReadSeeker) (*Icon, error)

LoadICO loads an ICO file and returns an icon, ready to embed in a resource set.

func NewIconFromImages

func NewIconFromImages(images []image.Image) (*Icon, error)

NewIconFromImages makes an icon from a list of images.

This converts every image to 32bpp PNG.

func NewIconFromResizedImage

func NewIconFromResizedImage(img image.Image, sizes []int) (*Icon, error)

NewIconFromResizedImage makes an icon from a single Image by resizing it.

If sizes is nil, the icon will be resized to: 256px, 64px, 48px, 32px, 16px.

func (*Icon) SaveICO

func (icon *Icon) SaveICO(ico io.Writer) error

SaveICO saves an icon as an ICO file.

type Identifier

type Identifier interface {
	// contains filtered or unexported methods
}

Identifier is either an ID or a Name.

When you are asked for an Identifier, you can pass an int cast to an ID or a string cast to a Name.

type Name

type Name string

Name is the type of a resource name, or a resource type name.

type ResourceSet

type ResourceSet struct {
	// contains filtered or unexported fields
}

ResourceSet is the main object in the package.

Create an empty ResourceSet and call Set methods to add resources, then WriteObject to produce a COFF object file.

func LoadFromEXE

func LoadFromEXE(exe io.ReadSeeker) (*ResourceSet, error)

LoadFromEXE loads the .rsrc section of the executable and returns a ResourceSet

func LoadFromEXESingleType

func LoadFromEXESingleType(exe io.ReadSeeker, typeID Identifier) (*ResourceSet, error)

LoadFromEXESingleType loads the .rsrc section of the executable and returns a ResourceSet containing only resources of one type.

func (*ResourceSet) Count

func (rs *ResourceSet) Count() int

Count returns the number of resources in the set.

func (*ResourceSet) Get

func (rs *ResourceSet) Get(typeID, resID Identifier, langID uint16) []byte

Get returns resource data.

Returns nil if the resource was not found.

func (*ResourceSet) GetCursor

func (rs *ResourceSet) GetCursor(resID Identifier) (*Cursor, error)

GetCursor extracts a cursor from a resource set.

func (*ResourceSet) GetCursorTranslation

func (rs *ResourceSet) GetCursorTranslation(resID Identifier, langID uint16) (*Cursor, error)

GetCursorTranslation extracts a cursor from a specific language of the resource set.

func (*ResourceSet) GetIcon

func (rs *ResourceSet) GetIcon(resID Identifier) (*Icon, error)

GetIcon extracts an icon from a resource set.

func (*ResourceSet) GetIconTranslation

func (rs *ResourceSet) GetIconTranslation(resID Identifier, langID uint16) (*Icon, error)

GetIconTranslation extracts an icon from a specific language of the resource set.

func (*ResourceSet) Set

func (rs *ResourceSet) Set(typeID, resID Identifier, langID uint16, data []byte) error

Set adds or replaces a resource.

typeID is the resource type's identifier. It can be either a standard type number (RT_ICON, RT_VERSION, ...) or any type name.

resID is the resource's unique identifier for a given type. It can either be an ID starting from 1, or a Name.

A resource ID can have different data depending on the user's locale. In this case Set can be called several times with the same resID but a different language ID.

langID can be 0 (neutral), or one of those LCID: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid

Warning: the ResourceSet takes ownership of the data parameter. The caller should not write into it anymore after calling this method.

func (*ResourceSet) SetCursor

func (rs *ResourceSet) SetCursor(resID Identifier, cursor *Cursor) error

SetCursor adds the cursor to the resource set.

func (*ResourceSet) SetCursorTranslation

func (rs *ResourceSet) SetCursorTranslation(resID Identifier, langID uint16, cursor *Cursor) error

SetCursorTranslation adds the cursor to a specific language in the resource set.

func (*ResourceSet) SetIcon

func (rs *ResourceSet) SetIcon(resID Identifier, icon *Icon) error

SetIcon adds the icon to the resource set.

The first icon will be the application's icon, as shown in Windows Explorer. That means:

  1. First name in case-sensitive ascending order, or else...
  2. First ID in ascending order

func (*ResourceSet) SetIconTranslation

func (rs *ResourceSet) SetIconTranslation(resID Identifier, langID uint16, icon *Icon) error

SetIconTranslation adds the icon to a specific language in the resource set.

The first icon will be the application's icon, as shown in Windows Explorer. That means:

  1. First name in case-sensitive ascending order, or else...
  2. First ID in ascending order

func (*ResourceSet) SetManifest

func (rs *ResourceSet) SetManifest(manifest AppManifest)

SetManifest is a simplified way to embed a typical application manifest, without writing xml directly.

func (*ResourceSet) SetVersionInfo

func (rs *ResourceSet) SetVersionInfo(vi version.Info)

SetVersionInfo sets the VersionInfo structure.

This what Windows displays in the Details tab of file properties.

func (*ResourceSet) Walk

func (rs *ResourceSet) Walk(f func(typeID, resID Identifier, langID uint16, data []byte) bool)

Walk walks through the resources in same order as they will be written.

It takes a callback function that takes same parameters as Set and returns a bool that should be true to continue, false to stop.

If you modify the set during a call to Walk, behaviour is undefined.

func (*ResourceSet) WalkType

func (rs *ResourceSet) WalkType(typeID Identifier, f func(resID Identifier, langID uint16, data []byte) bool)

WalkType walks through the resources or a certain type, in same order as they will be written.

It takes a callback function that takes same parameters as Set and returns a bool that should be true to continue, false to stop.

If you modify the set during a call to Walk, behaviour is undefined.

func (*ResourceSet) WriteObject

func (rs *ResourceSet) WriteObject(w io.Writer, arch Arch) error

WriteObject writes a full object file into w.

func (*ResourceSet) WriteToEXE

func (rs *ResourceSet) WriteToEXE(dst io.Writer, src io.ReadSeeker, opt ...exeOption) error

WriteToEXE patches an executable to replace its resources with this ResourceSet.

It reads the original file from src and writes the new file to dst.

src and dst should not point to a same file/buffer.

Options:

ForceCheckSum()         // Forces updating the checksum even when it was not set in the original file
WithAuthenticode(<how>) // Allows updating the .rsrc section despite the file being signed

type SupportedOS

type SupportedOS int

SupportedOS is an enumeration that provides a simplified way to fill the compatibility element in an application manifest, by only setting a minimum OS.

Its zero value is Win7AndAbove, which matches Go's requirements.

https://github.com/golang/go/wiki/MinimumRequirements#windows

const (
	WinVistaAndAbove SupportedOS = iota - 1
	Win7AndAbove
	Win8AndAbove
	Win81AndAbove
	Win10AndAbove
)

func (SupportedOS) MarshalText

func (os SupportedOS) MarshalText() ([]byte, error)

func (*SupportedOS) UnmarshalText

func (os *SupportedOS) UnmarshalText(b []byte) error

Directories

Path Synopsis
Package version provides functions to build a VERSIONINFO structure for Windows applications.
Package version provides functions to build a VERSIONINFO structure for Windows applications.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL