How to update console window's taskbar progress in Windows Terminal - c#

I have this code that works perfectly in cmd and PowerShell, but does nothing in Windows Terminal.
internal class TaskbarProgress : IDisposable
{
private IntPtr consoleWindowHandle = IntPtr.Zero;
[DllImport("kernel32.dll")]
private static extern IntPtr GetConsoleWindow();
internal TaskbarProgress()
{
consoleWindowHandle = GetConsoleWindow();
if (consoleWindowHandle != IntPtr.Zero)
{
TaskbarProgressCom.SetState(consoleWindowHandle, TaskbarProgressState.Normal);
}
}
internal void SetProgress(ulong currentValue, ulong maximumValue)
{
if (consoleWindowHandle != IntPtr.Zero)
{
TaskbarProgressCom.SetValue(consoleWindowHandle, currentValue, maximumValue);
}
}
public void Dispose()
{
if (consoleWindowHandle != IntPtr.Zero)
{
TaskbarProgressCom.SetState(consoleWindowHandle, TaskbarProgressState.NoProgress);
consoleWindowHandle = IntPtr.Zero;
}
}
}
internal enum TaskbarProgressState
{
NoProgress = 0,
Indeterminate = 0x1,
Normal = 0x2,
Error = 0x4,
Paused = 0x8
}
internal static class TaskbarProgressCom
{
... // Removed for StackOverflow complaint of too much code, but basically the same as https://www.nuget.org/packages/Microsoft-WindowsAPICodePack-Shell
}
I thought maybe the console window is childed, so grab the root window:
[DllImport("user32.dll", ExactSpelling = true)]
private static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags);
// ...
IntPtr rootOwnerHandle = GetAncestor(consoleWindowHandle, GetAncestorFlags.RootOwner);
if (rootOwnerHandle != IntPtr.Zero)
{
consoleWindowHandle = rootOwnerHandle;
}
But that didn't change anything. What am I missing?
Extra context: https://github.com/dotnet/BenchmarkDotNet/pull/2158

Thanks to folks on the Windows Terminal repo, I got the answer:
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GetConsoleMode(IntPtr hConsoleHandle, out ConsoleModes lpMode);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetConsoleMode(IntPtr hConsoleHandle, ConsoleModes dwMode);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetStdHandle(int nStdHandle);
const int STD_OUTPUT_HANDLE = -11;
[Flags]
private enum ConsoleModes : uint
{
ENABLE_PROCESSED_INPUT = 0x0001,
ENABLE_LINE_INPUT = 0x0002,
ENABLE_ECHO_INPUT = 0x0004,
ENABLE_WINDOW_INPUT = 0x0008,
ENABLE_MOUSE_INPUT = 0x0010,
ENABLE_INSERT_MODE = 0x0020,
ENABLE_QUICK_EDIT_MODE = 0x0040,
ENABLE_EXTENDED_FLAGS = 0x0080,
ENABLE_AUTO_POSITION = 0x0100,
ENABLE_PROCESSED_OUTPUT = 0x0001,
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002,
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004,
DISABLE_NEWLINE_AUTO_RETURN = 0x0008,
ENABLE_LVB_GRID_WORLDWIDE = 0x0010
}
static void Main(string[] args)
{
IntPtr handle = GetStdHandle(STD_OUTPUT_HANDLE);
ConsoleModes previousConsoleMode;
GetConsoleMode(handle, out previousConsoleMode);
SetConsoleMode(handle, ConsoleModes.ENABLE_VIRTUAL_TERMINAL_PROCESSING | ConsoleModes.ENABLE_PROCESSED_OUTPUT);
for (uint i = 0; i < 100; ++i)
{
// Set progress value (0-100).
Console.Write($"\x1b]9;4;1;{i}\x1b\\");
Thread.Sleep(100);
}
// Set state to no progress.
Console.Write($"\x1b]9;4;0;0\x1b\\");
SetConsoleMode(handle, previousConsoleMode);
}
The supported sequences are:
ESC ] 9 ; 4 ; st ; pr ST
Set progress state on Windows taskbar and tab. When `st` is:
0: remove progress.
1: set progress value to pr (number, 0-100).
2: set the taskbar to the "Error" state
3: set the taskbar to the "Indeterminate" state
4: set the taskbar to the "Warning" state
https://github.com/microsoft/terminal/issues/6700

Related

SetThreadDesktop not switching form to the other desktop

private async void WrongPassword_Load(object sender, EventArgs e)
{
IntPtr NEWDESKTOP = CreateDesktop("dew", IntPtr.Zero, IntPtr.Zero, 0, (uint) DESKTOP_ACCESS.GENERIC_ALL,IntPtr.Zero);
IntPtr OLDDESKTOP = GetThreadDesktop(GetCurrentThreadId());
SwitchDesktop(NEWDESKTOP);
SetThreadDesktop(NEWDESKTOP);
Thread.CurrentThread.TrySetApartmentState(ApartmentState.STA);
ShowIcon = false;
Text = "";
TopMost = true;
ControlBox = false;
FormBorderStyle = FormBorderStyle.None;
WindowState = FormWindowState.Maximized;
button1.Enabled = false;
MessageCycle();
var i = 60;
Task.Factory.StartNew(() =>
{
SoundPlayer dewd = new SoundPlayer(Resources.WrongPassword);
dewd.PlaySync();
});
PlayMusic();
while (i > 0)
{
CountDownLabel.Text = "Please wait " + i +
" seconds before you can dismiss to prevent \n DDOS, BRUTE FORCE ATTACKS";
i = i - 1;
Task.Delay(1000);
}
SetThreadDesktop(OLDDESKTOP);
CloseDesktop(NEWDESKTOP);
SwitchDesktop(OLDDESKTOP);
CountDownLabel.Text = "We are not responsible if you lose your password and files";
button1.Enabled = true;
}
When I put SetThreadDesktop(NEWDESKTOP), my form does not transfer from my current desktop to NEWDESKTOP, I have also put TrySetApartmentState(ApartmentState.STA) and it still does not work, can someone give me a solution to how to transfer a form from your current desktop to NEWDESKTOP?
Comments the [STAThread] and try to activate STA manually:
Also make sure that Don't use anything which will prevent you switching desktop before calling SetThreadDesktop
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;
namespace WindowsFormsApp1
{
static class Program
{
[Flags]
internal enum ACCESS_MASK : uint
{
DESKTOP_NONE = 0,
DESKTOP_READOBJECTS = 0x0001,
DESKTOP_CREATEWINDOW = 0x0002,
DESKTOP_CREATEMENU = 0x0004,
DESKTOP_HOOKCONTROL = 0x0008,
DESKTOP_JOURNALRECORD = 0x0010,
DESKTOP_JOURNALPLAYBACK = 0x0020,
DESKTOP_ENUMERATE = 0x0040,
DESKTOP_WRITEOBJECTS = 0x0080,
DESKTOP_SWITCHDESKTOP = 0x0100,
GENERIC_ALL = 0x10000000,
}
[DllImport("user32.dll", EntryPoint = "CreateDesktop", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr CreateDesktop(
[MarshalAs(UnmanagedType.LPWStr)] string desktopName,
[MarshalAs(UnmanagedType.LPWStr)] string device, // must be null.
[MarshalAs(UnmanagedType.LPWStr)] string deviceMode, // must be null,
[MarshalAs(UnmanagedType.U4)] int flags, // use 0
[MarshalAs(UnmanagedType.U4)] ACCESS_MASK accessMask,
IntPtr attributes);
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern uint GetCurrentThreadId();
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetThreadDesktop(uint dwThreadId);
[DllImport("user32.dll", SetLastError = true)]
public static extern int SetThreadDesktop(IntPtr hDesktop);
[DllImport("user32.dll", SetLastError = true)]
public static extern int SwitchDesktop(IntPtr hDesktop);
[DllImport("user32.dll", SetLastError = true)]
public static extern int CloseDesktop(IntPtr hDesktop);
/// <summary>
/// The main entry point for the application.
/// </summary>
//[STAThread]
static void Main()
{
int ret = 0;
IntPtr NEWDESKTOP = CreateDesktop("dew", null, null, 0, ACCESS_MASK.GENERIC_ALL, IntPtr.Zero);
IntPtr OLDDESKTOP = GetThreadDesktop(GetCurrentThreadId());
ret = SetThreadDesktop(NEWDESKTOP);
ret = SwitchDesktop(NEWDESKTOP);
Thread.CurrentThread.TrySetApartmentState(ApartmentState.STA);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
ret = SwitchDesktop(OLDDESKTOP);
CloseDesktop(NEWDESKTOP);
}
}
}

Retrieving the parent window Handle C# (trying to maximize outlook)

I generally do run the method listed below to maximize iconized windows;
however when it comes to outlook, there are times where it will maximize a Mail (message) that i have open instead of the parent application (outlook) ; its just pulling up anything outlook that it finds and i need the parent, how can i achieve this?
I have tried using WINAPI GetAncestor, I have also tried GetParent .
public static bool EventChecking(string progr)
{
int bb = 0;
if (Process.GetProcessesByName(progr).Length > 0)
{
bb++;
}
if (bb == 0)
{
return false;
}
foreach (Process ddcd in Process.GetProcesses())
{
if (ddcd.ProcessName.Contains(progr))
{
if (ddcd.MainWindowHandle != IntPtr.Zero)
{
pointer = ddcd.MainWindowHandle;
if (IsIconic(pointer))
{
SendMessage(pointer, 0x112, 0xF120, 0);
}
SetForegroundWindow(pointer);
}
};
}
return true;
}
EDIT:
I also recently tried:
if (ddcd.MainWindowTitle.EndsWith("- Outlook"))
and it still pulls up the single email
I have also had trouble working with Outlook via C# but I have had some success with Win32 calls. Below is one way to locate the Outlook Main Window by checking the Caption.
You could also try EnumWindows but it takes more effort to implement due to Callbacks.
using System.Text;
using System.Runtime.InteropServices;
public IntPtr GetOutlookHandle()
{
string windowClass = "rctrl_renwnd32";
uint GW_HWNDNEXT = 2;
IntPtr firstHandle = new IntPtr(0);
IntPtr handle = new IntPtr(0);
// Look for a Window with the right Class
firstHandle = FindWindow(windowClass, null);
// Nothing Found
if (firstHandle.Equals(IntPtr.Zero)) return IntPtr.Zero;
// Remember where we started to avoid an infinite loop
handle = firstHandle;
do
{
// Check the Caption to find the Main Window
if (GetWindowCaption(handle).EndsWith(" - Microsoft Outlook"))
{
return handle;
}
// Get the next Window with the same Class
handle = GetWindow(handle, GW_HWNDNEXT);
} while (handle != firstHandle);
// Didn't find any matches
return IntPtr.Zero;
}
private static string GetWindowCaption(IntPtr windowHandle)
{
// Determine Length of Caption
int length = GetWindowTextLength(windowHandle);
StringBuilder sb = new StringBuilder(length + 1);
// Get Window Caption
GetWindowText(windowHandle, sb, sb.Capacity);
return sb.ToString();
}
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int GetWindowTextLength(IntPtr hWnd);

C# - Is there any reliable event that exists to be notified when the screen saver become active/inactive

I'm looking for an event that would happen when the screen saver become active or inactive. I want to be notified. I do not want to use any timer.
I do not want to poll for it. I don't want to use: SystemParametersInfo( SPI_GETSCREENSAVERRUNNING, 0, ref isRunning, 0 );
I tried that without success, I never receive the SC_SCREENSAVE...
// ************************************************************************
public MainWindow()
{
InitializeComponent();
}
// ************************************************************************
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle;
HwndSource mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr);
if (mainWindowSrc != null)
{
mainWindowSrc.AddHook(WndProc);
}
//HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
//source.AddHook(WndProc);
}
// ************************************************************************
private const Int32 WM_SYSCOMMAND = 0x112;
private const int SC_SCREENSAVE = 0xF140;
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_SYSCOMMAND)
{
Debug.Print("SysCommand : " + wParam);
if (wParam.ToInt32() == SC_SCREENSAVE)
{
Debug.Print(DateTime.Now.ToString());
}
}
return IntPtr.Zero;
}
Anybody has any other idea or does know what is wrong with my code ???
if (wParam.ToInt32() == SC_SCREENSAVE)
That's not correct. It is an odd quirk in the WM_SYSCOMMAND message, surely dating to a long gone era where they had to squeeze a GUI operating system in 640 kilobytes. The low 4 bits in the command value are used for internal purposes. You'll have to mask them out before you compare. Fix:
if ((wParam.ToInt32() & 0xfff0) == SC_SCREENSAVE)
You'd probably had figured this out yourself by using the proper Debug statement formatting :)
Debug.Print("SysCommand : 0x{0:X}", wParam);
Hans answer seems to not work for me on Windows 7 when it is activated normally by the timer (at least when your account is part of a domain and a policy make screen saver parameters as readonly).
Using SystemParametersInfo with SPI_GETSCREENSAVERRUNNING work fine but it require a timer (polling) which is to my point of view: horrible poorly designed code... but up to now, it is the only way I found that works all the time... :-(
I left my code as reference. It include many of my tests.
There is a lot more but just remove what you don't need.
You could consult the HotKey excellent class there (I couldn't found my initial source but this one is exactly the same): https://github.com/shellscape/Lumen/blob/master/Application/HotkeyHandler.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using HQ.Util.General;
using HQ.Util.Unmanaged;
using HQ.Wpf.Util;
using Microsoft.Win32;
using SpreadsheetGear;
namespace MonitorMe
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public enum HookType : int
{
WH_JOURNALRECORD = 0,
WH_JOURNALPLAYBACK = 1,
WH_KEYBOARD = 2,
WH_GETMESSAGE = 3,
WH_CALLWNDPROC = 4,
WH_CBT = 5,
WH_SYSMSGFILTER = 6,
WH_MOUSE = 7,
WH_HARDWARE = 8,
WH_DEBUG = 9,
WH_SHELL = 10,
WH_FOREGROUNDIDLE = 11,
WH_CALLWNDPROCRET = 12,
WH_KEYBOARD_LL = 13,
WH_MOUSE_LL = 14
}
delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);
private HotKeyHandeler _hotKeyHandler = null;
private Timer _timerToMonitorScreenSaver = null;
// ************************************************************************
public MainWindow()
{
InitializeComponent();
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
Monitor.Instance.Add(SessionSwitchReason.SessionLogon);
_timerToMonitorScreenSaver = new Timer(TimerCallbackMonitorScreenSaver, this, 3000, 3000);
}
private void TimerCallbackMonitorScreenSaver(object state)
{
int active = 1;
SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, ref active, 0);
if (active == 1)
{
Debug.Print("Timer detected Screen Saver activated on: " + DateTime.Now.ToString());
}
}
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetWindowsHookEx(HookType hookType, HookProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll")]
static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
static extern IntPtr LoadLibrary(string lpFileName);
// Signatures for unmanaged calls
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool SystemParametersInfo(
int uAction, int uParam, ref int lpvParam,
int flags);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool SystemParametersInfo(
int uAction, int uParam, ref bool lpvParam,
int flags);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int PostMessage(IntPtr hWnd,
int wMsg, int wParam, int lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr OpenDesktop(
string hDesktop, int Flags, bool Inherit,
uint DesiredAccess);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool CloseDesktop(
IntPtr hDesktop);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool EnumDesktopWindows(
IntPtr hDesktop, EnumDesktopWindowsProc callback,
IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool IsWindowVisible(
IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetForegroundWindow();
// Callbacks
private delegate bool EnumDesktopWindowsProc(
IntPtr hDesktop, IntPtr lParam);
// Constants
private const int SPI_GETSCREENSAVERACTIVE = 16;
private const int SPI_SETSCREENSAVERACTIVE = 17;
private const int SPI_GETSCREENSAVERTIMEOUT = 14;
private const int SPI_SETSCREENSAVERTIMEOUT = 15;
private const int SPI_GETSCREENSAVERRUNNING = 114;
private const int SPIF_SENDWININICHANGE = 2;
private const uint DESKTOP_WRITEOBJECTS = 0x0080;
private const uint DESKTOP_READOBJECTS = 0x0001;
private const int WM_CLOSE = 16;
[DllImport("User32.dll")]
public static extern int SendMessage
(IntPtr hWnd,
uint Msg,
uint wParam,
uint lParam);
public enum SpecialHandles
{
HWND_DESKTOP = 0x0,
HWND_BROADCAST = 0xFFFF
}
// Registers a hot key with Windows.
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
// Unregisters the hot key with Windows.
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
private IntPtr _hHook;
// ************************************************************************
void _hotKeyHandler_HotKeyPressed(object sender, HotKeyEventArgs e)
{
ActivateScreenSaver();
}
// ************************************************************************
private IntPtr MessageHookProc(int code, IntPtr wParam, IntPtr lParam)
{
if (code == WM_SYSCOMMAND)
{
Debug.Print("SysCommand : " + wParam);
if ((wParam.ToInt32() & 0xfff0) == SC_SCREENSAVE)
{
Debug.Print("MessageHookProc" + DateTime.Now.ToString());
}
}
return CallNextHookEx(_hHook, code, wParam, lParam);
}
// ************************************************************************
private const Int32 WM_SYSCOMMAND = 0x0112;
private const int SC_SCREENSAVE = 0xF140;
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_SYSCOMMAND)
{
Debug.Print("SysCommand : " + wParam);
if ((wParam.ToInt32() & 0xfff0) == SC_SCREENSAVE)
{
// Works fine in almost all cases. I already did some code in the past which activate the screen saver
// but I never receive any WM_SYSCOMMAND for that code, I do not have source code for it anymore).
Debug.Print("WndProc" + DateTime.Now.ToString());
}
}
return IntPtr.Zero;
}
// ************************************************************************
void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
{
Monitor.Instance.Add(e.Reason);
}
// ************************************************************************
private void CmdExportToExcel_Click(object sender, RoutedEventArgs e)
{
ExportToExcel();
}
// ************************************************************************
private void ExportToExcel()
{
IWorkbook wb = Factory.GetWorkbook();
IWorksheet workSheet = wb.Worksheets[0];
int col = 1;
for (int dayIndex = -30; dayIndex <= 0; dayIndex++)
{
DateTime day = DateTime.Today + new TimeSpan(dayIndex, 0, 0, 0);
Debug.Print(day.ToString("yyyy-MM-dd"));
workSheet.Cells[0, col].Value = day.DayOfWeek.ToString();
workSheet.Cells[1, col].Value = day;
DayMonitor dayMonitor = Monitor.Instance.DayMonitors.FirstOrDefault(dm => dm.Day == day);
if (dayMonitor != null)
{
workSheet.Cells[2, col].Value = "Last - First";
workSheet.Cells[2, col + 1].Value = dayMonitor.TotalHours;
workSheet.Cells[3, col].Value = "Has estimated time (7h00 or 18h00)";
workSheet.Cells[3, col + 1].Value = dayMonitor.HasSomeEstimatedHours;
int row = 5;
foreach (var state in dayMonitor.SessionLockStateChanges)
{
workSheet.Cells[row, col].Value = state.SessionSwitchReason.ToString();
workSheet.Cells[row, col + 1].Value = state.DateTime;
row++;
}
}
workSheet.Cells[1, col].ColumnWidth = 18;
workSheet.Cells[1, col + 1].ColumnWidth = 18;
col += 2;
}
if (wb != null)
{
if (FileAssociation.IsFileAssociationExistsForExtensionWithDot(".xlsx"))
{
string path = TempFolderAutoClean.GetTempFileName("xlsx", "Export ");
wb.SaveAs(path, FileFormat.OpenXMLWorkbook);
Process p = new Process();
p.StartInfo.UseShellExecute = true;
p.StartInfo.FileName = path;
p.Start();
}
else
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.InitialDirectory = Environment.CurrentDirectory;
saveFileDialog.Filter = "Excel file (*.xlsx)|*.xlsx";
saveFileDialog.DefaultExt = ".xlsx";
if (saveFileDialog.ShowDialog(Application.Current.MainWindow) == true)
{
string path = saveFileDialog.FileName;
wb.SaveAs(path, FileFormat.OpenXMLWorkbook);
}
}
}
}
// ************************************************************************
private void PrintOnExecuted(object sender, ExecutedRoutedEventArgs e)
{
ExportToExcel();
}
// ************************************************************************
private void ExitOnExecuted(object sender, ExecutedRoutedEventArgs e)
{
this.Close();
}
// ************************************************************************
private void PrintOnCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
e.ContinueRouting = false;
}
// ************************************************************************
private void ExitOnCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
e.ContinueRouting = false;
}
// ************************************************************************
private void CmdLaunchScreenSaver_Click(object sender, RoutedEventArgs e)
{
ActivateScreenSaver();
}
// ************************************************************************
private void ActivateScreenSaver()
{
// Next won't work in a secured Screen Saver by Account Policy (ex: by a domain policy)
//int nullVar = 0;
//SystemParametersInfo(SPI_SETSCREENSAVERACTIVE, 1, ref nullVar, SPIF_SENDWININICHANGE);
// This works fine all the time... and also send appropriate message to every top level window
SendMessage(new IntPtr((int)SpecialHandles.HWND_BROADCAST), WM_SYSCOMMAND, SC_SCREENSAVE, 0);
}
// ************************************************************************
private void MainWindow_OnInitialized(object sender, EventArgs e)
{
int error;
IntPtr hMod = LoadLibrary("user32.dll"); // Hans Passant info in stackOverflow
_hHook = SetWindowsHookEx(HookType.WH_GETMESSAGE, MessageHookProc, IntPtr.Zero, (uint)Thread.CurrentThread.ManagedThreadId);
error = Marshal.GetLastWin32Error(); // Error 87
_hHook = SetWindowsHookEx(HookType.WH_GETMESSAGE, MessageHookProc, hMod, (uint)Thread.CurrentThread.ManagedThreadId);
error = Marshal.GetLastWin32Error(); // Error 87
_hHook = SetWindowsHookEx(HookType.WH_GETMESSAGE, MessageHookProc, hMod, 0);
error = Marshal.GetLastWin32Error(); // Work fine, got a hook, but never receive the WM_SYSCOMMAND:SC_SCREENSAVE
}
// ************************************************************************
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
}
// ************************************************************************
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
// Method 1
//IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle;
//HwndSource mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr);
//if (mainWindowSrc != null)
//{
// mainWindowSrc.AddHook(WndProc);
//}
// Method 2
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
_hotKeyHandler = new HotKeyHandeler(this);
_hotKeyHandler.HotKeyPressed += _hotKeyHandler_HotKeyPressed;
// _hotKeyHandler.RegisterHotKey(0, Key.NumPad0);
this.Visibility = Visibility.Hidden;
}
// ************************************************************************
}
}

How to get outlook select name dialog box to focus when opened from wpf application and outlook is running

I am creating a wpf application to send outlook appointment. In this application I am opening outlook select name dialog box to select recipients of the appointment. Following is my code:
Outlook.SelectNamesDialog selectNameDialog =
outlookApp.Session.GetSelectNamesDialog();
selectNameDialog.SetDefaultDisplayMode(
Outlook.OlDefaultSelectNamesDisplayMode.olDefaultMeeting);
foreach (var recipient in recipientsList)
{
if (string.IsNullOrEmpty(recipient))
continue;
Outlook.Recipient confRoom =
selectNameDialog.Recipients.Add(recipient);
// Explicitly specify Recipient.Type.
confRoom.Type = (int)Outlook.OlMeetingRecipientType.olRequired;
}
selectNameDialog.Recipients.ResolveAll();
selectNameDialog.Display();
My problem is that when I open select name dialog it works fine if outlook is not running. But if outlook is running and I open this dialog on click from my application, it opens in back of my application and on top of outlook window. I need to show it on top of my application even if outlook is running. Any help will be highly appreciated to bring this dialog in front of all. Thanks in advance.
You can try to get the outlook Process and bring his windows forward. There is not .NET hook to do so, you will need to use native Win32 DLL for that.
[Flags()]
private enum SetWindowPosFlags : uint
{
SynchronousWindowPosition = 0x4000,
DeferErase = 0x2000,
DrawFrame = 0x0020,
FrameChanged = 0x0020,
HideWindow = 0x0080,
DoNotActivate = 0x0010,
DoNotCopyBits = 0x0100,
IgnoreMove = 0x0002,
DoNotChangeOwnerZOrder = 0x0200,
DoNotRedraw = 0x0008,
DoNotReposition = 0x0200,
DoNotSendChangingEvent = 0x0400,
IgnoreResize = 0x0001,
IgnoreZOrder = 0x0004,
ShowWindow = 0x0040,
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern bool BringWindowToTop(IntPtr hWnd);
static readonly IntPtr HWND_TOP = new IntPtr(0);
static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);
[DllImport("user32.dll")]
static extern IntPtr SetFocus(IntPtr hWnd);
int bring_window_to_front_mode = 1; // Various option here, try them out
Boolean TopMost = false;
System.Diagnostics.Process[] prcs = System.Diagnostics.Process.GetProcessesByName("XBMCLauncher");
foreach (var proc in prcs)
{
Log.LogLine("Main Window Handle {0}", p.MainWindowHandle.ToInt32());
switch (bring_window_to_front_mode)
{
case 1:
if (TopMost)
{
Log.LogLine("SetWindowPos TopMost {0}", p.MainWindowHandle.ToInt32());
SetWindowPos(p.MainWindowHandle, HWND_TOPMOST, 50, 50, 500, 500, SetWindowPosFlags.IgnoreMove | SetWindowPosFlags.IgnoreResize);
}
else
{
Log.LogLine("SetWindowPos {0}", p.MainWindowHandle.ToInt32());
SetWindowPos(p.MainWindowHandle, HWND_TOP, 50, 50, 500, 500, SetWindowPosFlags.IgnoreMove | SetWindowPosFlags.IgnoreResize);
}
break;
case 2:
Log.LogLine("BringWindowToTop {0}", p.MainWindowHandle.ToInt32());
BringWindowToTop(p.MainWindowHandle);
break;
case 3:
Log.LogLine("SetForegroundWindow {0}", p.MainWindowHandle.ToInt32());
SetForegroundWindow(p.MainWindowHandle);
break;
case 4:
Log.LogLine("SetFocus {0}", p.MainWindowHandle.ToInt32());
SetFocus(p.MainWindowHandle);
break;
}
}
Of course Try/Catch...

How to set the height of a window using c#?

Is it possible to set the height of a window using the window handle or process handle?
I have the following so far, assume the application in question is notepad.
Process[] processes = Process.GetProcessesByName("notepad");
foreach (Process p in processes)
{
if (p.MainWindowTitle == title)
{
handle = p.MainWindowHandle;
while ((handle = p.MainWindowHandle) == IntPtr.Zero)
{
Thread.Sleep(1000);
p.Refresh();
}
break;
}
}
Can I make use of handle or p to set the height of the window?
This is how I would do it:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("user32.dll", SetLastError = true)]
static extern bool GetWindowRect(IntPtr hWnd, ref RECT Rect);
[DllImport("user32.dll", SetLastError = true)]
static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int Width, int Height, bool Repaint);
static void Main(string[] args)
{
Process[] processes = Process.GetProcessesByName("notepad");
foreach (Process p in processes)
{
IntPtr handle = p.MainWindowHandle;
RECT Rect = new RECT();
if (GetWindowRect(handle, ref Rect))
MoveWindow(handle, Rect.left, Rect.right, Rect.right-Rect.left, Rect.bottom-Rect.top + 50, true);
}
}
}
}
While you can do it with SetWindowPos, and SetWindowPos is the newer and more capable API, MoveWindow is just easier to call.
You should be able to use the Win32 SetWindowPos function (use for both position and size). Here's a link for how to do it in C#.
Here's a quick sample. This will move notepad to (10,10) on the screen, and resize it to (450,450):
class Program
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);
static void Main(string[] args)
{
Console.WriteLine("Start notepad and hit any key...");
Console.ReadKey(true);
Process[] processes = Process.GetProcessesByName("notepad");
foreach (Process p in processes)
{
var handle = p.MainWindowHandle;
SetWindowPos(handle, new IntPtr(SpecialWindowHandles.HWND_TOP), 10,10,450,450,SetWindowPosFlags.SWP_SHOWWINDOW);
break;
}
}
}
public enum SpecialWindowHandles
{
HWND_TOP = 0,
HWND_BOTTOM = 1,
HWND_TOPMOST = -1,
HWND_NOTOPMOST = -2
}
[Flags]
public enum SetWindowPosFlags : uint
{
SWP_ASYNCWINDOWPOS = 0x4000,
SWP_DEFERERASE = 0x2000,
SWP_DRAWFRAME = 0x0020,
SWP_FRAMECHANGED = 0x0020,
SWP_HIDEWINDOW = 0x0080,
SWP_NOACTIVATE = 0x0010,
SWP_NOCOPYBITS = 0x0100,
SWP_NOMOVE = 0x0002,
SWP_NOOWNERZORDER = 0x0200,
SWP_NOREDRAW = 0x0008,
SWP_NOREPOSITION = 0x0200,
SWP_NOSENDCHANGING = 0x0400,
SWP_NOSIZE = 0x0001,
SWP_NOZORDER = 0x0004,
SWP_SHOWWINDOW = 0x0040,
}

Categories

Resources