Notifications
Clear all

[Closed] Bring Max Process to Front

Alas not when I’ve connected it to the Toast Notification…

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)

1 Reply
(@polytools3d)
Joined: 10 months ago

Posts: 0

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?

Must be a win7/10 thing… it only flashes on taskbar for me…

1 Reply
(@denist)
Joined: 10 months ago

Posts: 0

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

Scratch that… scope variable issue

Yep that works! DenisT magic for the win! Thanks a lot!

i moved to 2016

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.

Page 2 / 3