Answered by:
How to get active application?

Question
-
I develop an UDF in C#:
public string GetActiveSheetName() { string Caller = null; Excel.Application oExcel = Marshal.GetActiveObject("Excel.Application") as Excel.Application; Caller = oExcel.ActiveSheet.Name; return Caller; }
This works fine if there is only one Excel process running. But if I have two or more instances of Excel are running, it still return first excel application's active sheet name.Thursday, December 29, 2011 7:10 AM
Answers
-
I've been working this problem since your previous posting. After a few days of trying I finally got all the code to work. I had to use a number of Winn32 API to get it to work. Here are the steps I used. I not sure if there is an easier way to do this.
1) You need to find all the Excel.exe processes. This was pretty easy to do. I used the Net Library function Process.GetProcessesByName(@"excel") which returns an array of Processes
2) I then checked that the Excel.exe window was the active window using Win32 API user32.dll function IsWindowVisible.
3) I then had to write another function EnumChildWindows(ExcelWin, cb, ref hwndChild) which uses the Win32 API User32.dll function GetClassName(). I needed the child window to be able to extract the excel application from the window.4) Next I used the Win32 API Oleacc.dll function AccessibleObjectFromWindow to get the excel object from the window.
5) Finally I overload the window object to an excel object and get the sheet name.
//using System.Runtime.InteropServices; //using System.Diagnostics; public delegate bool EnumChildCallback(int hwnd, ref int lParam); [System.Runtime.InteropServices.DllImport("User32.dll")] public static extern bool EnumChildWindows(IntPtr hWndParent, EnumChildCallback lpEnumFunc, ref IntPtr lParam); private static EnumChildCallback cb; [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool IsWindowVisible(IntPtr hWnd); [DllImport("Oleacc.dll")] private static extern int AccessibleObjectFromWindow( IntPtr hwnd, uint dwObjectID, byte[] riid, [MarshalAs(UnmanagedType.IUnknown)]ref object winobj); [DllImport("User32.dll")] public static extern int GetClassName( int hWnd, StringBuilder lpClassName, int nMaxCount); public static bool EnumChildProc(int hwndChild, ref int lParam) { StringBuilder buf = new StringBuilder(128); GetClassName(hwndChild, buf, 128); if (buf.ToString() == "EXCEL7") { lParam = hwndChild; return false; } return true; } public static string GetActiveSheetName() { string activesheetname = null; IntPtr activeAppWindow = IntPtr.Zero; IntPtr ExcelWin; Process[] ExcelProcesses = Process.GetProcessesByName(@"excel"); foreach(Process MyProcess in ExcelProcesses) { ExcelWin = MyProcess.MainWindowHandle; IntPtr hwndChild = (IntPtr)0; cb = new EnumChildCallback(EnumChildProc); EnumChildWindows(ExcelWin, cb, ref hwndChild); if (IsWindowVisible(ExcelWin)) { const uint OBJID_NATIVEOM = 0xFFFFFFF0; Guid IID_IDispatch = new Guid("{00020400-0000-0000-C000-000000000046}"); object winptr = null; int As = AccessibleObjectFromWindow( hwndChild, OBJID_NATIVEOM, IID_IDispatch.ToByteArray(), ref winptr); Excel.Window excelwin = (Excel.Window)winptr; Excel.Application XlApp = excelwin.Application; Excel.Worksheet sht = (Excel.Worksheet)XlApp.ActiveSheet; activesheetname = sht.Name; break; } } return activesheetname; }
- Edited by Joel Engineer Friday, December 30, 2011 4:37 AM
- Marked as answer by Calvin_Gao Monday, January 9, 2012 5:38 AM
Friday, December 30, 2011 4:33 AM
All replies
-
I've been working this problem since your previous posting. After a few days of trying I finally got all the code to work. I had to use a number of Winn32 API to get it to work. Here are the steps I used. I not sure if there is an easier way to do this.
1) You need to find all the Excel.exe processes. This was pretty easy to do. I used the Net Library function Process.GetProcessesByName(@"excel") which returns an array of Processes
2) I then checked that the Excel.exe window was the active window using Win32 API user32.dll function IsWindowVisible.
3) I then had to write another function EnumChildWindows(ExcelWin, cb, ref hwndChild) which uses the Win32 API User32.dll function GetClassName(). I needed the child window to be able to extract the excel application from the window.4) Next I used the Win32 API Oleacc.dll function AccessibleObjectFromWindow to get the excel object from the window.
5) Finally I overload the window object to an excel object and get the sheet name.
//using System.Runtime.InteropServices; //using System.Diagnostics; public delegate bool EnumChildCallback(int hwnd, ref int lParam); [System.Runtime.InteropServices.DllImport("User32.dll")] public static extern bool EnumChildWindows(IntPtr hWndParent, EnumChildCallback lpEnumFunc, ref IntPtr lParam); private static EnumChildCallback cb; [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool IsWindowVisible(IntPtr hWnd); [DllImport("Oleacc.dll")] private static extern int AccessibleObjectFromWindow( IntPtr hwnd, uint dwObjectID, byte[] riid, [MarshalAs(UnmanagedType.IUnknown)]ref object winobj); [DllImport("User32.dll")] public static extern int GetClassName( int hWnd, StringBuilder lpClassName, int nMaxCount); public static bool EnumChildProc(int hwndChild, ref int lParam) { StringBuilder buf = new StringBuilder(128); GetClassName(hwndChild, buf, 128); if (buf.ToString() == "EXCEL7") { lParam = hwndChild; return false; } return true; } public static string GetActiveSheetName() { string activesheetname = null; IntPtr activeAppWindow = IntPtr.Zero; IntPtr ExcelWin; Process[] ExcelProcesses = Process.GetProcessesByName(@"excel"); foreach(Process MyProcess in ExcelProcesses) { ExcelWin = MyProcess.MainWindowHandle; IntPtr hwndChild = (IntPtr)0; cb = new EnumChildCallback(EnumChildProc); EnumChildWindows(ExcelWin, cb, ref hwndChild); if (IsWindowVisible(ExcelWin)) { const uint OBJID_NATIVEOM = 0xFFFFFFF0; Guid IID_IDispatch = new Guid("{00020400-0000-0000-C000-000000000046}"); object winptr = null; int As = AccessibleObjectFromWindow( hwndChild, OBJID_NATIVEOM, IID_IDispatch.ToByteArray(), ref winptr); Excel.Window excelwin = (Excel.Window)winptr; Excel.Application XlApp = excelwin.Application; Excel.Worksheet sht = (Excel.Worksheet)XlApp.ActiveSheet; activesheetname = sht.Name; break; } } return activesheetname; }
- Edited by Joel Engineer Friday, December 30, 2011 4:37 AM
- Marked as answer by Calvin_Gao Monday, January 9, 2012 5:38 AM
Friday, December 30, 2011 4:33 AM -
Thank you very much!
If there is only one instance, it works fine. But if there are more than one instance, it doesn't work fine.
- Edited by zqsntws Friday, December 30, 2011 7:11 AM
Friday, December 30, 2011 6:48 AM