Bring Window To Foreground When MainWindowHandle Is 0 - excel

The following code brings the window to the foreground, if the MainWindowHandle is not 0.
How can I bring a window to the front that has MainWindowHandle = 0?
This is for the Microsoft Excel - Compatibility Checker window that shows a GUI but does not have an icon in the task bar and has MainWindowHandle = 0.
I have no other instances of Excel running.
Add-Type #"
using System;
using System.Runtime.InteropServices;
public class Tricks {
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
}
"#
$excel = (Get-Process | Where-Object { $_.ProcessName -eq 'EXCEL' }).MainWindowHandle
[void] [Tricks]::SetForegroundWindow($excel)
In Windows Task Manager, I can right click on 'Microsoft Excel - Compatibility Checker' and click on "Bring To Front" and that works. How can I mimic this functionality in Powershell?

Thanks to IInspectable for pointing me in the right direction.
This code gets the real MainWindowHandle value:
$TypeDef2 = #"
using System;
using System.Text;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Api
{
public class WinStruct
{
public string WinTitle {get; set; }
public int MainWindowHandle { get; set; }
}
public class ApiDef
{
private delegate bool CallBackPtr(int hwnd, int lParam);
private static CallBackPtr callBackPtr = Callback;
private static List<WinStruct> _WinStructList = new List<WinStruct>();
[DllImport("User32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumWindows(CallBackPtr lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
private static bool Callback(int hWnd, int lparam)
{
StringBuilder sb = new StringBuilder(256);
int res = GetWindowText((IntPtr)hWnd, sb, 256);
_WinStructList.Add(new WinStruct { MainWindowHandle = hWnd, WinTitle = sb.ToString() });
return true;
}
public static List<WinStruct> GetWindows()
{
_WinStructList = new List<WinStruct>();
EnumWindows(callBackPtr, IntPtr.Zero);
return _WinStructList;
}
}
}
"#
Add-Type -TypeDefinition $TypeDef2 -Language CSharpVersion3
$excelInstance = [Api.Apidef]::GetWindows() | Where-Object { $_.WinTitle.ToUpper() -eq "Microsoft Excel - Compatibility Checker".ToUpper() }
So now using this correct value, I can call the SetForegroundWindow() function:
Add-Type #"
using System;
using System.Runtime.InteropServices;
public class Tricks {
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
}
"#
[void] [Tricks]::SetForegroundWindow($excelInstance.MainWindowHandle)
I wrote a detailed blog about this on my website.
I've put up a full example on GitHub of how to create an Excel file, edit it and run the above code in a different thread which you have to do because the Excel popup blocks the main thread.

Related

Hello World for Pinvoke and Native Calls

I am trying to do a very basic hello world for Pinvoke and native calls.
I create a single solution with 2 projects (one for the dll and one for the universal windows app)
So I end up with a project heirachy like this
There is one method in my dll (file NativeCalls.cpp):
#include "pch.h"
#include "NativeCalls.h"
#include <stdio.h>
MYAPI void print_line(const char* str) {
printf("%s\n", str);
}
On the C# side of things I have my NativeCalls.cs file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace MSSurfaceHubMonitoring
{
public static class NativeCalls
{
[DllImport("NativeCalls.dll")]
private static extern void print_line(string str);
public static void sayHelo()
{
print_line("Hello, PInvoke!");
}
}
}
At this point I will build and run it but get an error that it cannot find the dll
However I believe it to be the dependency and not the dll it self. I have changed the output directory of the dll to be in the root of where the UW app runs from (\bin\x86) so it really should be finding it. So like I said I think its the dependencies and not the actual dll.
Here is what I see in Dependency Walker
But I have installed all c++ packages I can get my hands on so I dont understand how to get the missing dependencies. Plus this is just a hello world, why do I need all these libraries.
FYI
My dll project is NOT referenced by the UW app. Im not sure thats needed or not? I dont think so though since this a runtime thing, so as long as the dll is there it should find it and read it. But regardless if I do try to add the project as a reference I get this error:
The biggest help to me was finding these method declarations (not even in the class)
extern "C" {
__declspec(dllexport) int getPageSize()
{
SYSTEM_INFO siSysInfo;
GetSystemInfo(&siSysInfo);
return siSysInfo.dwPageSize;
}
}
extern "C" {
__declspec(dllexport) Windows::Foundation::Collections::IMap<Platform::String^, int> ^getSystemInfo()
{
SYSTEM_INFO siSysInfo;
GetSystemInfo(&siSysInfo);
IMap<String^, int> ^ret =
ref new Platform::Collections::Map<String^, int>;
ret->Insert("oemId", siSysInfo.dwOemId);
ret->Insert("cpuCount", siSysInfo.dwNumberOfProcessors);
ret->Insert("pageSize", siSysInfo.dwPageSize);
ret->Insert("processorType", siSysInfo.dwProcessorType);
ret->Insert("maxApplicationAddress", siSysInfo.lpMinimumApplicationAddress);
ret->Insert("minApplicationAddress", siSysInfo.lpMaximumApplicationAddress);
ret->Insert("activeProcessorMask", siSysInfo.dwActiveProcessorMask);
return ret;
}
but in the end I was creating wrappers for things I didnt need to. in c# you can directly call the native methods without the need for a seperate dll or component project.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Monitoring
{
public static class NativeCallsWrapper
{
private static SYSTEM_INFO sysInfo = new SYSTEM_INFO();
private static MEMORYSTATUSEX mem = new MEMORYSTATUSEX();
[DllImport("kernel32.dll", SetLastError = false)]
public static extern void GetSystemInfo([In, Out] SYSTEM_INFO Info);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);
static NativeCallsWrapper()
{
GetSystemInfo(sysInfo);
GlobalMemoryStatusEx(mem);
}
[StructLayout(LayoutKind.Explicit)]
public struct SYSTEM_INFO_UNION
{
[FieldOffset(0)]
public UInt32 OemId;
[FieldOffset(0)]
public UInt16 ProcessorArchitecture;
[FieldOffset(2)]
public UInt16 Reserved;
}
public struct SYSTEM_INFO
{
public SYSTEM_INFO_UNION CpuInfo;
public UInt32 PageSize;
public UInt32 MinimumApplicationAddress;
public UInt32 MaximumApplicationAddress;
public UInt32 ActiveProcessorMask;
public UInt32 NumberOfProcessors;
public UInt32 ProcessorType;
public UInt32 AllocationGranularity;
public UInt16 ProcessorLevel;
public UInt16 ProcessorRevision;
}
[StructLayout(LayoutKind.Sequential)]
public class MEMORYSTATUSEX
{
public uint dwLength;
public uint dwMemoryLoad;
public ulong ullTotalPhys;
public ulong ullAvailPhys;
public ulong ullTotalPageFile;
public ulong ullAvailPageFile;
public ulong ullTotalVirtual;
public ulong ullAvailVirtual;
public ulong ullAvailExtendedVirtual;
public MEMORYSTATUSEX()
{
this.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
}
}
public static GeneralStatistics getGeneralStatistics()
{
GeneralStatistics generalStatistics = new GeneralStatistics();
generalStatistics.numberOfProcesses = (int)sysInfo.NumberOfProcessors;
generalStatistics.memoryTotal = mem.ullTotalPhys / 1048;
generalStatistics.memoryInUse = (mem.ullTotalPhys - mem.ullAvailPhys) / 1048;
return generalStatistics;
}
}
}

OxyPlot EventTrigger

I am trying to handle event in OxyPlot using EventTrigger. But it does not work like I want.
<Window x:Class="WpfApplication14.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:oxy="http://oxyplot.org/wpf"
Title="MainWindow" Height="350" Width="525">
<Grid>
<oxy:PlotView Model="{Binding PlotModel}" DefaultTrackerTemplate="{x:Null}">
<i:Interaction.Triggers >
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding Move}"></i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</oxy:PlotView>
</Grid>
And code look's like
using OxyPlot;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using OxyPlot.Axes;
using GalaSoft.MvvmLight.Command;
namespace WpfApplication14
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
///
public partial class MainWindow : Window
{
public class DataGeneration
{
public PlotModel PlotModel { get; set; }
public ICommand Move { get; set; }
public int _NumberOf;
public Dictionary<int, List<int>> Test { get; set; }
OxyPlot.Series.LineSeries LS;
Random rnd;
LinearAxis LA;
public int EndPosition = 0;
public DataGeneration(int NumberOf)
{
LA = new LinearAxis()
{
Position=AxisPosition.Bottom,
Minimum=0,
Maximum = EndPosition
};
Move = new RelayCommand(() => TestMove());
_NumberOf = NumberOf;
rnd = new Random();
Test = new Dictionary<int, List<int>>();
PlotModel = new PlotModel();
PlotModel.Axes.Add(LA);
LS = new OxyPlot.Series.LineSeries();
PlotModel.Series.Add(LS);
}
public void TestMove()
{
PlotModel.Axes[0].Reset();
}
public void AddPoint()
{
do
{
LS.Points.Add(new DataPoint(++_NumberOf, rnd.Next(1, 10)));
System.Threading.Thread.Sleep(1000);
EndPosition += 1;
LA.Maximum = EndPosition+3;
LA.Minimum = EndPosition;
Update();
} while (true);
}
public void Update()
{
PlotModel.InvalidatePlot(true);
}
}
public delegate void BeginUpdate();
private Stopwatch stopwatch = new Stopwatch();
private long lastUpdateMilliSeconds;
DataGeneration Data;
public MainWindow()
{
Data = new DataGeneration(1);
BeginUpdate BU = new BeginUpdate(Data.AddPoint);
IAsyncResult result = BU.BeginInvoke(null, null);
this.DataContext = Data;
CompositionTarget.Rendering += CompositionTargetRendering;
InitializeComponent();
}
private void CompositionTargetRendering(object sender, EventArgs e)
{
if (stopwatch.ElapsedMilliseconds > lastUpdateMilliSeconds + 300)
{
Data.Update();
}
}
}
}
why it firing when I make double click on OxyPlot? Genaraly i am trying to pan chart by left mousebutton.It's implemented in oxyplot by default(right mouse button).

How to specify individual List item's Font color in VC++ WTL

I have list box CListBox in which i need to specify the color of individual list item according to some condition. How can i achieve this.
Im running VS2005.
The application is a WTL Dialog based app.
You can create your own listbox(Ex:CColorListBox)
ColorListBox.h
class CColorListBox : public CListBox
{
// Construction
public:
CColorListBox();
// Attributes
public:
// Operations
public:
int AddString( LPCTSTR lpszItem, COLORREF rgb);
int InsertString( int nIndex, LPCTSTR lpszItem, COLORREF rgb);
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CColorListBox)
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CColorListBox();
// Generated message map functions
protected:
//{{AFX_MSG(CColorListBox)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
ColorListBox.cpp
Here is an idea not exact code............
int CColorListBox::AddString( LPCTSTR lpszItem,COLORREF rgb )
{
int item = AddString(lpszItem);
if(item >=0)
SetItemData(item,rgb);
return item;
}
int CColorListBox::InsertString( int nIndex, LPCTSTR lpszItem, COLORREF rgb)
{
int item = ((CListBox*)this)->InsertString(nIndex,lpszItem);
if(item >=0)
SetItemData(item,rgb);
return item;
}
void CColorListBox::DrawItem(LPDRAWITEMSTRUCT lpdis)
{
}
This is what i did to implement the same functionality in ListViewCtrl.
I wrote a class to extend the CListViewCtrl.
class CListViewCtrlEx: public CWindowImpl<CListViewCtrlEx, CListViewCtrl>, public CCustomDraw<CListViewCtrlEx>
{
public:
BEGIN_MSG_MAP(CListViewCtrlEx)
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
CHAIN_MSG_MAP_ALT(CCustomDraw<CListViewCtrlEx>, 1)
DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()
LRESULT OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL bHandled);
DWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw);
DWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw);
void ForceMeasureItemMessage();
void DeleteItem(LPDELETEITEMSTRUCT /*lpDeleteItemStruct*/);
BOOL DeleteItem(int nItem);
void GetCellRect(int header_column, const CRect& item_rect, CRect& cell_rect);
};
The complete code is HERE.

Running control.exe as process does not WaitForExit()

I am running control.exe as a process. (Windows 7 OS, .NET 3.5, C#). It does not stop at WaitForExit() as expected. It immediately "exits" the process even though the control.exe window is still open. I have tried the process.Exited event also and that is triggered before the application exits as well.
Here is my code:
Process process = new Process();
process.StartInfo.FileName = #"c:\windows\system32\control.exe";
process.StartInfo.Arguments = #"userpasswords";
process.Start();
process.WaitForExit();
Send from phone (please correct my formatting, would take hours by phone)
Try to check if window is visible or task is running like:
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace yournamespace
{
class FormCheck
{
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, IntPtr windowTitle);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, StringBuilder lParam);
const int WM_GETTEXT = 0x000D;
const int WM_GETTEXTLENGTH = 0x000E;
public static bool IsRunning(string window, bool exactfit)
{ return Check(window,exactfit); }
public static bool IsRunning(string window)
{ return Check(window); }
public static bool Check(string Processname)
{
Process[] pname = Process.GetProcessesByName(Processname);
if (pname.Length <= 1) { return false; } else { return true; }
}
public static bool Check(string WindowTitle, bool exactfit)
{
bool response = false;
string[] strWindowsTitles = EnumerateOpenedWindows.GetDesktopWindowsTitles();
string strResponse = "";
foreach (string strTitle in strWindowsTitles)
{
if (strTitle.Contains(WindowTitle))
{
if (exactfit)
{
if (strTitle == WindowTitle)
{
strResponse = strTitle;
break;
}
}
else
{
if (strTitle.Contains(WindowTitle))
{
strResponse = strTitle;
break;
}
}
}
}
string pid = string.Empty;
if (strResponse != "")
{
response = true;
}
else { response = false; }
return response;
}
}
public class EnumerateOpenedWindows
{
const int MAXTITLE = 255;
private static List<string> lstTitles;
private delegate bool EnumDelegate(IntPtr hWnd, int lParam);
[DllImport("user32.dll", EntryPoint = "EnumDesktopWindows",
ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool EnumDesktopWindows(IntPtr hDesktop,
EnumDelegate lpEnumCallbackFunction, IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "GetWindowText",
ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
private static extern int _GetWindowText(IntPtr hWnd,
StringBuilder lpWindowText, int nMaxCount);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsWindowVisible(IntPtr hWnd);
private static bool EnumWindowsProc(IntPtr hWnd, int lParam)
{
string strTitle = GetWindowText(hWnd);
if (strTitle != "" & IsWindowVisible(hWnd)) //
{
lstTitles.Add(strTitle);
}
return true;
}
/// <summary>
/// Return the window title of handle
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
public static string GetWindowText(IntPtr hWnd)
{
StringBuilder strbTitle = new StringBuilder(MAXTITLE);
int nLength = _GetWindowText(hWnd, strbTitle, strbTitle.Capacity + 1);
strbTitle.Length = nLength;
return strbTitle.ToString();
}
/// <summary>
/// Return titles of all visible windows on desktop
/// </summary>
/// <returns>List of titles in type of string</returns>
public static string[] GetDesktopWindowsTitles()
{
lstTitles = new List<string>();
EnumDelegate delEnumfunc = new EnumDelegate(EnumWindowsProc);
bool bSuccessful = EnumDesktopWindows(IntPtr.Zero, delEnumfunc, IntPtr.Zero); //for current desktop
if (bSuccessful)
{
return lstTitles.ToArray();
}
else
{
// Get the last Win32 error code
int nErrorCode = Marshal.GetLastWin32Error();
string strErrMsg = String.Format("EnumDesktopWindows failed with code {0}.", nErrorCode);
throw new Exception(strErrMsg);
}
}
}
}
By using one of the methods of "isrunning" like:
int waiter = 0;
while (isRunning("Control")
{
//add 1 to an value and set to zero after x counts
waiter++;
if (waiter == 1000) { waiter=0; }
}
Your program will stuck until control shut down. Escaping sequences should inserted if control would never shut down again ;)

Switching to another application (previously active) on button click in .net

Hi I want to do something like on screen keyboard. I want user to click a button on inactive application and then key press will be sent to active application while keeping active application active. I wrote the code for hover event of the button in inactive application and it is working. But what I want is to do it in click event. It is not working because inactive application becomes active. The code is below for hover event. Thank you.
private void button1_MouseHover(object sender, EventArgs e)
{
SendKeys.Send("{TAB}");
}
Finally I could figure out a way to do it.
Refer the code below.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Timers;
using tmr = System.Timers;
using System.Threading;
namespace KeyPressTest
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern int GetForegroundWindow();
[DllImport("user32")]
private static extern UInt32 GetWindowThreadProcessId(Int32 hWnd, out Int32 lpdwProcessId);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
tmr.Timer tm = new tmr.Timer();
Int32 hwnd = 0;
private Int32 GetWindowProcessID(Int32 hwnd)
{
Int32 pid = 1;
GetWindowThreadProcessId(hwnd, out pid);
return pid;
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
tm.Elapsed += Timer_Elapsed;
tm.Interval = 100;
tm.Start();
}
private void button1_Click(object sender, EventArgs e)
{
SetForegroundWindow((IntPtr)hwnd);
Thread.Sleep(40);
SendKeys.Send("{TAB}");
}
private void Timer_Elapsed(object sender, System.EventArgs args)
{
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(delegate
{
if (this.Handle.ToInt32() != GetForegroundWindow())
{
hwnd = GetForegroundWindow();
}
}));
}
else
{
if (this.Handle.ToInt32() != GetForegroundWindow())
{
hwnd = GetForegroundWindow();
}
}
if (hwnd == 0)
{
return;
}
string appProcessName = "";
string appExePath = "";
string appExeName = "";
try
{
appProcessName = Process.GetProcessById(GetWindowProcessID(hwnd)).ProcessName;
appExePath = Process.GetProcessById(GetWindowProcessID(hwnd)).MainModule.FileName;
appExeName = appExePath.Substring(appExePath.LastIndexOf(#"\") + 1);
}
catch (Exception ex)
{
}
if (textBox1.InvokeRequired)
{
textBox1.Invoke(new MethodInvoker(delegate
{
textBox1.Text = appProcessName + " | " + appExePath + " | " + appExeName;
}));
}
else
{
textBox1.Text = appProcessName + " | " + appExePath + " | " + appExeName;
}
}
}
}
I have never done something similar, but here is what I found in this forum:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace WindowsApplication1
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern int GetForegroundWindow();
[DllImport("user32")]
private static extern UInt32 GetWindowThreadProcessId(Int32 hWnd, out Int32 lpdwProcessId);
private int teller = 0;
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (teller == 1)
{
setTextje();
}
teller++;
}
private Int32 GetWindowProcessID(Int32 hwnd)
{
Int32 pid = 1;
GetWindowThreadProcessId(hwnd, out pid);
return pid;
}
private void setTextje()
{
Int32 hwnd = 0;
hwnd = GetForegroundWindow();
string appProcessName = Process.GetProcessById(GetWindowProcessID(hwnd)).ProcessName;
string appExePath = Process.GetProcessById(GetWindowProcessID(hwnd)).MainModule.FileName;
string appExeName = appExePath.Substring(appExePath.LastIndexOf(#"\") + 1);
textBox1.Text = appProcessName + " | " + appExePath + " | " + appExeName;
}
}
}
It doesn't answer exactly to your question but it will give you a hint. You need to DllImport "User32.dll". After that you can get the id of the foreground window and play with that.
There is also a very interesting article about application switch tracking written in C#

Resources