mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-10 22:19:46 +08:00
[v3 windows] Initial support for start_on_login plugin for windows
This commit is contained in:
parent
3827ca2d78
commit
b898b79aaf
@ -78,4 +78,36 @@ When adding a common event, ensure that the platform specific events are mapped.
|
||||
})
|
||||
```
|
||||
|
||||
NOTE: We may try to automate this in the future by adding the mapping to the event definition.
|
||||
NOTE: We may try to automate this in the future by adding the mapping to the event definition.
|
||||
|
||||
### Plugins
|
||||
|
||||
Plugins are a way to extend the functionality of your Wails application.
|
||||
|
||||
#### Creating a plugin
|
||||
|
||||
Plugins are standard Go structure that adhere to the following interface:
|
||||
|
||||
```go
|
||||
type Plugin interface {
|
||||
Name() string
|
||||
Init(*application.App) error
|
||||
Shutdown()
|
||||
CallableByJS() []string
|
||||
InjectJS() string
|
||||
}
|
||||
```
|
||||
|
||||
The `Name()` method returns the name of the plugin. This is used for logging purposes.
|
||||
|
||||
The `Init(*application.App) error` method is called when the plugin is loaded. The `*application.App`
|
||||
parameter is the application that the plugin is being loaded into. Any errors will prevent
|
||||
the application from starting.
|
||||
|
||||
The `Shutdown()` method is called when the application is shutting down.
|
||||
|
||||
The `CallableByJS()` method returns a list of exported functions that can be called from
|
||||
the frontend. These method names must exactly match the names of the methods exported
|
||||
by the plugin.
|
||||
|
||||
The `InjectJS()` method returns JavaScript that should be injected into all windows as they are created. This is useful for adding custom JavaScript functions that complement the plugin.
|
||||
|
18
v3/STATUS.md
18
v3/STATUS.md
@ -90,7 +90,7 @@ Webview Window Interface Methods
|
||||
|
||||
| Feature | Windows | Linux | Mac | Notes |
|
||||
|---------|---------|-------|-----|-------|
|
||||
| Quit | Y | Y | Y | |
|
||||
| Quit | Y | Y | Y | |
|
||||
| Hide | Y | | Y | |
|
||||
| Show | Y | | Y | |
|
||||
|
||||
@ -214,7 +214,6 @@ An 'X' indicates that the option is not supported by the platform.
|
||||
| Zoom | | | | |
|
||||
| ZoomControlEnabled | | | | |
|
||||
|
||||
|
||||
### Log
|
||||
|
||||
To log or not to log? System logger vs custom logger.
|
||||
@ -223,7 +222,7 @@ To log or not to log? System logger vs custom logger.
|
||||
|
||||
| Event | Windows | Linux | Mac | Notes |
|
||||
|--------------------------|---------|-------|-----|-------|
|
||||
| Default Application Menu | Y | Y | Y | |
|
||||
| Default Application Menu | Y | Y | Y | |
|
||||
|
||||
## Tray Menus
|
||||
|
||||
@ -320,11 +319,10 @@ TODO:
|
||||
|
||||
## Frameless Windows
|
||||
|
||||
| Feature | Windows | Linux | Mac | Notes |
|
||||
|---------|---------|-------|-----|-----------------------------------------------|
|
||||
| Resize | | | | |
|
||||
| Drag | | Y | | Linux - can always drag with `Meta`+left mouse |
|
||||
|
||||
| Feature | Windows | Linux | Mac | Notes |
|
||||
|---------|---------|-------|-----|------------------------------------------------|
|
||||
| Resize | Y | | Y | |
|
||||
| Drag | Y | Y | Y | Linux - can always drag with `Meta`+left mouse |
|
||||
|
||||
## Mac Specific
|
||||
|
||||
@ -359,7 +357,6 @@ TODO:
|
||||
|
||||
## Linux Specific
|
||||
|
||||
|
||||
Implementation details for the functions utilized by the `*_linux.go` files are located in the following files:
|
||||
|
||||
- linux_cgo.go: CGo implementation
|
||||
@ -367,7 +364,8 @@ Implementation details for the functions utilized by the `*_linux.go` files are
|
||||
|
||||
### CGO
|
||||
|
||||
By default CGO is utilized to compile the Linux port. This prevents easy cross-compilation and so the PureGo implementation is also being simultaneously developed.
|
||||
By default CGO is utilized to compile the Linux port. This prevents easy cross-compilation and so the PureGo
|
||||
implementation is also being simultaneously developed.
|
||||
|
||||
### Purego
|
||||
|
||||
|
@ -14,7 +14,7 @@ Application events are events that are emitted by the application. These events
|
||||
|
||||
### Window Events
|
||||
|
||||
Window events are events that are emitted by a window. These events include native events such as `WindowDidBecomeMain` on macOS.
|
||||
Window events are events that are emitted by a window. These events include native events such as `WindowDidBecomeMain` on macOS. Common events are also defined, so they work cross-platform, e.g. `WindowClosing`.
|
||||
|
||||
### Custom Events
|
||||
|
||||
@ -46,6 +46,8 @@ When emitting an event in JS, it now sends the event to the application. This wi
|
||||
The Window API has largely remained the same, however the methods are now on an instance of a window rather than the runtime.
|
||||
Some notable differences are:
|
||||
- Windows now have a Name that identifies them. This is used to identify the window when emitting events.
|
||||
- Windows have even more methods on the that were previously unavailable, such as `AbsolutePosition` and `ToggleDevTools`.
|
||||
- Windows can now accept files via native drag and drop. See the Drag and Drop section for more details.
|
||||
|
||||
## ClipBoard
|
||||
|
||||
|
@ -7,6 +7,7 @@ require github.com/wailsapp/wails/v3 v3.0.0-alpha.0
|
||||
require (
|
||||
github.com/bep/debounce v1.2.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/ebitengine/purego v0.4.0-alpha.4 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||
@ -22,7 +23,7 @@ require (
|
||||
github.com/samber/lo v1.37.0 // indirect
|
||||
github.com/wailsapp/go-webview2 v1.0.2-0.20230604075323-d593c659ca7b // indirect
|
||||
github.com/wailsapp/mimetype v1.4.1 // indirect
|
||||
github.com/wailsapp/wails/v2 v2.3.2-0.20230117193915-45c3a501d9e6 // indirect
|
||||
github.com/wailsapp/wails/v2 v2.5.1 // indirect
|
||||
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
|
@ -5,6 +5,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/ebitengine/purego v0.4.0-alpha.4 h1:Y7yIV06Yo5M2BAdD7EVPhfp6LZ0tEcQo5770OhYUVes=
|
||||
github.com/ebitengine/purego v0.4.0-alpha.4/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
|
@ -39,15 +39,16 @@ func main() {
|
||||
// When true, the original app will be activated when a second instance is launched
|
||||
ActivateAppOnSubsequentLaunch: true,
|
||||
}),
|
||||
"start_at_login": start_at_login.NewPlugin(),
|
||||
"start_at_login": start_at_login.NewPlugin(start_at_login.Config{}),
|
||||
},
|
||||
Assets: application.AssetOptions{
|
||||
FS: assets,
|
||||
},
|
||||
})
|
||||
|
||||
window := app.NewWebviewWindow()
|
||||
window.ToggleDevTools()
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
DevToolsEnabled: true,
|
||||
})
|
||||
|
||||
err := app.Run()
|
||||
|
||||
|
225
v3/pkg/w32/guid.go
Normal file
225
v3/pkg/w32/guid.go
Normal file
@ -0,0 +1,225 @@
|
||||
//go:build windows
|
||||
|
||||
package w32
|
||||
|
||||
// This code has been adapted from: https://github.com/go-ole/go-ole
|
||||
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2013-2017 Yasuhiro Matsumoto, <mattn.jp@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the “Software”), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
const hextable = "0123456789ABCDEF"
|
||||
const emptyGUID = "{00000000-0000-0000-0000-000000000000}"
|
||||
|
||||
// GUID is Windows API specific GUID type.
|
||||
//
|
||||
// This exists to match Windows GUID type for direct passing for COM.
|
||||
// Format is in xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx.
|
||||
type GUID struct {
|
||||
Data1 uint32
|
||||
Data2 uint16
|
||||
Data3 uint16
|
||||
Data4 [8]byte
|
||||
}
|
||||
|
||||
// NewGUID converts the given string into a globally unique identifier that is
|
||||
// compliant with the Windows API.
|
||||
//
|
||||
// The supplied string may be in any of these formats:
|
||||
//
|
||||
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
// XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
|
||||
// {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
|
||||
//
|
||||
// The conversion of the supplied string is not case-sensitive.
|
||||
func NewGUID(guid string) *GUID {
|
||||
d := []byte(guid)
|
||||
var d1, d2, d3, d4a, d4b []byte
|
||||
|
||||
switch len(d) {
|
||||
case 38:
|
||||
if d[0] != '{' || d[37] != '}' {
|
||||
return nil
|
||||
}
|
||||
d = d[1:37]
|
||||
fallthrough
|
||||
case 36:
|
||||
if d[8] != '-' || d[13] != '-' || d[18] != '-' || d[23] != '-' {
|
||||
return nil
|
||||
}
|
||||
d1 = d[0:8]
|
||||
d2 = d[9:13]
|
||||
d3 = d[14:18]
|
||||
d4a = d[19:23]
|
||||
d4b = d[24:36]
|
||||
case 32:
|
||||
d1 = d[0:8]
|
||||
d2 = d[8:12]
|
||||
d3 = d[12:16]
|
||||
d4a = d[16:20]
|
||||
d4b = d[20:32]
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
var g GUID
|
||||
var ok1, ok2, ok3, ok4 bool
|
||||
g.Data1, ok1 = decodeHexUint32(d1)
|
||||
g.Data2, ok2 = decodeHexUint16(d2)
|
||||
g.Data3, ok3 = decodeHexUint16(d3)
|
||||
g.Data4, ok4 = decodeHexByte64(d4a, d4b)
|
||||
if ok1 && ok2 && ok3 && ok4 {
|
||||
return &g
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeHexUint32(src []byte) (value uint32, ok bool) {
|
||||
var b1, b2, b3, b4 byte
|
||||
var ok1, ok2, ok3, ok4 bool
|
||||
b1, ok1 = decodeHexByte(src[0], src[1])
|
||||
b2, ok2 = decodeHexByte(src[2], src[3])
|
||||
b3, ok3 = decodeHexByte(src[4], src[5])
|
||||
b4, ok4 = decodeHexByte(src[6], src[7])
|
||||
value = (uint32(b1) << 24) | (uint32(b2) << 16) | (uint32(b3) << 8) | uint32(b4)
|
||||
ok = ok1 && ok2 && ok3 && ok4
|
||||
return
|
||||
}
|
||||
|
||||
func decodeHexUint16(src []byte) (value uint16, ok bool) {
|
||||
var b1, b2 byte
|
||||
var ok1, ok2 bool
|
||||
b1, ok1 = decodeHexByte(src[0], src[1])
|
||||
b2, ok2 = decodeHexByte(src[2], src[3])
|
||||
value = (uint16(b1) << 8) | uint16(b2)
|
||||
ok = ok1 && ok2
|
||||
return
|
||||
}
|
||||
|
||||
func decodeHexByte64(s1 []byte, s2 []byte) (value [8]byte, ok bool) {
|
||||
var ok1, ok2, ok3, ok4, ok5, ok6, ok7, ok8 bool
|
||||
value[0], ok1 = decodeHexByte(s1[0], s1[1])
|
||||
value[1], ok2 = decodeHexByte(s1[2], s1[3])
|
||||
value[2], ok3 = decodeHexByte(s2[0], s2[1])
|
||||
value[3], ok4 = decodeHexByte(s2[2], s2[3])
|
||||
value[4], ok5 = decodeHexByte(s2[4], s2[5])
|
||||
value[5], ok6 = decodeHexByte(s2[6], s2[7])
|
||||
value[6], ok7 = decodeHexByte(s2[8], s2[9])
|
||||
value[7], ok8 = decodeHexByte(s2[10], s2[11])
|
||||
ok = ok1 && ok2 && ok3 && ok4 && ok5 && ok6 && ok7 && ok8
|
||||
return
|
||||
}
|
||||
|
||||
func decodeHexByte(c1, c2 byte) (value byte, ok bool) {
|
||||
var n1, n2 byte
|
||||
var ok1, ok2 bool
|
||||
n1, ok1 = decodeHexChar(c1)
|
||||
n2, ok2 = decodeHexChar(c2)
|
||||
value = (n1 << 4) | n2
|
||||
ok = ok1 && ok2
|
||||
return
|
||||
}
|
||||
|
||||
func decodeHexChar(c byte) (byte, bool) {
|
||||
switch {
|
||||
case '0' <= c && c <= '9':
|
||||
return c - '0', true
|
||||
case 'a' <= c && c <= 'f':
|
||||
return c - 'a' + 10, true
|
||||
case 'A' <= c && c <= 'F':
|
||||
return c - 'A' + 10, true
|
||||
}
|
||||
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// String converts the GUID to string form. It will adhere to this pattern:
|
||||
//
|
||||
// {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
|
||||
//
|
||||
// If the GUID is nil, the string representation of an empty GUID is returned:
|
||||
//
|
||||
// {00000000-0000-0000-0000-000000000000}
|
||||
func (guid *GUID) String() string {
|
||||
if guid == nil {
|
||||
return emptyGUID
|
||||
}
|
||||
|
||||
var c [38]byte
|
||||
c[0] = '{'
|
||||
putUint32Hex(c[1:9], guid.Data1)
|
||||
c[9] = '-'
|
||||
putUint16Hex(c[10:14], guid.Data2)
|
||||
c[14] = '-'
|
||||
putUint16Hex(c[15:19], guid.Data3)
|
||||
c[19] = '-'
|
||||
putByteHex(c[20:24], guid.Data4[0:2])
|
||||
c[24] = '-'
|
||||
putByteHex(c[25:37], guid.Data4[2:8])
|
||||
c[37] = '}'
|
||||
return string(c[:])
|
||||
}
|
||||
|
||||
func putUint32Hex(b []byte, v uint32) {
|
||||
b[0] = hextable[byte(v>>24)>>4]
|
||||
b[1] = hextable[byte(v>>24)&0x0f]
|
||||
b[2] = hextable[byte(v>>16)>>4]
|
||||
b[3] = hextable[byte(v>>16)&0x0f]
|
||||
b[4] = hextable[byte(v>>8)>>4]
|
||||
b[5] = hextable[byte(v>>8)&0x0f]
|
||||
b[6] = hextable[byte(v)>>4]
|
||||
b[7] = hextable[byte(v)&0x0f]
|
||||
}
|
||||
|
||||
func putUint16Hex(b []byte, v uint16) {
|
||||
b[0] = hextable[byte(v>>8)>>4]
|
||||
b[1] = hextable[byte(v>>8)&0x0f]
|
||||
b[2] = hextable[byte(v)>>4]
|
||||
b[3] = hextable[byte(v)&0x0f]
|
||||
}
|
||||
|
||||
func putByteHex(dst, src []byte) {
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i*2] = hextable[src[i]>>4]
|
||||
dst[i*2+1] = hextable[src[i]&0x0f]
|
||||
}
|
||||
}
|
||||
|
||||
// IsEqualGUID compares two GUID.
|
||||
//
|
||||
// Not constant time comparison.
|
||||
func IsEqualGUID(guid1 *GUID, guid2 *GUID) bool {
|
||||
return guid1.Data1 == guid2.Data1 &&
|
||||
guid1.Data2 == guid2.Data2 &&
|
||||
guid1.Data3 == guid2.Data3 &&
|
||||
guid1.Data4[0] == guid2.Data4[0] &&
|
||||
guid1.Data4[1] == guid2.Data4[1] &&
|
||||
guid1.Data4[2] == guid2.Data4[2] &&
|
||||
guid1.Data4[3] == guid2.Data4[3] &&
|
||||
guid1.Data4[4] == guid2.Data4[4] &&
|
||||
guid1.Data4[5] == guid2.Data4[5] &&
|
||||
guid1.Data4[6] == guid2.Data4[6] &&
|
||||
guid1.Data4[7] == guid2.Data4[7]
|
||||
}
|
@ -9,6 +9,7 @@ package w32
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"golang.org/x/sys/windows"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
@ -82,6 +83,124 @@ const (
|
||||
NOTIFYICON_VERSION = 4
|
||||
)
|
||||
|
||||
var (
|
||||
FOLDERID_AccountPictures = NewGUID("{008CA0B1-55B4-4C56-B8A8-4DE4B299D3BE}")
|
||||
FOLDERID_AddNewPrograms = NewGUID("{DE61D971-5EBC-4F02-A3A9-6C82895E5C04}")
|
||||
FOLDERID_AdminTools = NewGUID("{724EF170-A42D-4FEF-9F26-B60E846FBA4F}")
|
||||
FOLDERID_ApplicationShortcuts = NewGUID("{A3918781-E5F2-4890-B3D9-A7E54332328C}")
|
||||
FOLDERID_AppsFolder = NewGUID("{1E87508D-89C2-42F0-8A7E-645A0F50CA58}")
|
||||
FOLDERID_AppUpdates = NewGUID("{A305CE99-F527-492B-8B1A-7E76FA98D6E4}")
|
||||
FOLDERID_CDBurning = NewGUID("{9E52AB10-F80D-49DF-ACB8-4330F5687855}")
|
||||
FOLDERID_ChangeRemovePrograms = NewGUID("{DF7266AC-9274-4867-8D55-3BD661DE872D}")
|
||||
FOLDERID_CommonAdminTools = NewGUID("{D0384E7D-BAC3-4797-8F14-CBA229B392B5}")
|
||||
FOLDERID_CommonOEMLinks = NewGUID("{C1BAE2D0-10DF-4334-BEDD-7AA20B227A9D}")
|
||||
FOLDERID_CommonPrograms = NewGUID("{0139D44E-6AFE-49F2-8690-3DAFCAE6FFB8}")
|
||||
FOLDERID_CommonStartMenu = NewGUID("{A4115719-D62E-491D-AA7C-E74B8BE3B067}")
|
||||
FOLDERID_CommonStartup = NewGUID("{82A5EA35-D9CD-47C5-9629-E15D2F714E6E}")
|
||||
FOLDERID_CommonTemplates = NewGUID("{B94237E7-57AC-4347-9151-B08C6C32D1F7}")
|
||||
FOLDERID_ComputerFolder = NewGUID("{0AC0837C-BBF8-452A-850D-79D08E667CA7}")
|
||||
FOLDERID_ConflictFolder = NewGUID("{4BFEFB45-347D-4006-A5BE-AC0CB0567192}")
|
||||
FOLDERID_ConnectionsFolder = NewGUID("{6F0CD92B-2E97-45D1-88FF-B0D186B8DEDD}")
|
||||
FOLDERID_Contacts = NewGUID("{56784854-C6CB-462B-8169-88E350ACB882}")
|
||||
FOLDERID_ControlPanelFolder = NewGUID("{82A74AEB-AEB4-465C-A014-D097EE346D63}")
|
||||
FOLDERID_Cookies = NewGUID("{2B0F765D-C0E9-4171-908E-08A611B84FF6}")
|
||||
FOLDERID_Desktop = NewGUID("{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}")
|
||||
FOLDERID_DeviceMetadataStore = NewGUID("{5CE4A5E9-E4EB-479D-B89F-130C02886155}")
|
||||
FOLDERID_Documents = NewGUID("{FDD39AD0-238F-46AF-ADB4-6C85480369C7}")
|
||||
FOLDERID_DocumentsLibrary = NewGUID("{7B0DB17D-9CD2-4A93-9733-46CC89022E7C}")
|
||||
FOLDERID_Downloads = NewGUID("{374DE290-123F-4565-9164-39C4925E467B}")
|
||||
FOLDERID_Favorites = NewGUID("{1777F761-68AD-4D8A-87BD-30B759FA33DD}")
|
||||
FOLDERID_Fonts = NewGUID("{FD228CB7-AE11-4AE3-864C-16F3910AB8FE}")
|
||||
FOLDERID_Games = NewGUID("{CAC52C1A-B53D-4EDC-92D7-6B2E8AC19434}")
|
||||
FOLDERID_GameTasks = NewGUID("{054FAE61-4DD8-4787-80B6-090220C4B700}")
|
||||
FOLDERID_History = NewGUID("{D9DC8A3B-B784-432E-A781-5A1130A75963}")
|
||||
FOLDERID_HomeGroup = NewGUID("{52528A6B-B9E3-4ADD-B60D-588C2DBA842D}")
|
||||
FOLDERID_HomeGroupCurrentUser = NewGUID("{9B74B6A3-0DFD-4F11-9E78-5F7800F2E772}")
|
||||
FOLDERID_ImplicitAppShortcuts = NewGUID("{BCB5256F-79F6-4CEE-B725-DC34E402FD46}")
|
||||
FOLDERID_InternetCache = NewGUID("{352481E8-33BE-4251-BA85-6007CAEDCF9D}")
|
||||
FOLDERID_InternetFolder = NewGUID("{4D9F7874-4E0C-4904-967B-40B0D20C3E4B}")
|
||||
FOLDERID_Libraries = NewGUID("{1B3EA5DC-B587-4786-B4EF-BD1DC332AEAE}")
|
||||
FOLDERID_Links = NewGUID("{BFB9D5E0-C6A9-404C-B2B2-AE6DB6AF4968}")
|
||||
FOLDERID_LocalAppData = NewGUID("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}")
|
||||
FOLDERID_LocalAppDataLow = NewGUID("{A520A1A4-1780-4FF6-BD18-167343C5AF16}")
|
||||
FOLDERID_LocalizedResourcesDir = NewGUID("{2A00375E-224C-49DE-B8D1-440DF7EF3DDC}")
|
||||
FOLDERID_Music = NewGUID("{4BD8D571-6D19-48D3-BE97-422220080E43}")
|
||||
FOLDERID_MusicLibrary = NewGUID("{2112AB0A-C86A-4FFE-A368-0DE96E47012E}")
|
||||
FOLDERID_NetHood = NewGUID("{C5ABBF53-E17F-4121-8900-86626FC2C973}")
|
||||
FOLDERID_NetworkFolder = NewGUID("{D20BEEC4-5CA8-4905-AE3B-BF251EA09B53}")
|
||||
FOLDERID_OriginalImages = NewGUID("{2C36C0AA-5812-4B87-BFD0-4CD0DFB19B39}")
|
||||
FOLDERID_PhotoAlbums = NewGUID("{69D2CF90-FC33-4FB7-9A0C-EBB0F0FCB43C}")
|
||||
FOLDERID_Pictures = NewGUID("{33E28130-4E1E-4676-835A-98395C3BC3BB}")
|
||||
FOLDERID_PicturesLibrary = NewGUID("{A990AE9F-A03B-4E80-94BC-9912D7504104}")
|
||||
FOLDERID_Playlists = NewGUID("{DE92C1C7-837F-4F69-A3BB-86E631204A23}")
|
||||
FOLDERID_PrintersFolder = NewGUID("{76FC4E2D-D6AD-4519-A663-37BD56068185}")
|
||||
FOLDERID_PrintHood = NewGUID("{9274BD8D-CFD1-41C3-B35E-B13F55A758F4}")
|
||||
FOLDERID_Profile = NewGUID("{5E6C858F-0E22-4760-9AFE-EA3317B67173}")
|
||||
FOLDERID_ProgramData = NewGUID("{62AB5D82-FDC1-4DC3-A9DD-070D1D495D97}")
|
||||
FOLDERID_ProgramFiles = NewGUID("{905E63B6-C1BF-494E-B29C-65B732D3D21A}")
|
||||
FOLDERID_ProgramFilesCommon = NewGUID("{F7F1ED05-9F6D-47A2-AAAE-29D317C6F066}")
|
||||
FOLDERID_ProgramFilesCommonX64 = NewGUID("{6365D5A7-0F0D-45E5-87F6-0DA56B6A4F7D}")
|
||||
FOLDERID_ProgramFilesCommonX86 = NewGUID("{DE974D24-D9C6-4D3E-BF91-F4455120B917}")
|
||||
FOLDERID_ProgramFilesX64 = NewGUID("{6D809377-6AF0-444B-8957-A3773F02200E}")
|
||||
FOLDERID_ProgramFilesX86 = NewGUID("{7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E}")
|
||||
FOLDERID_Programs = NewGUID("{A77F5D77-2E2B-44C3-A6A2-ABA601054A51}")
|
||||
FOLDERID_Public = NewGUID("{DFDF76A2-C82A-4D63-906A-5644AC457385}")
|
||||
FOLDERID_PublicDesktop = NewGUID("{C4AA340D-F20F-4863-AFEF-1F769F2BE730}")
|
||||
FOLDERID_PublicDocuments = NewGUID("{ED4824AF-DCE4-45A8-81E2-FC7965083634}")
|
||||
FOLDERID_PublicDownloads = NewGUID("{3D644C9B-1FB8-4F30-9B45-F670235F79C0}")
|
||||
FOLDERID_PublicGameTasks = NewGUID("{DEBF2536-E1A8-4C59-B6A2-414586476AEA}")
|
||||
FOLDERID_PublicLibraries = NewGUID("{48DAF80B-E6CF-4F4E-B800-0E69D84EE384}")
|
||||
FOLDERID_PublicMusic = NewGUID("{3214FAB5-9757-4298-BB61-92A9DEAA44FF}")
|
||||
FOLDERID_PublicPictures = NewGUID("{B6EBFB86-6907-413C-9AF7-4FC2ABF07CC5}")
|
||||
FOLDERID_PublicRingtones = NewGUID("{E555AB60-153B-4D17-9F04-A5FE99FC15EC}")
|
||||
FOLDERID_PublicUserTiles = NewGUID("{0482af6c-08f1-4c34-8c90-e17ec98b1e17}")
|
||||
FOLDERID_PublicVideos = NewGUID("{2400183A-6185-49FB-A2D8-4A392A602BA3}")
|
||||
FOLDERID_QuickLaunch = NewGUID("{52a4f021-7b75-48a9-9f6b-4b87a210bc8f}")
|
||||
FOLDERID_Recent = NewGUID("{AE50C081-EBD2-438A-8655-8A092E34987A}")
|
||||
FOLDERID_RecordedTVLibrary = NewGUID("{1A6FDBA2-F42D-4358-A798-B74D745926C5}")
|
||||
FOLDERID_RecycleBinFolder = NewGUID("{B7534046-3ECB-4C18-BE4E-64CD4CB7D6AC}")
|
||||
FOLDERID_ResourceDir = NewGUID("{8AD10C31-2ADB-4296-A8F7-E4701232C972}")
|
||||
FOLDERID_Ringtones = NewGUID("{C870044B-F49E-4126-A9C3-B52A1FF411E8}")
|
||||
FOLDERID_RoamingAppData = NewGUID("{3EB685DB-65F9-4CF6-A03A-E3EF65729F3D}")
|
||||
FOLDERID_RoamingTiles = NewGUID("{AAA8D5A5-F1D6-4259-BAA8-78E7EF60835E}")
|
||||
FOLDERID_SampleMusic = NewGUID("{B250C668-F57D-4EE1-A63C-290EE7D1AA1F}")
|
||||
FOLDERID_SamplePictures = NewGUID("{C4900540-2379-4C75-844B-64E6FAF8716B}")
|
||||
FOLDERID_SamplePlaylists = NewGUID("{15CA69B3-30EE-49C1-ACE1-6B5EC372AFB5}")
|
||||
FOLDERID_SampleVideos = NewGUID("{859EAD94-2E85-48AD-A71A-0969CB56A6CD}")
|
||||
FOLDERID_SavedGames = NewGUID("{4C5C32FF-BB9D-43B0-B5B4-2D72E54EAAA4}")
|
||||
FOLDERID_SavedPictures = NewGUID("{3B193882-D3AD-4EAB-965A-69829D1FB59F}")
|
||||
FOLDERID_SavedPicturesLibrary = NewGUID("{E25B5812-BE88-4BD9-94B0-29233477B6C3}")
|
||||
FOLDERID_SavedSearches = NewGUID("{7D1D3A04-DEBB-4115-95CF-2F29DA2920DA}")
|
||||
FOLDERID_SEARCH_CSC = NewGUID("{ee32e446-31ca-4aba-814f-a5ebd2fd6d5e}")
|
||||
FOLDERID_SEARCH_MAPI = NewGUID("{98ec0e18-2098-4d44-8644-66979315a281}")
|
||||
FOLDERID_SearchHome = NewGUID("{190337d1-b8ca-4121-a639-6d472d16972a}")
|
||||
FOLDERID_SendTo = NewGUID("{8983036C-27C0-404B-8F08-102D10DCFD74}")
|
||||
FOLDERID_SidebarDefaultParts = NewGUID("{7B396E54-9EC5-4300-BE0A-2482EBAE1A26}")
|
||||
FOLDERID_SidebarParts = NewGUID("{A75D362E-50FC-4fb7-AC2C-A8BEAA314493}")
|
||||
FOLDERID_SkyDrive = NewGUID("{A52BBA46-E9E1-435f-B3D9-28DAA648C0F6}")
|
||||
FOLDERID_SkyDriveCameraRoll = NewGUID("{767E6811-49CB-4273-87C2-20F355E1085B}")
|
||||
FOLDERID_SkyDriveDocuments = NewGUID("{24D89E24-2F19-4534-9DDE-6A6671FBB8FE}")
|
||||
FOLDERID_SkyDriveMusic = NewGUID("{C3F2459E-80D6-45DC-BFEF-1F769F2BE730}")
|
||||
FOLDERID_SkyDrivePictures = NewGUID("{339719B5-8C47-4894-94C2-D8F77ADD44A6}")
|
||||
FOLDERID_StartMenu = NewGUID("{625B53C3-AB48-4EC1-BA1F-A1EF4146FC19}")
|
||||
FOLDERID_Startup = NewGUID("{B97D20BB-F46A-4C97-BA10-5E3608430854}")
|
||||
FOLDERID_SyncManagerFolder = NewGUID("{43668BF8-C14E-49B2-97C9-747784D784B7}")
|
||||
FOLDERID_SyncResultsFolder = NewGUID("{289a9a43-be44-4057-a41b-587a76d7e7f9}")
|
||||
FOLDERID_SyncSetupFolder = NewGUID("{0F214138-B1D3-4a90-BBA9-27CBC0C5389A}")
|
||||
FOLDERID_System = NewGUID("{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}")
|
||||
FOLDERID_SystemX86 = NewGUID("{D65231B0-B2F1-4857-A4CE-A8E7C6EA7D27}")
|
||||
FOLDERID_Templates = NewGUID("{A63293E8-664E-48DB-A079-DF759E0509F7}")
|
||||
FOLDERID_UserPinned = NewGUID("{9E3995AB-1F9C-4F13-B827-48B24B6C7174}")
|
||||
FOLDERID_UserProfiles = NewGUID("{0762D272-C50A-4BB0-A382-697DCD729B80}")
|
||||
FOLDERID_UserProgramFiles = NewGUID("{5CD7AEE2-2219-4A67-B85D-6C9CE15660CB}")
|
||||
FOLDERID_UserProgramFilesCommon = NewGUID("{BCBD3057-CA5C-4622-B42D-BC56DB0AE516}")
|
||||
FOLDERID_UsersFiles = NewGUID("{F3CE0F7C-4901-4ACC-8648-D5D44B04EF8F}")
|
||||
FOLDERID_UsersLibraries = NewGUID("{A302545D-DEFF-464b-ABE8-61C8648D939B}")
|
||||
FOLDERID_Videos = NewGUID("{18989B1D-99B5-455B-841C-AB7C74E4DDFC}")
|
||||
FOLDERID_VideosLibrary = NewGUID("{491E922F-5643-4AF4-A7EB-4E7A138D8174}")
|
||||
FOLDERID_Windows = NewGUID("{F38BF404-1D43-42F2-9305-67DE0B28FC23}")
|
||||
)
|
||||
|
||||
var (
|
||||
modshell32 = syscall.NewLazyDLL("shell32.dll")
|
||||
|
||||
@ -95,6 +214,7 @@ var (
|
||||
procExtractIcon = modshell32.NewProc("ExtractIconW")
|
||||
procGetSpecialFolderPath = modshell32.NewProc("SHGetSpecialFolderPathW")
|
||||
procShellNotifyIcon = modshell32.NewProc("Shell_NotifyIconW")
|
||||
procSHGetKnownFolderPath = modshell32.NewProc("SHGetKnownFolderPath")
|
||||
)
|
||||
|
||||
func ShellNotifyIcon(cmd uintptr, nid *NOTIFYICONDATA) bool {
|
||||
@ -108,6 +228,15 @@ func SHBrowseForFolder(bi *BROWSEINFO) uintptr {
|
||||
return ret
|
||||
}
|
||||
|
||||
func SHGetKnownFolderPath(rfid *GUID, dwFlags uint32, hToken HANDLE) (string, error) {
|
||||
var path *uint16
|
||||
ret, _, _ := procSHGetKnownFolderPath.Call(uintptr(unsafe.Pointer(rfid)), uintptr(dwFlags), hToken, uintptr(unsafe.Pointer(path)))
|
||||
if ret != uintptr(windows.S_OK) {
|
||||
return "", fmt.Errorf("SHGetKnownFolderPath failed: %v", ret)
|
||||
}
|
||||
return windows.UTF16PtrToString(path), nil
|
||||
}
|
||||
|
||||
func SHGetPathFromIDList(idl uintptr) string {
|
||||
buf := make([]uint16, 1024)
|
||||
procSHGetPathFromIDList.Call(
|
||||
|
@ -337,14 +337,6 @@ type BROWSEINFO struct {
|
||||
Image int32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373931.aspx
|
||||
type GUID struct {
|
||||
Data1 uint32
|
||||
Data2 uint16
|
||||
Data3 uint16
|
||||
Data4 [8]byte
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221627.aspx
|
||||
type VARIANT struct {
|
||||
VT uint16 // 2
|
||||
|
@ -24,7 +24,7 @@ You can then call the methods from the frontend:
|
||||
To use this from Go, create a new instance of the plugin, then call the methods on that:
|
||||
|
||||
```go
|
||||
start_at_login := start_at_login.NewPlugin()
|
||||
start_at_login := start_at_login.NewPlugin(Options)
|
||||
start_at_login.StartAtLogin(true)
|
||||
```
|
||||
|
||||
|
@ -7,10 +7,19 @@ import (
|
||||
type Plugin struct {
|
||||
app *application.App
|
||||
disabled bool
|
||||
options Config
|
||||
}
|
||||
|
||||
func NewPlugin() *Plugin {
|
||||
return &Plugin{}
|
||||
type Config struct {
|
||||
// RegistryKey is the key in the registry to use for storing the start at login setting.
|
||||
// This defaults to the name of the executable
|
||||
RegistryKey string
|
||||
}
|
||||
|
||||
func NewPlugin(options Config) *Plugin {
|
||||
return &Plugin{
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
// Shutdown is called when the app is shutting down
|
||||
|
@ -6,3 +6,11 @@ func (p *Plugin) init() error {
|
||||
// TBD
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Plugin) StartAtLogin(enabled bool) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (p *Plugin) IsStartAtLogin() (bool, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
@ -2,7 +2,87 @@
|
||||
|
||||
package start_at_login
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/sys/windows/registry"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (p *Plugin) init() error {
|
||||
// TBD
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Plugin) getRegistryKey() (string, string, error) {
|
||||
exePath, err := os.Executable()
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to get executable path: %s", err)
|
||||
}
|
||||
|
||||
registryKey := p.options.RegistryKey
|
||||
if p.options.RegistryKey == "" {
|
||||
registryKey = strings.Split(filepath.Base(exePath), ".")[0]
|
||||
}
|
||||
|
||||
return registryKey, exePath, nil
|
||||
}
|
||||
|
||||
func openRegKey() (registry.Key, error) {
|
||||
// Open the registry key
|
||||
return registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Run`, registry.ALL_ACCESS)
|
||||
}
|
||||
|
||||
func (p *Plugin) IsStartAtLogin() (bool, error) {
|
||||
registryKey, exePath, err := p.getRegistryKey()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
key, err := openRegKey()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer key.Close()
|
||||
|
||||
// Get the registry value
|
||||
value, _, err := key.GetStringValue(registryKey)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
return value == exePath, nil
|
||||
}
|
||||
|
||||
func (p *Plugin) StartAtLogin(enabled bool) error {
|
||||
registryKey, exePath, err := p.getRegistryKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if enabled {
|
||||
// Open the registry key
|
||||
key, err := openRegKey()
|
||||
defer key.Close()
|
||||
|
||||
// Set the registry value
|
||||
err = key.SetStringValue(registryKey, exePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set registry value: %s", err)
|
||||
}
|
||||
} else {
|
||||
// Remove registry key
|
||||
key, err := openRegKey()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open registry key: %s", err)
|
||||
}
|
||||
defer key.Close()
|
||||
|
||||
// Remove the registry value
|
||||
err = key.DeleteValue(registryKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete registry value: %s", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user