Getting Outlook Window from VSTO Addin - c#

I have an Outlook 2013 VSTO addin. I want to center my saveFileDialog that I create. To do this you need to pass it a Window object of the parent. I'm not sure if IWin32Window and Window are the same, but here's what I have.
public IWin32Window getWindowHandle()
{
dynamic activeWindow = Globals.ThisAddIn.Application.ActiveWindow();
IntPtr outlookHwnd = new OfficeWin32Window(activeWindow).Handle;
IWin32Window win = Control.FromHandle(outlookHwnd);
return win;
}
The SaveFileDialog.ShowDialog(Window) method takes a window. Can I pass it the IWin32Window? Is there a way to get the Window object from the handler other than Control.FromHandle?
Any criticisms would be welcome.
Thanks
EDIT:
Oh and the helper class for that function:
public class OfficeWin32Window : IWin32Window
{
[DllImport("user32")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
IntPtr _windowHandle = IntPtr.Zero;
public IntPtr Handle
{
get { return _windowHandle; }
}
public OfficeWin32Window(object windowObject)
{
string caption = windowObject.GetType().InvokeMember("Caption", System.Reflection.BindingFlags.GetProperty, null, windowObject, null).ToString();
// try to get the HWND ptr from the windowObject / could be an Inspector window or an explorer window
_windowHandle = FindWindow("rctrl_renwnd32\0", caption);
}
}
I was given this code, so I do have a side question about it: What does FindWindow("rctrl_renwnd32\0", caption) do? I don't get it at all. Especially the "rctrl_renwnd32\0" part.
EDIT:
New function with IOleWindow class:
public IOleWindow getWindowHandle()
{
dynamic activeWindow = Globals.ThisAddIn.Application.ActiveWindow();
IOleWindow win = activeWindow as IOleWindow;
window = win.GetWindow();
//IntPtr outlookHwnd = new OfficeWin32Window(activeWindow).Handle;
//IWin32Window wind = Control.FromHandle(outlookHwnd);
return window;
}
EDIT2:
My updated logic, I removed the function and added this in the place I need tthe handle:
Inspector currentObject = Globals.ThisAddIn.Application.ActiveInspector();
var winh = currentObject as IOleWindow;
IntPtr win = winh.GetWindow();
EDIT3:
Restructured:
Inspector currentObject = Globals.ThisAddIn.Application.ActiveInspector();
var winh = currentObject as IOleWindow;
IntPtr win;
winh.GetWindow(out win);

The FindWindow method retrieves a handle to the top-level window whose class name and window name match the specified strings. The first parameter specifies the window class name. The second parameter is the window name (the window's title). If this parameter is NULL, all window names match.
Instead of using the FindWindow function you need to cast the Explorer or Inspector window to the IOleWindow interface and use the GetWindow method to get the window handle.
/// <summary>
/// Implemented and used by containers and objects to obtain window handles
/// and manage context-sensitive help.
/// </summary>
/// <remarks>
/// The IOleWindow interface provides methods that allow an application to obtain
/// the handle to the various windows that participate in in-place activation,
/// and also to enter and exit context-sensitive help mode.
/// </remarks>
[ComImport]
[Guid("00000114-0000-0000-C000-000000000046")]
[InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleWindow
{
/// <summary>
/// Returns the window handle to one of the windows participating in in-place activation
/// (frame, document, parent, or in-place object window).
/// </summary>
/// <param name="phwnd">Pointer to where to return the window handle.</param>
void GetWindow (out IntPtr phwnd) ;
/// <summary>
/// Determines whether context-sensitive help mode should be entered during an
/// in-place activation session.
/// </summary>
/// <param name="fEnterMode"><c>true</c> if help mode should be entered;
/// <c>false</c> if it should be exited.</param>
void ContextSensitiveHelp ([In, MarshalAs(UnmanagedType.Bool)] bool fEnterMode) ;
}
An instance of the IWin32Window interface is used to specify the parent window handle for the Show or ShowDialog methods.

Related

Retrieve a window handle whitin outlook

I'm working on a custom outlook addin where I need to subclass the appointment window. This works basically pretty well following the principles mentioned in the following ariticle:
http://www.codeproject.com/Articles/27262/Additional-custom-panel-in-Microsoft-Outlook
I'm struggeling by getting the handle to the social connector within the new appointment window.
I've tryied out a few approaches (FindWindow, FindWindowEx, EnumChildWindow) but none of them gave me the correct handle.
Here you can find a small addin project to have a quick look at it.
Download
Or have a quick look at this abstract
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Outlook;
using Office = Microsoft.Office.Core;
namespace FindSocialConnector._2013
{
public partial class ThisAddIn
{
/// <summary>
/// Delegate for the EnumChildWindows method
/// </summary>
/// <param name="hWnd">Window handle</param>
/// <param name="parameter">Caller-defined variable; we use it for a pointer to our list</param>
/// <returns>True to continue enumerating, false to bail.</returns>
public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);
/// <summary>
/// Hält den Klassennamen des NewAppointment Windows.
/// </summary>
public const string NewAppointmentWindowClass = "rctrl_renwnd32";
private Inspectors _inspectors;
/// <summary>
/// The EnumChildWindows function enumerates the child windows that belong to the specified parent window by passing the handle to each child window,
/// in turn, to an application-defined callback function. EnumChildWindows continues until the last child window is enumerated or the callback function returns FALSE.
/// </summary>
/// <param name="parentHandle">
/// Handle to the parent window whose child windows are to be enumerated.
/// If this parameter is NULL, this function is equivalent to EnumWindows.
/// Windows 95/98/Me: parentHandle cannot be NULL.
/// </param>
/// <param name="callbackFunction">
/// Pointer to an application-defined callback function. For more information, see EnumChildProc.
/// </param>
/// <param name="param">
/// Specifies an application-defined value to be passed to the callback function.
/// </param>
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern int EnumChildWindows(IntPtr parentHandle, Delegate callbackFunction, IntPtr param);
/// <summary>
/// Retrieves a handle to the top-level window whose class name and window name match the specified strings. This function does not search child windows.
/// This function does not perform a case-sensitive search. To search child windows, beginning with a specified child window, use the FindWindowEx function.
/// <returns>
/// <param name="className">
/// The class name or a class atom created by a previous call to the RegisterClass or RegisterClassEx function.
/// The atom must be in the low-order word of lpClassName; the high-order word must be zero.
/// If lpClassName points to a string, it specifies the window class name.
/// The class name can be any name registered with RegisterClass or RegisterClassEx, or any of the predefined control-class names.
/// If lpClassName is NULL, it finds any window whose title matches the lpWindowName parameter.
/// </param>
/// <param name="windowName">The window name (the window's title). If this parameter is NULL, all window names match.</param>
/// If the function succeeds, the return value is a handle to the window that has the specified class name and window name.
/// If the function fails, the return value is NULL. To get extended error information, call GetLastError.
/// </returns>
/// </summary>
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string className, string windowName);
/// <summary>
/// The FindWindowEx function retrieves a handle to a window whose class name and window name match the specified strings.
/// The function searches child windows, beginning with the one following the specified child window.
/// This function does not perform a case-sensitive search.
/// </summary>
/// <param name="parentHandle">
/// Handle to the parent window whose child windows are to be searched.
/// If hwndParent is NULL, the function uses the desktop window as the parent window.
/// The function searches among windows that are child windows of the desktop.
/// </param>
/// <param name="childAfter">
/// Handle to a child window. The search begins with the next child window in the Z order.
/// The child window must be a direct child window of hwndParent, not just a descendant window.
/// If hwndChildAfter is NULL, the search begins with the first child window of hwndParent.
/// </param>
/// <param name="className">
/// Pointer to a null-terminated string that specifies the class name or a class atom created by a previous call to the RegisterClass or RegisterClassEx function.
/// The atom must be placed in the low-order word of lpszClass; the high-order word must be zero.
/// </param>
/// <param name="windowTitle">
/// Pointer to a null-terminated string that specifies the window name (the window's title).
/// If this parameter is NULL, all window names match.
/// </param>
/// <returns>
/// If the function succeeds, the return value is a handle to the window that has the specified class and window names.
/// If the function fails, the return value is NULL. To get extended error information, call GetLastError.
/// </returns>
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
/// <summary>
/// Liefert das Handle des NewAppointmentWindow's.
/// </summary>
private static IntPtr FindNewAppointmentWindowByCaption(string caption)
{
IntPtr newAppointmentWindowHandle = FindWindow(NewAppointmentWindowClass, caption);
if (newAppointmentWindowHandle == IntPtr.Zero)
{
throw new ArgumentException("NewAppointment Window wasn't found.");
}
return newAppointmentWindowHandle;
}
private void ThisAddIn_Startup(object sender, EventArgs e)
{
_inspectors = Application.Inspectors;
_inspectors.NewInspector += Inspectors_NewInspector;
}
private void Inspectors_NewInspector(Inspector inspector)
{
AppointmentItem appointmentItem = inspector.CurrentItem as AppointmentItem;
if (appointmentItem != null)
{
IntPtr appointmentWindow = FindNewAppointmentWindowByCaption(inspector.Caption);
// Get all child windows based on the new appointment window
// Unfortunately the social connector handle isn't returned
GetChildWindows(appointmentWindow);
// Directly get the social connector based on the class name
// Unfortunately this returns 0
IntPtr socialConnectorWindow = FindWindowEx(appointmentWindow, IntPtr.Zero, "MerenguePane", null);
}
}
/// <summary>
/// Callback method to be used when enumerating windows.
/// </summary>
/// <param name="handle">Handle of the next window</param>
/// <param name="pointer">Pointer to a GCHandle that holds a reference to the list to fill</param>
/// <returns>True to continue the enumeration, false to bail</returns>
private static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
GCHandle gch = GCHandle.FromIntPtr(pointer);
List<IntPtr> list = gch.Target as List<IntPtr>;
if (list == null)
{
throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
}
Debug.WriteLine("Current Window Handle: {0}, Hex: {1}", handle, handle.ToString("X"));
list.Add(handle);
// You can modify this to check to see if you want to cancel the operation, then return a null here
return true;
}
/// <summary>
/// Returns a list of child windows
/// </summary>
/// <param name="parent">Parent of the windows to return</param>
/// <returns>List of child windows</returns>
public static List<IntPtr> GetChildWindows(IntPtr parent)
{
List<IntPtr> result = new List<IntPtr>();
GCHandle listHandle = GCHandle.Alloc(result);
try
{
EnumWindowProc childProc = EnumWindow;
EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
}
finally
{
if (listHandle.IsAllocated)
{
listHandle.Free();
}
}
return result;
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
Startup += ThisAddIn_Startup;
}
}
}
Btw. the social connector is only displayed if you directly create a meeting request e.g. go to the calendar, right click --> New meeting request
Any thoughts on this?
Regards,
Lukas

Form does not work unless .Show() is called

I have a form that represents a USB device Terminal that has been giving me some errors. After half a day of debugging strange errors with no known source I somehow found out that the Terminal does not function when it is instantiated but not shown. When I change the code and add usbTerminal.Show();, then it works properly.
USBTerminal usbTouchTerminal;
public MainForm()
{
InitializeComponent();
USBSettings usbTouchSettings = new USBSettings();
usbTouchTerminal = new USBTerminal(usbTouchSettings); //Create Terminal with settings
usbTouchTerminal.StartUSB();
usbTouchTerminal.Show(); //works ONLY when show is here
}
How is this possible and why? I've done a massive search and none of my code depends on the .Visible property on either my Terminal or main form?
I'm completely baffled on why some form would not work if it isn't shown. MSDN or google wasn't really a help either. I was certain it would function properly when instantiated but not shown.
PS. I added
usbTerminal.Show();
usbTerminal.Hide();
and the Terminal functioned correctly.
Thank you for any help!
EDIT:
I should also note that this usbTerminal uses the WndProc override. I'm not an expert on that, but I feel that it may have something to do with it.
I should note that this is LibUSBdotnet
public class USBSettings
{
/// <summary>
/// This is the Vender ID Number. (0x0B6A)
/// </summary>
public ushort VID { get; set; }
/// <summary>
/// This is the Product ID Number. (0x5346)
/// </summary>
public ushort PID { get; set; }
/// <summary>
/// This is the optional Serial Name. ("")
/// </summary>
public string SerialName { get; set; }
/// <summary>
/// This is the Reader USB Endpoint. (ReadEndpointID.Ep02)
/// </summary>
public ReadEndpointID ReaderEndpoint { get; set; }
/// <summary>
/// This is the Writer USB Endpoint. (WriteEndpointID.Ep01)
/// </summary>
public WriteEndpointID WriterEndpoint { get; set; }
/// <summary>
/// This is the Registry Key for USB settings. ("SOFTWARE\\DEFAULT\\USBPROPERTIES")
/// </summary>
public string SubKey { get; set; }
/// <summary>
/// This is the default read buffer size for the USB Device.
/// </summary>
public int ReadBufferSize { get; set; }
/// <summary>
/// This constructor houses default values for all properties.
/// </summary>
public USBSettings()
{
VID = 0x0B6A;
PID = 0x5346;
SerialName = "";
ReaderEndpoint = ReadEndpointID.Ep02;
WriterEndpoint = WriteEndpointID.Ep01;
SubKey = "SOFTWARE\\DEFAULT\\USBPROPERTIES";
ReadBufferSize = 100;
}
}
The question is poorly documented but this is fairly normal for code that works with devices. They tend to need to know about Plug & Play events and that requires a top-level window to be created that receives the WM_DEVICECHANGE notification message. Creating a .NET Form object isn't enough, you also have to create the native window for it. Which, in typical .NET lazy fashion, happens at the last possible moment, when you force the window to be visible. Either by calling the Show() method or setting the Visible property to true. The window doesn't actually have to be visible to get the Plug & Play notifications.
You can get the window created without also making it visible. That requires modifying the USBTerminal class. Paste this code:
protected override void SetVisibleCore(bool value) {
if (!this.IsHandleCreated) {
this.CreateHandle();
value = false;
}
base.SetVisibleCore(value);
}
And call the Show() method as normal. Beware that the Load event won't fire until the window actually becomes visible so if necessary move any code in the event handler to this method. If this is not the primary window for the app, in other words not the one that's passed to Application.Run() in your Main() method, then you can make do with simply calling this.CreateHandle() as the last statement in the form constructor. In which case calling Show() is no longer necessary.
I suspect this is because the underlying window is not created before you call Show(). Since the window isn't created, your custom WndProc isn't called.
To verify, you can create the window without showing it - by looking at the Handle property. As the documentation says - if the handle has not been created by the time you call, it will be created. Try it, I bet it'll work just as if you called Show and then Hide.
It is very hard to tell from the information you have but I think you are using a form where a class should be used. You should rethink your program structure and re-write this as a class to hold and transmit the data as you need. As some of the other have pointed out the listbox and/or other function are not running until the form is shown and the methods is executed.
Because some required functions will be called when Form onShow event called.

Why does print screen in a Windows Service return a black image?

protected override void OnStart(string[] args)
{
base.OnStart(args);
CaptureScreen();
}
protected override void OnStop()
{
base.OnStop();
}
private void CaptureScreen()
{
Bitmap printscreen = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics graphics = Graphics.FromImage(printscreen as Image);
graphics.CopyFromScreen(0, 0, 0, 0, printscreen.Size);
printscreen.Save(#"L:\" + Counter++ + ".jpg", ImageFormat.Jpeg);
}
I checked interact with desktop
tried the the localService account & user
This is part of the session 0 isolation feature that was added to Vista. Services now run their own session with their own workstation and desktop. Much like the session that the login prompt and screen saver run in. You are taking a screenshot of that session's desktop, there's nothing in it. Getting access to the user desktop is no longer possible. It is a security feature, it prevents shatter attacks. Admittedly, I don't understand why the 'interact with desktop' checkbox wasn't removed.
You'll need to change your program to run as a "windows application", not a service. Put a shortcut in the Startup folder or use the Run registry key. Which is okay, there's nothing much worth snapping when no user is logged in.
You need to set your service to the users windows station. This is not my code and I can't remember where I got it from.
Add these two classes
then you can create a Desktop object
Desktop userDesk = new Desktop();
Then when you need your service to interact with the user session you would write
userDesk.BeginInteraction();
and finally to return to your service's session you call
userDesk.EndInteraction();
internal class Desktop
{
private IntPtr m_hCurWinsta = IntPtr.Zero;
private IntPtr m_hCurDesktop = IntPtr.Zero;
private IntPtr m_hWinsta = IntPtr.Zero;
private IntPtr m_hDesk = IntPtr.Zero;
/// <summary>
/// associate the current thread to the default desktop
/// </summary>
/// <returns></returns>
internal bool BeginInteraction()
{
EndInteraction();
m_hCurWinsta = User32DLL.GetProcessWindowStation();
if (m_hCurWinsta == IntPtr.Zero)
return false;
m_hCurDesktop = User32DLL.GetDesktopWindow();
if (m_hCurDesktop == IntPtr.Zero)
return false;
m_hWinsta = User32DLL.OpenWindowStation("winsta0", false,
WindowStationAccessRight.WINSTA_ACCESSCLIPBOARD |
WindowStationAccessRight.WINSTA_ACCESSGLOBALATOMS |
WindowStationAccessRight.WINSTA_CREATEDESKTOP |
WindowStationAccessRight.WINSTA_ENUMDESKTOPS |
WindowStationAccessRight.WINSTA_ENUMERATE |
WindowStationAccessRight.WINSTA_EXITWINDOWS |
WindowStationAccessRight.WINSTA_READATTRIBUTES |
WindowStationAccessRight.WINSTA_READSCREEN |
WindowStationAccessRight.WINSTA_WRITEATTRIBUTES
);
if (m_hWinsta == IntPtr.Zero)
return false;
User32DLL.SetProcessWindowStation(m_hWinsta);
m_hDesk = User32DLL.OpenDesktop("default", OpenDesktopFlag.DF_NONE, false,
DesktopAccessRight.DESKTOP_CREATEMENU |
DesktopAccessRight.DESKTOP_CREATEWINDOW |
DesktopAccessRight.DESKTOP_ENUMERATE |
DesktopAccessRight.DESKTOP_HOOKCONTROL |
DesktopAccessRight.DESKTOP_JOURNALPLAYBACK |
DesktopAccessRight.DESKTOP_JOURNALRECORD |
DesktopAccessRight.DESKTOP_READOBJECTS |
DesktopAccessRight.DESKTOP_SWITCHDESKTOP |
DesktopAccessRight.DESKTOP_WRITEOBJECTS
);
if (m_hDesk == IntPtr.Zero)
return false;
User32DLL.SetThreadDesktop(m_hDesk);
return true;
}
/// <summary>
/// restore
/// </summary>
internal void EndInteraction()
{
if (m_hCurWinsta != IntPtr.Zero)
User32DLL.SetProcessWindowStation(m_hCurWinsta);
if (m_hCurDesktop != IntPtr.Zero)
User32DLL.SetThreadDesktop(m_hCurDesktop);
if (m_hWinsta != IntPtr.Zero)
User32DLL.CloseWindowStation(m_hWinsta);
if (m_hDesk != IntPtr.Zero)
User32DLL.CloseDesktop(m_hDesk);
}
}
public static class User32DLL
{
/// <summary>
/// The GetDesktopWindow function returns a handle to the desktop window.
/// The desktop window covers the entire screen.
/// The desktop window is the area on top of which other windows are painted.
/// </summary>
/// <returns>The return value is a handle to the desktop window. </returns>
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr GetDesktopWindow();
/// <summary>
/// Retrieves a handle to the current window station for the calling process.
/// </summary>
/// <returns>If the function succeeds,
/// the return value is a handle to the window station.
/// If the function fails, the return value is NULL.</returns>
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr GetProcessWindowStation();
/// <summary>
/// Retrieves a handle to the desktop assigned to the specified thread.
/// </summary>
/// <param name="dwThread">[in] Handle to the thread
/// for which to return the desktop handle.</param>
/// <returns>If the function succeeds, the return value is a handle to the
/// desktop associated with the specified thread.
/// If the function fails, the return value is NULL.</returns>
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr GetThreadDesktop(uint dwThread);
/// <summary>
/// Opens the specified window station.
/// </summary>
/// <param name="lpszWinSta">Pointer to a null-terminated
/// string specifying the name of the window station
/// to be opened. Window station names are case-insensitive.
/// This window station must belong to the current session.
/// </param>
/// <param name="fInherit">[in] If this value
/// is TRUE, processes created by this process
/// will inherit the handle. Otherwise,
/// the processes do not inherit this handle.
/// </param>
/// <param name="dwDesiredAccess">[in] Access to the window station</param>
/// <returns>If the function succeeds, the return value
/// is the handle to the specified window station.
/// If the function fails, the return value is NULL.</returns>
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr OpenWindowStation(string lpszWinSta
, bool fInherit
, WindowStationAccessRight dwDesiredAccess
);
/// <summary>
/// Assigns the specified window station to the calling process.
/// This enables the process to access objects in the window
/// station such as desktops, the clipboard, and global atoms.
/// All subsequent operations on the window station
/// use the access rights granted to hWinSta.
/// </summary>
/// <param name="hWinSta">[in] Handle to the window
/// station to be assigned to the calling process</param>
/// <returns>If the function succeeds, the return value is nonzero.
/// If the function fails, the return value is zero. </returns>
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr SetProcessWindowStation(IntPtr hWinSta);
/// <summary>
/// Closes an open window station handle.
/// </summary>
/// <param name="hWinSta">[in] Handle
/// to the window station to be closed.</param>
/// <returns>If the function succeeds, the return value is nonzero.
/// If the function fails, the return value is zero. </returns>
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr CloseWindowStation(IntPtr hWinSta);
/// <summary>
/// Opens the specified desktop object.
/// </summary>
/// <param name="lpszDesktop">[in] Pointer to null-terminated string
/// specifying the name of the desktop to be opened.
/// Desktop names are case-insensitive.
/// This desktop must belong to the current window station.</param>
/// <param name="dwFlags">[in] This parameter can
/// be zero or DF_ALLOWOTHERACCOUNTHOOK=0x0001</param>
/// <param name="fInherit">[in] If this value is TRUE, processes created by
/// this process will inherit the handle.
/// Otherwise, the processes do not inherit this handle. </param>
/// <param name="dwDesiredAccess">[in] Access
/// to the desktop. For a list of access rights</param>
/// <returns>If the function succeeds, the return value is a handle to the opened desktop.
/// When you are finished using the handle, call the CloseDesktop function to close it.
/// If the function fails, the return value is NULL.
/// </returns>
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr OpenDesktop(string lpszDesktop
, OpenDesktopFlag dwFlags
, bool fInherit
, DesktopAccessRight dwDesiredAccess
);
/// <summary>
/// Closes an open handle to a desktop object.
/// </summary>
/// <param name="hDesktop">[in] Handle to the desktop to be closed.</param>
/// <returns>If the function succeeds, the return value is nonzero.
/// If the function fails, the return value is zero. </returns>
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr CloseDesktop(IntPtr hDesktop);
/// <summary>
/// Assigns the specified desktop to the calling thread.
/// All subsequent operations on the desktop use the access rights granted to the desktop.
/// </summary>
/// <param name="hDesktop">[in] Handle to the desktop
/// to be assigned to the calling thread.</param>
/// <returns>If the function succeeds, the return value is nonzero.
/// If the function fails, the return value is zero. </returns>
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool SetThreadDesktop(IntPtr hDesktop);
}
/// <summary>
/// REF MSDN:Window Station Security and Access Rights
/// ms-help://MS.MSDN.vAug06.en/dllproc/base/window_station_security_and_access_rights.htm
/// </summary>
[FlagsAttribute]
public enum WindowStationAccessRight : uint
{
/// <summary>All possible access rights for the window station.</summary>
WINSTA_ALL_ACCESS = 0x37F,
/// <summary>Required to use the clipboard.</summary>
WINSTA_ACCESSCLIPBOARD = 0x0004,
/// <summary>Required to manipulate global atoms.</summary>
WINSTA_ACCESSGLOBALATOMS = 0x0020,
/// <summary>Required to create new desktop
/// objects on the window station.</summary>
WINSTA_CREATEDESKTOP = 0x0008,
/// <summary>Required to enumerate existing desktop objects.</summary>
WINSTA_ENUMDESKTOPS = 0x0001,
/// <summary>Required for the window station to be enumerated.</summary>
WINSTA_ENUMERATE = 0x0100,
/// <summary>Required to successfully call the ExitWindows or ExitWindowsEx function.
/// Window stations can be shared by users and this access type can prevent other users
/// of a window station from logging off the window station owner.</summary>
WINSTA_EXITWINDOWS = 0x0040,
/// <summary>Required to read the attributes of a window station object.
/// This attribute includes color settings
/// and other global window station properties.</summary>
WINSTA_READATTRIBUTES = 0x0002,
/// <summary>Required to access screen contents.</summary>
WINSTA_READSCREEN = 0x0200,
/// <summary>Required to modify the attributes of
/// a window station object.
/// The attributes include color settings
/// and other global window station properties.</summary>
WINSTA_WRITEATTRIBUTES = 0x0010,
}
/// <summary>
/// OpenDesktop 2nd param
/// </summary>
public enum OpenDesktopFlag : uint
{
/// <summary>
/// Default value
/// </summary>
DF_NONE = 0x0000,
/// <summary>
/// Allows processes running in other accounts on the desktop
/// to set hooks in this process.
/// </summary>
DF_ALLOWOTHERACCOUNTHOOK = 0x0001,
}
/// <summary>
/// REF MSDN:Desktop Security and Access Rights
/// ms-help://MS.MSDN.vAug06.en/dllproc/base/desktop_security_and_access_rights.htm
/// </summary>
[FlagsAttribute]
public enum DesktopAccessRight : uint
{
/// <summary>Required to create a menu on the desktop. </summary>
DESKTOP_CREATEMENU = 0x0004,
/// <summary>Required to create a window on the desktop. </summary>
DESKTOP_CREATEWINDOW = 0x0002,
/// <summary>Required for the desktop to be enumerated. </summary>
DESKTOP_ENUMERATE = 0x0040,
/// <summary>Required to establish any of the window hooks. </summary>
DESKTOP_HOOKCONTROL = 0x0008,
/// <summary>Required to perform journal playback on a desktop. </summary>
DESKTOP_JOURNALPLAYBACK = 0x0020,
/// <summary>Required to perform journal recording on a desktop. </summary>
DESKTOP_JOURNALRECORD = 0x0010,
/// <summary>Required to read objects on the desktop. </summary>
DESKTOP_READOBJECTS = 0x0001,
/// <summary>Required to activate the desktop
/// using the SwitchDesktop function. </summary>
DESKTOP_SWITCHDESKTOP = 0x0100,
/// <summary>Required to write objects on the desktop. </summary>
DESKTOP_WRITEOBJECTS = 0x0080,
}
The service is "headless", no UI and without being a 100% sure (The documentation for CopyFromScreen is rather vague) I'd expect that to fail when running headless. How would the service know which screen to copy in the case where multiple users are logged on at the same time?
see this questions as well
In the case of XP/2003 the Interact with Desktop should help.
In the case of Windows 7/Windows 2008 an Interact with Desktop works differently.
The best solution for you would be to analyze logon sessions from the service and, for new session, start the "desktop" process in user session and communicate with that process to get screens.
It may just be as simple as turning the accelerator off in your browser. That worked for me. In Chrome it's under the System menu.

How do I create an "unfocusable" form in C#?

I'm looking to create a form in C# that cannot accept focus, i.e. when I click a button on the form, focus is not stolen from the application that currently has the focus.
See the Windows on-screen keyboard for an example of this. Note that when you click a button, the focus is not taken from the application you're currently using.
How can I implement this behaviour?
Update:
Turns out it's as simple as overriding the CreateParams property and adding WS_EX_NOACTIVATE to the extended window style. Thanks for pointing me in the right direction!
Unfortunately this has the undesirable side-effect that it messes with form movement, i.e. you can still drag and drop the form around the screen but the window's border is not displayed while dragging so it's difficult to precisely position it.
If anyone knows how to solve this it would be appreciated.
To disable activation by mouse:
class NonFocusableForm : Form
{
protected override void DefWndProc(ref Message m)
{
const int WM_MOUSEACTIVATE = 0x21;
const int MA_NOACTIVATE = 0x0003;
switch(m.Msg)
{
case WM_MOUSEACTIVATE:
m.Result = (IntPtr)MA_NOACTIVATE;
return;
}
base.DefWndProc(ref m);
}
}
To show form without activation (the only one way that worked for me in case of borderless form):
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr handle, int flags);
NativeMethods.ShowWindow(form.Handle, 8);
Standard way to do this (seems like it doesn't work for all form styles):
protected override bool ShowWithoutActivation
{
get { return true; }
}
If there are other ways of activating the form, they can be suppressed in similar manner.
This is the "NoFocusForm" I use:
public class NoFocusForm : Form
{
/// From MSDN <see cref="https://learn.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles"/>
/// A top-level window created with this style does not become the
/// foreground window when the user clicks it. The system does not
/// bring this window to the foreground when the user minimizes or
/// closes the foreground window. The window should not be activated
/// through programmatic access or via keyboard navigation by accessible
/// technology, such as Narrator. To activate the window, use the
/// SetActiveWindow or SetForegroundWindow function. The window does not
/// appear on the taskbar by default. To force the window to appear on
/// the taskbar, use the WS_EX_APPWINDOW style.
private const int WS_EX_NOACTIVATE = 0x08000000;
public NoFocusForm()
{
// my other initiate stuff
}
/// <summary>
/// Prevent form from getting focus
/// </summary>
protected override CreateParams CreateParams
{
get
{
var createParams = base.CreateParams;
createParams.ExStyle |= WS_EX_NOACTIVATE;
return createParams;
}
}
}

How to prevent flickering in ListView when updating a single ListViewItem's text?

All I want is to update an ListViewItem's text whithout seeing any flickering.
This is my code for updating (called several times):
listView.BeginUpdate();
listViewItem.SubItems[0].Text = state.ToString(); // update the state
listViewItem.SubItems[1].Text = progress.ToString(); // update the progress
listView.EndUpdate();
I've seen some solutions that involve overriding the component's WndProc():
protected override void WndProc(ref Message m)
{
if (m.Msg == (int)WM.WM_ERASEBKGND)
{
m.Msg = (int)IntPtr.Zero;
}
base.WndProc(ref m);
}
They say it solves the problem, but in my case It didn't. I believe this is because I'm using icons on every item.
The accepted answer works, but is quite lengthy, and deriving from the control (like mentioned in the other answers) just to enable double buffering is also a bit overdone. But fortunately we have reflection and can also call internal methods if we like to (but be sure what you do!).
Be encapsulating this approach into an extension method, we'll get a quite short class:
public static class ControlExtensions
{
public static void DoubleBuffering(this Control control, bool enable)
{
var method = typeof(Control).GetMethod("SetStyle", BindingFlags.Instance | BindingFlags.NonPublic);
method.Invoke(control, new object[] { ControlStyles.OptimizedDoubleBuffer, enable });
}
}
Which can easily be called within our code:
InitializeComponent();
myListView.DoubleBuffering(true); //after the InitializeComponent();
And all flickering is gone.
Update
I stumbled on this question and due to this fact, the extension method should (maybe) better be:
public static void DoubleBuffered(this Control control, bool enable)
{
var doubleBufferPropertyInfo = control.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
doubleBufferPropertyInfo.SetValue(control, enable, null);
}
To end this question, here is a helper class that should be called when the form is loading for each ListView or any other ListView's derived control in your form. Thanks to "Brian Gillespie" for giving the solution.
public enum ListViewExtendedStyles
{
/// <summary>
/// LVS_EX_GRIDLINES
/// </summary>
GridLines = 0x00000001,
/// <summary>
/// LVS_EX_SUBITEMIMAGES
/// </summary>
SubItemImages = 0x00000002,
/// <summary>
/// LVS_EX_CHECKBOXES
/// </summary>
CheckBoxes = 0x00000004,
/// <summary>
/// LVS_EX_TRACKSELECT
/// </summary>
TrackSelect = 0x00000008,
/// <summary>
/// LVS_EX_HEADERDRAGDROP
/// </summary>
HeaderDragDrop = 0x00000010,
/// <summary>
/// LVS_EX_FULLROWSELECT
/// </summary>
FullRowSelect = 0x00000020,
/// <summary>
/// LVS_EX_ONECLICKACTIVATE
/// </summary>
OneClickActivate = 0x00000040,
/// <summary>
/// LVS_EX_TWOCLICKACTIVATE
/// </summary>
TwoClickActivate = 0x00000080,
/// <summary>
/// LVS_EX_FLATSB
/// </summary>
FlatsB = 0x00000100,
/// <summary>
/// LVS_EX_REGIONAL
/// </summary>
Regional = 0x00000200,
/// <summary>
/// LVS_EX_INFOTIP
/// </summary>
InfoTip = 0x00000400,
/// <summary>
/// LVS_EX_UNDERLINEHOT
/// </summary>
UnderlineHot = 0x00000800,
/// <summary>
/// LVS_EX_UNDERLINECOLD
/// </summary>
UnderlineCold = 0x00001000,
/// <summary>
/// LVS_EX_MULTIWORKAREAS
/// </summary>
MultilWorkAreas = 0x00002000,
/// <summary>
/// LVS_EX_LABELTIP
/// </summary>
LabelTip = 0x00004000,
/// <summary>
/// LVS_EX_BORDERSELECT
/// </summary>
BorderSelect = 0x00008000,
/// <summary>
/// LVS_EX_DOUBLEBUFFER
/// </summary>
DoubleBuffer = 0x00010000,
/// <summary>
/// LVS_EX_HIDELABELS
/// </summary>
HideLabels = 0x00020000,
/// <summary>
/// LVS_EX_SINGLEROW
/// </summary>
SingleRow = 0x00040000,
/// <summary>
/// LVS_EX_SNAPTOGRID
/// </summary>
SnapToGrid = 0x00080000,
/// <summary>
/// LVS_EX_SIMPLESELECT
/// </summary>
SimpleSelect = 0x00100000
}
public enum ListViewMessages
{
First = 0x1000,
SetExtendedStyle = (First + 54),
GetExtendedStyle = (First + 55),
}
/// <summary>
/// Contains helper methods to change extended styles on ListView, including enabling double buffering.
/// Based on Giovanni Montrone's article on <see cref="http://www.codeproject.com/KB/list/listviewxp.aspx"/>
/// </summary>
public class ListViewHelper
{
private ListViewHelper()
{
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SendMessage(IntPtr handle, int messg, int wparam, int lparam);
public static void SetExtendedStyle(Control control, ListViewExtendedStyles exStyle)
{
ListViewExtendedStyles styles;
styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
styles |= exStyle;
SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
}
public static void EnableDoubleBuffer(Control control)
{
ListViewExtendedStyles styles;
// read current style
styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
// enable double buffer and border select
styles |= ListViewExtendedStyles.DoubleBuffer | ListViewExtendedStyles.BorderSelect;
// write new style
SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
}
public static void DisableDoubleBuffer(Control control)
{
ListViewExtendedStyles styles;
// read current style
styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
// disable double buffer and border select
styles -= styles & ListViewExtendedStyles.DoubleBuffer;
styles -= styles & ListViewExtendedStyles.BorderSelect;
// write new style
SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
}
}
The ListView in CommonControls 6 (XP or newer) supports double buffering. Fortunately, .NET wraps the newest CommonControls on the system. To enable double buffering, send the appropriate Windows message to the ListView control.
Here are the details:
http://www.codeproject.com/KB/list/listviewxp.aspx
In .NET Winforms 2.0 there exist a protected property called DoubleBuffered.
By inheriting from ListView, then one can set this protected property to true. This will enable double buffering without needing to call SendMessage.
Setting the DoubleBuffered property is the same as setting the following style:
listview.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94096
I know this question is quite old, but because this is one of the first search results on Google I wanted to share my fix.
The only way i could remove flickering 100% was to combine the answer from Oliver (extension class with double-buffering) and using the BeignUpdate() and EndUpdate() methods.
Neither of those on their own could fix flickering for me.
Granted, I use a very complex list, that I need to push into the list and also need to update it almost every sec.
this will help:
class DoubleBufferedListView : System.Windows.Forms.ListView
{
public DoubleBufferedListView()
:base()
{
this.DoubleBuffered = true;
}
}
If you only want to update the text, simply set the changed SubItem's text directly rather than updating the entire ListViewItem (you've not said how you're doing your updates).
The override you show is equivalent to simply overriding OnPaintBackground, which would be a "more correct" managed way to do that task, and it's not going to help for a single item.
If you still have problems, we'll need clarification on what you've actually tried.
This is a shot in the dark, but you could try double buffering the control.
SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.DoubleBuffer, true)
Call the BeginUpdate() method on the ListView before setting any of the list view items and then only call EndUpdate() after all of the items have been added.
That will stop the flicker.
Simple solution is this:
yourlistview.BeginUpdate()
//Do your update of adding and removing item from the list
yourlistview.EndUpdate()

Categories

Resources