1
$\begingroup$

I have a excel application COM object for an active workbook.

excelApplication=GetActiveCOMObject["Excel.Application"]

<<NETObject[Microsoft.Office.Interop.Excel.ApplicationClass]>>

But I click on the Wolfram window to run a code so the Excel application is no longer active. But I want to make the Excel window active again from a Wolfram code using NETLink.

Is there a method within a COM object that can activate its window and bring it to the front? The following fails:

excelApplication@Activate[]

There seem to be methods, but I don't know how to access them from NETLink.

https://learn.microsoft.com/en-us/office/vba/api/excel.window.activate

$\endgroup$
1
  • 2
    $\begingroup$ This is going to be tricky to do because, for security reasons, Win32 has restrictions upon which processes can bring a window to the front. The Mathematica kernel is a background process which does not pass those restrictions. All system calls like SetForegroundWindow will end up doing is make Excel's task bar button flash. Perhaps if someone knows of a way to make NETLink calls directly from the front end? $\endgroup$
    – WReach
    Commented Jul 28, 2023 at 3:33

1 Answer 1

2
$\begingroup$

This is complicated by Win32 usability/security restrictions which limit the processes permitted to bring a window to the front. The Mathematica kernel runs "headless" in the background and is blocked from performing such an operation. Any attempt to use a system call like SetForegroundWindow will only make the Excel task bar button flash instead of bringing the window to the front.

I do not know of a clean work-around for this, but I have a hacky one. The trick will be to briefly pop-up a Windows form that issues a call to SetForegroundWindow.

Here is the code:

Needs["NETLink`"]
InstallNET[];

setForegroundWindow =
  DefineDLLFunction["SetForegroundWindow", "user32.dll", "BOOL", {"IntPtr"}];

SetAttributes[DoInNETUI, HoldAll]

DoInNETUI[action_] :=
  NETBlock@Module[{form, handler}
  , form = NETNew["System.Windows.Forms.Form"]
  ; form@Text = "Temporary DotNET Form"
  ; handler = AddEventHandler[form@Activated, (action; form@Close[])&]
  ; DoNETModeless[form]
  ; RemoveEventHandler[form@Activated, handler]
  ]

bringExcelToFront[xl_] :=
  DoInNETUI[setForegroundWindow[NETNew["System.IntPtr", xl@ActiveWindow@hWnd]]]

So then...

excelApplication = GetActiveCOMObject["Excel.Application"];

bringExcelToFront[excelApplication]

This hack feels brittle so I hope someone else comes up with a more robust solution.

$\endgroup$
5
  • $\begingroup$ Thank you, this is wonderful, if someone could find a way to do it without Windows Form that would be nice. But I have one more question, for this application since there was a NETObject you were able to get the window handler HWND but is there a way to do it for an application where there is no direct NETObect? Is there a way to get a list of all running applications with Windows and then get a NETObject for them and extract their HWND and then bring them to the front? For example, Notepad or Wolfram FrontEnd itself. $\endgroup$
    – user13892
    Commented Jul 28, 2023 at 16:18
  • 1
    $\begingroup$ @user13892 The NETLink Tutorial shows several examples of calling the Win32 API. One of the examples gets a list of Windows and their handles: EnumWindows.nb. $\endgroup$
    – WReach
    Commented Jul 28, 2023 at 17:30
  • $\begingroup$ Thank you, I was able to figure out for every window through that example. But I will hold off accepting the answer so maybe if someone knows how to run NETLink from FrontEnd, they can share. $\endgroup$
    – user13892
    Commented Jul 29, 2023 at 19:56
  • $\begingroup$ I found a function FE`Evaluate in the FE context, do you think this might be it? Will just wrapping this function make it evaluate in the FrontEnd? $\endgroup$
    – user13892
    Commented Jul 31, 2023 at 13:37
  • $\begingroup$ @user13892 I believe that function will only evaluate a very restricted set of symbols. I would be surprised if it supports NETLink. $\endgroup$
    – WReach
    Commented Aug 3, 2023 at 2:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.