mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-04 12:51:38 +08:00

* Add service registration method * Fix error handling and formatting in messageprocessor * Add configurable error handling * Improve error strings * Fix service shutdown on macOS * Add post shutdown hook * Better fatal errors * Add startup/shutdown sequence tests * Improve debug messages * Update JS runtime * Update docs * Update changelog * Fix log message in clipboard message processor Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Remove panic in RegisterService * Fix linux tests (hopefully) * Fix error formatting everywhere * Fix typo in windows webview * Tidy example mods * Set application name in tests * Fix ubuntu test workflow * Cleanup template test pipeline * Fix dev build detection on Go 1.24 * Update template go.mod/sum to Go 1.24 * Remove redundant caching in template tests * Final format string cleanup * Fix wails3 tool references * Fix legacy log calls * Remove formatJS and simplify format strings * Fix indirect import --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
130 lines
2.6 KiB
Go
130 lines
2.6 KiB
Go
//go:build windows
|
|
|
|
package application
|
|
|
|
import (
|
|
"errors"
|
|
"syscall"
|
|
"unsafe"
|
|
|
|
"github.com/wailsapp/wails/v3/pkg/w32"
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
var (
|
|
user32 = syscall.NewLazyDLL("user32.dll")
|
|
)
|
|
|
|
type windowsLock struct {
|
|
handle syscall.Handle
|
|
uniqueID string
|
|
msgString string
|
|
hwnd w32.HWND
|
|
manager *singleInstanceManager
|
|
className string
|
|
windowName string
|
|
}
|
|
|
|
func newPlatformLock(manager *singleInstanceManager) (platformLock, error) {
|
|
return &windowsLock{
|
|
manager: manager,
|
|
}, nil
|
|
}
|
|
|
|
func (l *windowsLock) acquire(uniqueID string) error {
|
|
if uniqueID == "" {
|
|
return errors.New("UniqueID is required for single instance lock")
|
|
}
|
|
|
|
l.uniqueID = uniqueID
|
|
id := "wails-app-" + uniqueID
|
|
l.className = id + "-sic"
|
|
l.windowName = id + "-siw"
|
|
mutexName := id + "-sim"
|
|
|
|
_, err := windows.CreateMutex(nil, false, windows.StringToUTF16Ptr(mutexName))
|
|
if err != nil {
|
|
// Find the window
|
|
return alreadyRunningError
|
|
} else {
|
|
l.hwnd = createEventTargetWindow(l.className, l.windowName)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (l *windowsLock) release() {
|
|
if l.handle != 0 {
|
|
syscall.CloseHandle(l.handle)
|
|
l.handle = 0
|
|
}
|
|
if l.hwnd != 0 {
|
|
w32.DestroyWindow(l.hwnd)
|
|
l.hwnd = 0
|
|
}
|
|
}
|
|
|
|
func (l *windowsLock) notify(data string) error {
|
|
|
|
// app is already running
|
|
hwnd := w32.FindWindowW(windows.StringToUTF16Ptr(l.className), windows.StringToUTF16Ptr(l.windowName))
|
|
|
|
if hwnd == 0 {
|
|
return errors.New("unable to notify other instance")
|
|
}
|
|
|
|
w32.SendMessageToWindow(hwnd, data)
|
|
|
|
return nil
|
|
}
|
|
|
|
func createEventTargetWindow(className string, windowName string) w32.HWND {
|
|
var class w32.WNDCLASSEX
|
|
class.Size = uint32(unsafe.Sizeof(class))
|
|
class.Style = 0
|
|
class.WndProc = syscall.NewCallback(wndProc)
|
|
class.ClsExtra = 0
|
|
class.WndExtra = 0
|
|
class.Instance = w32.GetModuleHandle("")
|
|
class.Icon = 0
|
|
class.Cursor = 0
|
|
class.Background = 0
|
|
class.MenuName = nil
|
|
class.ClassName = w32.MustStringToUTF16Ptr(className)
|
|
class.IconSm = 0
|
|
|
|
w32.RegisterClassEx(&class)
|
|
|
|
// Create hidden message-only window
|
|
hwnd := w32.CreateWindowEx(
|
|
0,
|
|
w32.MustStringToUTF16Ptr(className),
|
|
w32.MustStringToUTF16Ptr(windowName),
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
w32.HWND_MESSAGE,
|
|
0,
|
|
w32.GetModuleHandle(""),
|
|
nil,
|
|
)
|
|
|
|
return hwnd
|
|
}
|
|
|
|
func wndProc(hwnd w32.HWND, msg uint32, wparam w32.WPARAM, lparam w32.LPARAM) w32.LRESULT {
|
|
if msg == w32.WM_COPYDATA {
|
|
ldata := (*w32.COPYDATASTRUCT)(unsafe.Pointer(lparam))
|
|
|
|
if ldata.DwData == w32.WMCOPYDATA_SINGLE_INSTANCE_DATA {
|
|
serialized := windows.UTF16PtrToString((*uint16)(unsafe.Pointer(ldata.LpData)))
|
|
secondInstanceBuffer <- serialized
|
|
}
|
|
return w32.LRESULT(0)
|
|
}
|
|
|
|
return w32.DefWindowProc(hwnd, msg, wparam, lparam)
|
|
}
|