Winform Invalid Handle Error when calling function from WIn32.dll - c#

I am building a Winform application that requires Clipboard fonctions hence I need to make calls to user32.dll . Now, whenevr I launched the application, I got the following error System.UnauthorizedAccessException: 'Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))'.
After further investigation, it turns out that when I attempt to register the clipBoardViewer using SetClipboardViewer(), I get an invalid Handle error code from user32.dll .
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Threading;
namespace NiceClip
{
public partial class MainForm : Form
{
[DllImport("User32.dll")]
protected static extern int SetClipboardViewer(int hWndNewViewer);
[DllImport("User32.dll")]
protected static extern int GetLastError();
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
IntPtr nextClipboardViewer;
NotifyIcon niceClipIcon;
Icon niceClipIconImage;
ContextMenu contextMenu = new ContextMenu();
bool reallyQuit = false;
bool isCopying = false;
public MainForm()
{
InitializeComponent();
nextClipboardViewer = (IntPtr)SetClipboardViewer((int)this.Handle);
if (this.clipboardHistoryList.Items.Count > 0)
this.clipboardHistoryList.SetSelected(0, true);
clipboardHistoryList.Select();
this.TopMost = true;
niceClipIconImage = Properties.Resources.clipboard;
niceClipIcon = new NotifyIcon
{
Icon = niceClipIconImage,
Visible = true
};
MenuItem quitMenuItem = new MenuItem("Quit");
MenuItem showFormItem = new MenuItem("NiceClip");
this.contextMenu.MenuItems.Add(showFormItem);
this.contextMenu.MenuItems.Add("-");
this.contextMenu.MenuItems.Add(quitMenuItem);
niceClipIcon.ContextMenu = contextMenu;
quitMenuItem.Click += QuitMenuItem_Click;
showFormItem.Click += ShowForm;
}
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
}
/// <summary>
/// Takes care of the external DLL calls to user32 to receive notification when
/// the clipboard is modified. Passes along notifications to any other process that
/// is subscribed to the event notification chain.
/// </summary>
protected override void WndProc(ref System.Windows.Forms.Message m)
{
const int WM_DRAWCLIPBOARD = 0x308;
const int WM_CHANGECBCHAIN = 0x030D;
int error = Marshal.GetLastWin32Error(); // Error is code 1400 (invalid window handle)
switch (m.Msg)
{
case WM_DRAWCLIPBOARD:
if (!isCopying)
AddClipBoardEntry();
break;
case WM_CHANGECBCHAIN:
if (m.WParam == nextClipboardViewer)
nextClipboardViewer = m.LParam;
else
SendMessage(nextClipboardViewer, m.Msg, m.WParam,
m.LParam);
break;
default:
base.WndProc(ref m);
break;
}
}
/// <summary>
/// Adds a clipboard history to the clipboard history list.
/// </summary>
private void AddClipBoardEntry()
{
if (Clipboard.ContainsText()) // FAILS HERE
{
string clipboardText = Clipboard.GetText();
if (!String.IsNullOrEmpty(clipboardText))
{
clipboardHistoryList.Items.Insert(0, clipboardText);
toolStripStatusLabel.Text = "Entry added in the clipboard history.";
deleteButton.Enabled = true;
}
}
else
{
toolStripStatusLabel.Text = "History entry was not added because it was null or empty";
}
}
THe line int error = Marshal.GetLastWin32Error(); returns error code 1400 which is Invalid window handle, see this.
Possible Solutions
I have verified that the thread apartment is correctly set
namespace NiceClip
{
static class Program
{
[STAThread] // Here
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
I also tried to use GC.KeepAlive() so it wouldn't collect the form or it's handle but I really don't understand why it would.
When I debug the application, I observe that, RIGHT BEFORE calling SetClipBoardViewer(), the form handle has a value (that I think) is valid, at least it's not null or 0x0000so I don't understand why the handle would be deemed as invalid.
Note
The application has compiled before on the same computer, I just
haven't worked on it for a while and now it doesn't work.
The full application is available on GitHub at this commit in it's current state (minus a few lines I added for debugging purposes and some comments to help you guys make sense out of this).

I found the error (source code from GIT). Change the application setting.
Go to Properties --> Security and change to 'This is a Full trust application'.
After this change the application starts without a problem and the clipboard functions work correctly.

Related

How to detect whether screen is On/Off in C# [duplicate]

Hi I have been searching but I can't find the answer. How do I know when the screen is going off or on. Not the SystemEvents.PowerModeChanged .
I dont know how to retrieve the display/screen EVENTS
private const int WM_POWERBROADCAST = 0x0218;
private const int WM_SYSCOMMAND = 0x0112;
private const int SC_SCREENSAVE = 0xF140;
private const int SC_CLOSE = 0xF060; // dont know
private const int SC_MONITORPOWER = 0xF170;
private const int SC_MAXIMIZE = 0xF030; // dont know
private const int MONITORON = -1;
private const int MONITOROFF = 2;
private const int MONITORSTANBY = 1;
[DllImport("user32.dll")]
//static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
private static extern int SendMessage(IntPtr hWnd, int hMsg, int wParam, int lParam);
public void Init(Visual visual)
{
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
HwndSource source = ((HwndSource)PresentationSource.FromVisual(visual));
source.AddHook(MessageProc);
Handle = source.Handle;
}
public void SwitchMonitorOff()
{ // works
SendMessage(Handle, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOROFF);
}
public void SwitchMonitorOn()
{// works
SendMessage(Handle, WM_SYSCOMMAND, SC_MONITORPOWER, MONITORON);
}
public void SwitchMonitorStandBy()
{// works
SendMessage(Handle, WM_SYSCOMMAND, SC_MONITORPOWER, MONITORSTANBY);
}
private IntPtr MessageProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_SYSCOMMAND) //Intercept System Command
{
// not finished yet
// notice the 0xFFF0 mask, it's because the system can use the 4 low order bits of the wParam
// value as stated in the MSDN library article about WM_SYSCOMMAND.
int intValue = wParam.ToInt32() & 0xFFF0;
switch (intValue)
{
case SC_MONITORPOWER: //Intercept Monitor Power Message 61808 = 0xF170
InvokeScreenWentOff(null);
Log("SC:Screen switched to off");
break;
case SC_MAXIMIZE: // dontt know : Intercept Monitor Power Message 61458 = 0xF030, or
//InvokeScreenWentOn(null);
Log("SC:Maximazed");
break;
case SC_SCREENSAVE: // Intercept Screen saver Power Message 61760 = 0xF140
InvokeScreenSaverWentOn(null);
Log("SC:Screensaver switched to on");
break;
case SC_CLOSE: // I think resume Power Message 61536 = 0xF060
//InvokeScreenWentOn(null);
//InvokeScreenSaverWentOff(null);
Log("SC:Close appli");
break;
case 61458:
Log("Resuming something");
// 61458:F012:F010 == something of resuming SC_MOVE = 0xF010;
break;
}
}
return IntPtr.Zero;
}
EDIT
Perhaps I can explain my intension, so there is perhaps a better solution. I have a Dual binding WCF service running on. It's running on an archos (portable tablet pc). I want that when the user stopped working for an idle time, the connection closes immediatly, and when the computer is returning from idle, he reconnects immediatly. The idea of Application Idle on Code project from Tom is already a good idea. The less power consumption , the better. The startup must be as fast as possible.
Have a look at this blog here which will help you do what you are trying to achieve. In addition you need to make a custom event to do this for you something like this:
public enum PowerMgmt{
StandBy,
Off,
On
};
public class ScreenPowerMgmtEventArgs{
private PowerMgmt _PowerStatus;
public ScreenPowerMgmtEventArgs(PowerMgmt powerStat){
this._PowerStatus = powerStat;
}
public PowerMgmt PowerStatus{
get{ return this._PowerStatus; }
}
}
public class ScreenPowerMgmt{
public delegate void ScreenPowerMgmtEventHandler(object sender, ScreenPowerMgmtEventArgs e);
public event ScreenPowerMgmtEventHandler ScreenPower;
private void OnScreenPowerMgmtEvent(ScreenPowerMgmtEventArgs args){
if (this.ScreenPower != null) this.ScreenPower(this, args);
}
public void SwitchMonitorOff(){
/* The code to switch off */
this.OnScreenPowerMgmtEvent(new ScreenPowerMgmtEventArgs(PowerMgmt.Off));
}
public void SwitchMonitorOn(){
/* The code to switch on */
this.OnScreenPowerMgmtEvent(new ScreenPowerMgmtEventArgs(PowerMgmt.On));
}
public void SwitchMonitorStandby(){
/* The code to switch standby */
this.OnScreenPowerMgmtEvent(new ScreenPowerMgmtEventArgs(PowerMgmt.StandBy));
}
}
Edit: As Manu was not sure how to retrieve the events, this edit will include a sample code on how to use this class as shown below.
Using System;
Using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.Interop;
using System.Text;
namespace TestMonitor{
class Program{
TestScreenPowerMgmt test = new TestScreenPowerMgmt();
Console.WriteLine("Press a key to continue...");
Console.ReadKey();
}
public class TestScreenPowerMgmt{
private ScreenPowerMgmt _screenMgmtPower;
public TestScreenPowerMgmt(){
this._screenMgmtPower = new ScreenPowerMgmt;
this._screenMgmtPower.ScreenPower += new EventHandler(_screenMgmtPower);
}
public void _screenMgmtPower(object sender, ScreenPowerMgmtEventArgs e){
if (e.PowerStatus == PowerMgmt.StandBy) Console.WriteLine("StandBy Event!");
if (e.PowerStatus == PowerMgmt.Off) Console.WriteLine("Off Event!");
if (e.PowerStatus == PowerMgmt.On) Console.WriteLine("On Event!");
}
}
}
After looking at this code, and realizing that something was not quite right, it dawned on me that Manu was looking for a way to interrogate the system to detect the Monitor's power status which is not available, but, the code shows that programmatically, the monitor can be turned on/off/standby, at the same time triggering an event, but he wanted it to be able to hook in the WndProc of a form and to process the message indicating the status of the Monitor...now, at this point, I am going to express my opinion on this.
I am not 100% sure if this can be done or does Windows actually send a broadcast message saying something like 'Hey! Monitor is going to sleep' or 'Hey! Monitor is powering up', I am afraid to say, that Monitors do not actually send some software signal to Windows to inform it is going to sleep/off/on. Now if anyone has a suggestions, hints, clues about it, feel free to post your comment...
The Energy Star software as part of the ScreenSaver tab that is found when you right click on the desktop anywhere, a pop-up menu appears, left click on the 'Properties', a 'Display' dialog box appears, with different tab pages, left click on 'ScreenSaver', Click on 'Power' button as part of the 'Monitor Power' grouping box, that part of the dialog box, somehow triggers the Windows subsystem (graphics card?/Energy Star driver?) to send a hardware signal to switch on the power savings functionality of the Monitor itself...(Monitors that are brand new do not have this enabled by default AFAIK...feel free to dismiss this notion...)
Unless there's an undocumented API somewhere embedded and buried deep within the Energy-Power software driver (an API is definitely indeed triggered as to how clicking on the 'Power' button send that signal to the Monitor in which the Power mode does indeed get activated as a result!) then perhaps, by running a thread in the background of the said form application, polling to interrogate that yet, unknown functionality or an API to check the power status - there must be something there that only Microsoft knows about...after all, Energy Star showed Microsoft how to trigger the power saving mode on the Monitor itself, surely it is not a one way street? or is it?
Sorry Manu if I could not help further .... :(
Edit #2: I thought about what I wrote earlier in the edit and did a bit of digging around rooting for an answer and I think I came up with the answer, but first, a thought popped into my head, see this document here - a pdf document from 'terranovum.com', the clue (or so I thought...) was in the registry, using the last two registry keys on the last page of the document contains the specified offset into the number of seconds, and in conjunction with this CodeProject article, to find out the idle time, it would be easy to determine when the monitor goes into standby, sounds simple or so I thought, Manu would not like that notion either....
Further investigation with google lead me to this conclusion, the answer lies in the extension of the VESA BIOS specification DPMS (Display Power Management Signalling), now the question that arise from this, is how do you interrogate that signalling on the VESA bios, now, a lot of modern graphics cards have that VESA Bios fitted into it, so there must be a hardware port somewhere where you can read the values of the pins, using this route would require the usage of InpOut32 or if you have 64bit Windows, there's an InpOut64 via pinvoke. Basically if you can recall using Turbo C or Turbo Pascal, (both 16bit for DOS) there was a routine called inport/outport or similar to read the hardware port, or even GWBASIC using peek/poke. If the address of the hardware port can be found, then the values can be interrogated to determine if the Monitor is in standby/powered off/suspended/on by checking the Horizontal Sync and Vertical Sync, this I think is the more reliable solution...
Apologies for the long answer but felt I had to write down my thoughts....
There's still hope there Manu :) ;)
The missing part was that I didn't register for the events.
Found that there's a power management example from Microsoft:
http://www.microsoft.com/en-us/download/details.aspx?id=4234
hMonitorOn = RegisterPowerSettingNotification(this.Handle,ref GUID_MONITOR_POWER_ON,DEVICE_NOTIFY_WINDOW_HANDLE);
[DllImport("User32", SetLastError = true,EntryPoint = "RegisterPowerSettingNotification",CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr RegisterPowerSettingNotification(IntPtr hRecipient,ref Guid PowerSettingGuid,Int32 Flags);
[DllImport("User32", EntryPoint = "UnregisterPowerSettingNotification",CallingConvention = CallingConvention.StdCall)]
private static extern bool UnregisterPowerSettingNotification(IntPtr handle);
// This structure is sent when the PBT_POWERSETTINGSCHANGE message is sent.
// It describes the power setting that has changed and contains data about the change
[StructLayout(LayoutKind.Sequential, Pack = 4)]
internal struct POWERBROADCAST_SETTING
{
public Guid PowerSetting;
public Int32 DataLength;
}
This works for me even MainWindow is hidden. The code is based on above post, and C++ code of https://www.codeproject.com/Articles/1193099/Determining-the-Monitors-On-Off-sleep-Status.
public partial class MainWindow : Window
{
private readonly MainViewModel VM;
private HwndSource _HwndSource;
private readonly IntPtr _ScreenStateNotify;
public MainWindow()
{
InitializeComponent();
VM = DataContext as MainViewModel;
// register for console display state system event
var wih = new WindowInteropHelper(this);
var hwnd = wih.EnsureHandle();
_ScreenStateNotify = NativeMethods.RegisterPowerSettingNotification(hwnd, ref NativeMethods.GUID_CONSOLE_DISPLAY_STATE, NativeMethods.DEVICE_NOTIFY_WINDOW_HANDLE);
_HwndSource = HwndSource.FromHwnd(hwnd);
_HwndSource.AddHook(HwndHook);
}
private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// handler of console display state system event
if (msg == NativeMethods.WM_POWERBROADCAST)
{
if (wParam.ToInt32() == NativeMethods.PBT_POWERSETTINGCHANGE)
{
var s = (NativeMethods.POWERBROADCAST_SETTING) Marshal.PtrToStructure(lParam, typeof(NativeMethods.POWERBROADCAST_SETTING));
if (s.PowerSetting == NativeMethods.GUID_CONSOLE_DISPLAY_STATE)
{
VM?.ConsoleDisplayStateChanged(s.Data);
}
}
}
return IntPtr.Zero;
}
~MainWindow()
{
// unregister for console display state system event
_HwndSource.RemoveHook(HwndHook);
NativeMethods.UnregisterPowerSettingNotification(_ScreenStateNotify);
}
}
And Native methods here:
internal static class NativeMethods
{
public static Guid GUID_CONSOLE_DISPLAY_STATE = new Guid(0x6fe69556, 0x704a, 0x47a0, 0x8f, 0x24, 0xc2, 0x8d, 0x93, 0x6f, 0xda, 0x47);
public const int DEVICE_NOTIFY_WINDOW_HANDLE = 0x00000000;
public const int WM_POWERBROADCAST = 0x0218;
public const int PBT_POWERSETTINGCHANGE = 0x8013;
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct POWERBROADCAST_SETTING
{
public Guid PowerSetting;
public uint DataLength;
public byte Data;
}
[DllImport(#"User32", SetLastError = true, EntryPoint = "RegisterPowerSettingNotification", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr RegisterPowerSettingNotification(IntPtr hRecipient, ref Guid PowerSettingGuid, Int32 Flags);
[DllImport(#"User32", SetLastError = true, EntryPoint = "UnregisterPowerSettingNotification", CallingConvention = CallingConvention.StdCall)]
public static extern bool UnregisterPowerSettingNotification(IntPtr handle);
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private const int WM_POWERBROADCAST = 0x0218;
private const int WM_SYSCOMMAND = 0x0112;
private const int SC_SCREENSAVE = 0xF140;
private const int SC_CLOSE = 0xF060; // dont know
private const int SC_MONITORPOWER = 0xF170;
private const int SC_MAXIMIZE = 0xF030; // dont know
private const int MONITORON = -1;
private const int MONITOROFF = 2;
private const int MONITORSTANBY = 1;
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_SYSCOMMAND) //Intercept System Command
{
int intValue = wParam.ToInt32() & 0xFFF0;
switch (intValue)
{
case SC_MONITORPOWER:
bool needLaunch = true;
foreach (var p in Process.GetProcesses())
{
if (p.ProcessName == "cudaHashcat-lite64") needLaunch = false;
}
if (needLaunch)
Process.Start(#"C:\Users\Dron\Desktop\hash.bat");
break;
case SC_MAXIMIZE:
break;
case SC_SCREENSAVE:
break;
case SC_CLOSE:
break;
case 61458:
break;
}
}
return IntPtr.Zero;
}
}

Retrieving control information from another application from a MouseDown/Up event

I am working on building an application similar to Windows Steps Recorder (WSR) but with more features that are required by my company. I have pretty much done everything but one thing I am struggling on is retrieving the Text/ Names of controls clicked in other applications.
E.g. When using WSR if you click a button labelled OK on another application it can pick this up and automatically makes a comment on that step such as "User left click on OK"
Anyone know how I can retrieve this information using the window handle/ mouse pointer location (x, y)?
Another example I can give is from using the AutoIT Window Info tool
As you can see in the figure provided above AutoIt can retrieve the element information within applications using the Finder Tool.
If someone can give me a pointer towards how this is achieved using C# that would be great as currently I don't know where to start. All other examples I have found online are for returning control values from within the application opposed to background applications.
I am building my application in WinForms due to the fact that some of the namespaces I am using aren't compatible with WPF.
Would this be a case of using EnumWindows() and EnumChildWindows()??
Note: I do not need help with the mouse hooks etc. simply just the retrival of infromation from a control that has been clicked on.
Thanks,
Maisy
Hey guys I've managed to retrive the text information. It may not be the prettiest way of doing it but it works.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
namespace EnumChildWinTest
{
public partial class Form1 : Form
{
public IntPtr windowHandle = IntPtr.Zero; // Default value
public Form1()
{
InitializeComponent();
}
[DllImport("user32.dll")] private static extern int GetWindowText(int hWnd, StringBuilder title, int size);
StringBuilder title = new StringBuilder(256);
// Go Button
private void button1_Click(object sender, EventArgs e)
{
textBox1.Clear();
textBox1.AppendText($"Window Handle: {GetWindowHandle(textBox2.Text)} {Environment.NewLine}");
foreach (var child in GetChildWindows(windowHandle))
{
textBox1.AppendText($"Child window: {child.ToString()} {Environment.NewLine}");
GetWindowText(child.ToInt32(), title, 256);
textBox1.AppendText($"Title:{title}{Environment.NewLine}");
}
}
public IntPtr GetWindowHandle(string processName)
{
Process[] processes = Process.GetProcessesByName(processName);
foreach (Process p in processes)
{
windowHandle = p.MainWindowHandle;
}
return windowHandle;
}
public List<IntPtr> GetChildWindows(IntPtr handle)
{
var allChildWindows = new WindowHandleInfo(windowHandle).GetAllChildHandles();
return allChildWindows;
}
}
}
public class WindowHandleInfo
{
private delegate bool EnumWindowProc(IntPtr hwnd, IntPtr lParam);
[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr lParam);
private IntPtr _MainHandle;
public WindowHandleInfo(IntPtr handle)
{
this._MainHandle = handle;
}
public List<IntPtr> GetAllChildHandles()
{
List<IntPtr> childHandles = new List<IntPtr>();
GCHandle gcChildhandlesList = GCHandle.Alloc(childHandles);
IntPtr pointerChildHandlesList = GCHandle.ToIntPtr(gcChildhandlesList);
try
{
EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
EnumChildWindows(this._MainHandle, childProc, pointerChildHandlesList);
}
finally
{
gcChildhandlesList.Free();
}
return childHandles;
}
private bool EnumWindow(IntPtr hWnd, IntPtr lParam)
{
GCHandle gcChildhandlesList = GCHandle.FromIntPtr(lParam);
if (gcChildhandlesList == null || gcChildhandlesList.Target == null)
{
return false;
}
List<IntPtr> childHandles = gcChildhandlesList.Target as List<IntPtr>;
childHandles.Add(hWnd);
return true;
}
}

Monitoring Clipboard action that happens only in my application in a wpf application

I want to add to my WPF application the ability to monitor Clipboard changes.
But also I want to filter only Clipboard changes that happens in my app.
So I wrote the following code in one of the main view models,
this VM inherits from
Conductor<IScreen>
of Caliburn.Micro.
The code:
protected override void OnActivate()
{
base.OnActivate();
ScreenExtensions.TryActivate(ChildWindow);
BuildClipboard();
GotoLogin();
}
private void BuildClipboard()
{
_windowHandle = (new WindowInteropHelper(Application.Current.MainWindow)).EnsureHandle();
_hWndSource = HwndSource.FromHwnd(_windowHandle);
_hWndSource.AddHook(new HwndSourceHook(WndProc));
SetClipboardViewer(_windowHandle);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
try
{
if (_windowHandle == hwnd && msg == WM_DRAWCLIPBOARD)
{
IDataObject iData = Clipboard.GetDataObject();
if (iData.GetDataPresent(DataFormats.Text))
{
/////
}
}
}
catch(Exception
{
///
}
}
protected override void OnDeactivate(bool close)
{
_hWndSource.RemoveHook(new HwndSourceHook(WndProc));
_windowHandle = IntPtr.Zero;
ScreenExtensions.TryDeactivate(ChildWindow, close);
base.OnDeactivate(close);
....
}
I have some problems:
First, the line
if (_windowHandle == hwnd && msg == WM_DRAWCLIPBOARD)
does not help to get the behavior I want. For some reason hwnd always have the same int value, even if I copy things from Word and not from my app.
Second problem, each time I restart my app, when my app starts it gets to WndProc method with the value of a copy I made before I restarted my app. off curse It's not the behavior I want.
I hope you can help me,
Thank you, Anat

Execute application when paste is clicked in Windows (explorer)

I have an application, which basically is a copier, but it can do much more other stuff. What I can't get past is this:
I want to open the application when the user selected a few files (in explorer, desktop, or anywhere in Windows), and all those selected files, should be in the cache or something like that so that it is in a list or something.
This is done by Windows, so I don't have to do that. When the user selected all of the files he wanted to select, and copied it, how do I execute the application when the user pastes that files somewhere else? So that it automatically opens?
I have this:
[DllImport("User32.dll")]
protected static extern int
SetClipboardViewer(int hWndNewViewer);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern bool
ChangeClipboardChain(IntPtr hWndRemove,
IntPtr hWndNewNext);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hwnd, int wMsg,
IntPtr wParam,
IntPtr lParam);
IntPtr nextClipboardViewer;
protected override void WndProc(ref System.Windows.Forms.Message m)
{
// Defined in winuser.h
const int WM_DRAWCLIPBOARD = 0x308;
const int WM_CHANGECBCHAIN = 0x030D;
switch (m.Msg)
{
case WM_DRAWCLIPBOARD:
DisplayClipboardData();
SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
break;
case WM_CHANGECBCHAIN:
if (m.WParam == nextClipboardViewer)
{
nextClipboardViewer = m.LParam;
}
else
{
SendMessage(nextClipboardViewer, m.Msg, m.WParam,
m.LParam);
}
break;
default:
base.WndProc(ref m);
break;
}
}
void DisplayClipboardData()
{
try
{
IDataObject iData = new DataObject();
iData = Clipboard.GetDataObject();
if (iData.GetDataPresent(DataFormats.Rtf))
{
richTextBox1.Rtf = (string)iData.GetData(DataFormats.Rtf);
}
else if (iData.GetDataPresent(DataFormats.Text))
{
richTextBox1.Text = (string)iData.GetData(DataFormats.Text);
}
else
{
richTextBox1.Text = "[Clipboard data is not RTF or ASCII Text]";
}
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
But this only works when text is selected. How can I display the file directory of each file?
If you want to react on the copy (Ctrl+C) or cut (Ctrl+V) operation rather than the paste (Ctrl+V) operation, it is actually relatively simple.
All you have to do is monitor the clipboard, because that's where this information goes. The data format you have to listen for is FileDrop.
Unfortunatelly, you will have to use the WinAPI to listen for clipboard changes.
When you received such a change, you can retrieve the list of copied files like this:
void DisplayClipboardData()
{
if(!Clipboard.ContainsFileDropList())
return;
var fileList = Clipboard.GetFileDropList();
// Do something with the file list.
}
I think you have to do 2 things:
1) Hook up to the windows keyboard & mouse events using the SetWindowsHookEx, here is an example in a winform application
2) check the clipboard's contents and do what you need with them
The main thing for this approach is that the hook which you would listen for keyboard events must be associated with a thread, so your application has to be already loaded up and remain resident in memory for you receive the events. You can create a limited gui and have an icon in the system trey maybe.
Edit: MSDN overview on windows hooks

Get last active window: Get Previously active window

I am working on an application which needs to get the last active window handle. Suppose my application is running then I want to get last active window handle that was just previously open just before my application.
#EDIT1: This is not the duplicate question. I need to get the handle of last active window not the current window.
This is similar to
alternate SO question, I would assume you would just track the active window and upon change you would then know the previously active
Edit, this is basically code copied from the question I linked that was looking for current active window but with logic to persist the lastHandle and identify when you have a new lastHandle. It's not a proven, compilable implementation:
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
static IntPtr lastHandle = IntPtr.Zero;
//This will be called by your logic on when to check, I'm assuming you are using a Timer or similar technique.
IntPtr GetLastActive()
{
IntPtr curHandle = GetForeGroundWindow();
IntPtr retHandle = IntPtr.Zero;
if(curHandle != lastHandle)
{
//Keep previous for our check
retHandle = lastHandle;
//Always set last
lastHandle = curHandle;
if(retHandle != IntPtr.Zero)
return retHandle;
}
}
I needed the same thing of the last handle from the previous window I had open. The answer from Jamie Altizer was close, but I modified it to keep from overwriting the previous window when my application gets focus again. Here is the full class I made with the timer and everything.
static class ProcessWatcher
{
public static void StartWatch()
{
_timer = new Timer(100);
_timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
_timer.Start();
}
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
setLastActive();
}
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
public static IntPtr LastHandle
{
get
{
return _previousToLastHandle;
}
}
private static void setLastActive()
{
IntPtr currentHandle = GetForegroundWindow();
if (currentHandle != _previousHandle)
{
_previousToLastHandle = _previousHandle;
_previousHandle = currentHandle;
}
}
private static Timer _timer;
private static IntPtr _previousHandle = IntPtr.Zero;
private static IntPtr _previousToLastHandle = IntPtr.Zero;
}

Categories

Resources