From ff4e749ce6460f1093f17f66e1521e16c31b98c9 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 22 Feb 2026 05:22:19 +0000
Subject: [PATCH] Initial plan: Fix Windows-specific bugs from discussion #5001
Co-authored-by: leaanthony <1943904+leaanthony@users.noreply.github.com>
---
v3/pkg/application/event_manager.go | 174 +
v3/pkg/application/webview_window_windows.go | 2479 ++++++++++++
v3/pkg/w32/actions.go | 27 +
v3/pkg/w32/clipboard.go | 143 +
v3/pkg/w32/com.go | 55 +
v3/pkg/w32/comctl32.go | 112 +
v3/pkg/w32/comdlg32.go | 40 +
v3/pkg/w32/constants.go | 3731 ++++++++++++++++++
v3/pkg/w32/consts.go | 102 +
v3/pkg/w32/dialogs.go | 28 +
v3/pkg/w32/dwmapi.go | 46 +
v3/pkg/w32/gdi32.go | 581 +++
v3/pkg/w32/gdiplus.go | 177 +
v3/pkg/w32/guid.go | 225 ++
v3/pkg/w32/icon.go | 255 ++
v3/pkg/w32/idataobject.go | 168 +
v3/pkg/w32/idispatch.go | 45 +
v3/pkg/w32/idroptarget.go | 140 +
v3/pkg/w32/image.go | 55 +
v3/pkg/w32/istream.go | 33 +
v3/pkg/w32/kernel32.go | 337 ++
v3/pkg/w32/menubar.go | 980 +++++
v3/pkg/w32/ole32.go | 119 +
v3/pkg/w32/oleaut32.go | 50 +
v3/pkg/w32/popupmenu.go | 96 +
v3/pkg/w32/screen.go | 143 +
v3/pkg/w32/shcore.go | 71 +
v3/pkg/w32/shell32.go | 414 ++
v3/pkg/w32/shlwapi.go | 26 +
v3/pkg/w32/taskbar.go | 95 +
v3/pkg/w32/theme.go | 345 ++
v3/pkg/w32/timer.go | 19 +
v3/pkg/w32/toolbar.go | 216 +
v3/pkg/w32/typedef.go | 1110 ++++++
v3/pkg/w32/user32.go | 1510 +++++++
v3/pkg/w32/utils.go | 637 +++
v3/pkg/w32/vars.go | 16 +
v3/pkg/w32/wda.go | 21 +
v3/pkg/w32/window.go | 377 ++
39 files changed, 15198 insertions(+)
create mode 100644 v3/pkg/application/event_manager.go
create mode 100644 v3/pkg/application/webview_window_windows.go
create mode 100644 v3/pkg/w32/actions.go
create mode 100644 v3/pkg/w32/clipboard.go
create mode 100644 v3/pkg/w32/com.go
create mode 100644 v3/pkg/w32/comctl32.go
create mode 100644 v3/pkg/w32/comdlg32.go
create mode 100644 v3/pkg/w32/constants.go
create mode 100644 v3/pkg/w32/consts.go
create mode 100644 v3/pkg/w32/dialogs.go
create mode 100644 v3/pkg/w32/dwmapi.go
create mode 100644 v3/pkg/w32/gdi32.go
create mode 100644 v3/pkg/w32/gdiplus.go
create mode 100644 v3/pkg/w32/guid.go
create mode 100644 v3/pkg/w32/icon.go
create mode 100644 v3/pkg/w32/idataobject.go
create mode 100644 v3/pkg/w32/idispatch.go
create mode 100644 v3/pkg/w32/idroptarget.go
create mode 100644 v3/pkg/w32/image.go
create mode 100644 v3/pkg/w32/istream.go
create mode 100644 v3/pkg/w32/kernel32.go
create mode 100644 v3/pkg/w32/menubar.go
create mode 100644 v3/pkg/w32/ole32.go
create mode 100644 v3/pkg/w32/oleaut32.go
create mode 100644 v3/pkg/w32/popupmenu.go
create mode 100644 v3/pkg/w32/screen.go
create mode 100644 v3/pkg/w32/shcore.go
create mode 100644 v3/pkg/w32/shell32.go
create mode 100644 v3/pkg/w32/shlwapi.go
create mode 100644 v3/pkg/w32/taskbar.go
create mode 100644 v3/pkg/w32/theme.go
create mode 100644 v3/pkg/w32/timer.go
create mode 100644 v3/pkg/w32/toolbar.go
create mode 100644 v3/pkg/w32/typedef.go
create mode 100644 v3/pkg/w32/user32.go
create mode 100644 v3/pkg/w32/utils.go
create mode 100644 v3/pkg/w32/vars.go
create mode 100644 v3/pkg/w32/wda.go
create mode 100644 v3/pkg/w32/window.go
diff --git a/v3/pkg/application/event_manager.go b/v3/pkg/application/event_manager.go
new file mode 100644
index 000000000..7555ff685
--- /dev/null
+++ b/v3/pkg/application/event_manager.go
@@ -0,0 +1,174 @@
+package application
+
+import (
+ "slices"
+
+ "github.com/wailsapp/wails/v3/pkg/events"
+)
+
+// EventManager manages event-related operations
+type EventManager struct {
+ app *App
+}
+
+// newEventManager creates a new EventManager instance
+func newEventManager(app *App) *EventManager {
+ return &EventManager{
+ app: app,
+ }
+}
+
+// Emit emits a custom event with the specified name and associated data.
+// It returns a boolean indicating whether the event was cancelled by a hook.
+//
+// If no data argument is provided, Emit emits an event with nil data.
+// When there is exactly one data argument, it will be used as the custom event's data field.
+// When more than one argument is provided, the event's data field will be set to the argument slice.
+//
+// If the given event name is registered, Emit validates the data parameter
+// against the expected data type. In case of a mismatch, Emit reports an error
+// to the registered error handler for the application and cancels the event.
+func (em *EventManager) Emit(name string, data ...any) bool {
+ event := &CustomEvent{Name: name}
+
+ if len(data) == 1 {
+ event.Data = data[0]
+ } else if len(data) > 1 {
+ event.Data = data
+ }
+
+ if err := em.app.customEventProcessor.Emit(event); err != nil {
+ globalApplication.handleError(err)
+ }
+
+ return event.IsCancelled()
+}
+
+// EmitEvent emits a custom event object (internal use)
+// It returns a boolean indicating whether the event was cancelled by a hook.
+//
+// If the given event name is registered, emitEvent validates the data parameter
+// against the expected data type. In case of a mismatch, emitEvent reports an error
+// to the registered error handler for the application and cancels the event.
+func (em *EventManager) EmitEvent(event *CustomEvent) bool {
+ if err := em.app.customEventProcessor.Emit(event); err != nil {
+ globalApplication.handleError(err)
+ }
+
+ return event.IsCancelled()
+}
+
+// On registers a listener for custom events
+func (em *EventManager) On(name string, callback func(event *CustomEvent)) func() {
+ return em.app.customEventProcessor.On(name, callback)
+}
+
+// Off removes all listeners for a custom event
+func (em *EventManager) Off(name string) {
+ em.app.customEventProcessor.Off(name)
+}
+
+// OnMultiple registers a listener for custom events that will be called N times
+func (em *EventManager) OnMultiple(name string, callback func(event *CustomEvent), counter int) {
+ em.app.customEventProcessor.OnMultiple(name, callback, counter)
+}
+
+// Reset removes all custom event listeners
+func (em *EventManager) Reset() {
+ em.app.customEventProcessor.OffAll()
+}
+
+// OnApplicationEvent registers a listener for application events
+func (em *EventManager) OnApplicationEvent(eventType events.ApplicationEventType, callback func(event *ApplicationEvent)) func() {
+ eventID := uint(eventType)
+ em.app.applicationEventListenersLock.Lock()
+ defer em.app.applicationEventListenersLock.Unlock()
+ listener := &EventListener{
+ callback: callback,
+ }
+ em.app.applicationEventListeners[eventID] = append(em.app.applicationEventListeners[eventID], listener)
+ if em.app.impl != nil {
+ go func() {
+ defer handlePanic()
+ em.app.impl.on(eventID)
+ }()
+ }
+
+ return func() {
+ // lock the map
+ em.app.applicationEventListenersLock.Lock()
+ defer em.app.applicationEventListenersLock.Unlock()
+ // Remove listener
+ em.app.applicationEventListeners[eventID] = slices.DeleteFunc(em.app.applicationEventListeners[eventID], func(l *EventListener) bool {
+ return l == listener
+ })
+ }
+}
+
+// RegisterApplicationEventHook registers an application event hook
+func (em *EventManager) RegisterApplicationEventHook(eventType events.ApplicationEventType, callback func(event *ApplicationEvent)) func() {
+ eventID := uint(eventType)
+ em.app.applicationEventHooksLock.Lock()
+ defer em.app.applicationEventHooksLock.Unlock()
+ thisHook := &eventHook{
+ callback: callback,
+ }
+ em.app.applicationEventHooks[eventID] = append(em.app.applicationEventHooks[eventID], thisHook)
+
+ return func() {
+ em.app.applicationEventHooksLock.Lock()
+ em.app.applicationEventHooks[eventID] = slices.DeleteFunc(em.app.applicationEventHooks[eventID], func(h *eventHook) bool {
+ return h == thisHook
+ })
+ em.app.applicationEventHooksLock.Unlock()
+ }
+}
+
+// Dispatch dispatches an event to listeners (internal use)
+func (em *EventManager) dispatch(event *CustomEvent) {
+ // Snapshot listeners under Lock
+ em.app.wailsEventListenerLock.Lock()
+ listeners := slices.Clone(em.app.wailsEventListeners)
+ em.app.wailsEventListenerLock.Unlock()
+
+ for _, listener := range listeners {
+ if event.IsCancelled() {
+ return
+ }
+ listener.DispatchWailsEvent(event)
+ }
+}
+
+// HandleApplicationEvent handles application events (internal use)
+func (em *EventManager) handleApplicationEvent(event *ApplicationEvent) {
+ defer handlePanic()
+ em.app.applicationEventListenersLock.RLock()
+ listeners, ok := em.app.applicationEventListeners[event.Id]
+ em.app.applicationEventListenersLock.RUnlock()
+ if !ok {
+ return
+ }
+
+ // Process Hooks
+ em.app.applicationEventHooksLock.RLock()
+ hooks, ok := em.app.applicationEventHooks[event.Id]
+ em.app.applicationEventHooksLock.RUnlock()
+ if ok {
+ for _, thisHook := range hooks {
+ thisHook.callback(event)
+ if event.IsCancelled() {
+ return
+ }
+ }
+ }
+
+ for _, listener := range listeners {
+ go func() {
+ if event.IsCancelled() {
+ return
+ }
+ defer handlePanic()
+ listener.callback(event)
+ }()
+ }
+}
diff --git a/v3/pkg/application/webview_window_windows.go b/v3/pkg/application/webview_window_windows.go
new file mode 100644
index 000000000..16ba08f0b
--- /dev/null
+++ b/v3/pkg/application/webview_window_windows.go
@@ -0,0 +1,2479 @@
+//go:build windows
+
+package application
+
+import (
+ "errors"
+ "fmt"
+ "net/url"
+ "strconv"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "time"
+ "unsafe"
+
+ "github.com/bep/debounce"
+ "github.com/wailsapp/go-webview2/webviewloader"
+ "github.com/wailsapp/wails/v3/internal/assetserver"
+ "github.com/wailsapp/wails/v3/internal/assetserver/webview"
+ "github.com/wailsapp/wails/v3/internal/capabilities"
+ "github.com/wailsapp/wails/v3/internal/runtime"
+ "github.com/wailsapp/wails/v3/internal/sliceutil"
+
+ "github.com/wailsapp/go-webview2/pkg/edge"
+ "github.com/wailsapp/wails/v3/pkg/events"
+ "github.com/wailsapp/wails/v3/pkg/w32"
+)
+
+var edgeMap = map[string]uintptr{
+ "n-resize": w32.HTTOP,
+ "ne-resize": w32.HTTOPRIGHT,
+ "e-resize": w32.HTRIGHT,
+ "se-resize": w32.HTBOTTOMRIGHT,
+ "s-resize": w32.HTBOTTOM,
+ "sw-resize": w32.HTBOTTOMLEFT,
+ "w-resize": w32.HTLEFT,
+ "nw-resize": w32.HTTOPLEFT,
+}
+
+type windowsWebviewWindow struct {
+ windowImpl unsafe.Pointer
+ parent *WebviewWindow
+ hwnd w32.HWND
+ menu *Win32Menu
+ currentlyOpenContextMenu *Win32Menu
+ ignoreDPIChangeResizing bool
+
+ // Fullscreen flags
+ isCurrentlyFullscreen bool
+ previousWindowStyle uint32
+ previousWindowExStyle uint32
+ previousWindowPlacement w32.WINDOWPLACEMENT
+
+ // Webview
+ chromium *edge.Chromium
+ webviewNavigationCompleted bool
+
+ // Window visibility management - robust fallback for issue #2861
+ showRequested bool // Track if show() was called before navigation completed
+ visibilityTimeout *time.Timer // Timeout to show window if navigation is delayed
+ windowShown bool // Track if window container has been shown
+ // Track whether content protection has been applied to the native window yet
+ contentProtectionApplied bool
+
+ // resizeBorder* is the width/height of the resize border in pixels.
+ resizeBorderWidth int32
+ resizeBorderHeight int32
+ focusingChromium bool
+ onceDo sync.Once
+
+ // Window move debouncer
+ moveDebouncer func(func())
+ resizeDebouncer func(func())
+
+ // isMinimizing indicates whether the window is currently being minimized
+ // Used to prevent unnecessary redraws during minimize/restore operations
+ isMinimizing bool
+
+ // menubarTheme is the theme for the menubar
+ menubarTheme *w32.MenuBarTheme
+}
+
+func (w *windowsWebviewWindow) setMenu(menu *Menu) {
+ menu.Update()
+ w.menu = NewApplicationMenu(w, menu)
+ w.menu.parentWindow = w
+ w32.SetMenu(w.hwnd, w.menu.menu)
+
+ // Set menu background if theme is active
+ if w.menubarTheme != nil {
+ globalApplication.debug("Applying menubar theme in setMenu", "window", w.parent.id)
+ w.menubarTheme.SetMenuBackground(w.menu.menu)
+ w32.DrawMenuBar(w.hwnd)
+ // Force a repaint of the menu area
+ w32.InvalidateRect(w.hwnd, nil, true)
+ } else {
+ globalApplication.debug("No menubar theme to apply in setMenu", "window", w.parent.id)
+ }
+
+ // Check if using translucent background with Mica - this makes menubars invisible
+ if w.parent.options.BackgroundType == BackgroundTypeTranslucent &&
+ (w.parent.options.Windows.BackdropType == Mica ||
+ w.parent.options.Windows.BackdropType == Acrylic ||
+ w.parent.options.Windows.BackdropType == Tabbed) {
+ // Log warning about menubar visibility issue
+ globalApplication.debug("Warning: Menubars may be invisible when using translucent backgrounds with Mica/Acrylic/Tabbed effects", "window", w.parent.id)
+ }
+}
+
+func (w *windowsWebviewWindow) cut() {
+ w.execJS("document.execCommand('cut')")
+}
+
+func (w *windowsWebviewWindow) paste() {
+ w.execJS(`
+ (async () => {
+ try {
+ // Try to read all available formats
+ const clipboardItems = await navigator.clipboard.read();
+
+ for (const clipboardItem of clipboardItems) {
+ // Check for image types
+ for (const type of clipboardItem.types) {
+ if (type.startsWith('image/')) {
+ const blob = await clipboardItem.getType(type);
+ const url = URL.createObjectURL(blob);
+ document.execCommand('insertHTML', false, '
');
+ return;
+ }
+ }
+
+ // If no image found, try text
+ if (clipboardItem.types.includes('text/plain')) {
+ const text = await navigator.clipboard.readText();
+ document.execCommand('insertText', false, text);
+ return;
+ }
+ }
+ } catch(err) {
+ // Fallback to text-only paste if clipboard access fails
+ try {
+ const text = await navigator.clipboard.readText();
+ document.execCommand('insertText', false, text);
+ } catch(fallbackErr) {
+ console.error('Failed to paste:', err, fallbackErr);
+ }
+ }
+ })()
+ `)
+}
+
+func (w *windowsWebviewWindow) copy() {
+ w.execJS(`
+ (async () => {
+ try {
+ const selection = window.getSelection();
+ if (!selection.rangeCount) return;
+
+ const range = selection.getRangeAt(0);
+ const container = document.createElement('div');
+ container.appendChild(range.cloneContents());
+
+ // Check if we have any images in the selection
+ const images = container.getElementsByTagName('img');
+ if (images.length > 0) {
+ // Handle image copy
+ const img = images[0]; // Take the first image
+ const response = await fetch(img.src);
+ const blob = await response.blob();
+ await navigator.clipboard.write([
+ new ClipboardItem({
+ [blob.type]: blob
+ })
+ ]);
+ } else {
+ // Handle text copy
+ const text = selection.toString();
+ if (text) {
+ await navigator.clipboard.writeText(text);
+ }
+ }
+ } catch(err) {
+ console.error('Failed to copy:', err);
+ }
+ })()
+ `)
+}
+
+func (w *windowsWebviewWindow) selectAll() {
+ w.execJS("document.execCommand('selectAll')")
+}
+
+func (w *windowsWebviewWindow) undo() {
+ w.execJS("document.execCommand('undo')")
+}
+
+func (w *windowsWebviewWindow) redo() {
+ w.execJS("document.execCommand('redo')")
+}
+
+func (w *windowsWebviewWindow) delete() {
+ w.execJS("document.execCommand('delete')")
+}
+
+func (w *windowsWebviewWindow) handleKeyEvent(_ string) {
+ // Unused on windows
+}
+
+func (w *windowsWebviewWindow) setEnabled(enabled bool) {
+ w32.EnableWindow(w.hwnd, enabled)
+}
+
+func (w *windowsWebviewWindow) print() error {
+ w.execJS("window.print();")
+ return nil
+}
+
+func (w *windowsWebviewWindow) startResize(border string) error {
+ if !w32.ReleaseCapture() {
+ return errors.New("unable to release mouse capture")
+ }
+ // Use PostMessage because we don't want to block the caller until resizing has been finished.
+ w32.PostMessage(w.hwnd, w32.WM_NCLBUTTONDOWN, edgeMap[border], 0)
+ return nil
+}
+
+func (w *windowsWebviewWindow) startDrag() error {
+ if !w32.ReleaseCapture() {
+ return errors.New("unable to release mouse capture")
+ }
+ // Use PostMessage because we don't want to block the caller until dragging has been finished.
+ w32.PostMessage(w.hwnd, w32.WM_NCLBUTTONDOWN, w32.HTCAPTION, 0)
+ return nil
+}
+
+func (w *windowsWebviewWindow) nativeWindow() unsafe.Pointer {
+ return unsafe.Pointer(w.hwnd)
+}
+
+func (w *windowsWebviewWindow) setTitle(title string) {
+ w32.SetWindowText(w.hwnd, title)
+}
+
+func (w *windowsWebviewWindow) setAlwaysOnTop(alwaysOnTop bool) {
+ var hwndInsertAfter uintptr
+ if alwaysOnTop {
+ hwndInsertAfter = w32.HWND_TOPMOST
+ } else {
+ hwndInsertAfter = w32.HWND_NOTOPMOST
+ }
+ w32.SetWindowPos(w.hwnd,
+ hwndInsertAfter,
+ 0,
+ 0,
+ 0,
+ 0,
+ uint(w32.SWP_NOMOVE|w32.SWP_NOSIZE))
+}
+
+func (w *windowsWebviewWindow) setURL(url string) {
+ // Navigate to the given URL in the webview
+ w.webviewNavigationCompleted = false
+ w.chromium.Navigate(url)
+}
+
+func (w *windowsWebviewWindow) setResizable(resizable bool) {
+ w.setStyle(resizable, w32.WS_THICKFRAME)
+ w.execJS(fmt.Sprintf("window._wails.setResizable(%v);", resizable))
+}
+
+func (w *windowsWebviewWindow) setMinSize(width, height int) {
+ w.parent.options.MinWidth = width
+ w.parent.options.MinHeight = height
+}
+
+func (w *windowsWebviewWindow) setMaxSize(width, height int) {
+ w.parent.options.MaxWidth = width
+ w.parent.options.MaxHeight = height
+}
+
+func (w *windowsWebviewWindow) execJS(js string) {
+ if w.chromium == nil {
+ return
+ }
+ globalApplication.dispatchOnMainThread(func() {
+ w.chromium.Eval(js)
+ })
+}
+
+func (w *windowsWebviewWindow) setBackgroundColour(color RGBA) {
+ switch w.parent.options.BackgroundType {
+ case BackgroundTypeSolid:
+ w32.SetBackgroundColour(w.hwnd, color.Red, color.Green, color.Blue)
+ w.chromium.SetBackgroundColour(color.Red, color.Green, color.Blue, color.Alpha)
+ case BackgroundTypeTransparent, BackgroundTypeTranslucent:
+ w.chromium.SetBackgroundColour(0, 0, 0, 0)
+ }
+}
+
+func (w *windowsWebviewWindow) framelessWithDecorations() bool {
+ return w.parent.options.Frameless && !w.parent.options.Windows.DisableFramelessWindowDecorations
+}
+
+func (w *windowsWebviewWindow) run() {
+
+ options := w.parent.options
+
+ // Initialize showRequested based on whether window should be hidden
+ // Non-hidden windows should be shown by default
+ w.showRequested = !options.Hidden
+
+ w.chromium = edge.NewChromium()
+ if globalApplication.options.ErrorHandler != nil {
+ w.chromium.SetErrorCallback(globalApplication.options.ErrorHandler)
+ }
+
+ exStyle := w32.WS_EX_CONTROLPARENT
+ if options.BackgroundType != BackgroundTypeSolid {
+ if (options.Frameless && options.BackgroundType == BackgroundTypeTransparent) ||
+ w.parent.options.IgnoreMouseEvents {
+ // Always if transparent and frameless
+ exStyle |= w32.WS_EX_TRANSPARENT | w32.WS_EX_LAYERED
+ } else {
+ // Only WS_EX_NOREDIRECTIONBITMAP if not (and not solid)
+ exStyle |= w32.WS_EX_NOREDIRECTIONBITMAP
+ }
+ }
+ if options.AlwaysOnTop {
+ exStyle |= w32.WS_EX_TOPMOST
+ }
+ // If we're frameless, we need to add the WS_EX_TOOLWINDOW style to hide the window from the taskbar
+ if options.Windows.HiddenOnTaskbar {
+ //exStyle |= w32.WS_EX_TOOLWINDOW
+ exStyle |= w32.WS_EX_NOACTIVATE
+ } else {
+ exStyle |= w32.WS_EX_APPWINDOW
+ }
+
+ if options.Windows.ExStyle != 0 {
+ exStyle = options.Windows.ExStyle
+ }
+
+ bounds := Rect{
+ X: options.X,
+ Y: options.Y,
+ Width: options.Width,
+ Height: options.Height,
+ }
+ initialScreen := ScreenNearestDipRect(bounds)
+ physicalBounds := initialScreen.dipToPhysicalRect(bounds)
+
+ // Default window position applied by the system
+ // TODO: provide a way to set (0,0) as an initial position?
+ if options.X == 0 && options.Y == 0 {
+ physicalBounds.X = w32.CW_USEDEFAULT
+ physicalBounds.Y = w32.CW_USEDEFAULT
+ }
+
+ var appMenu w32.HMENU
+
+ // Process Menu
+ if !options.Frameless {
+ userMenu := w.parent.options.Windows.Menu
+ if userMenu != nil {
+ // Explicit window menu takes priority
+ userMenu.Update()
+ w.menu = NewApplicationMenu(w, userMenu)
+ w.menu.parentWindow = w
+ appMenu = w.menu.menu
+ } else if options.UseApplicationMenu && globalApplication.applicationMenu != nil {
+ // Use the global application menu if opted in
+ globalApplication.applicationMenu.Update()
+ w.menu = NewApplicationMenu(w, globalApplication.applicationMenu)
+ w.menu.parentWindow = w
+ appMenu = w.menu.menu
+ }
+ }
+
+ var parent w32.HWND
+
+ var style uint = w32.WS_OVERLAPPEDWINDOW
+ // If the window should be hidden initially, exclude WS_VISIBLE from the style
+ // This prevents the white window flash reported in issue #4611
+ if options.Hidden {
+ style = style &^ uint(w32.WS_VISIBLE)
+ }
+
+ w.hwnd = w32.CreateWindowEx(
+ uint(exStyle),
+ w32.MustStringToUTF16Ptr(globalApplication.options.Windows.WndClass),
+ w32.MustStringToUTF16Ptr(options.Title),
+ style,
+ physicalBounds.X,
+ physicalBounds.Y,
+ physicalBounds.Width,
+ physicalBounds.Height,
+ parent,
+ appMenu,
+ w32.GetModuleHandle(""),
+ nil)
+
+ if w.hwnd == 0 {
+ globalApplication.fatal("unable to create window")
+ }
+
+ // Ensure correct window size in case the scale factor of current screen is different from the initial one.
+ // This could happen when using the default window position and the window launches on a secondary monitor.
+ currentScreen, _ := w.getScreen()
+ if currentScreen.ScaleFactor != initialScreen.ScaleFactor {
+ w.setSize(options.Width, options.Height)
+ }
+
+ w.setupChromium()
+
+ if options.Windows.WindowDidMoveDebounceMS == 0 {
+ options.Windows.WindowDidMoveDebounceMS = 50
+ }
+ w.moveDebouncer = debounce.New(
+ time.Duration(options.Windows.WindowDidMoveDebounceMS) * time.Millisecond,
+ )
+
+ if options.Windows.ResizeDebounceMS > 0 {
+ w.resizeDebouncer = debounce.New(
+ time.Duration(options.Windows.ResizeDebounceMS) * time.Millisecond,
+ )
+ }
+
+ // Initialise the window buttons
+ w.setMinimiseButtonState(options.MinimiseButtonState)
+ w.setMaximiseButtonState(options.MaximiseButtonState)
+ w.setCloseButtonState(options.CloseButtonState)
+
+ // Register the window with the application
+ getNativeApplication().registerWindow(w)
+
+ w.setResizable(!options.DisableResize)
+
+ w.setIgnoreMouseEvents(options.IgnoreMouseEvents)
+
+ if options.Frameless {
+ // Inform the application of the frame change this is needed to trigger the WM_NCCALCSIZE event.
+ // => https://learn.microsoft.com/en-us/windows/win32/dwm/customframe#removing-the-standard-frame
+ // This is normally done in WM_CREATE but we can't handle that there because that is emitted during CreateWindowEx
+ // and at that time we can't yet register the window for calling our WndProc method.
+ // This must be called after setResizable above!
+ rcClient := w32.GetWindowRect(w.hwnd)
+ w32.SetWindowPos(w.hwnd,
+ 0,
+ int(rcClient.Left),
+ int(rcClient.Top),
+ int(rcClient.Right-rcClient.Left),
+ int(rcClient.Bottom-rcClient.Top),
+ w32.SWP_FRAMECHANGED)
+ }
+
+ // Icon
+ if !options.Windows.DisableIcon {
+ // App icon ID is 3
+ icon, err := NewIconFromResource(w32.GetModuleHandle(""), uint16(3))
+ if err != nil {
+ // Try loading from the given icon
+ if globalApplication.options.Icon != nil {
+ icon, _ = w32.CreateLargeHIconFromImage(globalApplication.options.Icon)
+ }
+ }
+ if icon != 0 {
+ w.setIcon(icon)
+ }
+ } else {
+ w.disableIcon()
+ }
+
+ // Process the theme
+ switch options.Windows.Theme {
+ case SystemDefault:
+ isDark := w32.IsCurrentlyDarkMode()
+ if isDark {
+ w32.AllowDarkModeForWindow(w.hwnd, true)
+ }
+ w.updateTheme(isDark)
+ // Don't initialize default dark theme here if custom theme might be set
+ // The updateTheme call above will handle both default and custom themes
+ w.parent.onApplicationEvent(events.Windows.SystemThemeChanged, func(*ApplicationEvent) {
+ InvokeAsync(func() {
+ w.updateTheme(w32.IsCurrentlyDarkMode())
+ })
+ })
+ case Light:
+ w.updateTheme(false)
+ case Dark:
+ w32.AllowDarkModeForWindow(w.hwnd, true)
+ w.updateTheme(true)
+ // Don't initialize default dark theme here if custom theme might be set
+ // The updateTheme call above will handle custom themes
+ }
+
+ w.setBackgroundColour(options.BackgroundColour)
+ if options.BackgroundType == BackgroundTypeTranslucent {
+ w.setBackdropType(w.parent.options.Windows.BackdropType)
+ }
+
+ // Process StartState
+ switch options.StartState {
+ case WindowStateMaximised:
+ if w.parent.Resizable() {
+ w.maximise()
+ }
+ case WindowStateMinimised:
+ w.minimise()
+ case WindowStateFullscreen:
+ w.fullscreen()
+ case WindowStateNormal:
+ }
+
+ // Process window mask
+ if options.Windows.WindowMask != nil {
+ w.setWindowMask(options.Windows.WindowMask)
+ }
+
+ if options.InitialPosition == WindowCentered {
+ w.center()
+ } else {
+ w.setPosition(options.X, options.Y)
+ }
+
+ if options.Frameless {
+ // Trigger a resize to ensure the window is sized correctly
+ w.chromium.Resize()
+ }
+}
+
+func (w *windowsWebviewWindow) center() {
+ w32.CenterWindow(w.hwnd)
+}
+
+func (w *windowsWebviewWindow) disableSizeConstraints() {
+ w.setMaxSize(0, 0)
+ w.setMinSize(0, 0)
+}
+
+func (w *windowsWebviewWindow) enableSizeConstraints() {
+ options := w.parent.options
+ if options.MinWidth > 0 || options.MinHeight > 0 {
+ w.setMinSize(options.MinWidth, options.MinHeight)
+ }
+ if options.MaxWidth > 0 || options.MaxHeight > 0 {
+ w.setMaxSize(options.MaxWidth, options.MaxHeight)
+ }
+}
+
+func (w *windowsWebviewWindow) update() {
+ w32.UpdateWindow(w.hwnd)
+}
+
+// getBorderSizes returns the extended border size for the window
+func (w *windowsWebviewWindow) getBorderSizes() *LRTB {
+ var result LRTB
+ var frame w32.RECT
+ w32.DwmGetWindowAttribute(
+ w.hwnd,
+ w32.DWMWA_EXTENDED_FRAME_BOUNDS,
+ unsafe.Pointer(&frame),
+ unsafe.Sizeof(frame),
+ )
+ rect := w32.GetWindowRect(w.hwnd)
+ result.Left = int(frame.Left - rect.Left)
+ result.Top = int(frame.Top - rect.Top)
+ result.Right = int(rect.Right - frame.Right)
+ result.Bottom = int(rect.Bottom - frame.Bottom)
+ return &result
+}
+
+// convertWindowToWebviewCoordinates converts window-relative coordinates to webview-relative coordinates
+func (w *windowsWebviewWindow) convertWindowToWebviewCoordinates(windowX, windowY int) (int, int) {
+ // Get the client area of the window (this excludes borders, title bar, etc.)
+ clientRect := w32.GetClientRect(w.hwnd)
+ if clientRect == nil {
+ // Fallback: return coordinates as-is if we can't get client rect
+ globalApplication.debug("[DragDropDebug] convertWindowToWebviewCoordinates: Failed to get client rect, returning original coordinates", "windowX", windowX, "windowY", windowY)
+ return windowX, windowY
+ }
+
+ // Get the window rect to calculate the offset
+ windowRect := w32.GetWindowRect(w.hwnd)
+
+ globalApplication.debug("[DragDropDebug] convertWindowToWebviewCoordinates: Input window coordinates", "windowX", windowX, "windowY", windowY)
+ globalApplication.debug("[DragDropDebug] convertWindowToWebviewCoordinates: Window rect",
+ "left", windowRect.Left, "top", windowRect.Top, "right", windowRect.Right, "bottom", windowRect.Bottom,
+ "width", windowRect.Right-windowRect.Left, "height", windowRect.Bottom-windowRect.Top)
+ globalApplication.debug("[DragDropDebug] convertWindowToWebviewCoordinates: Client rect",
+ "left", clientRect.Left, "top", clientRect.Top, "right", clientRect.Right, "bottom", clientRect.Bottom,
+ "width", clientRect.Right-clientRect.Left, "height", clientRect.Bottom-clientRect.Top)
+
+ // Convert client (0,0) to screen coordinates to find where the client area starts
+ var point w32.POINT
+ point.X = 0
+ point.Y = 0
+
+ // Convert client (0,0) to screen coordinates
+ clientX, clientY := w32.ClientToScreen(w.hwnd, int(point.X), int(point.Y))
+
+ // The window coordinates from drag drop are relative to the window's top-left
+ // But we need them relative to the client area's top-left
+ // So we need to subtract the difference between window origin and client origin
+ windowOriginX := int(windowRect.Left)
+ windowOriginY := int(windowRect.Top)
+
+ globalApplication.debug("[DragDropDebug] convertWindowToWebviewCoordinates: Client (0,0) in screen coordinates", "clientX", clientX, "clientY", clientY)
+ globalApplication.debug("[DragDropDebug] convertWindowToWebviewCoordinates: Window origin in screen coordinates", "windowOriginX", windowOriginX, "windowOriginY", windowOriginY)
+
+ // Calculate the offset from window origin to client origin
+ offsetX := clientX - windowOriginX
+ offsetY := clientY - windowOriginY
+
+ globalApplication.debug("[DragDropDebug] convertWindowToWebviewCoordinates: Calculated offset", "offsetX", offsetX, "offsetY", offsetY)
+
+ // Convert window-relative coordinates to webview-relative coordinates
+ webviewX := windowX - offsetX
+ webviewY := windowY - offsetY
+
+ globalApplication.debug("[DragDropDebug] convertWindowToWebviewCoordinates: Final webview coordinates", "webviewX", webviewX, "webviewY", webviewY)
+
+ return webviewX, webviewY
+}
+
+func (w *windowsWebviewWindow) physicalBounds() Rect {
+ // var rect w32.RECT
+ // // Get the extended frame bounds instead of the window rect to offset the invisible borders in Windows 10
+ // w32.DwmGetWindowAttribute(w.hwnd, w32.DWMWA_EXTENDED_FRAME_BOUNDS, unsafe.Pointer(&rect), unsafe.Sizeof(rect))
+ rect := w32.GetWindowRect(w.hwnd)
+ return Rect{
+ X: int(rect.Left),
+ Y: int(rect.Top),
+ Width: int(rect.Right - rect.Left),
+ Height: int(rect.Bottom - rect.Top),
+ }
+}
+
+func (w *windowsWebviewWindow) setPhysicalBounds(physicalBounds Rect) {
+ // // Offset invisible borders
+ // borderSize := w.getBorderSizes()
+ // physicalBounds.X -= borderSize.Left
+ // physicalBounds.Y -= borderSize.Top
+ // physicalBounds.Width += borderSize.Left + borderSize.Right
+ // physicalBounds.Height += borderSize.Top + borderSize.Bottom
+
+ // Set flag to ignore resizing the window with DPI change because we already calculated the correct size
+ // for the target position, this prevents double resizing issue when the window is moved between screens
+ previousFlag := w.ignoreDPIChangeResizing
+ w.ignoreDPIChangeResizing = true
+ w32.SetWindowPos(
+ w.hwnd,
+ 0,
+ physicalBounds.X,
+ physicalBounds.Y,
+ physicalBounds.Width,
+ physicalBounds.Height,
+ w32.SWP_NOZORDER|w32.SWP_NOACTIVATE,
+ )
+ w.ignoreDPIChangeResizing = previousFlag
+}
+
+// Get window dip bounds
+func (w *windowsWebviewWindow) bounds() Rect {
+ return PhysicalToDipRect(w.physicalBounds())
+}
+
+// Set window dip bounds
+func (w *windowsWebviewWindow) setBounds(bounds Rect) {
+ w.setPhysicalBounds(DipToPhysicalRect(bounds))
+}
+
+func (w *windowsWebviewWindow) size() (int, int) {
+ bounds := w.bounds()
+ return bounds.Width, bounds.Height
+}
+
+func (w *windowsWebviewWindow) width() int {
+ return w.bounds().Width
+}
+
+func (w *windowsWebviewWindow) height() int {
+ return w.bounds().Height
+}
+
+func (w *windowsWebviewWindow) setSize(width, height int) {
+ bounds := w.bounds()
+ bounds.Width = width
+ bounds.Height = height
+
+ w.setBounds(bounds)
+}
+
+func (w *windowsWebviewWindow) position() (int, int) {
+ bounds := w.bounds()
+ return bounds.X, bounds.Y
+}
+
+func (w *windowsWebviewWindow) setPosition(x int, y int) {
+ bounds := w.bounds()
+ bounds.X = x
+ bounds.Y = y
+
+ w.setBounds(bounds)
+}
+
+// Get window position relative to the screen WorkArea on which it is
+func (w *windowsWebviewWindow) relativePosition() (int, int) {
+ screen, _ := w.getScreen()
+ pos := screen.absoluteToRelativeDipPoint(w.bounds().Origin())
+ // Relative to WorkArea origin
+ pos.X -= (screen.WorkArea.X - screen.X)
+ pos.Y -= (screen.WorkArea.Y - screen.Y)
+ return pos.X, pos.Y
+}
+
+// Set window position relative to the screen WorkArea on which it is
+func (w *windowsWebviewWindow) setRelativePosition(x int, y int) {
+ screen, _ := w.getScreen()
+ pos := screen.relativeToAbsoluteDipPoint(Point{X: x, Y: y})
+ // Relative to WorkArea origin
+ pos.X += (screen.WorkArea.X - screen.X)
+ pos.Y += (screen.WorkArea.Y - screen.Y)
+ w.setPosition(pos.X, pos.Y)
+}
+
+func (w *windowsWebviewWindow) destroy() {
+ w.parent.markAsDestroyed()
+ // destroy the window
+ w32.DestroyWindow(w.hwnd)
+}
+
+func (w *windowsWebviewWindow) reload() {
+ w.execJS("window.location.reload();")
+}
+
+func (w *windowsWebviewWindow) forceReload() {
+ // noop
+}
+
+func (w *windowsWebviewWindow) zoomReset() {
+ w.setZoom(1.0)
+}
+
+func (w *windowsWebviewWindow) zoomIn() {
+ // Increase the zoom level by 0.05
+ currentZoom := w.getZoom()
+ if currentZoom == -1 {
+ return
+ }
+ w.setZoom(currentZoom + 0.05)
+}
+
+func (w *windowsWebviewWindow) zoomOut() {
+ // Decrease the zoom level by 0.05
+ currentZoom := w.getZoom()
+ if currentZoom == -1 {
+ return
+ }
+ if currentZoom > 1.05 {
+ // Decrease the zoom level by 0.05
+ w.setZoom(currentZoom - 0.05)
+ } else {
+ // Set the zoom level to 1.0
+ w.setZoom(1.0)
+ }
+}
+
+func (w *windowsWebviewWindow) getZoom() float64 {
+ controller := w.chromium.GetController()
+ factor, err := controller.GetZoomFactor()
+ if err != nil {
+ return -1
+ }
+ return factor
+}
+
+func (w *windowsWebviewWindow) setZoom(zoom float64) {
+ w.chromium.PutZoomFactor(zoom)
+}
+
+func (w *windowsWebviewWindow) close() {
+ // Send WM_CLOSE message to trigger the same flow as clicking the X button
+ w32.SendMessage(w.hwnd, w32.WM_CLOSE, 0, 0)
+}
+
+func (w *windowsWebviewWindow) zoom() {
+ // Noop
+}
+
+func (w *windowsWebviewWindow) setHTML(html string) {
+ // Render the given HTML in the webview window
+ w.execJS(fmt.Sprintf("document.documentElement.innerHTML = %q;", html))
+}
+
+// on is used to indicate that a particular event should be listened for
+func (w *windowsWebviewWindow) on(_ uint) {
+ // We don't need to worry about this in Windows as we do not need
+ // to optimise cgo calls
+}
+
+func (w *windowsWebviewWindow) minimise() {
+ w32.ShowWindow(w.hwnd, w32.SW_MINIMIZE)
+}
+
+func (w *windowsWebviewWindow) unminimise() {
+ w.restore()
+}
+
+func (w *windowsWebviewWindow) maximise() {
+ w32.ShowWindow(w.hwnd, w32.SW_MAXIMIZE)
+ w.chromium.Focus()
+}
+
+func (w *windowsWebviewWindow) unmaximise() {
+ w.restore()
+ w.parent.emit(events.Windows.WindowUnMaximise)
+}
+
+func (w *windowsWebviewWindow) restore() {
+ w32.ShowWindow(w.hwnd, w32.SW_RESTORE)
+ w.chromium.Focus()
+}
+
+func (w *windowsWebviewWindow) fullscreen() {
+ if w.isFullscreen() {
+ return
+ }
+ if w.framelessWithDecorations() {
+ err := w32.ExtendFrameIntoClientArea(w.hwnd, false)
+ if err != nil {
+ globalApplication.handleFatalError(err)
+ }
+ }
+ w.disableSizeConstraints()
+ w.previousWindowStyle = uint32(w32.GetWindowLongPtr(w.hwnd, w32.GWL_STYLE))
+ w.previousWindowExStyle = uint32(w32.GetWindowLong(w.hwnd, w32.GWL_EXSTYLE))
+ monitor := w32.MonitorFromWindow(w.hwnd, w32.MONITOR_DEFAULTTOPRIMARY)
+ var monitorInfo w32.MONITORINFO
+ monitorInfo.CbSize = uint32(unsafe.Sizeof(monitorInfo))
+ if !w32.GetMonitorInfo(monitor, &monitorInfo) {
+ return
+ }
+ if !w32.GetWindowPlacement(w.hwnd, &w.previousWindowPlacement) {
+ return
+ }
+ // According to https://devblogs.microsoft.com/oldnewthing/20050505-04/?p=35703 one should use w32.WS_POPUP | w32.WS_VISIBLE
+ w32.SetWindowLong(
+ w.hwnd,
+ w32.GWL_STYLE,
+ w.previousWindowStyle & ^uint32(w32.WS_OVERLAPPEDWINDOW) | (w32.WS_POPUP|w32.WS_VISIBLE),
+ )
+ w32.SetWindowLong(
+ w.hwnd,
+ w32.GWL_EXSTYLE,
+ w.previousWindowExStyle & ^uint32(w32.WS_EX_DLGMODALFRAME),
+ )
+ w.isCurrentlyFullscreen = true
+ w32.SetWindowPos(w.hwnd, w32.HWND_TOP,
+ int(monitorInfo.RcMonitor.Left),
+ int(monitorInfo.RcMonitor.Top),
+ int(monitorInfo.RcMonitor.Right-monitorInfo.RcMonitor.Left),
+ int(monitorInfo.RcMonitor.Bottom-monitorInfo.RcMonitor.Top),
+ w32.SWP_NOOWNERZORDER|w32.SWP_FRAMECHANGED)
+
+ // Hide the menubar in fullscreen mode
+ w32.SetMenu(w.hwnd, 0)
+
+ w.chromium.Focus()
+ w.parent.emit(events.Windows.WindowFullscreen)
+}
+
+func (w *windowsWebviewWindow) unfullscreen() {
+ if !w.isFullscreen() {
+ return
+ }
+ if w.framelessWithDecorations() {
+ err := w32.ExtendFrameIntoClientArea(w.hwnd, true)
+ if err != nil {
+ globalApplication.handleFatalError(err)
+ }
+ }
+ w32.SetWindowLong(w.hwnd, w32.GWL_STYLE, w.previousWindowStyle)
+ w32.SetWindowLong(w.hwnd, w32.GWL_EXSTYLE, w.previousWindowExStyle)
+ w32.SetWindowPlacement(w.hwnd, &w.previousWindowPlacement)
+ w.isCurrentlyFullscreen = false
+
+ // Restore the menubar when exiting fullscreen
+ if w.menu != nil {
+ w32.SetMenu(w.hwnd, w.menu.menu)
+ }
+
+ w32.SetWindowPos(w.hwnd, 0, 0, 0, 0, 0,
+ w32.SWP_NOMOVE|w32.SWP_NOSIZE|w32.SWP_NOZORDER|w32.SWP_NOOWNERZORDER|w32.SWP_FRAMECHANGED)
+ w.enableSizeConstraints()
+ w.parent.emit(events.Windows.WindowUnFullscreen)
+}
+
+func (w *windowsWebviewWindow) isMinimised() bool {
+ style := uint32(w32.GetWindowLong(w.hwnd, w32.GWL_STYLE))
+ return style&w32.WS_MINIMIZE != 0
+}
+
+func (w *windowsWebviewWindow) isMaximised() bool {
+ style := uint32(w32.GetWindowLong(w.hwnd, w32.GWL_STYLE))
+ return style&w32.WS_MAXIMIZE != 0
+}
+
+func (w *windowsWebviewWindow) isFocused() bool {
+ // Returns true if the window is currently focused
+ return w32.GetForegroundWindow() == w.hwnd
+}
+
+func (w *windowsWebviewWindow) isFullscreen() bool {
+ // TODO: Actually calculate this based on size of window against screen size
+ // => stffabi: This flag is essential since it indicates that we are in fullscreen mode even before the native properties
+ // reflect this, e.g. when needing to know if we are in fullscreen during a wndproc message.
+ // That's also why this flag is set before SetWindowPos in v2 in fullscreen/unfullscreen.
+ return w.isCurrentlyFullscreen
+}
+
+func (w *windowsWebviewWindow) isNormal() bool {
+ return !w.isMinimised() && !w.isMaximised() && !w.isFullscreen()
+}
+
+func (w *windowsWebviewWindow) isVisible() bool {
+ style := uint32(w32.GetWindowLong(w.hwnd, w32.GWL_STYLE))
+ return style&w32.WS_VISIBLE != 0
+}
+
+func (w *windowsWebviewWindow) focus() {
+ w32.SetForegroundWindow(w.hwnd)
+
+ if w.isDisabled() {
+ return
+ }
+ if w.isMinimised() {
+ w.unminimise()
+ }
+
+ w.focusingChromium = true
+ w.chromium.Focus()
+ w.focusingChromium = false
+}
+
+// printStyle takes a windows style and prints it in a human-readable format
+// This is for debugging window style issues
+func (w *windowsWebviewWindow) printStyle() {
+ style := uint32(w32.GetWindowLong(w.hwnd, w32.GWL_STYLE))
+ fmt.Printf("Style: ")
+ if style&w32.WS_BORDER != 0 {
+ fmt.Printf("WS_BORDER ")
+ }
+ if style&w32.WS_CAPTION != 0 {
+ fmt.Printf("WS_CAPTION ")
+ }
+ if style&w32.WS_CHILD != 0 {
+ fmt.Printf("WS_CHILD ")
+ }
+ if style&w32.WS_CLIPCHILDREN != 0 {
+ fmt.Printf("WS_CLIPCHILDREN ")
+ }
+ if style&w32.WS_CLIPSIBLINGS != 0 {
+ fmt.Printf("WS_CLIPSIBLINGS ")
+ }
+ if style&w32.WS_DISABLED != 0 {
+ fmt.Printf("WS_DISABLED ")
+ }
+ if style&w32.WS_DLGFRAME != 0 {
+ fmt.Printf("WS_DLGFRAME ")
+ }
+ if style&w32.WS_GROUP != 0 {
+ fmt.Printf("WS_GROUP ")
+ }
+ if style&w32.WS_HSCROLL != 0 {
+ fmt.Printf("WS_HSCROLL ")
+ }
+ if style&w32.WS_MAXIMIZE != 0 {
+ fmt.Printf("WS_MAXIMIZE ")
+ }
+ if style&w32.WS_MAXIMIZEBOX != 0 {
+ fmt.Printf("WS_MAXIMIZEBOX ")
+ }
+ if style&w32.WS_MINIMIZE != 0 {
+ fmt.Printf("WS_MINIMIZE ")
+ }
+ if style&w32.WS_MINIMIZEBOX != 0 {
+ fmt.Printf("WS_MINIMIZEBOX ")
+ }
+ if style&w32.WS_OVERLAPPED != 0 {
+ fmt.Printf("WS_OVERLAPPED ")
+ }
+ if style&w32.WS_POPUP != 0 {
+ fmt.Printf("WS_POPUP ")
+ }
+ if style&w32.WS_SYSMENU != 0 {
+ fmt.Printf("WS_SYSMENU ")
+ }
+ if style&w32.WS_TABSTOP != 0 {
+ fmt.Printf("WS_TABSTOP ")
+ }
+ if style&w32.WS_THICKFRAME != 0 {
+ fmt.Printf("WS_THICKFRAME ")
+ }
+ if style&w32.WS_VISIBLE != 0 {
+ fmt.Printf("WS_VISIBLE ")
+ }
+ if style&w32.WS_VSCROLL != 0 {
+ fmt.Printf("WS_VSCROLL ")
+ }
+ fmt.Printf("\n")
+
+ // Do the same for the extended style
+ extendedStyle := uint32(w32.GetWindowLong(w.hwnd, w32.GWL_EXSTYLE))
+ fmt.Printf("Extended Style: ")
+ if extendedStyle&w32.WS_EX_ACCEPTFILES != 0 {
+ fmt.Printf("WS_EX_ACCEPTFILES ")
+ }
+ if extendedStyle&w32.WS_EX_APPWINDOW != 0 {
+ fmt.Printf("WS_EX_APPWINDOW ")
+ }
+ if extendedStyle&w32.WS_EX_CLIENTEDGE != 0 {
+ fmt.Printf("WS_EX_CLIENTEDGE ")
+ }
+ if extendedStyle&w32.WS_EX_COMPOSITED != 0 {
+ fmt.Printf("WS_EX_COMPOSITED ")
+ }
+ if extendedStyle&w32.WS_EX_CONTEXTHELP != 0 {
+ fmt.Printf("WS_EX_CONTEXTHELP ")
+ }
+ if extendedStyle&w32.WS_EX_CONTROLPARENT != 0 {
+ fmt.Printf("WS_EX_CONTROLPARENT ")
+ }
+ if extendedStyle&w32.WS_EX_DLGMODALFRAME != 0 {
+ fmt.Printf("WS_EX_DLGMODALFRAME ")
+ }
+ if extendedStyle&w32.WS_EX_LAYERED != 0 {
+ fmt.Printf("WS_EX_LAYERED ")
+ }
+ if extendedStyle&w32.WS_EX_LAYOUTRTL != 0 {
+ fmt.Printf("WS_EX_LAYOUTRTL ")
+ }
+ if extendedStyle&w32.WS_EX_LEFT != 0 {
+ fmt.Printf("WS_EX_LEFT ")
+ }
+ if extendedStyle&w32.WS_EX_LEFTSCROLLBAR != 0 {
+ fmt.Printf("WS_EX_LEFTSCROLLBAR ")
+ }
+ if extendedStyle&w32.WS_EX_LTRREADING != 0 {
+ fmt.Printf("WS_EX_LTRREADING ")
+ }
+ if extendedStyle&w32.WS_EX_MDICHILD != 0 {
+ fmt.Printf("WS_EX_MDICHILD ")
+ }
+ if extendedStyle&w32.WS_EX_NOACTIVATE != 0 {
+ fmt.Printf("WS_EX_NOACTIVATE ")
+ }
+ if extendedStyle&w32.WS_EX_NOINHERITLAYOUT != 0 {
+ fmt.Printf("WS_EX_NOINHERITLAYOUT ")
+ }
+ if extendedStyle&w32.WS_EX_NOPARENTNOTIFY != 0 {
+ fmt.Printf("WS_EX_NOPARENTNOTIFY ")
+ }
+ if extendedStyle&w32.WS_EX_NOREDIRECTIONBITMAP != 0 {
+ fmt.Printf("WS_EX_NOREDIRECTIONBITMAP ")
+ }
+ if extendedStyle&w32.WS_EX_OVERLAPPEDWINDOW != 0 {
+ fmt.Printf("WS_EX_OVERLAPPEDWINDOW ")
+ }
+ if extendedStyle&w32.WS_EX_PALETTEWINDOW != 0 {
+ fmt.Printf("WS_EX_PALETTEWINDOW ")
+ }
+ if extendedStyle&w32.WS_EX_RIGHT != 0 {
+ fmt.Printf("WS_EX_RIGHT ")
+ }
+ if extendedStyle&w32.WS_EX_RIGHTSCROLLBAR != 0 {
+ fmt.Printf("WS_EX_RIGHTSCROLLBAR ")
+ }
+ if extendedStyle&w32.WS_EX_RTLREADING != 0 {
+ fmt.Printf("WS_EX_RTLREADING ")
+ }
+ if extendedStyle&w32.WS_EX_STATICEDGE != 0 {
+ fmt.Printf("WS_EX_STATICEDGE ")
+ }
+ if extendedStyle&w32.WS_EX_TOOLWINDOW != 0 {
+ fmt.Printf("WS_EX_TOOLWINDOW ")
+ }
+ if extendedStyle&w32.WS_EX_TOPMOST != 0 {
+ fmt.Printf("WS_EX_TOPMOST ")
+ }
+ if extendedStyle&w32.WS_EX_TRANSPARENT != 0 {
+ fmt.Printf("WS_EX_TRANSPARENT ")
+ }
+ if extendedStyle&w32.WS_EX_WINDOWEDGE != 0 {
+ fmt.Printf("WS_EX_WINDOWEDGE ")
+ }
+ fmt.Printf("\n")
+
+}
+
+func (w *windowsWebviewWindow) show() {
+ // Always show the window container immediately (decouple from WebView state)
+ // This fixes issue #2861 where efficiency mode prevents window visibility
+ w32.ShowWindow(w.hwnd, w32.SW_SHOW)
+ w.windowShown = true
+ w.showRequested = true
+ w.updateContentProtection()
+
+ // Show WebView if navigation has completed
+ if w.webviewNavigationCompleted {
+ w.chromium.Show()
+ // Cancel timeout since we can show immediately
+ if w.visibilityTimeout != nil {
+ w.visibilityTimeout.Stop()
+ w.visibilityTimeout = nil
+ }
+ } else {
+ // Start timeout to show WebView if navigation is delayed (fallback for efficiency mode)
+ if w.visibilityTimeout == nil {
+ w.visibilityTimeout = time.AfterFunc(3*time.Second, func() {
+ // Show WebView even if navigation hasn't completed
+ // This prevents permanent invisibility in efficiency mode
+ if !w.webviewNavigationCompleted && w.chromium != nil {
+ w.chromium.Show()
+ }
+ w.visibilityTimeout = nil
+ })
+ }
+ }
+}
+
+func (w *windowsWebviewWindow) hide() {
+ w32.ShowWindow(w.hwnd, w32.SW_HIDE)
+ w.windowShown = false
+ w.showRequested = false
+
+ // Cancel any pending visibility timeout
+ if w.visibilityTimeout != nil {
+ w.visibilityTimeout.Stop()
+ w.visibilityTimeout = nil
+ }
+}
+
+// Get the screen for the current window
+func (w *windowsWebviewWindow) getScreen() (*Screen, error) {
+ return getScreenForWindow(w)
+}
+
+func (w *windowsWebviewWindow) setFrameless(b bool) {
+ // Remove or add the frame
+ if b {
+ w32.SetWindowLong(w.hwnd, w32.GWL_STYLE, w32.WS_VISIBLE|w32.WS_POPUP)
+ } else {
+ w32.SetWindowLong(w.hwnd, w32.GWL_STYLE, w32.WS_VISIBLE|w32.WS_OVERLAPPEDWINDOW)
+ }
+ w32.SetWindowPos(
+ w.hwnd,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ w32.SWP_NOMOVE|w32.SWP_NOSIZE|w32.SWP_NOZORDER|w32.SWP_FRAMECHANGED,
+ )
+}
+
+func newWindowImpl(parent *WebviewWindow) *windowsWebviewWindow {
+ result := &windowsWebviewWindow{
+ parent: parent,
+ resizeBorderWidth: int32(w32.GetSystemMetrics(w32.SM_CXSIZEFRAME)),
+ resizeBorderHeight: int32(w32.GetSystemMetrics(w32.SM_CYSIZEFRAME)),
+ // Initialize visibility tracking fields
+ showRequested: false,
+ visibilityTimeout: nil,
+ windowShown: false,
+ }
+
+ return result
+}
+
+func (w *windowsWebviewWindow) openContextMenu(menu *Menu, _ *ContextMenuData) {
+ // Destroy previous context menu if it exists to prevent memory leak
+ if w.currentlyOpenContextMenu != nil {
+ w.currentlyOpenContextMenu.Destroy()
+ }
+ // Create the menu from current Go-side menu state
+ thisMenu := NewPopupMenu(w.hwnd, menu)
+ thisMenu.Update()
+ w.currentlyOpenContextMenu = thisMenu
+ thisMenu.ShowAtCursor()
+}
+
+func (w *windowsWebviewWindow) setStyle(b bool, style int) {
+ currentStyle := int(w32.GetWindowLongPtr(w.hwnd, w32.GWL_STYLE))
+ if currentStyle != 0 {
+ if b {
+ currentStyle = currentStyle | style
+ } else {
+ currentStyle = currentStyle &^ style
+ }
+ w32.SetWindowLongPtr(w.hwnd, w32.GWL_STYLE, uintptr(currentStyle))
+ }
+}
+func (w *windowsWebviewWindow) setExStyle(b bool, style int) {
+ currentStyle := int(w32.GetWindowLongPtr(w.hwnd, w32.GWL_EXSTYLE))
+ if currentStyle != 0 {
+ if b {
+ currentStyle = currentStyle | style
+ } else {
+ currentStyle = currentStyle &^ style
+ }
+ w32.SetWindowLongPtr(w.hwnd, w32.GWL_EXSTYLE, uintptr(currentStyle))
+ }
+}
+
+func (w *windowsWebviewWindow) setBackdropType(backdropType BackdropType) {
+ if !w32.SupportsBackdropTypes() {
+ var accent = w32.ACCENT_POLICY{
+ AccentState: w32.ACCENT_ENABLE_BLURBEHIND,
+ }
+ var data w32.WINDOWCOMPOSITIONATTRIBDATA
+ data.Attrib = w32.WCA_ACCENT_POLICY
+ data.PvData = w32.PVOID(&accent)
+ data.CbData = unsafe.Sizeof(accent)
+
+ w32.SetWindowCompositionAttribute(w.hwnd, &data)
+ } else {
+ w32.EnableTranslucency(w.hwnd, uint32(backdropType))
+ }
+}
+
+func (w *windowsWebviewWindow) setIcon(icon w32.HICON) {
+ w32.SendMessage(w.hwnd, w32.WM_SETICON, w32.ICON_BIG, icon)
+}
+
+func (w *windowsWebviewWindow) disableIcon() {
+
+ // TODO: If frameless, return
+ exStyle := w32.GetWindowLong(w.hwnd, w32.GWL_EXSTYLE)
+ w32.SetWindowLong(w.hwnd, w32.GWL_EXSTYLE, uint32(exStyle|w32.WS_EX_DLGMODALFRAME))
+ w32.SetWindowPos(w.hwnd, 0, 0, 0, 0, 0,
+ uint(
+ w32.SWP_FRAMECHANGED|
+ w32.SWP_NOMOVE|
+ w32.SWP_NOSIZE|
+ w32.SWP_NOZORDER),
+ )
+}
+
+func (w *windowsWebviewWindow) processThemeColour(fn func(w32.HWND, uint32), value *uint32) {
+ if value == nil {
+ return
+ }
+ fn(w.hwnd, *value)
+}
+
+func (w *windowsWebviewWindow) isDisabled() bool {
+ style := uint32(w32.GetWindowLong(w.hwnd, w32.GWL_STYLE))
+ return style&w32.WS_DISABLED != 0
+}
+
+func (w *windowsWebviewWindow) updateTheme(isDarkMode bool) {
+
+ if w32.IsCurrentlyHighContrastMode() {
+ return
+ }
+
+ if !w32.SupportsThemes() {
+ return
+ }
+
+ w32.SetTheme(w.hwnd, isDarkMode)
+
+ // Clear any existing theme first
+ if w.menubarTheme != nil && !isDarkMode {
+ // Reset menu to default Windows theme when switching to light mode
+ w.menubarTheme = nil
+ if w.menu != nil {
+ // Clear the menu background by setting it to default
+ var mi w32.MENUINFO
+ mi.CbSize = uint32(unsafe.Sizeof(mi))
+ mi.FMask = w32.MIIM_BACKGROUND | w32.MIIM_APPLYTOSUBMENUS
+ mi.HbrBack = 0 // NULL brush resets to default
+ w32.SetMenuInfo(w.menu.menu, &mi)
+ }
+ }
+
+ // Custom theme processing
+ customTheme := w.parent.options.Windows.CustomTheme
+ // Custom theme
+ if w32.SupportsCustomThemes() {
+ var userTheme *MenuBarTheme
+ if isDarkMode {
+ userTheme = customTheme.DarkModeMenuBar
+ } else {
+ userTheme = customTheme.LightModeMenuBar
+ }
+
+ if userTheme != nil {
+ modeStr := "light"
+ if isDarkMode {
+ modeStr = "dark"
+ }
+ globalApplication.debug("Setting custom "+modeStr+" menubar theme", "window", w.parent.id)
+ w.menubarTheme = &w32.MenuBarTheme{
+ TitleBarBackground: userTheme.Default.Background,
+ TitleBarText: userTheme.Default.Text,
+ MenuBarBackground: userTheme.Default.Background, // Use default background for menubar
+ MenuHoverBackground: userTheme.Hover.Background,
+ MenuHoverText: userTheme.Hover.Text,
+ MenuSelectedBackground: userTheme.Selected.Background,
+ MenuSelectedText: userTheme.Selected.Text,
+ }
+ w.menubarTheme.Init()
+
+ // If menu is already set, update it
+ if w.menu != nil {
+ w.menubarTheme.SetMenuBackground(w.menu.menu)
+ w32.DrawMenuBar(w.hwnd)
+ w32.InvalidateRect(w.hwnd, nil, true)
+ }
+ } else if userTheme == nil && isDarkMode {
+ // Use default dark theme if no custom theme provided
+ globalApplication.debug("Setting default dark menubar theme", "window", w.parent.id)
+ w.menubarTheme = &w32.MenuBarTheme{
+ TitleBarBackground: w32.RGBptr(45, 45, 45), // Dark titlebar
+ TitleBarText: w32.RGBptr(222, 222, 222), // Slightly muted white
+ MenuBarBackground: w32.RGBptr(33, 33, 33), // Standard dark mode (#212121)
+ MenuHoverBackground: w32.RGBptr(48, 48, 48), // Slightly lighter for hover (#303030)
+ MenuHoverText: w32.RGBptr(222, 222, 222), // Slightly muted white
+ MenuSelectedBackground: w32.RGBptr(48, 48, 48), // Same as hover
+ MenuSelectedText: w32.RGBptr(222, 222, 222), // Slightly muted white
+ }
+ w.menubarTheme.Init()
+
+ // If menu is already set, update it
+ if w.menu != nil {
+ w.menubarTheme.SetMenuBackground(w.menu.menu)
+ w32.DrawMenuBar(w.hwnd)
+ w32.InvalidateRect(w.hwnd, nil, true)
+ }
+ } else if userTheme == nil && !isDarkMode && w.menu != nil {
+ // No custom theme for light mode - ensure menu is reset to default
+ globalApplication.debug("Resetting menu to default light theme", "window", w.parent.id)
+ var mi w32.MENUINFO
+ mi.CbSize = uint32(unsafe.Sizeof(mi))
+ mi.FMask = w32.MIIM_BACKGROUND | w32.MIIM_APPLYTOSUBMENUS
+ mi.HbrBack = 0 // NULL brush resets to default
+ w32.SetMenuInfo(w.menu.menu, &mi)
+ w32.DrawMenuBar(w.hwnd)
+ w32.InvalidateRect(w.hwnd, nil, true)
+ }
+ // Define a map for theme selection
+ themeMap := map[bool]map[bool]*WindowTheme{
+ true: { // Window is active
+ true: customTheme.DarkModeActive, // Dark mode
+ false: customTheme.LightModeActive, // Light mode
+ },
+ false: { // Window is inactive
+ true: customTheme.DarkModeInactive, // Dark mode
+ false: customTheme.LightModeInactive, // Light mode
+ },
+ }
+
+ // Select the appropriate theme
+ theme := themeMap[w.isActive()][isDarkMode]
+
+ // Apply theme colors
+ if theme != nil {
+ w.processThemeColour(w32.SetTitleBarColour, theme.TitleBarColour)
+ w.processThemeColour(w32.SetTitleTextColour, theme.TitleTextColour)
+ w.processThemeColour(w32.SetBorderColour, theme.BorderColour)
+ }
+ }
+}
+
+func (w *windowsWebviewWindow) isActive() bool {
+ return w32.GetForegroundWindow() == w.hwnd
+}
+
+var resizePending int32
+
+func (w *windowsWebviewWindow) WndProc(msg uint32, wparam, lparam uintptr) uintptr {
+
+ // Use the original implementation that works perfectly for maximized
+ processed, code := w32.MenuBarWndProc(w.hwnd, msg, wparam, lparam, w.menubarTheme)
+ if processed {
+ return code
+ }
+
+ switch msg {
+ case w32.WM_ACTIVATE:
+ if int(wparam&0xffff) == w32.WA_INACTIVE {
+ w.parent.emit(events.Windows.WindowInactive)
+ }
+ if wparam == w32.WA_ACTIVE {
+ getNativeApplication().currentWindowID = w.parent.id
+ w.parent.emit(events.Windows.WindowActive)
+ }
+ if wparam == w32.WA_CLICKACTIVE {
+ getNativeApplication().currentWindowID = w.parent.id
+ w.parent.emit(events.Windows.WindowClickActive)
+ }
+ // If we want to have a frameless window but with the default frame decorations, extend the DWM client area.
+ // This Option is not affected by returning 0 in WM_NCCALCSIZE.
+ // As a result we have hidden the titlebar but still have the default window frame styling.
+ // See: https://docs.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmextendframeintoclientarea#remarks
+ if w.framelessWithDecorations() {
+ err := w32.ExtendFrameIntoClientArea(w.hwnd, true)
+ if err != nil {
+ globalApplication.handleFatalError(err)
+ }
+ }
+ case w32.WM_CLOSE:
+
+ if atomic.LoadUint32(&w.parent.unconditionallyClose) == 0 {
+ // We were called by `Close()` or pressing the close button on the window
+ w.parent.emit(events.Windows.WindowClosing)
+ return 0
+ }
+
+ defer func() {
+ windowsApp := globalApplication.impl.(*windowsApp)
+ windowsApp.unregisterWindow(w)
+
+ }()
+
+ // Now do the actual close
+ w.chromium.ShuttingDown()
+ return w32.DefWindowProc(w.hwnd, w32.WM_CLOSE, 0, 0)
+
+ case w32.WM_KILLFOCUS:
+ if w.focusingChromium {
+ return 0
+ }
+ w.parent.emit(events.Windows.WindowKillFocus)
+ case w32.WM_ENTERSIZEMOVE:
+ // This is needed to close open dropdowns when moving the window https://github.com/MicrosoftEdge/WebView2Feedback/issues/2290
+ w32.SetFocus(w.hwnd)
+ if int(w32.GetKeyState(w32.VK_LBUTTON))&(0x8000) != 0 {
+ // Left mouse button is down - window is being moved
+ w.parent.emit(events.Windows.WindowStartMove)
+ } else {
+ // Window is being resized
+ w.parent.emit(events.Windows.WindowStartResize)
+ }
+ case w32.WM_EXITSIZEMOVE:
+ if int(w32.GetKeyState(w32.VK_LBUTTON))&0x8000 != 0 {
+ w.parent.emit(events.Windows.WindowEndMove)
+ } else {
+ w.parent.emit(events.Windows.WindowEndResize)
+ }
+ case w32.WM_SETFOCUS:
+ w.focus()
+ w.parent.emit(events.Windows.WindowSetFocus)
+ case w32.WM_MOVE, w32.WM_MOVING:
+ _ = w.chromium.NotifyParentWindowPositionChanged()
+ w.moveDebouncer(func() {
+ w.parent.emit(events.Windows.WindowDidMove)
+ })
+ case w32.WM_SHOWWINDOW:
+ if wparam == 1 {
+ w.parent.emit(events.Windows.WindowShow)
+ w.updateContentProtection()
+ } else {
+ w.parent.emit(events.Windows.WindowHide)
+ }
+ case w32.WM_WINDOWPOSCHANGED:
+ windowPos := (*w32.WINDOWPOS)(unsafe.Pointer(lparam))
+ if windowPos.Flags&w32.SWP_NOZORDER == 0 {
+ w.parent.emit(events.Windows.WindowZOrderChanged)
+ }
+ case w32.WM_PAINT:
+ w.parent.emit(events.Windows.WindowPaint)
+ case w32.WM_ERASEBKGND:
+ w.parent.emit(events.Windows.WindowBackgroundErase)
+ return 1 // Let WebView2 handle background erasing
+ // WM_UAHDRAWMENUITEM is handled by MenuBarWndProc at the top of this function
+ // Check for keypress
+ case w32.WM_SYSCOMMAND:
+ switch wparam {
+ case w32.SC_KEYMENU:
+ if lparam == 0 {
+ // F10 or plain Alt key
+ if w.processKeyBinding(w32.VK_F10) {
+ return 0
+ }
+ } else {
+ // Alt + key combination
+ // The character code is in the low word of lparam
+ char := byte(lparam & 0xFF)
+ // Convert ASCII to virtual key code if needed
+ vkey := w32.VkKeyScan(uint16(char))
+ if w.processKeyBinding(uint(vkey)) {
+ return 0
+ }
+ }
+ }
+ case w32.WM_SYSKEYDOWN:
+ globalApplication.debug("w32.WM_SYSKEYDOWN", "wparam", uint(wparam))
+ w.parent.emit(events.Windows.WindowKeyDown)
+ if w.processKeyBinding(uint(wparam)) {
+ return 0
+ }
+ case w32.WM_SYSKEYUP:
+ w.parent.emit(events.Windows.WindowKeyUp)
+ case w32.WM_KEYDOWN:
+ w.parent.emit(events.Windows.WindowKeyDown)
+ w.processKeyBinding(uint(wparam))
+ case w32.WM_KEYUP:
+ w.parent.emit(events.Windows.WindowKeyUp)
+ case w32.WM_SIZE:
+ switch wparam {
+ case w32.SIZE_MAXIMIZED:
+ if w.isMinimizing {
+ w.parent.emit(events.Windows.WindowUnMinimise)
+ }
+ w.isMinimizing = false
+ w.parent.emit(events.Windows.WindowMaximise)
+ // Force complete redraw when maximized
+ if w.menu != nil && w.menubarTheme != nil {
+ // Invalidate the entire window to force complete redraw
+ w32.RedrawWindow(w.hwnd, nil, 0, w32.RDW_FRAME|w32.RDW_INVALIDATE|w32.RDW_UPDATENOW)
+ }
+ case w32.SIZE_RESTORED:
+ if w.isMinimizing {
+ w.parent.emit(events.Windows.WindowUnMinimise)
+ }
+ w.isMinimizing = false
+ w.parent.emit(events.Windows.WindowRestore)
+ case w32.SIZE_MINIMIZED:
+ w.isMinimizing = true
+ w.parent.emit(events.Windows.WindowMinimise)
+ }
+
+ doResize := func() {
+ // Get the new size from lparam
+ width := int32(lparam & 0xFFFF)
+ height := int32((lparam >> 16) & 0xFFFF)
+ bounds := &edge.Rect{
+ Left: 0,
+ Top: 0,
+ Right: width,
+ Bottom: height,
+ }
+ InvokeSync(func() {
+ time.Sleep(1 * time.Nanosecond)
+ w.chromium.ResizeWithBounds(bounds)
+ atomic.StoreInt32(&resizePending, 0)
+ w.parent.emit(events.Windows.WindowDidResize)
+ })
+ }
+
+ if w.parent.options.Frameless && wparam == w32.SIZE_MINIMIZED {
+ // If the window is frameless, and we are minimizing, then we need to suppress the Resize on the
+ // WebView2. If we don't do this, restoring does not work as expected and first restores with some wrong
+ // size during the restore animation and only fully renders when the animation is done. This highly
+ // depends on the content in the WebView, see https://github.com/MicrosoftEdge/WebView2Feedback/issues/2549
+ } else if w.resizeDebouncer != nil {
+ w.resizeDebouncer(doResize)
+ } else {
+ if atomic.CompareAndSwapInt32(&resizePending, 0, 1) {
+ doResize()
+ }
+ }
+ return 0
+
+ case w32.WM_GETMINMAXINFO:
+ mmi := (*w32.MINMAXINFO)(unsafe.Pointer(lparam))
+ hasConstraints := false
+ options := w.parent.options
+ // Using ScreenManager to get the closest screen and scale according to its DPI is problematic
+ // here because in multi-monitor setup, when dragging the window between monitors with the mouse
+ // on the side with the higher DPI, the DPI change point is offset beyond the mid point, causing
+ // wrong scaling and unwanted resizing when using the monitor DPI. To avoid this issue, we use
+ // scaleWithWindowDPI() instead which retrieves the correct DPI with GetDpiForWindow().
+ if options.MinWidth > 0 || options.MinHeight > 0 {
+ hasConstraints = true
+
+ width, height := w.scaleWithWindowDPI(options.MinWidth, options.MinHeight)
+ if width > 0 {
+ mmi.PtMinTrackSize.X = int32(width)
+ }
+ if height > 0 {
+ mmi.PtMinTrackSize.Y = int32(height)
+ }
+ }
+ if options.MaxWidth > 0 || options.MaxHeight > 0 {
+ hasConstraints = true
+
+ width, height := w.scaleWithWindowDPI(options.MaxWidth, options.MaxHeight)
+ if width > 0 {
+ mmi.PtMaxTrackSize.X = int32(width)
+ }
+ if height > 0 {
+ mmi.PtMaxTrackSize.Y = int32(height)
+ }
+ }
+ if hasConstraints {
+ return 0
+ }
+
+ case w32.WM_DPICHANGED:
+ if !w.ignoreDPIChangeResizing {
+ newWindowRect := (*w32.RECT)(unsafe.Pointer(lparam))
+ w32.SetWindowPos(w.hwnd,
+ uintptr(0),
+ int(newWindowRect.Left),
+ int(newWindowRect.Top),
+ int(newWindowRect.Right-newWindowRect.Left),
+ int(newWindowRect.Bottom-newWindowRect.Top),
+ w32.SWP_NOZORDER|w32.SWP_NOACTIVATE)
+ }
+ w.parent.emit(events.Windows.WindowDPIChanged)
+ }
+
+ if w.parent.options.Windows.WindowMask != nil {
+ switch msg {
+ case w32.WM_NCHITTEST:
+ if w.parent.options.Windows.WindowMaskDraggable {
+ return w32.HTCAPTION
+ }
+ w.parent.emit(events.Windows.WindowNonClientHit)
+ return w32.HTCLIENT
+ case w32.WM_NCLBUTTONDOWN:
+ w.parent.emit(events.Windows.WindowNonClientMouseDown)
+ case w32.WM_NCLBUTTONUP:
+ w.parent.emit(events.Windows.WindowNonClientMouseUp)
+ case w32.WM_NCMOUSEMOVE:
+ w.parent.emit(events.Windows.WindowNonClientMouseMove)
+ case w32.WM_NCMOUSELEAVE:
+ w.parent.emit(events.Windows.WindowNonClientMouseLeave)
+ }
+ }
+
+ if w.menu != nil || w.currentlyOpenContextMenu != nil {
+ switch msg {
+ case w32.WM_COMMAND:
+ cmdMsgID := int(wparam & 0xffff)
+ switch cmdMsgID {
+ default:
+ var processed bool
+ if w.currentlyOpenContextMenu != nil {
+ processed = w.currentlyOpenContextMenu.ProcessCommand(cmdMsgID)
+ w.currentlyOpenContextMenu = nil
+
+ }
+ if !processed && w.menu != nil {
+ processed = w.menu.ProcessCommand(cmdMsgID)
+ }
+ }
+ }
+ }
+
+ if options := w.parent.options; options.Frameless {
+ switch msg {
+ case w32.WM_ACTIVATE:
+ // If we want to have a frameless window but with the default frame decorations, extend the DWM client area.
+ // This Option is not affected by returning 0 in WM_NCCALCSIZE.
+ // As a result we have hidden the titlebar but still have the default window frame styling.
+ // See: https://docs.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmextendframeintoclientarea#remarks
+ if w.framelessWithDecorations() {
+ err := w32.ExtendFrameIntoClientArea(w.hwnd, true)
+ if err != nil {
+ globalApplication.handleFatalError(err)
+ }
+ }
+
+ case w32.WM_NCCALCSIZE:
+ // Disable the standard frame by allowing the client area to take the full
+ // window size.
+ // See: https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-nccalcsize#remarks
+ // This hides the titlebar and also disables the resizing from user interaction because the standard frame is not
+ // shown. We still need the WS_THICKFRAME style to enable resizing from the frontend.
+ if wparam != 0 {
+ rgrc := (*w32.RECT)(unsafe.Pointer(lparam))
+ if w.isCurrentlyFullscreen {
+ // In Full-Screen mode we don't need to adjust anything
+ // It essential we have the flag here, that is set before SetWindowPos in fullscreen/unfullscreen
+ // because the native size might not yet reflect we are in fullscreen during this event!
+ w.setPadding(edge.Rect{})
+ } else if w.isMaximised() {
+ // If the window is maximized we must adjust the client area to the work area of the monitor. Otherwise
+ // some content goes beyond the visible part of the monitor.
+ // Make sure to use the provided RECT to get the monitor, because during maximizig there might be
+ // a wrong monitor returned in multiscreen mode when using MonitorFromWindow.
+ // See: https://github.com/MicrosoftEdge/WebView2Feedback/issues/2549
+ screen := ScreenNearestPhysicalRect(Rect{
+ X: int(rgrc.Left),
+ Y: int(rgrc.Top),
+ Width: int(rgrc.Right - rgrc.Left),
+ Height: int(rgrc.Bottom - rgrc.Top),
+ })
+
+ rect := screen.PhysicalWorkArea
+
+ maxWidth := options.MaxWidth
+ maxHeight := options.MaxHeight
+
+ if maxWidth > 0 {
+ maxWidth = screen.scale(maxWidth, false)
+ if rect.Width > maxWidth {
+ rect.Width = maxWidth
+ }
+ }
+
+ if maxHeight > 0 {
+ maxHeight = screen.scale(maxHeight, false)
+ if rect.Height > maxHeight {
+ rect.Height = maxHeight
+ }
+ }
+
+ *rgrc = w32.RECT{
+ Left: int32(rect.X),
+ Top: int32(rect.Y),
+ Right: int32(rect.X + rect.Width),
+ Bottom: int32(rect.Y + rect.Height),
+ }
+ w.setPadding(edge.Rect{})
+ } else {
+ // This is needed to work around the resize flickering in frameless mode with WindowDecorations
+ // See: https://stackoverflow.com/a/6558508
+ // The workaround from the SO answer suggests to reduce the bottom of the window by 1px.
+ // However, this would result in losing 1px of the WebView content.
+ // Increasing the bottom also worksaround the flickering, but we would lose 1px of the WebView content
+ // therefore let's pad the content with 1px at the bottom.
+ rgrc.Bottom += 1
+ w.setPadding(edge.Rect{Bottom: 1})
+ }
+ return 0
+ }
+ }
+ }
+ return w32.DefWindowProc(w.hwnd, msg, wparam, lparam)
+}
+
+func (w *windowsWebviewWindow) DPI() (w32.UINT, w32.UINT) {
+ if w32.HasGetDpiForWindowFunc() {
+ // GetDpiForWindow is supported beginning with Windows 10, 1607 and is the most accurate
+ // one, especially it is consistent with the WM_DPICHANGED event.
+ dpi := w32.GetDpiForWindow(w.hwnd)
+ return dpi, dpi
+ }
+
+ if w32.HasGetDPIForMonitorFunc() {
+ // GetDpiForWindow is supported beginning with Windows 8.1
+ monitor := w32.MonitorFromWindow(w.hwnd, w32.MONITOR_DEFAULTTONEAREST)
+ if monitor == 0 {
+ return 0, 0
+ }
+ var dpiX, dpiY w32.UINT
+ w32.GetDPIForMonitor(monitor, w32.MDT_EFFECTIVE_DPI, &dpiX, &dpiY)
+ return dpiX, dpiY
+ }
+
+ // If none of the above is supported fallback to the System DPI.
+ screen := w32.GetDC(0)
+ x := w32.GetDeviceCaps(screen, w32.LOGPIXELSX)
+ y := w32.GetDeviceCaps(screen, w32.LOGPIXELSY)
+ w32.ReleaseDC(0, screen)
+ return w32.UINT(x), w32.UINT(y)
+}
+
+func (w *windowsWebviewWindow) scaleWithWindowDPI(width, height int) (int, int) {
+ dpix, dpiy := w.DPI()
+ scaledWidth := ScaleWithDPI(width, dpix)
+ scaledHeight := ScaleWithDPI(height, dpiy)
+
+ return scaledWidth, scaledHeight
+}
+
+func ScaleWithDPI(pixels int, dpi uint) int {
+ return (pixels * int(dpi)) / 96
+}
+
+func (w *windowsWebviewWindow) setWindowMask(imageData []byte) {
+
+ // Set the window to a WS_EX_LAYERED window
+ newStyle := w32.GetWindowLong(w.hwnd, w32.GWL_EXSTYLE) | w32.WS_EX_LAYERED
+
+ if w.isAlwaysOnTop() {
+ newStyle |= w32.WS_EX_TOPMOST
+ }
+ // Save the current window style
+ w.previousWindowExStyle = uint32(w32.GetWindowLong(w.hwnd, w32.GWL_EXSTYLE))
+
+ w32.SetWindowLong(w.hwnd, w32.GWL_EXSTYLE, uint32(newStyle))
+
+ data, err := pngToImage(imageData)
+ if err != nil {
+ globalApplication.fatal("fatal error in callback setWindowMask: %w", err)
+ }
+
+ bitmap, err := w32.CreateHBITMAPFromImage(data)
+ hdc := w32.CreateCompatibleDC(0)
+ defer w32.DeleteDC(hdc)
+
+ oldBitmap := w32.SelectObject(hdc, bitmap)
+ defer w32.SelectObject(hdc, oldBitmap)
+
+ screenDC := w32.GetDC(0)
+ defer w32.ReleaseDC(0, screenDC)
+
+ size := w32.SIZE{CX: int32(data.Bounds().Dx()), CY: int32(data.Bounds().Dy())}
+ ptSrc := w32.POINT{X: 0, Y: 0}
+ ptDst := w32.POINT{X: int32(w.width()), Y: int32(w.height())}
+ blend := w32.BLENDFUNCTION{
+ BlendOp: w32.AC_SRC_OVER,
+ BlendFlags: 0,
+ SourceConstantAlpha: 255,
+ AlphaFormat: w32.AC_SRC_ALPHA,
+ }
+ w32.UpdateLayeredWindow(w.hwnd, screenDC, &ptDst, &size, hdc, &ptSrc, 0, &blend, w32.ULW_ALPHA)
+}
+
+func (w *windowsWebviewWindow) isAlwaysOnTop() bool {
+ return w32.GetWindowLong(w.hwnd, w32.GWL_EXSTYLE)&w32.WS_EX_TOPMOST != 0
+}
+
+// processMessage is given a message sent from JS via the postMessage API
+// We put it on the global window message buffer to be processed centrally
+func (w *windowsWebviewWindow) processMessage(message string, sender *edge.ICoreWebView2, args *edge.ICoreWebView2WebMessageReceivedEventArgs) {
+ topSource, err := sender.GetSource()
+ if err != nil {
+ globalApplication.error("Unable to get source from sender: %s", err.Error())
+ topSource = ""
+ }
+
+ senderSource, err := args.GetSource()
+ if err != nil {
+ globalApplication.error("Unable to get source from args: %s", err.Error())
+ senderSource = ""
+ }
+
+ // We send all messages to the centralised window message buffer
+ windowMessageBuffer <- &windowMessage{
+ windowId: w.parent.id,
+ message: message,
+ originInfo: &OriginInfo{
+ Origin: senderSource,
+ TopOrigin: topSource,
+ },
+ }
+}
+
+func (w *windowsWebviewWindow) processRequest(
+ req *edge.ICoreWebView2WebResourceRequest,
+ args *edge.ICoreWebView2WebResourceRequestedEventArgs,
+) {
+
+ // Setting the UserAgent on the CoreWebView2Settings clears the whole default UserAgent of the Edge browser, but
+ // we want to just append our ApplicationIdentifier. So we adjust the UserAgent for every request.
+ if reqHeaders, err := req.GetHeaders(); err == nil {
+ useragent, _ := reqHeaders.GetHeader(assetserver.HeaderUserAgent)
+ useragent = strings.Join([]string{useragent, assetserver.WailsUserAgentValue}, " ")
+ err = reqHeaders.SetHeader(assetserver.HeaderUserAgent, useragent)
+ if err != nil {
+ globalApplication.fatal("error setting UserAgent header: %w", err)
+ }
+ err = reqHeaders.SetHeader(
+ webViewRequestHeaderWindowId,
+ strconv.FormatUint(uint64(w.parent.id), 10),
+ )
+ if err != nil {
+ globalApplication.fatal("error setting WindowId header: %w", err)
+ }
+ err = reqHeaders.Release()
+ if err != nil {
+ globalApplication.fatal("error releasing headers: %w", err)
+ }
+ }
+
+ if globalApplication.assets == nil {
+ // We are using the devServer let the WebView2 handle the request with its default handler
+ return
+ }
+
+ //Get the request
+ uri, _ := req.GetUri()
+ reqUri, err := url.ParseRequestURI(uri)
+ if err != nil {
+ globalApplication.error("unable to parse request uri: uri='%s' error='%w'", uri, err)
+ return
+ }
+
+ if reqUri.Scheme != "http" {
+ // Let the WebView2 handle the request with its default handler
+ return
+ } else if !strings.HasPrefix(reqUri.Host, "wails.localhost") {
+ // Let the WebView2 handle the request with its default handler
+ return
+ }
+
+ webviewRequest, err := webview.NewRequest(
+ w.chromium.Environment(),
+ args,
+ func(fn func()) {
+ InvokeSync(fn)
+ })
+ if err != nil {
+ globalApplication.error("%s: NewRequest failed: %w", uri, err)
+ return
+ }
+
+ webviewRequests <- &webViewAssetRequest{
+ Request: webviewRequest,
+ windowId: w.parent.id,
+ windowName: w.parent.options.Name,
+ }
+}
+
+func (w *windowsWebviewWindow) setupChromium() {
+ chromium := w.chromium
+ debugMode := globalApplication.isDebugMode
+
+ opts := w.parent.options.Windows
+
+ webview2version, err := webviewloader.GetAvailableCoreWebView2BrowserVersionString(
+ globalApplication.options.Windows.WebviewBrowserPath,
+ )
+ if err != nil {
+ globalApplication.error("error getting WebView2 version: %w", err)
+ return
+ }
+ globalApplication.capabilities = capabilities.NewCapabilities(webview2version)
+
+ // Browser flags apply globally to the shared WebView2 environment
+ // Use application-level options, not per-window options
+ appOpts := globalApplication.options.Windows
+
+ // We disable this by default. Can be overridden with the `EnableFraudulentWebsiteWarnings` option
+ disabledFeatures := append([]string{"msSmartScreenProtection"}, appOpts.DisabledFeatures...)
+
+ if len(disabledFeatures) > 0 {
+ disabledFeatures = sliceutil.Unique(disabledFeatures)
+ arg := fmt.Sprintf("--disable-features=%s", strings.Join(disabledFeatures, ","))
+ chromium.AdditionalBrowserArgs = append(chromium.AdditionalBrowserArgs, arg)
+ }
+
+ if len(appOpts.EnabledFeatures) > 0 {
+ enabledFeatures := sliceutil.Unique(appOpts.EnabledFeatures)
+ arg := fmt.Sprintf("--enable-features=%s", strings.Join(enabledFeatures, ","))
+ chromium.AdditionalBrowserArgs = append(chromium.AdditionalBrowserArgs, arg)
+ }
+
+ if len(appOpts.AdditionalBrowserArgs) > 0 {
+ chromium.AdditionalBrowserArgs = append(chromium.AdditionalBrowserArgs, appOpts.AdditionalBrowserArgs...)
+ }
+
+ chromium.DataPath = globalApplication.options.Windows.WebviewUserDataPath
+ chromium.BrowserPath = globalApplication.options.Windows.WebviewBrowserPath
+
+ if opts.Permissions != nil {
+ for permission, state := range opts.Permissions {
+ chromium.SetPermission(edge.CoreWebView2PermissionKind(permission),
+ edge.CoreWebView2PermissionState(state))
+ }
+ }
+
+ chromium.MessageCallback = w.processMessage
+ chromium.MessageWithAdditionalObjectsCallback = w.processMessageWithAdditionalObjects
+ chromium.WebResourceRequestedCallback = w.processRequest
+ chromium.ContainsFullScreenElementChangedCallback = w.fullscreenChanged
+ chromium.NavigationCompletedCallback = w.navigationCompleted
+ chromium.AcceleratorKeyCallback = w.processKeyBinding
+
+ chromium.Embed(w.hwnd)
+
+ // Prevent efficiency mode by keeping WebView2 visible (fixes issue #2861)
+ // Microsoft recommendation: keep IsVisible = true to avoid efficiency mode
+ // See: https://github.com/MicrosoftEdge/WebView2Feedback/discussions/4021
+ // TODO: Re-enable when PutIsVisible method is available in go-webview2 package
+ // err := chromium.PutIsVisible(true)
+ // if err != nil {
+ // globalApplication.error("Failed to set WebView2 visibility for efficiency mode prevention: %v", err)
+ // }
+
+ if chromium.HasCapability(edge.SwipeNavigation) {
+ err := chromium.PutIsSwipeNavigationEnabled(opts.EnableSwipeGestures)
+ if err != nil {
+ globalApplication.handleFatalError(err)
+ }
+ }
+
+ // File drop handling on Windows:
+ // WebView2's AllowExternalDrop controls ALL drag-and-drop (both external file drops
+ // AND internal HTML5 drag-and-drop). We cannot disable it without breaking HTML5 DnD.
+ //
+ // When EnableFileDrop is true:
+ // - JS dragenter/dragover/drop events fire for external file drags
+ // - JS calls preventDefault() to stop the browser from navigating to the file
+ // - JS uses chrome.webview.postMessageWithAdditionalObjects to send file paths to Go
+ // - Go receives paths via processMessageWithAdditionalObjects
+ //
+ // When EnableFileDrop is false:
+ // - We cannot use AllowExternalDrag(false) as it breaks HTML5 internal drag-and-drop
+ // - JS runtime checks window._wails.flags.enableFileDrop and shows "no drop" cursor
+ // - The enableFileDrop flag is injected in navigationCompleted callback
+
+ err = chromium.PutIsGeneralAutofillEnabled(opts.GeneralAutofillEnabled)
+ if err != nil {
+ if errors.Is(err, edge.UnsupportedCapabilityError) {
+ globalApplication.warning("unsupported capability: GeneralAutofillEnabled")
+ } else {
+ globalApplication.handleFatalError(err)
+ }
+ }
+
+ err = chromium.PutIsPasswordAutosaveEnabled(opts.PasswordAutosaveEnabled)
+ if err != nil {
+ if errors.Is(err, edge.UnsupportedCapabilityError) {
+ globalApplication.warning("unsupported capability: PasswordAutosaveEnabled")
+ } else {
+ globalApplication.handleFatalError(err)
+ }
+ }
+
+ chromium.Resize()
+ settings, err := chromium.GetSettings()
+ if err != nil {
+ globalApplication.handleFatalError(err)
+ }
+ if settings == nil {
+ globalApplication.fatal("error getting settings")
+ }
+ err = settings.PutAreDefaultContextMenusEnabled(
+ debugMode || !w.parent.options.DefaultContextMenuDisabled,
+ )
+ if err != nil {
+ globalApplication.handleFatalError(err)
+ }
+
+ w.enableDevTools(settings)
+
+ if w.parent.options.Zoom > 0.0 {
+ chromium.PutZoomFactor(w.parent.options.Zoom)
+ }
+ err = settings.PutIsZoomControlEnabled(w.parent.options.ZoomControlEnabled)
+ if err != nil {
+ globalApplication.handleFatalError(err)
+ }
+
+ err = settings.PutIsStatusBarEnabled(false)
+ if err != nil {
+ globalApplication.handleFatalError(err)
+ }
+ err = settings.PutAreBrowserAcceleratorKeysEnabled(false)
+ if err != nil {
+ globalApplication.handleFatalError(err)
+ }
+ err = settings.PutIsSwipeNavigationEnabled(false)
+ if err != nil {
+ globalApplication.handleFatalError(err)
+ }
+
+ if debugMode && w.parent.options.OpenInspectorOnStartup {
+ chromium.OpenDevToolsWindow()
+ }
+
+ // Set background colour
+ w.setBackgroundColour(w.parent.options.BackgroundColour)
+ chromium.SetBackgroundColour(
+ w.parent.options.BackgroundColour.Red,
+ w.parent.options.BackgroundColour.Green,
+ w.parent.options.BackgroundColour.Blue,
+ w.parent.options.BackgroundColour.Alpha,
+ )
+
+ chromium.SetGlobalPermission(edge.CoreWebView2PermissionStateAllow)
+ chromium.AddWebResourceRequestedFilter("*", edge.COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL)
+
+ if w.parent.options.HTML != "" {
+ var script string
+ if w.parent.options.JS != "" {
+ script = w.parent.options.JS
+ }
+ if w.parent.options.CSS != "" {
+ script += fmt.Sprintf(
+ "; addEventListener(\"DOMContentLoaded\", (event) => { document.head.appendChild(document.createElement('style')).innerHTML=\"%s\"; });",
+ strings.ReplaceAll(w.parent.options.CSS, `"`, `\"`),
+ )
+ }
+ if script != "" {
+ chromium.Init(script)
+ }
+ chromium.NavigateToString(w.parent.options.HTML)
+ } else {
+ startURL, err := assetserver.GetStartURL(w.parent.options.URL)
+ if err != nil {
+ globalApplication.handleFatalError(err)
+ }
+ w.webviewNavigationCompleted = false
+ chromium.Navigate(startURL)
+ }
+
+}
+
+func (w *windowsWebviewWindow) fullscreenChanged(
+ sender *edge.ICoreWebView2,
+ _ *edge.ICoreWebView2ContainsFullScreenElementChangedEventArgs,
+) {
+ isFullscreen, err := sender.GetContainsFullScreenElement()
+ if err != nil {
+ globalApplication.fatal("fatal error in callback fullscreenChanged: %w", err)
+ }
+ if isFullscreen {
+ w.fullscreen()
+ } else {
+ w.unfullscreen()
+ }
+}
+
+func (w *windowsWebviewWindow) flash(enabled bool) {
+ w32.FlashWindow(w.hwnd, enabled)
+}
+
+func (w *windowsWebviewWindow) navigationCompleted(
+ sender *edge.ICoreWebView2,
+ args *edge.ICoreWebView2NavigationCompletedEventArgs,
+) {
+
+ // Install the runtime core
+ w.execJS(runtime.Core(globalApplication.impl.GetFlags(globalApplication.options)))
+
+ // Set the EnableFileDrop flag for this window (Windows-specific)
+ // The JS runtime checks this before processing file drops
+ w.execJS(fmt.Sprintf("window._wails.flags.enableFileDrop = %v;", w.parent.options.EnableFileDrop))
+
+ // EmitEvent DomReady ApplicationEvent
+ windowEvents <- &windowEvent{EventID: uint(events.Windows.WebViewNavigationCompleted), WindowID: w.parent.id}
+
+ if w.webviewNavigationCompleted {
+ // NavigationCompleted is triggered for every Load. If an application uses reloads the Hide/Show will trigger
+ // a flickering of the window with every reload. So we only do this once for the first NavigationCompleted.
+ return
+ }
+ w.webviewNavigationCompleted = true
+
+ // Cancel any pending visibility timeout since navigation completed
+ if w.visibilityTimeout != nil {
+ w.visibilityTimeout.Stop()
+ w.visibilityTimeout = nil
+ }
+
+ wasFocused := w.isFocused()
+ // Hack to make it visible: https://github.com/MicrosoftEdge/WebView2Feedback/issues/1077#issuecomment-825375026
+ err := w.chromium.Hide()
+ if err != nil {
+ globalApplication.handleFatalError(err)
+ }
+ err = w.chromium.Show()
+ if err != nil {
+ globalApplication.handleFatalError(err)
+ }
+ if wasFocused {
+ w.focus()
+ }
+
+ // Only call parent.Show() if not hidden and show was requested but window wasn't shown yet
+ // The new robust show() method handles window visibility independently
+ if !w.parent.options.Hidden {
+ if w.showRequested && !w.windowShown {
+ w.parent.Show()
+ }
+ w.update()
+ }
+}
+
+func (w *windowsWebviewWindow) processKeyBinding(vkey uint) bool {
+
+ globalApplication.debug("Processing key binding", "vkey", vkey)
+
+ // Get the keyboard state and convert to an accelerator
+ var keyState [256]byte
+ if !w32.GetKeyboardState(keyState[:]) {
+ globalApplication.error("error getting keyboard state")
+ return false
+ }
+
+ var acc accelerator
+ // Check if CTRL is pressed
+ if keyState[w32.VK_CONTROL]&0x80 != 0 {
+ acc.Modifiers = append(acc.Modifiers, ControlKey)
+ }
+ // Check if ALT is pressed
+ if keyState[w32.VK_MENU]&0x80 != 0 {
+ acc.Modifiers = append(acc.Modifiers, OptionOrAltKey)
+ }
+ // Check if SHIFT is pressed
+ if keyState[w32.VK_SHIFT]&0x80 != 0 {
+ acc.Modifiers = append(acc.Modifiers, ShiftKey)
+ }
+ // Check if WIN is pressed
+ if keyState[w32.VK_LWIN]&0x80 != 0 || keyState[w32.VK_RWIN]&0x80 != 0 {
+ acc.Modifiers = append(acc.Modifiers, SuperKey)
+ }
+
+ if vkey != w32.VK_CONTROL && vkey != w32.VK_MENU && vkey != w32.VK_SHIFT &&
+ vkey != w32.VK_LWIN &&
+ vkey != w32.VK_RWIN {
+ // Convert the vkey to a string
+ accKey, ok := VirtualKeyCodes[vkey]
+ if !ok {
+ return false
+ }
+ acc.Key = accKey
+ }
+
+ accKey := acc.String()
+ globalApplication.debug("Processing key binding", "vkey", vkey, "acc", accKey)
+
+ // Process the key binding
+ if w.parent.processKeyBinding(accKey) {
+ return true
+ }
+
+ if accKey == "alt+f4" {
+ w32.PostMessage(w.hwnd, w32.WM_CLOSE, 0, 0)
+ return true
+ }
+
+ return false
+}
+
+func (w *windowsWebviewWindow) processMessageWithAdditionalObjects(
+ message string,
+ sender *edge.ICoreWebView2,
+ args *edge.ICoreWebView2WebMessageReceivedEventArgs,
+) {
+ if strings.HasPrefix(message, "file:drop:") {
+ objs, err := args.GetAdditionalObjects()
+ if err != nil {
+ globalApplication.handleError(err)
+ return
+ }
+
+ defer func() {
+ err = objs.Release()
+ if err != nil {
+ globalApplication.error("error releasing objects: %w", err)
+ }
+ }()
+
+ count, err := objs.GetCount()
+ if err != nil {
+ globalApplication.error("cannot get count: %w", err)
+ return
+ }
+
+ var filenames []string
+ for i := uint32(0); i < count; i++ {
+ _file, err := objs.GetValueAtIndex(i)
+ if err != nil {
+ globalApplication.error("cannot get value at %d: %w", i, err)
+ return
+ }
+
+ file := (*edge.ICoreWebView2File)(unsafe.Pointer(_file))
+
+ // TODO: Fix this
+ defer file.Release()
+
+ filepath, err := file.GetPath()
+ if err != nil {
+ globalApplication.error("cannot get path for object at %d: %w", i, err)
+ return
+ }
+
+ filenames = append(filenames, filepath)
+ }
+
+ // Extract X/Y coordinates from message - format is "file:drop:x:y"
+ var x, y int
+ parts := strings.Split(message, ":")
+ if len(parts) >= 4 {
+ if parsedX, err := strconv.Atoi(parts[2]); err == nil {
+ x = parsedX
+ }
+ if parsedY, err := strconv.Atoi(parts[3]); err == nil {
+ y = parsedY
+ }
+ }
+
+ globalApplication.debug("[DragDropDebug] processMessageWithAdditionalObjects: Raw WebView2 coordinates", "x", x, "y", y)
+
+ // Convert webview-relative coordinates to window-relative coordinates, then to webview-relative coordinates
+ // Note: The coordinates from WebView2 are already webview-relative, but let's log them for debugging
+ webviewX, webviewY := x, y
+
+ globalApplication.debug("[DragDropDebug] processMessageWithAdditionalObjects: Using coordinates as-is (already webview-relative)", "webviewX", webviewX, "webviewY", webviewY)
+
+ w.parent.InitiateFrontendDropProcessing(filenames, webviewX, webviewY)
+ return
+ }
+}
+
+func (w *windowsWebviewWindow) setMaximiseButtonEnabled(enabled bool) {
+ w.setStyle(enabled, w32.WS_MAXIMIZEBOX)
+}
+
+func (w *windowsWebviewWindow) setMinimiseButtonEnabled(enabled bool) {
+ w.setStyle(enabled, w32.WS_MINIMIZEBOX)
+}
+
+func (w *windowsWebviewWindow) toggleMenuBar() {
+ if w.menu != nil {
+ if w32.GetMenu(w.hwnd) == 0 {
+ w32.SetMenu(w.hwnd, w.menu.menu)
+ } else {
+ w32.SetMenu(w.hwnd, 0)
+ }
+
+ // Get the bounds of the client area
+ //bounds := w32.GetClientRect(w.hwnd)
+
+ // Resize the webview
+ w.chromium.Resize()
+
+ // Update size of webview
+ w.update()
+ // Restore focus to the webview after toggling menu
+ w.focus()
+ }
+}
+
+func (w *windowsWebviewWindow) enableRedraw() {
+ w32.SendMessage(w.hwnd, w32.WM_SETREDRAW, 1, 0)
+ w32.RedrawWindow(
+ w.hwnd,
+ nil,
+ 0,
+ w32.RDW_ERASE|w32.RDW_FRAME|w32.RDW_INVALIDATE|w32.RDW_ALLCHILDREN,
+ )
+}
+
+func (w *windowsWebviewWindow) disableRedraw() {
+ w32.SendMessage(w.hwnd, w32.WM_SETREDRAW, 0, 0)
+}
+
+func (w *windowsWebviewWindow) disableRedrawWithCallback(callback func()) {
+ w.disableRedraw()
+ callback()
+ w.enableRedraw()
+
+}
+
+func NewIconFromResource(instance w32.HINSTANCE, resId uint16) (w32.HICON, error) {
+ var err error
+ var result w32.HICON
+ if result = w32.LoadIconWithResourceID(instance, resId); result == 0 {
+ err = fmt.Errorf("cannot load icon from resource with id %v", resId)
+ }
+ return result, err
+}
+
+func (w *windowsWebviewWindow) setMinimiseButtonState(state ButtonState) {
+ switch state {
+ case ButtonDisabled, ButtonHidden:
+ w.setStyle(false, w32.WS_MINIMIZEBOX)
+ case ButtonEnabled:
+ w.setStyle(true, w32.WS_SYSMENU)
+ w.setStyle(true, w32.WS_MINIMIZEBOX)
+
+ }
+}
+
+func (w *windowsWebviewWindow) setMaximiseButtonState(state ButtonState) {
+ switch state {
+ case ButtonDisabled, ButtonHidden:
+ w.setStyle(false, w32.WS_MAXIMIZEBOX)
+ case ButtonEnabled:
+ w.setStyle(true, w32.WS_SYSMENU)
+ w.setStyle(true, w32.WS_MAXIMIZEBOX)
+ }
+}
+
+func (w *windowsWebviewWindow) setCloseButtonState(state ButtonState) {
+ switch state {
+ case ButtonEnabled:
+ w.setStyle(true, w32.WS_SYSMENU)
+ _ = w32.EnableCloseButton(w.hwnd)
+ case ButtonDisabled:
+ w.setStyle(true, w32.WS_SYSMENU)
+ _ = w32.DisableCloseButton(w.hwnd)
+ case ButtonHidden:
+ w.setStyle(false, w32.WS_SYSMENU)
+ }
+}
+
+func (w *windowsWebviewWindow) setGWLStyle(style int) {
+ w32.SetWindowLong(w.hwnd, w32.GWL_STYLE, uint32(style))
+}
+
+func (w *windowsWebviewWindow) isIgnoreMouseEvents() bool {
+ exStyle := w32.GetWindowLong(w.hwnd, w32.GWL_EXSTYLE)
+ return exStyle&w32.WS_EX_TRANSPARENT != 0
+}
+
+func (w *windowsWebviewWindow) setIgnoreMouseEvents(ignore bool) {
+ exStyle := w32.GetWindowLong(w.hwnd, w32.GWL_EXSTYLE)
+ if ignore {
+ exStyle |= w32.WS_EX_LAYERED | w32.WS_EX_TRANSPARENT
+ } else {
+ exStyle &^= w32.WS_EX_TRANSPARENT
+ }
+ w32.SetWindowLong(w.hwnd, w32.GWL_EXSTYLE, uint32(exStyle))
+}
+
+func (w *windowsWebviewWindow) setPadding(padding edge.Rect) {
+ // Skip SetPadding if window is being minimized to prevent flickering
+ if w.isMinimizing {
+ return
+ }
+ w.chromium.SetPadding(padding)
+}
+
+func (w *windowsWebviewWindow) showMenuBar() {
+ if w.menu != nil {
+ w32.SetMenu(w.hwnd, w.menu.menu)
+ }
+}
+
+func (w *windowsWebviewWindow) hideMenuBar() {
+ if w.menu != nil {
+ w32.SetMenu(w.hwnd, 0)
+ }
+}
+
+func (w *windowsWebviewWindow) snapAssist() {
+ // Simulate Win+Z key combination to trigger Snap Assist
+ // Press Windows key
+ w32.KeybdEvent(byte(w32.VK_LWIN), 0, 0, 0)
+ // Press Z key
+ w32.KeybdEvent(byte('Z'), 0, 0, 0)
+ // Release Z key
+ w32.KeybdEvent(byte('Z'), 0, w32.KEYEVENTF_KEYUP, 0)
+ // Release Windows key
+ w32.KeybdEvent(byte(w32.VK_LWIN), 0, w32.KEYEVENTF_KEYUP, 0)
+}
+
+func (w *windowsWebviewWindow) setContentProtection(enabled bool) {
+ // Ensure the option reflects the requested state for future show() calls
+ w.parent.options.ContentProtectionEnabled = enabled
+ w.updateContentProtection()
+}
+
+func (w *windowsWebviewWindow) updateContentProtection() {
+ if w.hwnd == 0 {
+ return
+ }
+
+ if !w.isVisible() {
+ // Defer updates until the window is visible to avoid affinity glitches.
+ return
+ }
+
+ desired := w.parent.options.ContentProtectionEnabled
+
+ if desired {
+ if w.applyDisplayAffinity(w32.WDA_EXCLUDEFROMCAPTURE) {
+ w.contentProtectionApplied = true
+ }
+ return
+ }
+
+ if w.applyDisplayAffinity(w32.WDA_NONE) {
+ w.contentProtectionApplied = false
+ }
+}
+
+func (w *windowsWebviewWindow) applyDisplayAffinity(affinity uint32) bool {
+ if ok := w32.SetWindowDisplayAffinity(w.hwnd, affinity); !ok {
+ // Note: wrapper already falls back to WDA_MONITOR on older Windows.
+ globalApplication.warning("SetWindowDisplayAffinity failed: window=%v, affinity=%v", w.parent.id, affinity)
+ return false
+ }
+ return true
+}
diff --git a/v3/pkg/w32/actions.go b/v3/pkg/w32/actions.go
new file mode 100644
index 000000000..2d376c7f4
--- /dev/null
+++ b/v3/pkg/w32/actions.go
@@ -0,0 +1,27 @@
+//go:build windows
+
+package w32
+
+func Undo(hwnd HWND) {
+ SendMessage(hwnd, WM_UNDO, 0, 0)
+}
+
+func Cut(hwnd HWND) {
+ SendMessage(hwnd, WM_CUT, 0, 0)
+}
+
+func Copy(hwnd HWND) {
+ SendMessage(hwnd, WM_COPY, 0, 0)
+}
+
+func Paste(hwnd HWND) {
+ SendMessage(hwnd, WM_PASTE, 0, 0)
+}
+
+func Delete(hwnd HWND) {
+ SendMessage(hwnd, WM_CLEAR, 0, 0)
+}
+
+func SelectAll(hwnd HWND) {
+ SendMessage(hwnd, WM_SELECTALL, 0, 0)
+}
diff --git a/v3/pkg/w32/clipboard.go b/v3/pkg/w32/clipboard.go
new file mode 100644
index 000000000..89334c0a4
--- /dev/null
+++ b/v3/pkg/w32/clipboard.go
@@ -0,0 +1,143 @@
+//go:build windows
+
+/*
+ * Based on code originally from https://github.com/atotto/clipboard. Copyright (c) 2013 Ato Araki. All rights reserved.
+ */
+
+package w32
+
+import (
+ "runtime"
+ "syscall"
+ "time"
+ "unsafe"
+)
+
+const (
+ cfUnicodetext = 13
+ gmemMoveable = 0x0002
+)
+
+// waitOpenClipboard opens the clipboard, waiting for up to a second to do so.
+func waitOpenClipboard() error {
+ started := time.Now()
+ limit := started.Add(time.Second)
+ var r uintptr
+ var err error
+ for time.Now().Before(limit) {
+ r, _, err = procOpenClipboard.Call(0)
+ if r != 0 {
+ return nil
+ }
+ time.Sleep(time.Millisecond)
+ }
+ return err
+}
+
+func GetClipboardText() (string, error) {
+ // LockOSThread ensure that the whole method will keep executing on the same thread from begin to end (it actually locks the goroutine thread attribution).
+ // Otherwise if the goroutine switch thread during execution (which is a common practice), the OpenClipboard and CloseClipboard will happen on two different threads, and it will result in a clipboard deadlock.
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ if formatAvailable, _, err := procIsClipboardFormatAvailable.Call(cfUnicodetext); formatAvailable == 0 {
+ return "", err
+ }
+ err := waitOpenClipboard()
+ if err != nil {
+ return "", err
+ }
+
+ h, _, err := procGetClipboardData.Call(cfUnicodetext)
+ if h == 0 {
+ _, _, _ = procCloseClipboard.Call()
+ return "", err
+ }
+
+ l, _, err := kernelGlobalLock.Call(h)
+ if l == 0 {
+ _, _, _ = procCloseClipboard.Call()
+ return "", err
+ }
+
+ text := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(l))[:])
+
+ r, _, err := kernelGlobalUnlock.Call(h)
+ if r == 0 {
+ _, _, _ = procCloseClipboard.Call()
+ return "", err
+ }
+
+ closed, _, err := procCloseClipboard.Call()
+ if closed == 0 {
+ return "", err
+ }
+ return text, nil
+}
+
+func SetClipboardText(text string) error {
+ // LockOSThread ensure that the whole method will keep executing on the same thread from begin to end (it actually locks the goroutine thread attribution).
+ // Otherwise if the goroutine switch thread during execution (which is a common practice), the OpenClipboard and CloseClipboard will happen on two different threads, and it will result in a clipboard deadlock.
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err := waitOpenClipboard()
+ if err != nil {
+ return err
+ }
+
+ r, _, err := procEmptyClipboard.Call(0)
+ if r == 0 {
+ _, _, _ = procCloseClipboard.Call()
+ return err
+ }
+
+ data, err := syscall.UTF16FromString(text)
+ if err != nil {
+ return err
+ }
+
+ // "If the hMem parameter identifies a memory object, the object must have
+ // been allocated using the function with the GMEM_MOVEABLE flag."
+ h, _, err := kernelGlobalAlloc.Call(gmemMoveable, uintptr(len(data)*int(unsafe.Sizeof(data[0]))))
+ if h == 0 {
+ _, _, _ = procCloseClipboard.Call()
+ return err
+ }
+ defer func() {
+ if h != 0 {
+ kernelGlobalFree.Call(h)
+ }
+ }()
+
+ l, _, err := kernelGlobalLock.Call(h)
+ if l == 0 {
+ _, _, _ = procCloseClipboard.Call()
+ return err
+ }
+
+ r, _, err = kernelLstrcpy.Call(l, uintptr(unsafe.Pointer(&data[0])))
+ if r == 0 {
+ _, _, _ = procCloseClipboard.Call()
+ return err
+ }
+
+ r, _, err = kernelGlobalUnlock.Call(h)
+ if r == 0 {
+ if err.(syscall.Errno) != 0 {
+ _, _, _ = procCloseClipboard.Call()
+ return err
+ }
+ }
+
+ r, _, err = procSetClipboardData.Call(cfUnicodetext, h)
+ if r == 0 {
+ _, _, _ = procCloseClipboard.Call()
+ return err
+ }
+ h = 0 // suppress deferred cleanup
+ closed, _, err := procCloseClipboard.Call()
+ if closed == 0 {
+ return err
+ }
+ return nil
+}
diff --git a/v3/pkg/w32/com.go b/v3/pkg/w32/com.go
new file mode 100644
index 000000000..35b79e535
--- /dev/null
+++ b/v3/pkg/w32/com.go
@@ -0,0 +1,55 @@
+//go:build windows
+
+package w32
+
+import (
+ "golang.org/x/sys/windows"
+ "syscall"
+ "unsafe"
+)
+
+// ComProc stores a COM procedure.
+type ComProc uintptr
+
+// NewComProc creates a new COM proc from a Go function.
+func NewComProc(fn interface{}) ComProc {
+ return ComProc(windows.NewCallback(fn))
+}
+
+type EventRegistrationToken struct {
+ value int64
+}
+
+// IUnknown
+type IUnknown struct {
+ Vtbl *IUnknownVtbl
+}
+
+type IUnknownVtbl struct {
+ QueryInterface ComProc
+ AddRef ComProc
+ Release ComProc
+}
+
+func (i *IUnknownVtbl) CallRelease(this unsafe.Pointer) error {
+ _, _, err := i.Release.Call(
+ uintptr(this),
+ )
+ if err != windows.ERROR_SUCCESS {
+ return err
+ }
+ return nil
+}
+
+type IUnknownImpl interface {
+ QueryInterface(refiid, object uintptr) uintptr
+ AddRef() uintptr
+ Release() uintptr
+}
+
+// Call calls a COM procedure.
+//
+//go:uintptrescapes
+func (p ComProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
+ return syscall.SyscallN(uintptr(p), a...)
+}
diff --git a/v3/pkg/w32/comctl32.go b/v3/pkg/w32/comctl32.go
new file mode 100644
index 000000000..b66709f5f
--- /dev/null
+++ b/v3/pkg/w32/comctl32.go
@@ -0,0 +1,112 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 The Winc Authors. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modcomctl32 = syscall.NewLazyDLL("comctl32.dll")
+
+ procInitCommonControlsEx = modcomctl32.NewProc("InitCommonControlsEx")
+ procImageList_Create = modcomctl32.NewProc("ImageList_Create")
+ procImageList_Destroy = modcomctl32.NewProc("ImageList_Destroy")
+ procImageList_GetImageCount = modcomctl32.NewProc("ImageList_GetImageCount")
+ procImageList_SetImageCount = modcomctl32.NewProc("ImageList_SetImageCount")
+ procImageList_Add = modcomctl32.NewProc("ImageList_Add")
+ procImageList_ReplaceIcon = modcomctl32.NewProc("ImageList_ReplaceIcon")
+ procImageList_Remove = modcomctl32.NewProc("ImageList_Remove")
+ procTrackMouseEvent = modcomctl32.NewProc("_TrackMouseEvent")
+)
+
+func InitCommonControlsEx(lpInitCtrls *INITCOMMONCONTROLSEX) bool {
+ ret, _, _ := procInitCommonControlsEx.Call(
+ uintptr(unsafe.Pointer(lpInitCtrls)))
+
+ return ret != 0
+}
+
+func ImageList_Create(cx, cy int, flags uint, cInitial, cGrow int) HIMAGELIST {
+ ret, _, _ := procImageList_Create.Call(
+ uintptr(cx),
+ uintptr(cy),
+ uintptr(flags),
+ uintptr(cInitial),
+ uintptr(cGrow))
+
+ if ret == 0 {
+ panic("Create image list failed")
+ }
+
+ return HIMAGELIST(ret)
+}
+
+func ImageList_Destroy(himl HIMAGELIST) bool {
+ ret, _, _ := procImageList_Destroy.Call(
+ uintptr(himl))
+
+ return ret != 0
+}
+
+func ImageList_GetImageCount(himl HIMAGELIST) int {
+ ret, _, _ := procImageList_GetImageCount.Call(
+ uintptr(himl))
+
+ return int(ret)
+}
+
+func ImageList_SetImageCount(himl HIMAGELIST, uNewCount uint) bool {
+ ret, _, _ := procImageList_SetImageCount.Call(
+ uintptr(himl),
+ uintptr(uNewCount))
+
+ return ret != 0
+}
+
+func ImageList_Add(himl HIMAGELIST, hbmImage, hbmMask HBITMAP) int {
+ ret, _, _ := procImageList_Add.Call(
+ uintptr(himl),
+ uintptr(hbmImage),
+ uintptr(hbmMask))
+
+ return int(ret)
+}
+
+func ImageList_ReplaceIcon(himl HIMAGELIST, i int, hicon HICON) int {
+ ret, _, _ := procImageList_ReplaceIcon.Call(
+ uintptr(himl),
+ uintptr(i),
+ uintptr(hicon))
+
+ return int(ret)
+}
+
+func ImageList_AddIcon(himl HIMAGELIST, hicon HICON) int {
+ return ImageList_ReplaceIcon(himl, -1, hicon)
+}
+
+func ImageList_Remove(himl HIMAGELIST, i int) bool {
+ ret, _, _ := procImageList_Remove.Call(
+ uintptr(himl),
+ uintptr(i))
+
+ return ret != 0
+}
+
+func ImageList_RemoveAll(himl HIMAGELIST) bool {
+ return ImageList_Remove(himl, -1)
+}
+
+func TrackMouseEvent(tme *TRACKMOUSEEVENT) bool {
+ ret, _, _ := procTrackMouseEvent.Call(
+ uintptr(unsafe.Pointer(tme)))
+
+ return ret != 0
+}
diff --git a/v3/pkg/w32/comdlg32.go b/v3/pkg/w32/comdlg32.go
new file mode 100644
index 000000000..d28922c33
--- /dev/null
+++ b/v3/pkg/w32/comdlg32.go
@@ -0,0 +1,40 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 The Winc Authors. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modcomdlg32 = syscall.NewLazyDLL("comdlg32.dll")
+
+ procGetSaveFileName = modcomdlg32.NewProc("GetSaveFileNameW")
+ procGetOpenFileName = modcomdlg32.NewProc("GetOpenFileNameW")
+ procCommDlgExtendedError = modcomdlg32.NewProc("CommDlgExtendedError")
+)
+
+func GetOpenFileName(ofn *OPENFILENAME) bool {
+ ret, _, _ := procGetOpenFileName.Call(
+ uintptr(unsafe.Pointer(ofn)))
+
+ return ret != 0
+}
+
+func GetSaveFileName(ofn *OPENFILENAME) bool {
+ ret, _, _ := procGetSaveFileName.Call(
+ uintptr(unsafe.Pointer(ofn)))
+
+ return ret != 0
+}
+
+func CommDlgExtendedError() uint {
+ ret, _, _ := procCommDlgExtendedError.Call()
+
+ return uint(ret)
+}
diff --git a/v3/pkg/w32/constants.go b/v3/pkg/w32/constants.go
new file mode 100644
index 000000000..50085a6e6
--- /dev/null
+++ b/v3/pkg/w32/constants.go
@@ -0,0 +1,3731 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 The Winc Authors. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+const (
+ FALSE = 0
+ TRUE = 1
+)
+
+const (
+ NO_ERROR = 0
+ ERROR_SUCCESS = 0
+ ERROR_FILE_NOT_FOUND = 2
+ ERROR_PATH_NOT_FOUND = 3
+ ERROR_ACCESS_DENIED = 5
+ ERROR_INVALID_HANDLE = 6
+ ERROR_BAD_FORMAT = 11
+ ERROR_INVALID_NAME = 123
+ ERROR_MORE_DATA = 234
+ ERROR_NO_MORE_ITEMS = 259
+ ERROR_INVALID_SERVICE_CONTROL = 1052
+ ERROR_SERVICE_REQUEST_TIMEOUT = 1053
+ ERROR_SERVICE_NO_THREAD = 1054
+ ERROR_SERVICE_DATABASE_LOCKED = 1055
+ ERROR_SERVICE_ALREADY_RUNNING = 1056
+ ERROR_SERVICE_DISABLED = 1058
+ ERROR_SERVICE_DOES_NOT_EXIST = 1060
+ ERROR_SERVICE_CANNOT_ACCEPT_CTRL = 1061
+ ERROR_SERVICE_NOT_ACTIVE = 1062
+ ERROR_DATABASE_DOES_NOT_EXIST = 1065
+ ERROR_SERVICE_DEPENDENCY_FAIL = 1068
+ ERROR_SERVICE_LOGON_FAILED = 1069
+ ERROR_SERVICE_MARKED_FOR_DELETE = 1072
+ ERROR_SERVICE_DEPENDENCY_DELETED = 1075
+)
+
+const (
+ SE_ERR_FNF = 2
+ SE_ERR_PNF = 3
+ SE_ERR_ACCESSDENIED = 5
+ SE_ERR_OOM = 8
+ SE_ERR_DLLNOTFOUND = 32
+ SE_ERR_SHARE = 26
+ SE_ERR_ASSOCINCOMPLETE = 27
+ SE_ERR_DDETIMEOUT = 28
+ SE_ERR_DDEFAIL = 29
+ SE_ERR_DDEBUSY = 30
+ SE_ERR_NOASSOC = 31
+)
+
+const (
+ EDS_ROTATEDMODE = 0x00000001
+ EDS_RAWMODE = 0x00000002
+ DMDO_DEFAULT = 0
+ DMDO_90 = 1
+ DMDO_180 = 2
+ DMDO_270 = 3
+)
+
+const (
+ CW_USEDEFAULT = ^0x7fffffff
+)
+
+const (
+ IMAGE_BITMAP = 0
+ IMAGE_ICON = 1
+ IMAGE_CURSOR = 2
+ IMAGE_ENHMETAFILE = 3
+)
+
+// SetProcessDpiAwareness constants
+const (
+ PROCESS_DPI_UNAWARE = 0
+ PROCESS_SYSTEM_DPI_AWARE = 1
+ PROCESS_PER_MONITOR_DPI_AWARE = 2
+)
+
+// SetProcessDpiAwarenessContext constants
+// Credit: https://github.com/ncruces/zenity
+const (
+ DPI_AWARENESS_CONTEXT_UNAWARE = ^uintptr(1) + 1
+ DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = ^uintptr(2) + 1
+ DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = ^uintptr(3) + 1
+ DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = ^uintptr(4) + 1
+ DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED = ^uintptr(5) + 1
+)
+
+// ShowWindow constants
+const (
+ SW_HIDE = 0
+ SW_NORMAL = 1
+ SW_SHOWNORMAL = 1
+ SW_SHOWMINIMIZED = 2
+ SW_MAXIMIZE = 3
+ SW_SHOWMAXIMIZED = 3
+ SW_SHOWNOACTIVATE = 4
+ SW_SHOW = 5
+ SW_MINIMIZE = 6
+ SW_SHOWMINNOACTIVE = 7
+ SW_SHOWNA = 8
+ SW_RESTORE = 9
+ SW_SHOWDEFAULT = 10
+ SW_FORCEMINIMIZE = 11
+)
+
+// Window class styles
+const (
+ CS_VREDRAW = 0x00000001
+ CS_HREDRAW = 0x00000002
+ CS_KEYCVTWINDOW = 0x00000004
+ CS_DBLCLKS = 0x00000008
+ CS_OWNDC = 0x00000020
+ CS_CLASSDC = 0x00000040
+ CS_PARENTDC = 0x00000080
+ CS_NOKEYCVT = 0x00000100
+ CS_NOCLOSE = 0x00000200
+ CS_SAVEBITS = 0x00000800
+ CS_BYTEALIGNCLIENT = 0x00001000
+ CS_BYTEALIGNWINDOW = 0x00002000
+ CS_GLOBALCLASS = 0x00004000
+ CS_IME = 0x00010000
+ CS_DROPSHADOW = 0x00020000
+)
+
+// Predefined cursor constants
+const (
+ IDC_ARROW = 32512
+ IDC_IBEAM = 32513
+ IDC_WAIT = 32514
+ IDC_CROSS = 32515
+ IDC_UPARROW = 32516
+ IDC_SIZENWSE = 32642
+ IDC_SIZENESW = 32643
+ IDC_SIZEWE = 32644
+ IDC_SIZENS = 32645
+ IDC_SIZEALL = 32646
+ IDC_NO = 32648
+ IDC_HAND = 32649
+ IDC_APPSTARTING = 32650
+ IDC_HELP = 32651
+ IDC_ICON = 32641
+ IDC_SIZE = 32640
+)
+
+// Predefined icon constants
+const (
+ IDI_APPLICATION = 32512
+ IDI_HAND = 32513
+ IDI_QUESTION = 32514
+ IDI_EXCLAMATION = 32515
+ IDI_ASTERISK = 32516
+ IDI_WINLOGO = 32517
+ IDI_WARNING = IDI_EXCLAMATION
+ IDI_ERROR = IDI_HAND
+ IDI_INFORMATION = IDI_ASTERISK
+)
+
+const (
+ RT_CURSOR = 1 // win32.MAKEINTRESOURCE(1)
+ RT_BITMAP = 2
+ RT_ICON = 3
+ RT_MENU = 4
+ RT_DIALOG = 5
+ RT_STRING = 6
+ RT_FONTDIR = 7
+ RT_FONT = 8
+ RT_ACCELERATOR = 9
+ RT_RCDATA = 10
+ RT_MESSAGETABLE = 11
+ RT_GROUP_CURSOR = 12
+ RT_GROUP_ICON = 14
+ RT_VERSION = 16
+ RT_DLGINCLUDE = 17
+ RT_PLUGPLAY = 19
+ RT_VXD = 20
+ RT_ANICURSOR = 21
+ RT_ANIICON = 22
+ RT_HTML = 23
+ RT_MANIFEST = 24
+)
+
+// Button style constants
+const (
+ BS_3STATE = 5
+ BS_AUTO3STATE = 6
+ BS_AUTOCHECKBOX = 3
+ BS_AUTORADIOBUTTON = 9
+ BS_BITMAP = 128
+ BS_BOTTOM = 0x800
+ BS_CENTER = 0x300
+ BS_CHECKBOX = 2
+ BS_DEFPUSHBUTTON = 1
+ BS_GROUPBOX = 7
+ BS_ICON = 64
+ BS_LEFT = 256
+ BS_LEFTTEXT = 32
+ BS_MULTILINE = 0x2000
+ BS_NOTIFY = 0x4000
+ BS_OWNERDRAW = 0xB
+ BS_PUSHBUTTON = 0
+ BS_PUSHLIKE = 4096
+ BS_RADIOBUTTON = 4
+ BS_RIGHT = 512
+ BS_RIGHTBUTTON = 32
+ BS_TEXT = 0
+ BS_TOP = 0x400
+ BS_USERBUTTON = 8
+ BS_VCENTER = 0xC00
+ BS_FLAT = 0x8000
+ BS_SPLITBUTTON = 0x000C // >= Vista
+ BS_DEFSPLITBUTTON = 0x000D // >= Vista
+)
+
+// Button state constants
+const (
+ BST_CHECKED = 1
+ BST_INDETERMINATE = 2
+ BST_UNCHECKED = 0
+ BST_FOCUS = 8
+ BST_PUSHED = 4
+)
+
+// Predefined brushes constants
+const (
+ COLOR_3DDKSHADOW = 21
+ COLOR_3DFACE = 15
+ COLOR_3DHILIGHT = 20
+ COLOR_3DHIGHLIGHT = 20
+ COLOR_3DLIGHT = 22
+ COLOR_BTNHILIGHT = 20
+ COLOR_3DSHADOW = 16
+ COLOR_ACTIVEBORDER = 10
+ COLOR_ACTIVECAPTION = 2
+ COLOR_APPWORKSPACE = 12
+ COLOR_BACKGROUND = 1
+ COLOR_DESKTOP = 1
+ COLOR_BTNFACE = 15
+ COLOR_BTNHIGHLIGHT = 20
+ COLOR_BTNSHADOW = 16
+ COLOR_BTNTEXT = 18
+ COLOR_CAPTIONTEXT = 9
+ COLOR_GRAYTEXT = 17
+ COLOR_HIGHLIGHT = 13
+ COLOR_HIGHLIGHTTEXT = 14
+ COLOR_INACTIVEBORDER = 11
+ COLOR_INACTIVECAPTION = 3
+ COLOR_INACTIVECAPTIONTEXT = 19
+ COLOR_INFOBK = 24
+ COLOR_INFOTEXT = 23
+ COLOR_MENU = 4
+ COLOR_MENUTEXT = 7
+ COLOR_SCROLLBAR = 0
+ COLOR_WINDOW = 5
+ COLOR_WINDOWFRAME = 6
+ COLOR_WINDOWTEXT = 8
+ COLOR_HOTLIGHT = 26
+ COLOR_GRADIENTACTIVECAPTION = 27
+ COLOR_GRADIENTINACTIVECAPTION = 28
+)
+
+// Button message constants
+const (
+ BM_CLICK = 245
+ BM_GETCHECK = 240
+ BM_GETIMAGE = 246
+ BM_GETSTATE = 242
+ BM_SETCHECK = 241
+ BM_SETIMAGE = 247
+ BM_SETSTATE = 243
+ BM_SETSTYLE = 244
+)
+
+// Button notifications
+const (
+ BN_CLICKED = 0
+ BN_PAINT = 1
+ BN_HILITE = 2
+ BN_PUSHED = BN_HILITE
+ BN_UNHILITE = 3
+ BN_UNPUSHED = BN_UNHILITE
+ BN_DISABLE = 4
+ BN_DOUBLECLICKED = 5
+ BN_DBLCLK = BN_DOUBLECLICKED
+ BN_SETFOCUS = 6
+ BN_KILLFOCUS = 7
+)
+
+// TrackPopupMenu[Ex] flags
+const (
+ TPM_CENTERALIGN = 0x0004
+ TPM_LEFTALIGN = 0x0000
+ TPM_RIGHTALIGN = 0x0008
+ TPM_BOTTOMALIGN = 0x0020
+ TPM_TOPALIGN = 0x0000
+ TPM_VCENTERALIGN = 0x0010
+ TPM_NONOTIFY = 0x0080
+ TPM_RETURNCMD = 0x0100
+ TPM_LEFTBUTTON = 0x0000
+ TPM_RIGHTBUTTON = 0x0002
+ TPM_HORNEGANIMATION = 0x0800
+ TPM_HORPOSANIMATION = 0x0400
+ TPM_NOANIMATION = 0x4000
+ TPM_VERNEGANIMATION = 0x2000
+ TPM_VERPOSANIMATION = 0x1000
+ TPM_HORIZONTAL = 0x0000
+ TPM_VERTICAL = 0x0040
+)
+
+// GetWindowLong and GetWindowLongPtr constants
+const (
+ GWL_EXSTYLE = -20
+ GWL_STYLE = -16
+ GWL_WNDPROC = -4
+ GWLP_WNDPROC = -4
+ GWL_HINSTANCE = -6
+ GWLP_HINSTANCE = -6
+ GWL_HWNDPARENT = -8
+ GWLP_HWNDPARENT = -8
+ GWL_ID = -12
+ GWLP_ID = -12
+ GWL_USERDATA = -21
+ GWLP_USERDATA = -21
+)
+
+const (
+ GW_HWNDFIRST = 0
+ GW_HWNDLAST = 1
+ GW_HWNDNEXT = 2
+ GW_HWNDPREV = 3
+ GW_OWNER = 4
+ GW_CHILD = 5
+ GW_ENABLEDPOPUP = 6
+)
+
+// Window style constants
+const (
+ WS_OVERLAPPED = 0x00000000
+ WS_POPUP = 0x80000000
+ WS_CHILD = 0x40000000
+ WS_MINIMIZE = 0x20000000
+ WS_VISIBLE = 0x10000000
+ WS_DISABLED = 0x08000000
+ WS_CLIPSIBLINGS = 0x04000000
+ WS_CLIPCHILDREN = 0x02000000
+ WS_MAXIMIZE = 0x01000000
+ WS_CAPTION = 0x00C00000
+ WS_BORDER = 0x00800000
+ WS_DLGFRAME = 0x00400000
+ WS_VSCROLL = 0x00200000
+ WS_HSCROLL = 0x00100000
+ WS_SYSMENU = 0x00080000
+ WS_THICKFRAME = 0x00040000
+ WS_GROUP = 0x00020000
+ WS_TABSTOP = 0x00010000
+ WS_MINIMIZEBOX = 0x00020000
+ WS_MAXIMIZEBOX = 0x00010000
+ WS_TILED = 0x00000000
+ WS_ICONIC = 0x20000000
+ WS_SIZEBOX = 0x00040000
+ WS_OVERLAPPEDWINDOW = 0x00000000 | 0x00C00000 | 0x00080000 | 0x00040000 | 0x00020000 | 0x00010000
+ WS_POPUPWINDOW = 0x80000000 | 0x00800000 | 0x00080000
+ WS_CHILDWINDOW = 0x40000000
+)
+
+// Extended window style constants
+const (
+ WS_EX_DLGMODALFRAME = 0x00000001
+ WS_EX_NOPARENTNOTIFY = 0x00000004
+ WS_EX_TOPMOST = 0x00000008
+ WS_EX_ACCEPTFILES = 0x00000010
+ WS_EX_TRANSPARENT = 0x00000020
+ WS_EX_MDICHILD = 0x00000040
+ WS_EX_TOOLWINDOW = 0x00000080
+ WS_EX_WINDOWEDGE = 0x00000100
+ WS_EX_CLIENTEDGE = 0x00000200
+ WS_EX_CONTEXTHELP = 0x00000400
+ WS_EX_COMPOSITED = 0x02000000
+ WS_EX_RIGHT = 0x00001000
+ WS_EX_LEFT = 0x00000000
+ WS_EX_RTLREADING = 0x00002000
+ WS_EX_LTRREADING = 0x00000000
+ WS_EX_LEFTSCROLLBAR = 0x00004000
+ WS_EX_RIGHTSCROLLBAR = 0x00000000
+ WS_EX_CONTROLPARENT = 0x00010000
+ WS_EX_STATICEDGE = 0x00020000
+ WS_EX_APPWINDOW = 0x00040000
+ WS_EX_OVERLAPPEDWINDOW = 0x00000100 | 0x00000200
+ WS_EX_PALETTEWINDOW = 0x00000100 | 0x00000080 | 0x00000008
+ WS_EX_LAYERED = 0x00080000
+ WS_EX_NOINHERITLAYOUT = 0x00100000
+ WS_EX_NOREDIRECTIONBITMAP = 0x00200000
+ WS_EX_LAYOUTRTL = 0x00400000
+ WS_EX_NOACTIVATE = 0x08000000
+)
+
+// Window message constants
+const (
+ WM_APP = 32768
+ WM_ACTIVATE = 6
+ WM_ACTIVATEAPP = 28
+ WM_AFXFIRST = 864
+ WM_AFXLAST = 895
+ WM_ASKCBFORMATNAME = 780
+ WM_CANCELJOURNAL = 75
+ WM_CANCELMODE = 31
+ WM_CAPTURECHANGED = 533
+ WM_CHANGECBCHAIN = 781
+ WM_CHAR = 258
+ WM_CHARTOITEM = 47
+ WM_CHILDACTIVATE = 34
+ WM_CLEAR = 771
+ WM_CLOSE = 16
+ WM_COMMAND = 273
+ WM_COMMNOTIFY = 68 /* OBSOLETE */
+ WM_COMPACTING = 65
+ WM_COMPAREITEM = 57
+ WM_CONTEXTMENU = 123
+ WM_COPY = 769
+ WM_COPYDATA = 74
+ WM_CREATE = 1
+ WM_CTLCOLORBTN = 309
+ WM_CTLCOLORDLG = 310
+ WM_CTLCOLOREDIT = 307
+ WM_CTLCOLORLISTBOX = 308
+ WM_CTLCOLORMSGBOX = 306
+ WM_CTLCOLORSCROLLBAR = 311
+ WM_CTLCOLORSTATIC = 312
+ WM_CUT = 768
+ WM_DEADCHAR = 259
+ WM_DELETEITEM = 45
+ WM_DESTROY = 2
+ WM_DESTROYCLIPBOARD = 775
+ WM_DEVICECHANGE = 537
+ WM_DEVMODECHANGE = 27
+ WM_DISPLAYCHANGE = 126
+ WM_DRAWCLIPBOARD = 776
+ WM_DRAWITEM = 43
+ WM_DROPFILES = 563
+ WM_ENABLE = 10
+ WM_ENDSESSION = 22
+ WM_ENTERIDLE = 289
+ WM_ENTERMENULOOP = 529
+ WM_ENTERSIZEMOVE = 561
+ WM_ERASEBKGND = 20
+ WM_EXITMENULOOP = 530
+ WM_EXITSIZEMOVE = 562
+ WM_FONTCHANGE = 29
+ WM_GETDLGCODE = 135
+ WM_GETFONT = 49
+ WM_GETHOTKEY = 51
+ WM_GETICON = 127
+ WM_GETMINMAXINFO = 36
+ WM_GETTEXT = 13
+ WM_GETTEXTLENGTH = 14
+ WM_HANDHELDFIRST = 856
+ WM_HANDHELDLAST = 863
+ WM_HELP = 83
+ WM_HOTKEY = 786
+ WM_HSCROLL = 276
+ WM_HSCROLLCLIPBOARD = 782
+ WM_ICONERASEBKGND = 39
+ WM_INITDIALOG = 272
+ WM_INITMENU = 278
+ WM_INITMENUPOPUP = 279
+ WM_INPUT = 0x00FF
+ WM_INPUTLANGCHANGE = 81
+ WM_INPUTLANGCHANGEREQUEST = 80
+ WM_KEYDOWN = 256
+ WM_KEYUP = 257
+ WM_KILLFOCUS = 8
+ WM_MDIACTIVATE = 546
+ WM_MDICASCADE = 551
+ WM_MDICREATE = 544
+ WM_MDIDESTROY = 545
+ WM_MDIGETACTIVE = 553
+ WM_MDIICONARRANGE = 552
+ WM_MDIMAXIMIZE = 549
+ WM_MDINEXT = 548
+ WM_MDIREFRESHMENU = 564
+ WM_MDIRESTORE = 547
+ WM_MDISETMENU = 560
+ WM_MDITILE = 550
+ WM_MEASUREITEM = 44
+ WM_GETOBJECT = 0x003D
+ WM_CHANGEUISTATE = 0x0127
+ WM_UPDATEUISTATE = 0x0128
+ WM_QUERYUISTATE = 0x0129
+ WM_UNINITMENUPOPUP = 0x0125
+ WM_MENURBUTTONUP = 290
+ WM_MENUCOMMAND = 0x0126
+ WM_MENUGETOBJECT = 0x0124
+ WM_MENUDRAG = 0x0123
+ WM_APPCOMMAND = 0x0319
+ WM_MENUCHAR = 288
+ WM_MENUSELECT = 287
+ WM_MOVE = 3
+ WM_MOVING = 534
+ WM_NCACTIVATE = 134
+ WM_NCCALCSIZE = 131
+ WM_NCCREATE = 129
+ WM_NCDESTROY = 130
+ WM_NCHITTEST = 132
+ WM_NCLBUTTONDBLCLK = 163
+ WM_NCLBUTTONDOWN = 161
+ WM_NCLBUTTONUP = 162
+ WM_NCMBUTTONDBLCLK = 169
+ WM_NCMBUTTONDOWN = 167
+ WM_NCMBUTTONUP = 168
+ WM_NCXBUTTONDOWN = 171
+ WM_NCXBUTTONUP = 172
+ WM_NCXBUTTONDBLCLK = 173
+ WM_NCMOUSEHOVER = 0x02A0
+ WM_NCMOUSELEAVE = 0x02A2
+ WM_NCMOUSEMOVE = 160
+ WM_NCPAINT = 133
+ WM_NCRBUTTONDBLCLK = 166
+ WM_NCRBUTTONDOWN = 164
+ WM_NCRBUTTONUP = 165
+ WM_NEXTDLGCTL = 40
+ WM_NEXTMENU = 531
+ WM_NOTIFY = 78
+ WM_NOTIFYFORMAT = 85
+ WM_NULL = 0
+ WM_PAINT = 15
+ WM_PAINTCLIPBOARD = 777
+ WM_PAINTICON = 38
+ WM_UAHDRAWMENU = 0x0091
+ WM_UAHDRAWMENUITEM = 0x0092
+ WM_UAHMEASUREMENUITEM = 0x0094
+ WM_PALETTECHANGED = 785
+ WM_PALETTEISCHANGING = 784
+ WM_PARENTNOTIFY = 528
+ WM_PASTE = 770
+ WM_PENWINFIRST = 896
+ WM_PENWINLAST = 911
+ WM_POWER = 72
+ WM_POWERBROADCAST = 536
+ WM_PRINT = 791
+ WM_PRINTCLIENT = 792
+ WM_QUERYDRAGICON = 55
+ WM_QUERYENDSESSION = 17
+ WM_QUERYNEWPALETTE = 783
+ WM_QUERYOPEN = 19
+ WM_QUEUESYNC = 35
+ WM_QUIT = 18
+ WM_RENDERALLFORMATS = 774
+ WM_RENDERFORMAT = 773
+ WM_SETCURSOR = 32
+ WM_SETFOCUS = 7
+ WM_SETFONT = 48
+ WM_SETHOTKEY = 50
+ WM_SETICON = 128
+ WM_SETREDRAW = 11
+ WM_SETTEXT = 12
+ WM_SETTINGCHANGE = 26
+ WM_SHOWWINDOW = 24
+ WM_SIZE = 5
+ WM_SIZECLIPBOARD = 779
+ WM_SIZING = 532
+ WM_SPOOLERSTATUS = 42
+ WM_STYLECHANGED = 125
+ WM_STYLECHANGING = 124
+ WM_SYSCHAR = 262
+ WM_SYSCOLORCHANGE = 21
+ WM_SYSCOMMAND = 274
+ WM_SYSDEADCHAR = 263
+ WM_SYSKEYDOWN = 260
+ WM_SYSKEYUP = 261
+ WM_TCARD = 82
+ WM_THEMECHANGED = 794
+ WM_TIMECHANGE = 30
+ WM_TIMER = 275
+ WM_UNDO = 772
+ WM_USER = 1024
+ WM_USERCHANGED = 84
+ WM_VKEYTOITEM = 46
+ WM_VSCROLL = 277
+ WM_VSCROLLCLIPBOARD = 778
+ WM_WINDOWPOSCHANGED = 71
+ WM_WINDOWPOSCHANGING = 70
+ WM_SELECTALL = 0x00B1
+ WM_WININICHANGE = 26
+ WM_KEYFIRST = 256
+ WM_KEYLAST = 264
+ WM_SYNCPAINT = 136
+ WM_MOUSEACTIVATE = 33
+ WM_MOUSEMOVE = 512
+ WM_LBUTTONDOWN = 513
+ WM_LBUTTONUP = 514
+ WM_LBUTTONDBLCLK = 515
+ WM_RBUTTONDOWN = 516
+ WM_RBUTTONUP = 517
+ WM_RBUTTONDBLCLK = 518
+ WM_MBUTTONDOWN = 519
+ WM_MBUTTONUP = 520
+ WM_MBUTTONDBLCLK = 521
+ WM_MOUSEWHEEL = 522
+ WM_MOUSEHWHEEL = 526
+ WM_MOUSEFIRST = 512
+ WM_XBUTTONDOWN = 523
+ WM_XBUTTONUP = 524
+ WM_XBUTTONDBLCLK = 525
+ WM_MOUSELAST = 525
+ WM_MOUSEHOVER = 0x2A1
+ WM_MOUSELEAVE = 0x2A3
+ WM_CLIPBOARDUPDATE = 0x031D
+ WM_DPICHANGED = 0x02E0
+)
+
+const (
+ SC_SIZE = 0xF000 // Resize the window
+ SC_MOVE = 0xF010 // Move the window
+ SC_MINIMIZE = 0xF020 // Minimize the window
+ SC_MAXIMIZE = 0xF030 // Maximize the window
+ SC_NEXTWINDOW = 0xF040 // Move to next window
+ SC_PREVWINDOW = 0xF050 // Move to previous window
+ SC_CLOSE = 0xF060 // Close the window
+ SC_VSCROLL = 0xF070 // Vertical scroll
+ SC_HSCROLL = 0xF080 // Horizontal scroll
+ SC_MOUSEMENU = 0xF090 // Mouse menu
+ SC_KEYMENU = 0xF100 // Key menu (triggered by Alt or F10)
+ SC_ARRANGE = 0xF110 // Arrange windows
+ SC_RESTORE = 0xF120 // Restore window from minimized/maximized
+ SC_TASKLIST = 0xF130 // Task list
+ SC_SCREENSAVE = 0xF140 // Screen saver
+ SC_HOTKEY = 0xF150 // Hotkey
+ SC_DEFAULT = 0xF160 // Default command
+ SC_MONITORPOWER = 0xF170 // Monitor power
+ SC_CONTEXTHELP = 0xF180 // Context help
+ SC_SEPARATOR = 0xF00F // Separator
+)
+
+const (
+ // Remove the Close option from the window menu
+ SC_MASK_CLOSE = ^uint16(SC_CLOSE)
+ // Mask for extracting the system command
+ SC_MASK_CMD = 0xFFF0
+)
+
+// WM_ACTIVATE
+const (
+ WA_INACTIVE = 0
+ WA_ACTIVE = 1
+ WA_CLICKACTIVE = 2
+)
+
+const LF_FACESIZE = 32
+
+// Font weight constants
+const (
+ FW_DONTCARE = 0
+ FW_THIN = 100
+ FW_EXTRALIGHT = 200
+ FW_ULTRALIGHT = FW_EXTRALIGHT
+ FW_LIGHT = 300
+ FW_NORMAL = 400
+ FW_REGULAR = 400
+ FW_MEDIUM = 500
+ FW_SEMIBOLD = 600
+ FW_DEMIBOLD = FW_SEMIBOLD
+ FW_BOLD = 700
+ FW_EXTRABOLD = 800
+ FW_ULTRABOLD = FW_EXTRABOLD
+ FW_HEAVY = 900
+ FW_BLACK = FW_HEAVY
+)
+
+// Charset constants
+const (
+ ANSI_CHARSET = 0
+ DEFAULT_CHARSET = 1
+ SYMBOL_CHARSET = 2
+ SHIFTJIS_CHARSET = 128
+ HANGEUL_CHARSET = 129
+ HANGUL_CHARSET = 129
+ GB2312_CHARSET = 134
+ CHINESEBIG5_CHARSET = 136
+ GREEK_CHARSET = 161
+ TURKISH_CHARSET = 162
+ HEBREW_CHARSET = 177
+ ARABIC_CHARSET = 178
+ BALTIC_CHARSET = 186
+ RUSSIAN_CHARSET = 204
+ THAI_CHARSET = 222
+ EASTEUROPE_CHARSET = 238
+ OEM_CHARSET = 255
+ JOHAB_CHARSET = 130
+ VIETNAMESE_CHARSET = 163
+ MAC_CHARSET = 77
+)
+
+const (
+ // PBT_APMPOWERSTATUSCHANGE - Power status has changed.
+ PBT_APMPOWERSTATUSCHANGE = 10
+
+ // PBT_APMRESUMEAUTOMATIC -Operation is resuming automatically from a low-power state. This message is sent every time the system resumes.
+ PBT_APMRESUMEAUTOMATIC = 18
+
+ // PBT_APMRESUMESUSPEND - Operation is resuming from a low-power state. This message is sent after PBT_APMRESUMEAUTOMATIC if the resume is triggered by user input, such as pressing a key.
+ PBT_APMRESUMESUSPEND = 7
+
+ // PBT_APMSUSPEND - System is suspending operation.
+ PBT_APMSUSPEND = 4
+
+ // PBT_POWERSETTINGCHANGE - A power setting change event has been received.
+ PBT_POWERSETTINGCHANGE = 32787
+)
+
+// Font output precision constants
+const (
+ OUT_DEFAULT_PRECIS = 0
+ OUT_STRING_PRECIS = 1
+ OUT_CHARACTER_PRECIS = 2
+ OUT_STROKE_PRECIS = 3
+ OUT_TT_PRECIS = 4
+ OUT_DEVICE_PRECIS = 5
+ OUT_RASTER_PRECIS = 6
+ OUT_TT_ONLY_PRECIS = 7
+ OUT_OUTLINE_PRECIS = 8
+ OUT_PS_ONLY_PRECIS = 10
+)
+
+// Font clipping precision constants
+const (
+ CLIP_DEFAULT_PRECIS = 0
+ CLIP_CHARACTER_PRECIS = 1
+ CLIP_STROKE_PRECIS = 2
+ CLIP_MASK = 15
+ CLIP_LH_ANGLES = 16
+ CLIP_TT_ALWAYS = 32
+ CLIP_EMBEDDED = 128
+)
+
+// Font output quality constants
+const (
+ DEFAULT_QUALITY = 0
+ DRAFT_QUALITY = 1
+ PROOF_QUALITY = 2
+ NONANTIALIASED_QUALITY = 3
+ ANTIALIASED_QUALITY = 4
+ CLEARTYPE_QUALITY = 5
+)
+
+// Font pitch constants
+const (
+ DEFAULT_PITCH = 0
+ FIXED_PITCH = 1
+ VARIABLE_PITCH = 2
+)
+
+// Font family constants
+const (
+ FF_DECORATIVE = 80
+ FF_DONTCARE = 0
+ FF_MODERN = 48
+ FF_ROMAN = 16
+ FF_SCRIPT = 64
+ FF_SWISS = 32
+)
+
+// DeviceCapabilities capabilities
+const (
+ DC_FIELDS = 1
+ DC_PAPERS = 2
+ DC_PAPERSIZE = 3
+ DC_MINEXTENT = 4
+ DC_MAXEXTENT = 5
+ DC_BINS = 6
+ DC_DUPLEX = 7
+ DC_SIZE = 8
+ DC_EXTRA = 9
+ DC_VERSION = 10
+ DC_DRIVER = 11
+ DC_BINNAMES = 12
+ DC_ENUMRESOLUTIONS = 13
+ DC_FILEDEPENDENCIES = 14
+ DC_TRUETYPE = 15
+ DC_PAPERNAMES = 16
+ DC_ORIENTATION = 17
+ DC_COPIES = 18
+ DC_BINADJUST = 19
+ DC_EMF_COMPLIANT = 20
+ DC_DATATYPE_PRODUCED = 21
+ DC_COLLATE = 22
+ DC_MANUFACTURER = 23
+ DC_MODEL = 24
+ DC_PERSONALITY = 25
+ DC_PRINTRATE = 26
+ DC_PRINTRATEUNIT = 27
+ DC_PRINTERMEM = 28
+ DC_MEDIAREADY = 29
+ DC_STAPLE = 30
+ DC_PRINTRATEPPM = 31
+ DC_COLORDEVICE = 32
+ DC_NUP = 33
+ DC_MEDIATYPENAMES = 34
+ DC_MEDIATYPES = 35
+)
+
+// GetDeviceCaps index constants
+const (
+ DRIVERVERSION = 0
+ TECHNOLOGY = 2
+ HORZSIZE = 4
+ VERTSIZE = 6
+ HORZRES = 8
+ VERTRES = 10
+ LOGPIXELSX = 88
+ LOGPIXELSY = 90
+ BITSPIXEL = 12
+ PLANES = 14
+ NUMBRUSHES = 16
+ NUMPENS = 18
+ NUMFONTS = 22
+ NUMCOLORS = 24
+ NUMMARKERS = 20
+ ASPECTX = 40
+ ASPECTY = 42
+ ASPECTXY = 44
+ PDEVICESIZE = 26
+ CLIPCAPS = 36
+ SIZEPALETTE = 104
+ NUMRESERVED = 106
+ COLORRES = 108
+ PHYSICALWIDTH = 110
+ PHYSICALHEIGHT = 111
+ PHYSICALOFFSETX = 112
+ PHYSICALOFFSETY = 113
+ SCALINGFACTORX = 114
+ SCALINGFACTORY = 115
+ VREFRESH = 116
+ DESKTOPHORZRES = 118
+ DESKTOPVERTRES = 117
+ BLTALIGNMENT = 119
+ SHADEBLENDCAPS = 120
+ COLORMGMTCAPS = 121
+ RASTERCAPS = 38
+ CURVECAPS = 28
+ LINECAPS = 30
+ POLYGONALCAPS = 32
+ TEXTCAPS = 34
+)
+
+// GetDeviceCaps TECHNOLOGY constants
+const (
+ DT_PLOTTER = 0
+ DT_RASDISPLAY = 1
+ DT_RASPRINTER = 2
+ DT_RASCAMERA = 3
+ DT_CHARSTREAM = 4
+ DT_METAFILE = 5
+ DT_DISPFILE = 6
+)
+
+// GetDeviceCaps SHADEBLENDCAPS constants
+const (
+ SB_NONE = 0x00
+ SB_CONST_ALPHA = 0x01
+ SB_PIXEL_ALPHA = 0x02
+ SB_PREMULT_ALPHA = 0x04
+ SB_GRAD_RECT = 0x10
+ SB_GRAD_TRI = 0x20
+)
+
+// GetDeviceCaps COLORMGMTCAPS constants
+const (
+ CM_NONE = 0x00
+ CM_DEVICE_ICM = 0x01
+ CM_GAMMA_RAMP = 0x02
+ CM_CMYK_COLOR = 0x04
+)
+
+// GetDeviceCaps RASTERCAPS constants
+const (
+ RC_BANDING = 2
+ RC_BITBLT = 1
+ RC_BITMAP64 = 8
+ RC_DI_BITMAP = 128
+ RC_DIBTODEV = 512
+ RC_FLOODFILL = 4096
+ RC_GDI20_OUTPUT = 16
+ RC_PALETTE = 256
+ RC_SCALING = 4
+ RC_STRETCHBLT = 2048
+ RC_STRETCHDIB = 8192
+ RC_DEVBITS = 0x8000
+ RC_OP_DX_OUTPUT = 0x4000
+)
+
+// GetDeviceCaps CURVECAPS constants
+const (
+ CC_NONE = 0
+ CC_CIRCLES = 1
+ CC_PIE = 2
+ CC_CHORD = 4
+ CC_ELLIPSES = 8
+ CC_WIDE = 16
+ CC_STYLED = 32
+ CC_WIDESTYLED = 64
+ CC_INTERIORS = 128
+ CC_ROUNDRECT = 256
+)
+
+// GetDeviceCaps LINECAPS constants
+const (
+ LC_NONE = 0
+ LC_POLYLINE = 2
+ LC_MARKER = 4
+ LC_POLYMARKER = 8
+ LC_WIDE = 16
+ LC_STYLED = 32
+ LC_WIDESTYLED = 64
+ LC_INTERIORS = 128
+)
+
+// GetDeviceCaps POLYGONALCAPS constants
+const (
+ PC_NONE = 0
+ PC_POLYGON = 1
+ PC_POLYPOLYGON = 256
+ PC_PATHS = 512
+ PC_RECTANGLE = 2
+ PC_WINDPOLYGON = 4
+ PC_SCANLINE = 8
+ PC_TRAPEZOID = 4
+ PC_WIDE = 16
+ PC_STYLED = 32
+ PC_WIDESTYLED = 64
+ PC_INTERIORS = 128
+)
+
+// GetDeviceCaps TEXTCAPS constants
+const (
+ TC_OP_CHARACTER = 1
+ TC_OP_STROKE = 2
+ TC_CP_STROKE = 4
+ TC_CR_90 = 8
+ TC_CR_ANY = 16
+ TC_SF_X_YINDEP = 32
+ TC_SA_DOUBLE = 64
+ TC_SA_INTEGER = 128
+ TC_SA_CONTIN = 256
+ TC_EA_DOUBLE = 512
+ TC_IA_ABLE = 1024
+ TC_UA_ABLE = 2048
+ TC_SO_ABLE = 4096
+ TC_RA_ABLE = 8192
+ TC_VA_ABLE = 16384
+ TC_RESERVED = 32768
+ TC_SCROLLBLT = 65536
+)
+
+// Static control styles
+const (
+ SS_BITMAP = 14
+ SS_BLACKFRAME = 7
+ SS_BLACKRECT = 4
+ SS_CENTER = 1
+ SS_CENTERIMAGE = 512
+ SS_EDITCONTROL = 0x2000
+ SS_ENHMETAFILE = 15
+ SS_ETCHEDFRAME = 18
+ SS_ETCHEDHORZ = 16
+ SS_ETCHEDVERT = 17
+ SS_GRAYFRAME = 8
+ SS_GRAYRECT = 5
+ SS_ICON = 3
+ SS_LEFT = 0
+ SS_LEFTNOWORDWRAP = 0xc
+ SS_NOPREFIX = 128
+ SS_NOTIFY = 256
+ SS_OWNERDRAW = 0xd
+ SS_REALSIZECONTROL = 0x040
+ SS_REALSIZEIMAGE = 0x800
+ SS_RIGHT = 2
+ SS_RIGHTJUST = 0x400
+ SS_SIMPLE = 11
+ SS_SUNKEN = 4096
+ SS_WHITEFRAME = 9
+ SS_WHITERECT = 6
+ SS_USERITEM = 10
+ SS_TYPEMASK = 0x0000001F
+ SS_ENDELLIPSIS = 0x00004000
+ SS_PATHELLIPSIS = 0x00008000
+ SS_WORDELLIPSIS = 0x0000C000
+ SS_ELLIPSISMASK = 0x0000C000
+)
+
+const (
+ FLASHW_STOP = 0 // Stop flashing. The system restores the window to its original state.
+ FLASHW_CAPTION = 1 // Flash the window caption.
+ FLASHW_TRAY = 2 // Flash the taskbar button.
+ FLASHW_ALL = 3 // Flash both the window caption and taskbar button. This is equivalent to setting the FLASHW_CAPTION | FLASHW_TRAY flags.
+ FLASHW_TIMER = 4 // Flash continuously, until the FLASHW_STOP flag is set.
+ FLASHW_TIMERNOFG = 12 // Flash continuously until the window comes to the foreground.
+)
+
+// Edit styles
+const (
+ ES_LEFT = 0x0000
+ ES_CENTER = 0x0001
+ ES_RIGHT = 0x0002
+ ES_MULTILINE = 0x0004
+ ES_UPPERCASE = 0x0008
+ ES_LOWERCASE = 0x0010
+ ES_PASSWORD = 0x0020
+ ES_AUTOVSCROLL = 0x0040
+ ES_AUTOHSCROLL = 0x0080
+ ES_NOHIDESEL = 0x0100
+ ES_OEMCONVERT = 0x0400
+ ES_READONLY = 0x0800
+ ES_WANTRETURN = 0x1000
+ ES_NUMBER = 0x2000
+)
+
+// Edit notifications
+const (
+ EN_SETFOCUS = 0x0100
+ EN_KILLFOCUS = 0x0200
+ EN_CHANGE = 0x0300
+ EN_UPDATE = 0x0400
+ EN_ERRSPACE = 0x0500
+ EN_MAXTEXT = 0x0501
+ EN_HSCROLL = 0x0601
+ EN_VSCROLL = 0x0602
+ EN_ALIGN_LTR_EC = 0x0700
+ EN_ALIGN_RTL_EC = 0x0701
+)
+
+// Edit messages
+const (
+ EM_GETSEL = 0x00B0
+ EM_SETSEL = 0x00B1
+ EM_GETRECT = 0x00B2
+ EM_SETRECT = 0x00B3
+ EM_SETRECTNP = 0x00B4
+ EM_SCROLL = 0x00B5
+ EM_LINESCROLL = 0x00B6
+ EM_SCROLLCARET = 0x00B7
+ EM_GETMODIFY = 0x00B8
+ EM_SETMODIFY = 0x00B9
+ EM_GETLINECOUNT = 0x00BA
+ EM_LINEINDEX = 0x00BB
+ EM_SETHANDLE = 0x00BC
+ EM_GETHANDLE = 0x00BD
+ EM_GETTHUMB = 0x00BE
+ EM_LINELENGTH = 0x00C1
+ EM_REPLACESEL = 0x00C2
+ EM_GETLINE = 0x00C4
+ EM_LIMITTEXT = 0x00C5
+ EM_CANUNDO = 0x00C6
+ EM_UNDO = 0x00C7
+ EM_FMTLINES = 0x00C8
+ EM_LINEFROMCHAR = 0x00C9
+ EM_SETTABSTOPS = 0x00CB
+ EM_SETPASSWORDCHAR = 0x00CC
+ EM_EMPTYUNDOBUFFER = 0x00CD
+ EM_GETFIRSTVISIBLELINE = 0x00CE
+ EM_SETREADONLY = 0x00CF
+ EM_SETWORDBREAKPROC = 0x00D0
+ EM_GETWORDBREAKPROC = 0x00D1
+ EM_GETPASSWORDCHAR = 0x00D2
+ EM_SETMARGINS = 0x00D3
+ EM_GETMARGINS = 0x00D4
+ EM_SETLIMITTEXT = EM_LIMITTEXT
+ EM_GETLIMITTEXT = 0x00D5
+ EM_POSFROMCHAR = 0x00D6
+ EM_CHARFROMPOS = 0x00D7
+ EM_SETIMESTATUS = 0x00D8
+ EM_GETIMESTATUS = 0x00D9
+ EM_SETCUEBANNER = 0x1501
+ EM_GETCUEBANNER = 0x1502
+)
+
+const (
+ CCM_FIRST = 0x2000
+ CCM_LAST = CCM_FIRST + 0x200
+ CCM_SETBKCOLOR = 8193
+ CCM_SETCOLORSCHEME = 8194
+ CCM_GETCOLORSCHEME = 8195
+ CCM_GETDROPTARGET = 8196
+ CCM_SETUNICODEFORMAT = 8197
+ CCM_GETUNICODEFORMAT = 8198
+ CCM_SETVERSION = 0x2007
+ CCM_GETVERSION = 0x2008
+ CCM_SETNOTIFYWINDOW = 0x2009
+ CCM_SETWINDOWTHEME = 0x200b
+ CCM_DPISCALE = 0x200c
+)
+
+// Common controls styles
+const (
+ CCS_TOP = 1
+ CCS_NOMOVEY = 2
+ CCS_BOTTOM = 3
+ CCS_NORESIZE = 4
+ CCS_NOPARENTALIGN = 8
+ CCS_ADJUSTABLE = 32
+ CCS_NODIVIDER = 64
+ CCS_VERT = 128
+ CCS_LEFT = 129
+ CCS_NOMOVEX = 130
+ CCS_RIGHT = 131
+)
+
+// ProgressBar messages
+const (
+ PROGRESS_CLASS = "msctls_progress32"
+ PBM_SETPOS = WM_USER + 2
+ PBM_DELTAPOS = WM_USER + 3
+ PBM_SETSTEP = WM_USER + 4
+ PBM_STEPIT = WM_USER + 5
+ PBM_SETRANGE32 = 1030
+ PBM_GETRANGE = 1031
+ PBM_GETPOS = 1032
+ PBM_SETBARCOLOR = 1033
+ PBM_SETBKCOLOR = CCM_SETBKCOLOR
+ PBS_SMOOTH = 1
+ PBS_VERTICAL = 4
+)
+
+// Trackbar messages and constants
+const (
+ TBS_AUTOTICKS = 1
+ TBS_VERT = 2
+ TBS_HORZ = 0
+ TBS_TOP = 4
+ TBS_BOTTOM = 0
+ TBS_LEFT = 4
+ TBS_RIGHT = 0
+ TBS_BOTH = 8
+ TBS_NOTICKS = 16
+ TBS_ENABLESELRANGE = 32
+ TBS_FIXEDLENGTH = 64
+ TBS_NOTHUMB = 128
+ TBS_TOOLTIPS = 0x0100
+)
+
+const (
+ TBM_GETPOS = WM_USER
+ TBM_GETRANGEMIN = WM_USER + 1
+ TBM_GETRANGEMAX = WM_USER + 2
+ TBM_GETTIC = WM_USER + 3
+ TBM_SETTIC = WM_USER + 4
+ TBM_SETPOS = WM_USER + 5
+ TBM_SETRANGE = WM_USER + 6
+ TBM_SETRANGEMIN = WM_USER + 7
+ TBM_SETRANGEMAX = WM_USER + 8
+ TBM_CLEARTICS = WM_USER + 9
+ TBM_SETSEL = WM_USER + 10
+ TBM_SETSELSTART = WM_USER + 11
+ TBM_SETSELEND = WM_USER + 12
+ TBM_GETPTICS = WM_USER + 14
+ TBM_GETTICPOS = WM_USER + 15
+ TBM_GETNUMTICS = WM_USER + 16
+ TBM_GETSELSTART = WM_USER + 17
+ TBM_GETSELEND = WM_USER + 18
+ TBM_CLEARSEL = WM_USER + 19
+ TBM_SETTICFREQ = WM_USER + 20
+ TBM_SETPAGESIZE = WM_USER + 21
+ TBM_GETPAGESIZE = WM_USER + 22
+ TBM_SETLINESIZE = WM_USER + 23
+ TBM_GETLINESIZE = WM_USER + 24
+ TBM_GETTHUMBRECT = WM_USER + 25
+ TBM_GETCHANNELRECT = WM_USER + 26
+ TBM_SETTHUMBLENGTH = WM_USER + 27
+ TBM_GETTHUMBLENGTH = WM_USER + 28
+ TBM_SETTOOLTIPS = WM_USER + 29
+ TBM_GETTOOLTIPS = WM_USER + 30
+ TBM_SETTIPSIDE = WM_USER + 31
+ TBM_SETBUDDY = WM_USER + 32
+ TBM_GETBUDDY = WM_USER + 33
+)
+
+const (
+ TB_LINEUP = 0
+ TB_LINEDOWN = 1
+ TB_PAGEUP = 2
+ TB_PAGEDOWN = 3
+ TB_THUMBPOSITION = 4
+ TB_THUMBTRACK = 5
+ TB_TOP = 6
+ TB_BOTTOM = 7
+ TB_ENDTRACK = 8
+)
+
+// GetOpenFileName and GetSaveFileName extended flags
+const (
+ OFN_EX_NOPLACESBAR = 0x00000001
+)
+
+// GetOpenFileName and GetSaveFileName flags
+const (
+ OFN_ALLOWMULTISELECT = 0x00000200
+ OFN_CREATEPROMPT = 0x00002000
+ OFN_DONTADDTORECENT = 0x02000000
+ OFN_ENABLEHOOK = 0x00000020
+ OFN_ENABLEINCLUDENOTIFY = 0x00400000
+ OFN_ENABLESIZING = 0x00800000
+ OFN_ENABLETEMPLATE = 0x00000040
+ OFN_ENABLETEMPLATEHANDLE = 0x00000080
+ OFN_EXPLORER = 0x00080000
+ OFN_EXTENSIONDIFFERENT = 0x00000400
+ OFN_FILEMUSTEXIST = 0x00001000
+ OFN_FORCESHOWHIDDEN = 0x10000000
+ OFN_HIDEREADONLY = 0x00000004
+ OFN_LONGNAMES = 0x00200000
+ OFN_NOCHANGEDIR = 0x00000008
+ OFN_NODEREFERENCELINKS = 0x00100000
+ OFN_NOLONGNAMES = 0x00040000
+ OFN_NONETWORKBUTTON = 0x00020000
+ OFN_NOREADONLYRETURN = 0x00008000
+ OFN_NOTESTFILECREATE = 0x00010000
+ OFN_NOVALIDATE = 0x00000100
+ OFN_OVERWRITEPROMPT = 0x00000002
+ OFN_PATHMUSTEXIST = 0x00000800
+ OFN_READONLY = 0x00000001
+ OFN_SHAREAWARE = 0x00004000
+ OFN_SHOWHELP = 0x00000010
+)
+
+// SHBrowseForFolder flags
+const (
+ BIF_RETURNONLYFSDIRS = 0x00000001
+ BIF_DONTGOBELOWDOMAIN = 0x00000002
+ BIF_STATUSTEXT = 0x00000004
+ BIF_RETURNFSANCESTORS = 0x00000008
+ BIF_EDITBOX = 0x00000010
+ BIF_VALIDATE = 0x00000020
+ BIF_NEWDIALOGSTYLE = 0x00000040
+ BIF_BROWSEINCLUDEURLS = 0x00000080
+ BIF_USENEWUI = BIF_EDITBOX | BIF_NEWDIALOGSTYLE
+ BIF_UAHINT = 0x00000100
+ BIF_NONEWFOLDERBUTTON = 0x00000200
+ BIF_NOTRANSLATETARGETS = 0x00000400
+ BIF_BROWSEFORCOMPUTER = 0x00001000
+ BIF_BROWSEFORPRINTER = 0x00002000
+ BIF_BROWSEINCLUDEFILES = 0x00004000
+ BIF_SHAREABLE = 0x00008000
+ BIF_BROWSEFILEJUNCTIONS = 0x00010000
+)
+
+// MessageBox flags
+const (
+ MB_OK = 0x00000000
+ MB_OKCANCEL = 0x00000001
+ MB_ABORTRETRYIGNORE = 0x00000002
+ MB_YESNOCANCEL = 0x00000003
+ MB_YESNO = 0x00000004
+ MB_RETRYCANCEL = 0x00000005
+ MB_CANCELTRYCONTINUE = 0x00000006
+ MB_ICONHAND = 0x00000010
+ MB_ICONQUESTION = 0x00000020
+ MB_ICONEXCLAMATION = 0x00000030
+ MB_ICONASTERISK = 0x00000040
+ MB_USERICON = 0x00000080
+ MB_ICONWARNING = MB_ICONEXCLAMATION
+ MB_ICONERROR = MB_ICONHAND
+ MB_ICONINFORMATION = MB_ICONASTERISK
+ MB_ICONSTOP = MB_ICONHAND
+ MB_DEFBUTTON1 = 0x00000000
+ MB_DEFBUTTON2 = 0x00000100
+ MB_DEFBUTTON3 = 0x00000200
+ MB_DEFBUTTON4 = 0x00000300
+)
+
+// COM
+const (
+ E_INVALIDARG = 0x80070057
+ E_OUTOFMEMORY = 0x8007000E
+ E_UNEXPECTED = 0x8000FFFF
+)
+
+const (
+ S_OK = 0
+ S_FALSE = 0x0001
+ RPC_E_CHANGED_MODE = 0x80010106
+)
+
+// GetSystemMetrics constants
+const (
+ SM_CXSCREEN = 0
+ SM_CYSCREEN = 1
+ SM_CXVSCROLL = 2
+ SM_CYHSCROLL = 3
+ SM_CYCAPTION = 4
+ SM_CXBORDER = 5
+ SM_CYBORDER = 6
+ SM_CXDLGFRAME = 7
+ SM_CYDLGFRAME = 8
+ SM_CYVTHUMB = 9
+ SM_CXHTHUMB = 10
+ SM_CXICON = 11
+ SM_CYICON = 12
+ SM_CXCURSOR = 13
+ SM_CYCURSOR = 14
+ SM_CYMENU = 15
+ SM_CXFULLSCREEN = 16
+ SM_CYFULLSCREEN = 17
+ SM_CYKANJIWINDOW = 18
+ SM_MOUSEPRESENT = 19
+ SM_CYVSCROLL = 20
+ SM_CXHSCROLL = 21
+ SM_DEBUG = 22
+ SM_SWAPBUTTON = 23
+ SM_RESERVED1 = 24
+ SM_RESERVED2 = 25
+ SM_RESERVED3 = 26
+ SM_RESERVED4 = 27
+ SM_CXMIN = 28
+ SM_CYMIN = 29
+ SM_CXSIZE = 30
+ SM_CYSIZE = 31
+ SM_CXFRAME = 32
+ SM_CYFRAME = 33
+ SM_CXMINTRACK = 34
+ SM_CYMINTRACK = 35
+ SM_CXDOUBLECLK = 36
+ SM_CYDOUBLECLK = 37
+ SM_CXICONSPACING = 38
+ SM_CYICONSPACING = 39
+ SM_MENUDROPALIGNMENT = 40
+ SM_PENWINDOWS = 41
+ SM_DBCSENABLED = 42
+ SM_CMOUSEBUTTONS = 43
+ SM_CXFIXEDFRAME = SM_CXDLGFRAME
+ SM_CYFIXEDFRAME = SM_CYDLGFRAME
+ SM_CXSIZEFRAME = SM_CXFRAME
+ SM_CYSIZEFRAME = SM_CYFRAME
+ SM_SECURE = 44
+ SM_CXEDGE = 45
+ SM_CYEDGE = 46
+ SM_CXMINSPACING = 47
+ SM_CYMINSPACING = 48
+ SM_CXSMICON = 49
+ SM_CYSMICON = 50
+ SM_CYSMCAPTION = 51
+ SM_CXSMSIZE = 52
+ SM_CYSMSIZE = 53
+ SM_CXMENUSIZE = 54
+ SM_CYMENUSIZE = 55
+ SM_ARRANGE = 56
+ SM_CXMINIMIZED = 57
+ SM_CYMINIMIZED = 58
+ SM_CXMAXTRACK = 59
+ SM_CYMAXTRACK = 60
+ SM_CXMAXIMIZED = 61
+ SM_CYMAXIMIZED = 62
+ SM_NETWORK = 63
+ SM_CLEANBOOT = 67
+ SM_CXDRAG = 68
+ SM_CYDRAG = 69
+ SM_SHOWSOUNDS = 70
+ SM_CXMENUCHECK = 71
+ SM_CYMENUCHECK = 72
+ SM_SLOWMACHINE = 73
+ SM_MIDEASTENABLED = 74
+ SM_MOUSEWHEELPRESENT = 75
+ SM_XVIRTUALSCREEN = 76
+ SM_YVIRTUALSCREEN = 77
+ SM_CXVIRTUALSCREEN = 78
+ SM_CYVIRTUALSCREEN = 79
+ SM_CMONITORS = 80
+ SM_SAMEDISPLAYFORMAT = 81
+ SM_IMMENABLED = 82
+ SM_CXFOCUSBORDER = 83
+ SM_CYFOCUSBORDER = 84
+ SM_TABLETPC = 86
+ SM_MEDIACENTER = 87
+ SM_STARTER = 88
+ SM_SERVERR2 = 89
+ SM_CMETRICS = 91
+ SM_CXPADDEDBORDER = 92
+ SM_REMOTESESSION = 0x1000
+ SM_SHUTTINGDOWN = 0x2000
+ SM_REMOTECONTROL = 0x2001
+ SM_CARETBLINKINGENABLED = 0x2002
+)
+
+const (
+ CLSCTX_INPROC_SERVER = 1
+ CLSCTX_INPROC_HANDLER = 2
+ CLSCTX_LOCAL_SERVER = 4
+ CLSCTX_INPROC_SERVER16 = 8
+ CLSCTX_REMOTE_SERVER = 16
+ CLSCTX_ALL = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER
+ CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER
+ CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER
+)
+
+const (
+ COINIT_APARTMENTTHREADED = 0x2
+ COINIT_MULTITHREADED = 0x0
+ COINIT_DISABLE_OLE1DDE = 0x4
+ COINIT_SPEED_OVER_MEMORY = 0x8
+)
+
+const (
+ DISPATCH_METHOD = 1
+ DISPATCH_PROPERTYGET = 2
+ DISPATCH_PROPERTYPUT = 4
+ DISPATCH_PROPERTYPUTREF = 8
+)
+
+const (
+ CC_FASTCALL = iota
+ CC_CDECL
+ CC_MSCPASCAL
+ CC_PASCAL = CC_MSCPASCAL
+ CC_MACPASCAL
+ CC_STDCALL
+ CC_FPFASTCALL
+ CC_SYSCALL
+ CC_MPWCDECL
+ CC_MPWPASCAL
+ CC_MAX = CC_MPWPASCAL
+)
+
+const (
+ VT_EMPTY = 0x0
+ VT_NULL = 0x1
+ VT_I2 = 0x2
+ VT_I4 = 0x3
+ VT_R4 = 0x4
+ VT_R8 = 0x5
+ VT_CY = 0x6
+ VT_DATE = 0x7
+ VT_BSTR = 0x8
+ VT_DISPATCH = 0x9
+ VT_ERROR = 0xa
+ VT_BOOL = 0xb
+ VT_VARIANT = 0xc
+ VT_UNKNOWN = 0xd
+ VT_DECIMAL = 0xe
+ VT_I1 = 0x10
+ VT_UI1 = 0x11
+ VT_UI2 = 0x12
+ VT_UI4 = 0x13
+ VT_I8 = 0x14
+ VT_UI8 = 0x15
+ VT_INT = 0x16
+ VT_UINT = 0x17
+ VT_VOID = 0x18
+ VT_HRESULT = 0x19
+ VT_PTR = 0x1a
+ VT_SAFEARRAY = 0x1b
+ VT_CARRAY = 0x1c
+ VT_USERDEFINED = 0x1d
+ VT_LPSTR = 0x1e
+ VT_LPWSTR = 0x1f
+ VT_RECORD = 0x24
+ VT_INT_PTR = 0x25
+ VT_UINT_PTR = 0x26
+ VT_FILETIME = 0x40
+ VT_BLOB = 0x41
+ VT_STREAM = 0x42
+ VT_STORAGE = 0x43
+ VT_STREAMED_OBJECT = 0x44
+ VT_STORED_OBJECT = 0x45
+ VT_BLOB_OBJECT = 0x46
+ VT_CF = 0x47
+ VT_CLSID = 0x48
+ VT_BSTR_BLOB = 0xfff
+ VT_VECTOR = 0x1000
+ VT_ARRAY = 0x2000
+ VT_BYREF = 0x4000
+ VT_RESERVED = 0x8000
+ VT_ILLEGAL = 0xffff
+ VT_ILLEGALMASKED = 0xfff
+ VT_TYPEMASK = 0xfff
+)
+
+const (
+ DISPID_UNKNOWN = -1
+ DISPID_VALUE = 0
+ DISPID_PROPERTYPUT = -3
+ DISPID_NEWENUM = -4
+ DISPID_EVALUATE = -5
+ DISPID_CONSTRUCTOR = -6
+ DISPID_DESTRUCTOR = -7
+ DISPID_COLLECT = -8
+)
+
+const (
+ MONITOR_DEFAULTTONULL = 0x00000000
+ MONITOR_DEFAULTTOPRIMARY = 0x00000001
+ MONITOR_DEFAULTTONEAREST = 0x00000002
+
+ MONITORINFOF_PRIMARY = 0x00000001
+)
+
+const (
+ CCHDEVICENAME = 32
+ CCHFORMNAME = 32
+)
+
+const (
+ IDOK = 1
+ IDCANCEL = 2
+ IDABORT = 3
+ IDRETRY = 4
+ IDIGNORE = 5
+ IDYES = 6
+ IDNO = 7
+ IDCLOSE = 8
+ IDHELP = 9
+ IDTRYAGAIN = 10
+ IDCONTINUE = 11
+ IDTIMEOUT = 32000
+)
+
+// Generic WM_NOTIFY notification codes
+const (
+ NM_FIRST = 0
+ NM_OUTOFMEMORY = NM_FIRST - 1
+ NM_CLICK = NM_FIRST - 2
+ NM_DBLCLK = NM_FIRST - 3
+ NM_RETURN = NM_FIRST - 4
+ NM_RCLICK = NM_FIRST - 5
+ NM_RDBLCLK = NM_FIRST - 6
+ NM_SETFOCUS = NM_FIRST - 7
+ NM_KILLFOCUS = NM_FIRST - 8
+ NM_CUSTOMDRAW = NM_FIRST - 12
+ NM_HOVER = NM_FIRST - 13
+ NM_NCHITTEST = NM_FIRST - 14
+ NM_KEYDOWN = NM_FIRST - 15
+ NM_RELEASEDCAPTURE = NM_FIRST - 16
+ NM_SETCURSOR = NM_FIRST - 17
+ NM_CHAR = NM_FIRST - 18
+ NM_TOOLTIPSCREATED = NM_FIRST - 19
+ NM_LAST = NM_FIRST - 99
+)
+
+// ListView messages
+const (
+ LVM_FIRST = 0x1000
+ LVM_GETITEMCOUNT = LVM_FIRST + 4
+ LVM_SETIMAGELIST = LVM_FIRST + 3
+ LVM_GETIMAGELIST = LVM_FIRST + 2
+ LVM_GETITEM = LVM_FIRST + 75
+ LVM_SETITEM = LVM_FIRST + 76
+ LVM_INSERTITEM = LVM_FIRST + 77
+ LVM_DELETEITEM = LVM_FIRST + 8
+ LVM_DELETEALLITEMS = LVM_FIRST + 9
+ LVM_GETCALLBACKMASK = LVM_FIRST + 10
+ LVM_SETCALLBACKMASK = LVM_FIRST + 11
+ LVM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT
+ LVM_GETNEXTITEM = LVM_FIRST + 12
+ LVM_FINDITEM = LVM_FIRST + 83
+ LVM_GETITEMRECT = LVM_FIRST + 14
+ LVM_GETSTRINGWIDTH = LVM_FIRST + 87
+ LVM_HITTEST = LVM_FIRST + 18
+ LVM_ENSUREVISIBLE = LVM_FIRST + 19
+ LVM_SCROLL = LVM_FIRST + 20
+ LVM_REDRAWITEMS = LVM_FIRST + 21
+ LVM_ARRANGE = LVM_FIRST + 22
+ LVM_EDITLABEL = LVM_FIRST + 118
+ LVM_GETEDITCONTROL = LVM_FIRST + 24
+ LVM_GETCOLUMN = LVM_FIRST + 95
+ LVM_SETCOLUMN = LVM_FIRST + 96
+ LVM_INSERTCOLUMN = LVM_FIRST + 97
+ LVM_DELETECOLUMN = LVM_FIRST + 28
+ LVM_GETCOLUMNWIDTH = LVM_FIRST + 29
+ LVM_SETCOLUMNWIDTH = LVM_FIRST + 30
+ LVM_GETHEADER = LVM_FIRST + 31
+ LVM_CREATEDRAGIMAGE = LVM_FIRST + 33
+ LVM_GETVIEWRECT = LVM_FIRST + 34
+ LVM_GETTEXTCOLOR = LVM_FIRST + 35
+ LVM_SETTEXTCOLOR = LVM_FIRST + 36
+ LVM_GETTEXTBKCOLOR = LVM_FIRST + 37
+ LVM_SETTEXTBKCOLOR = LVM_FIRST + 38
+ LVM_GETTOPINDEX = LVM_FIRST + 39
+ LVM_GETCOUNTPERPAGE = LVM_FIRST + 40
+ LVM_GETORIGIN = LVM_FIRST + 41
+ LVM_UPDATE = LVM_FIRST + 42
+ LVM_SETITEMSTATE = LVM_FIRST + 43
+ LVM_GETITEMSTATE = LVM_FIRST + 44
+ LVM_GETITEMTEXT = LVM_FIRST + 115
+ LVM_SETITEMTEXT = LVM_FIRST + 116
+ LVM_SETITEMCOUNT = LVM_FIRST + 47
+ LVM_SORTITEMS = LVM_FIRST + 48
+ LVM_SETITEMPOSITION32 = LVM_FIRST + 49
+ LVM_GETSELECTEDCOUNT = LVM_FIRST + 50
+ LVM_GETITEMSPACING = LVM_FIRST + 51
+ LVM_GETISEARCHSTRING = LVM_FIRST + 117
+ LVM_SETICONSPACING = LVM_FIRST + 53
+ LVM_SETEXTENDEDLISTVIEWSTYLE = LVM_FIRST + 54
+ LVM_GETEXTENDEDLISTVIEWSTYLE = LVM_FIRST + 55
+ LVM_GETSUBITEMRECT = LVM_FIRST + 56
+ LVM_SUBITEMHITTEST = LVM_FIRST + 57
+ LVM_SETCOLUMNORDERARRAY = LVM_FIRST + 58
+ LVM_GETCOLUMNORDERARRAY = LVM_FIRST + 59
+ LVM_SETHOTITEM = LVM_FIRST + 60
+ LVM_GETHOTITEM = LVM_FIRST + 61
+ LVM_SETHOTCURSOR = LVM_FIRST + 62
+ LVM_GETHOTCURSOR = LVM_FIRST + 63
+ LVM_APPROXIMATEVIEWRECT = LVM_FIRST + 64
+ LVM_SETWORKAREAS = LVM_FIRST + 65
+ LVM_GETWORKAREAS = LVM_FIRST + 70
+ LVM_GETNUMBEROFWORKAREAS = LVM_FIRST + 73
+ LVM_GETSELECTIONMARK = LVM_FIRST + 66
+ LVM_SETSELECTIONMARK = LVM_FIRST + 67
+ LVM_SETHOVERTIME = LVM_FIRST + 71
+ LVM_GETHOVERTIME = LVM_FIRST + 72
+ LVM_SETTOOLTIPS = LVM_FIRST + 74
+ LVM_GETTOOLTIPS = LVM_FIRST + 78
+ LVM_SORTITEMSEX = LVM_FIRST + 81
+ LVM_SETBKIMAGE = LVM_FIRST + 138
+ LVM_GETBKIMAGE = LVM_FIRST + 139
+ LVM_SETSELECTEDCOLUMN = LVM_FIRST + 140
+ LVM_SETVIEW = LVM_FIRST + 142
+ LVM_GETVIEW = LVM_FIRST + 143
+ LVM_INSERTGROUP = LVM_FIRST + 145
+ LVM_SETGROUPINFO = LVM_FIRST + 147
+ LVM_GETGROUPINFO = LVM_FIRST + 149
+ LVM_REMOVEGROUP = LVM_FIRST + 150
+ LVM_MOVEGROUP = LVM_FIRST + 151
+ LVM_GETGROUPCOUNT = LVM_FIRST + 152
+ LVM_GETGROUPINFOBYINDEX = LVM_FIRST + 153
+ LVM_MOVEITEMTOGROUP = LVM_FIRST + 154
+ LVM_GETGROUPRECT = LVM_FIRST + 98
+ LVM_SETGROUPMETRICS = LVM_FIRST + 155
+ LVM_GETGROUPMETRICS = LVM_FIRST + 156
+ LVM_ENABLEGROUPVIEW = LVM_FIRST + 157
+ LVM_SORTGROUPS = LVM_FIRST + 158
+ LVM_INSERTGROUPSORTED = LVM_FIRST + 159
+ LVM_REMOVEALLGROUPS = LVM_FIRST + 160
+ LVM_HASGROUP = LVM_FIRST + 161
+ LVM_GETGROUPSTATE = LVM_FIRST + 92
+ LVM_GETFOCUSEDGROUP = LVM_FIRST + 93
+ LVM_SETTILEVIEWINFO = LVM_FIRST + 162
+ LVM_GETTILEVIEWINFO = LVM_FIRST + 163
+ LVM_SETTILEINFO = LVM_FIRST + 164
+ LVM_GETTILEINFO = LVM_FIRST + 165
+ LVM_SETINSERTMARK = LVM_FIRST + 166
+ LVM_GETINSERTMARK = LVM_FIRST + 167
+ LVM_INSERTMARKHITTEST = LVM_FIRST + 168
+ LVM_GETINSERTMARKRECT = LVM_FIRST + 169
+ LVM_SETINSERTMARKCOLOR = LVM_FIRST + 170
+ LVM_GETINSERTMARKCOLOR = LVM_FIRST + 171
+ LVM_SETINFOTIP = LVM_FIRST + 173
+ LVM_GETSELECTEDCOLUMN = LVM_FIRST + 174
+ LVM_ISGROUPVIEWENABLED = LVM_FIRST + 175
+ LVM_GETOUTLINECOLOR = LVM_FIRST + 176
+ LVM_SETOUTLINECOLOR = LVM_FIRST + 177
+ LVM_CANCELEDITLABEL = LVM_FIRST + 179
+ LVM_MAPINDEXTOID = LVM_FIRST + 180
+ LVM_MAPIDTOINDEX = LVM_FIRST + 181
+ LVM_ISITEMVISIBLE = LVM_FIRST + 182
+ LVM_GETNEXTITEMINDEX = LVM_FIRST + 211
+)
+
+// ListView notifications
+const (
+ LVN_FIRST = -100
+
+ LVN_ITEMCHANGING = LVN_FIRST - 0
+ LVN_ITEMCHANGED = LVN_FIRST - 1
+ LVN_INSERTITEM = LVN_FIRST - 2
+ LVN_DELETEITEM = LVN_FIRST - 3
+ LVN_DELETEALLITEMS = LVN_FIRST - 4
+ LVN_BEGINLABELEDITA = LVN_FIRST - 5
+ LVN_BEGINLABELEDITW = LVN_FIRST - 75
+ LVN_ENDLABELEDITA = LVN_FIRST - 6
+ LVN_ENDLABELEDITW = LVN_FIRST - 76
+ LVN_COLUMNCLICK = LVN_FIRST - 8
+ LVN_BEGINDRAG = LVN_FIRST - 9
+ LVN_BEGINRDRAG = LVN_FIRST - 11
+ LVN_ODCACHEHINT = LVN_FIRST - 13
+ LVN_ODFINDITEMA = LVN_FIRST - 52
+ LVN_ODFINDITEMW = LVN_FIRST - 79
+ LVN_ITEMACTIVATE = LVN_FIRST - 14
+ LVN_ODSTATECHANGED = LVN_FIRST - 15
+ LVN_HOTTRACK = LVN_FIRST - 21
+ LVN_GETDISPINFO = LVN_FIRST - 77
+ LVN_SETDISPINFO = LVN_FIRST - 78
+ LVN_KEYDOWN = LVN_FIRST - 55
+ LVN_MARQUEEBEGIN = LVN_FIRST - 56
+ LVN_GETINFOTIP = LVN_FIRST - 58
+ LVN_INCREMENTALSEARCH = LVN_FIRST - 63
+ LVN_BEGINSCROLL = LVN_FIRST - 80
+ LVN_ENDSCROLL = LVN_FIRST - 81
+)
+
+const (
+ LVSCW_AUTOSIZE = ^uintptr(0)
+ LVSCW_AUTOSIZE_USEHEADER = ^uintptr(1)
+)
+
+// ListView LVNI constants
+const (
+ LVNI_ALL = 0
+ LVNI_FOCUSED = 1
+ LVNI_SELECTED = 2
+ LVNI_CUT = 4
+ LVNI_DROPHILITED = 8
+ LVNI_ABOVE = 256
+ LVNI_BELOW = 512
+ LVNI_TOLEFT = 1024
+ LVNI_TORIGHT = 2048
+)
+
+// ListView styles
+const (
+ LVS_ICON = 0x0000
+ LVS_REPORT = 0x0001
+ LVS_SMALLICON = 0x0002
+ LVS_LIST = 0x0003
+ LVS_TYPEMASK = 0x0003
+ LVS_SINGLESEL = 0x0004
+ LVS_SHOWSELALWAYS = 0x0008
+ LVS_SORTASCENDING = 0x0010
+ LVS_SORTDESCENDING = 0x0020
+ LVS_SHAREIMAGELISTS = 0x0040
+ LVS_NOLABELWRAP = 0x0080
+ LVS_AUTOARRANGE = 0x0100
+ LVS_EDITLABELS = 0x0200
+ LVS_OWNERDATA = 0x1000
+ LVS_NOSCROLL = 0x2000
+ LVS_TYPESTYLEMASK = 0xfc00
+ LVS_ALIGNTOP = 0x0000
+ LVS_ALIGNLEFT = 0x0800
+ LVS_ALIGNMASK = 0x0c00
+ LVS_OWNERDRAWFIXED = 0x0400
+ LVS_NOCOLUMNHEADER = 0x4000
+ LVS_NOSORTHEADER = 0x8000
+)
+
+// ListView extended styles
+const (
+ LVS_EX_GRIDLINES = 0x00000001
+ LVS_EX_SUBITEMIMAGES = 0x00000002
+ LVS_EX_CHECKBOXES = 0x00000004
+ LVS_EX_TRACKSELECT = 0x00000008
+ LVS_EX_HEADERDRAGDROP = 0x00000010
+ LVS_EX_FULLROWSELECT = 0x00000020
+ LVS_EX_ONECLICKACTIVATE = 0x00000040
+ LVS_EX_TWOCLICKACTIVATE = 0x00000080
+ LVS_EX_FLATSB = 0x00000100
+ LVS_EX_REGIONAL = 0x00000200
+ LVS_EX_INFOTIP = 0x00000400
+ LVS_EX_UNDERLINEHOT = 0x00000800
+ LVS_EX_UNDERLINECOLD = 0x00001000
+ LVS_EX_MULTIWORKAREAS = 0x00002000
+ LVS_EX_LABELTIP = 0x00004000
+ LVS_EX_BORDERSELECT = 0x00008000
+ LVS_EX_DOUBLEBUFFER = 0x00010000
+ LVS_EX_HIDELABELS = 0x00020000
+ LVS_EX_SINGLEROW = 0x00040000
+ LVS_EX_SNAPTOGRID = 0x00080000
+ LVS_EX_SIMPLESELECT = 0x00100000
+)
+
+// ListView column flags
+const (
+ LVCF_FMT = 0x0001
+ LVCF_WIDTH = 0x0002
+ LVCF_TEXT = 0x0004
+ LVCF_SUBITEM = 0x0008
+ LVCF_IMAGE = 0x0010
+ LVCF_ORDER = 0x0020
+)
+
+// ListView column format constants
+const (
+ LVCFMT_LEFT = 0x0000
+ LVCFMT_RIGHT = 0x0001
+ LVCFMT_CENTER = 0x0002
+ LVCFMT_JUSTIFYMASK = 0x0003
+ LVCFMT_IMAGE = 0x0800
+ LVCFMT_BITMAP_ON_RIGHT = 0x1000
+ LVCFMT_COL_HAS_IMAGES = 0x8000
+)
+
+// ListView item flags
+const (
+ LVIF_TEXT = 0x00000001
+ LVIF_IMAGE = 0x00000002
+ LVIF_PARAM = 0x00000004
+ LVIF_STATE = 0x00000008
+ LVIF_INDENT = 0x00000010
+ LVIF_NORECOMPUTE = 0x00000800
+ LVIF_GROUPID = 0x00000100
+ LVIF_COLUMNS = 0x00000200
+)
+
+const LVFI_PARAM = 0x0001
+
+// ListView item states
+const (
+ LVIS_FOCUSED = 1
+ LVIS_SELECTED = 2
+ LVIS_CUT = 4
+ LVIS_DROPHILITED = 8
+ LVIS_OVERLAYMASK = 0xF00
+ LVIS_STATEIMAGEMASK = 0xF000
+)
+
+// ListView hit test constants
+const (
+ LVHT_NOWHERE = 0x00000001
+ LVHT_ONITEMICON = 0x00000002
+ LVHT_ONITEMLABEL = 0x00000004
+ LVHT_ONITEMSTATEICON = 0x00000008
+ LVHT_ONITEM = LVHT_ONITEMICON | LVHT_ONITEMLABEL | LVHT_ONITEMSTATEICON
+
+ LVHT_ABOVE = 0x00000008
+ LVHT_BELOW = 0x00000010
+ LVHT_TORIGHT = 0x00000020
+ LVHT_TOLEFT = 0x00000040
+)
+
+// ListView image list types
+const (
+ LVSIL_NORMAL = 0
+ LVSIL_SMALL = 1
+ LVSIL_STATE = 2
+ LVSIL_GROUPHEADER = 3
+)
+
+// InitCommonControlsEx flags
+const (
+ ICC_LISTVIEW_CLASSES = 1
+ ICC_TREEVIEW_CLASSES = 2
+ ICC_BAR_CLASSES = 4
+ ICC_TAB_CLASSES = 8
+ ICC_UPDOWN_CLASS = 16
+ ICC_PROGRESS_CLASS = 32
+ ICC_HOTKEY_CLASS = 64
+ ICC_ANIMATE_CLASS = 128
+ ICC_WIN95_CLASSES = 255
+ ICC_DATE_CLASSES = 256
+ ICC_USEREX_CLASSES = 512
+ ICC_COOL_CLASSES = 1024
+ ICC_INTERNET_CLASSES = 2048
+ ICC_PAGESCROLLER_CLASS = 4096
+ ICC_NATIVEFNTCTL_CLASS = 8192
+ INFOTIPSIZE = 1024
+ ICC_STANDARD_CLASSES = 0x00004000
+ ICC_LINK_CLASS = 0x00008000
+)
+
+// Dialog Codes
+const (
+ DLGC_WANTARROWS = 0x0001
+ DLGC_WANTTAB = 0x0002
+ DLGC_WANTALLKEYS = 0x0004
+ DLGC_WANTMESSAGE = 0x0004
+ DLGC_HASSETSEL = 0x0008
+ DLGC_DEFPUSHBUTTON = 0x0010
+ DLGC_UNDEFPUSHBUTTON = 0x0020
+ DLGC_RADIOBUTTON = 0x0040
+ DLGC_WANTCHARS = 0x0080
+ DLGC_STATIC = 0x0100
+ DLGC_BUTTON = 0x2000
+)
+
+// Get/SetWindowWord/Long offsets for use with WC_DIALOG windows
+const (
+ DWL_MSGRESULT = 0
+ DWL_DLGPROC = 4
+ DWL_USER = 8
+)
+
+// Registry predefined keys
+const (
+ HKEY_CLASSES_ROOT HKEY = 0x80000000
+ HKEY_CURRENT_USER HKEY = 0x80000001
+ HKEY_LOCAL_MACHINE HKEY = 0x80000002
+ HKEY_USERS HKEY = 0x80000003
+ HKEY_PERFORMANCE_DATA HKEY = 0x80000004
+ HKEY_CURRENT_CONFIG HKEY = 0x80000005
+ HKEY_DYN_DATA HKEY = 0x80000006
+)
+
+// Registry Key Security and Access Rights
+const (
+ KEY_ALL_ACCESS = 0xF003F
+ KEY_CREATE_SUB_KEY = 0x0004
+ KEY_ENUMERATE_SUB_KEYS = 0x0008
+ KEY_NOTIFY = 0x0010
+ KEY_QUERY_VALUE = 0x0001
+ KEY_SET_VALUE = 0x0002
+ KEY_READ = 0x20019
+ KEY_WRITE = 0x20006
+)
+
+const (
+ NFR_ANSI = 1
+ NFR_UNICODE = 2
+ NF_QUERY = 3
+ NF_REQUERY = 4
+)
+
+// Registry value types
+const (
+ RRF_RT_REG_NONE = 0x00000001
+ RRF_RT_REG_SZ = 0x00000002
+ RRF_RT_REG_EXPAND_SZ = 0x00000004
+ RRF_RT_REG_BINARY = 0x00000008
+ RRF_RT_REG_DWORD = 0x00000010
+ RRF_RT_REG_MULTI_SZ = 0x00000020
+ RRF_RT_REG_QWORD = 0x00000040
+ RRF_RT_DWORD = RRF_RT_REG_BINARY | RRF_RT_REG_DWORD
+ RRF_RT_QWORD = RRF_RT_REG_BINARY | RRF_RT_REG_QWORD
+ RRF_RT_ANY = 0x0000ffff
+ RRF_NOEXPAND = 0x10000000
+ RRF_ZEROONFAILURE = 0x20000000
+ REG_PROCESS_APPKEY = 0x00000001
+ REG_MUI_STRING_TRUNCATE = 0x00000001
+)
+
+// PeekMessage wRemoveMsg value
+const (
+ PM_NOREMOVE = 0x000
+ PM_REMOVE = 0x001
+ PM_NOYIELD = 0x002
+)
+
+// ImageList flags
+const (
+ ILC_MASK = 0x00000001
+ ILC_COLOR = 0x00000000
+ ILC_COLORDDB = 0x000000FE
+ ILC_COLOR4 = 0x00000004
+ ILC_COLOR8 = 0x00000008
+ ILC_COLOR16 = 0x00000010
+ ILC_COLOR24 = 0x00000018
+ ILC_COLOR32 = 0x00000020
+ ILC_PALETTE = 0x00000800
+ ILC_MIRROR = 0x00002000
+ ILC_PERITEMMIRROR = 0x00008000
+ ILC_ORIGINALSIZE = 0x00010000
+ ILC_HIGHQUALITYSCALE = 0x00020000
+)
+
+// Keystroke Message Flags
+const (
+ KF_EXTENDED = 0x0100
+ KF_DLGMODE = 0x0800
+ KF_MENUMODE = 0x1000
+ KF_ALTDOWN = 0x2000
+ KF_REPEAT = 0x4000
+ KF_UP = 0x8000
+)
+
+// Virtual-Key Codes
+/*
+const (
+ VK_LBUTTON = 0x01
+ VK_RBUTTON = 0x02
+ VK_CANCEL = 0x03
+ VK_MBUTTON = 0x04
+ VK_XBUTTON1 = 0x05
+ VK_XBUTTON2 = 0x06
+ VK_BACK = 0x08
+ VK_TAB = 0x09
+ VK_CLEAR = 0x0C
+ VK_RETURN = 0x0D
+ VK_SHIFT = 0x10
+ VK_CONTROL = 0x11
+ VK_MENU = 0x12
+ VK_PAUSE = 0x13
+ VK_CAPITAL = 0x14
+ VK_KANA = 0x15
+ VK_HANGEUL = 0x15
+ VK_HANGUL = 0x15
+ VK_JUNJA = 0x17
+ VK_FINAL = 0x18
+ VK_HANJA = 0x19
+ VK_KANJI = 0x19
+ VK_ESCAPE = 0x1B
+ VK_CONVERT = 0x1C
+ VK_NONCONVERT = 0x1D
+ VK_ACCEPT = 0x1E
+ VK_MODECHANGE = 0x1F
+ VK_SPACE = 0x20
+ VK_PRIOR = 0x21
+ VK_NEXT = 0x22
+ VK_END = 0x23
+ VK_HOME = 0x24
+ VK_LEFT = 0x25
+ VK_UP = 0x26
+ VK_RIGHT = 0x27
+ VK_DOWN = 0x28
+ VK_SELECT = 0x29
+ VK_PRINT = 0x2A
+ VK_EXECUTE = 0x2B
+ VK_SNAPSHOT = 0x2C
+ VK_INSERT = 0x2D
+ VK_DELETE = 0x2E
+ VK_HELP = 0x2F
+ VK_LWIN = 0x5B
+ VK_RWIN = 0x5C
+ VK_APPS = 0x5D
+ VK_SLEEP = 0x5F
+ VK_NUMPAD0 = 0x60
+ VK_NUMPAD1 = 0x61
+ VK_NUMPAD2 = 0x62
+ VK_NUMPAD3 = 0x63
+ VK_NUMPAD4 = 0x64
+ VK_NUMPAD5 = 0x65
+ VK_NUMPAD6 = 0x66
+ VK_NUMPAD7 = 0x67
+ VK_NUMPAD8 = 0x68
+ VK_NUMPAD9 = 0x69
+ VK_MULTIPLY = 0x6A
+ VK_ADD = 0x6B
+ VK_SEPARATOR = 0x6C
+ VK_SUBTRACT = 0x6D
+ VK_DECIMAL = 0x6E
+ VK_DIVIDE = 0x6F
+ VK_F1 = 0x70
+ VK_F2 = 0x71
+ VK_F3 = 0x72
+ VK_F4 = 0x73
+ VK_F5 = 0x74
+ VK_F6 = 0x75
+ VK_F7 = 0x76
+ VK_F8 = 0x77
+ VK_F9 = 0x78
+ VK_F10 = 0x79
+ VK_F11 = 0x7A
+ VK_F12 = 0x7B
+ VK_F13 = 0x7C
+ VK_F14 = 0x7D
+ VK_F15 = 0x7E
+ VK_F16 = 0x7F
+ VK_F17 = 0x80
+ VK_F18 = 0x81
+ VK_F19 = 0x82
+ VK_F20 = 0x83
+ VK_F21 = 0x84
+ VK_F22 = 0x85
+ VK_F23 = 0x86
+ VK_F24 = 0x87
+ VK_NUMLOCK = 0x90
+ VK_SCROLL = 0x91
+ VK_OEM_NEC_EQUAL = 0x92
+ VK_OEM_FJ_JISHO = 0x92
+ VK_OEM_FJ_MASSHOU = 0x93
+ VK_OEM_FJ_TOUROKU = 0x94
+ VK_OEM_FJ_LOYA = 0x95
+ VK_OEM_FJ_ROYA = 0x96
+ VK_LSHIFT = 0xA0
+ VK_RSHIFT = 0xA1
+ VK_LCONTROL = 0xA2
+ VK_RCONTROL = 0xA3
+ VK_LMENU = 0xA4
+ VK_RMENU = 0xA5
+ VK_BROWSER_BACK = 0xA6
+ VK_BROWSER_FORWARD = 0xA7
+ VK_BROWSER_REFRESH = 0xA8
+ VK_BROWSER_STOP = 0xA9
+ VK_BROWSER_SEARCH = 0xAA
+ VK_BROWSER_FAVORITES = 0xAB
+ VK_BROWSER_HOME = 0xAC
+ VK_VOLUME_MUTE = 0xAD
+ VK_VOLUME_DOWN = 0xAE
+ VK_VOLUME_UP = 0xAF
+ VK_MEDIA_NEXT_TRACK = 0xB0
+ VK_MEDIA_PREV_TRACK = 0xB1
+ VK_MEDIA_STOP = 0xB2
+ VK_MEDIA_PLAY_PAUSE = 0xB3
+ VK_LAUNCH_MAIL = 0xB4
+ VK_LAUNCH_MEDIA_SELECT = 0xB5
+ VK_LAUNCH_APP1 = 0xB6
+ VK_LAUNCH_APP2 = 0xB7
+ VK_OEM_1 = 0xBA
+ VK_OEM_PLUS = 0xBB
+ VK_OEM_COMMA = 0xBC
+ VK_OEM_MINUS = 0xBD
+ VK_OEM_PERIOD = 0xBE
+ VK_OEM_2 = 0xBF
+ VK_OEM_3 = 0xC0
+ VK_OEM_4 = 0xDB
+ VK_OEM_5 = 0xDC
+ VK_OEM_6 = 0xDD
+ VK_OEM_7 = 0xDE
+ VK_OEM_8 = 0xDF
+ VK_OEM_AX = 0xE1
+ VK_OEM_102 = 0xE2
+ VK_ICO_HELP = 0xE3
+ VK_ICO_00 = 0xE4
+ VK_PROCESSKEY = 0xE5
+ VK_ICO_CLEAR = 0xE6
+ VK_OEM_RESET = 0xE9
+ VK_OEM_JUMP = 0xEA
+ VK_OEM_PA1 = 0xEB
+ VK_OEM_PA2 = 0xEC
+ VK_OEM_PA3 = 0xED
+ VK_OEM_WSCTRL = 0xEE
+ VK_OEM_CUSEL = 0xEF
+ VK_OEM_ATTN = 0xF0
+ VK_OEM_FINISH = 0xF1
+ VK_OEM_COPY = 0xF2
+ VK_OEM_AUTO = 0xF3
+ VK_OEM_ENLW = 0xF4
+ VK_OEM_BACKTAB = 0xF5
+ VK_ATTN = 0xF6
+ VK_CRSEL = 0xF7
+ VK_EXSEL = 0xF8
+ VK_EREOF = 0xF9
+ VK_PLAY = 0xFA
+ VK_ZOOM = 0xFB
+ VK_NONAME = 0xFC
+ VK_PA1 = 0xFD
+ VK_OEM_CLEAR = 0xFE
+)*/
+
+// Registry Value Types
+const (
+ REG_NONE = 0
+ REG_SZ = 1
+ REG_EXPAND_SZ = 2
+ REG_BINARY = 3
+ REG_DWORD = 4
+ REG_DWORD_LITTLE_ENDIAN = 4
+ REG_DWORD_BIG_ENDIAN = 5
+ REG_LINK = 6
+ REG_MULTI_SZ = 7
+ REG_RESOURCE_LIST = 8
+ REG_FULL_RESOURCE_DESCRIPTOR = 9
+ REG_RESOURCE_REQUIREMENTS_LIST = 10
+ REG_QWORD = 11
+ REG_QWORD_LITTLE_ENDIAN = 11
+)
+
+// Tooltip styles
+const (
+ TTS_ALWAYSTIP = 0x01
+ TTS_NOPREFIX = 0x02
+ TTS_NOANIMATE = 0x10
+ TTS_NOFADE = 0x20
+ TTS_BALLOON = 0x40
+ TTS_CLOSE = 0x80
+ TTS_USEVISUALSTYLE = 0x100
+)
+
+// Tooltip messages
+const (
+ TTM_ACTIVATE = WM_USER + 1
+ TTM_SETDELAYTIME = WM_USER + 3
+ TTM_ADDTOOL = WM_USER + 50
+ TTM_DELTOOL = WM_USER + 51
+ TTM_NEWTOOLRECT = WM_USER + 52
+ TTM_RELAYEVENT = WM_USER + 7
+ TTM_GETTOOLINFO = WM_USER + 53
+ TTM_SETTOOLINFO = WM_USER + 54
+ TTM_HITTEST = WM_USER + 55
+ TTM_GETTEXT = WM_USER + 56
+ TTM_UPDATETIPTEXT = WM_USER + 57
+ TTM_GETTOOLCOUNT = WM_USER + 13
+ TTM_ENUMTOOLS = WM_USER + 58
+ TTM_GETCURRENTTOOL = WM_USER + 59
+ TTM_WINDOWFROMPOINT = WM_USER + 16
+ TTM_TRACKACTIVATE = WM_USER + 17
+ TTM_TRACKPOSITION = WM_USER + 18
+ TTM_SETTIPBKCOLOR = WM_USER + 19
+ TTM_SETTIPTEXTCOLOR = WM_USER + 20
+ TTM_GETDELAYTIME = WM_USER + 21
+ TTM_GETTIPBKCOLOR = WM_USER + 22
+ TTM_GETTIPTEXTCOLOR = WM_USER + 23
+ TTM_SETMAXTIPWIDTH = WM_USER + 24
+ TTM_GETMAXTIPWIDTH = WM_USER + 25
+ TTM_SETMARGIN = WM_USER + 26
+ TTM_GETMARGIN = WM_USER + 27
+ TTM_POP = WM_USER + 28
+ TTM_UPDATE = WM_USER + 29
+ TTM_GETBUBBLESIZE = WM_USER + 30
+ TTM_ADJUSTRECT = WM_USER + 31
+ TTM_SETTITLE = WM_USER + 33
+ TTM_POPUP = WM_USER + 34
+ TTM_GETTITLE = WM_USER + 35
+)
+
+// Tooltip icons
+const (
+ TTI_NONE = 0
+ TTI_INFO = 1
+ TTI_WARNING = 2
+ TTI_ERROR = 3
+ TTI_INFO_LARGE = 4
+ TTI_WARNING_LARGE = 5
+ TTI_ERROR_LARGE = 6
+)
+
+// Tooltip notifications
+const (
+ TTN_FIRST = -520
+ TTN_LAST = -549
+ TTN_GETDISPINFO = TTN_FIRST - 10
+ TTN_SHOW = TTN_FIRST - 1
+ TTN_POP = TTN_FIRST - 2
+ TTN_LINKCLICK = TTN_FIRST - 3
+ TTN_NEEDTEXT = TTN_GETDISPINFO
+)
+
+const (
+ TTF_IDISHWND = 0x0001
+ TTF_CENTERTIP = 0x0002
+ TTF_RTLREADING = 0x0004
+ TTF_SUBCLASS = 0x0010
+ TTF_TRACK = 0x0020
+ TTF_ABSOLUTE = 0x0080
+ TTF_TRANSPARENT = 0x0100
+ TTF_PARSELINKS = 0x1000
+ TTF_DI_SETITEM = 0x8000
+)
+
+const (
+ SWP_NOSIZE = 0x0001
+ SWP_NOMOVE = 0x0002
+ SWP_NOZORDER = 0x0004
+ SWP_NOREDRAW = 0x0008
+ SWP_NOACTIVATE = 0x0010
+ SWP_FRAMECHANGED = 0x0020
+ SWP_SHOWWINDOW = 0x0040
+ SWP_HIDEWINDOW = 0x0080
+ SWP_NOCOPYBITS = 0x0100
+ SWP_NOOWNERZORDER = 0x0200
+ SWP_NOSENDCHANGING = 0x0400
+ SWP_DRAWFRAME = SWP_FRAMECHANGED
+ SWP_NOREPOSITION = SWP_NOOWNERZORDER
+ SWP_DEFERERASE = 0x2000
+ SWP_ASYNCWINDOWPOS = 0x4000
+)
+
+// Predefined window handles
+const (
+ HWND_BROADCAST = HWND(0xFFFF)
+ HWND_BOTTOM = HWND(1)
+ HWND_NOTOPMOST = ^HWND(1) // -2
+ HWND_TOP = HWND(0)
+ HWND_TOPMOST = ^HWND(0) // -1
+ HWND_DESKTOP = HWND(0)
+ HWND_MESSAGE = ^HWND(2) // -3
+)
+
+// Pen types
+const (
+ PS_COSMETIC = 0x00000000
+ PS_GEOMETRIC = 0x00010000
+ PS_TYPE_MASK = 0x000F0000
+)
+
+// Pen styles
+const (
+ PS_SOLID = 0
+ PS_DASH = 1
+ PS_DOT = 2
+ PS_DASHDOT = 3
+ PS_DASHDOTDOT = 4
+ PS_NULL = 5
+ PS_INSIDEFRAME = 6
+ PS_USERSTYLE = 7
+ PS_ALTERNATE = 8
+ PS_STYLE_MASK = 0x0000000F
+)
+
+// Pen cap types
+const (
+ PS_ENDCAP_ROUND = 0x00000000
+ PS_ENDCAP_SQUARE = 0x00000100
+ PS_ENDCAP_FLAT = 0x00000200
+ PS_ENDCAP_MASK = 0x00000F00
+)
+
+// Pen join types
+const (
+ PS_JOIN_ROUND = 0x00000000
+ PS_JOIN_BEVEL = 0x00001000
+ PS_JOIN_MITER = 0x00002000
+ PS_JOIN_MASK = 0x0000F000
+)
+
+// Hatch styles
+const (
+ HS_HORIZONTAL = 0
+ HS_VERTICAL = 1
+ HS_FDIAGONAL = 2
+ HS_BDIAGONAL = 3
+ HS_CROSS = 4
+ HS_DIAGCROSS = 5
+)
+
+// Stock Logical Objects
+const (
+ WHITE_BRUSH = 0
+ LTGRAY_BRUSH = 1
+ GRAY_BRUSH = 2
+ DKGRAY_BRUSH = 3
+ BLACK_BRUSH = 4
+ NULL_BRUSH = 5
+ HOLLOW_BRUSH = NULL_BRUSH
+ WHITE_PEN = 6
+ BLACK_PEN = 7
+ NULL_PEN = 8
+ OEM_FIXED_FONT = 10
+ ANSI_FIXED_FONT = 11
+ ANSI_VAR_FONT = 12
+ SYSTEM_FONT = 13
+ DEVICE_DEFAULT_FONT = 14
+ DEFAULT_PALETTE = 15
+ SYSTEM_FIXED_FONT = 16
+ DEFAULT_GUI_FONT = 17
+ DC_BRUSH = 18
+ DC_PEN = 19
+)
+
+// Brush styles
+const (
+ BS_SOLID = 0
+ BS_NULL = 1
+ BS_HOLLOW = BS_NULL
+ BS_HATCHED = 2
+ BS_PATTERN = 3
+ BS_INDEXED = 4
+ BS_DIBPATTERN = 5
+ BS_DIBPATTERNPT = 6
+ BS_PATTERN8X8 = 7
+ BS_DIBPATTERN8X8 = 8
+ BS_MONOPATTERN = 9
+)
+
+// TRACKMOUSEEVENT flags
+const (
+ TME_HOVER = 0x00000001
+ TME_LEAVE = 0x00000002
+ TME_NONCLIENT = 0x00000010
+ TME_QUERY = 0x40000000
+ TME_CANCEL = 0x80000000
+
+ HOVER_DEFAULT = 0xFFFFFFFF
+)
+
+// WM_NCHITTEST and MOUSEHOOKSTRUCT Mouse Position Codes
+const (
+ HTERROR = -2
+ HTTRANSPARENT = -1
+ HTNOWHERE = 0
+ HTCLIENT = 1
+ HTCAPTION = 2
+ HTSYSMENU = 3
+ HTGROWBOX = 4
+ HTSIZE = HTGROWBOX
+ HTMENU = 5
+ HTHSCROLL = 6
+ HTVSCROLL = 7
+ HTMINBUTTON = 8
+ HTMAXBUTTON = 9
+ HTLEFT = 10
+ HTRIGHT = 11
+ HTTOP = 12
+ HTTOPLEFT = 13
+ HTTOPRIGHT = 14
+ HTBOTTOM = 15
+ HTBOTTOMLEFT = 16
+ HTBOTTOMRIGHT = 17
+ HTBORDER = 18
+ HTREDUCE = HTMINBUTTON
+ HTZOOM = HTMAXBUTTON
+ HTSIZEFIRST = HTLEFT
+ HTSIZELAST = HTBOTTOMRIGHT
+ HTOBJECT = 19
+ HTCLOSE = 20
+ HTHELP = 21
+)
+
+// DrawText[Ex] format flags
+const (
+ DT_TOP = 0x00000000
+ DT_LEFT = 0x00000000
+ DT_CENTER = 0x00000001
+ DT_RIGHT = 0x00000002
+ DT_VCENTER = 0x00000004
+ DT_BOTTOM = 0x00000008
+ DT_WORDBREAK = 0x00000010
+ DT_SINGLELINE = 0x00000020
+ DT_EXPANDTABS = 0x00000040
+ DT_TABSTOP = 0x00000080
+ DT_NOCLIP = 0x00000100
+ DT_EXTERNALLEADING = 0x00000200
+ DT_CALCRECT = 0x00000400
+ DT_NOPREFIX = 0x00000800
+ DT_INTERNAL = 0x00001000
+ DT_EDITCONTROL = 0x00002000
+ DT_PATH_ELLIPSIS = 0x00004000
+ DT_END_ELLIPSIS = 0x00008000
+ DT_MODIFYSTRING = 0x00010000
+ DT_RTLREADING = 0x00020000
+ DT_WORD_ELLIPSIS = 0x00040000
+ DT_NOFULLWIDTHCHARBREAK = 0x00080000
+ DT_HIDEPREFIX = 0x00100000
+ DT_PREFIXONLY = 0x00200000
+)
+
+const CLR_INVALID = 0xFFFFFFFF
+
+// Background Modes
+const (
+ TRANSPARENT = 1
+ OPAQUE = 2
+ BKMODE_LAST = 2
+)
+
+// Global Memory Flags
+const (
+ GMEM_FIXED = 0x0000
+ GMEM_MOVEABLE = 0x0002
+ GMEM_NOCOMPACT = 0x0010
+ GMEM_NODISCARD = 0x0020
+ GMEM_ZEROINIT = 0x0040
+ GMEM_MODIFY = 0x0080
+ GMEM_DISCARDABLE = 0x0100
+ GMEM_NOT_BANKED = 0x1000
+ GMEM_SHARE = 0x2000
+ GMEM_DDESHARE = 0x2000
+ GMEM_NOTIFY = 0x4000
+ GMEM_LOWER = GMEM_NOT_BANKED
+ GMEM_VALID_FLAGS = 0x7F72
+ GMEM_INVALID_HANDLE = 0x8000
+ GHND = GMEM_MOVEABLE | GMEM_ZEROINIT
+ GPTR = GMEM_FIXED | GMEM_ZEROINIT
+)
+
+// Ternary raster operations
+const (
+ SRCCOPY = 0x00CC0020
+ SRCPAINT = 0x00EE0086
+ SRCAND = 0x008800C6
+ SRCINVERT = 0x00660046
+ SRCERASE = 0x00440328
+ NOTSRCCOPY = 0x00330008
+ NOTSRCERASE = 0x001100A6
+ MERGECOPY = 0x00C000CA
+ MERGEPAINT = 0x00BB0226
+ PATCOPY = 0x00F00021
+ PATPAINT = 0x00FB0A09
+ PATINVERT = 0x005A0049
+ DSTINVERT = 0x00550009
+ BLACKNESS = 0x00000042
+ WHITENESS = 0x00FF0062
+ NOMIRRORBITMAP = 0x80000000
+ CAPTUREBLT = 0x40000000
+)
+
+// Clipboard formats
+const (
+ CF_TEXT = 1
+ CF_BITMAP = 2
+ CF_METAFILEPICT = 3
+ CF_SYLK = 4
+ CF_DIF = 5
+ CF_TIFF = 6
+ CF_OEMTEXT = 7
+ CF_DIB = 8
+ CF_PALETTE = 9
+ CF_PENDATA = 10
+ CF_RIFF = 11
+ CF_WAVE = 12
+ CF_UNICODETEXT = 13
+ CF_ENHMETAFILE = 14
+ CF_HDROP = 15
+ CF_LOCALE = 16
+ CF_DIBV5 = 17
+ CF_MAX = 18
+ CF_OWNERDISPLAY = 0x0080
+ CF_DSPTEXT = 0x0081
+ CF_DSPBITMAP = 0x0082
+ CF_DSPMETAFILEPICT = 0x0083
+ CF_DSPENHMETAFILE = 0x008E
+ CF_PRIVATEFIRST = 0x0200
+ CF_PRIVATELAST = 0x02FF
+ CF_GDIOBJFIRST = 0x0300
+ CF_GDIOBJLAST = 0x03FF
+)
+
+// Bitmap compression formats
+const (
+ BI_RGB = 0
+ BI_RLE8 = 1
+ BI_RLE4 = 2
+ BI_BITFIELDS = 3
+ BI_JPEG = 4
+ BI_PNG = 5
+)
+
+// SetDIBitsToDevice fuColorUse
+const (
+ DIB_PAL_COLORS = 1
+ DIB_RGB_COLORS = 0
+)
+
+const (
+ STANDARD_RIGHTS_REQUIRED = 0x000F
+)
+
+// Service Control Manager object specific access types
+const (
+ SC_MANAGER_CONNECT = 0x0001
+ SC_MANAGER_CREATE_SERVICE = 0x0002
+ SC_MANAGER_ENUMERATE_SERVICE = 0x0004
+ SC_MANAGER_LOCK = 0x0008
+ SC_MANAGER_QUERY_LOCK_STATUS = 0x0010
+ SC_MANAGER_MODIFY_BOOT_CONFIG = 0x0020
+ SC_MANAGER_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_LOCK | SC_MANAGER_QUERY_LOCK_STATUS | SC_MANAGER_MODIFY_BOOT_CONFIG
+)
+
+// Service Types (Bit Mask)
+const (
+ SERVICE_KERNEL_DRIVER = 0x00000001
+ SERVICE_FILE_SYSTEM_DRIVER = 0x00000002
+ SERVICE_ADAPTER = 0x00000004
+ SERVICE_RECOGNIZER_DRIVER = 0x00000008
+ SERVICE_DRIVER = SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER
+ SERVICE_WIN32_OWN_PROCESS = 0x00000010
+ SERVICE_WIN32_SHARE_PROCESS = 0x00000020
+ SERVICE_WIN32 = SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS
+ SERVICE_INTERACTIVE_PROCESS = 0x00000100
+ SERVICE_TYPE_ALL = SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS
+)
+
+// Service State -- for CurrentState
+const (
+ SERVICE_STOPPED = 0x00000001
+ SERVICE_START_PENDING = 0x00000002
+ SERVICE_STOP_PENDING = 0x00000003
+ SERVICE_RUNNING = 0x00000004
+ SERVICE_CONTINUE_PENDING = 0x00000005
+ SERVICE_PAUSE_PENDING = 0x00000006
+ SERVICE_PAUSED = 0x00000007
+)
+
+// Controls Accepted (Bit Mask)
+const (
+ SERVICE_ACCEPT_STOP = 0x00000001
+ SERVICE_ACCEPT_PAUSE_CONTINUE = 0x00000002
+ SERVICE_ACCEPT_SHUTDOWN = 0x00000004
+ SERVICE_ACCEPT_PARAMCHANGE = 0x00000008
+ SERVICE_ACCEPT_NETBINDCHANGE = 0x00000010
+ SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 0x00000020
+ SERVICE_ACCEPT_POWEREVENT = 0x00000040
+ SERVICE_ACCEPT_SESSIONCHANGE = 0x00000080
+ SERVICE_ACCEPT_PRESHUTDOWN = 0x00000100
+ SERVICE_ACCEPT_TIMECHANGE = 0x00000200
+ SERVICE_ACCEPT_TRIGGEREVENT = 0x00000400
+)
+
+// Service object specific access type
+const (
+ SERVICE_QUERY_CONFIG = 0x0001
+ SERVICE_CHANGE_CONFIG = 0x0002
+ SERVICE_QUERY_STATUS = 0x0004
+ SERVICE_ENUMERATE_DEPENDENTS = 0x0008
+ SERVICE_START = 0x0010
+ SERVICE_STOP = 0x0020
+ SERVICE_PAUSE_CONTINUE = 0x0040
+ SERVICE_INTERROGATE = 0x0080
+ SERVICE_USER_DEFINED_CONTROL = 0x0100
+
+ SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
+ SERVICE_QUERY_CONFIG |
+ SERVICE_CHANGE_CONFIG |
+ SERVICE_QUERY_STATUS |
+ SERVICE_ENUMERATE_DEPENDENTS |
+ SERVICE_START |
+ SERVICE_STOP |
+ SERVICE_PAUSE_CONTINUE |
+ SERVICE_INTERROGATE |
+ SERVICE_USER_DEFINED_CONTROL
+)
+
+// MapVirtualKey maptypes
+const (
+ MAPVK_VK_TO_CHAR = 2
+ MAPVK_VK_TO_VSC = 0
+ MAPVK_VSC_TO_VK = 1
+ MAPVK_VSC_TO_VK_EX = 3
+)
+
+// ReadEventLog Flags
+const (
+ EVENTLOG_SEEK_READ = 0x0002
+ EVENTLOG_SEQUENTIAL_READ = 0x0001
+ EVENTLOG_FORWARDS_READ = 0x0004
+ EVENTLOG_BACKWARDS_READ = 0x0008
+)
+
+// CreateToolhelp32Snapshot flags
+const (
+ TH32CS_SNAPHEAPLIST = 0x00000001
+ TH32CS_SNAPPROCESS = 0x00000002
+ TH32CS_SNAPTHREAD = 0x00000004
+ TH32CS_SNAPMODULE = 0x00000008
+ TH32CS_SNAPMODULE32 = 0x00000010
+ TH32CS_INHERIT = 0x80000000
+ TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST | TH32CS_SNAPMODULE | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD
+)
+
+const (
+ MAX_MODULE_NAME32 = 255
+ MAX_PATH = 260
+)
+
+const (
+ NOTIFYICON_VERSION = 3
+ NOTIFYICON_VERSION_4 = 4
+)
+
+const (
+ NIM_ADD = 0x00000000
+ NIM_MODIFY = 0x00000001
+ NIM_DELETE = 0x00000002
+ NIM_SETVERSION = 0x00000004
+
+ NIF_MESSAGE = 0x00000001
+ NIF_ICON = 0x00000002
+ NIF_TIP = 0x00000004
+ NIF_STATE = 0x00000008
+ NIF_INFO = 0x00000010
+ NIF_GUID = 0x00000020
+ NIF_REALTIME = 0x00000040
+ NIF_SHOWTIP = 0x00000080
+
+ NIS_HIDDEN = 0x00000001
+
+ NIN_POPUPOPEN = WM_USER + 6
+ NIN_POPUPCLOSE = WM_USER + 7
+
+ NIIF_NONE = 0x00000000
+ NIIF_INFO = 0x00000001
+ NIIF_WARNING = 0x00000002
+ NIIF_ERROR = 0x00000003
+ NIIF_USER = 0x00000004
+ NIIF_NOSOUND = 0x00000010
+ NIIF_LARGE_ICON = 0x00000020
+ NIIF_RESPECT_QUIET_TIME = 0x00000080
+ NIIF_ICON_MASK = 0x0000000F
+)
+
+const (
+ FOREGROUND_BLUE = 0x0001
+ FOREGROUND_GREEN = 0x0002
+ FOREGROUND_RED = 0x0004
+ FOREGROUND_INTENSITY = 0x0008
+ BACKGROUND_BLUE = 0x0010
+ BACKGROUND_GREEN = 0x0020
+ BACKGROUND_RED = 0x0040
+ BACKGROUND_INTENSITY = 0x0080
+ COMMON_LVB_LEADING_BYTE = 0x0100
+ COMMON_LVB_TRAILING_BYTE = 0x0200
+ COMMON_LVB_GRID_HORIZONTAL = 0x0400
+ COMMON_LVB_GRID_LVERTICAL = 0x0800
+ COMMON_LVB_GRID_RVERTICAL = 0x1000
+ COMMON_LVB_REVERSE_VIDEO = 0x4000
+ COMMON_LVB_UNDERSCORE = 0x8000
+)
+
+// Flags used by the DWM_BLURBEHIND structure to indicate
+// which of its members contain valid information.
+const (
+ DWM_BB_ENABLE = 0x00000001 // A value for the fEnable member has been specified.
+ DWM_BB_BLURREGION = 0x00000002 // A value for the hRgnBlur member has been specified.
+ DWM_BB_TRANSITIONONMAXIMIZED = 0x00000004 // A value for the fTransitionOnMaximized member has been specified.
+)
+
+// Flags used by the DwmEnableComposition function
+// to change the state of Desktop Window Manager (DWM) composition.
+const (
+ DWM_EC_DISABLECOMPOSITION = 0 // Disable composition
+ DWM_EC_ENABLECOMPOSITION = 1 // Enable composition
+)
+
+// enum-lite implementation for the following constant structure
+type DWM_SHOWCONTACT int32
+
+const (
+ DWMSC_DOWN = 0x00000001
+ DWMSC_UP = 0x00000002
+ DWMSC_DRAG = 0x00000004
+ DWMSC_HOLD = 0x00000008
+ DWMSC_PENBARREL = 0x00000010
+ DWMSC_NONE = 0x00000000
+ DWMSC_ALL = 0xFFFFFFFF
+)
+
+// enum-lite implementation for the following constant structure
+type DWM_SOURCE_FRAME_SAMPLING int32
+
+// TODO: need to verify this construction
+// Flags used by the DwmSetPresentParameters function
+// to specify the frame sampling type
+const (
+ DWM_SOURCE_FRAME_SAMPLING_POINT = iota + 1
+ DWM_SOURCE_FRAME_SAMPLING_COVERAGE
+ DWM_SOURCE_FRAME_SAMPLING_LAST
+)
+
+// Flags used by the DWM_THUMBNAIL_PROPERTIES structure to
+// indicate which of its members contain valid information.
+const (
+ DWM_TNP_RECTDESTINATION = 0x00000001 // A value for the rcDestination member has been specified
+ DWM_TNP_RECTSOURCE = 0x00000002 // A value for the rcSource member has been specified
+ DWM_TNP_OPACITY = 0x00000004 // A value for the opacity member has been specified
+ DWM_TNP_VISIBLE = 0x00000008 // A value for the fVisible member has been specified
+ DWM_TNP_SOURCECLIENTAREAONLY = 0x00000010 // A value for the fSourceClientAreaOnly member has been specified
+)
+
+// enum-lite implementation for the following constant structure
+type DWMFLIP3DWINDOWPOLICY int32
+
+// TODO: need to verify this construction
+// Flags used by the DwmSetWindowAttribute function
+// to specify the Flip3D window policy
+const (
+ DWMFLIP3D_DEFAULT = iota + 1
+ DWMFLIP3D_EXCLUDEBELOW
+ DWMFLIP3D_EXCLUDEABOVE
+ DWMFLIP3D_LAST
+)
+
+// enum-lite implementation for the following constant structure
+type DWMNCRENDERINGPOLICY int32
+
+// TODO: need to verify this construction
+// Flags used by the DwmSetWindowAttribute function
+// to specify the non-client area rendering policy
+const (
+ DWMNCRP_USEWINDOWSTYLE = iota + 1
+ DWMNCRP_DISABLED
+ DWMNCRP_ENABLED
+ DWMNCRP_LAST
+)
+
+// enum-lite implementation for the following constant structure
+type DWMTRANSITION_OWNEDWINDOW_TARGET int32
+
+const (
+ DWMTRANSITION_OWNEDWINDOW_NULL = -1
+ DWMTRANSITION_OWNEDWINDOW_REPOSITION = 0
+)
+
+// TODO: need to verify this construction
+// Flags used by the DwmGetWindowAttribute and DwmSetWindowAttribute functions
+// to specify window attributes for non-client rendering
+const (
+ DWMWA_NCRENDERING_ENABLED = iota + 1
+ DWMWA_NCRENDERING_POLICY
+ DWMWA_TRANSITIONS_FORCEDISABLED
+ DWMWA_ALLOW_NCPAINT
+ DWMWA_CAPTION_BUTTON_BOUNDS
+ DWMWA_NONCLIENT_RTL_LAYOUT
+ DWMWA_FORCE_ICONIC_REPRESENTATION
+ DWMWA_FLIP3D_POLICY
+ DWMWA_EXTENDED_FRAME_BOUNDS
+ DWMWA_HAS_ICONIC_BITMAP
+ DWMWA_DISALLOW_PEEK
+ DWMWA_EXCLUDED_FROM_PEEK
+ DWMWA_CLOAK
+ DWMWA_CLOAKED
+ DWMWA_FREEZE_REPRESENTATION
+ DWMWA_LAST
+)
+
+// enum-lite implementation for the following constant structure
+type GESTURE_TYPE int32
+
+// TODO: use iota?
+// Identifies the gesture type
+const (
+ GT_PEN_TAP = 0
+ GT_PEN_DOUBLETAP = 1
+ GT_PEN_RIGHTTAP = 2
+ GT_PEN_PRESSANDHOLD = 3
+ GT_PEN_PRESSANDHOLDABORT = 4
+ GT_TOUCH_TAP = 5
+ GT_TOUCH_DOUBLETAP = 6
+ GT_TOUCH_RIGHTTAP = 7
+ GT_TOUCH_PRESSANDHOLD = 8
+ GT_TOUCH_PRESSANDHOLDABORT = 9
+ GT_TOUCH_PRESSANDTAP = 10
+)
+
+// Icons
+const (
+ ICON_SMALL = 0
+ ICON_BIG = 1
+ ICON_SMALL2 = 2
+)
+
+const (
+ SIZE_RESTORED = 0
+ SIZE_MINIMIZED = 1
+ SIZE_MAXIMIZED = 2
+ SIZE_MAXSHOW = 3
+ SIZE_MAXHIDE = 4
+)
+
+// XButton values
+const (
+ XBUTTON1 = 1
+ XBUTTON2 = 2
+)
+
+const (
+ LR_LOADFROMFILE = 0x00000010
+ LR_DEFAULTSIZE = 0x00000040
+)
+
+// Devmode
+const (
+ DM_SPECVERSION = 0x0401
+
+ DM_ORIENTATION = 0x00000001
+ DM_PAPERSIZE = 0x00000002
+ DM_PAPERLENGTH = 0x00000004
+ DM_PAPERWIDTH = 0x00000008
+ DM_SCALE = 0x00000010
+ DM_POSITION = 0x00000020
+ DM_NUP = 0x00000040
+ DM_DISPLAYORIENTATION = 0x00000080
+ DM_COPIES = 0x00000100
+ DM_DEFAULTSOURCE = 0x00000200
+ DM_PRINTQUALITY = 0x00000400
+ DM_COLOR = 0x00000800
+ DM_DUPLEX = 0x00001000
+ DM_YRESOLUTION = 0x00002000
+ DM_TTOPTION = 0x00004000
+ DM_COLLATE = 0x00008000
+ DM_FORMNAME = 0x00010000
+ DM_LOGPIXELS = 0x00020000
+ DM_BITSPERPEL = 0x00040000
+ DM_PELSWIDTH = 0x00080000
+ DM_PELSHEIGHT = 0x00100000
+ DM_DISPLAYFLAGS = 0x00200000
+ DM_DISPLAYFREQUENCY = 0x00400000
+ DM_ICMMETHOD = 0x00800000
+ DM_ICMINTENT = 0x01000000
+ DM_MEDIATYPE = 0x02000000
+ DM_DITHERTYPE = 0x04000000
+ DM_PANNINGWIDTH = 0x08000000
+ DM_PANNINGHEIGHT = 0x10000000
+ DM_DISPLAYFIXEDOUTPUT = 0x20000000
+)
+
+// ChangeDisplaySettings
+const (
+ CDS_UPDATEREGISTRY = 0x00000001
+ CDS_TEST = 0x00000002
+ CDS_FULLSCREEN = 0x00000004
+ CDS_GLOBAL = 0x00000008
+ CDS_SET_PRIMARY = 0x00000010
+ CDS_VIDEOPARAMETERS = 0x00000020
+ CDS_RESET = 0x40000000
+ CDS_NORESET = 0x10000000
+
+ DISP_CHANGE_SUCCESSFUL = 0
+ DISP_CHANGE_RESTART = 1
+ DISP_CHANGE_FAILED = -1
+ DISP_CHANGE_BADMODE = -2
+ DISP_CHANGE_NOTUPDATED = -3
+ DISP_CHANGE_BADFLAGS = -4
+ DISP_CHANGE_BADPARAM = -5
+ DISP_CHANGE_BADDUALVIEW = -6
+)
+
+const (
+ ENUM_CURRENT_SETTINGS = 0xFFFFFFFF
+ ENUM_REGISTRY_SETTINGS = 0xFFFFFFFE
+)
+
+// PIXELFORMATDESCRIPTOR
+const (
+ PFD_TYPE_RGBA = 0
+ PFD_TYPE_COLORINDEX = 1
+
+ PFD_MAIN_PLANE = 0
+ PFD_OVERLAY_PLANE = 1
+ PFD_UNDERLAY_PLANE = -1
+
+ PFD_DOUBLEBUFFER = 0x00000001
+ PFD_STEREO = 0x00000002
+ PFD_DRAW_TO_WINDOW = 0x00000004
+ PFD_DRAW_TO_BITMAP = 0x00000008
+ PFD_SUPPORT_GDI = 0x00000010
+ PFD_SUPPORT_OPENGL = 0x00000020
+ PFD_GENERIC_FORMAT = 0x00000040
+ PFD_NEED_PALETTE = 0x00000080
+ PFD_NEED_SYSTEM_PALETTE = 0x00000100
+ PFD_SWAP_EXCHANGE = 0x00000200
+ PFD_SWAP_COPY = 0x00000400
+ PFD_SWAP_LAYER_BUFFERS = 0x00000800
+ PFD_GENERIC_ACCELERATED = 0x00001000
+ PFD_SUPPORT_DIRECTDRAW = 0x00002000
+ PFD_DIRECT3D_ACCELERATED = 0x00004000
+ PFD_SUPPORT_COMPOSITION = 0x00008000
+
+ PFD_DEPTH_DONTCARE = 0x20000000
+ PFD_DOUBLEBUFFER_DONTCARE = 0x40000000
+ PFD_STEREO_DONTCARE = 0x80000000
+)
+
+const (
+ INPUT_MOUSE = 0
+ INPUT_KEYBOARD = 1
+ INPUT_HARDWARE = 2
+)
+
+const (
+ KEYEVENTF_EXTENDEDKEY = 0x0001
+ KEYEVENTF_KEYUP = 0x0002
+ KEYEVENTF_SCANCODE = 0x0008
+ KEYEVENTF_UNICODE = 0x0004
+)
+
+const (
+ MOUSEEVENTF_ABSOLUTE = 0x8000
+ MOUSEEVENTF_HWHEEL = 0x01000
+ MOUSEEVENTF_MOVE = 0x0001
+ MOUSEEVENTF_MOVE_NOCOALESCE = 0x2000
+ MOUSEEVENTF_LEFTDOWN = 0x0002
+ MOUSEEVENTF_LEFTUP = 0x0004
+ MOUSEEVENTF_RIGHTDOWN = 0x0008
+ MOUSEEVENTF_RIGHTUP = 0x0010
+ MOUSEEVENTF_MIDDLEDOWN = 0x0020
+ MOUSEEVENTF_MIDDLEUP = 0x0040
+ MOUSEEVENTF_VIRTUALDESK = 0x4000
+ MOUSEEVENTF_WHEEL = 0x0800
+ MOUSEEVENTF_XDOWN = 0x0080
+ MOUSEEVENTF_XUP = 0x0100
+)
+
+// Windows Hooks (WH_*)
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx
+const (
+ WH_CALLWNDPROC = 4
+ WH_CALLWNDPROCRET = 12
+ WH_CBT = 5
+ WH_DEBUG = 9
+ WH_FOREGROUNDIDLE = 11
+ WH_GETMESSAGE = 3
+ WH_JOURNALPLAYBACK = 1
+ WH_JOURNALRECORD = 0
+ WH_KEYBOARD = 2
+ WH_KEYBOARD_LL = 13
+ WH_MOUSE = 7
+ WH_MOUSE_LL = 14
+ WH_MSGFILTER = -1
+ WH_SHELL = 10
+ WH_SYSMSGFILTER = 6
+)
+
+// ComboBox return values
+const (
+ CB_OKAY = 0
+ CB_ERR = ^uintptr(0) // -1
+ CB_ERRSPACE = ^uintptr(1) // -2
+)
+
+// ComboBox notifications
+const (
+ CBN_ERRSPACE = -1
+ CBN_SELCHANGE = 1
+ CBN_DBLCLK = 2
+ CBN_SETFOCUS = 3
+ CBN_KILLFOCUS = 4
+ CBN_EDITCHANGE = 5
+ CBN_EDITUPDATE = 6
+ CBN_DROPDOWN = 7
+ CBN_CLOSEUP = 8
+ CBN_SELENDOK = 9
+ CBN_SELENDCANCEL = 10
+)
+
+// ComboBox styles
+const (
+ CBS_SIMPLE = 0x0001
+ CBS_DROPDOWN = 0x0002
+ CBS_DROPDOWNLIST = 0x0003
+ CBS_OWNERDRAWFIXED = 0x0010
+ CBS_OWNERDRAWVARIABLE = 0x0020
+ CBS_AUTOHSCROLL = 0x0040
+ CBS_OEMCONVERT = 0x0080
+ CBS_SORT = 0x0100
+ CBS_HASSTRINGS = 0x0200
+ CBS_NOINTEGRALHEIGHT = 0x0400
+ CBS_DISABLENOSCROLL = 0x0800
+ CBS_UPPERCASE = 0x2000
+ CBS_LOWERCASE = 0x4000
+)
+
+// ComboBox messages
+const (
+ CB_GETEDITSEL = 0x0140
+ CB_LIMITTEXT = 0x0141
+ CB_SETEDITSEL = 0x0142
+ CB_ADDSTRING = 0x0143
+ CB_DELETESTRING = 0x0144
+ CB_DIR = 0x0145
+ CB_GETCOUNT = 0x0146
+ CB_GETCURSEL = 0x0147
+ CB_GETLBTEXT = 0x0148
+ CB_GETLBTEXTLEN = 0x0149
+ CB_INSERTSTRING = 0x014A
+ CB_RESETCONTENT = 0x014B
+ CB_FINDSTRING = 0x014C
+ CB_SELECTSTRING = 0x014D
+ CB_SETCURSEL = 0x014E
+ CB_SHOWDROPDOWN = 0x014F
+ CB_GETITEMDATA = 0x0150
+ CB_SETITEMDATA = 0x0151
+ CB_GETDROPPEDCONTROLRECT = 0x0152
+ CB_SETITEMHEIGHT = 0x0153
+ CB_GETITEMHEIGHT = 0x0154
+ CB_SETEXTENDEDUI = 0x0155
+ CB_GETEXTENDEDUI = 0x0156
+ CB_GETDROPPEDSTATE = 0x0157
+ CB_FINDSTRINGEXACT = 0x0158
+ CB_SETLOCALE = 0x0159
+ CB_GETLOCALE = 0x015A
+ CB_GETTOPINDEX = 0x015b
+ CB_SETTOPINDEX = 0x015c
+ CB_GETHORIZONTALEXTENT = 0x015d
+ CB_SETHORIZONTALEXTENT = 0x015e
+ CB_GETDROPPEDWIDTH = 0x015f
+ CB_SETDROPPEDWIDTH = 0x0160
+ CB_INITSTORAGE = 0x0161
+ CB_MULTIPLEADDSTRING = 0x0163
+ CB_GETCOMBOBOXINFO = 0x0164
+)
+
+// TreeView styles
+const (
+ TVS_HASBUTTONS = 0x0001
+ TVS_HASLINES = 0x0002
+ TVS_LINESATROOT = 0x0004
+ TVS_EDITLABELS = 0x0008
+ TVS_DISABLEDRAGDROP = 0x0010
+ TVS_SHOWSELALWAYS = 0x0020
+ TVS_RTLREADING = 0x0040
+ TVS_NOTOOLTIPS = 0x0080
+ TVS_CHECKBOXES = 0x0100
+ TVS_TRACKSELECT = 0x0200
+ TVS_SINGLEEXPAND = 0x0400
+ TVS_INFOTIP = 0x0800
+ TVS_FULLROWSELECT = 0x1000
+ TVS_NOSCROLL = 0x2000
+ TVS_NONEVENHEIGHT = 0x4000
+ TVS_NOHSCROLL = 0x8000
+)
+
+const (
+ TVS_EX_NOSINGLECOLLAPSE = 0x0001
+ TVS_EX_MULTISELECT = 0x0002
+ TVS_EX_DOUBLEBUFFER = 0x0004
+ TVS_EX_NOINDENTSTATE = 0x0008
+ TVS_EX_RICHTOOLTIP = 0x0010
+ TVS_EX_AUTOHSCROLL = 0x0020
+ TVS_EX_FADEINOUTEXPANDOS = 0x0040
+ TVS_EX_PARTIALCHECKBOXES = 0x0080
+ TVS_EX_EXCLUSIONCHECKBOXES = 0x0100
+ TVS_EX_DIMMEDCHECKBOXES = 0x0200
+ TVS_EX_DRAWIMAGEASYNC = 0x0400
+)
+
+const (
+ TVIF_TEXT = 0x0001
+ TVIF_IMAGE = 0x0002
+ TVIF_PARAM = 0x0004
+ TVIF_STATE = 0x0008
+ TVIF_HANDLE = 0x0010
+ TVIF_SELECTEDIMAGE = 0x0020
+ TVIF_CHILDREN = 0x0040
+ TVIF_INTEGRAL = 0x0080
+ TVIF_STATEEX = 0x0100
+ TVIF_EXPANDEDIMAGE = 0x0200
+)
+
+const (
+ TVIS_SELECTED = 0x0002
+ TVIS_CUT = 0x0004
+ TVIS_DROPHILITED = 0x0008
+ TVIS_BOLD = 0x0010
+ TVIS_EXPANDED = 0x0020
+ TVIS_EXPANDEDONCE = 0x0040
+ TVIS_EXPANDPARTIAL = 0x0080
+ TVIS_OVERLAYMASK = 0x0F00
+ TVIS_STATEIMAGEMASK = 0xF000
+ TVIS_USERMASK = 0xF000
+)
+
+const (
+ TVIS_EX_FLAT = 0x0001
+ TVIS_EX_DISABLED = 0x0002
+ TVIS_EX_ALL = 0x0002
+)
+
+const (
+ TVI_ROOT = ^HTREEITEM(0xffff)
+ TVI_FIRST = ^HTREEITEM(0xfffe)
+ TVI_LAST = ^HTREEITEM(0xfffd)
+ TVI_SORT = ^HTREEITEM(0xfffc)
+)
+
+// TVM_EXPAND action flags
+const (
+ TVE_COLLAPSE = 0x0001
+ TVE_EXPAND = 0x0002
+ TVE_TOGGLE = 0x0003
+ TVE_EXPANDPARTIAL = 0x4000
+ TVE_COLLAPSERESET = 0x8000
+)
+
+const (
+ TVGN_CARET = 9
+)
+
+// TreeView messages
+const (
+ TV_FIRST = 0x1100
+
+ TVM_INSERTITEM = TV_FIRST + 50
+ TVM_DELETEITEM = TV_FIRST + 1
+ TVM_EXPAND = TV_FIRST + 2
+ TVM_GETITEMRECT = TV_FIRST + 4
+ TVM_GETCOUNT = TV_FIRST + 5
+ TVM_GETINDENT = TV_FIRST + 6
+ TVM_SETINDENT = TV_FIRST + 7
+ TVM_GETIMAGELIST = TV_FIRST + 8
+ TVM_SETIMAGELIST = TV_FIRST + 9
+ TVM_GETNEXTITEM = TV_FIRST + 10
+ TVM_SELECTITEM = TV_FIRST + 11
+ TVM_GETITEM = TV_FIRST + 62
+ TVM_SETITEM = TV_FIRST + 63
+ TVM_EDITLABEL = TV_FIRST + 65
+ TVM_GETEDITCONTROL = TV_FIRST + 15
+ TVM_GETVISIBLECOUNT = TV_FIRST + 16
+ TVM_HITTEST = TV_FIRST + 17
+ TVM_CREATEDRAGIMAGE = TV_FIRST + 18
+ TVM_SORTCHILDREN = TV_FIRST + 19
+ TVM_ENSUREVISIBLE = TV_FIRST + 20
+ TVM_SORTCHILDRENCB = TV_FIRST + 21
+ TVM_ENDEDITLABELNOW = TV_FIRST + 22
+ TVM_GETISEARCHSTRING = TV_FIRST + 64
+ TVM_SETTOOLTIPS = TV_FIRST + 24
+ TVM_GETTOOLTIPS = TV_FIRST + 25
+ TVM_SETINSERTMARK = TV_FIRST + 26
+ TVM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT
+ TVM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT
+ TVM_SETITEMHEIGHT = TV_FIRST + 27
+ TVM_GETITEMHEIGHT = TV_FIRST + 28
+ TVM_SETBKCOLOR = TV_FIRST + 29
+ TVM_SETTEXTCOLOR = TV_FIRST + 30
+ TVM_GETBKCOLOR = TV_FIRST + 31
+ TVM_GETTEXTCOLOR = TV_FIRST + 32
+ TVM_SETSCROLLTIME = TV_FIRST + 33
+ TVM_GETSCROLLTIME = TV_FIRST + 34
+ TVM_SETINSERTMARKCOLOR = TV_FIRST + 37
+ TVM_GETINSERTMARKCOLOR = TV_FIRST + 38
+ TVM_GETITEMSTATE = TV_FIRST + 39
+ TVM_SETLINECOLOR = TV_FIRST + 40
+ TVM_GETLINECOLOR = TV_FIRST + 41
+ TVM_MAPACCIDTOHTREEITEM = TV_FIRST + 42
+ TVM_MAPHTREEITEMTOACCID = TV_FIRST + 43
+ TVM_SETEXTENDEDSTYLE = TV_FIRST + 44
+ TVM_GETEXTENDEDSTYLE = TV_FIRST + 45
+ TVM_SETAUTOSCROLLINFO = TV_FIRST + 59
+)
+
+// TreeView notifications
+const (
+ TVN_FIRST = ^uint32(399)
+
+ TVN_SELCHANGING = TVN_FIRST - 50
+ TVN_SELCHANGED = TVN_FIRST - 51
+ TVN_GETDISPINFO = TVN_FIRST - 52
+ TVN_ITEMEXPANDING = TVN_FIRST - 54
+ TVN_ITEMEXPANDED = TVN_FIRST - 55
+ TVN_BEGINDRAG = TVN_FIRST - 56
+ TVN_BEGINRDRAG = TVN_FIRST - 57
+ TVN_DELETEITEM = TVN_FIRST - 58
+ TVN_BEGINLABELEDIT = TVN_FIRST - 59
+ TVN_ENDLABELEDIT = TVN_FIRST - 60
+ TVN_KEYDOWN = TVN_FIRST - 12
+ TVN_GETINFOTIP = TVN_FIRST - 14
+ TVN_SINGLEEXPAND = TVN_FIRST - 15
+ TVN_ITEMCHANGING = TVN_FIRST - 17
+ TVN_ITEMCHANGED = TVN_FIRST - 19
+ TVN_ASYNCDRAW = TVN_FIRST - 20
+)
+
+// TreeView hit test constants
+const (
+ TVHT_NOWHERE = 1
+ TVHT_ONITEMICON = 2
+ TVHT_ONITEMLABEL = 4
+ TVHT_ONITEM = TVHT_ONITEMICON | TVHT_ONITEMLABEL | TVHT_ONITEMSTATEICON
+ TVHT_ONITEMINDENT = 8
+ TVHT_ONITEMBUTTON = 16
+ TVHT_ONITEMRIGHT = 32
+ TVHT_ONITEMSTATEICON = 64
+ TVHT_ABOVE = 256
+ TVHT_BELOW = 512
+ TVHT_TORIGHT = 1024
+ TVHT_TOLEFT = 2048
+)
+
+type HTREEITEM HANDLE
+
+type TVITEM struct {
+ Mask uint32
+ HItem HTREEITEM
+ State uint32
+ StateMask uint32
+ PszText uintptr
+ CchTextMax int32
+ IImage int32
+ ISelectedImage int32
+ CChildren int32
+ LParam uintptr
+}
+
+/*type TVITEMEX struct {
+ mask UINT
+ hItem HTREEITEM
+ state UINT
+ stateMask UINT
+ pszText LPWSTR
+ cchTextMax int
+ iImage int
+ iSelectedImage int
+ cChildren int
+ lParam LPARAM
+ iIntegral int
+ uStateEx UINT
+ hwnd HWND
+ iExpandedImage int
+}*/
+
+type TVINSERTSTRUCT struct {
+ HParent HTREEITEM
+ HInsertAfter HTREEITEM
+ Item TVITEM
+ // itemex TVITEMEX
+}
+
+type NMTREEVIEW struct {
+ Hdr NMHDR
+ Action uint32
+ ItemOld TVITEM
+ ItemNew TVITEM
+ PtDrag POINT
+}
+
+type NMTVDISPINFO struct {
+ Hdr NMHDR
+ Item TVITEM
+}
+
+type NMTVKEYDOWN struct {
+ Hdr NMHDR
+ WVKey uint16
+ Flags uint32
+}
+
+type TVHITTESTINFO struct {
+ Pt POINT
+ Flags uint32
+ HItem HTREEITEM
+}
+
+// TabPage support
+
+const TCM_FIRST = 0x1300
+const TCN_FIRST = -550
+
+const (
+ TCS_SCROLLOPPOSITE = 0x0001
+ TCS_BOTTOM = 0x0002
+ TCS_RIGHT = 0x0002
+ TCS_MULTISELECT = 0x0004
+ TCS_FLATBUTTONS = 0x0008
+ TCS_FORCEICONLEFT = 0x0010
+ TCS_FORCELABELLEFT = 0x0020
+ TCS_HOTTRACK = 0x0040
+ TCS_VERTICAL = 0x0080
+ TCS_TABS = 0x0000
+ TCS_BUTTONS = 0x0100
+ TCS_SINGLELINE = 0x0000
+ TCS_MULTILINE = 0x0200
+ TCS_RIGHTJUSTIFY = 0x0000
+ TCS_FIXEDWIDTH = 0x0400
+ TCS_RAGGEDRIGHT = 0x0800
+ TCS_FOCUSONBUTTONDOWN = 0x1000
+ TCS_OWNERDRAWFIXED = 0x2000
+ TCS_TOOLTIPS = 0x4000
+ TCS_FOCUSNEVER = 0x8000
+)
+
+const (
+ TCS_EX_FLATSEPARATORS = 0x00000001
+ TCS_EX_REGISTERDROP = 0x00000002
+)
+
+const (
+ TCM_GETIMAGELIST = TCM_FIRST + 2
+ TCM_SETIMAGELIST = TCM_FIRST + 3
+ TCM_GETITEMCOUNT = TCM_FIRST + 4
+ TCM_GETITEM = TCM_FIRST + 60
+ TCM_SETITEM = TCM_FIRST + 61
+ TCM_INSERTITEM = TCM_FIRST + 62
+ TCM_DELETEITEM = TCM_FIRST + 8
+ TCM_DELETEALLITEMS = TCM_FIRST + 9
+ TCM_GETITEMRECT = TCM_FIRST + 10
+ TCM_GETCURSEL = TCM_FIRST + 11
+ TCM_SETCURSEL = TCM_FIRST + 12
+ TCM_HITTEST = TCM_FIRST + 13
+ TCM_SETITEMEXTRA = TCM_FIRST + 14
+ TCM_ADJUSTRECT = TCM_FIRST + 40
+ TCM_SETITEMSIZE = TCM_FIRST + 41
+ TCM_REMOVEIMAGE = TCM_FIRST + 42
+ TCM_SETPADDING = TCM_FIRST + 43
+ TCM_GETROWCOUNT = TCM_FIRST + 44
+ TCM_GETTOOLTIPS = TCM_FIRST + 45
+ TCM_SETTOOLTIPS = TCM_FIRST + 46
+ TCM_GETCURFOCUS = TCM_FIRST + 47
+ TCM_SETCURFOCUS = TCM_FIRST + 48
+ TCM_SETMINTABWIDTH = TCM_FIRST + 49
+ TCM_DESELECTALL = TCM_FIRST + 50
+ TCM_HIGHLIGHTITEM = TCM_FIRST + 51
+ TCM_SETEXTENDEDSTYLE = TCM_FIRST + 52
+ TCM_GETEXTENDEDSTYLE = TCM_FIRST + 53
+ TCM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT
+ TCM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT
+)
+
+const (
+ TCIF_TEXT = 0x0001
+ TCIF_IMAGE = 0x0002
+ TCIF_RTLREADING = 0x0004
+ TCIF_PARAM = 0x0008
+ TCIF_STATE = 0x0010
+)
+
+const (
+ TCIS_BUTTONPRESSED = 0x0001
+ TCIS_HIGHLIGHTED = 0x0002
+)
+
+const (
+ TCHT_NOWHERE = 0x0001
+ TCHT_ONITEMICON = 0x0002
+ TCHT_ONITEMLABEL = 0x0004
+ TCHT_ONITEM = TCHT_ONITEMICON | TCHT_ONITEMLABEL
+)
+
+const (
+ TCN_KEYDOWN = TCN_FIRST - 0
+ TCN_SELCHANGE = TCN_FIRST - 1
+ TCN_SELCHANGING = TCN_FIRST - 2
+ TCN_GETOBJECT = TCN_FIRST - 3
+ TCN_FOCUSCHANGE = TCN_FIRST - 4
+)
+
+type TCITEMHEADER struct {
+ Mask uint32
+ LpReserved1 uint32
+ LpReserved2 uint32
+ PszText *uint16
+ CchTextMax int32
+ IImage int32
+}
+
+type TCITEM struct {
+ Mask uint32
+ DwState uint32
+ DwStateMask uint32
+ PszText *uint16
+ CchTextMax int32
+ IImage int32
+ LParam uintptr
+}
+
+type TCHITTESTINFO struct {
+ Pt POINT
+ flags uint32
+}
+
+type NMTCKEYDOWN struct {
+ Hdr NMHDR
+ WVKey uint16
+ Flags uint32
+}
+
+// Menu support constants
+
+// Constants for MENUITEMINFO.fMask
+const (
+ MIIM_STATE = 1
+ MIIM_ID = 2
+ MIIM_SUBMENU = 4
+ MIIM_CHECKMARKS = 8
+ MIIM_TYPE = 16
+ MIIM_DATA = 32
+ MIIM_STRING = 64
+ MIIM_BITMAP = 128
+ MIIM_FTYPE = 256
+)
+
+// Constants for MENUITEMINFO.fType
+const (
+ MFT_BITMAP = 4
+ MFT_MENUBARBREAK = 32
+ MFT_MENUBREAK = 64
+ MFT_OWNERDRAW = 256
+ MFT_RADIOCHECK = 512
+ MFT_RIGHTJUSTIFY = 0x4000
+ MFT_SEPARATOR = 0x800
+ MFT_RIGHTORDER = 0x2000
+ MFT_STRING = 0
+)
+
+// Constants for MENUITEMINFO.fState
+const (
+ MFS_CHECKED = 8
+ MFS_DEFAULT = 4096
+ MFS_DISABLED = 3
+ MFS_ENABLED = 0
+ MFS_GRAYED = 3
+ MFS_HILITE = 128
+ MFS_UNCHECKED = 0
+ MFS_UNHILITE = 0
+)
+
+// Constants for MENUITEMINFO.hbmp*
+const (
+ HBMMENU_CALLBACK = -1
+ HBMMENU_SYSTEM = 1
+ HBMMENU_MBAR_RESTORE = 2
+ HBMMENU_MBAR_MINIMIZE = 3
+ HBMMENU_MBAR_CLOSE = 5
+ HBMMENU_MBAR_CLOSE_D = 6
+ HBMMENU_MBAR_MINIMIZE_D = 7
+ HBMMENU_POPUP_CLOSE = 8
+ HBMMENU_POPUP_RESTORE = 9
+ HBMMENU_POPUP_MAXIMIZE = 10
+ HBMMENU_POPUP_MINIMIZE = 11
+)
+
+// MENUINFO mask constants
+const (
+ MIM_APPLYTOSUBMENUS = 0x80000000
+ MIM_BACKGROUND = 0x00000002
+ MIM_HELPID = 0x00000004
+ MIM_MAXHEIGHT = 0x00000001
+ MIM_MENUDATA = 0x00000008
+ MIM_STYLE = 0x00000010
+)
+
+// MENUINFO style constants
+const (
+ MNS_AUTODISMISS = 0x10000000
+ MNS_CHECKORBMP = 0x04000000
+ MNS_DRAGDROP = 0x20000000
+ MNS_MODELESS = 0x40000000
+ MNS_NOCHECK = 0x80000000
+ MNS_NOTIFYBYPOS = 0x08000000
+)
+
+const (
+ MF_BYCOMMAND = 0x00000000
+ MF_BYPOSITION = 0x00000400
+ MF_BITMAP = 0x00000004
+ MF_CHECKED = 0x00000008
+ MF_DISABLED = 0x00000002
+ MF_ENABLED = 0x00000000
+ MF_GRAYED = 0x00000001
+ MF_MENUBARBREAK = 0x00000020
+ MF_MENUBREAK = 0x00000040
+ MF_OWNERDRAW = 0x00000100
+ MF_POPUP = 0x00000010
+ MF_SEPARATOR = 0x00000800
+ MF_STRING = 0x00000000
+ MF_UNCHECKED = 0x00000000
+)
+
+type MENUITEMINFO struct {
+ CbSize uint32
+ FMask uint32
+ FType uint32
+ FState uint32
+ WID uint32
+ HSubMenu HMENU
+ HbmpChecked HBITMAP
+ HbmpUnchecked HBITMAP
+ DwItemData uintptr
+ DwTypeData *uint16
+ Cch uint32
+ HbmpItem HBITMAP
+}
+
+type MENUINFO struct {
+ CbSize uint32
+ FMask uint32
+ DwStyle uint32
+ CyMax uint32
+ HbrBack HBRUSH
+ DwContextHelpID uint32
+ DwMenuData uintptr
+}
+
+// UI state constants
+const (
+ UIS_SET = 1
+ UIS_CLEAR = 2
+ UIS_INITIALIZE = 3
+)
+
+// UI state constants
+const (
+ UISF_HIDEFOCUS = 0x1
+ UISF_HIDEACCEL = 0x2
+ UISF_ACTIVE = 0x4
+)
+
+// Virtual key codes
+const (
+ VK_LBUTTON = 1
+ VK_RBUTTON = 2
+ VK_CANCEL = 3
+ VK_MBUTTON = 4
+ VK_XBUTTON1 = 5
+ VK_XBUTTON2 = 6
+ VK_BACK = 8
+ VK_TAB = 9
+ VK_CLEAR = 12
+ VK_RETURN = 13
+ VK_SHIFT = 16
+ VK_CONTROL = 17
+ VK_MENU = 18
+ VK_PAUSE = 19
+ VK_CAPITAL = 20
+ VK_KANA = 0x15
+ VK_HANGEUL = 0x15
+ VK_HANGUL = 0x15
+ VK_JUNJA = 0x17
+ VK_FINAL = 0x18
+ VK_HANJA = 0x19
+ VK_KANJI = 0x19
+ VK_ESCAPE = 0x1B
+ VK_CONVERT = 0x1C
+ VK_NONCONVERT = 0x1D
+ VK_ACCEPT = 0x1E
+ VK_MODECHANGE = 0x1F
+ VK_SPACE = 32
+ VK_PRIOR = 33
+ VK_NEXT = 34
+ VK_END = 35
+ VK_HOME = 36
+ VK_LEFT = 37
+ VK_UP = 38
+ VK_RIGHT = 39
+ VK_DOWN = 40
+ VK_SELECT = 41
+ VK_PRINT = 42
+ VK_EXECUTE = 43
+ VK_SNAPSHOT = 44
+ VK_INSERT = 45
+ VK_DELETE = 46
+ VK_HELP = 47
+ VK_LWIN = 0x5B
+ VK_RWIN = 0x5C
+ VK_APPS = 0x5D
+ VK_SLEEP = 0x5F
+ VK_NUMPAD0 = 0x60
+ VK_NUMPAD1 = 0x61
+ VK_NUMPAD2 = 0x62
+ VK_NUMPAD3 = 0x63
+ VK_NUMPAD4 = 0x64
+ VK_NUMPAD5 = 0x65
+ VK_NUMPAD6 = 0x66
+ VK_NUMPAD7 = 0x67
+ VK_NUMPAD8 = 0x68
+ VK_NUMPAD9 = 0x69
+ VK_MULTIPLY = 0x6A
+ VK_ADD = 0x6B
+ VK_SEPARATOR = 0x6C
+ VK_SUBTRACT = 0x6D
+ VK_DECIMAL = 0x6E
+ VK_DIVIDE = 0x6F
+ VK_F1 = 0x70
+ VK_F2 = 0x71
+ VK_F3 = 0x72
+ VK_F4 = 0x73
+ VK_F5 = 0x74
+ VK_F6 = 0x75
+ VK_F7 = 0x76
+ VK_F8 = 0x77
+ VK_F9 = 0x78
+ VK_F10 = 0x79
+ VK_F11 = 0x7A
+ VK_F12 = 0x7B
+ VK_F13 = 0x7C
+ VK_F14 = 0x7D
+ VK_F15 = 0x7E
+ VK_F16 = 0x7F
+ VK_F17 = 0x80
+ VK_F18 = 0x81
+ VK_F19 = 0x82
+ VK_F20 = 0x83
+ VK_F21 = 0x84
+ VK_F22 = 0x85
+ VK_F23 = 0x86
+ VK_F24 = 0x87
+ VK_NUMLOCK = 0x90
+ VK_SCROLL = 0x91
+ VK_LSHIFT = 0xA0
+ VK_RSHIFT = 0xA1
+ VK_LCONTROL = 0xA2
+ VK_RCONTROL = 0xA3
+ VK_LMENU = 0xA4
+ VK_RMENU = 0xA5
+ VK_BROWSER_BACK = 0xA6
+ VK_BROWSER_FORWARD = 0xA7
+ VK_BROWSER_REFRESH = 0xA8
+ VK_BROWSER_STOP = 0xA9
+ VK_BROWSER_SEARCH = 0xAA
+ VK_BROWSER_FAVORITES = 0xAB
+ VK_BROWSER_HOME = 0xAC
+ VK_VOLUME_MUTE = 0xAD
+ VK_VOLUME_DOWN = 0xAE
+ VK_VOLUME_UP = 0xAF
+ VK_MEDIA_NEXT_TRACK = 0xB0
+ VK_MEDIA_PREV_TRACK = 0xB1
+ VK_MEDIA_STOP = 0xB2
+ VK_MEDIA_PLAY_PAUSE = 0xB3
+ VK_LAUNCH_MAIL = 0xB4
+ VK_LAUNCH_MEDIA_SELECT = 0xB5
+ VK_LAUNCH_APP1 = 0xB6
+ VK_LAUNCH_APP2 = 0xB7
+ VK_OEM_1 = 0xBA
+ VK_OEM_PLUS = 0xBB
+ VK_OEM_COMMA = 0xBC
+ VK_OEM_MINUS = 0xBD
+ VK_OEM_PERIOD = 0xBE
+ VK_OEM_2 = 0xBF
+ VK_OEM_3 = 0xC0
+ VK_OEM_4 = 0xDB
+ VK_OEM_5 = 0xDC
+ VK_OEM_6 = 0xDD
+ VK_OEM_7 = 0xDE
+ VK_OEM_8 = 0xDF
+ VK_OEM_102 = 0xE2
+ VK_PROCESSKEY = 0xE5
+ VK_PACKET = 0xE7
+ VK_ATTN = 0xF6
+ VK_CRSEL = 0xF7
+ VK_EXSEL = 0xF8
+ VK_EREOF = 0xF9
+ VK_PLAY = 0xFA
+ VK_ZOOM = 0xFB
+ VK_NONAME = 0xFC
+ VK_PA1 = 0xFD
+ VK_OEM_CLEAR = 0xFE
+)
+
+// ScrollBar constants
+const (
+ SB_HORZ = 0
+ SB_VERT = 1
+ SB_CTL = 2
+ SB_BOTH = 3
+)
+
+// ScrollBar commands
+const (
+ SB_LINEUP = 0
+ SB_LINELEFT = 0
+ SB_LINEDOWN = 1
+ SB_LINERIGHT = 1
+ SB_PAGEUP = 2
+ SB_PAGELEFT = 2
+ SB_PAGEDOWN = 3
+ SB_PAGERIGHT = 3
+ SB_THUMBPOSITION = 4
+ SB_THUMBTRACK = 5
+ SB_TOP = 6
+ SB_LEFT = 6
+ SB_BOTTOM = 7
+ SB_RIGHT = 7
+ SB_ENDSCROLL = 8
+)
+
+// [Get|Set]ScrollInfo mask constants
+const (
+ SIF_RANGE = 1
+ SIF_PAGE = 2
+ SIF_POS = 4
+ SIF_DISABLENOSCROLL = 8
+ SIF_TRACKPOS = 16
+ SIF_ALL = SIF_RANGE + SIF_PAGE + SIF_POS + SIF_TRACKPOS
+)
+
+const AC_SRC_OVER = 0
+const AC_SRC_ALPHA = 1
+
+const ULW_COLORKEY = 1
+const ULW_ALPHA = 2
+const ULW_OPAQUE = 4
+const ULW_EX_NORESIZE = 8
+
+// RedrawWindow flags
+const (
+ RDW_INVALIDATE = 0x0001
+ RDW_INTERNALPAINT = 0x0002
+ RDW_ERASE = 0x0004
+ RDW_VALIDATE = 0x0008
+ RDW_NOINTERNALPAINT = 0x0010
+ RDW_NOERASE = 0x0020
+ RDW_NOCHILDREN = 0x0040
+ RDW_ALLCHILDREN = 0x0080
+ RDW_UPDATENOW = 0x0100
+ RDW_ERASENOW = 0x0200
+ RDW_FRAME = 0x0400
+ RDW_NOFRAME = 0x0800
+)
diff --git a/v3/pkg/w32/consts.go b/v3/pkg/w32/consts.go
new file mode 100644
index 000000000..b8cdf0358
--- /dev/null
+++ b/v3/pkg/w32/consts.go
@@ -0,0 +1,102 @@
+//go:build windows
+
+package w32
+
+import (
+ "fmt"
+ "golang.org/x/sys/windows"
+ "golang.org/x/sys/windows/registry"
+ "strconv"
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modwingdi = syscall.NewLazyDLL("gdi32.dll")
+ procCreateSolidBrush = modwingdi.NewProc("CreateSolidBrush")
+)
+var (
+ kernel32 = syscall.NewLazyDLL("kernel32")
+ kernelGlobalAlloc = kernel32.NewProc("GlobalAlloc")
+ kernelGlobalFree = kernel32.NewProc("GlobalFree")
+ kernelGlobalLock = kernel32.NewProc("GlobalLock")
+ kernelGlobalUnlock = kernel32.NewProc("GlobalUnlock")
+ kernelLstrcpy = kernel32.NewProc("lstrcpyW")
+)
+var (
+ modBranding = syscall.NewLazyDLL("winbrand.dll")
+ brandingFormatString = modBranding.NewProc("BrandingFormatString")
+)
+
+var windowsVersion, _ = GetWindowsVersionInfo()
+
+func IsWindowsVersionAtLeast(major, minor, buildNumber int) bool {
+ return windowsVersion.Major >= major &&
+ windowsVersion.Minor >= minor &&
+ windowsVersion.Build >= buildNumber
+}
+
+type WindowsVersionInfo struct {
+ Major int
+ Minor int
+ Build int
+ DisplayVersion string
+}
+
+func (w *WindowsVersionInfo) String() string {
+ return fmt.Sprintf("%d.%d.%d (%s)", w.Major, w.Minor, w.Build, w.DisplayVersion)
+}
+
+func (w *WindowsVersionInfo) IsWindowsVersionAtLeast(major, minor, buildNumber int) bool {
+ return w.Major >= major && w.Minor >= minor && w.Build >= buildNumber
+}
+
+func GetBranding() string {
+ windowsLong := MustStringToUTF16Ptr("%WINDOWS_LONG%\x00")
+ ret, _, _ := brandingFormatString.Call(
+ uintptr(unsafe.Pointer(windowsLong)),
+ )
+ return windows.UTF16PtrToString((*uint16)(unsafe.Pointer(ret)))
+}
+
+func GetWindowsVersionInfo() (*WindowsVersionInfo, error) {
+ key, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
+ if err != nil {
+ return nil, err
+ }
+
+ return &WindowsVersionInfo{
+ Major: regDWORDKeyAsInt(key, "CurrentMajorVersionNumber"),
+ Minor: regDWORDKeyAsInt(key, "CurrentMinorVersionNumber"),
+ Build: regStringKeyAsInt(key, "CurrentBuildNumber"),
+ DisplayVersion: regKeyAsString(key, "DisplayVersion"),
+ }, nil
+}
+
+func regDWORDKeyAsInt(key registry.Key, name string) int {
+ result, _, err := key.GetIntegerValue(name)
+ if err != nil {
+ return -1
+ }
+ return int(result)
+}
+
+func regStringKeyAsInt(key registry.Key, name string) int {
+ resultStr, _, err := key.GetStringValue(name)
+ if err != nil {
+ return -1
+ }
+ result, err := strconv.Atoi(resultStr)
+ if err != nil {
+ return -1
+ }
+ return result
+}
+
+func regKeyAsString(key registry.Key, name string) string {
+ resultStr, _, err := key.GetStringValue(name)
+ if err != nil {
+ return ""
+ }
+ return resultStr
+}
diff --git a/v3/pkg/w32/dialogs.go b/v3/pkg/w32/dialogs.go
new file mode 100644
index 000000000..d327187c0
--- /dev/null
+++ b/v3/pkg/w32/dialogs.go
@@ -0,0 +1,28 @@
+//go:build windows
+
+package w32
+
+import (
+ "unsafe"
+)
+
+func MessageBoxWithIcon(hwnd HWND, text *uint16, caption *uint16, iconID int, flags uint32) (int32, error) {
+
+ params := MSGBOXPARAMS{
+ cbSize: uint32(unsafe.Sizeof(MSGBOXPARAMS{})),
+ hwndOwner: hwnd,
+ hInstance: GetApplicationHandle(),
+ lpszText: text,
+ lpszCaption: caption,
+ dwStyle: flags,
+ lpszIcon: (*uint16)(unsafe.Pointer(uintptr(iconID))),
+ }
+
+ r, _, err := procMessageBoxIndirect.Call(
+ uintptr(unsafe.Pointer(¶ms)),
+ )
+ if r == 0 {
+ return 0, err
+ }
+ return int32(r), nil
+}
diff --git a/v3/pkg/w32/dwmapi.go b/v3/pkg/w32/dwmapi.go
new file mode 100644
index 000000000..1b911efc3
--- /dev/null
+++ b/v3/pkg/w32/dwmapi.go
@@ -0,0 +1,46 @@
+//go:build windows
+
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ moddwmapi = syscall.NewLazyDLL("dwmapi.dll")
+
+ procDwmSetWindowAttribute = moddwmapi.NewProc("DwmSetWindowAttribute")
+ procDwmGetWindowAttribute = moddwmapi.NewProc("DwmGetWindowAttribute")
+ procDwmExtendFrameIntoClientArea = moddwmapi.NewProc("DwmExtendFrameIntoClientArea")
+)
+
+func DwmSetWindowAttribute(hwnd HWND, dwAttribute DWMWINDOWATTRIBUTE, pvAttribute unsafe.Pointer, cbAttribute uintptr) HRESULT {
+ ret, _, _ := procDwmSetWindowAttribute.Call(
+ hwnd,
+ uintptr(dwAttribute),
+ uintptr(pvAttribute),
+ cbAttribute)
+ return HRESULT(ret)
+}
+
+func DwmGetWindowAttribute(hwnd HWND, dwAttribute DWMWINDOWATTRIBUTE, pvAttribute unsafe.Pointer, cbAttribute uintptr) HRESULT {
+ ret, _, _ := procDwmGetWindowAttribute.Call(
+ hwnd,
+ uintptr(dwAttribute),
+ uintptr(pvAttribute),
+ cbAttribute)
+ return HRESULT(ret)
+}
+
+func dwmExtendFrameIntoClientArea(hwnd uintptr, margins *MARGINS) error {
+ ret, _, _ := procDwmExtendFrameIntoClientArea.Call(
+ hwnd,
+ uintptr(unsafe.Pointer(margins)))
+
+ if ret != 0 {
+ return syscall.GetLastError()
+ }
+
+ return nil
+}
diff --git a/v3/pkg/w32/gdi32.go b/v3/pkg/w32/gdi32.go
new file mode 100644
index 000000000..04d11ca14
--- /dev/null
+++ b/v3/pkg/w32/gdi32.go
@@ -0,0 +1,581 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 The Winc Authors. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modgdi32 = syscall.NewLazyDLL("gdi32.dll")
+
+ procGetDeviceCaps = modgdi32.NewProc("GetDeviceCaps")
+ procDeleteObject = modgdi32.NewProc("DeleteObject")
+ procCreateFontIndirect = modgdi32.NewProc("CreateFontIndirectW")
+ procAbortDoc = modgdi32.NewProc("AbortDoc")
+ procBitBlt = modgdi32.NewProc("BitBlt")
+ procPatBlt = modgdi32.NewProc("PatBlt")
+ procCloseEnhMetaFile = modgdi32.NewProc("CloseEnhMetaFile")
+ procCopyEnhMetaFile = modgdi32.NewProc("CopyEnhMetaFileW")
+ procCreateBrushIndirect = modgdi32.NewProc("CreateBrushIndirect")
+ procCreateCompatibleDC = modgdi32.NewProc("CreateCompatibleDC")
+ procCreateDC = modgdi32.NewProc("CreateDCW")
+ procCreateDIBSection = modgdi32.NewProc("CreateDIBSection")
+ procCreateEnhMetaFile = modgdi32.NewProc("CreateEnhMetaFileW")
+ procCreateIC = modgdi32.NewProc("CreateICW")
+ procDeleteDC = modgdi32.NewProc("DeleteDC")
+ procDeleteEnhMetaFile = modgdi32.NewProc("DeleteEnhMetaFile")
+ procEllipse = modgdi32.NewProc("Ellipse")
+ procEndDoc = modgdi32.NewProc("EndDoc")
+ procEndPage = modgdi32.NewProc("EndPage")
+ procExtCreatePen = modgdi32.NewProc("ExtCreatePen")
+ procGetEnhMetaFile = modgdi32.NewProc("GetEnhMetaFileW")
+ procGetEnhMetaFileHeader = modgdi32.NewProc("GetEnhMetaFileHeader")
+ procGetObject = modgdi32.NewProc("GetObjectW")
+ procGetStockObject = modgdi32.NewProc("GetStockObject")
+ procGetTextExtentExPoint = modgdi32.NewProc("GetTextExtentExPointW")
+ procGetTextExtentPoint32 = modgdi32.NewProc("GetTextExtentPoint32W")
+ procGetTextMetrics = modgdi32.NewProc("GetTextMetricsW")
+ procLineTo = modgdi32.NewProc("LineTo")
+ procMoveToEx = modgdi32.NewProc("MoveToEx")
+ procPlayEnhMetaFile = modgdi32.NewProc("PlayEnhMetaFile")
+ procRectangle = modgdi32.NewProc("Rectangle")
+ procResetDC = modgdi32.NewProc("ResetDCW")
+ procSelectObject = modgdi32.NewProc("SelectObject")
+ procSetBkMode = modgdi32.NewProc("SetBkMode")
+ procSetBrushOrgEx = modgdi32.NewProc("SetBrushOrgEx")
+ procSetStretchBltMode = modgdi32.NewProc("SetStretchBltMode")
+ procSetTextColor = modgdi32.NewProc("SetTextColor")
+ procSetBkColor = modgdi32.NewProc("SetBkColor")
+ procStartDoc = modgdi32.NewProc("StartDocW")
+ procStartPage = modgdi32.NewProc("StartPage")
+ procStretchBlt = modgdi32.NewProc("StretchBlt")
+ procSetDIBitsToDevice = modgdi32.NewProc("SetDIBitsToDevice")
+ procChoosePixelFormat = modgdi32.NewProc("ChoosePixelFormat")
+ procDescribePixelFormat = modgdi32.NewProc("DescribePixelFormat")
+ procGetEnhMetaFilePixelFormat = modgdi32.NewProc("GetEnhMetaFilePixelFormat")
+ procGetPixelFormat = modgdi32.NewProc("GetPixelFormat")
+ procSetPixelFormat = modgdi32.NewProc("SetPixelFormat")
+ procSwapBuffers = modgdi32.NewProc("SwapBuffers")
+ procSaveDC = modgdi32.NewProc("SaveDC")
+ procRestoreDC = modgdi32.NewProc("RestoreDC")
+ procSelectClipRgn = modgdi32.NewProc("SelectClipRgn")
+ procExcludeClipRect = modgdi32.NewProc("ExcludeClipRect")
+ procExtTextOut = modgdi32.NewProc("ExtTextOutW")
+)
+
+func GetDeviceCaps(hdc HDC, index int) int {
+ ret, _, _ := procGetDeviceCaps.Call(
+ uintptr(hdc),
+ uintptr(index))
+
+ return int(ret)
+}
+
+func DeleteObject(hObject HGDIOBJ) bool {
+ ret, _, _ := procDeleteObject.Call(
+ uintptr(hObject))
+
+ return ret != 0
+}
+
+func CreateFontIndirect(logFont *LOGFONT) HFONT {
+ ret, _, _ := procCreateFontIndirect.Call(
+ uintptr(unsafe.Pointer(logFont)))
+
+ return HFONT(ret)
+}
+
+func AbortDoc(hdc HDC) int {
+ ret, _, _ := procAbortDoc.Call(
+ uintptr(hdc))
+
+ return int(ret)
+}
+
+func BitBlt(hdcDest HDC, nXDest, nYDest, nWidth, nHeight int, hdcSrc HDC, nXSrc, nYSrc int, dwRop uint) {
+ ret, _, _ := procBitBlt.Call(
+ uintptr(hdcDest),
+ uintptr(nXDest),
+ uintptr(nYDest),
+ uintptr(nWidth),
+ uintptr(nHeight),
+ uintptr(hdcSrc),
+ uintptr(nXSrc),
+ uintptr(nYSrc),
+ uintptr(dwRop))
+
+ if ret == 0 {
+ panic("BitBlt failed")
+ }
+}
+
+func PatBlt(hdc HDC, nXLeft, nYLeft, nWidth, nHeight int, dwRop uint) {
+ ret, _, _ := procPatBlt.Call(
+ uintptr(hdc),
+ uintptr(nXLeft),
+ uintptr(nYLeft),
+ uintptr(nWidth),
+ uintptr(nHeight),
+ uintptr(dwRop))
+
+ if ret == 0 {
+ panic("PatBlt failed")
+ }
+}
+
+func CloseEnhMetaFile(hdc HDC) HENHMETAFILE {
+ ret, _, _ := procCloseEnhMetaFile.Call(
+ uintptr(hdc))
+
+ return HENHMETAFILE(ret)
+}
+
+func CopyEnhMetaFile(hemfSrc HENHMETAFILE, lpszFile *uint16) HENHMETAFILE {
+ ret, _, _ := procCopyEnhMetaFile.Call(
+ uintptr(hemfSrc),
+ uintptr(unsafe.Pointer(lpszFile)))
+
+ return HENHMETAFILE(ret)
+}
+
+func CreateBrushIndirect(lplb *LOGBRUSH) HBRUSH {
+ ret, _, _ := procCreateBrushIndirect.Call(
+ uintptr(unsafe.Pointer(lplb)))
+
+ return HBRUSH(ret)
+}
+
+func CreateCompatibleDC(hdc HDC) HDC {
+ ret, _, _ := procCreateCompatibleDC.Call(
+ uintptr(hdc))
+
+ if ret == 0 {
+ panic("Create compatible DC failed")
+ }
+
+ return HDC(ret)
+}
+
+func CreateDC(lpszDriver, lpszDevice, lpszOutput *uint16, lpInitData *DEVMODE) HDC {
+ ret, _, _ := procCreateDC.Call(
+ uintptr(unsafe.Pointer(lpszDriver)),
+ uintptr(unsafe.Pointer(lpszDevice)),
+ uintptr(unsafe.Pointer(lpszOutput)),
+ uintptr(unsafe.Pointer(lpInitData)))
+
+ return HDC(ret)
+}
+
+func CreateDIBSection(hdc HDC, pbmi *BITMAPINFO, iUsage uint, ppvBits *unsafe.Pointer, hSection HANDLE, dwOffset uint) HBITMAP {
+ ret, _, _ := procCreateDIBSection.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(pbmi)),
+ uintptr(iUsage),
+ uintptr(unsafe.Pointer(ppvBits)),
+ uintptr(hSection),
+ uintptr(dwOffset))
+
+ return HBITMAP(ret)
+}
+
+func CreateEnhMetaFile(hdcRef HDC, lpFilename *uint16, lpRect *RECT, lpDescription *uint16) HDC {
+ ret, _, _ := procCreateEnhMetaFile.Call(
+ uintptr(hdcRef),
+ uintptr(unsafe.Pointer(lpFilename)),
+ uintptr(unsafe.Pointer(lpRect)),
+ uintptr(unsafe.Pointer(lpDescription)))
+
+ return HDC(ret)
+}
+
+func CreateIC(lpszDriver, lpszDevice, lpszOutput *uint16, lpdvmInit *DEVMODE) HDC {
+ ret, _, _ := procCreateIC.Call(
+ uintptr(unsafe.Pointer(lpszDriver)),
+ uintptr(unsafe.Pointer(lpszDevice)),
+ uintptr(unsafe.Pointer(lpszOutput)),
+ uintptr(unsafe.Pointer(lpdvmInit)))
+
+ return HDC(ret)
+}
+
+func DeleteDC(hdc HDC) bool {
+ ret, _, _ := procDeleteDC.Call(
+ uintptr(hdc))
+
+ return ret != 0
+}
+
+func DeleteEnhMetaFile(hemf HENHMETAFILE) bool {
+ ret, _, _ := procDeleteEnhMetaFile.Call(
+ uintptr(hemf))
+
+ return ret != 0
+}
+
+func Ellipse(hdc HDC, nLeftRect, nTopRect, nRightRect, nBottomRect int32) bool {
+ ret, _, _ := procEllipse.Call(
+ uintptr(hdc),
+ uintptr(nLeftRect),
+ uintptr(nTopRect),
+ uintptr(nRightRect),
+ uintptr(nBottomRect))
+
+ return ret != 0
+}
+
+func EndDoc(hdc HDC) int {
+ ret, _, _ := procEndDoc.Call(
+ uintptr(hdc))
+
+ return int(ret)
+}
+
+func EndPage(hdc HDC) int {
+ ret, _, _ := procEndPage.Call(
+ uintptr(hdc))
+
+ return int(ret)
+}
+
+func ExtCreatePen(dwPenStyle, dwWidth uint, lplb *LOGBRUSH, dwStyleCount uint, lpStyle *uint) HPEN {
+ ret, _, _ := procExtCreatePen.Call(
+ uintptr(dwPenStyle),
+ uintptr(dwWidth),
+ uintptr(unsafe.Pointer(lplb)),
+ uintptr(dwStyleCount),
+ uintptr(unsafe.Pointer(lpStyle)))
+
+ return HPEN(ret)
+}
+
+func GetEnhMetaFile(lpszMetaFile *uint16) HENHMETAFILE {
+ ret, _, _ := procGetEnhMetaFile.Call(
+ uintptr(unsafe.Pointer(lpszMetaFile)))
+
+ return HENHMETAFILE(ret)
+}
+
+func GetEnhMetaFileHeader(hemf HENHMETAFILE, cbBuffer uint, lpemh *ENHMETAHEADER) uint {
+ ret, _, _ := procGetEnhMetaFileHeader.Call(
+ uintptr(hemf),
+ uintptr(cbBuffer),
+ uintptr(unsafe.Pointer(lpemh)))
+
+ return uint(ret)
+}
+
+func GetObject(hgdiobj HGDIOBJ, cbBuffer uintptr, lpvObject unsafe.Pointer) int {
+ ret, _, _ := procGetObject.Call(
+ uintptr(hgdiobj),
+ uintptr(cbBuffer),
+ uintptr(lpvObject))
+
+ return int(ret)
+}
+
+func GetStockObject(fnObject int) HGDIOBJ {
+ ret, _, _ := procGetDeviceCaps.Call(
+ uintptr(fnObject))
+
+ return HGDIOBJ(ret)
+}
+
+func GetTextExtentExPoint(hdc HDC, lpszStr *uint16, cchString, nMaxExtent int, lpnFit, alpDx *int, lpSize *SIZE) bool {
+ ret, _, _ := procGetTextExtentExPoint.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(lpszStr)),
+ uintptr(cchString),
+ uintptr(nMaxExtent),
+ uintptr(unsafe.Pointer(lpnFit)),
+ uintptr(unsafe.Pointer(alpDx)),
+ uintptr(unsafe.Pointer(lpSize)))
+
+ return ret != 0
+}
+
+func GetTextExtentPoint32(hdc HDC, lpString *uint16, c int, lpSize *SIZE) bool {
+ ret, _, _ := procGetTextExtentPoint32.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(lpString)),
+ uintptr(c),
+ uintptr(unsafe.Pointer(lpSize)))
+
+ return ret != 0
+}
+
+func GetTextMetrics(hdc HDC, lptm *TEXTMETRIC) bool {
+ ret, _, _ := procGetTextMetrics.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(lptm)))
+
+ return ret != 0
+}
+
+func LineTo(hdc HDC, nXEnd, nYEnd int32) bool {
+ ret, _, _ := procLineTo.Call(
+ uintptr(hdc),
+ uintptr(nXEnd),
+ uintptr(nYEnd))
+
+ return ret != 0
+}
+
+func MoveToEx(hdc HDC, x, y int, lpPoint *POINT) bool {
+ ret, _, _ := procMoveToEx.Call(
+ uintptr(hdc),
+ uintptr(x),
+ uintptr(y),
+ uintptr(unsafe.Pointer(lpPoint)))
+
+ return ret != 0
+}
+
+func PlayEnhMetaFile(hdc HDC, hemf HENHMETAFILE, lpRect *RECT) bool {
+ ret, _, _ := procPlayEnhMetaFile.Call(
+ uintptr(hdc),
+ uintptr(hemf),
+ uintptr(unsafe.Pointer(lpRect)))
+
+ return ret != 0
+}
+
+func Rectangle(hdc HDC, nLeftRect, nTopRect, nRightRect, nBottomRect int32) bool {
+ ret, _, _ := procRectangle.Call(
+ uintptr(hdc),
+ uintptr(nLeftRect),
+ uintptr(nTopRect),
+ uintptr(nRightRect),
+ uintptr(nBottomRect))
+
+ return ret != 0
+}
+
+func ResetDC(hdc HDC, lpInitData *DEVMODE) HDC {
+ ret, _, _ := procResetDC.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(lpInitData)))
+
+ return HDC(ret)
+}
+
+func SelectObject(hdc HDC, hgdiobj HGDIOBJ) HGDIOBJ {
+ ret, _, _ := procSelectObject.Call(
+ uintptr(hdc),
+ uintptr(hgdiobj))
+
+ if ret == 0 {
+ panic("SelectObject failed")
+ }
+
+ return HGDIOBJ(ret)
+}
+
+func SetBkMode(hdc HDC, iBkMode int) int {
+ ret, _, _ := procSetBkMode.Call(
+ uintptr(hdc),
+ uintptr(iBkMode))
+
+ if ret == 0 {
+ panic("SetBkMode failed")
+ }
+
+ return int(ret)
+}
+
+func SetBrushOrgEx(hdc HDC, nXOrg, nYOrg int, lppt *POINT) bool {
+ ret, _, _ := procSetBrushOrgEx.Call(
+ uintptr(hdc),
+ uintptr(nXOrg),
+ uintptr(nYOrg),
+ uintptr(unsafe.Pointer(lppt)))
+
+ return ret != 0
+}
+
+func SetStretchBltMode(hdc HDC, iStretchMode int) int {
+ ret, _, _ := procSetStretchBltMode.Call(
+ uintptr(hdc),
+ uintptr(iStretchMode))
+
+ return int(ret)
+}
+
+func SetTextColor(hdc HDC, crColor COLORREF) COLORREF {
+ ret, _, _ := procSetTextColor.Call(
+ uintptr(hdc),
+ uintptr(crColor))
+
+ if ret == CLR_INVALID {
+ panic("SetTextColor failed")
+ }
+
+ return COLORREF(ret)
+}
+
+func SetBkColor(hdc HDC, crColor COLORREF) COLORREF {
+ ret, _, _ := procSetBkColor.Call(
+ uintptr(hdc),
+ uintptr(crColor))
+
+ if ret == CLR_INVALID {
+ panic("SetBkColor failed")
+ }
+
+ return COLORREF(ret)
+}
+
+func StartDoc(hdc HDC, lpdi *DOCINFO) int {
+ ret, _, _ := procStartDoc.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(lpdi)))
+
+ return int(ret)
+}
+
+func StartPage(hdc HDC) int {
+ ret, _, _ := procStartPage.Call(
+ uintptr(hdc))
+
+ return int(ret)
+}
+
+func StretchBlt(hdcDest HDC, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest int, hdcSrc HDC, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc int, dwRop uint) {
+ ret, _, _ := procStretchBlt.Call(
+ uintptr(hdcDest),
+ uintptr(nXOriginDest),
+ uintptr(nYOriginDest),
+ uintptr(nWidthDest),
+ uintptr(nHeightDest),
+ uintptr(hdcSrc),
+ uintptr(nXOriginSrc),
+ uintptr(nYOriginSrc),
+ uintptr(nWidthSrc),
+ uintptr(nHeightSrc),
+ uintptr(dwRop))
+
+ if ret == 0 {
+ panic("StretchBlt failed")
+ }
+}
+
+func SetDIBitsToDevice(hdc HDC, xDest, yDest, dwWidth, dwHeight, xSrc, ySrc int, uStartScan, cScanLines uint, lpvBits []byte, lpbmi *BITMAPINFO, fuColorUse uint) int {
+ ret, _, _ := procSetDIBitsToDevice.Call(
+ uintptr(hdc),
+ uintptr(xDest),
+ uintptr(yDest),
+ uintptr(dwWidth),
+ uintptr(dwHeight),
+ uintptr(xSrc),
+ uintptr(ySrc),
+ uintptr(uStartScan),
+ uintptr(cScanLines),
+ uintptr(unsafe.Pointer(&lpvBits[0])),
+ uintptr(unsafe.Pointer(lpbmi)),
+ uintptr(fuColorUse))
+
+ return int(ret)
+}
+
+func ChoosePixelFormat(hdc HDC, pfd *PIXELFORMATDESCRIPTOR) int {
+ ret, _, _ := procChoosePixelFormat.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(pfd)),
+ )
+ return int(ret)
+}
+
+func DescribePixelFormat(hdc HDC, iPixelFormat int, nBytes uint, pfd *PIXELFORMATDESCRIPTOR) int {
+ ret, _, _ := procDescribePixelFormat.Call(
+ uintptr(hdc),
+ uintptr(iPixelFormat),
+ uintptr(nBytes),
+ uintptr(unsafe.Pointer(pfd)),
+ )
+ return int(ret)
+}
+
+func GetEnhMetaFilePixelFormat(hemf HENHMETAFILE, cbBuffer uint32, pfd *PIXELFORMATDESCRIPTOR) uint {
+ ret, _, _ := procGetEnhMetaFilePixelFormat.Call(
+ uintptr(hemf),
+ uintptr(cbBuffer),
+ uintptr(unsafe.Pointer(pfd)),
+ )
+ return uint(ret)
+}
+
+func GetPixelFormat(hdc HDC) int {
+ ret, _, _ := procGetPixelFormat.Call(
+ uintptr(hdc),
+ )
+ return int(ret)
+}
+
+func SetPixelFormat(hdc HDC, iPixelFormat int, pfd *PIXELFORMATDESCRIPTOR) bool {
+ ret, _, _ := procSetPixelFormat.Call(
+ uintptr(hdc),
+ uintptr(iPixelFormat),
+ uintptr(unsafe.Pointer(pfd)),
+ )
+ return ret == TRUE
+}
+
+func SwapBuffers(hdc HDC) bool {
+ ret, _, _ := procSwapBuffers.Call(uintptr(hdc))
+ return ret == TRUE
+}
+
+func SaveDC(hdc HDC) int {
+ ret, _, _ := procSaveDC.Call(uintptr(hdc))
+ return int(ret)
+}
+
+func RestoreDC(hdc HDC, nSavedDC int) bool {
+ ret, _, _ := procRestoreDC.Call(
+ uintptr(hdc),
+ uintptr(nSavedDC))
+ return ret != 0
+}
+
+func SelectClipRgn(hdc HDC, hrgn HRGN) int {
+ ret, _, _ := procSelectClipRgn.Call(
+ uintptr(hdc),
+ uintptr(hrgn))
+ return int(ret)
+}
+
+func ExcludeClipRect(hdc HDC, left, top, right, bottom int32) int {
+ ret, _, _ := procExcludeClipRect.Call(
+ uintptr(hdc),
+ uintptr(left),
+ uintptr(top),
+ uintptr(right),
+ uintptr(bottom))
+ return int(ret)
+}
+
+func ExtTextOut(hdc HDC, x, y int32, fuOptions uint32, lprc *RECT, lpString *uint16, cbCount uint32, lpDx *int) bool {
+ var rectPtr uintptr
+ if lprc != nil {
+ rectPtr = uintptr(unsafe.Pointer(lprc))
+ }
+ var dxPtr uintptr
+ if lpDx != nil {
+ dxPtr = uintptr(unsafe.Pointer(lpDx))
+ }
+ ret, _, _ := procExtTextOut.Call(
+ uintptr(hdc),
+ uintptr(x),
+ uintptr(y),
+ uintptr(fuOptions),
+ rectPtr,
+ uintptr(unsafe.Pointer(lpString)),
+ uintptr(cbCount),
+ dxPtr)
+ return ret != 0
+}
diff --git a/v3/pkg/w32/gdiplus.go b/v3/pkg/w32/gdiplus.go
new file mode 100644
index 000000000..2591ed71b
--- /dev/null
+++ b/v3/pkg/w32/gdiplus.go
@@ -0,0 +1,177 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 The Winc Authors. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+import (
+ "errors"
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+const (
+ Ok = 0
+ GenericError = 1
+ InvalidParameter = 2
+ OutOfMemory = 3
+ ObjectBusy = 4
+ InsufficientBuffer = 5
+ NotImplemented = 6
+ Win32Error = 7
+ WrongState = 8
+ Aborted = 9
+ FileNotFound = 10
+ ValueOverflow = 11
+ AccessDenied = 12
+ UnknownImageFormat = 13
+ FontFamilyNotFound = 14
+ FontStyleNotFound = 15
+ NotTrueTypeFont = 16
+ UnsupportedGdiplusVersion = 17
+ GdiplusNotInitialized = 18
+ PropertyNotFound = 19
+ PropertyNotSupported = 20
+ ProfileNotFound = 21
+)
+
+func GetGpStatus(s int32) string {
+ switch s {
+ case Ok:
+ return "Ok"
+ case GenericError:
+ return "GenericError"
+ case InvalidParameter:
+ return "InvalidParameter"
+ case OutOfMemory:
+ return "OutOfMemory"
+ case ObjectBusy:
+ return "ObjectBusy"
+ case InsufficientBuffer:
+ return "InsufficientBuffer"
+ case NotImplemented:
+ return "NotImplemented"
+ case Win32Error:
+ return "Win32Error"
+ case WrongState:
+ return "WrongState"
+ case Aborted:
+ return "Aborted"
+ case FileNotFound:
+ return "FileNotFound"
+ case ValueOverflow:
+ return "ValueOverflow"
+ case AccessDenied:
+ return "AccessDenied"
+ case UnknownImageFormat:
+ return "UnknownImageFormat"
+ case FontFamilyNotFound:
+ return "FontFamilyNotFound"
+ case FontStyleNotFound:
+ return "FontStyleNotFound"
+ case NotTrueTypeFont:
+ return "NotTrueTypeFont"
+ case UnsupportedGdiplusVersion:
+ return "UnsupportedGdiplusVersion"
+ case GdiplusNotInitialized:
+ return "GdiplusNotInitialized"
+ case PropertyNotFound:
+ return "PropertyNotFound"
+ case PropertyNotSupported:
+ return "PropertyNotSupported"
+ case ProfileNotFound:
+ return "ProfileNotFound"
+ }
+ return "Unknown Status Value"
+}
+
+var (
+ token uintptr
+
+ modgdiplus = syscall.NewLazyDLL("gdiplus.dll")
+
+ procGdipCreateBitmapFromFile = modgdiplus.NewProc("GdipCreateBitmapFromFile")
+ procGdipCreateBitmapFromHBITMAP = modgdiplus.NewProc("GdipCreateBitmapFromHBITMAP")
+ procGdipCreateHBITMAPFromBitmap = modgdiplus.NewProc("GdipCreateHBITMAPFromBitmap")
+ procGdipCreateBitmapFromResource = modgdiplus.NewProc("GdipCreateBitmapFromResource")
+ procGdipCreateBitmapFromStream = modgdiplus.NewProc("GdipCreateBitmapFromStream")
+ procGdipDisposeImage = modgdiplus.NewProc("GdipDisposeImage")
+ procGdiplusShutdown = modgdiplus.NewProc("GdiplusShutdown")
+ procGdiplusStartup = modgdiplus.NewProc("GdiplusStartup")
+)
+
+func GdipCreateBitmapFromFile(filename string) (*uintptr, error) {
+ var bitmap *uintptr
+ ret, _, _ := procGdipCreateBitmapFromFile.Call(
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(filename))),
+ uintptr(unsafe.Pointer(&bitmap)))
+
+ if ret != Ok {
+ return nil, errors.New(fmt.Sprintf("GdipCreateBitmapFromFile failed with status '%s' for file '%s'", GetGpStatus(int32(ret)), filename))
+ }
+
+ return bitmap, nil
+}
+
+func GdipCreateBitmapFromResource(instance HINSTANCE, resId *uint16) (*uintptr, error) {
+ var bitmap *uintptr
+ ret, _, _ := procGdipCreateBitmapFromResource.Call(
+ uintptr(instance),
+ uintptr(unsafe.Pointer(resId)),
+ uintptr(unsafe.Pointer(&bitmap)))
+
+ if ret != Ok {
+ return nil, errors.New(fmt.Sprintf("GdiCreateBitmapFromResource failed with status '%s'", GetGpStatus(int32(ret))))
+ }
+
+ return bitmap, nil
+}
+
+func GdipCreateBitmapFromStream(stream *IStream) (*uintptr, error) {
+ var bitmap *uintptr
+ ret, _, _ := procGdipCreateBitmapFromStream.Call(
+ uintptr(unsafe.Pointer(stream)),
+ uintptr(unsafe.Pointer(&bitmap)))
+
+ if ret != Ok {
+ return nil, errors.New(fmt.Sprintf("GdipCreateBitmapFromStream failed with status '%s'", GetGpStatus(int32(ret))))
+ }
+
+ return bitmap, nil
+}
+
+func GdipCreateHBITMAPFromBitmap(bitmap *uintptr, background uint32) (HBITMAP, error) {
+ var hbitmap HBITMAP
+ ret, _, _ := procGdipCreateHBITMAPFromBitmap.Call(
+ uintptr(unsafe.Pointer(bitmap)),
+ uintptr(unsafe.Pointer(&hbitmap)),
+ uintptr(background))
+
+ if ret != Ok {
+ return 0, errors.New(fmt.Sprintf("GdipCreateHBITMAPFromBitmap failed with status '%s'", GetGpStatus(int32(ret))))
+ }
+
+ return hbitmap, nil
+}
+
+func GdipDisposeImage(image *uintptr) {
+ procGdipDisposeImage.Call(uintptr(unsafe.Pointer(image)))
+}
+
+func GdiplusShutdown() {
+ procGdiplusShutdown.Call(token)
+}
+
+func GdiplusStartup(input *GdiplusStartupInput, output *GdiplusStartupOutput) {
+ ret, _, _ := procGdiplusStartup.Call(
+ uintptr(unsafe.Pointer(&token)),
+ uintptr(unsafe.Pointer(input)),
+ uintptr(unsafe.Pointer(output)))
+
+ if ret != Ok {
+ panic("GdiplusStartup failed with status " + GetGpStatus(int32(ret)))
+ }
+}
diff --git a/v3/pkg/w32/guid.go b/v3/pkg/w32/guid.go
new file mode 100644
index 000000000..b6e557f01
--- /dev/null
+++ b/v3/pkg/w32/guid.go
@@ -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,
+
+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]
+}
diff --git a/v3/pkg/w32/icon.go b/v3/pkg/w32/icon.go
new file mode 100644
index 000000000..97d4ad854
--- /dev/null
+++ b/v3/pkg/w32/icon.go
@@ -0,0 +1,255 @@
+//go:build windows
+
+package w32
+
+import (
+ "bytes"
+ "fmt"
+ "image"
+ "image/color"
+ "image/draw"
+ "image/png"
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+func CreateIconFromResourceEx(presbits uintptr, dwResSize uint32, isIcon bool, version uint32, cxDesired int, cyDesired int, flags uint) (uintptr, error) {
+ icon := 0
+ if isIcon {
+ icon = 1
+ }
+ r, _, err := procCreateIconFromResourceEx.Call(
+ presbits,
+ uintptr(dwResSize),
+ uintptr(icon),
+ uintptr(version),
+ uintptr(cxDesired),
+ uintptr(cyDesired),
+ uintptr(flags),
+ )
+
+ if r == 0 {
+ return 0, err
+ }
+ return r, nil
+}
+
+func isPNG(fileData []byte) bool {
+ if len(fileData) < 4 {
+ return false
+ }
+ return string(fileData[:4]) == "\x89PNG"
+}
+
+func isICO(fileData []byte) bool {
+ if len(fileData) < 4 {
+ return false
+ }
+ return string(fileData[:4]) == "\x00\x00\x01\x00"
+}
+
+// CreateSmallHIconFromImage creates a HICON from a PNG or ICO file
+func CreateSmallHIconFromImage(fileData []byte) (HICON, error) {
+ if len(fileData) < 8 {
+ return 0, fmt.Errorf("invalid file format")
+ }
+
+ if !isPNG(fileData) && !isICO(fileData) {
+ return 0, fmt.Errorf("unsupported file format")
+ }
+ iconWidth := GetSystemMetrics(SM_CXSMICON)
+ iconHeight := GetSystemMetrics(SM_CYSMICON)
+ icon, err := CreateIconFromResourceEx(
+ uintptr(unsafe.Pointer(&fileData[0])),
+ uint32(len(fileData)),
+ true,
+ 0x00030000,
+ iconWidth,
+ iconHeight,
+ LR_DEFAULTSIZE)
+ return HICON(icon), err
+}
+
+// CreateLargeHIconFromImage creates a HICON from a PNG or ICO file
+func CreateLargeHIconFromImage(fileData []byte) (HICON, error) {
+ if len(fileData) < 8 {
+ return 0, fmt.Errorf("invalid file format")
+ }
+
+ if !isPNG(fileData) && !isICO(fileData) {
+ return 0, fmt.Errorf("unsupported file format")
+ }
+ iconWidth := GetSystemMetrics(SM_CXICON)
+ iconHeight := GetSystemMetrics(SM_CXICON)
+ icon, err := CreateIconFromResourceEx(
+ uintptr(unsafe.Pointer(&fileData[0])),
+ uint32(len(fileData)),
+ true,
+ 0x00030000,
+ iconWidth,
+ iconHeight,
+ LR_DEFAULTSIZE)
+ return HICON(icon), err
+}
+
+type ICONINFO struct {
+ FIcon int32
+ XHotspot int32
+ YHotspot int32
+ HbmMask syscall.Handle
+ HbmColor syscall.Handle
+}
+
+func SaveHIconAsPNG(hIcon HICON, filePath string) error {
+ // Load necessary DLLs
+ user32 := syscall.NewLazyDLL("user32.dll")
+ gdi32 := syscall.NewLazyDLL("gdi32.dll")
+
+ // Get procedures
+ getIconInfo := user32.NewProc("GetIconInfo")
+ getObject := gdi32.NewProc("GetObjectW")
+ createCompatibleDC := gdi32.NewProc("CreateCompatibleDC")
+ selectObject := gdi32.NewProc("SelectObject")
+ getDIBits := gdi32.NewProc("GetDIBits")
+ deleteObject := gdi32.NewProc("DeleteObject")
+ deleteDC := gdi32.NewProc("DeleteDC")
+
+ // Get icon info
+ var iconInfo ICONINFO
+ ret, _, err := getIconInfo.Call(
+ uintptr(hIcon),
+ uintptr(unsafe.Pointer(&iconInfo)),
+ )
+ if ret == 0 {
+ return err
+ }
+ defer deleteObject.Call(uintptr(iconInfo.HbmMask))
+ defer deleteObject.Call(uintptr(iconInfo.HbmColor))
+
+ // Get bitmap info
+ var bmp BITMAP
+ ret, _, err = getObject.Call(
+ uintptr(iconInfo.HbmColor),
+ unsafe.Sizeof(bmp),
+ uintptr(unsafe.Pointer(&bmp)),
+ )
+ if ret == 0 {
+ return err
+ }
+
+ // Create DC
+ hdc, _, _ := createCompatibleDC.Call(0)
+ if hdc == 0 {
+ return syscall.EINVAL
+ }
+ defer deleteDC.Call(hdc)
+
+ // Select bitmap into DC
+ oldBitmap, _, _ := selectObject.Call(hdc, uintptr(iconInfo.HbmColor))
+ defer selectObject.Call(hdc, oldBitmap)
+
+ // Prepare bitmap info header
+ var bi BITMAPINFO
+ bi.BmiHeader.BiSize = uint32(unsafe.Sizeof(bi.BmiHeader))
+ bi.BmiHeader.BiWidth = bmp.BmWidth
+ bi.BmiHeader.BiHeight = bmp.BmHeight
+ bi.BmiHeader.BiPlanes = 1
+ bi.BmiHeader.BiBitCount = 32
+ bi.BmiHeader.BiCompression = BI_RGB
+
+ // Allocate memory for bitmap bits
+ width, height := int(bmp.BmWidth), int(bmp.BmHeight)
+ bufferSize := width * height * 4
+ bits := make([]byte, bufferSize)
+
+ // Get bitmap bits
+ ret, _, err = getDIBits.Call(
+ hdc,
+ uintptr(iconInfo.HbmColor),
+ 0,
+ uintptr(bmp.BmHeight),
+ uintptr(unsafe.Pointer(&bits[0])),
+ uintptr(unsafe.Pointer(&bi)),
+ DIB_RGB_COLORS,
+ )
+ if ret == 0 {
+ return err
+ }
+
+ // Create Go image
+ img := image.NewRGBA(image.Rect(0, 0, width, height))
+
+ // Convert DIB to RGBA
+ for y := 0; y < height; y++ {
+ for x := 0; x < width; x++ {
+ // DIB is bottom-up, so we need to invert Y
+ dibIndex := ((height-1-y)*width + x) * 4
+
+ // BGRA to RGBA
+ b := bits[dibIndex]
+ g := bits[dibIndex+1]
+ r := bits[dibIndex+2]
+ a := bits[dibIndex+3]
+
+ // Set pixel in the image
+ img.Set(x, y, color.RGBA{R: r, G: g, B: b, A: a})
+ }
+ }
+
+ // Create output file
+ outFile, err := os.Create(filePath)
+ if err != nil {
+ return err
+ }
+ defer outFile.Close()
+
+ // Encode and save the image
+ return png.Encode(outFile, img)
+}
+
+func SetWindowIcon(hwnd HWND, icon HICON) {
+ SendMessage(hwnd, WM_SETICON, ICON_SMALL, uintptr(icon))
+}
+
+func pngToImage(data []byte) (*image.RGBA, error) {
+ img, err := png.Decode(bytes.NewReader(data))
+ if err != nil {
+ return nil, err
+ }
+
+ bounds := img.Bounds()
+ rgba := image.NewRGBA(bounds)
+ draw.Draw(rgba, bounds, img, bounds.Min, draw.Src)
+ return rgba, nil
+}
+
+func SetMenuIcons(parentMenu HMENU, itemID int, unchecked []byte, checked []byte) error {
+ if unchecked == nil {
+ return fmt.Errorf("invalid unchecked bitmap")
+ }
+ var err error
+ var uncheckedIcon, checkedIcon HBITMAP
+ var uncheckedImage, checkedImage *image.RGBA
+ uncheckedImage, err = pngToImage(unchecked)
+ if err != nil {
+ return err
+ }
+ uncheckedIcon, err = CreateHBITMAPFromImage(uncheckedImage)
+ if err != nil {
+ return err
+ }
+ if checked != nil {
+ checkedImage, err = pngToImage(checked)
+ if err != nil {
+ return err
+ }
+ checkedIcon, err = CreateHBITMAPFromImage(checkedImage)
+ if err != nil {
+ return err
+ }
+ } else {
+ checkedIcon = uncheckedIcon
+ }
+ return SetMenuItemBitmaps(parentMenu, uint32(itemID), MF_BYCOMMAND, checkedIcon, uncheckedIcon)
+}
diff --git a/v3/pkg/w32/idataobject.go b/v3/pkg/w32/idataobject.go
new file mode 100644
index 000000000..cf56d0934
--- /dev/null
+++ b/v3/pkg/w32/idataobject.go
@@ -0,0 +1,168 @@
+//go:build windows
+
+package w32
+
+import (
+ "golang.org/x/sys/windows"
+ "syscall"
+ "unsafe"
+)
+
+type IDataObjectVtbl struct {
+ IUnknownVtbl
+ GetData ComProc
+ GetDataHere ComProc
+ QueryGetData ComProc
+ GetCanonicalFormatEtc ComProc
+ SetData ComProc
+ EnumFormatEtc ComProc
+ DAdvise ComProc
+}
+
+type IDataObject struct {
+ Vtbl *IDataObjectVtbl
+}
+
+func (i *IDataObject) AddRef() uintptr {
+ refCounter, _, _ := i.Vtbl.AddRef.Call(uintptr(unsafe.Pointer(i)))
+ return refCounter
+}
+
+func (i *IDataObject) GetData(formatEtc *FORMATETC, medium *STGMEDIUM) error {
+ hr, _, err := i.Vtbl.GetData.Call(
+ uintptr(unsafe.Pointer(i)),
+ uintptr(unsafe.Pointer(formatEtc)),
+ uintptr(unsafe.Pointer(medium)),
+ )
+ if windows.Handle(hr) != windows.S_OK {
+ return syscall.Errno(hr)
+ }
+ return err
+}
+
+func (i *IDataObject) GetDataHere(formatEtc *FORMATETC, medium *STGMEDIUM) error {
+ hr, _, err := i.Vtbl.GetDataHere.Call(
+ uintptr(unsafe.Pointer(i)),
+ uintptr(unsafe.Pointer(formatEtc)),
+ uintptr(unsafe.Pointer(medium)),
+ )
+ if windows.Handle(hr) != windows.S_OK {
+ return syscall.Errno(hr)
+ }
+ return err
+}
+
+func (i *IDataObject) QueryGetData(formatEtc *FORMATETC) error {
+ hr, _, err := i.Vtbl.QueryGetData.Call(
+ uintptr(unsafe.Pointer(i)),
+ uintptr(unsafe.Pointer(formatEtc)),
+ )
+ if windows.Handle(hr) != windows.S_OK {
+ return syscall.Errno(hr)
+ }
+ return err
+}
+
+func (i *IDataObject) GetCanonicalFormatEtc(inputFormatEtc *FORMATETC, outputFormatEtc *FORMATETC) error {
+ hr, _, err := i.Vtbl.GetCanonicalFormatEtc.Call(
+ uintptr(unsafe.Pointer(i)),
+ uintptr(unsafe.Pointer(inputFormatEtc)),
+ uintptr(unsafe.Pointer(outputFormatEtc)),
+ )
+ if windows.Handle(hr) != windows.S_OK {
+ return syscall.Errno(hr)
+ }
+ return err
+}
+
+func (i *IDataObject) SetData(formatEtc *FORMATETC, medium *STGMEDIUM, release bool) error {
+ hr, _, err := i.Vtbl.SetData.Call(
+ uintptr(unsafe.Pointer(i)),
+ uintptr(unsafe.Pointer(formatEtc)),
+ uintptr(unsafe.Pointer(medium)),
+ uintptr(BoolToBOOL(release)),
+ )
+ if windows.Handle(hr) != windows.S_OK {
+ return syscall.Errno(hr)
+ }
+ return err
+}
+
+func (i *IDataObject) EnumFormatEtc(dwDirection uint32, enumFormatEtc **IEnumFORMATETC) error {
+ hr, _, err := i.Vtbl.EnumFormatEtc.Call(
+ uintptr(unsafe.Pointer(i)),
+ uintptr(dwDirection),
+ uintptr(unsafe.Pointer(enumFormatEtc)),
+ )
+ if windows.Handle(hr) != windows.S_OK {
+ return syscall.Errno(hr)
+ }
+ return err
+}
+
+func (i *IDataObject) DAdvise(formatEtc *FORMATETC, advf uint32, adviseSink *IAdviseSink, pdwConnection *uint32) error {
+ hr, _, err := i.Vtbl.DAdvise.Call(
+ uintptr(unsafe.Pointer(i)),
+ uintptr(unsafe.Pointer(formatEtc)),
+ uintptr(advf),
+ uintptr(unsafe.Pointer(adviseSink)),
+ uintptr(unsafe.Pointer(pdwConnection)),
+ )
+ if windows.Handle(hr) != windows.S_OK {
+ return syscall.Errno(hr)
+ }
+ return err
+}
+
+type DVTargetDevice struct {
+ TdSize uint32
+ TdDriverNameOffset uint16
+ TdDeviceNameOffset uint16
+ TdPortNameOffset uint16
+ TdExtDevmodeOffset uint16
+ TdData [1]byte
+}
+
+type FORMATETC struct {
+ CfFormat uint16
+ Ptd *DVTargetDevice
+ DwAspect uint32
+ Lindex int32
+ Tymed Tymed
+}
+
+type Tymed uint32
+
+const (
+ TYMED_HGLOBAL Tymed = 1
+ TYMED_FILE Tymed = 2
+ TYMED_ISTREAM Tymed = 4
+ TYMED_ISTORAGE Tymed = 8
+ TYMED_GDI Tymed = 16
+ TYMED_MFPICT Tymed = 32
+ TYMED_ENHMF Tymed = 64
+ TYMED_NULL Tymed = 0
+)
+
+type STGMEDIUM struct {
+ Tymed Tymed
+ Union uintptr
+ PUnkForRelease IUnknownImpl
+}
+
+func (s STGMEDIUM) FileName() string {
+ if s.Tymed != TYMED_FILE {
+ return ""
+ }
+ return windows.UTF16PtrToString((*uint16)(unsafe.Pointer(s.Union)))
+}
+
+func (s STGMEDIUM) Release() {
+ if s.PUnkForRelease != nil {
+ s.PUnkForRelease.Release()
+ }
+}
+
+type IEnumFORMATETC struct{}
+type IAdviseSink struct{}
+type IEnumStatData struct{}
diff --git a/v3/pkg/w32/idispatch.go b/v3/pkg/w32/idispatch.go
new file mode 100644
index 000000000..4f610f3ff
--- /dev/null
+++ b/v3/pkg/w32/idispatch.go
@@ -0,0 +1,45 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 The Winc Authors. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+import (
+ "unsafe"
+)
+
+type pIDispatchVtbl struct {
+ pQueryInterface uintptr
+ pAddRef uintptr
+ pRelease uintptr
+ pGetTypeInfoCount uintptr
+ pGetTypeInfo uintptr
+ pGetIDsOfNames uintptr
+ pInvoke uintptr
+}
+
+type IDispatch struct {
+ lpVtbl *pIDispatchVtbl
+}
+
+func (this *IDispatch) QueryInterface(id *GUID) *IDispatch {
+ return ComQueryInterface((*IUnknown)(unsafe.Pointer(this)), id)
+}
+
+func (this *IDispatch) AddRef() int32 {
+ return ComAddRef((*IUnknown)(unsafe.Pointer(this)))
+}
+
+func (this *IDispatch) Release() int32 {
+ return ComRelease((*IUnknown)(unsafe.Pointer(this)))
+}
+
+func (this *IDispatch) GetIDsOfName(names []string) []int32 {
+ return ComGetIDsOfName(this, names)
+}
+
+func (this *IDispatch) Invoke(dispid int32, dispatch int16, params ...interface{}) *VARIANT {
+ return ComInvoke(this, dispid, dispatch, params...)
+}
diff --git a/v3/pkg/w32/idroptarget.go b/v3/pkg/w32/idroptarget.go
new file mode 100644
index 000000000..abcc931db
--- /dev/null
+++ b/v3/pkg/w32/idroptarget.go
@@ -0,0 +1,140 @@
+//go:build windows
+
+package w32
+
+import (
+ "github.com/wailsapp/go-webview2/pkg/combridge"
+ "golang.org/x/sys/windows"
+)
+
+var (
+ DROPEFFECT_NONE DWORD = 0
+ DROPEFFECT_COPY DWORD = 1
+ DROPEFFECT_MOVE DWORD = 2
+ DROPEFFECT_LINK DWORD = 4
+)
+
+const (
+ DRAGDROP_E_ALREADYREGISTERED = 0x80040101
+ DRAGDROP_E_INVALIDHWND = 0x80040102
+)
+
+func _NOP(_ uintptr) uintptr {
+ return uintptr(windows.S_FALSE)
+}
+
+func init() {
+ combridge.RegisterVTable[combridge.IUnknown, iDropTarget](
+ "{00000122-0000-0000-C000-000000000046}",
+ _iDropTargetDragEnter,
+ _iDropTargetDragOver,
+ _iDropTargetDragLeave,
+ _iDropTargetDrop,
+ )
+}
+
+func _iDropTargetDragEnter(
+ this uintptr,
+ dataObject *IDataObject,
+ grfKeyState DWORD,
+ point POINT,
+ pdfEffect *DWORD,
+) uintptr {
+ return combridge.Resolve[iDropTarget](this).DragEnter(dataObject, grfKeyState, point, pdfEffect)
+}
+
+func _iDropTargetDragOver(this uintptr, grfKeyState DWORD, point POINT, pdfEffect *DWORD) uintptr {
+ return combridge.Resolve[iDropTarget](this).DragOver(grfKeyState, point, pdfEffect)
+}
+
+func _iDropTargetDragLeave(this uintptr) uintptr {
+ return combridge.Resolve[iDropTarget](this).DragLeave()
+}
+
+func _iDropTargetDrop(this uintptr, dataObject *IDataObject, grfKeyState DWORD, point POINT, pdfEffect *DWORD) uintptr {
+ return combridge.Resolve[iDropTarget](this).Drop(dataObject, grfKeyState, point, pdfEffect)
+}
+
+type iDropTarget interface {
+ combridge.IUnknown
+
+ DragEnter(dataObject *IDataObject, grfKeyState DWORD, point POINT, pdfEffect *DWORD) uintptr
+ DragOver(grfKeyState DWORD, point POINT, pdfEffect *DWORD) uintptr
+ DragLeave() uintptr
+ Drop(dataObject *IDataObject, grfKeyState DWORD, point POINT, pdfEffect *DWORD) uintptr
+}
+
+var _ iDropTarget = &DropTarget{}
+
+type DropTarget struct {
+ combridge.IUnknownImpl
+ OnEnterEffect DWORD
+ OnOverEffect DWORD
+ OnEnter func()
+ OnLeave func()
+ OnOver func()
+ OnDrop func(filenames []string, x int, y int)
+}
+
+func NewDropTarget() *DropTarget {
+ result := &DropTarget{
+ OnEnterEffect: DROPEFFECT_COPY,
+ OnOverEffect: DROPEFFECT_COPY,
+ }
+ return result
+}
+
+func (d *DropTarget) DragEnter(dataObject *IDataObject, grfKeyState DWORD, point POINT, pdfEffect *DWORD) uintptr {
+ *pdfEffect = d.OnEnterEffect
+ if d.OnEnter != nil {
+ d.OnEnter()
+ }
+ return uintptr(windows.S_OK)
+}
+
+func (d *DropTarget) DragOver(grfKeyState DWORD, point POINT, pdfEffect *DWORD) uintptr {
+ *pdfEffect = d.OnOverEffect
+ if d.OnOver != nil {
+ d.OnOver()
+ }
+ return uintptr(windows.S_OK)
+}
+
+func (d *DropTarget) DragLeave() uintptr {
+ if d.OnLeave != nil {
+ d.OnLeave()
+ }
+ return uintptr(windows.S_OK)
+}
+
+func (d *DropTarget) Drop(dataObject *IDataObject, grfKeyState DWORD, point POINT, pdfEffect *DWORD) uintptr {
+
+ if d.OnDrop == nil {
+ return uintptr(windows.S_OK)
+ }
+
+ // Extract filenames from dataObject
+ var filenames []string
+ var formatETC = FORMATETC{
+ CfFormat: CF_HDROP,
+ Tymed: TYMED_HGLOBAL,
+ }
+
+ var stgMedium STGMEDIUM
+
+ err := dataObject.GetData(&formatETC, &stgMedium)
+ if err != nil && err != windows.ERROR_SUCCESS {
+ return uintptr(windows.S_FALSE)
+ }
+ defer stgMedium.Release()
+ hDrop := stgMedium.Union
+ _, numFiles := DragQueryFile(hDrop, 0xFFFFFFFF)
+ for i := uint(0); i < numFiles; i++ {
+ filename, _ := DragQueryFile(hDrop, i)
+ filenames = append(filenames, filename)
+ }
+
+ d.OnDrop(filenames, int(point.X), int(point.Y))
+
+ return uintptr(windows.S_OK)
+}
diff --git a/v3/pkg/w32/image.go b/v3/pkg/w32/image.go
new file mode 100644
index 000000000..1c7520f36
--- /dev/null
+++ b/v3/pkg/w32/image.go
@@ -0,0 +1,55 @@
+//go:build windows
+
+package w32
+
+import (
+ "image"
+ "syscall"
+ "unsafe"
+)
+
+func CreateHBITMAPFromImage(img *image.RGBA) (HBITMAP, error) {
+ bounds := img.Bounds()
+ width, height := bounds.Dx(), bounds.Dy()
+
+ // Create a BITMAPINFO structure for the DIB
+ bmi := BITMAPINFO{
+ BmiHeader: BITMAPINFOHEADER{
+ BiSize: uint32(unsafe.Sizeof(BITMAPINFOHEADER{})),
+ BiWidth: int32(width),
+ BiHeight: int32(-height), // negative to indicate top-down bitmap
+ BiPlanes: 1,
+ BiBitCount: 32,
+ BiCompression: BI_RGB,
+ BiSizeImage: uint32(width * height * 4), // RGBA = 4 bytes
+ },
+ }
+
+ // Create the DIB section
+ var bits unsafe.Pointer
+
+ hbmp := CreateDIBSection(0, &bmi, DIB_RGB_COLORS, &bits, 0, 0)
+ if hbmp == 0 {
+ return 0, syscall.GetLastError()
+ }
+
+ // Copy the pixel data from the Go image to the DIB section
+ for y := 0; y < height; y++ {
+ for x := 0; x < width; x++ {
+ i := img.PixOffset(x, y)
+ r := img.Pix[i+0]
+ g := img.Pix[i+1]
+ b := img.Pix[i+2]
+ a := img.Pix[i+3]
+
+ // Write the RGBA pixel data to the DIB section (BGR order)
+ offset := y*width*4 + x*4
+ *((*uint8)(unsafe.Pointer(uintptr(bits) + uintptr(offset) + 0))) = b
+ *((*uint8)(unsafe.Pointer(uintptr(bits) + uintptr(offset) + 1))) = g
+ *((*uint8)(unsafe.Pointer(uintptr(bits) + uintptr(offset) + 2))) = r
+ *((*uint8)(unsafe.Pointer(uintptr(bits) + uintptr(offset) + 3))) = a
+ }
+ }
+
+ return hbmp, nil
+}
diff --git a/v3/pkg/w32/istream.go b/v3/pkg/w32/istream.go
new file mode 100644
index 000000000..a47fbbce1
--- /dev/null
+++ b/v3/pkg/w32/istream.go
@@ -0,0 +1,33 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+import (
+ "unsafe"
+)
+
+type pIStreamVtbl struct {
+ pQueryInterface uintptr
+ pAddRef uintptr
+ pRelease uintptr
+}
+
+type IStream struct {
+ lpVtbl *pIStreamVtbl
+}
+
+func (this *IStream) QueryInterface(id *GUID) *IDispatch {
+ return ComQueryInterface((*IUnknown)(unsafe.Pointer(this)), id)
+}
+
+func (this *IStream) AddRef() int32 {
+ return ComAddRef((*IUnknown)(unsafe.Pointer(this)))
+}
+
+func (this *IStream) Release() int32 {
+ return ComRelease((*IUnknown)(unsafe.Pointer(this)))
+}
diff --git a/v3/pkg/w32/kernel32.go b/v3/pkg/w32/kernel32.go
new file mode 100644
index 000000000..affd497cd
--- /dev/null
+++ b/v3/pkg/w32/kernel32.go
@@ -0,0 +1,337 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modkernel32 = syscall.NewLazyDLL("kernel32.dll")
+
+ procGetModuleHandle = modkernel32.NewProc("GetModuleHandleW")
+ procMulDiv = modkernel32.NewProc("MulDiv")
+ procGetConsoleWindow = modkernel32.NewProc("GetConsoleWindow")
+ procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
+ procGetCurrentThreadId = modkernel32.NewProc("GetCurrentThreadId")
+ procGetLogicalDrives = modkernel32.NewProc("GetLogicalDrives")
+ procGetLogicalDriveStrings = modkernel32.NewProc("GetLogicalDriveStringsW")
+ procGetUserDefaultLCID = modkernel32.NewProc("GetUserDefaultLCID")
+ procLstrlen = modkernel32.NewProc("lstrlenW")
+ procLstrcpy = modkernel32.NewProc("lstrcpyW")
+ procGlobalAlloc = modkernel32.NewProc("GlobalAlloc")
+ procGlobalFree = modkernel32.NewProc("GlobalFree")
+ procGlobalLock = modkernel32.NewProc("GlobalLock")
+ procGlobalUnlock = modkernel32.NewProc("GlobalUnlock")
+ procMoveMemory = modkernel32.NewProc("RtlMoveMemory")
+ procFindResource = modkernel32.NewProc("FindResourceW")
+ procSizeofResource = modkernel32.NewProc("SizeofResource")
+ procLockResource = modkernel32.NewProc("LockResource")
+ procLoadResource = modkernel32.NewProc("LoadResource")
+ procGetLastError = modkernel32.NewProc("GetLastError")
+ procOpenProcess = modkernel32.NewProc("OpenProcess")
+ procTerminateProcess = modkernel32.NewProc("TerminateProcess")
+ procCloseHandle = modkernel32.NewProc("CloseHandle")
+ procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot")
+ procModule32First = modkernel32.NewProc("Module32FirstW")
+ procModule32Next = modkernel32.NewProc("Module32NextW")
+ procGetSystemTimes = modkernel32.NewProc("GetSystemTimes")
+ procGetConsoleScreenBufferInfo = modkernel32.NewProc("GetConsoleScreenBufferInfo")
+ procSetConsoleTextAttribute = modkernel32.NewProc("SetConsoleTextAttribute")
+ procGetDiskFreeSpaceEx = modkernel32.NewProc("GetDiskFreeSpaceExW")
+ procGetProcessTimes = modkernel32.NewProc("GetProcessTimes")
+ procSetSystemTime = modkernel32.NewProc("SetSystemTime")
+ procGetSystemTime = modkernel32.NewProc("GetSystemTime")
+)
+
+func GetModuleHandle(modulename string) HINSTANCE {
+ var mn uintptr
+ if modulename == "" {
+ mn = 0
+ } else {
+ mn = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(modulename)))
+ }
+ ret, _, _ := procGetModuleHandle.Call(mn)
+ return HINSTANCE(ret)
+}
+
+func GetApplicationHandle() HINSTANCE {
+ ret, _, _ := procGetModuleHandle.Call(0)
+ return ret
+}
+
+func MulDiv(number, numerator, denominator int) int {
+ ret, _, _ := procMulDiv.Call(
+ uintptr(number),
+ uintptr(numerator),
+ uintptr(denominator))
+
+ return int(ret)
+}
+
+func GetConsoleWindow() HWND {
+ ret, _, _ := procGetConsoleWindow.Call()
+
+ return HWND(ret)
+}
+
+func GetCurrentThread() HANDLE {
+ ret, _, _ := procGetCurrentThread.Call()
+
+ return HANDLE(ret)
+}
+
+func GetCurrentThreadId() HANDLE {
+ ret, _, _ := procGetCurrentThreadId.Call()
+
+ return HANDLE(ret)
+}
+
+func GetLogicalDrives() uint32 {
+ ret, _, _ := procGetLogicalDrives.Call()
+
+ return uint32(ret)
+}
+
+func GetUserDefaultLCID() uint32 {
+ ret, _, _ := procGetUserDefaultLCID.Call()
+
+ return uint32(ret)
+}
+
+func Lstrlen(lpString *uint16) int {
+ ret, _, _ := procLstrlen.Call(uintptr(unsafe.Pointer(lpString)))
+
+ return int(ret)
+}
+
+func Lstrcpy(buf []uint16, lpString *uint16) {
+ procLstrcpy.Call(
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(lpString)))
+}
+
+func GlobalAlloc(uFlags uint, dwBytes uint32) HGLOBAL {
+ ret, _, _ := procGlobalAlloc.Call(
+ uintptr(uFlags),
+ uintptr(dwBytes))
+
+ if ret == 0 {
+ panic("GlobalAlloc failed")
+ }
+
+ return HGLOBAL(ret)
+}
+
+func GlobalFree(hMem HGLOBAL) {
+ ret, _, _ := procGlobalFree.Call(uintptr(hMem))
+
+ if ret != 0 {
+ panic("GlobalFree failed")
+ }
+}
+
+func GlobalLock(hMem HGLOBAL) unsafe.Pointer {
+ ret, _, _ := procGlobalLock.Call(uintptr(hMem))
+
+ if ret == 0 {
+ panic("GlobalLock failed")
+ }
+
+ return unsafe.Pointer(ret)
+}
+
+func GlobalUnlock(hMem HGLOBAL) bool {
+ ret, _, _ := procGlobalUnlock.Call(uintptr(hMem))
+
+ return ret != 0
+}
+
+func MoveMemory(destination, source unsafe.Pointer, length uint32) {
+ procMoveMemory.Call(
+ uintptr(unsafe.Pointer(destination)),
+ uintptr(source),
+ uintptr(length))
+}
+
+func FindResource(hModule HMODULE, lpName, lpType *uint16) (HRSRC, error) {
+ ret, _, _ := procFindResource.Call(
+ uintptr(hModule),
+ uintptr(unsafe.Pointer(lpName)),
+ uintptr(unsafe.Pointer(lpType)))
+
+ if ret == 0 {
+ return 0, syscall.GetLastError()
+ }
+
+ return HRSRC(ret), nil
+}
+
+func SizeofResource(hModule HMODULE, hResInfo HRSRC) uint32 {
+ ret, _, _ := procSizeofResource.Call(
+ uintptr(hModule),
+ uintptr(hResInfo))
+
+ if ret == 0 {
+ panic("SizeofResource failed")
+ }
+
+ return uint32(ret)
+}
+
+func LockResource(hResData HGLOBAL) unsafe.Pointer {
+ ret, _, _ := procLockResource.Call(uintptr(hResData))
+
+ if ret == 0 {
+ panic("LockResource failed")
+ }
+
+ return unsafe.Pointer(ret)
+}
+
+func LoadResource(hModule HMODULE, hResInfo HRSRC) HGLOBAL {
+ ret, _, _ := procLoadResource.Call(
+ uintptr(hModule),
+ uintptr(hResInfo))
+
+ if ret == 0 {
+ panic("LoadResource failed")
+ }
+
+ return HGLOBAL(ret)
+}
+
+func GetLastError() uint32 {
+ ret, _, _ := procGetLastError.Call()
+ return uint32(ret)
+}
+
+func OpenProcess(desiredAccess uint32, inheritHandle bool, processId uint32) HANDLE {
+ inherit := 0
+ if inheritHandle {
+ inherit = 1
+ }
+
+ ret, _, _ := procOpenProcess.Call(
+ uintptr(desiredAccess),
+ uintptr(inherit),
+ uintptr(processId))
+ return HANDLE(ret)
+}
+
+func TerminateProcess(hProcess HANDLE, uExitCode uint) bool {
+ ret, _, _ := procTerminateProcess.Call(
+ uintptr(hProcess),
+ uintptr(uExitCode))
+ return ret != 0
+}
+
+func CloseHandle(object HANDLE) bool {
+ ret, _, _ := procCloseHandle.Call(
+ uintptr(object))
+ return ret != 0
+}
+
+func CreateToolhelp32Snapshot(flags, processId uint32) HANDLE {
+ ret, _, _ := procCreateToolhelp32Snapshot.Call(
+ uintptr(flags),
+ uintptr(processId))
+
+ if ret <= 0 {
+ return HANDLE(0)
+ }
+
+ return HANDLE(ret)
+}
+
+func Module32First(snapshot HANDLE, me *MODULEENTRY32) bool {
+ ret, _, _ := procModule32First.Call(
+ uintptr(snapshot),
+ uintptr(unsafe.Pointer(me)))
+
+ return ret != 0
+}
+
+func Module32Next(snapshot HANDLE, me *MODULEENTRY32) bool {
+ ret, _, _ := procModule32Next.Call(
+ uintptr(snapshot),
+ uintptr(unsafe.Pointer(me)))
+
+ return ret != 0
+}
+
+func GetSystemTimes(lpIdleTime, lpKernelTime, lpUserTime *FILETIME) bool {
+ ret, _, _ := procGetSystemTimes.Call(
+ uintptr(unsafe.Pointer(lpIdleTime)),
+ uintptr(unsafe.Pointer(lpKernelTime)),
+ uintptr(unsafe.Pointer(lpUserTime)))
+
+ return ret != 0
+}
+
+func GetProcessTimes(hProcess HANDLE, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime *FILETIME) bool {
+ ret, _, _ := procGetProcessTimes.Call(
+ uintptr(hProcess),
+ uintptr(unsafe.Pointer(lpCreationTime)),
+ uintptr(unsafe.Pointer(lpExitTime)),
+ uintptr(unsafe.Pointer(lpKernelTime)),
+ uintptr(unsafe.Pointer(lpUserTime)))
+
+ return ret != 0
+}
+
+func GetConsoleScreenBufferInfo(hConsoleOutput HANDLE) *CONSOLE_SCREEN_BUFFER_INFO {
+ var csbi CONSOLE_SCREEN_BUFFER_INFO
+ ret, _, _ := procGetConsoleScreenBufferInfo.Call(
+ uintptr(hConsoleOutput),
+ uintptr(unsafe.Pointer(&csbi)))
+ if ret == 0 {
+ return nil
+ }
+ return &csbi
+}
+
+func SetConsoleTextAttribute(hConsoleOutput HANDLE, wAttributes uint16) bool {
+ ret, _, _ := procSetConsoleTextAttribute.Call(
+ uintptr(hConsoleOutput),
+ uintptr(wAttributes))
+ return ret != 0
+}
+
+func GetDiskFreeSpaceEx(dirName string) (r bool,
+ freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes uint64) {
+ ret, _, _ := procGetDiskFreeSpaceEx.Call(
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(dirName))),
+ uintptr(unsafe.Pointer(&freeBytesAvailable)),
+ uintptr(unsafe.Pointer(&totalNumberOfBytes)),
+ uintptr(unsafe.Pointer(&totalNumberOfFreeBytes)))
+ return ret != 0,
+ freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes
+}
+
+func GetSystemTime() *SYSTEMTIME {
+ var time SYSTEMTIME
+ procGetSystemTime.Call(
+ uintptr(unsafe.Pointer(&time)))
+ return &time
+}
+
+func SetSystemTime(time *SYSTEMTIME) bool {
+ ret, _, _ := procSetSystemTime.Call(
+ uintptr(unsafe.Pointer(time)))
+ return ret != 0
+}
+
+func GetLogicalDriveStrings(nBufferLength uint32, lpBuffer *uint16) uint32 {
+ ret, _, _ := procGetLogicalDriveStrings.Call(
+ uintptr(nBufferLength),
+ uintptr(unsafe.Pointer(lpBuffer)),
+ 0)
+
+ return uint32(ret)
+}
diff --git a/v3/pkg/w32/menubar.go b/v3/pkg/w32/menubar.go
new file mode 100644
index 000000000..6b11c1e02
--- /dev/null
+++ b/v3/pkg/w32/menubar.go
@@ -0,0 +1,980 @@
+//go:build windows
+
+package w32
+
+import (
+ "os"
+ "unsafe"
+)
+
+const (
+ OBJID_MENU = -3
+ ODT_MENU = 1
+ // Menu info flags
+ MIIM_BACKGROUND = 0x00000002
+ MIIM_APPLYTOSUBMENUS = 0x80000000
+)
+
+var (
+ menuTheme HTHEME
+ procSetMenuInfo = moduser32.NewProc("SetMenuInfo")
+)
+
+type DTTOPTS struct {
+ DwSize uint32
+ DwFlags uint32
+ CrText uint32
+ CrBorder uint32
+ CrShadow uint32
+ ITextShadowType int32
+ PtShadowOffset POINT
+ iBorderSize int32
+ iFontPropId int32
+ IColorPropId int32
+ IStateId int32
+ FApplyOverlay int32
+ IGlowSize int32
+ PfnDrawTextCallback uintptr
+ LParam uintptr
+}
+
+const (
+ MENU_POPUPITEM = 14
+ MENU_BARITEM = 8 // Menu bar item part ID for theme drawing
+ DTT_TEXTCOLOR = 1
+)
+
+// Menu item states
+const (
+ ODS_SELECTED = 0x0001
+ ODS_GRAYED = 0x0002
+ ODS_DISABLED = 0x0004
+ ODS_CHECKED = 0x0008
+ ODS_FOCUS = 0x0010
+ ODS_DEFAULT = 0x0020
+ ODS_HOTLIGHT = 0x0040
+ ODS_INACTIVE = 0x0080
+ ODS_NOACCEL = 0x0100
+ ODS_NOFOCUSRECT = 0x0200
+)
+
+// Menu Button Image states
+const (
+ MBI_NORMAL = 1
+ MBI_HOT = 2
+ MBI_PUSHED = 3
+ MBI_DISABLED = 4
+)
+
+var (
+ procGetMenuItemInfo = moduser32.NewProc("GetMenuItemInfoW")
+ procGetMenuItemCount = moduser32.NewProc("GetMenuItemCount")
+ procGetMenuItemRect = moduser32.NewProc("GetMenuItemRect")
+)
+
+func GetMenuItemInfo(hmenu HMENU, item uint32, fByPosition bool, lpmii *MENUITEMINFO) bool {
+ ret, _, _ := procGetMenuItemInfo.Call(
+ uintptr(hmenu),
+ uintptr(item),
+ uintptr(boolToUint(fByPosition)),
+ uintptr(unsafe.Pointer(lpmii)),
+ )
+ return ret != 0
+}
+
+func GetMenuItemCount(hmenu HMENU) int {
+ ret, _, _ := procGetMenuItemCount.Call(uintptr(hmenu))
+ return int(ret)
+}
+
+func GetMenuItemRect(hwnd HWND, hmenu HMENU, item uint32, rect *RECT) bool {
+ ret, _, _ := procGetMenuItemRect.Call(
+ uintptr(hwnd),
+ uintptr(hmenu),
+ uintptr(item),
+ uintptr(unsafe.Pointer(rect)),
+ )
+ return ret != 0
+}
+
+// Helper function to convert bool to uint
+func boolToUint(b bool) uint {
+ if b {
+ return 1
+ }
+ return 0
+}
+
+type UAHMENU struct {
+ Hmenu HMENU
+ Hdc HDC
+ DwFlags uint32
+}
+
+type MENUBARINFO struct {
+ CbSize uint32
+ Bar RECT
+ Menu HMENU
+ Window HWND
+ BarFocused int32
+ Focused int32
+}
+
+type DRAWITEMSTRUCT struct {
+ ControlType uint32
+ ControlID uint32
+ ItemID uint32
+ ItemAction uint32
+ ItemState uint32
+ HWNDItem HWND
+ HDC HDC
+ RcItem RECT
+ ItemData uintptr
+}
+
+type UAHDRAWMENUITEM struct {
+ DIS DRAWITEMSTRUCT
+ UM UAHMENU
+ UAMI UAHMENUITEM
+}
+
+type UAHMENUITEM struct {
+ Position int
+ Umim UAHMENUITEMMETRICS
+ Umpm UAHMENUPOPUPMETRICS
+}
+type UAHMENUITEMMETRICS struct {
+ data [32]byte // Total size of the union in bytes (4 DWORDs * 4 bytes each * 2 arrays)
+}
+
+func (u *UAHMENUITEMMETRICS) RgsizeBar() *[2]struct{ cx, cy uint32 } {
+ return (*[2]struct{ cx, cy uint32 })(unsafe.Pointer(&u.data))
+}
+
+func (u *UAHMENUITEMMETRICS) RgsizePopup() *[4]struct{ cx, cy uint32 } {
+ return (*[4]struct{ cx, cy uint32 })(unsafe.Pointer(&u.data))
+}
+
+type UAHMEASUREMENUITEM struct {
+ UM UAHMENU
+ UAMI UAHMENUITEM
+ Mis MEASUREITEMSTRUCT
+}
+
+type MEASUREITEMSTRUCT struct {
+ CtlType uint32
+ CtlID uint32
+ ItemID uint32
+ ItemWidth uint32
+ ItemHeight uint32
+ ItemData uintptr
+}
+
+type UAHMENUPOPUPMETRICS struct {
+ Rgcx [4]uint32 // Array of 4 DWORDs
+ FUpdateMaxWidths uint32 // Bit-field represented as a uint32
+}
+
+// Helper function to get the value of the fUpdateMaxWidths bit-field
+func (u *UAHMENUPOPUPMETRICS) GetFUpdateMaxWidths() uint32 {
+ return u.FUpdateMaxWidths & 0x3 // Mask to get the first 2 bits
+}
+
+// Helper function to set the value of the fUpdateMaxWidths bit-field
+func (u *UAHMENUPOPUPMETRICS) SetFUpdateMaxWidths(value uint32) {
+ u.FUpdateMaxWidths = (u.FUpdateMaxWidths &^ 0x3) | (value & 0x3) // Clear and set the first 2 bits
+}
+
+type MenuBarTheme struct {
+ TitleBarBackground *uint32
+ TitleBarText *uint32
+ MenuBarBackground *uint32 // Separate color for menubar
+ MenuHoverBackground *uint32
+ MenuHoverText *uint32
+ MenuSelectedBackground *uint32
+ MenuSelectedText *uint32
+
+ // private brushes
+ titleBarBackgroundBrush HBRUSH
+ menuBarBackgroundBrush HBRUSH // Separate brush for menubar
+ menuHoverBackgroundBrush HBRUSH
+ menuSelectedBackgroundBrush HBRUSH
+}
+
+func createColourWithDefaultColor(color *uint32, def uint32) *uint32 {
+ if color == nil {
+ return &def
+ }
+ return color
+}
+
+func (d *MenuBarTheme) Init() {
+ d.TitleBarBackground = createColourWithDefaultColor(d.TitleBarBackground, RGB(25, 25, 26))
+ d.TitleBarText = createColourWithDefaultColor(d.TitleBarText, RGB(222, 222, 222))
+ d.MenuBarBackground = createColourWithDefaultColor(d.MenuBarBackground, RGB(33, 33, 33))
+ d.MenuSelectedText = createColourWithDefaultColor(d.MenuSelectedText, RGB(222, 222, 222))
+ d.MenuSelectedBackground = createColourWithDefaultColor(d.MenuSelectedBackground, RGB(48, 48, 48))
+ d.MenuHoverText = createColourWithDefaultColor(d.MenuHoverText, RGB(222, 222, 222))
+ d.MenuHoverBackground = createColourWithDefaultColor(d.MenuHoverBackground, RGB(48, 48, 48))
+ // Create brushes
+ d.titleBarBackgroundBrush = CreateSolidBrush(*d.TitleBarBackground)
+ d.menuBarBackgroundBrush = CreateSolidBrush(*d.MenuBarBackground)
+ d.menuHoverBackgroundBrush = CreateSolidBrush(*d.MenuHoverBackground)
+ d.menuSelectedBackgroundBrush = CreateSolidBrush(*d.MenuSelectedBackground)
+}
+
+// SetMenuBackground sets the menu background brush directly
+func (d *MenuBarTheme) SetMenuBackground(hmenu HMENU) {
+ var mi MENUINFO
+ mi.CbSize = uint32(unsafe.Sizeof(mi))
+ mi.FMask = MIIM_BACKGROUND | MIIM_APPLYTOSUBMENUS
+ mi.HbrBack = d.menuBarBackgroundBrush // Use separate menubar brush
+ SetMenuInfo(hmenu, &mi)
+}
+
+// SetMenuInfo wrapper function
+func SetMenuInfo(hmenu HMENU, lpcmi *MENUINFO) bool {
+ ret, _, _ := procSetMenuInfo.Call(
+ uintptr(hmenu),
+ uintptr(unsafe.Pointer(lpcmi)))
+ return ret != 0
+}
+
+func CreateSolidBrush(color COLORREF) HBRUSH {
+ ret, _, _ := procCreateSolidBrush.Call(
+ uintptr(color),
+ )
+ return HBRUSH(ret)
+}
+
+func RGB(r, g, b byte) uint32 {
+ return uint32(r) | uint32(g)<<8 | uint32(b)<<16
+}
+
+func RGBptr(r, g, b byte) *uint32 {
+ result := uint32(r) | uint32(g)<<8 | uint32(b)<<16
+ return &result
+}
+
+// Track hover state for menubar items when maximized
+var (
+ currentHoverItem int = -1
+ menuIsOpen bool = false // Track if a dropdown menu is open
+)
+
+func MenuBarWndProc(hwnd HWND, msg uint32, wParam WPARAM, lParam LPARAM, theme *MenuBarTheme) (bool, LRESULT) {
+ // Only proceed if we have a theme (either for dark or light mode)
+ if theme == nil {
+ return false, 0
+ }
+ switch msg {
+ case WM_UAHDRAWMENU:
+ udm := (*UAHMENU)(unsafe.Pointer(lParam))
+
+ // Check if maximized first
+ isMaximized := IsZoomed(hwnd)
+
+ // get the menubar rect
+ var menuBarInfo MENUBARINFO
+ menuBarInfo.CbSize = uint32(unsafe.Sizeof(menuBarInfo))
+ if !GetMenuBarInfo(hwnd, OBJID_MENU, 0, &menuBarInfo) {
+ return false, 0
+ }
+
+ winRect := GetWindowRect(hwnd)
+
+ // the rcBar is offset by the window rect
+ rc := menuBarInfo.Bar
+ OffsetRect(&rc, int(-winRect.Left), int(-winRect.Top))
+
+ // DEBUG: Log the coordinates
+ // println("WM_UAHDRAWMENU: maximized=", isMaximized)
+ // println(" menubar screen rect: L=", menuBarInfo.Bar.Left, "T=", menuBarInfo.Bar.Top,
+ // "R=", menuBarInfo.Bar.Right, "B=", menuBarInfo.Bar.Bottom)
+ // println(" window rect: L=", winRect.Left, "T=", winRect.Top,
+ // "R=", winRect.Right, "B=", winRect.Bottom)
+ // println(" converted rect: L=", rc.Left, "T=", rc.Top,
+ // "R=", rc.Right, "B=", rc.Bottom)
+
+ // When maximized, Windows extends the window beyond the visible area
+ // We need to adjust the menubar rect to ensure it's fully visible
+ if isMaximized {
+ // Get the frame size - this is how much the window extends beyond visible area when maximized
+ frameY := GetSystemMetrics(SM_CYSIZEFRAME)
+ paddedBorder := GetSystemMetrics(SM_CXPADDEDBORDER)
+
+ // In Windows 10/11, the actual border is frame + padding
+ borderSize := frameY + paddedBorder
+
+ // println(" Frame metrics: frameY=", frameY, "paddedBorder=", paddedBorder, "borderSize=", borderSize)
+
+ // First, fill the area from the top of the visible area to the menubar
+ topFillRect := RECT{
+ Left: rc.Left,
+ Top: int32(borderSize), // Start of visible area in window coordinates
+ Right: rc.Right,
+ Bottom: rc.Top, // Up to where the menubar starts
+ }
+ FillRect(udm.Hdc, &topFillRect, theme.menuBarBackgroundBrush)
+ }
+
+ // Fill the entire menubar background with dark color
+ FillRect(udm.Hdc, &rc, theme.menuBarBackgroundBrush)
+
+ // Paint over the menubar border explicitly
+ // The border is typically 1-2 pixels at the bottom
+ borderRect := rc
+ borderRect.Top = borderRect.Bottom - 1
+ borderRect.Bottom = borderRect.Bottom + 2
+ FillRect(udm.Hdc, &borderRect, theme.menuBarBackgroundBrush)
+
+ // When maximized, we still need to handle the drawing ourselves
+ // Some projects found that returning false here causes issues
+
+ // When maximized, manually draw all menu items here
+ if isMaximized {
+ // Draw each menu item manually
+ itemCount := GetMenuItemCount(menuBarInfo.Menu)
+ for i := 0; i < itemCount; i++ {
+ var itemRect RECT
+ if GetMenuItemRect(hwnd, menuBarInfo.Menu, uint32(i), &itemRect) {
+ // Convert to window coordinates
+ OffsetRect(&itemRect, int(-winRect.Left), int(-winRect.Top))
+
+ // Check if this item is hovered
+ if i == currentHoverItem {
+ // Fill with hover background
+ FillRect(udm.Hdc, &itemRect, theme.menuHoverBackgroundBrush)
+ }
+
+ // Get menu text
+ menuString := make([]uint16, 256)
+ mii := MENUITEMINFO{
+ CbSize: uint32(unsafe.Sizeof(MENUITEMINFO{})),
+ FMask: MIIM_STRING,
+ DwTypeData: &menuString[0],
+ Cch: uint32(len(menuString) - 1),
+ }
+
+ if GetMenuItemInfo(menuBarInfo.Menu, uint32(i), true, &mii) {
+ // Draw the text
+ if i == currentHoverItem {
+ SetTextColor(udm.Hdc, COLORREF(*theme.MenuHoverText))
+ } else {
+ SetTextColor(udm.Hdc, COLORREF(*theme.TitleBarText))
+ }
+ SetBkMode(udm.Hdc, TRANSPARENT)
+ DrawText(udm.Hdc, menuString, -1, &itemRect, DT_CENTER|DT_SINGLELINE|DT_VCENTER)
+ }
+ }
+ }
+ }
+
+ // Return the original HDC so Windows can draw the menu text
+ return true, LRESULT(udm.Hdc)
+ case WM_DRAWITEM:
+ // Handle owner-drawn menu items
+ dis := (*DRAWITEMSTRUCT)(unsafe.Pointer(lParam))
+
+ // Check if this is a menu item
+ if dis.ControlType == ODT_MENU {
+ // Draw the menu item background
+ var bgBrush HBRUSH
+ var textColor uint32
+
+ if dis.ItemState&ODS_SELECTED != 0 {
+ // Selected state
+ bgBrush = theme.menuSelectedBackgroundBrush
+ textColor = *theme.MenuSelectedText
+ } else {
+ // Normal state
+ bgBrush = theme.titleBarBackgroundBrush
+ textColor = *theme.TitleBarText
+ }
+
+ // Fill background
+ FillRect(dis.HDC, &dis.RcItem, bgBrush)
+
+ // Draw text if we have item data
+ if dis.ItemData != 0 {
+ text := (*uint16)(unsafe.Pointer(dis.ItemData))
+ if text != nil {
+ // Set text color and draw
+ SetTextColor(dis.HDC, COLORREF(textColor))
+ SetBkMode(dis.HDC, TRANSPARENT)
+ DrawText(dis.HDC, (*[256]uint16)(unsafe.Pointer(text))[:], -1, &dis.RcItem, DT_CENTER|DT_SINGLELINE|DT_VCENTER)
+ }
+ }
+
+ return true, 1
+ }
+ case WM_UAHDRAWMENUITEM:
+ udmi := (*UAHDRAWMENUITEM)(unsafe.Pointer(lParam))
+
+ // Check if we're getting menu item draw messages when maximized or fullscreen
+ isMaximized := IsZoomed(hwnd)
+
+ // Create buffer for menu text
+ menuString := make([]uint16, 256)
+
+ // Setup menu item info structure
+ mii := MENUITEMINFO{
+ CbSize: uint32(unsafe.Sizeof(MENUITEMINFO{})),
+ FMask: MIIM_STRING | MIIM_SUBMENU,
+ DwTypeData: &menuString[0],
+ Cch: uint32(len(menuString) - 1),
+ }
+
+ if !GetMenuItemInfo(udmi.UM.Hmenu, uint32(udmi.UAMI.Position), true, &mii) {
+ // Failed to get menu item info, let default handler process
+ return false, 0
+ }
+
+ // Remove automatic popup on hover - menus should only open on click
+ // This was causing the menu to appear at wrong coordinates
+ dwFlags := uint32(DT_CENTER | DT_SINGLELINE | DT_VCENTER)
+
+ // When maximized/fullscreen, try without VCENTER to see if text appears
+ if isMaximized && os.Getenv("WAILS_TEST_NO_VCENTER") == "1" {
+ dwFlags = uint32(DT_CENTER | DT_SINGLELINE)
+ println(" Using dwFlags without VCENTER")
+ }
+
+ // Check if this is a menubar item
+ // When dwFlags has 0x0A00 (2560) it's a menubar item
+ isMenuBarItem := (udmi.UM.DwFlags&0x0A00) == 0x0A00 || udmi.UM.DwFlags == 0
+
+ // Use different colors for menubar vs popup items
+ var bgBrush HBRUSH
+ var textColor uint32
+
+ if udmi.DIS.ItemState&ODS_HOTLIGHT != 0 {
+ // Hot state - use a specific color for hover
+ bgBrush = theme.menuHoverBackgroundBrush
+ textColor = *theme.MenuHoverText
+ } else if udmi.DIS.ItemState&ODS_SELECTED != 0 {
+ // Selected state
+ bgBrush = theme.menuSelectedBackgroundBrush
+ textColor = *theme.MenuSelectedText
+ } else {
+ // Normal state
+ if isMenuBarItem {
+ // Menubar items in normal state
+ bgBrush = theme.menuBarBackgroundBrush
+ textColor = *theme.TitleBarText
+ } else {
+ // Popup menu items in normal state - use same color as menubar
+ bgBrush = theme.menuBarBackgroundBrush
+ textColor = *theme.TitleBarText
+ }
+ }
+
+ // Fill background
+ if bgBrush != 0 {
+ FillRect(udmi.UM.Hdc, &udmi.DIS.RcItem, bgBrush)
+ }
+
+ // Draw text
+ SetTextColor(udmi.UM.Hdc, COLORREF(textColor))
+ SetBkMode(udmi.UM.Hdc, TRANSPARENT)
+
+ // When maximized/fullscreen and menubar item, use the same font settings as drawMenuBarText
+ if isMaximized && isMenuBarItem {
+ // Create a non-bold font explicitly
+ menuFont := LOGFONT{
+ Height: -12, // Standard Windows menu font height (9pt)
+ Weight: 400, // FW_NORMAL (not bold)
+ CharSet: 1, // DEFAULT_CHARSET
+ Quality: 5, // CLEARTYPE_QUALITY
+ PitchAndFamily: 0, // DEFAULT_PITCH
+ }
+ // Set font face name to "Segoe UI" (Windows default)
+ fontName := []uint16{'S', 'e', 'g', 'o', 'e', ' ', 'U', 'I', 0}
+ copy(menuFont.FaceName[:], fontName)
+
+ hFont := CreateFontIndirect(&menuFont)
+ if hFont != 0 {
+ oldFont := SelectObject(udmi.UM.Hdc, HGDIOBJ(hFont))
+ DrawText(udmi.UM.Hdc, menuString, -1, &udmi.DIS.RcItem, dwFlags)
+ SelectObject(udmi.UM.Hdc, oldFont)
+ DeleteObject(HGDIOBJ(hFont))
+ } else {
+ DrawText(udmi.UM.Hdc, menuString, -1, &udmi.DIS.RcItem, dwFlags)
+ }
+ return true, 4 // CDRF_SKIPDEFAULT
+ } else {
+ DrawText(udmi.UM.Hdc, menuString, -1, &udmi.DIS.RcItem, dwFlags)
+ }
+
+ // Return appropriate value based on whether we're in maximized/fullscreen
+ // For maximized, we need to ensure Windows doesn't override our drawing
+ if isMaximized {
+ // Skip default processing to prevent Windows from overriding our colors
+ return true, 4 // CDRF_SKIPDEFAULT
+ }
+ // Return 1 to indicate we've handled the drawing
+ return true, 1
+ case WM_UAHMEASUREMENUITEM:
+ // Let the default window procedure handle the menu item measurement
+ // We're not modifying the default sizing anymore
+ result := DefWindowProc(hwnd, msg, wParam, lParam)
+
+ return true, result
+ case WM_NCPAINT:
+ // Paint our custom menubar first
+ paintDarkMenuBar(hwnd, theme)
+
+ // Then let Windows do its default painting
+ result := DefWindowProc(hwnd, msg, wParam, lParam)
+
+ // Paint again to ensure our painting is on top
+ paintDarkMenuBar(hwnd, theme)
+
+ return true, result
+ case WM_NCACTIVATE:
+ result := DefWindowProc(hwnd, msg, wParam, lParam)
+
+ // Force paint the menubar with dark background
+ paintDarkMenuBar(hwnd, theme)
+
+ return false, result
+ case WM_PAINT:
+ // Let Windows paint first
+ result := DefWindowProc(hwnd, msg, wParam, lParam)
+
+ // Then paint our menubar
+ paintDarkMenuBar(hwnd, theme)
+
+ return false, result
+ case WM_ACTIVATEAPP, WM_ACTIVATE:
+ // Handle app activation/deactivation
+ result := DefWindowProc(hwnd, msg, wParam, lParam)
+
+ // Repaint menubar
+ paintDarkMenuBar(hwnd, theme)
+
+ return false, result
+ case WM_SIZE, WM_WINDOWPOSCHANGED:
+ // Handle window size changes
+ result := DefWindowProc(hwnd, msg, wParam, lParam)
+
+ // Repaint menubar after size change
+ paintDarkMenuBar(hwnd, theme)
+
+ // CRITICAL: Force complete menubar redraw when maximized
+ if msg == WM_SIZE && wParam == SIZE_MAXIMIZED {
+ // Invalidate the entire menubar area to force redraw
+ var mbi MENUBARINFO
+ mbi.CbSize = uint32(unsafe.Sizeof(mbi))
+ if GetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi) {
+ InvalidateRect(hwnd, &mbi.Bar, true)
+ DrawMenuBar(hwnd)
+ }
+ }
+
+ return false, result
+ case WM_SETFOCUS, WM_KILLFOCUS:
+ // Handle focus changes (e.g., when inspector opens)
+ result := DefWindowProc(hwnd, msg, wParam, lParam)
+
+ // Repaint menubar after focus change
+ paintDarkMenuBar(hwnd, theme)
+
+ return false, result
+ case WM_ERASEBKGND:
+ // When maximized, draw menubar text here
+ if IsZoomed(hwnd) {
+ var menuBarInfo MENUBARINFO
+ menuBarInfo.CbSize = uint32(unsafe.Sizeof(menuBarInfo))
+ if GetMenuBarInfo(hwnd, OBJID_MENU, 0, &menuBarInfo) {
+ hdc := HDC(wParam)
+ drawMenuBarText(hwnd, hdc, &menuBarInfo, theme)
+ }
+ }
+ return false, 0
+ case WM_NCMOUSEMOVE, WM_MOUSEMOVE:
+ // Track mouse movement for hover effects when maximized
+ if IsZoomed(hwnd) {
+ // Don't process hover changes while menu is open
+ if menuIsOpen {
+ return false, 0
+ }
+
+ var screenX, screenY int32
+ if msg == WM_NCMOUSEMOVE {
+ // For NC messages, lParam contains screen coordinates
+ screenX = int32(LOWORD(uint32(lParam)))
+ screenY = int32(HIWORD(uint32(lParam)))
+ } else {
+ // For regular MOUSEMOVE, convert client to screen coordinates
+ clientX := int32(LOWORD(uint32(lParam)))
+ clientY := int32(HIWORD(uint32(lParam)))
+ sx, sy := ClientToScreen(hwnd, int(clientX), int(clientY))
+ screenX = int32(sx)
+ screenY = int32(sy)
+ }
+
+ // Check if we're over the menubar
+ var menuBarInfo MENUBARINFO
+ menuBarInfo.CbSize = uint32(unsafe.Sizeof(menuBarInfo))
+ if GetMenuBarInfo(hwnd, OBJID_MENU, 0, &menuBarInfo) {
+ // menuBarInfo.Bar already contains screen coordinates
+ // Check if mouse is over menubar using screen coordinates
+ if screenX >= menuBarInfo.Bar.Left && screenX <= menuBarInfo.Bar.Right &&
+ screenY >= menuBarInfo.Bar.Top && screenY <= menuBarInfo.Bar.Bottom {
+
+ // Always re-request mouse tracking to ensure we get leave messages
+ TrackMouseEvent(&TRACKMOUSEEVENT{
+ CbSize: uint32(unsafe.Sizeof(TRACKMOUSEEVENT{})),
+ DwFlags: TME_LEAVE | TME_NONCLIENT,
+ HwndTrack: hwnd,
+ DwHoverTime: 0,
+ })
+ // Find which menu item we're over
+ itemCount := GetMenuItemCount(menuBarInfo.Menu)
+ newHoverItem := -1
+
+ for i := 0; i < itemCount; i++ {
+ var itemRect RECT
+ if GetMenuItemRect(hwnd, menuBarInfo.Menu, uint32(i), &itemRect) {
+ // itemRect is already in screen coordinates from GetMenuItemRect
+ // Check using screen coordinates
+ if screenX >= itemRect.Left && screenX <= itemRect.Right &&
+ screenY >= itemRect.Top && screenY <= itemRect.Bottom {
+ newHoverItem = i
+ break
+ }
+ }
+ }
+
+ // If hover item changed, update and redraw just the menubar
+ if newHoverItem != currentHoverItem {
+ currentHoverItem = newHoverItem
+ // Get the actual menubar rect for precise invalidation
+ winRect := GetWindowRect(hwnd)
+ menubarRect := menuBarInfo.Bar
+ // Convert to window coordinates
+ menubarRect.Left -= winRect.Left
+ menubarRect.Top -= winRect.Top
+ menubarRect.Right -= winRect.Left
+ menubarRect.Bottom -= winRect.Top
+ // Invalidate only the menubar
+ InvalidateRect(hwnd, &menubarRect, false)
+ }
+ } else {
+ // Mouse left menubar
+ if currentHoverItem != -1 {
+ currentHoverItem = -1
+ // Get the actual menubar rect
+ winRect := GetWindowRect(hwnd)
+ menubarRect := menuBarInfo.Bar
+ // Convert to window coordinates
+ menubarRect.Left -= winRect.Left
+ menubarRect.Top -= winRect.Top
+ menubarRect.Right -= winRect.Left
+ menubarRect.Bottom -= winRect.Top
+ InvalidateRect(hwnd, &menubarRect, false)
+ }
+ }
+ }
+ }
+ return false, 0
+ case WM_NCLBUTTONDOWN:
+ // When clicking on menubar, clear hover state immediately
+ if IsZoomed(hwnd) && currentHoverItem != -1 {
+ // Check if click is on menubar
+ var menuBarInfo MENUBARINFO
+ menuBarInfo.CbSize = uint32(unsafe.Sizeof(menuBarInfo))
+ if GetMenuBarInfo(hwnd, OBJID_MENU, 0, &menuBarInfo) {
+ // Get click position (screen coordinates)
+ clickX := int32(LOWORD(uint32(lParam)))
+ clickY := int32(HIWORD(uint32(lParam)))
+
+ if clickX >= menuBarInfo.Bar.Left && clickX <= menuBarInfo.Bar.Right &&
+ clickY >= menuBarInfo.Bar.Top && clickY <= menuBarInfo.Bar.Bottom {
+ // Click is on menubar - clear hover
+ currentHoverItem = -1
+ }
+ }
+ }
+ return false, 0
+ case WM_NCMOUSELEAVE, WM_MOUSELEAVE:
+ // Clear hover state when mouse leaves (but not if menu is open)
+ if IsZoomed(hwnd) && currentHoverItem != -1 && !menuIsOpen {
+ currentHoverItem = -1
+ // Get menubar info for precise invalidation
+ var menuBarInfo MENUBARINFO
+ menuBarInfo.CbSize = uint32(unsafe.Sizeof(menuBarInfo))
+ if GetMenuBarInfo(hwnd, OBJID_MENU, 0, &menuBarInfo) {
+ winRect := GetWindowRect(hwnd)
+ menubarRect := menuBarInfo.Bar
+ menubarRect.Left -= winRect.Left
+ menubarRect.Top -= winRect.Top
+ menubarRect.Right -= winRect.Left
+ menubarRect.Bottom -= winRect.Top
+ InvalidateRect(hwnd, &menubarRect, false)
+ }
+ }
+ return false, 0
+ case WM_ENTERMENULOOP:
+ // Menu is being opened - clear hover state
+ menuIsOpen = true
+ if IsZoomed(hwnd) && currentHoverItem != -1 {
+ oldHoverItem := currentHoverItem
+ currentHoverItem = -1
+ // Redraw the previously hovered item to remove hover effect
+ var menuBarInfo MENUBARINFO
+ menuBarInfo.CbSize = uint32(unsafe.Sizeof(menuBarInfo))
+ if GetMenuBarInfo(hwnd, OBJID_MENU, 0, &menuBarInfo) {
+ var itemRect RECT
+ if GetMenuItemRect(hwnd, menuBarInfo.Menu, uint32(oldHoverItem), &itemRect) {
+ winRect := GetWindowRect(hwnd)
+ // Convert to window coordinates
+ itemRect.Left -= winRect.Left
+ itemRect.Top -= winRect.Top
+ itemRect.Right -= winRect.Left
+ itemRect.Bottom -= winRect.Top
+ // Add some padding
+ itemRect.Left -= 5
+ itemRect.Right += 5
+ itemRect.Top -= 5
+ itemRect.Bottom += 5
+ InvalidateRect(hwnd, &itemRect, false)
+ }
+ }
+ }
+ return false, 0
+ case WM_EXITMENULOOP:
+ // Menu has been closed
+ menuIsOpen = false
+ // Clear any existing hover state first
+ currentHoverItem = -1
+ // Force a complete menubar redraw
+ if IsZoomed(hwnd) {
+ var menuBarInfo MENUBARINFO
+ menuBarInfo.CbSize = uint32(unsafe.Sizeof(menuBarInfo))
+ if GetMenuBarInfo(hwnd, OBJID_MENU, 0, &menuBarInfo) {
+ winRect := GetWindowRect(hwnd)
+ menubarRect := menuBarInfo.Bar
+ menubarRect.Left -= winRect.Left
+ menubarRect.Top -= winRect.Top
+ menubarRect.Right -= winRect.Left
+ menubarRect.Bottom -= winRect.Top
+ InvalidateRect(hwnd, &menubarRect, false)
+ }
+ // Force a timer to restart mouse tracking
+ SetTimer(hwnd, 1001, 50, 0)
+ }
+ return false, 0
+ case WM_TIMER:
+ // Handle our mouse tracking restart timer
+ if wParam == 1001 {
+ KillTimer(hwnd, 1001)
+ if IsZoomed(hwnd) {
+ // Get current mouse position and simulate a mouse move
+ x, y, _ := GetCursorPos()
+ // Check if mouse is over the window
+ winRect := GetWindowRect(hwnd)
+ if x >= int(winRect.Left) && x <= int(winRect.Right) &&
+ y >= int(winRect.Top) && y <= int(winRect.Bottom) {
+ // Check if we're over the menubar specifically
+ var menuBarInfo MENUBARINFO
+ menuBarInfo.CbSize = uint32(unsafe.Sizeof(menuBarInfo))
+ if GetMenuBarInfo(hwnd, OBJID_MENU, 0, &menuBarInfo) {
+ if int32(x) >= menuBarInfo.Bar.Left && int32(x) <= menuBarInfo.Bar.Right &&
+ int32(y) >= menuBarInfo.Bar.Top && int32(y) <= menuBarInfo.Bar.Bottom {
+ // Post a non-client mouse move to restart tracking
+ PostMessage(hwnd, WM_NCMOUSEMOVE, 0, uintptr(y)<<16|uintptr(x)&0xFFFF)
+ } else {
+ // Convert to client coordinates for regular mouse move
+ clientX, clientY, _ := ScreenToClient(hwnd, x, y)
+ // Post a mouse move message to restart tracking
+ PostMessage(hwnd, WM_MOUSEMOVE, 0, uintptr(clientY)<<16|uintptr(clientX)&0xFFFF)
+ }
+ }
+ }
+ }
+ return true, 0
+ }
+ return false, 0
+ }
+ return false, 0
+}
+
+// paintDarkMenuBar paints the menubar with dark background
+func paintDarkMenuBar(hwnd HWND, theme *MenuBarTheme) {
+ // Get menubar info
+ var menuBarInfo MENUBARINFO
+ menuBarInfo.CbSize = uint32(unsafe.Sizeof(menuBarInfo))
+ if !GetMenuBarInfo(hwnd, OBJID_MENU, 0, &menuBarInfo) {
+ return
+ }
+
+ // Get window DC
+ hdc := GetWindowDC(hwnd)
+ if hdc == 0 {
+ return
+ }
+ defer ReleaseDC(hwnd, hdc)
+
+ // Check if window is maximized or fullscreen
+ isMaximized := IsZoomed(hwnd)
+ isFullscreen := false
+
+ // Check if window is in fullscreen by checking if it covers the monitor
+ windowRect := GetWindowRect(hwnd)
+ monitor := MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)
+ var monitorInfo MONITORINFO
+ monitorInfo.CbSize = uint32(unsafe.Sizeof(monitorInfo))
+ if GetMonitorInfo(monitor, &monitorInfo) {
+ // If window matches monitor bounds, it's fullscreen
+ if windowRect.Left == monitorInfo.RcMonitor.Left &&
+ windowRect.Top == monitorInfo.RcMonitor.Top &&
+ windowRect.Right == monitorInfo.RcMonitor.Right &&
+ windowRect.Bottom == monitorInfo.RcMonitor.Bottom {
+ isFullscreen = true
+ }
+ }
+
+ // When maximized or fullscreen, we need to handle the special case
+ if isMaximized || isFullscreen {
+ // Convert menubar rect from screen to window coordinates
+ menubarRect := menuBarInfo.Bar
+ menubarRect.Left -= windowRect.Left
+ menubarRect.Top -= windowRect.Top
+ menubarRect.Right -= windowRect.Left
+ menubarRect.Bottom -= windowRect.Top
+
+ if isMaximized && !isFullscreen {
+ // Get the frame size (only for maximized, not fullscreen)
+ frameY := GetSystemMetrics(SM_CYSIZEFRAME)
+ paddedBorder := GetSystemMetrics(SM_CXPADDEDBORDER)
+ borderSize := frameY + paddedBorder
+
+ // Fill from visible area top to menubar
+ topFillRect := RECT{
+ Left: menubarRect.Left,
+ Top: int32(borderSize), // Start of visible area
+ Right: menubarRect.Right,
+ Bottom: menubarRect.Top,
+ }
+ FillRect(hdc, &topFillRect, theme.menuBarBackgroundBrush)
+ } else if isFullscreen {
+ // In fullscreen, fill from the very top
+ topFillRect := RECT{
+ Left: menubarRect.Left,
+ Top: 0, // Start from top in fullscreen
+ Right: menubarRect.Right,
+ Bottom: menubarRect.Top,
+ }
+ FillRect(hdc, &topFillRect, theme.menuBarBackgroundBrush)
+ }
+
+ // Fill the menubar itself
+ FillRect(hdc, &menubarRect, theme.menuBarBackgroundBrush)
+ } else {
+ // Paint the menubar background with dark color
+ FillRect(hdc, &menuBarInfo.Bar, theme.menuBarBackgroundBrush)
+ }
+
+ // Get window and client rects to find the non-client area
+ clientRect := GetClientRect(hwnd)
+
+ // Convert client rect top-left to screen coordinates
+ _, screenY := ClientToScreen(hwnd, int(clientRect.Left), int(clientRect.Top))
+
+ // Paint the entire area between menubar and client area
+ // This should cover any borders
+ borderRect := RECT{
+ Left: 0,
+ Top: menuBarInfo.Bar.Bottom - windowRect.Top,
+ Right: windowRect.Right - windowRect.Left,
+ Bottom: int32(screenY) - windowRect.Top,
+ }
+ FillRect(hdc, &borderRect, theme.menuBarBackgroundBrush)
+
+ // When maximized or fullscreen, also draw menubar text
+ if isMaximized || isFullscreen {
+ drawMenuBarText(hwnd, hdc, &menuBarInfo, theme)
+ }
+}
+
+func drawMenuBarText(hwnd HWND, hdc HDC, menuBarInfo *MENUBARINFO, theme *MenuBarTheme) {
+ // Get the menu handle
+ hmenu := menuBarInfo.Menu
+ if hmenu == 0 {
+ return
+ }
+
+ // Get the number of menu items
+ itemCount := GetMenuItemCount(hmenu)
+ if itemCount <= 0 {
+ return
+ }
+
+ // Create a non-bold font explicitly
+ menuFont := LOGFONT{
+ Height: -12, // Standard Windows menu font height (9pt)
+ Weight: 400, // FW_NORMAL (not bold)
+ CharSet: 1, // DEFAULT_CHARSET
+ Quality: 5, // CLEARTYPE_QUALITY
+ PitchAndFamily: 0, // DEFAULT_PITCH
+ }
+ // Set font face name to "Segoe UI" (Windows default)
+ fontName := []uint16{'S', 'e', 'g', 'o', 'e', ' ', 'U', 'I', 0}
+ copy(menuFont.FaceName[:], fontName)
+
+ hFont := CreateFontIndirect(&menuFont)
+ if hFont != 0 {
+ oldFont := SelectObject(hdc, HGDIOBJ(hFont))
+ defer func() {
+ SelectObject(hdc, oldFont)
+ DeleteObject(HGDIOBJ(hFont))
+ }()
+ }
+
+ // Set text color and background mode
+ SetTextColor(hdc, COLORREF(*theme.TitleBarText))
+ SetBkMode(hdc, TRANSPARENT)
+
+ // Get the window rect for coordinate conversion
+ winRect := GetWindowRect(hwnd)
+
+ // Iterate through each menu item
+ for i := 0; i < itemCount; i++ {
+ // Get the menu item rect
+ var itemRect RECT
+ if !GetMenuItemRect(hwnd, hmenu, uint32(i), &itemRect) {
+ continue
+ }
+
+ // Convert to window coordinates
+ OffsetRect(&itemRect, int(-winRect.Left), int(-winRect.Top))
+
+ // Check if this item is hovered
+ if i == currentHoverItem {
+ // Fill with hover background
+ FillRect(hdc, &itemRect, theme.menuHoverBackgroundBrush)
+ }
+
+ // Get the menu item text
+ menuString := make([]uint16, 256)
+ mii := MENUITEMINFO{
+ CbSize: uint32(unsafe.Sizeof(MENUITEMINFO{})),
+ FMask: MIIM_STRING,
+ DwTypeData: &menuString[0],
+ Cch: uint32(len(menuString) - 1),
+ }
+
+ if GetMenuItemInfo(hmenu, uint32(i), true, &mii) {
+ // Set text color based on hover state
+ if i == currentHoverItem {
+ SetTextColor(hdc, COLORREF(*theme.MenuHoverText))
+ } else {
+ SetTextColor(hdc, COLORREF(*theme.TitleBarText))
+ }
+ // Draw the text
+ DrawText(hdc, menuString, -1, &itemRect, DT_CENTER|DT_SINGLELINE|DT_VCENTER)
+ }
+ }
+}
diff --git a/v3/pkg/w32/ole32.go b/v3/pkg/w32/ole32.go
new file mode 100644
index 000000000..a7d204912
--- /dev/null
+++ b/v3/pkg/w32/ole32.go
@@ -0,0 +1,119 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+
+ "github.com/wailsapp/go-webview2/pkg/combridge"
+)
+
+var (
+ modole32 = syscall.NewLazyDLL("ole32.dll")
+
+ procCoInitializeEx = modole32.NewProc("CoInitializeEx")
+ procCoInitialize = modole32.NewProc("CoInitialize")
+ procOleInitialize = modole32.NewProc("OleInitialize")
+ procCoUninitialize = modole32.NewProc("CoUninitialize")
+ procCoCreateInstance = modole32.NewProc("CoCreateInstance")
+ procCreateStreamOnHGlobal = modole32.NewProc("CreateStreamOnHGlobal")
+ procRegisterDragDrop = modole32.NewProc("RegisterDragDrop")
+ procRevokeDragDrop = modole32.NewProc("RevokeDragDrop")
+)
+
+func CoInitializeEx(coInit uintptr) HRESULT {
+ ret, _, _ := procCoInitializeEx.Call(
+ 0,
+ coInit)
+
+ switch uint32(ret) {
+ case E_INVALIDARG:
+ panic("CoInitializeEx failed with E_INVALIDARG")
+ case E_OUTOFMEMORY:
+ panic("CoInitializeEx failed with E_OUTOFMEMORY")
+ case E_UNEXPECTED:
+ panic("CoInitializeEx failed with E_UNEXPECTED")
+ }
+
+ return HRESULT(ret)
+}
+
+func CoInitialize() {
+ procCoInitialize.Call(0)
+}
+
+func CoUninitialize() {
+ procCoUninitialize.Call()
+}
+
+func CoCreateInstance(clsid *syscall.GUID, dwClsContext uintptr, riid *syscall.GUID, ppv uintptr) HRESULT {
+ ret, _, _ := procCoCreateInstance.Call(
+ uintptr(unsafe.Pointer(clsid)),
+ 0,
+ uintptr(dwClsContext),
+ uintptr(unsafe.Pointer(riid)),
+ uintptr(ppv))
+
+ switch uint32(ret) {
+ case E_INVALIDARG:
+ panic("CoCreateInstance failed with E_INVALIDARG")
+ case E_OUTOFMEMORY:
+ panic("CoCreateInstance failed with E_OUTOFMEMORY")
+ case E_UNEXPECTED:
+ panic("CoCreateInstance failed with E_UNEXPECTED")
+ }
+
+ return HRESULT(ret)
+}
+
+func CreateStreamOnHGlobal(hGlobal HGLOBAL, fDeleteOnRelease bool) *IStream {
+ stream := new(IStream)
+ ret, _, _ := procCreateStreamOnHGlobal.Call(
+ uintptr(hGlobal),
+ uintptr(BoolToBOOL(fDeleteOnRelease)),
+ uintptr(unsafe.Pointer(&stream)))
+
+ switch uint32(ret) {
+ case E_INVALIDARG:
+ panic("CreateStreamOnHGlobal failed with E_INVALIDARG")
+ case E_OUTOFMEMORY:
+ panic("CreateStreamOnHGlobal failed with E_OUTOFMEMORY")
+ case E_UNEXPECTED:
+ panic("CreateStreamOnHGlobal failed with E_UNEXPECTED")
+ }
+
+ return stream
+}
+func OleInitialise() {
+ procOleInitialize.Call()
+}
+
+func RegisterDragDrop(hwnd HWND, dropTarget *DropTarget) error {
+
+ dt := combridge.New[iDropTarget](dropTarget)
+ hr, _, _ := procRegisterDragDrop.Call(
+ hwnd,
+ dt.Ref(),
+ )
+
+ if hr != S_OK {
+ return syscall.Errno(hr)
+ }
+ return nil
+}
+
+func RevokeDragDrop(hwnd HWND) error {
+ hr, _, _ := procRevokeDragDrop.Call(
+ hwnd,
+ )
+
+ if hr != S_OK {
+ return syscall.Errno(hr)
+ }
+ return nil
+}
diff --git a/v3/pkg/w32/oleaut32.go b/v3/pkg/w32/oleaut32.go
new file mode 100644
index 000000000..0bb8ef7da
--- /dev/null
+++ b/v3/pkg/w32/oleaut32.go
@@ -0,0 +1,50 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modoleaut32 = syscall.NewLazyDLL("oleaut32")
+
+ procVariantInit = modoleaut32.NewProc("VariantInit")
+ procSysAllocString = modoleaut32.NewProc("SysAllocString")
+ procSysFreeString = modoleaut32.NewProc("SysFreeString")
+ procSysStringLen = modoleaut32.NewProc("SysStringLen")
+ procCreateDispTypeInfo = modoleaut32.NewProc("CreateDispTypeInfo")
+ procCreateStdDispatch = modoleaut32.NewProc("CreateStdDispatch")
+)
+
+func VariantInit(v *VARIANT) {
+ hr, _, _ := procVariantInit.Call(uintptr(unsafe.Pointer(v)))
+ if hr != 0 {
+ panic("Invoke VariantInit error.")
+ }
+ return
+}
+
+func SysAllocString(v string) (ss *int16) {
+ pss, _, _ := procSysAllocString.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(v))))
+ ss = (*int16)(unsafe.Pointer(pss))
+ return
+}
+
+func SysFreeString(v *int16) {
+ hr, _, _ := procSysFreeString.Call(uintptr(unsafe.Pointer(v)))
+ if hr != 0 {
+ panic("Invoke SysFreeString error.")
+ }
+ return
+}
+
+func SysStringLen(v *int16) uint {
+ l, _, _ := procSysStringLen.Call(uintptr(unsafe.Pointer(v)))
+ return uint(l)
+}
diff --git a/v3/pkg/w32/popupmenu.go b/v3/pkg/w32/popupmenu.go
new file mode 100644
index 000000000..670eabf9f
--- /dev/null
+++ b/v3/pkg/w32/popupmenu.go
@@ -0,0 +1,96 @@
+//go:build windows
+
+package w32
+
+type Menu HMENU
+type PopupMenu Menu
+
+func (m Menu) destroy() bool {
+ ret, _, _ := procDestroyMenu.Call(uintptr(m))
+ return ret != 0
+}
+
+func (p PopupMenu) destroy() bool {
+ return Menu(p).destroy()
+}
+
+func (p PopupMenu) Track(hwnd HWND, flags uint32, x, y int32) bool {
+ return TrackPopupMenuEx(
+ HMENU(p),
+ flags,
+ x,
+ y,
+ hwnd,
+ nil)
+}
+
+func RemoveMenu(m HMENU, pos, flags int) bool {
+ ret, _, _ := procRemoveMenu.Call(
+ uintptr(m),
+ uintptr(pos),
+ uintptr(flags))
+ return ret != 0
+}
+
+func (p PopupMenu) Append(flags uint32, id uintptr, text string) bool {
+ return Menu(p).Append(flags, id, text)
+}
+
+func (m Menu) Append(flags uint32, id uintptr, text string) bool {
+ return AppendMenu(HMENU(m), flags, id, MustStringToUTF16Ptr(text))
+}
+
+func (p PopupMenu) Check(id uintptr, checked bool) bool {
+ return Menu(p).Check(id, checked)
+}
+
+func (m Menu) Check(id uintptr, check bool) bool {
+ var checkState uint = MF_UNCHECKED
+ if check {
+ checkState = MF_CHECKED
+ }
+ return CheckMenuItem(HMENU(m), id, checkState) != 0
+}
+
+func CheckRadio(m HMENU, startID int, endID int, selectedID int) bool {
+ ret, _, _ := procCheckMenuRadioItem.Call(
+ m,
+ uintptr(startID),
+ uintptr(endID),
+ uintptr(selectedID),
+ MF_BYCOMMAND)
+ return ret != 0
+}
+
+func (m Menu) CheckRadio(startID int, endID int, selectedID int) bool {
+ ret, _, _ := procCheckMenuRadioItem.Call(
+ uintptr(m),
+ uintptr(startID),
+ uintptr(endID),
+ uintptr(selectedID),
+ MF_BYCOMMAND)
+ return ret != 0
+}
+
+func CheckMenuItem(menu HMENU, id uintptr, flags uint) uint {
+ ret, _, _ := procCheckMenuItem.Call(
+ menu,
+ id,
+ uintptr(flags),
+ )
+ return uint(ret)
+}
+
+func (p PopupMenu) CheckRadio(startID, endID, selectedID int) bool {
+ return Menu(p).CheckRadio(startID, endID, selectedID)
+}
+
+func NewMenu() HMENU {
+ ret, _, _ := procCreateMenu.Call()
+ return HMENU(ret)
+}
+
+func NewPopupMenu() HMENU {
+ ret, _, _ := procCreatePopupMenu.Call()
+ return ret
+}
diff --git a/v3/pkg/w32/screen.go b/v3/pkg/w32/screen.go
new file mode 100644
index 000000000..113b1d4cc
--- /dev/null
+++ b/v3/pkg/w32/screen.go
@@ -0,0 +1,143 @@
+//go:build windows
+
+package w32
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+type Screen struct {
+ MONITORINFOEX
+ HMonitor uintptr
+ Name string
+ IsPrimary bool
+ IsCurrent bool
+ ScaleFactor float32
+ Rotation float32
+}
+
+type DISPLAY_DEVICE struct {
+ cb uint32
+ DeviceName [32]uint16
+ DeviceString [128]uint16
+ StateFlags uint32
+ DeviceID [128]uint16
+ DeviceKey [128]uint16
+}
+
+func getMonitorName(deviceName string) (string, error) {
+ var device DISPLAY_DEVICE
+ device.cb = uint32(unsafe.Sizeof(device))
+ i := uint32(0)
+ for {
+ res, _, _ := procEnumDisplayDevices.Call(uintptr(unsafe.Pointer(MustStringToUTF16Ptr(deviceName))), uintptr(i), uintptr(unsafe.Pointer(&device)), 0)
+ if res == 0 {
+ break
+ }
+ if device.StateFlags&0x1 != 0 {
+ return syscall.UTF16ToString(device.DeviceString[:]), nil
+ }
+ i++
+ }
+
+ return "", fmt.Errorf("monitor name not found for device: %s", deviceName)
+}
+
+// I'm not convinced this works properly
+func GetRotationForMonitor(displayName [32]uint16) (float32, error) {
+ var devMode DEVMODE
+ devMode.DmSize = uint16(unsafe.Sizeof(devMode))
+ resp, _, _ := procEnumDisplaySettings.Call(uintptr(unsafe.Pointer(&displayName[0])), ENUM_CURRENT_SETTINGS, uintptr(unsafe.Pointer(&devMode)))
+ if resp == 0 {
+ return 0, fmt.Errorf("EnumDisplaySettings failed")
+ }
+
+ if (devMode.DmFields & DM_DISPLAYORIENTATION) == 0 {
+ return 0, fmt.Errorf("DM_DISPLAYORIENTATION not set")
+ }
+
+ switch devMode.DmOrientation {
+ case DMDO_DEFAULT:
+ return 0, nil
+ case DMDO_90:
+ return 90, nil
+ case DMDO_180:
+ return 180, nil
+ case DMDO_270:
+ return 270, nil
+ }
+
+ return -1, nil
+}
+
+func GetAllScreens() ([]*Screen, error) {
+ var result []*Screen
+ var errMessage string
+
+ // Get cursor position to determine the current monitor
+ var cursor POINT
+ ret, _, _ := procGetCursorPos.Call(uintptr(unsafe.Pointer(&cursor)))
+ if ret == 0 {
+ return nil, fmt.Errorf("GetCursorPos failed")
+ }
+
+ // Enumerate the monitors
+ enumFunc := func(hMonitor uintptr, hdc uintptr, lprcMonitor *RECT, lParam uintptr) uintptr {
+ monitor := MONITORINFOEX{
+ MONITORINFO: MONITORINFO{
+ CbSize: uint32(unsafe.Sizeof(MONITORINFOEX{})),
+ },
+ SzDevice: [32]uint16{},
+ }
+ ret, _, _ := procGetMonitorInfo.Call(hMonitor, uintptr(unsafe.Pointer(&monitor)))
+ if ret == 0 {
+ errMessage = "GetMonitorInfo failed"
+ return 0 // Stop enumeration
+ }
+
+ screen := &Screen{
+ MONITORINFOEX: monitor,
+ HMonitor: hMonitor,
+ IsPrimary: monitor.DwFlags == MONITORINFOF_PRIMARY,
+ IsCurrent: rectContainsPoint(monitor.RcMonitor, cursor),
+ }
+
+ // Get monitor name
+ name, err := getMonitorName(syscall.UTF16ToString(monitor.SzDevice[:]))
+ if err == nil {
+ screen.Name = name
+ }
+
+ // Get DPI for monitor
+ var dpiX, dpiY uint
+ ret = GetDPIForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY)
+ if ret != S_OK {
+ errMessage = "GetDpiForMonitor failed"
+ return 0 // Stop enumeration
+ }
+ // Convert to scale factor
+ screen.ScaleFactor = float32(dpiX) / 96.0
+
+ // Get rotation of monitor
+ rot, err := GetRotationForMonitor(monitor.SzDevice)
+ if err == nil {
+ screen.Rotation = rot
+ }
+
+ result = append(result, screen)
+ return 1 // Continue enumeration
+ }
+
+ ret, _, _ = procEnumDisplayMonitors.Call(0, 0, syscall.NewCallback(enumFunc), 0)
+ if ret == 0 {
+ return nil, fmt.Errorf("EnumDisplayMonitors failed: %s", errMessage)
+ }
+
+ return result, nil
+}
+
+func rectContainsPoint(r RECT, p POINT) bool {
+ return p.X >= r.Left && p.X < r.Right && p.Y >= r.Top && p.Y < r.Bottom
+}
diff --git a/v3/pkg/w32/shcore.go b/v3/pkg/w32/shcore.go
new file mode 100644
index 000000000..f83062eb3
--- /dev/null
+++ b/v3/pkg/w32/shcore.go
@@ -0,0 +1,71 @@
+//go:build windows
+
+package w32
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modshcore = syscall.NewLazyDLL("shcore.dll")
+
+ procGetDpiForMonitor = modshcore.NewProc("GetDpiForMonitor")
+ procGetProcessDpiAwareness = modshcore.NewProc("GetProcessDpiAwareness")
+ procSetProcessDpiAwareness = modshcore.NewProc("SetProcessDpiAwareness")
+)
+
+func HasGetProcessDpiAwarenessFunc() bool {
+ err := procGetProcessDpiAwareness.Find()
+ return err == nil
+}
+
+// GetProcessDpiAwareness retrieves the DPI awareness of the current process.
+// Returns one of: PROCESS_DPI_UNAWARE, PROCESS_SYSTEM_DPI_AWARE, or PROCESS_PER_MONITOR_DPI_AWARE.
+func GetProcessDpiAwareness() (uint, error) {
+ var awareness uint
+ status, _, err := procGetProcessDpiAwareness.Call(0, uintptr(unsafe.Pointer(&awareness)))
+ if status != S_OK {
+ return 0, fmt.Errorf("GetProcessDpiAwareness failed: %v", err)
+ }
+ return awareness, nil
+}
+
+func HasSetProcessDpiAwarenessFunc() bool {
+ err := procSetProcessDpiAwareness.Find()
+ return err == nil
+}
+
+func SetProcessDpiAwareness(val uint) error {
+ status, r, err := procSetProcessDpiAwareness.Call(uintptr(val))
+ if status != S_OK {
+ return fmt.Errorf("procSetProcessDpiAwareness failed %d: %v %v", status, r, err)
+ }
+ return nil
+}
+
+func HasGetDPIForMonitorFunc() bool {
+ err := procGetDpiForMonitor.Find()
+ return err == nil
+}
+
+func GetDPIForMonitor(hmonitor HMONITOR, dpiType MONITOR_DPI_TYPE, dpiX *UINT, dpiY *UINT) uintptr {
+ ret, _, _ := procGetDpiForMonitor.Call(
+ hmonitor,
+ uintptr(dpiType),
+ uintptr(unsafe.Pointer(dpiX)),
+ uintptr(unsafe.Pointer(dpiY)))
+
+ return ret
+}
+
+func GetNotificationFlyoutBounds() (*RECT, error) {
+ var rect RECT
+ res, _, err := procSystemParametersInfo.Call(SPI_GETNOTIFYWINDOWRECT, 0, uintptr(unsafe.Pointer(&rect)), 0)
+ if res == 0 {
+ _ = err
+ return nil, err
+ }
+ return &rect, nil
+}
diff --git a/v3/pkg/w32/shell32.go b/v3/pkg/w32/shell32.go
new file mode 100644
index 000000000..e8f3f8f08
--- /dev/null
+++ b/v3/pkg/w32/shell32.go
@@ -0,0 +1,414 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+package w32
+
+import (
+ "errors"
+ "fmt"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+type CSIDL uint32
+
+const (
+ CSIDL_DESKTOP = 0x00
+ CSIDL_INTERNET = 0x01
+ CSIDL_PROGRAMS = 0x02
+ CSIDL_CONTROLS = 0x03
+ CSIDL_PRINTERS = 0x04
+ CSIDL_PERSONAL = 0x05
+ CSIDL_FAVORITES = 0x06
+ CSIDL_STARTUP = 0x07
+ CSIDL_RECENT = 0x08
+ CSIDL_SENDTO = 0x09
+ CSIDL_BITBUCKET = 0x0A
+ CSIDL_STARTMENU = 0x0B
+ CSIDL_MYDOCUMENTS = 0x0C
+ CSIDL_MYMUSIC = 0x0D
+ CSIDL_MYVIDEO = 0x0E
+ CSIDL_DESKTOPDIRECTORY = 0x10
+ CSIDL_DRIVES = 0x11
+ CSIDL_NETWORK = 0x12
+ CSIDL_NETHOOD = 0x13
+ CSIDL_FONTS = 0x14
+ CSIDL_TEMPLATES = 0x15
+ CSIDL_COMMON_STARTMENU = 0x16
+ CSIDL_COMMON_PROGRAMS = 0x17
+ CSIDL_COMMON_STARTUP = 0x18
+ CSIDL_COMMON_DESKTOPDIRECTORY = 0x19
+ CSIDL_APPDATA = 0x1A
+ CSIDL_PRINTHOOD = 0x1B
+ CSIDL_LOCAL_APPDATA = 0x1C
+ CSIDL_ALTSTARTUP = 0x1D
+ CSIDL_COMMON_ALTSTARTUP = 0x1E
+ CSIDL_COMMON_FAVORITES = 0x1F
+ CSIDL_INTERNET_CACHE = 0x20
+ CSIDL_COOKIES = 0x21
+ CSIDL_HISTORY = 0x22
+ CSIDL_COMMON_APPDATA = 0x23
+ CSIDL_WINDOWS = 0x24
+ CSIDL_SYSTEM = 0x25
+ CSIDL_PROGRAM_FILES = 0x26
+ CSIDL_MYPICTURES = 0x27
+ CSIDL_PROFILE = 0x28
+ CSIDL_SYSTEMX86 = 0x29
+ CSIDL_PROGRAM_FILESX86 = 0x2A
+ CSIDL_PROGRAM_FILES_COMMON = 0x2B
+ CSIDL_PROGRAM_FILES_COMMONX86 = 0x2C
+ CSIDL_COMMON_TEMPLATES = 0x2D
+ CSIDL_COMMON_DOCUMENTS = 0x2E
+ CSIDL_COMMON_ADMINTOOLS = 0x2F
+ CSIDL_ADMINTOOLS = 0x30
+ CSIDL_CONNECTIONS = 0x31
+ CSIDL_COMMON_MUSIC = 0x35
+ CSIDL_COMMON_PICTURES = 0x36
+ CSIDL_COMMON_VIDEO = 0x37
+ CSIDL_RESOURCES = 0x38
+ CSIDL_RESOURCES_LOCALIZED = 0x39
+ CSIDL_COMMON_OEM_LINKS = 0x3A
+ CSIDL_CDBURN_AREA = 0x3B
+ CSIDL_COMPUTERSNEARME = 0x3D
+ CSIDL_FLAG_CREATE = 0x8000
+ CSIDL_FLAG_DONT_VERIFY = 0x4000
+ CSIDL_FLAG_NO_ALIAS = 0x1000
+ CSIDL_FLAG_PER_USER_INIT = 0x8000
+ CSIDL_FLAG_MASK = 0xFF00
+)
+
+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")
+
+ procSHBrowseForFolder = modshell32.NewProc("SHBrowseForFolderW")
+ procSHGetPathFromIDList = modshell32.NewProc("SHGetPathFromIDListW")
+ procDragAcceptFiles = modshell32.NewProc("DragAcceptFiles")
+ procDragQueryFile = modshell32.NewProc("DragQueryFileW")
+ procDragQueryPoint = modshell32.NewProc("DragQueryPoint")
+ procDragFinish = modshell32.NewProc("DragFinish")
+ procShellExecute = modshell32.NewProc("ShellExecuteW")
+ procExtractIcon = modshell32.NewProc("ExtractIconW")
+ procGetSpecialFolderPath = modshell32.NewProc("SHGetSpecialFolderPathW")
+ procShellNotifyIcon = modshell32.NewProc("Shell_NotifyIconW")
+ procShellNotifyIconGetRect = modshell32.NewProc("Shell_NotifyIconGetRect")
+ procSHGetKnownFolderPath = modshell32.NewProc("SHGetKnownFolderPath")
+ procSHAppBarMessage = modshell32.NewProc("SHAppBarMessage")
+)
+
+type APPBARDATA struct {
+ CbSize uint32
+ HWnd HWND
+ UCallbackMessage uint32
+ UEdge uint32
+ Rc RECT
+ LParam uintptr
+}
+
+func ShellNotifyIcon(cmd uintptr, nid *NOTIFYICONDATA) bool {
+ ret, _, _ := procShellNotifyIcon.Call(cmd, uintptr(unsafe.Pointer(nid)))
+ return ret == 1
+}
+
+func SHBrowseForFolder(bi *BROWSEINFO) uintptr {
+ ret, _, _ := procSHBrowseForFolder.Call(uintptr(unsafe.Pointer(bi)))
+
+ 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(
+ idl,
+ uintptr(unsafe.Pointer(&buf[0])))
+
+ return syscall.UTF16ToString(buf)
+}
+
+func DragAcceptFiles(hwnd HWND, accept bool) {
+ procDragAcceptFiles.Call(
+ hwnd,
+ uintptr(BoolToBOOL(accept)))
+}
+
+func DragQueryFile(hDrop HDROP, iFile uint) (fileName string, fileCount uint) {
+ ret, _, _ := procDragQueryFile.Call(
+ hDrop,
+ uintptr(iFile),
+ 0,
+ 0)
+
+ fileCount = uint(ret)
+
+ if iFile != 0xFFFFFFFF {
+ buf := make([]uint16, fileCount+1)
+
+ ret, _, _ := procDragQueryFile.Call(
+ hDrop,
+ uintptr(iFile),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(fileCount+1))
+
+ if ret == 0 {
+ panic("Invoke DragQueryFile error.")
+ }
+
+ fileName = syscall.UTF16ToString(buf)
+ }
+
+ return
+}
+
+func DragQueryPoint(hDrop HDROP) (x, y int, isClientArea bool) {
+ var pt POINT
+ ret, _, _ := procDragQueryPoint.Call(
+ uintptr(hDrop),
+ uintptr(unsafe.Pointer(&pt)))
+
+ return int(pt.X), int(pt.Y), (ret == 1)
+}
+
+func DragFinish(hDrop HDROP) {
+ procDragFinish.Call(uintptr(hDrop))
+}
+
+func ShellExecute(hwnd HWND, lpOperation, lpFile, lpParameters, lpDirectory string, nShowCmd int) error {
+ var op, param, directory uintptr
+ if len(lpOperation) != 0 {
+ op = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpOperation)))
+ }
+ if len(lpParameters) != 0 {
+ param = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpParameters)))
+ }
+ if len(lpDirectory) != 0 {
+ directory = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpDirectory)))
+ }
+
+ ret, _, _ := procShellExecute.Call(
+ uintptr(hwnd),
+ op,
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpFile))),
+ param,
+ directory,
+ uintptr(nShowCmd))
+
+ errorMsg := ""
+ if ret != 0 && ret <= 32 {
+ switch int(ret) {
+ case ERROR_FILE_NOT_FOUND:
+ errorMsg = "The specified file was not found."
+ case ERROR_PATH_NOT_FOUND:
+ errorMsg = "The specified path was not found."
+ case ERROR_BAD_FORMAT:
+ errorMsg = "The .exe file is invalid (non-Win32 .exe or error in .exe image)."
+ case SE_ERR_ACCESSDENIED:
+ errorMsg = "The operating system denied access to the specified file."
+ case SE_ERR_ASSOCINCOMPLETE:
+ errorMsg = "The file name association is incomplete or invalid."
+ case SE_ERR_DDEBUSY:
+ errorMsg = "The DDE transaction could not be completed because other DDE transactions were being processed."
+ case SE_ERR_DDEFAIL:
+ errorMsg = "The DDE transaction failed."
+ case SE_ERR_DDETIMEOUT:
+ errorMsg = "The DDE transaction could not be completed because the request timed out."
+ case SE_ERR_DLLNOTFOUND:
+ errorMsg = "The specified DLL was not found."
+ case SE_ERR_NOASSOC:
+ errorMsg = "There is no application associated with the given file name extension. This error will also be returned if you attempt to print a file that is not printable."
+ case SE_ERR_OOM:
+ errorMsg = "There was not enough memory to complete the operation."
+ case SE_ERR_SHARE:
+ errorMsg = "A sharing violation occurred."
+ default:
+ errorMsg = fmt.Sprintf("Unknown error occurred with error code %v", ret)
+ }
+ } else {
+ return nil
+ }
+
+ return errors.New(errorMsg)
+}
+
+func ExtractIcon(lpszExeFileName string, nIconIndex int) HICON {
+ ret, _, _ := procExtractIcon.Call(
+ 0,
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpszExeFileName))),
+ uintptr(nIconIndex))
+
+ return HICON(ret)
+}
+
+func SHGetSpecialFolderPath(hwndOwner HWND, lpszPath *uint16, csidl CSIDL, fCreate bool) bool {
+ ret, _, _ := procGetSpecialFolderPath.Call(
+ uintptr(hwndOwner),
+ uintptr(unsafe.Pointer(lpszPath)),
+ uintptr(csidl),
+ uintptr(BoolToBOOL(fCreate)),
+ 0,
+ 0)
+
+ return ret != 0
+}
+
+func GetSystrayBounds(hwnd HWND, uid uint32) (*RECT, error) {
+ var rect RECT
+ identifier := NOTIFYICONIDENTIFIER{
+ CbSize: uint32(unsafe.Sizeof(NOTIFYICONIDENTIFIER{})),
+ HWnd: hwnd,
+ UId: uid,
+ }
+ ret, _, _ := procShellNotifyIconGetRect.Call(
+ uintptr(unsafe.Pointer(&identifier)),
+ uintptr(unsafe.Pointer(&rect)))
+
+ if ret != S_OK {
+ return nil, syscall.GetLastError()
+ }
+
+ return &rect, nil
+}
+
+// GetTaskbarPosition returns the location of the taskbar.
+func GetTaskbarPosition() *APPBARDATA {
+ var result APPBARDATA
+ result.CbSize = uint32(unsafe.Sizeof(APPBARDATA{}))
+ ret, _, _ := procSHAppBarMessage.Call(
+ ABM_GETTASKBARPOS,
+ uintptr(unsafe.Pointer(&result)))
+ if ret == 0 {
+ return nil
+ }
+
+ return &result
+}
diff --git a/v3/pkg/w32/shlwapi.go b/v3/pkg/w32/shlwapi.go
new file mode 100644
index 000000000..89d17ce6f
--- /dev/null
+++ b/v3/pkg/w32/shlwapi.go
@@ -0,0 +1,26 @@
+//go:build windows
+
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modshlwapi = syscall.NewLazyDLL("shlwapi.dll")
+
+ procSHCreateMemStream = modshlwapi.NewProc("SHCreateMemStream")
+)
+
+func SHCreateMemStream(data []byte) (uintptr, error) {
+ ret, _, err := procSHCreateMemStream.Call(
+ uintptr(unsafe.Pointer(&data[0])),
+ uintptr(len(data)),
+ )
+ if ret == 0 {
+ return 0, err
+ }
+
+ return ret, nil
+}
diff --git a/v3/pkg/w32/taskbar.go b/v3/pkg/w32/taskbar.go
new file mode 100644
index 000000000..7f2a697d6
--- /dev/null
+++ b/v3/pkg/w32/taskbar.go
@@ -0,0 +1,95 @@
+//go:build windows
+
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ CLSID_TaskbarList = syscall.GUID{Data1: 0x56FDF344, Data2: 0xFD6D, Data3: 0x11D0, Data4: [8]byte{0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}}
+ IID_ITaskbarList3 = syscall.GUID{Data1: 0xEA1AFB91, Data2: 0x9E28, Data3: 0x4B86, Data4: [8]byte{0x90, 0xE9, 0x9E, 0x9F, 0x8A, 0x5E, 0xEF, 0xAF}}
+)
+
+// ITaskbarList3 interface for Windows taskbar functionality
+type ITaskbarList3 struct {
+ lpVtbl *taskbarList3Vtbl
+}
+
+type taskbarList3Vtbl struct {
+ QueryInterface uintptr
+ AddRef uintptr
+ Release uintptr
+ HrInit uintptr
+ AddTab uintptr
+ DeleteTab uintptr
+ ActivateTab uintptr
+ SetActiveAlt uintptr
+ MarkFullscreenWindow uintptr
+ SetProgressValue uintptr
+ SetProgressState uintptr
+ RegisterTab uintptr
+ UnregisterTab uintptr
+ SetTabOrder uintptr
+ SetTabActive uintptr
+ ThumbBarAddButtons uintptr
+ ThumbBarUpdateButtons uintptr
+ ThumbBarSetImageList uintptr
+ SetOverlayIcon uintptr
+ SetThumbnailTooltip uintptr
+ SetThumbnailClip uintptr
+}
+
+// NewTaskbarList3 creates a new instance of ITaskbarList3
+func NewTaskbarList3() (*ITaskbarList3, error) {
+ const COINIT_APARTMENTTHREADED = 0x2
+
+ if hrInit := CoInitializeEx(COINIT_APARTMENTTHREADED); hrInit != 0 && hrInit != 0x1 {
+ return nil, syscall.Errno(hrInit)
+ }
+
+ var taskbar *ITaskbarList3
+ hr := CoCreateInstance(
+ &CLSID_TaskbarList,
+ CLSCTX_INPROC_SERVER,
+ &IID_ITaskbarList3,
+ uintptr(unsafe.Pointer(&taskbar)),
+ )
+
+ if hr != 0 {
+ CoUninitialize()
+ return nil, syscall.Errno(hr)
+ }
+
+ if r, _, _ := syscall.SyscallN(taskbar.lpVtbl.HrInit, uintptr(unsafe.Pointer(taskbar))); r != 0 {
+ syscall.SyscallN(taskbar.lpVtbl.Release, uintptr(unsafe.Pointer(taskbar)))
+ CoUninitialize()
+ return nil, syscall.Errno(r)
+ }
+
+ return taskbar, nil
+}
+
+// SetOverlayIcon sets an overlay icon on the taskbar
+func (t *ITaskbarList3) SetOverlayIcon(hwnd HWND, hIcon HICON, description *uint16) error {
+ ret, _, _ := syscall.SyscallN(
+ t.lpVtbl.SetOverlayIcon,
+ uintptr(unsafe.Pointer(t)),
+ uintptr(hwnd),
+ uintptr(hIcon),
+ uintptr(unsafe.Pointer(description)),
+ )
+ if ret != 0 {
+ return syscall.Errno(ret)
+ }
+ return nil
+}
+
+// Release releases the ITaskbarList3 interface
+func (t *ITaskbarList3) Release() {
+ if t != nil {
+ syscall.SyscallN(t.lpVtbl.Release, uintptr(unsafe.Pointer(t)))
+ CoUninitialize()
+ }
+}
diff --git a/v3/pkg/w32/theme.go b/v3/pkg/w32/theme.go
new file mode 100644
index 000000000..0e8a8ef17
--- /dev/null
+++ b/v3/pkg/w32/theme.go
@@ -0,0 +1,345 @@
+//go:build windows
+
+package w32
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+ "golang.org/x/sys/windows/registry"
+)
+
+type DWMWINDOWATTRIBUTE int32
+
+const DwmwaUseImmersiveDarkModeBefore20h1 DWMWINDOWATTRIBUTE = 19
+const DwmwaUseImmersiveDarkMode DWMWINDOWATTRIBUTE = 20
+const DwmwaBorderColor DWMWINDOWATTRIBUTE = 34
+const DwmwaCaptionColor DWMWINDOWATTRIBUTE = 35
+const DwmwaTextColor DWMWINDOWATTRIBUTE = 36
+const DwmwaSystemBackdropType DWMWINDOWATTRIBUTE = 38
+
+const SPI_GETHIGHCONTRAST = 0x0042
+const HCF_HIGHCONTRASTON = 0x00000001
+
+type WINDOWCOMPOSITIONATTRIB DWORD
+
+type HTHEME HANDLE
+
+const (
+ WCA_UNDEFINED WINDOWCOMPOSITIONATTRIB = 0
+ WCA_NCRENDERING_ENABLED WINDOWCOMPOSITIONATTRIB = 1
+ WCA_NCRENDERING_POLICY WINDOWCOMPOSITIONATTRIB = 2
+ WCA_TRANSITIONS_FORCEDISABLED WINDOWCOMPOSITIONATTRIB = 3
+ WCA_ALLOW_NCPAINT WINDOWCOMPOSITIONATTRIB = 4
+ WCA_CAPTION_BUTTON_BOUNDS WINDOWCOMPOSITIONATTRIB = 5
+ WCA_NONCLIENT_RTL_LAYOUT WINDOWCOMPOSITIONATTRIB = 6
+ WCA_FORCE_ICONIC_REPRESENTATION WINDOWCOMPOSITIONATTRIB = 7
+ WCA_EXTENDED_FRAME_BOUNDS WINDOWCOMPOSITIONATTRIB = 8
+ WCA_HAS_ICONIC_BITMAP WINDOWCOMPOSITIONATTRIB = 9
+ WCA_THEME_ATTRIBUTES WINDOWCOMPOSITIONATTRIB = 10
+ WCA_NCRENDERING_EXILED WINDOWCOMPOSITIONATTRIB = 11
+ WCA_NCADORNMENTINFO WINDOWCOMPOSITIONATTRIB = 12
+ WCA_EXCLUDED_FROM_LIVEPREVIEW WINDOWCOMPOSITIONATTRIB = 13
+ WCA_VIDEO_OVERLAY_ACTIVE WINDOWCOMPOSITIONATTRIB = 14
+ WCA_FORCE_ACTIVEWINDOW_APPEARANCE WINDOWCOMPOSITIONATTRIB = 15
+ WCA_DISALLOW_PEEK WINDOWCOMPOSITIONATTRIB = 16
+ WCA_CLOAK WINDOWCOMPOSITIONATTRIB = 17
+ WCA_CLOAKED WINDOWCOMPOSITIONATTRIB = 18
+ WCA_ACCENT_POLICY WINDOWCOMPOSITIONATTRIB = 19
+ WCA_FREEZE_REPRESENTATION WINDOWCOMPOSITIONATTRIB = 20
+ WCA_EVER_UNCLOAKED WINDOWCOMPOSITIONATTRIB = 21
+ WCA_VISUAL_OWNER WINDOWCOMPOSITIONATTRIB = 22
+ WCA_HOLOGRAPHIC WINDOWCOMPOSITIONATTRIB = 23
+ WCA_EXCLUDED_FROM_DDA WINDOWCOMPOSITIONATTRIB = 24
+ WCA_PASSIVEUPDATEMODE WINDOWCOMPOSITIONATTRIB = 25
+ WCA_USEDARKMODECOLORS WINDOWCOMPOSITIONATTRIB = 26
+ WCA_CORNER_STYLE WINDOWCOMPOSITIONATTRIB = 27
+ WCA_PART_COLOR WINDOWCOMPOSITIONATTRIB = 28
+ WCA_DISABLE_MOVESIZE_FEEDBACK WINDOWCOMPOSITIONATTRIB = 29
+ WCA_LAST WINDOWCOMPOSITIONATTRIB = 30
+)
+
+type WINDOWCOMPOSITIONATTRIBDATA struct {
+ Attrib WINDOWCOMPOSITIONATTRIB
+ PvData unsafe.Pointer
+ CbData uintptr
+}
+
+var (
+ uxtheme = syscall.NewLazyDLL("uxtheme.dll")
+ procSetWindowTheme = uxtheme.NewProc("SetWindowTheme")
+ procOpenThemeData = uxtheme.NewProc("OpenThemeData")
+ procCloseThemeData = uxtheme.NewProc("CloseThemeData")
+ procDrawThemeBackground = uxtheme.NewProc("DrawThemeBackground")
+ procAllowDarkModeForApplication = uxtheme.NewProc("AllowDarkModeForApp")
+ procDrawThemeTextEx = uxtheme.NewProc("DrawThemeTextEx")
+)
+
+type PreferredAppMode = int32
+
+const (
+ PreferredAppModeDefault PreferredAppMode = iota
+ PreferredAppModeAllowDark
+ PreferredAppModeForceDark
+ PreferredAppModeForceLight
+ PreferredAppModeMax
+)
+
+var (
+ AllowDarkModeForWindow func(hwnd HWND, allow bool) uintptr
+ SetPreferredAppMode func(mode int32) uintptr
+ FlushMenuThemes func()
+ RefreshImmersiveColorPolicyState func()
+ ShouldAppsUseDarkMode func() bool
+)
+
+func init() {
+ if IsWindowsVersionAtLeast(10, 0, 18334) {
+ // AllowDarkModeForWindow is only available on Windows 10+
+ localUXTheme, err := windows.LoadLibrary("uxtheme.dll")
+ if err == nil {
+ procAllowDarkModeForWindow, err := windows.GetProcAddressByOrdinal(localUXTheme, uintptr(133))
+ if err == nil {
+ AllowDarkModeForWindow = func(hwnd HWND, allow bool) uintptr {
+ var allowInt int32
+ if allow {
+ allowInt = 1
+ }
+ ret, _, _ := syscall.SyscallN(procAllowDarkModeForWindow, uintptr(allowInt))
+ return ret
+ }
+ }
+
+ // Add ShouldAppsUseDarkMode
+ procShouldAppsUseDarkMode, err := windows.GetProcAddressByOrdinal(localUXTheme, uintptr(132))
+ if err == nil {
+ ShouldAppsUseDarkMode = func() bool {
+ ret, _, _ := syscall.SyscallN(procShouldAppsUseDarkMode)
+ return ret != 0
+ }
+ }
+
+ // SetPreferredAppMode is only available on Windows 10+
+ procSetPreferredAppMode, err := windows.GetProcAddressByOrdinal(localUXTheme, uintptr(135))
+ if err == nil {
+ SetPreferredAppMode = func(mode int32) uintptr {
+ ret, _, _ := syscall.SyscallN(procSetPreferredAppMode, uintptr(mode))
+ return ret
+ }
+ }
+
+ // Add FlushMenuThemes
+ procFlushMenuThemesAddr, err := windows.GetProcAddressByOrdinal(localUXTheme, uintptr(136))
+ if err == nil {
+ FlushMenuThemes = func() {
+ syscall.SyscallN(procFlushMenuThemesAddr)
+ }
+ }
+
+ // Add RefreshImmersiveColorPolicyState
+ procRefreshImmersiveColorPolicyStateAddr, err := windows.GetProcAddressByOrdinal(localUXTheme, uintptr(104))
+ if err == nil {
+ RefreshImmersiveColorPolicyState = func() {
+ syscall.SyscallN(procRefreshImmersiveColorPolicyStateAddr)
+ }
+ }
+
+ // Initialize dark mode
+ if SetPreferredAppMode != nil {
+ SetPreferredAppMode(PreferredAppModeAllowDark)
+ if RefreshImmersiveColorPolicyState != nil {
+ RefreshImmersiveColorPolicyState()
+ }
+ }
+
+ windows.FreeLibrary(localUXTheme)
+ }
+ }
+}
+
+func dwmSetWindowAttribute(hwnd uintptr, dwAttribute DWMWINDOWATTRIBUTE, pvAttribute unsafe.Pointer, cbAttribute uintptr) {
+ ret, _, err := procDwmSetWindowAttribute.Call(
+ hwnd,
+ uintptr(dwAttribute),
+ uintptr(pvAttribute),
+ cbAttribute)
+ if ret != 0 {
+ _ = err
+ // println(err.Error())
+ }
+}
+
+func SupportsThemes() bool {
+ // We can't support Windows versions before 17763
+ return IsWindowsVersionAtLeast(10, 0, 17763)
+}
+
+func SupportsCustomThemes() bool {
+ return IsWindowsVersionAtLeast(10, 0, 17763)
+}
+
+func SupportsBackdropTypes() bool {
+ return IsWindowsVersionAtLeast(10, 0, 22621)
+}
+
+func SupportsImmersiveDarkMode() bool {
+ return IsWindowsVersionAtLeast(10, 0, 18985)
+}
+
+func SetMenuTheme(hwnd uintptr, useDarkMode bool) {
+ if !SupportsThemes() {
+ return
+ }
+
+ // Check if dark mode is supported and enabled
+ if useDarkMode && ShouldAppsUseDarkMode != nil && !ShouldAppsUseDarkMode() {
+ useDarkMode = false
+ }
+
+ // Set the window theme
+ themeName := "Explorer"
+ if useDarkMode {
+ themeName = "DarkMode_Explorer"
+ }
+ procSetWindowTheme.Call(HWND(hwnd), uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(themeName))), 0)
+
+ // Update the theme state
+ if RefreshImmersiveColorPolicyState != nil {
+ RefreshImmersiveColorPolicyState()
+ }
+
+ // Flush menu themes to force a refresh
+ if FlushMenuThemes != nil {
+ FlushMenuThemes()
+ }
+
+ // Set dark mode for the window
+ if AllowDarkModeForWindow != nil {
+ AllowDarkModeForWindow(HWND(hwnd), useDarkMode)
+ }
+
+ // Force a redraw
+ InvalidateRect(HWND(hwnd), nil, true)
+}
+
+func SetTheme(hwnd uintptr, useDarkMode bool) {
+ if SupportsThemes() {
+ attr := DwmwaUseImmersiveDarkModeBefore20h1
+ if SupportsImmersiveDarkMode() {
+ attr = DwmwaUseImmersiveDarkMode
+ }
+ var winDark int32
+ if useDarkMode {
+ winDark = 1
+ }
+ dwmSetWindowAttribute(hwnd, attr, unsafe.Pointer(&winDark), unsafe.Sizeof(winDark))
+ SetMenuTheme(hwnd, useDarkMode)
+ }
+}
+
+func EnableTranslucency(hwnd uintptr, backdrop uint32) {
+ dwmSetWindowAttribute(hwnd, DwmwaSystemBackdropType, unsafe.Pointer(&backdrop), unsafe.Sizeof(backdrop))
+}
+
+func SetTitleBarColour(hwnd uintptr, titleBarColour uint32) {
+ // Debug: Print the color value being set
+ // fmt.Printf("Setting titlebar color to: 0x%08X (RGB: %d, %d, %d)\n", titleBarColour, titleBarColour&0xFF, (titleBarColour>>8)&0xFF, (titleBarColour>>16)&0xFF)
+ dwmSetWindowAttribute(hwnd, DwmwaCaptionColor, unsafe.Pointer(&titleBarColour), unsafe.Sizeof(titleBarColour))
+}
+
+func SetTitleTextColour(hwnd uintptr, titleTextColour uint32) {
+ dwmSetWindowAttribute(hwnd, DwmwaTextColor, unsafe.Pointer(&titleTextColour), unsafe.Sizeof(titleTextColour))
+}
+
+func SetBorderColour(hwnd uintptr, titleBorderColour uint32) {
+ dwmSetWindowAttribute(hwnd, DwmwaBorderColor, unsafe.Pointer(&titleBorderColour), unsafe.Sizeof(titleBorderColour))
+}
+
+func IsCurrentlyDarkMode() bool {
+ key, err := registry.OpenKey(registry.CURRENT_USER, `SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize`, registry.QUERY_VALUE)
+ if err != nil {
+ return false
+ }
+ defer key.Close()
+
+ AppsUseLightTheme, _, err := key.GetIntegerValue("AppsUseLightTheme")
+ if err != nil {
+ return false
+ }
+ return AppsUseLightTheme == 0
+}
+
+type highContrast struct {
+ CbSize uint32
+ DwFlags uint32
+ LpszDefaultScheme *int16
+}
+
+func IsCurrentlyHighContrastMode() bool {
+ var result highContrast
+ result.CbSize = uint32(unsafe.Sizeof(result))
+ res, _, err := procSystemParametersInfo.Call(SPI_GETHIGHCONTRAST, uintptr(result.CbSize), uintptr(unsafe.Pointer(&result)), 0)
+ if res == 0 {
+ _ = err
+ return false
+ }
+ r := result.DwFlags&HCF_HIGHCONTRASTON == HCF_HIGHCONTRASTON
+ return r
+}
+
+func GetAccentColor() (string, error) {
+ key, err := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\DWM`, registry.QUERY_VALUE)
+ if err != nil {
+ return "", err
+ }
+ defer key.Close()
+
+ accentColor, _, err := key.GetIntegerValue("AccentColor")
+ if err != nil {
+ return "", err
+ }
+
+ // Extract RGB components from ABGR format (Alpha, Blue, Green, Red)
+ red := uint8(accentColor & 0xFF)
+ green := uint8((accentColor >> 8) & 0xFF)
+ blue := uint8((accentColor >> 16) & 0xFF)
+
+ return fmt.Sprintf("rgb(%d,%d,%d)", red, green, blue), nil
+}
+
+// OpenThemeData opens theme data for a window and its class
+func OpenThemeData(hwnd HWND, pszClassList string) HTHEME {
+ ret, _, _ := procOpenThemeData.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(pszClassList))))
+ return HTHEME(ret)
+}
+
+// CloseThemeData closes theme data handle
+func CloseThemeData(hTheme HTHEME) error {
+ ret, _, err := procCloseThemeData.Call(uintptr(hTheme))
+ if ret != 0 {
+ return err
+ }
+ return nil
+}
+
+// DrawThemeTextEx draws theme text with extended options
+func DrawThemeTextEx(hTheme HTHEME, hdc HDC, iPartId int32, iStateId int32, pszText []uint16, cchText int32, dwTextFlags uint32, pRect *RECT, pOptions *DTTOPTS) error {
+ ret, _, err := procDrawThemeTextEx.Call(
+ uintptr(hTheme),
+ uintptr(hdc),
+ uintptr(iPartId),
+ uintptr(iStateId),
+ uintptr(unsafe.Pointer(&pszText[0])),
+ uintptr(cchText),
+ uintptr(dwTextFlags),
+ uintptr(unsafe.Pointer(pRect)),
+ uintptr(unsafe.Pointer(pOptions)))
+ if ret != 0 {
+ return err
+ }
+ return nil
+}
diff --git a/v3/pkg/w32/timer.go b/v3/pkg/w32/timer.go
new file mode 100644
index 000000000..c95253e53
--- /dev/null
+++ b/v3/pkg/w32/timer.go
@@ -0,0 +1,19 @@
+//go:build windows
+
+package w32
+
+func SetTimer(hwnd HWND, nIDEvent uintptr, uElapse uint32, lpTimerFunc uintptr) uintptr {
+ ret, _, _ := procSetTimer.Call(
+ uintptr(hwnd),
+ nIDEvent,
+ uintptr(uElapse),
+ lpTimerFunc)
+ return ret
+}
+
+func KillTimer(hwnd HWND, nIDEvent uintptr) bool {
+ ret, _, _ := procKillTimer.Call(
+ uintptr(hwnd),
+ nIDEvent)
+ return ret != 0
+}
diff --git a/v3/pkg/w32/toolbar.go b/v3/pkg/w32/toolbar.go
new file mode 100644
index 000000000..ac9261fc4
--- /dev/null
+++ b/v3/pkg/w32/toolbar.go
@@ -0,0 +1,216 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+
+package w32
+
+// ToolBar messages
+const (
+ TB_ENABLEBUTTON = WM_USER + 1
+ TB_CHECKBUTTON = WM_USER + 2
+ TB_PRESSBUTTON = WM_USER + 3
+ TB_HIDEBUTTON = WM_USER + 4
+ TB_INDETERMINATE = WM_USER + 5
+ TB_MARKBUTTON = WM_USER + 6
+ TB_ISBUTTONENABLED = WM_USER + 9
+ TB_ISBUTTONCHECKED = WM_USER + 10
+ TB_ISBUTTONPRESSED = WM_USER + 11
+ TB_ISBUTTONHIDDEN = WM_USER + 12
+ TB_ISBUTTONINDETERMINATE = WM_USER + 13
+ TB_ISBUTTONHIGHLIGHTED = WM_USER + 14
+ TB_SETSTATE = WM_USER + 17
+ TB_GETSTATE = WM_USER + 18
+ TB_ADDBITMAP = WM_USER + 19
+ TB_DELETEBUTTON = WM_USER + 22
+ TB_GETBUTTON = WM_USER + 23
+ TB_BUTTONCOUNT = WM_USER + 24
+ TB_COMMANDTOINDEX = WM_USER + 25
+ TB_SAVERESTORE = WM_USER + 76
+ TB_CUSTOMIZE = WM_USER + 27
+ TB_ADDSTRING = WM_USER + 77
+ TB_GETITEMRECT = WM_USER + 29
+ TB_BUTTONSTRUCTSIZE = WM_USER + 30
+ TB_SETBUTTONSIZE = WM_USER + 31
+ TB_SETBITMAPSIZE = WM_USER + 32
+ TB_AUTOSIZE = WM_USER + 33
+ TB_GETTOOLTIPS = WM_USER + 35
+ TB_SETTOOLTIPS = WM_USER + 36
+ TB_SETPARENT = WM_USER + 37
+ TB_SETROWS = WM_USER + 39
+ TB_GETROWS = WM_USER + 40
+ TB_GETBITMAPFLAGS = WM_USER + 41
+ TB_SETCMDID = WM_USER + 42
+ TB_CHANGEBITMAP = WM_USER + 43
+ TB_GETBITMAP = WM_USER + 44
+ TB_GETBUTTONTEXT = WM_USER + 75
+ TB_REPLACEBITMAP = WM_USER + 46
+ TB_GETBUTTONSIZE = WM_USER + 58
+ TB_SETBUTTONWIDTH = WM_USER + 59
+ TB_SETINDENT = WM_USER + 47
+ TB_SETIMAGELIST = WM_USER + 48
+ TB_GETIMAGELIST = WM_USER + 49
+ TB_LOADIMAGES = WM_USER + 50
+ TB_GETRECT = WM_USER + 51
+ TB_SETHOTIMAGELIST = WM_USER + 52
+ TB_GETHOTIMAGELIST = WM_USER + 53
+ TB_SETDISABLEDIMAGELIST = WM_USER + 54
+ TB_GETDISABLEDIMAGELIST = WM_USER + 55
+ TB_SETSTYLE = WM_USER + 56
+ TB_GETSTYLE = WM_USER + 57
+ TB_SETMAXTEXTROWS = WM_USER + 60
+ TB_GETTEXTROWS = WM_USER + 61
+ TB_GETOBJECT = WM_USER + 62
+ TB_GETBUTTONINFO = WM_USER + 63
+ TB_SETBUTTONINFO = WM_USER + 64
+ TB_INSERTBUTTON = WM_USER + 67
+ TB_ADDBUTTONS = WM_USER + 68
+ TB_HITTEST = WM_USER + 69
+ TB_SETDRAWTEXTFLAGS = WM_USER + 70
+ TB_GETHOTITEM = WM_USER + 71
+ TB_SETHOTITEM = WM_USER + 72
+ TB_SETANCHORHIGHLIGHT = WM_USER + 73
+ TB_GETANCHORHIGHLIGHT = WM_USER + 74
+ TB_GETINSERTMARK = WM_USER + 79
+ TB_SETINSERTMARK = WM_USER + 80
+ TB_INSERTMARKHITTEST = WM_USER + 81
+ TB_MOVEBUTTON = WM_USER + 82
+ TB_GETMAXSIZE = WM_USER + 83
+ TB_SETEXTENDEDSTYLE = WM_USER + 84
+ TB_GETEXTENDEDSTYLE = WM_USER + 85
+ TB_GETPADDING = WM_USER + 86
+ TB_SETPADDING = WM_USER + 87
+ TB_SETINSERTMARKCOLOR = WM_USER + 88
+ TB_GETINSERTMARKCOLOR = WM_USER + 89
+ TB_MAPACCELERATOR = WM_USER + 90
+ TB_GETSTRING = WM_USER + 91
+ TB_SETCOLORSCHEME = CCM_SETCOLORSCHEME
+ TB_GETCOLORSCHEME = CCM_GETCOLORSCHEME
+ TB_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT
+ TB_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT
+)
+
+// ToolBar notifications
+const (
+ TBN_FIRST = -700
+ TBN_DROPDOWN = TBN_FIRST - 10
+)
+
+// TBN_DROPDOWN return codes
+const (
+ TBDDRET_DEFAULT = 0
+ TBDDRET_NODEFAULT = 1
+ TBDDRET_TREATPRESSED = 2
+)
+
+// ToolBar state constants
+const (
+ TBSTATE_CHECKED = 1
+ TBSTATE_PRESSED = 2
+ TBSTATE_ENABLED = 4
+ TBSTATE_HIDDEN = 8
+ TBSTATE_INDETERMINATE = 16
+ TBSTATE_WRAP = 32
+ TBSTATE_ELLIPSES = 0x40
+ TBSTATE_MARKED = 0x0080
+)
+
+// ToolBar style constants
+const (
+ TBSTYLE_BUTTON = 0
+ TBSTYLE_SEP = 1
+ TBSTYLE_CHECK = 2
+ TBSTYLE_GROUP = 4
+ TBSTYLE_CHECKGROUP = TBSTYLE_GROUP | TBSTYLE_CHECK
+ TBSTYLE_DROPDOWN = 8
+ TBSTYLE_AUTOSIZE = 16
+ TBSTYLE_NOPREFIX = 32
+ TBSTYLE_TOOLTIPS = 256
+ TBSTYLE_WRAPABLE = 512
+ TBSTYLE_ALTDRAG = 1024
+ TBSTYLE_FLAT = 2048
+ TBSTYLE_LIST = 4096
+ TBSTYLE_CUSTOMERASE = 8192
+ TBSTYLE_REGISTERDROP = 0x4000
+ TBSTYLE_TRANSPARENT = 0x8000
+)
+
+// ToolBar extended style constants
+const (
+ TBSTYLE_EX_DRAWDDARROWS = 0x00000001
+ TBSTYLE_EX_MIXEDBUTTONS = 8
+ TBSTYLE_EX_HIDECLIPPEDBUTTONS = 16
+ TBSTYLE_EX_DOUBLEBUFFER = 0x80
+)
+
+// ToolBar button style constants
+const (
+ BTNS_BUTTON = TBSTYLE_BUTTON
+ BTNS_SEP = TBSTYLE_SEP
+ BTNS_CHECK = TBSTYLE_CHECK
+ BTNS_GROUP = TBSTYLE_GROUP
+ BTNS_CHECKGROUP = TBSTYLE_CHECKGROUP
+ BTNS_DROPDOWN = TBSTYLE_DROPDOWN
+ BTNS_AUTOSIZE = TBSTYLE_AUTOSIZE
+ BTNS_NOPREFIX = TBSTYLE_NOPREFIX
+ BTNS_WHOLEDROPDOWN = 0x0080
+ BTNS_SHOWTEXT = 0x0040
+)
+
+// TBBUTTONINFO mask flags
+const (
+ TBIF_IMAGE = 0x00000001
+ TBIF_TEXT = 0x00000002
+ TBIF_STATE = 0x00000004
+ TBIF_STYLE = 0x00000008
+ TBIF_LPARAM = 0x00000010
+ TBIF_COMMAND = 0x00000020
+ TBIF_SIZE = 0x00000040
+ TBIF_BYINDEX = 0x80000000
+)
+
+type NMMOUSE struct {
+ Hdr NMHDR
+ DwItemSpec uintptr
+ DwItemData uintptr
+ Pt POINT
+ DwHitInfo uintptr
+}
+
+type NMTOOLBAR struct {
+ Hdr NMHDR
+ IItem int32
+ TbButton TBBUTTON
+ CchText int32
+ PszText *uint16
+ RcButton RECT
+}
+
+type TBBUTTON struct {
+ IBitmap int32
+ IdCommand int32
+ FsState byte
+ FsStyle byte
+ //#ifdef _WIN64
+ // BYTE bReserved[6] // padding for alignment
+ //#elif defined(_WIN32)
+ BReserved [2]byte // padding for alignment
+ //#endif
+ DwData uintptr
+ IString uintptr
+}
+
+type TBBUTTONINFO struct {
+ CbSize uint32
+ DwMask uint32
+ IdCommand int32
+ IImage int32
+ FsState byte
+ FsStyle byte
+ Cx uint16
+ LParam uintptr
+ PszText uintptr
+ CchText int32
+}
diff --git a/v3/pkg/w32/typedef.go b/v3/pkg/w32/typedef.go
new file mode 100644
index 000000000..cf1c13c09
--- /dev/null
+++ b/v3/pkg/w32/typedef.go
@@ -0,0 +1,1110 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+
+package w32
+
+import (
+ "fmt"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+// From MSDN: Windows Data Types
+// http://msdn.microsoft.com/en-us/library/s3f49ktz.aspx
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751.aspx
+// ATOM WORD
+// BOOL int32
+// BOOLEAN byte
+// BYTE byte
+// CCHAR int8
+// CHAR int8
+// COLORREF DWORD
+// DWORD uint32
+// DWORDLONG ULONGLONG
+// DWORD_PTR ULONG_PTR
+// DWORD32 uint32
+// DWORD64 uint64
+// FLOAT float32
+// HACCEL HANDLE
+// HALF_PTR struct{} // ???
+// HANDLE PVOID
+// HBITMAP HANDLE
+// HBRUSH HANDLE
+// HCOLORSPACE HANDLE
+// HCONV HANDLE
+// HCONVLIST HANDLE
+// HCURSOR HANDLE
+// HDC HANDLE
+// HDDEDATA HANDLE
+// HDESK HANDLE
+// HDROP HANDLE
+// HDWP HANDLE
+// HENHMETAFILE HANDLE
+// HFILE HANDLE
+// HFONT HANDLE
+// HGDIOBJ HANDLE
+// HGLOBAL HANDLE
+// HHOOK HANDLE
+// HICON HANDLE
+// HINSTANCE HANDLE
+// HKEY HANDLE
+// HKL HANDLE
+// HLOCAL HANDLE
+// HMENU HANDLE
+// HMETAFILE HANDLE
+// HMODULE HANDLE
+// HPALETTE HANDLE
+// HPEN HANDLE
+// HRESULT int32
+// HRGN HANDLE
+// HSZ HANDLE
+// HWINSTA HANDLE
+// HWND HANDLE
+// INT int32
+// INT_PTR uintptr
+// INT8 int8
+// INT16 int16
+// INT32 int32
+// INT64 int64
+// LANGID WORD
+// LCID DWORD
+// LCTYPE DWORD
+// LGRPID DWORD
+// LONG int32
+// LONGLONG int64
+// LONG_PTR uintptr
+// LONG32 int32
+// LONG64 int64
+// LPARAM LONG_PTR
+// LPBOOL *BOOL
+// LPBYTE *BYTE
+// LPCOLORREF *COLORREF
+// LPCSTR *int8
+// LPCTSTR LPCWSTR
+// LPCVOID unsafe.Pointer
+// LPCWSTR *WCHAR
+// LPDWORD *DWORD
+// LPHANDLE *HANDLE
+// LPINT *INT
+// LPLONG *LONG
+// LPSTR *CHAR
+// LPTSTR LPWSTR
+// LPVOID unsafe.Pointer
+// LPWORD *WORD
+// LPWSTR *WCHAR
+// LRESULT LONG_PTR
+// PBOOL *BOOL
+// PBOOLEAN *BOOLEAN
+// PBYTE *BYTE
+// PCHAR *CHAR
+// PCSTR *CHAR
+// PCTSTR PCWSTR
+// PCWSTR *WCHAR
+// PDWORD *DWORD
+// PDWORDLONG *DWORDLONG
+// PDWORD_PTR *DWORD_PTR
+// PDWORD32 *DWORD32
+// PDWORD64 *DWORD64
+// PFLOAT *FLOAT
+// PHALF_PTR *HALF_PTR
+// PHANDLE *HANDLE
+// PHKEY *HKEY
+// PINT_PTR *INT_PTR
+// PINT8 *INT8
+// PINT16 *INT16
+// PINT32 *INT32
+// PINT64 *INT64
+// PLCID *LCID
+// PLONG *LONG
+// PLONGLONG *LONGLONG
+// PLONG_PTR *LONG_PTR
+// PLONG32 *LONG32
+// PLONG64 *LONG64
+// POINTER_32 struct{} // ???
+// POINTER_64 struct{} // ???
+// POINTER_SIGNED uintptr
+// POINTER_UNSIGNED uintptr
+// PSHORT *SHORT
+// PSIZE_T *SIZE_T
+// PSSIZE_T *SSIZE_T
+// PSTR *CHAR
+// PTBYTE *TBYTE
+// PTCHAR *TCHAR
+// PTSTR PWSTR
+// PUCHAR *UCHAR
+// PUHALF_PTR *UHALF_PTR
+// PUINT *UINT
+// PUINT_PTR *UINT_PTR
+// PUINT8 *UINT8
+// PUINT16 *UINT16
+// PUINT32 *UINT32
+// PUINT64 *UINT64
+// PULONG *ULONG
+// PULONGLONG *ULONGLONG
+// PULONG_PTR *ULONG_PTR
+// PULONG32 *ULONG32
+// PULONG64 *ULONG64
+// PUSHORT *USHORT
+// PVOID unsafe.Pointer
+// PWCHAR *WCHAR
+// PWORD *WORD
+// PWSTR *WCHAR
+// QWORD uint64
+// SC_HANDLE HANDLE
+// SC_LOCK LPVOID
+// SERVICE_STATUS_HANDLE HANDLE
+// SHORT int16
+// SIZE_T ULONG_PTR
+// SSIZE_T LONG_PTR
+// TBYTE WCHAR
+// TCHAR WCHAR
+// UCHAR uint8
+// UHALF_PTR struct{} // ???
+// UINT uint32
+// UINT_PTR uintptr
+// UINT8 uint8
+// UINT16 uint16
+// UINT32 uint32
+// UINT64 uint64
+// ULONG uint32
+// ULONGLONG uint64
+// ULONG_PTR uintptr
+// ULONG32 uint32
+// ULONG64 uint64
+// USHORT uint16
+// USN LONGLONG
+// WCHAR uint16
+// WORD uint16
+// WPARAM UINT_PTR
+type (
+ ATOM = uint16
+ BOOL = int32
+ COLORREF = uint32
+ DWM_FRAME_COUNT = uint64
+ WORD = uint16
+ DWORD = uint32
+ HACCEL = HANDLE
+ HANDLE = uintptr
+ HBITMAP = HANDLE
+ HBRUSH = HANDLE
+ HCURSOR = HANDLE
+ HDC = HANDLE
+ HDROP = HANDLE
+ HDWP = HANDLE
+ HENHMETAFILE = HANDLE
+ HFONT = HANDLE
+ HGDIOBJ = HANDLE
+ HGLOBAL = HANDLE
+ HGLRC = HANDLE
+ HHOOK = HANDLE
+ HICON = HANDLE
+ HIMAGELIST = HANDLE
+ HINSTANCE = HANDLE
+ HKEY = HANDLE
+ HKL = HANDLE
+ HMENU = HANDLE
+ HMODULE = HANDLE
+ HMONITOR = HANDLE
+ HPEN = HANDLE
+ HRESULT = int32
+ HRGN = HANDLE
+ HRSRC = HANDLE
+ HTHUMBNAIL = HANDLE
+ HWND = HANDLE
+ LPARAM = uintptr
+ LPCVOID = unsafe.Pointer
+ LRESULT = uintptr
+ PVOID = unsafe.Pointer
+ QPC_TIME = uint64
+ ULONG_PTR = uintptr
+ SIZE_T = ULONG_PTR
+ WPARAM = uintptr
+ UINT = uint
+)
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162805.aspx
+type POINT struct {
+ X, Y int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162897.aspx
+type RECT struct {
+ Left, Top, Right, Bottom int32
+}
+
+func (r *RECT) String() string {
+ return fmt.Sprintf("RECT (%p): Left: %d, Top: %d, Right: %d, Bottom: %d", r, r.Left, r.Top, r.Right, r.Bottom)
+}
+
+func RectToPoints(rect *RECT) []POINT {
+ return []POINT{
+ {X: rect.Left, Y: rect.Top}, // Top-left
+ {X: rect.Right, Y: rect.Bottom}, // Bottom-right
+ }
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms633577.aspx
+type WNDCLASSEX struct {
+ Size uint32
+ Style uint32
+ WndProc uintptr
+ ClsExtra int32
+ WndExtra int32
+ Instance HINSTANCE
+ Icon HICON
+ Cursor HCURSOR
+ Background HBRUSH
+ MenuName *uint16
+ ClassName *uint16
+ IconSm HICON
+}
+
+type TPMPARAMS struct {
+ CbSize uint32
+ RcExclude RECT
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644958.aspx
+type MSG struct {
+ Hwnd HWND
+ Message uint32
+ WParam uintptr
+ LParam uintptr
+ Time uint32
+ Pt POINT
+}
+
+// https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-minmaxinfo
+type MINMAXINFO struct {
+ PtReserved POINT
+ PtMaxSize POINT
+ PtMaxPosition POINT
+ PtMinTrackSize POINT
+ PtMaxTrackSize POINT
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145037.aspx
+type LOGFONT struct {
+ Height int32
+ Width int32
+ Escapement int32
+ Orientation int32
+ Weight int32
+ Italic byte
+ Underline byte
+ StrikeOut byte
+ CharSet byte
+ OutPrecision byte
+ ClipPrecision byte
+ Quality byte
+ PitchAndFamily byte
+ FaceName [LF_FACESIZE]uint16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646839.aspx
+type OPENFILENAME struct {
+ StructSize uint32
+ Owner HWND
+ Instance HINSTANCE
+ Filter *uint16
+ CustomFilter *uint16
+ MaxCustomFilter uint32
+ FilterIndex uint32
+ File *uint16
+ MaxFile uint32
+ FileTitle *uint16
+ MaxFileTitle uint32
+ InitialDir *uint16
+ Title *uint16
+ Flags uint32
+ FileOffset uint16
+ FileExtension uint16
+ DefExt *uint16
+ CustData uintptr
+ FnHook uintptr
+ TemplateName *uint16
+ PvReserved unsafe.Pointer
+ DwReserved uint32
+ FlagsEx uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb773205.aspx
+type BROWSEINFO struct {
+ Owner HWND
+ Root *uint16
+ DisplayName *uint16
+ Title *uint16
+ Flags uint32
+ CallbackFunc uintptr
+ LParam uintptr
+ Image int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221627.aspx
+type VARIANT struct {
+ VT uint16 // 2
+ WReserved1 uint16 // 4
+ WReserved2 uint16 // 6
+ WReserved3 uint16 // 8
+ Val int64 // 16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221416.aspx
+type DISPPARAMS struct {
+ Rgvarg uintptr
+ RgdispidNamedArgs uintptr
+ CArgs uint32
+ CNamedArgs uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221133.aspx
+type EXCEPINFO struct {
+ WCode uint16
+ WReserved uint16
+ BstrSource *uint16
+ BstrDescription *uint16
+ BstrHelpFile *uint16
+ DwHelpContext uint32
+ PvReserved uintptr
+ PfnDeferredFillIn uintptr
+ Scode int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145035.aspx
+type LOGBRUSH struct {
+ LbStyle uint32
+ LbColor COLORREF
+ LbHatch uintptr
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183565.aspx
+type DEVMODE struct {
+ DmDeviceName [CCHDEVICENAME]uint16
+ DmSpecVersion uint16
+ DmDriverVersion uint16
+ DmSize uint16
+ DmDriverExtra uint16
+ DmFields uint32
+ DmOrientation int16
+ DmPaperSize int16
+ DmPaperLength int16
+ DmPaperWidth int16
+ DmScale int16
+ DmCopies int16
+ DmDefaultSource int16
+ DmPrintQuality int16
+ DmColor int16
+ DmDuplex int16
+ DmYResolution int16
+ DmTTOption int16
+ DmCollate int16
+ DmFormName [CCHFORMNAME]uint16
+ DmLogPixels uint16
+ DmBitsPerPel uint32
+ DmPelsWidth uint32
+ DmPelsHeight uint32
+ DmDisplayFlags uint32
+ DmDisplayFrequency uint32
+ DmICMMethod uint32
+ DmICMIntent uint32
+ DmMediaType uint32
+ DmDitherType uint32
+ DmReserved1 uint32
+ DmReserved2 uint32
+ DmPanningWidth uint32
+ DmPanningHeight uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376.aspx
+type BITMAPINFOHEADER struct {
+ BiSize uint32
+ BiWidth int32
+ BiHeight int32
+ BiPlanes uint16
+ BiBitCount uint16
+ BiCompression uint32
+ BiSizeImage uint32
+ BiXPelsPerMeter int32
+ BiYPelsPerMeter int32
+ BiClrUsed uint32
+ BiClrImportant uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162938.aspx
+type RGBQUAD struct {
+ RgbBlue byte
+ RgbGreen byte
+ RgbRed byte
+ RgbReserved byte
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183375.aspx
+type BITMAPINFO struct {
+ BmiHeader BITMAPINFOHEADER
+ BmiColors *RGBQUAD
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183371.aspx
+type BITMAP struct {
+ BmType int32
+ BmWidth int32
+ BmHeight int32
+ BmWidthBytes int32
+ BmPlanes uint16
+ BmBitsPixel uint16
+ BmBits unsafe.Pointer
+}
+
+type BLENDFUNCTION struct {
+ BlendOp byte
+ BlendFlags byte
+ SourceConstantAlpha byte
+ AlphaFormat byte
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183567.aspx
+type DIBSECTION struct {
+ DsBm BITMAP
+ DsBmih BITMAPINFOHEADER
+ DsBitfields [3]uint32
+ DshSection HANDLE
+ DsOffset uint32
+}
+
+type MSGBOXPARAMS struct {
+ cbSize uint32
+ hwndOwner HWND
+ hInstance HANDLE
+ lpszText *uint16
+ lpszCaption *uint16
+ dwStyle uint32
+ lpszIcon *uint16
+ dwContextHelp uintptr
+ lpfnMsgBoxCallback uintptr
+ dwLanguageId uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162607.aspx
+type ENHMETAHEADER struct {
+ IType uint32
+ NSize uint32
+ RclBounds RECT
+ RclFrame RECT
+ DSignature uint32
+ NVersion uint32
+ NBytes uint32
+ NRecords uint32
+ NHandles uint16
+ SReserved uint16
+ NDescription uint32
+ OffDescription uint32
+ NPalEntries uint32
+ SzlDevice SIZE
+ SzlMillimeters SIZE
+ CbPixelFormat uint32
+ OffPixelFormat uint32
+ BOpenGL uint32
+ SzlMicrometers SIZE
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145106.aspx
+type SIZE struct {
+ CX, CY int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145132.aspx
+type TEXTMETRIC struct {
+ TmHeight int32
+ TmAscent int32
+ TmDescent int32
+ TmInternalLeading int32
+ TmExternalLeading int32
+ TmAveCharWidth int32
+ TmMaxCharWidth int32
+ TmWeight int32
+ TmOverhang int32
+ TmDigitizedAspectX int32
+ TmDigitizedAspectY int32
+ TmFirstChar uint16
+ TmLastChar uint16
+ TmDefaultChar uint16
+ TmBreakChar uint16
+ TmItalic byte
+ TmUnderlined byte
+ TmStruckOut byte
+ TmPitchAndFamily byte
+ TmCharSet byte
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183574.aspx
+type DOCINFO struct {
+ CbSize int32
+ LpszDocName *uint16
+ LpszOutput *uint16
+ LpszDatatype *uint16
+ FwType uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb775514.aspx
+type NMHDR struct {
+ HwndFrom HWND
+ IdFrom uintptr
+ Code uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774743.aspx
+type LVCOLUMN struct {
+ Mask uint32
+ Fmt int32
+ Cx int32
+ PszText *uint16
+ CchTextMax int32
+ ISubItem int32
+ IImage int32
+ IOrder int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774760.aspx
+type LVITEM struct {
+ Mask uint32
+ IItem int32
+ ISubItem int32
+ State uint32
+ StateMask uint32
+ PszText *uint16
+ CchTextMax int32
+ IImage int32
+ LParam uintptr
+ IIndent int32
+ IGroupId int32
+ CColumns uint32
+ PuColumns uint32
+}
+
+type LVFINDINFO struct {
+ Flags uint32
+ PszText *uint16
+ LParam uintptr
+ Pt POINT
+ VkDirection uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774754.aspx
+type LVHITTESTINFO struct {
+ Pt POINT
+ Flags uint32
+ IItem int32
+ ISubItem int32
+ IGroup int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774771.aspx
+type NMITEMACTIVATE struct {
+ Hdr NMHDR
+ IItem int32
+ ISubItem int32
+ UNewState uint32
+ UOldState uint32
+ UChanged uint32
+ PtAction POINT
+ LParam uintptr
+ UKeyFlags uint32
+}
+
+type NMLVKEYDOWN struct {
+ Hdr NMHDR
+ WVKey uint16
+ Flags uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774773.aspx
+type NMLISTVIEW struct {
+ Hdr NMHDR
+ IItem int32
+ ISubItem int32
+ UNewState uint32
+ UOldState uint32
+ UChanged uint32
+ PtAction POINT
+ LParam uintptr
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774780.aspx
+type NMLVDISPINFO struct {
+ Hdr NMHDR
+ Item LVITEM
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb775507.aspx
+type INITCOMMONCONTROLSEX struct {
+ DwSize uint32
+ DwICC uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb760256.aspx
+type TOOLINFO struct {
+ CbSize uint32
+ UFlags uint32
+ Hwnd HWND
+ UId uintptr
+ Rect RECT
+ Hinst HINSTANCE
+ LpszText *uint16
+ LParam uintptr
+ LpReserved unsafe.Pointer
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms645604.aspx
+type TRACKMOUSEEVENT struct {
+ CbSize uint32
+ DwFlags uint32
+ HwndTrack HWND
+ DwHoverTime uint32
+}
+
+type NOTIFYICONDATA struct {
+ CbSize uint32
+ HWnd HWND
+ UID uint32
+ UFlags uint32
+ UCallbackMessage uint32
+ HIcon HICON
+ SzTip [128]uint16
+ DwState uint32
+ DwStateMask uint32
+ SzInfo [256]uint16
+ UVersion uint32
+ SzInfoTitle [64]uint16
+ DwInfoFlags uint32
+ GuidItem windows.GUID
+ HBalloonIcon HICON
+}
+
+const SPI_GETNOTIFYWINDOWRECT = 0x0040
+const SPI_SETWORKAREA = 0x002F
+
+// Taskbar constants
+const ABM_GETTASKBARPOS = 0x00000005
+const ABM_GETSTATE = 0x00000004
+const ABM_GETAUTOHIDEBAR = 0x00000007
+const ABM_SETSTATE = 0x0000000a
+const ABM_SETAUTOHIDEBAR = 0x00000008
+const ABM_WINDOWPOSCHANGED = 0x00000009
+const ABM_SETPOS = 0x00000003
+
+const ABE_LEFT = 0
+const ABE_TOP = 1
+const ABE_RIGHT = 2
+const ABE_BOTTOM = 3
+
+type NOTIFYICONIDENTIFIER struct {
+ CbSize uint32
+ HWnd HWND
+ UId uint32
+ GuidItem windows.GUID
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms534067.aspx
+type GdiplusStartupInput struct {
+ GdiplusVersion uint32
+ DebugEventCallback uintptr
+ SuppressBackgroundThread BOOL
+ SuppressExternalCodecs BOOL
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms534068.aspx
+type GdiplusStartupOutput struct {
+ NotificationHook uintptr
+ NotificationUnhook uintptr
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162768.aspx
+type PAINTSTRUCT struct {
+ Hdc HDC
+ FErase BOOL
+ RcPaint RECT
+ FRestore BOOL
+ FIncUpdate BOOL
+ RgbReserved [32]byte
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa363646.aspx
+type EVENTLOGRECORD struct {
+ Length uint32
+ Reserved uint32
+ RecordNumber uint32
+ TimeGenerated uint32
+ TimeWritten uint32
+ EventID uint32
+ EventType uint16
+ NumStrings uint16
+ EventCategory uint16
+ ReservedFlags uint16
+ ClosingRecordNumber uint32
+ StringOffset uint32
+ UserSidLength uint32
+ UserSidOffset uint32
+ DataLength uint32
+ DataOffset uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms685996.aspx
+type SERVICE_STATUS struct {
+ DwServiceType uint32
+ DwCurrentState uint32
+ DwControlsAccepted uint32
+ DwWin32ExitCode uint32
+ DwServiceSpecificExitCode uint32
+ DwCheckPoint uint32
+ DwWaitHint uint32
+}
+
+/* -------------------------
+ Undocumented API
+------------------------- */
+
+type ACCENT_STATE DWORD
+
+const (
+ ACCENT_DISABLED ACCENT_STATE = 0
+ ACCENT_ENABLE_GRADIENT ACCENT_STATE = 1
+ ACCENT_ENABLE_TRANSPARENTGRADIENT ACCENT_STATE = 2
+ ACCENT_ENABLE_BLURBEHIND ACCENT_STATE = 3
+ ACCENT_ENABLE_ACRYLICBLURBEHIND ACCENT_STATE = 4 // RS4 1803
+ ACCENT_ENABLE_HOSTBACKDROP ACCENT_STATE = 5 // RS5 1809
+ ACCENT_INVALID_STATE ACCENT_STATE = 6
+)
+
+type ACCENT_POLICY struct {
+ AccentState ACCENT_STATE
+ AccentFlags DWORD
+ GradientColor DWORD
+ AnimationId DWORD
+}
+
+// -------------------------
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms684225.aspx
+type MODULEENTRY32 struct {
+ Size uint32
+ ModuleID uint32
+ ProcessID uint32
+ GlblcntUsage uint32
+ ProccntUsage uint32
+ ModBaseAddr *uint8
+ ModBaseSize uint32
+ HModule HMODULE
+ SzModule [MAX_MODULE_NAME32 + 1]uint16
+ SzExePath [MAX_PATH]uint16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx
+type FILETIME struct {
+ DwLowDateTime uint32
+ DwHighDateTime uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682119.aspx
+type COORD struct {
+ X, Y int16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686311.aspx
+type SMALL_RECT struct {
+ Left, Top, Right, Bottom int16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093.aspx
+type CONSOLE_SCREEN_BUFFER_INFO struct {
+ DwSize COORD
+ DwCursorPosition COORD
+ WAttributes uint16
+ SrWindow SMALL_RECT
+ DwMaximumWindowSize COORD
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb773244.aspx
+type MARGINS struct {
+ CxLeftWidth, CxRightWidth, CyTopHeight, CyBottomHeight int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969500.aspx
+type DWM_BLURBEHIND struct {
+ DwFlags uint32
+ fEnable BOOL
+ hRgnBlur HRGN
+ fTransitionOnMaximized BOOL
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969501.aspx
+type DWM_PRESENT_PARAMETERS struct {
+ cbSize uint32
+ fQueue BOOL
+ cRefreshStart DWM_FRAME_COUNT
+ cBuffer uint32
+ fUseSourceRate BOOL
+ rateSource UNSIGNED_RATIO
+ cRefreshesPerFrame uint32
+ eSampling DWM_SOURCE_FRAME_SAMPLING
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969502.aspx
+type DWM_THUMBNAIL_PROPERTIES struct {
+ dwFlags uint32
+ rcDestination RECT
+ rcSource RECT
+ opacity byte
+ fVisible BOOL
+ fSourceClientAreaOnly BOOL
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969503.aspx
+type DWM_TIMING_INFO struct {
+ cbSize uint32
+ rateRefresh UNSIGNED_RATIO
+ qpcRefreshPeriod QPC_TIME
+ rateCompose UNSIGNED_RATIO
+ qpcVBlank QPC_TIME
+ cRefresh DWM_FRAME_COUNT
+ cDXRefresh uint32
+ qpcCompose QPC_TIME
+ cFrame DWM_FRAME_COUNT
+ cDXPresent uint32
+ cRefreshFrame DWM_FRAME_COUNT
+ cFrameSubmitted DWM_FRAME_COUNT
+ cDXPresentSubmitted uint32
+ cFrameConfirmed DWM_FRAME_COUNT
+ cDXPresentConfirmed uint32
+ cRefreshConfirmed DWM_FRAME_COUNT
+ cDXRefreshConfirmed uint32
+ cFramesLate DWM_FRAME_COUNT
+ cFramesOutstanding uint32
+ cFrameDisplayed DWM_FRAME_COUNT
+ qpcFrameDisplayed QPC_TIME
+ cRefreshFrameDisplayed DWM_FRAME_COUNT
+ cFrameComplete DWM_FRAME_COUNT
+ qpcFrameComplete QPC_TIME
+ cFramePending DWM_FRAME_COUNT
+ qpcFramePending QPC_TIME
+ cFramesDisplayed DWM_FRAME_COUNT
+ cFramesComplete DWM_FRAME_COUNT
+ cFramesPending DWM_FRAME_COUNT
+ cFramesAvailable DWM_FRAME_COUNT
+ cFramesDropped DWM_FRAME_COUNT
+ cFramesMissed DWM_FRAME_COUNT
+ cRefreshNextDisplayed DWM_FRAME_COUNT
+ cRefreshNextPresented DWM_FRAME_COUNT
+ cRefreshesDisplayed DWM_FRAME_COUNT
+ cRefreshesPresented DWM_FRAME_COUNT
+ cRefreshStarted DWM_FRAME_COUNT
+ cPixelsReceived uint64
+ cPixelsDrawn uint64
+ cBuffersEmpty DWM_FRAME_COUNT
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd389402.aspx
+type MilMatrix3x2D struct {
+ S_11, S_12, S_21, S_22 float64
+ DX, DY float64
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969505.aspx
+type UNSIGNED_RATIO struct {
+ uiNumerator uint32
+ uiDenominator uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms632603.aspx
+type CREATESTRUCT struct {
+ CreateParams uintptr
+ Instance HINSTANCE
+ Menu HMENU
+ Parent HWND
+ Cy, Cx int32
+ Y, X int32
+ Style int32
+ Name *uint16
+ Class *uint16
+ dwExStyle uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145065.aspx
+type MONITORINFO struct {
+ CbSize uint32
+ RcMonitor RECT
+ RcWork RECT
+ DwFlags uint32
+}
+
+type WINDOWINFO struct {
+ CbSize DWORD
+ RcWindow RECT
+ RcClient RECT
+ DwStyle DWORD
+ DwExStyle DWORD
+ DwWindowStatus DWORD
+ CxWindowBorders UINT
+ CyWindowBorders UINT
+ AtomWindowType ATOM
+ WCreatorVersion WORD
+}
+
+type MONITOR_DPI_TYPE int32
+
+const (
+ MDT_EFFECTIVE_DPI MONITOR_DPI_TYPE = 0
+ MDT_ANGULAR_DPI MONITOR_DPI_TYPE = 1
+ MDT_RAW_DPI MONITOR_DPI_TYPE = 2
+ MDT_DEFAULT MONITOR_DPI_TYPE = 0
+)
+
+func (w *WINDOWINFO) isStyle(style DWORD) bool {
+ return w.DwStyle&style == style
+}
+
+func (w *WINDOWINFO) IsPopup() bool {
+ return w.isStyle(WS_POPUP)
+}
+
+func (m *MONITORINFO) Dump() {
+ fmt.Printf("MONITORINFO (%p)\n", m)
+ fmt.Printf(" CbSize : %d\n", m.CbSize)
+ fmt.Printf(" RcMonitor: %s\n", &m.RcMonitor)
+ fmt.Printf(" RcWork : %s\n", &m.RcWork)
+ fmt.Printf(" DwFlags : %d\n", m.DwFlags)
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145066.aspx
+type MONITORINFOEX struct {
+ MONITORINFO
+ SzDevice [CCHDEVICENAME]uint16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd368826.aspx
+type PIXELFORMATDESCRIPTOR struct {
+ Size uint16
+ Version uint16
+ DwFlags uint32
+ IPixelType byte
+ ColorBits byte
+ RedBits, RedShift byte
+ GreenBits, GreenShift byte
+ BlueBits, BlueShift byte
+ AlphaBits, AlphaShift byte
+ AccumBits byte
+ AccumRedBits byte
+ AccumGreenBits byte
+ AccumBlueBits byte
+ AccumAlphaBits byte
+ DepthBits, StencilBits byte
+ AuxBuffers byte
+ ILayerType byte
+ Reserved byte
+ DwLayerMask uint32
+ DwVisibleMask uint32
+ DwDamageMask uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx
+type INPUT struct {
+ Type uint32
+ Mi MOUSEINPUT
+ Ki KEYBDINPUT
+ Hi HARDWAREINPUT
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646273(v=vs.85).aspx
+type MOUSEINPUT struct {
+ Dx int32
+ Dy int32
+ MouseData uint32
+ DwFlags uint32
+ Time uint32
+ DwExtraInfo uintptr
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646271(v=vs.85).aspx
+type KEYBDINPUT struct {
+ WVk uint16
+ WScan uint16
+ DwFlags uint32
+ Time uint32
+ DwExtraInfo uintptr
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646269(v=vs.85).aspx
+type HARDWAREINPUT struct {
+ UMsg uint32
+ WParamL uint16
+ WParamH uint16
+}
+
+type KbdInput struct {
+ typ uint32
+ ki KEYBDINPUT
+}
+
+type MouseInput struct {
+ typ uint32
+ mi MOUSEINPUT
+}
+
+type HardwareInput struct {
+ typ uint32
+ hi HARDWAREINPUT
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx
+type SYSTEMTIME struct {
+ Year uint16
+ Month uint16
+ DayOfWeek uint16
+ Day uint16
+ Hour uint16
+ Minute uint16
+ Second uint16
+ Milliseconds uint16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644967(v=vs.85).aspx
+type KBDLLHOOKSTRUCT struct {
+ VkCode DWORD
+ ScanCode DWORD
+ Flags DWORD
+ Time DWORD
+ DwExtraInfo ULONG_PTR
+}
+
+type HOOKPROC func(int, WPARAM, LPARAM) LRESULT
+
+type WINDOWPLACEMENT struct {
+ Length uint32
+ Flags uint32
+ ShowCmd uint32
+ PtMinPosition POINT
+ PtMaxPosition POINT
+ RcNormalPosition RECT
+}
+
+type SCROLLINFO struct {
+ CbSize uint32
+ FMask uint32
+ NMin int32
+ NMax int32
+ NPage uint32
+ NPos int32
+ NTrackPos int32
+}
+
+type FLASHWINFO struct {
+ CbSize uint32
+ Hwnd HWND
+ DwFlags DWORD
+ UCount uint32
+ DwTimeout DWORD
+}
diff --git a/v3/pkg/w32/user32.go b/v3/pkg/w32/user32.go
new file mode 100644
index 000000000..95463d86b
--- /dev/null
+++ b/v3/pkg/w32/user32.go
@@ -0,0 +1,1510 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+
+package w32
+
+import (
+ "fmt"
+ "runtime"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+var (
+ moduser32 = syscall.NewLazyDLL("user32.dll")
+
+ procRegisterClassEx = moduser32.NewProc("RegisterClassExW")
+ procGetClassName = moduser32.NewProc("GetClassNameW")
+ procLoadIcon = moduser32.NewProc("LoadIconW")
+ procLoadCursor = moduser32.NewProc("LoadCursorW")
+ procShowWindow = moduser32.NewProc("ShowWindow")
+ procGetDesktopWindow = moduser32.NewProc("GetDesktopWindow")
+ procShowWindowAsync = moduser32.NewProc("ShowWindowAsync")
+ procIsZoomed = moduser32.NewProc("IsZoomed")
+ procUpdateWindow = moduser32.NewProc("UpdateWindow")
+ procCreateWindowEx = moduser32.NewProc("CreateWindowExW")
+ procAdjustWindowRect = moduser32.NewProc("AdjustWindowRect")
+ procAdjustWindowRectEx = moduser32.NewProc("AdjustWindowRectEx")
+ procDestroyWindow = moduser32.NewProc("DestroyWindow")
+ procDefWindowProc = moduser32.NewProc("DefWindowProcW")
+ procDefDlgProc = moduser32.NewProc("DefDlgProcW")
+ procPostQuitMessage = moduser32.NewProc("PostQuitMessage")
+ procGetMessage = moduser32.NewProc("GetMessageW")
+ procTranslateMessage = moduser32.NewProc("TranslateMessage")
+ procDispatchMessage = moduser32.NewProc("DispatchMessageW")
+ procSendMessage = moduser32.NewProc("SendMessageW")
+ procPostMessage = moduser32.NewProc("PostMessageW")
+ procWaitMessage = moduser32.NewProc("WaitMessage")
+ procSetWindowText = moduser32.NewProc("SetWindowTextW")
+ procGetWindowTextLength = moduser32.NewProc("GetWindowTextLengthW")
+ procGetWindowText = moduser32.NewProc("GetWindowTextW")
+ procGetWindowRect = moduser32.NewProc("GetWindowRect")
+ procGetWindowInfo = moduser32.NewProc("GetWindowInfo")
+ procGetWindow = moduser32.NewProc("GetWindow")
+ procSetWindowCompositionAttribute = moduser32.NewProc("SetWindowCompositionAttribute")
+ procMoveWindow = moduser32.NewProc("MoveWindow")
+ procScreenToClient = moduser32.NewProc("ScreenToClient")
+ procCallWindowProc = moduser32.NewProc("CallWindowProcW")
+ procSetWindowLong = moduser32.NewProc("SetWindowLongW")
+ procSetWindowLongPtr = moduser32.NewProc("SetWindowLongW")
+ procGetWindowLong = moduser32.NewProc("GetWindowLongW")
+ procGetWindowLongPtr = moduser32.NewProc("GetWindowLongW")
+ procEnableWindow = moduser32.NewProc("EnableWindow")
+ procIsWindowEnabled = moduser32.NewProc("IsWindowEnabled")
+ procIsWindowVisible = moduser32.NewProc("IsWindowVisible")
+ procSetFocus = moduser32.NewProc("SetFocus")
+ procGetFocus = moduser32.NewProc("GetFocus")
+ procSetActiveWindow = moduser32.NewProc("SetActiveWindow")
+ procSetForegroundWindow = moduser32.NewProc("SetForegroundWindow")
+ procBringWindowToTop = moduser32.NewProc("BringWindowToTop")
+ procInvalidateRect = moduser32.NewProc("InvalidateRect")
+ procGetClientRect = moduser32.NewProc("GetClientRect")
+ procGetDC = moduser32.NewProc("GetDC")
+ procReleaseDC = moduser32.NewProc("ReleaseDC")
+ procSetCapture = moduser32.NewProc("SetCapture")
+ procReleaseCapture = moduser32.NewProc("ReleaseCapture")
+ procGetWindowThreadProcessId = moduser32.NewProc("GetWindowThreadProcessId")
+ procMessageBox = moduser32.NewProc("MessageBoxW")
+ procMessageBoxIndirect = moduser32.NewProc("MessageBoxIndirectW")
+ procGetSystemMetrics = moduser32.NewProc("GetSystemMetrics")
+ procPostThreadMessageW = moduser32.NewProc("PostThreadMessageW")
+ procRegisterWindowMessageA = moduser32.NewProc("RegisterWindowMessageA")
+ procCopyRect = moduser32.NewProc("CopyRect")
+ procEqualRect = moduser32.NewProc("EqualRect")
+ procInflateRect = moduser32.NewProc("InflateRect")
+ procIntersectRect = moduser32.NewProc("IntersectRect")
+ procIsRectEmpty = moduser32.NewProc("IsRectEmpty")
+ procOffsetRect = moduser32.NewProc("OffsetRect")
+ procPtInRect = moduser32.NewProc("PtInRect")
+ procSetRect = moduser32.NewProc("SetRect")
+ procSetRectEmpty = moduser32.NewProc("SetRectEmpty")
+ procSubtractRect = moduser32.NewProc("SubtractRect")
+ procUnionRect = moduser32.NewProc("UnionRect")
+ procCreateDialogParam = moduser32.NewProc("CreateDialogParamW")
+ procDialogBoxParam = moduser32.NewProc("DialogBoxParamW")
+ procGetDlgItem = moduser32.NewProc("GetDlgItem")
+ procDrawIcon = moduser32.NewProc("DrawIcon")
+ procCreateMenu = moduser32.NewProc("CreateMenu")
+ procRemoveMenu = moduser32.NewProc("RemoveMenu")
+ procGetMenuItemPosition = moduser32.NewProc("GetMenuItemPosition")
+ procDestroyMenu = moduser32.NewProc("DestroyMenu")
+ procCreatePopupMenu = moduser32.NewProc("CreatePopupMenu")
+ procCheckMenuRadioItem = moduser32.NewProc("CheckMenuRadioItem")
+ procCreateIconFromResourceEx = moduser32.NewProc("CreateIconFromResourceEx")
+ procInsertMenuItem = moduser32.NewProc("InsertMenuItemW")
+ procCheckMenuItem = moduser32.NewProc("CheckMenuItem")
+ procClientToScreen = moduser32.NewProc("ClientToScreen")
+ procIsDialogMessage = moduser32.NewProc("IsDialogMessageW")
+ procIsWindow = moduser32.NewProc("IsWindow")
+ procEndDialog = moduser32.NewProc("EndDialog")
+ procPeekMessage = moduser32.NewProc("PeekMessageW")
+ procTranslateAccelerator = moduser32.NewProc("TranslateAcceleratorW")
+ procSetWindowPos = moduser32.NewProc("SetWindowPos")
+ procFillRect = moduser32.NewProc("FillRect")
+ procFrameRect = moduser32.NewProc("FrameRect")
+ procDrawText = moduser32.NewProc("DrawTextW")
+ procAddClipboardFormatListener = moduser32.NewProc("AddClipboardFormatListener")
+ procRemoveClipboardFormatListener = moduser32.NewProc("RemoveClipboardFormatListener")
+ procOpenClipboard = moduser32.NewProc("OpenClipboard")
+ procCloseClipboard = moduser32.NewProc("CloseClipboard")
+ procEnumClipboardFormats = moduser32.NewProc("EnumClipboardFormats")
+ procGetClipboardData = moduser32.NewProc("GetClipboardData")
+ procSetClipboardData = moduser32.NewProc("SetClipboardData")
+ procEmptyClipboard = moduser32.NewProc("EmptyClipboard")
+ procGetClipboardFormatName = moduser32.NewProc("GetClipboardFormatNameW")
+ procIsClipboardFormatAvailable = moduser32.NewProc("IsClipboardFormatAvailable")
+ procBeginPaint = moduser32.NewProc("BeginPaint")
+ procEndPaint = moduser32.NewProc("EndPaint")
+ procGetKeyboardState = moduser32.NewProc("GetKeyboardState")
+ procMapVirtualKey = moduser32.NewProc("MapVirtualKeyW")
+ procMapVirtualKeyEx = moduser32.NewProc("MapVirtualKeyExW")
+ procGetAsyncKeyState = moduser32.NewProc("GetAsyncKeyState")
+ procToAscii = moduser32.NewProc("ToAscii")
+ procSwapMouseButton = moduser32.NewProc("SwapMouseButton")
+ procGetCursorPos = moduser32.NewProc("GetCursorPos")
+ procSetCursorPos = moduser32.NewProc("SetCursorPos")
+ procSetCursor = moduser32.NewProc("SetCursor")
+ procCreateIcon = moduser32.NewProc("CreateIcon")
+ procDestroyIcon = moduser32.NewProc("DestroyIcon")
+ procMonitorFromPoint = moduser32.NewProc("MonitorFromPoint")
+ procMonitorFromRect = moduser32.NewProc("MonitorFromRect")
+ procMonitorFromWindow = moduser32.NewProc("MonitorFromWindow")
+ procGetMonitorInfo = moduser32.NewProc("GetMonitorInfoW")
+ procGetDpiForSystem = moduser32.NewProc("GetDpiForSystem")
+ procGetDpiForWindow = moduser32.NewProc("GetDpiForWindow")
+ procSetProcessDPIAware = moduser32.NewProc("SetProcessDPIAware")
+ procSetProcessDpiAwarenessContext = moduser32.NewProc("SetProcessDpiAwarenessContext")
+ procEnumDisplayMonitors = moduser32.NewProc("EnumDisplayMonitors")
+ procEnumDisplayDevices = moduser32.NewProc("EnumDisplayDevicesW")
+ procEnumDisplaySettings = moduser32.NewProc("EnumDisplaySettingsW")
+ procEnumDisplaySettingsEx = moduser32.NewProc("EnumDisplaySettingsExW")
+ procEnumWindows = moduser32.NewProc("EnumWindows")
+ procEnumChildWindows = moduser32.NewProc("EnumChildWindows")
+ procChangeDisplaySettingsEx = moduser32.NewProc("ChangeDisplaySettingsExW")
+ procSetTimer = moduser32.NewProc("SetTimer")
+ procKillTimer = moduser32.NewProc("KillTimer")
+ procKeybdEvent = moduser32.NewProc("keybd_event")
+ procSendInput = moduser32.NewProc("SendInput")
+ procSetWindowsHookEx = moduser32.NewProc("SetWindowsHookExW")
+ procUnhookWindowsHookEx = moduser32.NewProc("UnhookWindowsHookEx")
+ procCallNextHookEx = moduser32.NewProc("CallNextHookEx")
+ procGetForegroundWindow = moduser32.NewProc("GetForegroundWindow")
+ procUpdateLayeredWindow = moduser32.NewProc("UpdateLayeredWindow")
+ getDisplayConfig = moduser32.NewProc("GetDisplayConfigBufferSizes")
+ queryDisplayConfig = moduser32.NewProc("QueryDisplayConfig")
+
+ procSystemParametersInfo = moduser32.NewProc("SystemParametersInfoW")
+ procSetClassLong = moduser32.NewProc("SetClassLongW")
+ procSetClassLongPtr = moduser32.NewProc("SetClassLongPtrW")
+
+ procSetMenu = moduser32.NewProc("SetMenu")
+ procAppendMenu = moduser32.NewProc("AppendMenuW")
+ procSetMenuItemInfo = moduser32.NewProc("SetMenuItemInfoW")
+ procDrawMenuBar = moduser32.NewProc("DrawMenuBar")
+ procTrackPopupMenu = moduser32.NewProc("TrackPopupMenu")
+ procTrackPopupMenuEx = moduser32.NewProc("TrackPopupMenuEx")
+ procGetMenuBarInfo = moduser32.NewProc("GetMenuBarInfo")
+ procMapWindowPoints = moduser32.NewProc("MapWindowPoints")
+ procGetKeyState = moduser32.NewProc("GetKeyState")
+ procGetSysColorBrush = moduser32.NewProc("GetSysColorBrush")
+ procGetSysColor = moduser32.NewProc("GetSysColor")
+
+ procGetWindowPlacement = moduser32.NewProc("GetWindowPlacement")
+ procSetWindowPlacement = moduser32.NewProc("SetWindowPlacement")
+ procGetWindowDC = moduser32.NewProc("GetWindowDC")
+
+ procGetScrollInfo = moduser32.NewProc("GetScrollInfo")
+ procSetScrollInfo = moduser32.NewProc("SetScrollInfo")
+
+ procFlashWindowEx = moduser32.NewProc("FlashWindowEx")
+
+ procSetMenuItemBitmaps = moduser32.NewProc("SetMenuItemBitmaps")
+
+ procRedrawWindow = moduser32.NewProc("RedrawWindow")
+
+ procRegisterWindowMessageW = moduser32.NewProc("RegisterWindowMessageW")
+ procSetWindowDisplayAffinity = moduser32.NewProc("SetWindowDisplayAffinity")
+
+ mainThread HANDLE
+)
+
+func init() {
+ runtime.LockOSThread()
+ mainThread = GetCurrentThreadId()
+}
+
+func GetWindowDC(hwnd HWND) HDC {
+ ret, _, _ := procGetWindowDC.Call(hwnd)
+ return ret
+}
+
+func GET_X_LPARAM(lp uintptr) int32 {
+ return int32(int16(LOWORD(uint32(lp))))
+}
+
+func GET_Y_LPARAM(lp uintptr) int32 {
+ return int32(int16(HIWORD(uint32(lp))))
+}
+
+func RegisterClassEx(wndClassEx *WNDCLASSEX) ATOM {
+ ret, _, _ := procRegisterClassEx.Call(uintptr(unsafe.Pointer(wndClassEx)))
+ return ATOM(ret)
+}
+
+func SetMenuItemBitmaps(hMenu HMENU, uPosition, uFlags uint32, hBitmapUnchecked HBITMAP, hBitmapChecked HBITMAP) error {
+ ret, _, _ := procSetMenuItemBitmaps.Call(
+ hMenu,
+ uintptr(uPosition),
+ uintptr(uFlags),
+ hBitmapUnchecked,
+ hBitmapChecked)
+
+ if ret == 0 {
+ return windows.GetLastError()
+ }
+ return nil
+}
+
+func GetDesktopWindow() HWND {
+ ret, _, _ := procGetDesktopWindow.Call()
+ return ret
+}
+
+func LoadIcon(instance HINSTANCE, iconName *uint16) HICON {
+ ret, _, _ := procLoadIcon.Call(
+ uintptr(instance),
+ uintptr(unsafe.Pointer(iconName)))
+
+ return HICON(ret)
+}
+
+func LoadIconWithResourceID(instance HINSTANCE, res uint16) HICON {
+ ret, _, _ := procLoadIcon.Call(
+ uintptr(instance),
+ uintptr(res))
+
+ return HICON(ret)
+}
+
+func LoadCursor(instance HINSTANCE, cursorName *uint16) HCURSOR {
+ ret, _, _ := procLoadCursor.Call(
+ uintptr(instance),
+ uintptr(unsafe.Pointer(cursorName)))
+
+ return HCURSOR(ret)
+}
+
+func LoadCursorWithResourceID(instance HINSTANCE, res uint16) HCURSOR {
+ ret, _, _ := procLoadCursor.Call(
+ uintptr(instance),
+ uintptr(res))
+
+ return HCURSOR(ret)
+}
+
+func MessageBoxIndirect(msgbox *MSGBOXPARAMS) int32 {
+ ret, _, _ := procMessageBoxIndirect.Call(
+ uintptr(unsafe.Pointer(msgbox)))
+
+ return int32(ret)
+}
+
+func ShowWindow(hwnd HWND, cmdshow int) bool {
+ ret, _, _ := procShowWindow.Call(
+ uintptr(hwnd),
+ uintptr(cmdshow))
+
+ return ret != 0
+}
+
+func IsZoomed(hwnd HWND) bool {
+ ret, _, _ := procIsZoomed.Call(uintptr(hwnd))
+ return ret != 0
+}
+
+func ShowWindowAsync(hwnd HWND, cmdshow int) bool {
+ ret, _, _ := procShowWindowAsync.Call(
+ uintptr(hwnd),
+ uintptr(cmdshow))
+
+ return ret != 0
+}
+
+func UpdateWindow(hwnd HWND) bool {
+ ret, _, _ := procUpdateWindow.Call(
+ uintptr(hwnd))
+ return ret != 0
+}
+
+func UpdateLayeredWindow(hwnd HWND, hdcDst HDC, pptDst *POINT, psize *SIZE,
+ hdcSrc HDC, pptSrc *POINT, crKey COLORREF, pblend *BLENDFUNCTION, dwFlags DWORD) bool {
+ ret, _, _ := procUpdateLayeredWindow.Call(
+ hwnd,
+ hdcDst,
+ uintptr(unsafe.Pointer(pptDst)),
+ uintptr(unsafe.Pointer(psize)),
+ hdcSrc,
+ uintptr(unsafe.Pointer(pptSrc)),
+ uintptr(crKey),
+ uintptr(unsafe.Pointer(pblend)),
+ uintptr(dwFlags))
+ return ret != 0
+}
+
+func PostThreadMessage(threadID HANDLE, msg int, wp, lp uintptr) {
+ procPostThreadMessageW.Call(threadID, uintptr(msg), wp, lp)
+}
+
+func RegisterWindowMessage(name *uint16) uint32 {
+ ret, _, _ := procRegisterWindowMessageW.Call(uintptr(unsafe.Pointer(name)))
+ return uint32(ret)
+}
+
+func PostMainThreadMessage(msg uint32, wp, lp uintptr) bool {
+ ret, _, _ := procPostThreadMessageW.Call(mainThread, uintptr(msg), wp, lp)
+ return ret != 0
+}
+
+func CreateWindowEx(exStyle uint, className, windowName *uint16,
+ style uint, x, y, width, height int, parent HWND, menu HMENU,
+ instance HINSTANCE, param unsafe.Pointer) HWND {
+ ret, _, _ := procCreateWindowEx.Call(
+ uintptr(exStyle),
+ uintptr(unsafe.Pointer(className)),
+ uintptr(unsafe.Pointer(windowName)),
+ uintptr(style),
+ uintptr(x),
+ uintptr(y),
+ uintptr(width),
+ uintptr(height),
+ uintptr(parent),
+ uintptr(menu),
+ uintptr(instance),
+ uintptr(param))
+
+ return HWND(ret)
+}
+
+func AdjustWindowRectEx(rect *RECT, style uint, menu bool, exStyle uint) bool {
+ ret, _, _ := procAdjustWindowRectEx.Call(
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(style),
+ uintptr(BoolToBOOL(menu)),
+ uintptr(exStyle))
+
+ return ret != 0
+}
+
+func AdjustWindowRect(rect *RECT, style uint, menu bool) bool {
+ ret, _, _ := procAdjustWindowRect.Call(
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(style),
+ uintptr(BoolToBOOL(menu)))
+
+ return ret != 0
+}
+
+func DestroyWindow(hwnd HWND) bool {
+ ret, _, _ := procDestroyWindow.Call(hwnd)
+ return ret != 0
+}
+
+func HasGetDpiForWindowFunc() bool {
+ err := procGetDpiForWindow.Find()
+ return err == nil
+}
+
+func GetDpiForWindow(hwnd HWND) UINT {
+ dpi, _, _ := procGetDpiForWindow.Call(hwnd)
+ return uint(dpi)
+}
+
+func HasSetProcessDPIAwareFunc() bool {
+ err := procSetProcessDPIAware.Find()
+ return err == nil
+}
+
+func GetClassName(hwnd HWND) string {
+ var buf [256]uint16
+ procGetClassName.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(len(buf)))
+
+ return syscall.UTF16ToString(buf[:])
+}
+
+func SetProcessDPIAware() error {
+ status, r, err := procSetProcessDPIAware.Call()
+ if status == 0 {
+ return fmt.Errorf("SetProcessDPIAware failed %d: %v %v", status, r, err)
+ }
+ return nil
+}
+
+func HasSetProcessDpiAwarenessContextFunc() bool {
+ err := procSetProcessDpiAwarenessContext.Find()
+ return err == nil
+}
+
+func SetProcessDpiAwarenessContext(ctx uintptr) error {
+ status, r, err := procSetProcessDpiAwarenessContext.Call(ctx)
+ if status == 0 {
+ return fmt.Errorf("SetProcessDpiAwarenessContext failed %d: %v %v", status, r, err)
+ }
+ return nil
+}
+
+func GetForegroundWindow() HWND {
+ ret, _, _ := procGetForegroundWindow.Call()
+ return HWND(ret)
+}
+
+func SetWindowCompositionAttribute(hwnd HWND, data *WINDOWCOMPOSITIONATTRIBDATA) bool {
+ if procSetWindowCompositionAttribute != nil {
+ ret, _, _ := procSetWindowCompositionAttribute.Call(
+ hwnd,
+ uintptr(unsafe.Pointer(data)),
+ )
+ return ret != 0
+ }
+ return false
+}
+
+func DefWindowProc(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr {
+ ret, _, _ := procDefWindowProc.Call(
+ uintptr(hwnd),
+ uintptr(msg),
+ wParam,
+ lParam)
+
+ return ret
+}
+
+func DefDlgProc(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr {
+ ret, _, _ := procDefDlgProc.Call(
+ uintptr(hwnd),
+ uintptr(msg),
+ wParam,
+ lParam)
+
+ return ret
+}
+
+func PostQuitMessage(exitCode int) {
+ procPostQuitMessage.Call(
+ uintptr(exitCode))
+}
+
+func GetMessage(msg *MSG, hwnd HWND, msgFilterMin, msgFilterMax uint32) int {
+ ret, _, _ := procGetMessage.Call(
+ uintptr(unsafe.Pointer(msg)),
+ uintptr(hwnd),
+ uintptr(msgFilterMin),
+ uintptr(msgFilterMax))
+
+ return int(ret)
+}
+
+func TranslateMessage(msg *MSG) bool {
+ ret, _, _ := procTranslateMessage.Call(
+ uintptr(unsafe.Pointer(msg)))
+
+ return ret != 0
+
+}
+
+func DispatchMessage(msg *MSG) uintptr {
+ ret, _, _ := procDispatchMessage.Call(
+ uintptr(unsafe.Pointer(msg)))
+
+ return ret
+
+}
+
+func SendMessage(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr {
+ ret, _, _ := procSendMessage.Call(
+ uintptr(hwnd),
+ uintptr(msg),
+ wParam,
+ lParam)
+
+ return ret
+}
+
+func PostMessage(hwnd HWND, msg uint32, wParam, lParam uintptr) bool {
+ ret, _, _ := procPostMessage.Call(
+ uintptr(hwnd),
+ uintptr(msg),
+ wParam,
+ lParam)
+
+ return ret != 0
+}
+
+func WaitMessage() bool {
+ ret, _, _ := procWaitMessage.Call()
+ return ret != 0
+}
+
+func SetWindowText(hwnd HWND, text string) {
+ procSetWindowText.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))))
+}
+
+func GetWindowTextLength(hwnd HWND) int {
+ ret, _, _ := procGetWindowTextLength.Call(
+ uintptr(hwnd))
+
+ return int(ret)
+}
+
+func GetWindowInfo(hwnd HWND, info *WINDOWINFO) int {
+ ret, _, _ := procGetWindowInfo.Call(
+ hwnd,
+ uintptr(unsafe.Pointer(info)),
+ )
+ return int(ret)
+}
+
+func GetWindow(hwnd HWND, cmd uint32) HWND {
+ ret, _, _ := procGetWindow.Call(
+ hwnd,
+ uintptr(cmd),
+ )
+ return HWND(ret)
+}
+
+func GetWindowText(hwnd HWND) string {
+ textLen := GetWindowTextLength(hwnd) + 1
+
+ buf := make([]uint16, textLen)
+ procGetWindowText.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(textLen))
+
+ return syscall.UTF16ToString(buf)
+}
+
+func GetWindowRect(hwnd HWND) *RECT {
+ var rect RECT
+ procGetWindowRect.Call(
+ hwnd,
+ uintptr(unsafe.Pointer(&rect)))
+
+ return &rect
+}
+
+func MoveWindow(hwnd HWND, x, y, width, height int, repaint bool) bool {
+ ret, _, _ := procMoveWindow.Call(
+ uintptr(hwnd),
+ uintptr(x),
+ uintptr(y),
+ uintptr(width),
+ uintptr(height),
+ uintptr(BoolToBOOL(repaint)))
+
+ return ret != 0
+
+}
+
+func ScreenToClient(hwnd HWND, x, y int) (X, Y int, ok bool) {
+ pt := POINT{X: int32(x), Y: int32(y)}
+ ret, _, _ := procScreenToClient.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(&pt)))
+
+ return int(pt.X), int(pt.Y), ret != 0
+}
+
+func CallWindowProc(preWndProc uintptr, hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr {
+ ret, _, _ := procCallWindowProc.Call(
+ preWndProc,
+ uintptr(hwnd),
+ uintptr(msg),
+ wParam,
+ lParam)
+
+ return ret
+}
+
+func SetWindowLong(hwnd HWND, index int, value uint32) uint32 {
+ ret, _, _ := procSetWindowLong.Call(
+ uintptr(hwnd),
+ uintptr(index),
+ uintptr(value))
+
+ return uint32(ret)
+}
+
+func SetWindowLongPtr(hwnd HWND, index int, value uintptr) uintptr {
+ ret, _, _ := procSetWindowLongPtr.Call(
+ uintptr(hwnd),
+ uintptr(index),
+ value)
+
+ return ret
+}
+
+func GetWindowLong(hwnd HWND, index int) int32 {
+ ret, _, _ := procGetWindowLong.Call(
+ uintptr(hwnd),
+ uintptr(index))
+
+ return int32(ret)
+}
+
+func GetWindowLongPtr(hwnd HWND, index int) uintptr {
+ ret, _, _ := procGetWindowLongPtr.Call(
+ uintptr(hwnd),
+ uintptr(index))
+
+ return ret
+}
+
+func EnableWindow(hwnd HWND, b bool) bool {
+ ret, _, _ := procEnableWindow.Call(
+ uintptr(hwnd),
+ uintptr(BoolToBOOL(b)))
+ return ret != 0
+}
+
+func IsWindowEnabled(hwnd HWND) bool {
+ ret, _, _ := procIsWindowEnabled.Call(
+ uintptr(hwnd))
+
+ return ret != 0
+}
+
+func IsWindowVisible(hwnd HWND) bool {
+ ret, _, _ := procIsWindowVisible.Call(
+ uintptr(hwnd))
+
+ return ret != 0
+}
+
+func SetFocus(hwnd HWND) HWND {
+ ret, _, _ := procSetFocus.Call(
+ uintptr(hwnd))
+
+ return HWND(ret)
+}
+
+func SetActiveWindow(hwnd HWND) HWND {
+ ret, _, _ := procSetActiveWindow.Call(
+ uintptr(hwnd))
+
+ return HWND(ret)
+}
+
+func BringWindowToTop(hwnd HWND) bool {
+ ret, _, _ := procBringWindowToTop.Call(uintptr(hwnd))
+ return ret != 0
+}
+
+func SetForegroundWindow(hwnd HWND) HWND {
+ ret, _, _ := procSetForegroundWindow.Call(
+ uintptr(hwnd))
+
+ return HWND(ret)
+}
+
+func GetFocus() HWND {
+ ret, _, _ := procGetFocus.Call()
+ return HWND(ret)
+}
+
+func InvalidateRect(hwnd HWND, rect *RECT, erase bool) bool {
+ ret, _, _ := procInvalidateRect.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(BoolToBOOL(erase)))
+
+ return ret != 0
+}
+
+func GetClientRect(hwnd HWND) *RECT {
+ var rect RECT
+ ret, _, _ := procGetClientRect.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(&rect)))
+
+ if ret == 0 {
+ panic(fmt.Sprintf("GetClientRect(%d) failed", hwnd))
+ }
+
+ return &rect
+}
+
+func GetDC(hwnd HWND) HDC {
+ ret, _, _ := procGetDC.Call(
+ uintptr(hwnd))
+
+ return HDC(ret)
+}
+
+func ReleaseDC(hwnd HWND, hDC HDC) bool {
+ ret, _, _ := procReleaseDC.Call(
+ uintptr(hwnd),
+ uintptr(hDC))
+
+ return ret != 0
+}
+
+func SetCapture(hwnd HWND) HWND {
+ ret, _, _ := procSetCapture.Call(
+ uintptr(hwnd))
+
+ return HWND(ret)
+}
+
+func ReleaseCapture() bool {
+ ret, _, _ := procReleaseCapture.Call()
+
+ return ret != 0
+}
+
+func EnumWindows(enumFunc uintptr, lparam uintptr) bool {
+ ret, _, _ := procEnumWindows.Call(
+ enumFunc,
+ lparam)
+
+ return ret != 0
+}
+
+func GetWindowThreadProcessId(hwnd HWND) (HANDLE, int) {
+ var processId int
+ ret, _, _ := procGetWindowThreadProcessId.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(&processId)))
+
+ return HANDLE(ret), processId
+}
+
+func MessageBox(hwnd HWND, title, caption string, flags uint) int {
+ ret, _, _ := procMessageBox.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(title))),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))),
+ uintptr(flags))
+
+ return int(ret)
+}
+
+func GetSystemMetrics(index int) int {
+ ret, _, _ := procGetSystemMetrics.Call(
+ uintptr(index))
+
+ return int(ret)
+}
+
+func GetSysColorBrush(nIndex int) HBRUSH {
+ ret, _, _ := procGetSysColorBrush.Call(1,
+ uintptr(nIndex),
+ 0,
+ 0)
+
+ return HBRUSH(ret)
+}
+
+func GetSysColor(nIndex int) COLORREF {
+ ret, _, _ := procGetSysColor.Call(
+ uintptr(nIndex))
+
+ return COLORREF(ret)
+}
+
+func CopyRect(dst, src *RECT) bool {
+ ret, _, _ := procCopyRect.Call(
+ uintptr(unsafe.Pointer(dst)),
+ uintptr(unsafe.Pointer(src)))
+
+ return ret != 0
+}
+
+func EqualRect(rect1, rect2 *RECT) bool {
+ ret, _, _ := procEqualRect.Call(
+ uintptr(unsafe.Pointer(rect1)),
+ uintptr(unsafe.Pointer(rect2)))
+
+ return ret != 0
+}
+
+func InflateRect(rect *RECT, dx, dy int) bool {
+ ret, _, _ := procInflateRect.Call(
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(dx),
+ uintptr(dy))
+
+ return ret != 0
+}
+
+func IntersectRect(dst, src1, src2 *RECT) bool {
+ ret, _, _ := procIntersectRect.Call(
+ uintptr(unsafe.Pointer(dst)),
+ uintptr(unsafe.Pointer(src1)),
+ uintptr(unsafe.Pointer(src2)))
+
+ return ret != 0
+}
+
+func IsRectEmpty(rect *RECT) bool {
+ ret, _, _ := procIsRectEmpty.Call(
+ uintptr(unsafe.Pointer(rect)))
+
+ return ret != 0
+}
+
+func OffsetRect(rect *RECT, dx, dy int) bool {
+ ret, _, _ := procOffsetRect.Call(
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(dx),
+ uintptr(dy))
+
+ return ret != 0
+}
+
+func PtInRect(rect *RECT, x, y int) bool {
+ pt := POINT{X: int32(x), Y: int32(y)}
+ ret, _, _ := procPtInRect.Call(
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(unsafe.Pointer(&pt)))
+
+ return ret != 0
+}
+
+func RectInRect(rect1, rect2 *RECT) bool {
+ return rect1.Left >= rect2.Left && rect1.Right <= rect2.Right &&
+ rect1.Top >= rect2.Top && rect1.Bottom <= rect2.Bottom
+}
+
+func SetRect(rect *RECT, left, top, right, bottom int) bool {
+ ret, _, _ := procSetRect.Call(
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(left),
+ uintptr(top),
+ uintptr(right),
+ uintptr(bottom))
+
+ return ret != 0
+}
+
+func SetRectEmpty(rect *RECT) bool {
+ ret, _, _ := procSetRectEmpty.Call(
+ uintptr(unsafe.Pointer(rect)))
+
+ return ret != 0
+}
+
+func SubtractRect(dst, src1, src2 *RECT) bool {
+ ret, _, _ := procSubtractRect.Call(
+ uintptr(unsafe.Pointer(dst)),
+ uintptr(unsafe.Pointer(src1)),
+ uintptr(unsafe.Pointer(src2)))
+
+ return ret != 0
+}
+
+func UnionRect(dst, src1, src2 *RECT) bool {
+ ret, _, _ := procUnionRect.Call(
+ uintptr(unsafe.Pointer(dst)),
+ uintptr(unsafe.Pointer(src1)),
+ uintptr(unsafe.Pointer(src2)))
+
+ return ret != 0
+}
+
+func CreateDialog(hInstance HINSTANCE, lpTemplate *uint16, hWndParent HWND, lpDialogProc uintptr) HWND {
+ ret, _, _ := procCreateDialogParam.Call(
+ uintptr(hInstance),
+ uintptr(unsafe.Pointer(lpTemplate)),
+ uintptr(hWndParent),
+ lpDialogProc,
+ 0)
+
+ return HWND(ret)
+}
+
+func DialogBox(hInstance HINSTANCE, lpTemplateName *uint16, hWndParent HWND, lpDialogProc uintptr) int {
+ ret, _, _ := procDialogBoxParam.Call(
+ uintptr(hInstance),
+ uintptr(unsafe.Pointer(lpTemplateName)),
+ uintptr(hWndParent),
+ lpDialogProc,
+ 0)
+
+ return int(ret)
+}
+
+func GetDlgItem(hDlg HWND, nIDDlgItem int) HWND {
+ ret, _, _ := procGetDlgItem.Call(
+ uintptr(unsafe.Pointer(hDlg)),
+ uintptr(nIDDlgItem))
+
+ return HWND(ret)
+}
+
+func DrawIcon(hDC HDC, x, y int, hIcon HICON) bool {
+ ret, _, _ := procDrawIcon.Call(
+ uintptr(unsafe.Pointer(hDC)),
+ uintptr(x),
+ uintptr(y),
+ uintptr(unsafe.Pointer(hIcon)))
+
+ return ret != 0
+}
+
+func CreateMenu() HMENU {
+ ret, _, _ := procCreateMenu.Call(0,
+ 0,
+ 0,
+ 0)
+
+ return HMENU(ret)
+}
+
+func SetMenu(hWnd HWND, hMenu HMENU) bool {
+
+ ret, _, _ := procSetMenu.Call(hWnd, hMenu)
+ return ret != 0
+}
+
+func AppendMenu(hMenu HMENU, uFlags uint32, uIDNewItem uintptr, lpNewItem *uint16) bool {
+ ret, _, _ := procAppendMenu.Call(
+ hMenu,
+ uintptr(uFlags),
+ uIDNewItem,
+ uintptr(unsafe.Pointer(lpNewItem)))
+
+ return ret != 0
+}
+
+// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-checkmenuradioitem
+func SelectRadioMenuItem(menuID uint16, startID uint16, endID uint16, hwnd HWND) bool {
+ ret, _, _ := procCheckMenuRadioItem.Call(
+ hwnd,
+ uintptr(startID),
+ uintptr(endID),
+ uintptr(menuID),
+ MF_BYCOMMAND)
+ return ret != 0
+
+}
+
+func CreatePopupMenu() PopupMenu {
+ ret, _, _ := procCreatePopupMenu.Call(0,
+ 0,
+ 0,
+ 0)
+
+ return PopupMenu(ret)
+}
+
+func TrackPopupMenuEx(hMenu HMENU, fuFlags uint32, x, y int32, hWnd HWND, lptpm *TPMPARAMS) bool {
+
+ ret, _, _ := procTrackPopupMenuEx.Call(
+ hMenu,
+ uintptr(fuFlags),
+ uintptr(x),
+ uintptr(y),
+ hWnd,
+ uintptr(unsafe.Pointer(lptpm)))
+
+ return ret != 0
+}
+
+func DrawMenuBar(hWnd HWND) bool {
+ ret, _, _ := procDrawMenuBar.Call(hWnd, 0, 0)
+ return ret != 0
+}
+
+func InsertMenuItem(hMenu HMENU, uItem uint32, fByPosition bool, lpmii *MENUITEMINFO) bool {
+ ret, _, _ := procInsertMenuItem.Call(
+ hMenu,
+ uintptr(uItem),
+ uintptr(BoolToBOOL(fByPosition)),
+ uintptr(unsafe.Pointer(lpmii)),
+ 0,
+ 0)
+
+ return ret != 0
+}
+
+func SetMenuItemInfo(hMenu HMENU, uItem uint32, fByPosition bool, lpmii *MENUITEMINFO) bool {
+ ret, _, _ := procSetMenuItemInfo.Call(
+ hMenu,
+ uintptr(uItem),
+ uintptr(BoolToBOOL(fByPosition)),
+ uintptr(unsafe.Pointer(lpmii)),
+ 0,
+ 0)
+
+ return ret != 0
+}
+
+func ClientToScreen(hwnd HWND, x, y int) (int, int) {
+ pt := POINT{X: int32(x), Y: int32(y)}
+
+ procClientToScreen.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(&pt)))
+
+ return int(pt.X), int(pt.Y)
+}
+
+func IsDialogMessage(hwnd HWND, msg *MSG) bool {
+ ret, _, _ := procIsDialogMessage.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(msg)))
+
+ return ret != 0
+}
+
+func IsWindow(hwnd HWND) bool {
+ ret, _, _ := procIsWindow.Call(
+ uintptr(hwnd))
+
+ return ret != 0
+}
+
+func EndDialog(hwnd HWND, nResult uintptr) bool {
+ ret, _, _ := procEndDialog.Call(
+ uintptr(hwnd),
+ nResult)
+
+ return ret != 0
+}
+
+func PeekMessage(lpMsg *MSG, hwnd HWND, wMsgFilterMin, wMsgFilterMax, wRemoveMsg uint32) bool {
+ ret, _, _ := procPeekMessage.Call(
+ uintptr(unsafe.Pointer(lpMsg)),
+ uintptr(hwnd),
+ uintptr(wMsgFilterMin),
+ uintptr(wMsgFilterMax),
+ uintptr(wRemoveMsg))
+
+ return ret != 0
+}
+
+func TranslateAccelerator(hwnd HWND, hAccTable HACCEL, lpMsg *MSG) bool {
+ ret, _, _ := procTranslateMessage.Call(
+ uintptr(hwnd),
+ uintptr(hAccTable),
+ uintptr(unsafe.Pointer(lpMsg)))
+
+ return ret != 0
+}
+
+func SetWindowPos(hwnd, hWndInsertAfter HWND, x, y, cx, cy int, uFlags uint) bool {
+ ret, _, _ := procSetWindowPos.Call(
+ uintptr(hwnd),
+ uintptr(hWndInsertAfter),
+ uintptr(x),
+ uintptr(y),
+ uintptr(cx),
+ uintptr(cy),
+ uintptr(uFlags))
+
+ return ret != 0
+}
+
+func FillRect(hDC HDC, lprc *RECT, hbr HBRUSH) bool {
+ ret, _, _ := procFillRect.Call(
+ uintptr(hDC),
+ uintptr(unsafe.Pointer(lprc)),
+ uintptr(hbr))
+
+ return ret != 0
+}
+
+func DrawText(hDC HDC, text []uint16, uCount int, lpRect *RECT, uFormat uint32) int {
+
+ // Convert the string to a UTF16 pointer
+ // This is necessary because the DrawText function expects a UTF16 pointer
+
+ ret, _, _ := procDrawText.Call(
+ uintptr(hDC),
+ uintptr(unsafe.Pointer(&text[0])),
+ uintptr(uCount),
+ uintptr(unsafe.Pointer(lpRect)),
+ uintptr(uFormat))
+
+ return int(ret)
+}
+
+func AddClipboardFormatListener(hwnd HWND) bool {
+ ret, _, _ := procAddClipboardFormatListener.Call(
+ uintptr(hwnd))
+ return ret != 0
+}
+
+func RemoveClipboardFormatListener(hwnd HWND) bool {
+ ret, _, _ := procRemoveClipboardFormatListener.Call(
+ uintptr(hwnd))
+ return ret != 0
+}
+
+func OpenClipboard(hWndNewOwner HWND) bool {
+ ret, _, _ := procOpenClipboard.Call(
+ uintptr(hWndNewOwner))
+ return ret != 0
+}
+
+func CloseClipboard() bool {
+ ret, _, _ := procCloseClipboard.Call()
+ return ret != 0
+}
+
+func EnumClipboardFormats(format uint) uint {
+ ret, _, _ := procEnumClipboardFormats.Call(
+ uintptr(format))
+ return uint(ret)
+}
+
+func GetClipboardData(uFormat uint) HANDLE {
+ ret, _, _ := procGetClipboardData.Call(
+ uintptr(uFormat))
+ return HANDLE(ret)
+}
+
+func SetClipboardData(uFormat uint, hMem HANDLE) HANDLE {
+ ret, _, _ := procSetClipboardData.Call(
+ uintptr(uFormat),
+ uintptr(hMem))
+ return HANDLE(ret)
+}
+
+func EmptyClipboard() bool {
+ ret, _, _ := procEmptyClipboard.Call()
+ return ret != 0
+}
+
+func GetClipboardFormatName(format uint) (string, bool) {
+ cchMaxCount := 255
+ buf := make([]uint16, cchMaxCount)
+ ret, _, _ := procGetClipboardFormatName.Call(
+ uintptr(format),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(cchMaxCount))
+
+ if ret > 0 {
+ return syscall.UTF16ToString(buf), true
+ }
+
+ return "Requested format does not exist or is predefined", false
+}
+
+func IsClipboardFormatAvailable(format uint) bool {
+ ret, _, _ := procIsClipboardFormatAvailable.Call(uintptr(format))
+ return ret != 0
+}
+
+func BeginPaint(hwnd HWND, paint *PAINTSTRUCT) HDC {
+ ret, _, _ := procBeginPaint.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(paint)))
+ return HDC(ret)
+}
+
+func EndPaint(hwnd HWND, paint *PAINTSTRUCT) {
+ procEndPaint.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(paint)))
+}
+
+func GetKeyboardState(keyState []byte) bool {
+ if len(keyState) != 256 {
+ panic("keyState slice must have a size of 256 bytes")
+ }
+ ret, _, _ := procGetKeyboardState.Call(uintptr(unsafe.Pointer(&keyState[0])))
+ return ret != 0
+}
+
+func MapVirtualKeyEx(uCode, uMapType uint, dwhkl HKL) uint {
+ ret, _, _ := procMapVirtualKeyEx.Call(
+ uintptr(uCode),
+ uintptr(uMapType),
+ uintptr(dwhkl))
+ return uint(ret)
+}
+
+func MapVirtualKey(uCode uint, uMapType uint) uint {
+ ret, _, _ := procMapVirtualKey.Call(uintptr(uCode), uintptr(uMapType))
+ return uint(ret)
+}
+
+func GetAsyncKeyState(vKey int) uint16 {
+ ret, _, _ := procGetAsyncKeyState.Call(uintptr(vKey))
+ return uint16(ret)
+}
+
+func ToAscii(uVirtKey, uScanCode uint, lpKeyState *byte, lpChar *uint16, uFlags uint) int {
+ ret, _, _ := procToAscii.Call(
+ uintptr(uVirtKey),
+ uintptr(uScanCode),
+ uintptr(unsafe.Pointer(lpKeyState)),
+ uintptr(unsafe.Pointer(lpChar)),
+ uintptr(uFlags))
+ return int(ret)
+}
+
+func SwapMouseButton(fSwap bool) bool {
+ ret, _, _ := procSwapMouseButton.Call(
+ uintptr(BoolToBOOL(fSwap)))
+ return ret != 0
+}
+
+func GetCursorPos() (x, y int, ok bool) {
+ pt := POINT{}
+ ret, _, _ := procGetCursorPos.Call(uintptr(unsafe.Pointer(&pt)))
+ return int(pt.X), int(pt.Y), ret != 0
+}
+
+func SetCursorPos(x, y int) bool {
+ ret, _, _ := procSetCursorPos.Call(
+ uintptr(x),
+ uintptr(y),
+ )
+ return ret != 0
+}
+
+func SetCursor(cursor HCURSOR) HCURSOR {
+ ret, _, _ := procSetCursor.Call(
+ uintptr(cursor),
+ )
+ return HCURSOR(ret)
+}
+
+func CreateIcon(instance HINSTANCE, nWidth, nHeight int, cPlanes, cBitsPerPixel byte, ANDbits, XORbits *byte) HICON {
+ ret, _, _ := procCreateIcon.Call(
+ uintptr(instance),
+ uintptr(nWidth),
+ uintptr(nHeight),
+ uintptr(cPlanes),
+ uintptr(cBitsPerPixel),
+ uintptr(unsafe.Pointer(ANDbits)),
+ uintptr(unsafe.Pointer(XORbits)),
+ )
+ return HICON(ret)
+}
+
+func DestroyIcon(icon HICON) bool {
+ ret, _, _ := procDestroyIcon.Call(
+ uintptr(icon),
+ )
+ return ret != 0
+}
+
+func MonitorFromPoint(x, y int, dwFlags uint32) HMONITOR {
+ ret, _, _ := procMonitorFromPoint.Call(
+ uintptr(x),
+ uintptr(y),
+ uintptr(dwFlags),
+ )
+ return HMONITOR(ret)
+}
+
+func MonitorFromRect(rc *RECT, dwFlags uint32) HMONITOR {
+ ret, _, _ := procMonitorFromRect.Call(
+ uintptr(unsafe.Pointer(rc)),
+ uintptr(dwFlags),
+ )
+ return HMONITOR(ret)
+}
+
+func MonitorFromWindow(hwnd HWND, dwFlags uint32) HMONITOR {
+ ret, _, _ := procMonitorFromWindow.Call(
+ uintptr(hwnd),
+ uintptr(dwFlags),
+ )
+ return HMONITOR(ret)
+}
+
+func GetMonitorInfo(hMonitor HMONITOR, lmpi *MONITORINFO) bool {
+ ret, _, _ := procGetMonitorInfo.Call(
+ uintptr(hMonitor),
+ uintptr(unsafe.Pointer(lmpi)),
+ )
+ return ret != 0
+}
+
+func GetMonitorInfoEx(hMonitor HMONITOR, lmpi *MONITORINFOEX) bool {
+ ret, _, _ := procGetMonitorInfo.Call(
+ uintptr(hMonitor),
+ uintptr(unsafe.Pointer(lmpi)),
+ )
+ return ret != 0
+}
+
+func EnumDisplayMonitors(hdc HDC, clip *RECT, fnEnum uintptr, dwData unsafe.Pointer) bool {
+ ret, _, _ := procEnumDisplayMonitors.Call(
+ hdc,
+ uintptr(unsafe.Pointer(clip)),
+ fnEnum,
+ uintptr(dwData),
+ )
+ return ret != 0
+}
+
+func EnumDisplaySettingsEx(szDeviceName *uint16, iModeNum uint32, devMode *DEVMODE, dwFlags uint32) bool {
+ ret, _, _ := procEnumDisplaySettingsEx.Call(
+ uintptr(unsafe.Pointer(szDeviceName)),
+ uintptr(iModeNum),
+ uintptr(unsafe.Pointer(devMode)),
+ uintptr(dwFlags),
+ )
+ return ret != 0
+}
+
+func ChangeDisplaySettingsEx(szDeviceName *uint16, devMode *DEVMODE, hwnd HWND, dwFlags uint32, lParam uintptr) int32 {
+ ret, _, _ := procChangeDisplaySettingsEx.Call(
+ uintptr(unsafe.Pointer(szDeviceName)),
+ uintptr(unsafe.Pointer(devMode)),
+ uintptr(hwnd),
+ uintptr(dwFlags),
+ lParam,
+ )
+ return int32(ret)
+}
+
+/*
+func SendInput(inputs []INPUT) uint32 {
+ var validInputs []C.INPUT
+
+ for _, oneInput := range inputs {
+ input := C.INPUT{_type: C.DWORD(oneInput.Type)}
+
+ switch oneInput.Type {
+ case INPUT_MOUSE:
+ (*MouseInput)(unsafe.Pointer(&input)).mi = oneInput.Mi
+ case INPUT_KEYBOARD:
+ (*KbdInput)(unsafe.Pointer(&input)).ki = oneInput.Ki
+ case INPUT_HARDWARE:
+ (*HardwareInput)(unsafe.Pointer(&input)).hi = oneInput.Hi
+ default:
+ panic("unkown type")
+ }
+
+ validInputs = append(validInputs, input)
+ }
+
+ ret, _, _ := procSendInput.Call(
+ uintptr(len(validInputs)),
+ uintptr(unsafe.Pointer(&validInputs[0])),
+ uintptr(unsafe.Sizeof(C.INPUT{})),
+ )
+ return uint32(ret)
+}*/
+
+func SetWindowsHookEx(idHook int, lpfn HOOKPROC, hMod HINSTANCE, dwThreadId DWORD) HHOOK {
+ ret, _, _ := procSetWindowsHookEx.Call(
+ uintptr(idHook),
+ uintptr(syscall.NewCallback(lpfn)),
+ uintptr(hMod),
+ uintptr(dwThreadId),
+ )
+ return HHOOK(ret)
+}
+
+func UnhookWindowsHookEx(hhk HHOOK) bool {
+ ret, _, _ := procUnhookWindowsHookEx.Call(
+ uintptr(hhk),
+ )
+ return ret != 0
+}
+
+func CallNextHookEx(hhk HHOOK, nCode int, wParam WPARAM, lParam LPARAM) LRESULT {
+ ret, _, _ := procCallNextHookEx.Call(
+ uintptr(hhk),
+ uintptr(nCode),
+ uintptr(wParam),
+ uintptr(lParam),
+ )
+ return LRESULT(ret)
+}
+
+func GetKeyState(nVirtKey int32) int16 {
+ ret, _, _ := procGetKeyState.Call(
+ uintptr(nVirtKey),
+ 0,
+ 0)
+
+ return int16(ret)
+}
+
+func DestroyMenu(hMenu HMENU) bool {
+ ret, _, _ := procDestroyMenu.Call(1,
+ uintptr(hMenu),
+ 0,
+ 0)
+
+ return ret != 0
+}
+
+func GetWindowPlacement(hWnd HWND, lpwndpl *WINDOWPLACEMENT) bool {
+ ret, _, _ := procGetWindowPlacement.Call(
+ uintptr(hWnd),
+ uintptr(unsafe.Pointer(lpwndpl)),
+ 0)
+
+ return ret != 0
+}
+
+func SetWindowPlacement(hWnd HWND, lpwndpl *WINDOWPLACEMENT) bool {
+ ret, _, _ := procSetWindowPlacement.Call(
+ uintptr(hWnd),
+ uintptr(unsafe.Pointer(lpwndpl)),
+ 0)
+
+ return ret != 0
+}
+
+func SetScrollInfo(hwnd HWND, fnBar int32, lpsi *SCROLLINFO, fRedraw bool) int32 {
+ ret, _, _ := procSetScrollInfo.Call(
+ hwnd,
+ uintptr(fnBar),
+ uintptr(unsafe.Pointer(lpsi)),
+ uintptr(BoolToBOOL(fRedraw)),
+ 0,
+ 0)
+
+ return int32(ret)
+}
+
+func GetScrollInfo(hwnd HWND, fnBar int32, lpsi *SCROLLINFO) bool {
+ ret, _, _ := procGetScrollInfo.Call(
+ hwnd,
+ uintptr(fnBar),
+ uintptr(unsafe.Pointer(lpsi)))
+
+ return ret != 0
+}
+
+func RedrawWindow(hwnd HWND, lprcUpdate *RECT, hrgnUpdate HRGN, flags uint32) bool {
+ ret, _, _ := procRedrawWindow.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(lprcUpdate)),
+ uintptr(hrgnUpdate),
+ uintptr(flags))
+ return ret != 0
+}
+
+func FrameRect(hDC HDC, lprc *RECT, hbr HBRUSH) int {
+ ret, _, _ := procFrameRect.Call(
+ uintptr(hDC),
+ uintptr(unsafe.Pointer(lprc)),
+ uintptr(hbr))
+ return int(ret)
+}
+
+func GetMenuBarInfo(hwnd HWND, idObject int32, idItem uint32, pmbi *MENUBARINFO) bool {
+ ret, _, _ := procGetMenuBarInfo.Call(
+ uintptr(hwnd),
+ uintptr(idObject),
+ uintptr(idItem),
+ uintptr(unsafe.Pointer(pmbi)))
+ return ret != 0
+}
+
+func MapWindowPoints(hwndFrom, hwndTo HWND, lpPoints *POINT, cPoints uint) int {
+ ret, _, _ := procMapWindowPoints.Call(
+ uintptr(hwndFrom),
+ uintptr(hwndTo),
+ uintptr(unsafe.Pointer(lpPoints)),
+ uintptr(cPoints))
+ return int(ret)
+}
+
+func TrackPopupMenu(hmenu HMENU, flags uint32, x, y int32, reserved int32, hwnd HWND, prcRect *RECT) bool {
+ ret, _, _ := procTrackPopupMenu.Call(
+ uintptr(hmenu),
+ uintptr(flags),
+ uintptr(x),
+ uintptr(y),
+ uintptr(reserved),
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(prcRect)))
+ return ret != 0
+}
+
+// KeybdEvent synthesizes a keystroke. The system can use such a synthesized keystroke to generate a WM_KEYUP or WM_KEYDOWN message.
+// bVk: Virtual-key code
+// bScan: Hardware scan code
+// dwFlags: Controls various aspects of function operation (KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP)
+// dwExtraInfo: Additional value associated with the keystroke
+func KeybdEvent(bVk byte, bScan byte, dwFlags uint32, dwExtraInfo uintptr) {
+ procKeybdEvent.Call(
+ uintptr(bVk),
+ uintptr(bScan),
+ uintptr(dwFlags),
+ dwExtraInfo,
+ )
+}
diff --git a/v3/pkg/w32/utils.go b/v3/pkg/w32/utils.go
new file mode 100644
index 000000000..f4e99dbaf
--- /dev/null
+++ b/v3/pkg/w32/utils.go
@@ -0,0 +1,637 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+
+package w32
+
+import (
+ "fmt"
+ "syscall"
+ "unicode/utf16"
+ "unsafe"
+)
+
+func MustLoadLibrary(name string) uintptr {
+ lib, err := syscall.LoadLibrary(name)
+ if err != nil {
+ panic(err)
+ }
+
+ return uintptr(lib)
+}
+
+func MustGetProcAddress(lib uintptr, name string) uintptr {
+ addr, err := syscall.GetProcAddress(syscall.Handle(lib), name)
+ if err != nil {
+ panic(err)
+ }
+
+ return uintptr(addr)
+}
+
+func SUCCEEDED(hr HRESULT) bool {
+ return hr >= 0
+}
+
+func FAILED(hr HRESULT) bool {
+ return hr < 0
+}
+
+func LOWORD(dw uint32) uint16 {
+ return uint16(dw)
+}
+
+func HIWORD(dw uint32) uint16 {
+ return uint16(dw >> 16 & 0xffff)
+}
+
+func MAKELONG(lo, hi uint16) uint32 {
+ return uint32(uint32(lo) | ((uint32(hi)) << 16))
+}
+
+func BoolToBOOL(value bool) BOOL {
+ if value {
+ return 1
+ }
+
+ return 0
+}
+
+func UTF16PtrToString(cstr *uint16) string {
+ if cstr != nil {
+ us := make([]uint16, 0, 256)
+ for p := uintptr(unsafe.Pointer(cstr)); ; p += 2 {
+ u := *(*uint16)(unsafe.Pointer(p))
+ if u == 0 {
+ return string(utf16.Decode(us))
+ }
+ us = append(us, u)
+ }
+ }
+
+ return ""
+}
+
+func ComAddRef(unknown *IUnknown) int32 {
+ ret, _, _ := syscall.SyscallN(uintptr(unknown.Vtbl.AddRef),
+ uintptr(unsafe.Pointer(unknown)),
+ 0,
+ 0)
+ return int32(ret)
+}
+
+func ComRelease(unknown *IUnknown) int32 {
+ ret, _, _ := syscall.SyscallN(uintptr(unknown.Vtbl.Release),
+ uintptr(unsafe.Pointer(unknown)),
+ 0,
+ 0)
+ return int32(ret)
+}
+
+func ComQueryInterface(unknown *IUnknown, id *GUID) *IDispatch {
+ var disp *IDispatch
+ hr, _, _ := syscall.SyscallN(uintptr(unknown.Vtbl.QueryInterface),
+ uintptr(unsafe.Pointer(unknown)),
+ uintptr(unsafe.Pointer(id)),
+ uintptr(unsafe.Pointer(&disp)))
+ if hr != 0 {
+ panic("Invoke QieryInterface error.")
+ }
+ return disp
+}
+
+func ComGetIDsOfName(disp *IDispatch, names []string) []int32 {
+ wnames := make([]*uint16, len(names))
+ dispid := make([]int32, len(names))
+ for i := 0; i < len(names); i++ {
+ wnames[i] = syscall.StringToUTF16Ptr(names[i])
+ }
+ hr, _, _ := syscall.SyscallN(disp.lpVtbl.pGetIDsOfNames,
+ uintptr(unsafe.Pointer(disp)),
+ uintptr(unsafe.Pointer(IID_NULL)),
+ uintptr(unsafe.Pointer(&wnames[0])),
+ uintptr(len(names)),
+ uintptr(GetUserDefaultLCID()),
+ uintptr(unsafe.Pointer(&dispid[0])))
+ if hr != 0 {
+ panic("Invoke GetIDsOfName error.")
+ }
+ return dispid
+}
+
+func ComInvoke(disp *IDispatch, dispid int32, dispatch int16, params ...interface{}) (result *VARIANT) {
+ var dispparams DISPPARAMS
+
+ if dispatch&DISPATCH_PROPERTYPUT != 0 {
+ dispnames := [1]int32{DISPID_PROPERTYPUT}
+ dispparams.RgdispidNamedArgs = uintptr(unsafe.Pointer(&dispnames[0]))
+ dispparams.CNamedArgs = 1
+ }
+ var vargs []VARIANT
+ if len(params) > 0 {
+ vargs = make([]VARIANT, len(params))
+ for i, v := range params {
+ //n := len(params)-i-1
+ n := len(params) - i - 1
+ VariantInit(&vargs[n])
+ switch v.(type) {
+ case bool:
+ if v.(bool) {
+ vargs[n] = VARIANT{VT_BOOL, 0, 0, 0, 0xffff}
+ } else {
+ vargs[n] = VARIANT{VT_BOOL, 0, 0, 0, 0}
+ }
+ case *bool:
+ vargs[n] = VARIANT{VT_BOOL | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*bool))))}
+ case byte:
+ vargs[n] = VARIANT{VT_I1, 0, 0, 0, int64(v.(byte))}
+ case *byte:
+ vargs[n] = VARIANT{VT_I1 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*byte))))}
+ case int16:
+ vargs[n] = VARIANT{VT_I2, 0, 0, 0, int64(v.(int16))}
+ case *int16:
+ vargs[n] = VARIANT{VT_I2 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int16))))}
+ case uint16:
+ vargs[n] = VARIANT{VT_UI2, 0, 0, 0, int64(v.(int16))}
+ case *uint16:
+ vargs[n] = VARIANT{VT_UI2 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint16))))}
+ case int, int32:
+ vargs[n] = VARIANT{VT_UI4, 0, 0, 0, int64(v.(int))}
+ case *int, *int32:
+ vargs[n] = VARIANT{VT_I4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int))))}
+ case uint, uint32:
+ vargs[n] = VARIANT{VT_UI4, 0, 0, 0, int64(v.(uint))}
+ case *uint, *uint32:
+ vargs[n] = VARIANT{VT_UI4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint))))}
+ case int64:
+ vargs[n] = VARIANT{VT_I8, 0, 0, 0, v.(int64)}
+ case *int64:
+ vargs[n] = VARIANT{VT_I8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int64))))}
+ case uint64:
+ vargs[n] = VARIANT{VT_UI8, 0, 0, 0, int64(v.(uint64))}
+ case *uint64:
+ vargs[n] = VARIANT{VT_UI8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint64))))}
+ case float32:
+ vargs[n] = VARIANT{VT_R4, 0, 0, 0, int64(v.(float32))}
+ case *float32:
+ vargs[n] = VARIANT{VT_R4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*float32))))}
+ case float64:
+ vargs[n] = VARIANT{VT_R8, 0, 0, 0, int64(v.(float64))}
+ case *float64:
+ vargs[n] = VARIANT{VT_R8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*float64))))}
+ case string:
+ vargs[n] = VARIANT{VT_BSTR, 0, 0, 0, int64(uintptr(unsafe.Pointer(SysAllocString(v.(string)))))}
+ case *string:
+ vargs[n] = VARIANT{VT_BSTR | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*string))))}
+ case *IDispatch:
+ vargs[n] = VARIANT{VT_DISPATCH, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*IDispatch))))}
+ case **IDispatch:
+ vargs[n] = VARIANT{VT_DISPATCH | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(**IDispatch))))}
+ case nil:
+ vargs[n] = VARIANT{VT_NULL, 0, 0, 0, 0}
+ case *VARIANT:
+ vargs[n] = VARIANT{VT_VARIANT | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*VARIANT))))}
+ default:
+ panic("unknown type")
+ }
+ }
+ dispparams.Rgvarg = uintptr(unsafe.Pointer(&vargs[0]))
+ dispparams.CArgs = uint32(len(params))
+ }
+
+ var ret VARIANT
+ var excepInfo EXCEPINFO
+ VariantInit(&ret)
+ hr, _, _ := syscall.SyscallN(disp.lpVtbl.pInvoke,
+ uintptr(unsafe.Pointer(disp)),
+ uintptr(dispid),
+ uintptr(unsafe.Pointer(IID_NULL)),
+ uintptr(GetUserDefaultLCID()),
+ uintptr(dispatch),
+ uintptr(unsafe.Pointer(&dispparams)),
+ uintptr(unsafe.Pointer(&ret)),
+ uintptr(unsafe.Pointer(&excepInfo)),
+ 0)
+ if hr != 0 {
+ if excepInfo.BstrDescription != nil {
+ bs := UTF16PtrToString(excepInfo.BstrDescription)
+ panic(bs)
+ }
+ }
+ for _, varg := range vargs {
+ if varg.VT == VT_BSTR && varg.Val != 0 {
+ SysFreeString(((*int16)(unsafe.Pointer(uintptr(varg.Val)))))
+ }
+ }
+ result = &ret
+ return
+}
+
+func WMMessageToString(msg uintptr) string {
+ // Convert windows message to string
+ switch msg {
+ case WM_APP:
+ return "WM_APP"
+ case WM_ACTIVATE:
+ return "WM_ACTIVATE"
+ case WM_ACTIVATEAPP:
+ return "WM_ACTIVATEAPP"
+ case WM_AFXFIRST:
+ return "WM_AFXFIRST"
+ case WM_AFXLAST:
+ return "WM_AFXLAST"
+ case WM_ASKCBFORMATNAME:
+ return "WM_ASKCBFORMATNAME"
+ case WM_CANCELJOURNAL:
+ return "WM_CANCELJOURNAL"
+ case WM_CANCELMODE:
+ return "WM_CANCELMODE"
+ case WM_CAPTURECHANGED:
+ return "WM_CAPTURECHANGED"
+ case WM_CHANGECBCHAIN:
+ return "WM_CHANGECBCHAIN"
+ case WM_CHAR:
+ return "WM_CHAR"
+ case WM_CHARTOITEM:
+ return "WM_CHARTOITEM"
+ case WM_CHILDACTIVATE:
+ return "WM_CHILDACTIVATE"
+ case WM_CLEAR:
+ return "WM_CLEAR"
+ case WM_CLOSE:
+ return "WM_CLOSE"
+ case WM_COMMAND:
+ return "WM_COMMAND"
+ case WM_COMMNOTIFY /* OBSOLETE */ :
+ return "WM_COMMNOTIFY"
+ case WM_COMPACTING:
+ return "WM_COMPACTING"
+ case WM_COMPAREITEM:
+ return "WM_COMPAREITEM"
+ case WM_CONTEXTMENU:
+ return "WM_CONTEXTMENU"
+ case WM_COPY:
+ return "WM_COPY"
+ case WM_COPYDATA:
+ return "WM_COPYDATA"
+ case WM_CREATE:
+ return "WM_CREATE"
+ case WM_CTLCOLORBTN:
+ return "WM_CTLCOLORBTN"
+ case WM_CTLCOLORDLG:
+ return "WM_CTLCOLORDLG"
+ case WM_CTLCOLOREDIT:
+ return "WM_CTLCOLOREDIT"
+ case WM_CTLCOLORLISTBOX:
+ return "WM_CTLCOLORLISTBOX"
+ case WM_CTLCOLORMSGBOX:
+ return "WM_CTLCOLORMSGBOX"
+ case WM_CTLCOLORSCROLLBAR:
+ return "WM_CTLCOLORSCROLLBAR"
+ case WM_CTLCOLORSTATIC:
+ return "WM_CTLCOLORSTATIC"
+ case WM_CUT:
+ return "WM_CUT"
+ case WM_DEADCHAR:
+ return "WM_DEADCHAR"
+ case WM_DELETEITEM:
+ return "WM_DELETEITEM"
+ case WM_DESTROY:
+ return "WM_DESTROY"
+ case WM_DESTROYCLIPBOARD:
+ return "WM_DESTROYCLIPBOARD"
+ case WM_DEVICECHANGE:
+ return "WM_DEVICECHANGE"
+ case WM_DEVMODECHANGE:
+ return "WM_DEVMODECHANGE"
+ case WM_DISPLAYCHANGE:
+ return "WM_DISPLAYCHANGE"
+ case WM_DRAWCLIPBOARD:
+ return "WM_DRAWCLIPBOARD"
+ case WM_DRAWITEM:
+ return "WM_DRAWITEM"
+ case WM_DROPFILES:
+ return "WM_DROPFILES"
+ case WM_ENABLE:
+ return "WM_ENABLE"
+ case WM_ENDSESSION:
+ return "WM_ENDSESSION"
+ case WM_ENTERIDLE:
+ return "WM_ENTERIDLE"
+ case WM_ENTERMENULOOP:
+ return "WM_ENTERMENULOOP"
+ case WM_ENTERSIZEMOVE:
+ return "WM_ENTERSIZEMOVE"
+ case WM_ERASEBKGND:
+ return "WM_ERASEBKGND"
+ case WM_EXITMENULOOP:
+ return "WM_EXITMENULOOP"
+ case WM_EXITSIZEMOVE:
+ return "WM_EXITSIZEMOVE"
+ case WM_FONTCHANGE:
+ return "WM_FONTCHANGE"
+ case WM_GETDLGCODE:
+ return "WM_GETDLGCODE"
+ case WM_GETFONT:
+ return "WM_GETFONT"
+ case WM_GETHOTKEY:
+ return "WM_GETHOTKEY"
+ case WM_GETICON:
+ return "WM_GETICON"
+ case WM_GETMINMAXINFO:
+ return "WM_GETMINMAXINFO"
+ case WM_GETTEXT:
+ return "WM_GETTEXT"
+ case WM_GETTEXTLENGTH:
+ return "WM_GETTEXTLENGTH"
+ case WM_HANDHELDFIRST:
+ return "WM_HANDHELDFIRST"
+ case WM_HANDHELDLAST:
+ return "WM_HANDHELDLAST"
+ case WM_HELP:
+ return "WM_HELP"
+ case WM_HOTKEY:
+ return "WM_HOTKEY"
+ case WM_HSCROLL:
+ return "WM_HSCROLL"
+ case WM_HSCROLLCLIPBOARD:
+ return "WM_HSCROLLCLIPBOARD"
+ case WM_ICONERASEBKGND:
+ return "WM_ICONERASEBKGND"
+ case WM_INITDIALOG:
+ return "WM_INITDIALOG"
+ case WM_INITMENU:
+ return "WM_INITMENU"
+ case WM_INITMENUPOPUP:
+ return "WM_INITMENUPOPUP"
+ case WM_INPUT:
+ return "WM_INPUT"
+ case WM_INPUTLANGCHANGE:
+ return "WM_INPUTLANGCHANGE"
+ case WM_INPUTLANGCHANGEREQUEST:
+ return "WM_INPUTLANGCHANGEREQUEST"
+ case WM_KEYDOWN:
+ return "WM_KEYDOWN"
+ case WM_KEYUP:
+ return "WM_KEYUP"
+ case WM_KILLFOCUS:
+ return "WM_KILLFOCUS"
+ case WM_MDIACTIVATE:
+ return "WM_MDIACTIVATE"
+ case WM_MDICASCADE:
+ return "WM_MDICASCADE"
+ case WM_MDICREATE:
+ return "WM_MDICREATE"
+ case WM_MDIDESTROY:
+ return "WM_MDIDESTROY"
+ case WM_MDIGETACTIVE:
+ return "WM_MDIGETACTIVE"
+ case WM_MDIICONARRANGE:
+ return "WM_MDIICONARRANGE"
+ case WM_MDIMAXIMIZE:
+ return "WM_MDIMAXIMIZE"
+ case WM_MDINEXT:
+ return "WM_MDINEXT"
+ case WM_MDIREFRESHMENU:
+ return "WM_MDIREFRESHMENU"
+ case WM_MDIRESTORE:
+ return "WM_MDIRESTORE"
+ case WM_MDISETMENU:
+ return "WM_MDISETMENU"
+ case WM_MDITILE:
+ return "WM_MDITILE"
+ case WM_MEASUREITEM:
+ return "WM_MEASUREITEM"
+ case WM_GETOBJECT:
+ return "WM_GETOBJECT"
+ case WM_CHANGEUISTATE:
+ return "WM_CHANGEUISTATE"
+ case WM_UPDATEUISTATE:
+ return "WM_UPDATEUISTATE"
+ case WM_QUERYUISTATE:
+ return "WM_QUERYUISTATE"
+ case WM_UNINITMENUPOPUP:
+ return "WM_UNINITMENUPOPUP"
+ case WM_MENURBUTTONUP:
+ return "WM_MENURBUTTONUP"
+ case WM_MENUCOMMAND:
+ return "WM_MENUCOMMAND"
+ case WM_MENUGETOBJECT:
+ return "WM_MENUGETOBJECT"
+ case WM_MENUDRAG:
+ return "WM_MENUDRAG"
+ case WM_APPCOMMAND:
+ return "WM_APPCOMMAND"
+ case WM_MENUCHAR:
+ return "WM_MENUCHAR"
+ case WM_MENUSELECT:
+ return "WM_MENUSELECT"
+ case WM_MOVE:
+ return "WM_MOVE"
+ case WM_MOVING:
+ return "WM_MOVING"
+ case WM_NCACTIVATE:
+ return "WM_NCACTIVATE"
+ case WM_NCCALCSIZE:
+ return "WM_NCCALCSIZE"
+ case WM_NCCREATE:
+ return "WM_NCCREATE"
+ case WM_NCDESTROY:
+ return "WM_NCDESTROY"
+ case WM_NCHITTEST:
+ return "WM_NCHITTEST"
+ case WM_NCLBUTTONDBLCLK:
+ return "WM_NCLBUTTONDBLCLK"
+ case WM_NCLBUTTONDOWN:
+ return "WM_NCLBUTTONDOWN"
+ case WM_NCLBUTTONUP:
+ return "WM_NCLBUTTONUP"
+ case WM_NCMBUTTONDBLCLK:
+ return "WM_NCMBUTTONDBLCLK"
+ case WM_NCMBUTTONDOWN:
+ return "WM_NCMBUTTONDOWN"
+ case WM_NCMBUTTONUP:
+ return "WM_NCMBUTTONUP"
+ case WM_NCXBUTTONDOWN:
+ return "WM_NCXBUTTONDOWN"
+ case WM_NCXBUTTONUP:
+ return "WM_NCXBUTTONUP"
+ case WM_NCXBUTTONDBLCLK:
+ return "WM_NCXBUTTONDBLCLK"
+ case WM_NCMOUSEHOVER:
+ return "WM_NCMOUSEHOVER"
+ case WM_NCMOUSELEAVE:
+ return "WM_NCMOUSELEAVE"
+ case WM_NCMOUSEMOVE:
+ return "WM_NCMOUSEMOVE"
+ case WM_NCPAINT:
+ return "WM_NCPAINT"
+ case WM_NCRBUTTONDBLCLK:
+ return "WM_NCRBUTTONDBLCLK"
+ case WM_NCRBUTTONDOWN:
+ return "WM_NCRBUTTONDOWN"
+ case WM_NCRBUTTONUP:
+ return "WM_NCRBUTTONUP"
+ case WM_NEXTDLGCTL:
+ return "WM_NEXTDLGCTL"
+ case WM_NEXTMENU:
+ return "WM_NEXTMENU"
+ case WM_NOTIFY:
+ return "WM_NOTIFY"
+ case WM_NOTIFYFORMAT:
+ return "WM_NOTIFYFORMAT"
+ case WM_NULL:
+ return "WM_NULL"
+ case WM_PAINT:
+ return "WM_PAINT"
+ case WM_PAINTCLIPBOARD:
+ return "WM_PAINTCLIPBOARD"
+ case WM_PAINTICON:
+ return "WM_PAINTICON"
+ case WM_PALETTECHANGED:
+ return "WM_PALETTECHANGED"
+ case WM_PALETTEISCHANGING:
+ return "WM_PALETTEISCHANGING"
+ case WM_PARENTNOTIFY:
+ return "WM_PARENTNOTIFY"
+ case WM_PASTE:
+ return "WM_PASTE"
+ case WM_PENWINFIRST:
+ return "WM_PENWINFIRST"
+ case WM_PENWINLAST:
+ return "WM_PENWINLAST"
+ case WM_POWER:
+ return "WM_POWER"
+ case WM_PRINT:
+ return "WM_PRINT"
+ case WM_PRINTCLIENT:
+ return "WM_PRINTCLIENT"
+ case WM_QUERYDRAGICON:
+ return "WM_QUERYDRAGICON"
+ case WM_QUERYENDSESSION:
+ return "WM_QUERYENDSESSION"
+ case WM_QUERYNEWPALETTE:
+ return "WM_QUERYNEWPALETTE"
+ case WM_QUERYOPEN:
+ return "WM_QUERYOPEN"
+ case WM_QUEUESYNC:
+ return "WM_QUEUESYNC"
+ case WM_QUIT:
+ return "WM_QUIT"
+ case WM_RENDERALLFORMATS:
+ return "WM_RENDERALLFORMATS"
+ case WM_RENDERFORMAT:
+ return "WM_RENDERFORMAT"
+ case WM_SETCURSOR:
+ return "WM_SETCURSOR"
+ case WM_SETFOCUS:
+ return "WM_SETFOCUS"
+ case WM_SETFONT:
+ return "WM_SETFONT"
+ case WM_SETHOTKEY:
+ return "WM_SETHOTKEY"
+ case WM_SETICON:
+ return "WM_SETICON"
+ case WM_SETREDRAW:
+ return "WM_SETREDRAW"
+ case WM_SETTEXT:
+ return "WM_SETTEXT"
+ case WM_SETTINGCHANGE:
+ return "WM_SETTINGCHANGE"
+ case WM_SHOWWINDOW:
+ return "WM_SHOWWINDOW"
+ case WM_SIZE:
+ return "WM_SIZE"
+ case WM_SIZECLIPBOARD:
+ return "WM_SIZECLIPBOARD"
+ case WM_SIZING:
+ return "WM_SIZING"
+ case WM_SPOOLERSTATUS:
+ return "WM_SPOOLERSTATUS"
+ case WM_STYLECHANGED:
+ return "WM_STYLECHANGED"
+ case WM_STYLECHANGING:
+ return "WM_STYLECHANGING"
+ case WM_SYSCHAR:
+ return "WM_SYSCHAR"
+ case WM_SYSCOLORCHANGE:
+ return "WM_SYSCOLORCHANGE"
+ case WM_SYSCOMMAND:
+ return "WM_SYSCOMMAND"
+ case WM_SYSDEADCHAR:
+ return "WM_SYSDEADCHAR"
+ case WM_SYSKEYDOWN:
+ return "WM_SYSKEYDOWN"
+ case WM_SYSKEYUP:
+ return "WM_SYSKEYUP"
+ case WM_TCARD:
+ return "WM_TCARD"
+ case WM_THEMECHANGED:
+ return "WM_THEMECHANGED"
+ case WM_TIMECHANGE:
+ return "WM_TIMECHANGE"
+ case WM_TIMER:
+ return "WM_TIMER"
+ case WM_UNDO:
+ return "WM_UNDO"
+ case WM_USER:
+ return "WM_USER"
+ case WM_USERCHANGED:
+ return "WM_USERCHANGED"
+ case WM_VKEYTOITEM:
+ return "WM_VKEYTOITEM"
+ case WM_VSCROLL:
+ return "WM_VSCROLL"
+ case WM_VSCROLLCLIPBOARD:
+ return "WM_VSCROLLCLIPBOARD"
+ case WM_WINDOWPOSCHANGED:
+ return "WM_WINDOWPOSCHANGED"
+ case WM_WINDOWPOSCHANGING:
+ return "WM_WINDOWPOSCHANGING"
+ case WM_KEYLAST:
+ return "WM_KEYLAST"
+ case WM_SYNCPAINT:
+ return "WM_SYNCPAINT"
+ case WM_MOUSEACTIVATE:
+ return "WM_MOUSEACTIVATE"
+ case WM_MOUSEMOVE:
+ return "WM_MOUSEMOVE"
+ case WM_LBUTTONDOWN:
+ return "WM_LBUTTONDOWN"
+ case WM_LBUTTONUP:
+ return "WM_LBUTTONUP"
+ case WM_LBUTTONDBLCLK:
+ return "WM_LBUTTONDBLCLK"
+ case WM_RBUTTONDOWN:
+ return "WM_RBUTTONDOWN"
+ case WM_RBUTTONUP:
+ return "WM_RBUTTONUP"
+ case WM_RBUTTONDBLCLK:
+ return "WM_RBUTTONDBLCLK"
+ case WM_MBUTTONDOWN:
+ return "WM_MBUTTONDOWN"
+ case WM_MBUTTONUP:
+ return "WM_MBUTTONUP"
+ case WM_MBUTTONDBLCLK:
+ return "WM_MBUTTONDBLCLK"
+ case WM_MOUSEWHEEL:
+ return "WM_MOUSEWHEEL"
+ case WM_XBUTTONDOWN:
+ return "WM_XBUTTONDOWN"
+ case WM_XBUTTONUP:
+ return "WM_XBUTTONUP"
+ case WM_MOUSELAST:
+ return "WM_MOUSELAST"
+ case WM_MOUSEHOVER:
+ return "WM_MOUSEHOVER"
+ case WM_MOUSELEAVE:
+ return "WM_MOUSELEAVE"
+ case WM_CLIPBOARDUPDATE:
+ return "WM_CLIPBOARDUPDATE"
+ default:
+ return fmt.Sprintf("0x%08x", msg)
+ }
+}
diff --git a/v3/pkg/w32/vars.go b/v3/pkg/w32/vars.go
new file mode 100644
index 000000000..cb69f9d19
--- /dev/null
+++ b/v3/pkg/w32/vars.go
@@ -0,0 +1,16 @@
+//go:build windows
+
+/*
+ * Copyright (C) 2019 Tad Vizbaras. All Rights Reserved.
+ * Copyright (C) 2010-2012 The W32 Authors. All Rights Reserved.
+ */
+
+package w32
+
+var (
+ IID_NULL = &GUID{0x00000000, 0x0000, 0x0000, [8]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}
+ IID_IUnknown = &GUID{0x00000000, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}
+ IID_IDispatch = &GUID{0x00020400, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}
+ IID_IConnectionPointContainer = &GUID{0xB196B284, 0xBAB4, 0x101A, [8]byte{0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}}
+ IID_IConnectionPoint = &GUID{0xB196B286, 0xBAB4, 0x101A, [8]byte{0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}}
+)
diff --git a/v3/pkg/w32/wda.go b/v3/pkg/w32/wda.go
new file mode 100644
index 000000000..0faf91a82
--- /dev/null
+++ b/v3/pkg/w32/wda.go
@@ -0,0 +1,21 @@
+//go:build windows
+
+package w32
+
+const (
+ WDA_NONE = 0x00000000
+ WDA_MONITOR = 0x00000001
+ WDA_EXCLUDEFROMCAPTURE = 0x00000011 // windows 10 2004+
+)
+
+func SetWindowDisplayAffinity(hwnd uintptr, affinity uint32) bool {
+ if affinity == WDA_EXCLUDEFROMCAPTURE && !IsWindowsVersionAtLeast(10, 0, 19041) {
+ // for older windows versions, use WDA_MONITOR
+ affinity = WDA_MONITOR
+ }
+ ret, _, _ := procSetWindowDisplayAffinity.Call(
+ hwnd,
+ uintptr(affinity),
+ )
+ return ret != 0
+}
diff --git a/v3/pkg/w32/window.go b/v3/pkg/w32/window.go
new file mode 100644
index 000000000..c26ec414d
--- /dev/null
+++ b/v3/pkg/w32/window.go
@@ -0,0 +1,377 @@
+//go:build windows
+
+package w32
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "syscall"
+ "unsafe"
+)
+
+var (
+ user32 = syscall.NewLazyDLL("user32.dll")
+ getSystemMenu = user32.NewProc("GetSystemMenu")
+ getMenuProc = user32.NewProc("GetMenu")
+ enableMenuItem = user32.NewProc("EnableMenuItem")
+ findWindow = user32.NewProc("FindWindowW")
+ sendMessage = user32.NewProc("SendMessageW")
+ vkKeyScan = user32.NewProc("VkKeyScanW") // Use W version for Unicode
+)
+
+func VkKeyScan(ch uint16) uint16 {
+ ret, _, _ := syscall.SyscallN(
+ vkKeyScan.Addr(),
+ uintptr(ch),
+ )
+ return uint16(ret)
+}
+
+const (
+ WMCOPYDATA_SINGLE_INSTANCE_DATA = 1542
+)
+
+type COPYDATASTRUCT struct {
+ DwData uintptr
+ CbData uint32
+ LpData uintptr
+}
+
+var Fatal func(error)
+
+const (
+ GCLP_HBRBACKGROUND int32 = -10
+ GCLP_HICON int32 = -14
+)
+
+type WINDOWPOS struct {
+ HwndInsertAfter HWND
+ X int32
+ Y int32
+ Cx int32
+ Cy int32
+ Flags uint32
+}
+
+func ExtendFrameIntoClientArea(hwnd uintptr, extend bool) error {
+ // -1: Adds the default frame styling (aero shadow and e.g. rounded corners on Windows 11)
+ // Also shows the caption buttons if transparent ant translucent but they don't work.
+ // 0: Adds the default frame styling but no aero shadow, does not show the caption buttons.
+ // 1: Adds the default frame styling (aero shadow and e.g. rounded corners on Windows 11) but no caption buttons
+ // are shown if transparent ant translucent.
+ var margins MARGINS
+ if extend {
+ margins = MARGINS{1, 1, 1, 1} // Only extend 1 pixel to have the default frame styling but no caption buttons
+ }
+ if err := dwmExtendFrameIntoClientArea(hwnd, &margins); err != nil {
+ return fmt.Errorf("DwmExtendFrameIntoClientArea failed: %s", err)
+ }
+ return nil
+}
+
+func IsVisible(hwnd uintptr) bool {
+ ret, _, _ := procIsWindowVisible.Call(hwnd)
+ return ret != 0
+}
+
+func IsWindowFullScreen(hwnd uintptr) bool {
+ wRect := GetWindowRect(hwnd)
+ m := MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)
+ var mi MONITORINFO
+ mi.CbSize = uint32(unsafe.Sizeof(mi))
+ if !GetMonitorInfo(m, &mi) {
+ return false
+ }
+ return wRect.Left == mi.RcMonitor.Left &&
+ wRect.Top == mi.RcMonitor.Top &&
+ wRect.Right == mi.RcMonitor.Right &&
+ wRect.Bottom == mi.RcMonitor.Bottom
+}
+
+func IsWindowMaximised(hwnd uintptr) bool {
+ style := uint32(getWindowLong(hwnd, GWL_STYLE))
+ return style&WS_MAXIMIZE != 0
+}
+func IsWindowMinimised(hwnd uintptr) bool {
+ style := uint32(getWindowLong(hwnd, GWL_STYLE))
+ return style&WS_MINIMIZE != 0
+}
+
+func RestoreWindow(hwnd uintptr) {
+ showWindow(hwnd, SW_RESTORE)
+}
+
+func ShowWindowMaximised(hwnd uintptr) {
+ showWindow(hwnd, SW_MAXIMIZE)
+}
+func ShowWindowMinimised(hwnd uintptr) {
+ showWindow(hwnd, SW_MINIMIZE)
+}
+
+func SetApplicationIcon(hwnd uintptr, icon HICON) {
+ setClassLongPtr(hwnd, GCLP_HICON, icon)
+}
+
+func SetBackgroundColour(hwnd uintptr, r, g, b uint8) {
+ col := uint32(r) | uint32(g)<<8 | uint32(b)<<16
+ hbrush, _, _ := procCreateSolidBrush.Call(uintptr(col))
+ setClassLongPtr(hwnd, GCLP_HBRBACKGROUND, hbrush)
+}
+
+func IsWindowNormal(hwnd uintptr) bool {
+ return !IsWindowMaximised(hwnd) && !IsWindowMinimised(hwnd) && !IsWindowFullScreen(hwnd)
+}
+
+func setClassLongPtr(hwnd uintptr, param int32, val uintptr) bool {
+ proc := procSetClassLongPtr
+ if strconv.IntSize == 32 {
+ /*
+ https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setclasslongptrw
+ Note: To write code that is compatible with both 32-bit and 64-bit Windows, use SetClassLongPtr.
+ When compiling for 32-bit Windows, SetClassLongPtr is defined as a call to the SetClassLong function
+
+ => We have to do this dynamically when directly calling the DLL procedures
+ */
+ proc = procSetClassLong
+ }
+
+ ret, _, _ := proc.Call(
+ hwnd,
+ uintptr(param),
+ val,
+ )
+ return ret != 0
+}
+
+func getWindowLong(hwnd uintptr, index int) int32 {
+ ret, _, _ := procGetWindowLong.Call(
+ hwnd,
+ uintptr(index))
+
+ return int32(ret)
+}
+
+func showWindow(hwnd uintptr, cmdshow int) bool {
+ ret, _, _ := procShowWindow.Call(
+ hwnd,
+ uintptr(cmdshow))
+ return ret != 0
+}
+
+func stripNulls(str string) string {
+ // Split the string into substrings at each null character
+ substrings := strings.Split(str, "\x00")
+
+ // Join the substrings back into a single string
+ strippedStr := strings.Join(substrings, "")
+
+ return strippedStr
+}
+
+func MustStringToUTF16Ptr(input string) *uint16 {
+ input = stripNulls(input)
+ result, err := syscall.UTF16PtrFromString(input)
+ if err != nil {
+ Fatal(err)
+ }
+ return result
+}
+
+// MustStringToUTF16uintptr converts input to a NUL-terminated UTF-16 buffer and returns its pointer as a uintptr.
+// It first removes any internal NUL characters from input, then converts the result to a UTF-16 pointer.
+// The function panics if the conversion fails.
+func MustStringToUTF16uintptr(input string) uintptr {
+ input = stripNulls(input)
+ ret, err := syscall.UTF16PtrFromString(input)
+ if err != nil {
+ panic(err)
+ }
+ return uintptr(unsafe.Pointer(ret))
+}
+
+// MustStringToUTF16 converts s to UTF-16 encoding, stripping any embedded NULs and panicking on error.
+//
+// The returned slice is suitable for Windows API calls that expect a UTF-16 encoded string.
+func MustStringToUTF16(input string) []uint16 {
+ input = stripNulls(input)
+ ret, err := syscall.UTF16FromString(input)
+ if err != nil {
+ panic(err)
+ }
+ return ret
+}
+
+// StringToUTF16 converts input to a UTF-16 encoded, NUL-terminated []uint16 suitable for Windows API calls.
+// It first removes any embedded NUL ('\x00') characters from input. The returned slice is NUL-terminated;
+// an error is returned if the conversion fails.
+func StringToUTF16(input string) ([]uint16, error) {
+ input = stripNulls(input)
+ return syscall.UTF16FromString(input)
+}
+
+func CenterWindow(hwnd HWND) {
+ windowInfo := getWindowInfo(hwnd)
+ frameless := windowInfo.IsPopup()
+
+ info := GetMonitorInfoForWindow(hwnd)
+ workRect := info.RcWork
+ screenMiddleW := workRect.Left + (workRect.Right-workRect.Left)/2
+ screenMiddleH := workRect.Top + (workRect.Bottom-workRect.Top)/2
+ var winRect *RECT
+ if !frameless {
+ winRect = GetWindowRect(hwnd)
+ } else {
+ winRect = GetClientRect(hwnd)
+ }
+ winWidth := winRect.Right - winRect.Left
+ winHeight := winRect.Bottom - winRect.Top
+ windowX := screenMiddleW - (winWidth / 2)
+ windowY := screenMiddleH - (winHeight / 2)
+ SetWindowPos(hwnd, HWND_TOP, int(windowX), int(windowY), int(winWidth), int(winHeight), SWP_NOSIZE)
+}
+
+func getWindowInfo(hwnd HWND) *WINDOWINFO {
+ var info WINDOWINFO
+ info.CbSize = uint32(unsafe.Sizeof(info))
+ GetWindowInfo(hwnd, &info)
+ return &info
+}
+
+func GetMonitorInfoForWindow(hwnd HWND) *MONITORINFO {
+ currentMonitor := MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST)
+ var info MONITORINFO
+ info.CbSize = uint32(unsafe.Sizeof(info))
+ GetMonitorInfo(currentMonitor, &info)
+ return &info
+}
+
+type WindowProc func(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr
+
+var windowClasses = make(map[string]HINSTANCE)
+var windowClassesLock sync.Mutex
+
+func getWindowClass(name string) (HINSTANCE, bool) {
+ windowClassesLock.Lock()
+ defer windowClassesLock.Unlock()
+ result, exists := windowClasses[name]
+ return result, exists
+}
+
+func setWindowClass(name string, instance HINSTANCE) {
+ windowClassesLock.Lock()
+ defer windowClassesLock.Unlock()
+ windowClasses[name] = instance
+}
+
+func RegisterWindow(name string, proc WindowProc) (HINSTANCE, error) {
+ classInstance, exists := getWindowClass(name)
+ if exists {
+ return classInstance, nil
+ }
+ applicationInstance := GetModuleHandle("")
+ if applicationInstance == 0 {
+ return 0, fmt.Errorf("get module handle failed")
+ }
+
+ var wc WNDCLASSEX
+ wc.Size = uint32(unsafe.Sizeof(wc))
+ wc.WndProc = syscall.NewCallback(proc)
+ wc.Instance = applicationInstance
+ wc.Icon = LoadIconWithResourceID(0, uint16(IDI_APPLICATION))
+ wc.Cursor = LoadCursorWithResourceID(0, uint16(IDC_ARROW))
+ wc.Background = COLOR_BTNFACE + 1
+ wc.ClassName = MustStringToUTF16Ptr(name)
+
+ atom := RegisterClassEx(&wc)
+ if atom == 0 {
+ panic(syscall.GetLastError())
+ }
+
+ setWindowClass(name, applicationInstance)
+
+ return applicationInstance, nil
+}
+
+func FlashWindow(hwnd HWND, enabled bool) {
+ var flashInfo FLASHWINFO
+ flashInfo.CbSize = uint32(unsafe.Sizeof(flashInfo))
+ flashInfo.Hwnd = hwnd
+ if enabled {
+ flashInfo.DwFlags = FLASHW_ALL | FLASHW_TIMERNOFG
+ } else {
+ flashInfo.DwFlags = FLASHW_STOP
+ }
+ _, _, _ = procFlashWindowEx.Call(uintptr(unsafe.Pointer(&flashInfo)))
+}
+
+func EnumChildWindows(hwnd HWND, callback func(hwnd HWND, lparam LPARAM) LRESULT) LRESULT {
+ r, _, _ := procEnumChildWindows.Call(hwnd, syscall.NewCallback(callback), 0)
+ return r
+}
+
+func DisableCloseButton(hwnd HWND) error {
+ hSysMenu, _, err := getSystemMenu.Call(hwnd, 0)
+ if hSysMenu == 0 {
+ return err
+ }
+
+ r1, _, err := enableMenuItem.Call(hSysMenu, SC_CLOSE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED)
+ if r1 == 0 {
+ return err
+ }
+
+ return nil
+}
+
+func EnableCloseButton(hwnd HWND) error {
+ hSysMenu, _, err := getSystemMenu.Call(hwnd, 0)
+ if hSysMenu == 0 {
+ return err
+ }
+
+ r1, _, err := enableMenuItem.Call(hSysMenu, SC_CLOSE, MF_BYCOMMAND|MF_ENABLED)
+ if r1 == 0 {
+ return err
+ }
+
+ return nil
+}
+
+func FindWindowW(className, windowName *uint16) HWND {
+ ret, _, _ := findWindow.Call(
+ uintptr(unsafe.Pointer(className)),
+ uintptr(unsafe.Pointer(windowName)),
+ )
+ return HWND(ret)
+}
+
+func SendMessageToWindow(hwnd HWND, msg string) {
+ // Convert data to UTF16 string
+ dataUTF16, err := StringToUTF16(msg)
+ if err != nil {
+ return
+ }
+
+ // Prepare COPYDATASTRUCT
+ cds := COPYDATASTRUCT{
+ DwData: WMCOPYDATA_SINGLE_INSTANCE_DATA,
+ CbData: uint32((len(dataUTF16) * 2) + 1), // +1 for null terminator
+ LpData: uintptr(unsafe.Pointer(&dataUTF16[0])),
+ }
+
+ // Send message to first instance
+ _, _, _ = procSendMessage.Call(
+ hwnd,
+ WM_COPYDATA,
+ 0,
+ uintptr(unsafe.Pointer(&cds)),
+ )
+}
+
+// GetMenu retrieves a handle to the menu assigned to the specified window
+func GetMenu(hwnd HWND) HMENU {
+ ret, _, _ := getMenuProc.Call(hwnd)
+ return ret
+}
\ No newline at end of file