because you ask to bring MAX to top from MAX it should be enough only:
SetWindowPos(max_hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
SetWindowPos(max_hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE);
(it’s c++ Win32)
after that you should set focus to the control you want
Is this focus fighting?
struct notify
(
fn CreateUser32Assembly =
(
src = "using System;"
src += "using System.Runtime.InteropServices;"
src += "class User32"
src += "{"
src += "[DllImport(\"User32.dll\")]
public static extern bool ShowWindow(IntPtr handle, int nCmdShow);
[DllImport(\"User32.dll\")]
static extern bool BringWindowToTop(IntPtr hWnd);
[DllImport(\"User32.dll\")]
public static extern IntPtr GetForegroundWindow();
[DllImport(\"user32.dll\")]
static extern bool AttachThreadInput(uint idAttach, uint idAttachTo,bool fAttach);
[DllImport(\"user32.dll\")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport(\"kernel32.dll\")]
static extern uint GetCurrentThreadId();
public static void ForceForegroundWindow(IntPtr hWnd)
{
uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
uint appThread = GetCurrentThreadId();
const int SW_SHOW = 5;
if (foreThread != appThread)
{
AttachThreadInput(foreThread, appThread, true);
BringWindowToTop(hWnd);
ShowWindow(hWnd, SW_SHOW);
AttachThreadInput(foreThread, appThread, false);
}
else
{
BringWindowToTop(hWnd);
ShowWindow(hWnd, SW_SHOW);
}
}}"
provider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
params = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
params.GenerateInMemory = true
result = provider.CompileAssemblyFromSource params #(src)
result.CompiledAssembly.CreateInstance "User32"
),
maxHWND,
fn BalloonTipClicked =
(
user32assembly = _notifyUser.CreateUser32Assembly()
user32assembly.ForceForegroundWindow _notifyUser.maxHWND
),
fn BalloonClick = NotifyIcon.Dispose(),
fn notifyUser title:"3ds Max Notification" message:"" =
(
--Use this to notify using the windows 10 pop-up 'toast' notifications.
--Useful for when someone leaves a max session to run a script for a while and to alert them that something is done.
NotifyIcon = dotnetobject "System.Windows.Forms.NotifyIcon"
NotifyIcon.BalloonTipTitle = title
NotifyIcon.BalloonTipText = message
NotifyIcon.Visible = true
-- Application Asterisk Error Exclamation Hand Information Question Shield Warning WinLogo --
NotifyIcon.Icon = (dotnetclass "System.Drawing.SystemIcons").Asterisk
--fn BalloonTipClosed = NotifyIcon.Dispose()
maxHWND = (dotnetobject "system.IntPtr" (windows.getMAXHWND()))
dotnet.addeventhandler NotifyIcon "BalloonTipClicked" BalloonTipClicked
dotnet.addeventhandler NotifyIcon "Click" BalloonClick
--dotnet.addeventhandler NotifyIcon "BalloonTipClosed" BalloonTipClosed
NotifyIcon.ShowBalloonTip 0
)
)
_notifyUser = notify()
sleep 10
_notifyUser.notifyUser message:"test"
or as Sereiah showed above:
BringWindowToTop(hwnd);
ShowWindow(hwnd, SW_SHOW);
all other doesn’t make sense because you call it via MXS (which means same as MAX process and foreground window)
Even tough, this works consistently well on my end, across all Max versions from 2014 to 2021. Weird.
When I click the Ballontip it brings Max to the front, regardless if it is maximized or minimized.
(
fn CreateUser32Assembly =
(
src = "using System;"
src += "using System.Runtime.InteropServices;"
src += "class User32"
src += "{"
src += "[DllImport(\"User32.dll\")]"
src += "public static extern bool SwitchToThisWindow(IntPtr hWnd, bool fUnknown);"
src += "}"
provider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
params = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
params.GenerateInMemory = true
result = provider.CompileAssemblyFromSource params #(src)
result.CompiledAssembly.CreateInstance "User32"
)
user32 = CreateUser32Assembly()
NotifyIcon = dotnetobject "System.Windows.Forms.NotifyIcon"
NotifyIcon.BalloonTipTitle = "3ds Max Notification"
NotifyIcon.BalloonTipText = "Task Completed!"
NotifyIcon.Visible = true
/* Application Asterisk Error Exclamation Hand Information Question Shield Warning WinLogo */
NotifyIcon.Icon = (dotnetclass "System.Drawing.SystemIcons").Asterisk
fn SwitchToMax =
(
maxHWND = dotnetobject "system.IntPtr" (windows.getMAXHWND())
user32.SwitchToThisWindow maxHWND true
NotifyIcon.Dispose()
)
dotnet.addeventhandler NotifyIcon "BalloonTipClicked" SwitchToMax
dotnet.addeventhandler NotifyIcon "Click" SwitchToMax
dotnet.addeventhandler NotifyIcon "BalloonTipClosed" SwitchToMax
try (destroydialog ::RO_TEST) catch()
rollout RO_TEST "" width:242 height:72
(
label lb "A NOTIFICATION WILL BE SEND OUT IN: 10" pos:[12,24]
timer clock "" interval:1000
local counter = 10
on clock tick do
(
counter -= 1
if counter == 0 do
(
NotifyIcon.ShowBalloonTip 0
destroydialog RO_TEST
)
lb.text = "A NOTIFICATION WILL BE SEND OUT IN: " + (counter as string)
)
)
createdialog RO_TEST
)
Any idea why it doesn’t work when using the toast notification as above?
here is my version (works for me):
global WinAssembly
fn CreateWinAssembly forceRecompile:off =
(
if forceRecompile or not iskindof ::WinAssembly dotnetobject or (::WinAssembly.GetType()).name != "Assembly" do
(
source = "using System;\n"
source += "using System.Runtime.InteropServices;\n"
source += "using System.Text;\n"
source += "class _user32\n"
source += "{\n"
source += " [DllImport(\"user32.dll\")]\n"
source += " public static extern bool SetWindowPos(Int32 hWnd, int hWndArg, int Left, int Top, int Width, int Height, int hWndFlags);\n"
source += " public void BringWindowToTop(Int32 hWnd)\n"
source += " {\n"
source += " SetWindowPos(hWnd, -1, 0, 0, 0, 0, 3);\n"
source += " SetWindowPos(hWnd, -2, 0, 0, 0, 0, 67);\n"
source += " }\n"
source += "\t[DllImport(\"user32.dll\")]\n"
source += "\tpublic static extern Int32 SetFocus(Int32 hWnd);\n"
source += "}\n"
csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
compilerParams.GenerateInMemory = on
compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
WinAssembly = compilerResults.CompiledAssembly
WinAssembly.CreateInstance "_user32"
)
)
global _user32 = if _user32 == undefined then CreateWinAssembly() else _user32
try(destroydialog rol) catch()
rollout rol "Test" width:191
(
local ni
fn setupNotifyIcon =
(
local NotifyIcon = dotnetobject "System.Windows.Forms.NotifyIcon"
NotifyIcon.BalloonTipTitle = "3ds Max Notification"
NotifyIcon.BalloonTipText = "Call 3DS MAX !"
NotifyIcon.Visible = true
NotifyIcon.Icon = (dotnetclass "System.Drawing.SystemIcons").Asterisk
fn BalloonTipClicked sender args =
(
hwnd = windows.getMAXHWND()
_user32.BringWindowToTop hwnd
sender.Dispose()
)
fn Click sender args =
(
sender.Dispose()
)
dotnet.addeventhandler NotifyIcon "BalloonTipClicked" BalloonTipClicked
dotnet.addeventhandler NotifyIcon "Click" Click
NotifyIcon
)
button easy_topmost_tb "Easy Topmost" width:185
on easy_topmost_tb pressed do
(
ni = setupNotifyIcon()
sleep 10
ni.ShowBalloonTip 0
)
on rol open do
(
)
)
createdialog rol
Yes, I can confirm this. In Windows 7 it brings the windows to the front but in Windows 10 it only flashes on the taskbar.
The code from Denis works on both.