I have a problem. I am trying to use the ClipboardMonitor for my C# Application. The goal is to monitor every change in the clipboard.
To start monitoring:
AddClipboardFormatListener(this.Handle);
To stop the listener:
RemoveClipboardFormatListener(this.Handle);
And the override WndProc() method:
const int WM_DRAWCLIPBOARD = 0x308;
const int WM_CHANGECBCHAIN = 0x030D;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_DRAWCLIPBOARD:
IDataObject iData = Clipboard.GetDataObject();
if (iData.GetDataPresent(DataFormats.Text))
{
ClipboardMonitor_OnClipboardChange((string)iData.GetData(DataFormats.Text));
}
break;
default:
base.WndProc(ref m);
break;
}
}
And of course the DLL import:
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool AddClipboardFormatListener(IntPtr hwnd);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool RemoveClipboardFormatListener(IntPtr hwnd);
But when putting a breakpoint at the method call ClipboardMonitor_OnClipboardChange and changing the clipboard, I never get the method called.
How can I change my code so that I receive a WM_ message notifying me that the clipboard has changed?
The problem is that you're handling the wrong window message. Quoting the documentation for AddClipboardFormatListener:
When a window has been added to the clipboard format listener list, it is posted a WM_CLIPBOARDUPDATE message whenever the contents of the clipboard have changed.
With that knowledge, change the code to:
const int WM_CLIPBOARDUPDATE = 0x031D;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_CLIPBOARDUPDATE:
IDataObject iData = Clipboard.GetDataObject();
if (iData.GetDataPresent(DataFormats.Text))
{
string data = (string)iData.GetData(DataFormats.Text);
}
break;
default:
base.WndProc(ref m);
break;
}
}
SharpClipboard as a library could be of more benefit as it encapsulates the same features into one fine component library. You can then access its ClipboardChanged event and detect various data-formats when they're cut/copied.
You can choose the various data-formats you want to monitor:
var clipboard = new SharpClipboard();
clipboard.ObservableFormats.Texts = true;
clipboard.ObservableFormats.Files = true;
clipboard.ObservableFormats.Images = true;
clipboard.ObservableFormats.Others = true;
Here's an example using its ClipboardChanged event:
private void ClipboardChanged(Object sender, ClipboardChangedEventArgs e)
{
// Is the content copied of text type?
if (e.ContentType == SharpClipboard.ContentTypes.Text)
{
// Get the cut/copied text.
Debug.WriteLine(clipboard.ClipboardText);
}
// Is the content copied of image type?
else if (e.ContentType == SharpClipboard.ContentTypes.Image)
{
// Get the cut/copied image.
Image img = clipboard.ClipboardImage;
}
// Is the content copied of file type?
else if (e.ContentType == SharpClipboard.ContentTypes.Files)
{
// Get the cut/copied file/files.
Debug.WriteLine(clipboard.ClipboardFiles.ToArray());
// ...or use 'ClipboardFile' to get a single copied file.
Debug.WriteLine(clipboard.ClipboardFile);
}
// If the cut/copied content is complex, use 'Other'.
else if (e.ContentType == SharpClipboard.ContentTypes.Other)
{
// Do something with 'e.Content' here...
}
}
You can also find out the application that the cut/copy event occurred on together with its details:
private void ClipboardChanged(Object sender, SharpClipboard.ClipboardChangedEventArgs e)
{
// Gets the application's executable name.
Debug.WriteLine(e.SourceApplication.Name);
// Gets the application's window title.
Debug.WriteLine(e.SourceApplication.Title);
// Gets the application's process ID.
Debug.WriteLine(e.SourceApplication.ID.ToString());
// Gets the application's executable path.
Debug.WriteLine(e.SourceApplication.Path);
}
There are also other events such as the MonitorChanged event which listens whenever clipboard-monitoring is disabled, meaning that you can enable or disable monitoring the clipboard at runtime.
In addition to all this, since it's a component, you can use it in Designer View by dragging-and-dropping it to a Windows Form, making it super easy for anyone to customize its options and work with its inbuilt events.
SharpClipboard seems to be the very best option for clipboard-monitoring scenarios in .NET.
Just to add to theB's excellent answer ...
The WM_DRAWCLIPBOARD message is an older message used after setting up a "Clipboard Viewer Window." This dates back at least to Windows 95. Starting with Windows Vista and Windows Server 2008, the "Clipboard Format Listener" API was added.
The old Clipboard Viewer Window required more work:
Add your window into the chain of objects receiving clipboard messages by calling the SetClipboardViewer() API.
You receive a WM_CHANGECBCHAIN message when another window in the chain adds or removes itself from the chain, and you are required to process that message by passing it on to the next window in the chain with the SendMessage() API.
When you receive the WM_DRAWCLIPBOARD message, you also needed to pass the message along to the next object (hwnd) in the chain, using the SendMessage() API. Then you could process the changed contents of the Clipboard.
When you close your program, you needed to remove it from the chain, using the ChangeClipboardChain() API.
The newer Clipboard Format Listener only requires:
Start monitoring the clipboard by calling the AddClipboardFormatListener() API.
Wait for the WM_CLIPBOARDUPDATE message to notify you of changed clipboard contents.
Before closing your program, stop the monitoring by calling RemoveClipboardFormatListener().
All issues relating to the chain of notification are handled automatically by Windows.
Another key difference: WM_DRAWCLIPBOARD is a sent (non-queued) message, which will have to be processed by your program immediately. WM_CLIPBOARDUPDATE is a posted (queued) message, which will be added to a queue, where it will be handled after your program is finished executing its current process.
This means that when the WM_DRAWCLIPBOARD message comes through, your program will have to process it immediately, even if you are in the middle executing code. For example, let's say you've created a clipboard monitor that allows you to save and retrieve past clips, and load those past clips to the clipboard. You've decided to use the older SetClipboardViewer() API, which will trigger the WM_DRAWCLIPBOARD message when the clipboard changes. When you execute the code to load the old clip back into the clipboard, you have just changed the clipboard contents, which will trigger the message. If you are stepping through your C# code line by line in Visual Studio, the Clipboard.SetText() method will trigger the message and you will be taken immediately back to your WndProc() method, starting that whole process all over again. When the WndProc() method is finished, you will continue on to the next line of code after Clipboard.SetText().
If instead, you use the newer AddClipboardFormatListener() API, you can use the Clipboard.SetText() method also, but it won't trigger an immediate message. The WM_CLIPBOARDUPDATE message is added to a queue, and it won't be processed by your program until your code is finished executing. If you are stepping through the code line by line, you can execute the Clipboard.SetText() method and simply move on to the next line. When your program finishes whatever it is doing, you will then be taken back to the WndProc() method to deal with the WM message. Here is some Microsoft documentation about message queuing and routing:
Windows Message Routing
There will be times when our program will need to treat WM messages in different ways, depending on what has triggered the message. If the end user copies a new clip into the clipboard, we will want to process that WM message. If the end user uses our program to load a saved old clip back into the clipboard, we will want our program to ignore the WM message that results from that. One way to ignore a WM message is to create a public class integer property called "Ignore". Every time our code changes the clipboard contents (instead of the user copying something new), we FIRST increment (increase) the Class.Ignore property. We add an If statement in the WndProc() method to only process a WM clipboard message if the ignore property is zero. If Class.Ignore is greater than zero, WndProc() will ignore the message. Every time it ignores a message, it also decrements (decreases) the Class.Ignore integer. That is how the program can know if the WM_ message was generated from copying a new clip, or from an old clip being re-loaded into the clipboard.
Just remember that the newer AddClipboardFormatListener() API requires Windows Vista (Client machine) or Windows Server 2008 (server machine) or later. But according to this article in August, 2021, only about 0.5% or less of Windows users are still on XP or older.
Here is a writeup for implementing the Clipboard Format Listener in C#:
Monitor for clipboard changes using AddClipboardFormatListener
And here is the Microsoft Documentation (in C++) for anyone interested:
Microsoft Documentation on monitoring the clipboard
Best of luck to everyone in their coding.
Related
I have an unmanaged DLL with delphi and integrated there are some events that fire at certain points on runtime.
On its manual it says that it calls the Win32 api PostMessage().
When the event is fired a text message is sent and wParam and IParam have some other information.
How can i fire an event from my c# application when a message from the dll is posted and ofcourse get the information?
UPDATE:
Trying to describe what the manual is saying:
So i have a function called init() which accepts the handle parameter which i am passing as follows:
wr.Init((IntPtr)this.Handle);
from the c# Winform application to the unmanaged dll which returns true if it is fine and that is what i am seeing.
Now the manual says:
When event (from the dll) is fired it sends a windows message to the window handle supplied with the Init function, infact PostMessage() Win32 API is called.
And i have the list of the messages that are sent on the PostMessage() for example:
TextMessage: WM_TECH_BROKENLINE
wParam: Point (which is a number displaying for example where is broken)
IParam: 0
Now as i explained i want that when a message like the one above is posted from the dll i fire an event from c# and ofcourse get the text message and the Params
The steps necessary are as follows:
Obtain a window handle for a window in your C# program.
Pass that window handle to the unmanaged DLL so that it knows where to send the messages.
In your C# code, add code to receive and respond to the message arriving.
As an alternative to the above you might prefer to keep the GUI windows of your program separate from this message passing mechanism. In which case do the following:
Create a subclass of NativeWindow to handle incoming messages.
Create an instance of your class and pass its window handle to the unmanaged DLL.
Override WndProc in your window class and then handle the message there. At which point you can surface it as an event.
This latter approach gives better separation of your interop code from your GUI, and will allow you to make your wrapper less tangled with your GUI.
In order to describe any of this in more detail, one would need to know the details of your program. For instance, is it WinForms or WPF? Does your program have a window at hand to receive messages? How is the string encoded? In which message arg does it arrive? How is memory for the string deallocated if the message is delivered asynchronously?
I suspect you'll have answers to some of these questions, but perhaps not all. You now know at a high level what you need to do, but now need to find out more details for your own program.
Try overriding WndProc method of the form which handle you're passing to the dll. An example can be found here: https://msdn.microsoft.com/en-us/library/system.windows.forms.control.wndproc(v=vs.110).aspx
A simplified example for your case (add it into your form class):
const int WM_TECH_BROKENLINE = 0x0401; // It's WM_USER + 1 in my example.
// Set it according to you dll's spec
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_TECH_BROKENLINE)
{
long dataPassedFromTheDll = (long)m.WParam;
// Your stuff here:
this.Text = string.Format("The dll sent us: {0}", dataPassedFromTheDll);
}
base.WndProc(ref m);
}
I've made a WPF application that has a GUI but I also want it to optionally run from command line, so I have added this to my App.xaml.cs:
[DllImport("kernel32.dll")]
private static extern bool AttachConsole(int pid);
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
if (e.Args.Count() > 0)
{
CreateReport(e.Args);
Environment.Exit(0);
}
}
void CreateReport(string[] arguments)
{
AttachConsole(-1);
// Parse arguments, generate report, etc.
}
There are two problems with this approach:
Problem 1: Running the application from command-line waits for user input before it closes:
C:\Code>GenerateReport.exe -output Example.html
Started report generation.
Report has been generated.
<-- Console waits until user input here, even though the application has finished doing its business.
Problem 2: These are command line redirection operators. AttachConsole, for some reason, stops them from working:
C:\Code>GenerateReport.exe -output Example.html > Log.txt <-- Causes no output in Log.txt (just an empty file)!
I've checked other Stack questions but none address this issue in particular...so how can you actually attach to the current console Window to output this data back to the user (for example, give them error messages, etc.) but not have these nasty problems come out of it?
I found a discussion about this here:
The problem of attachconsole
Seems you are out of luck or if you are not willing to resort to an ugly hack.
From the previous thread's answer: I always have gone with option 3:
"Or you can restructure your application/source a bit and provide two executables, GUI one that starts GUI directly, another that is console executable."
What I want to have happen is that the console window just goes away, or better yet that it is hidden, but I want my application to keep running. Is that possible? I want to be able to use Console.WriteLine and have the console serve as an output window. I want to be able to hide and show it, and I don't want the whole app to die just because the console was closed.
EDIT
Code:
internal class SomeClass {
[DllImport("kernel32")]
private static extern bool AllocConsole();
private static void Main() {
AllocConsole();
while(true) continue;
}
}
EDIT 2
I tried the accepted solution here [ Capture console exit C# ], per the suggestion in the comments on this question. The example code is bugged in that the DLLImport needs to be "kernel32.dll" or "kernel32", not "Kernel32". After making that change, I'm getting a message to my handler for CTRL_CLOSE_EVENT when I click the X on the console window. However, calling FreeConsole and/or returning true doesn't prevent the application from terminating.
Ah, yes, this is one of the caveats of using the Windows console subsystem. When the user closes the console window (regardless of how the console was allocated), all of the processes that are attached to the console are terminated. That behavior makes obvious sense for console applications (i.e., those that specifically target the console subsystem, as opposed to standard Windows applications), but it can be a major pain in cases like yours.
The only workaround that I know of is to use the SetConsoleCtrlHandler function, which allows you to register a handler function for Ctrl+C and Ctrl+Break signals, as well as system events like the user closing the console window, the user logging off, or the system shutting down. The documentation says that if you're only interested in ignoring these events, you can pass null for the first argument. For example:
[DllImport("kernel32")]
static extern bool SetConsoleCtrlHandler(HandlerRoutine HandlerRoutine, bool Add);
delegate bool HandlerRoutine(uint dwControlType);
static void Main()
{
AllocConsole();
SetConsoleCtrlHandler(null, true);
while (true) continue;
}
That works perfectly for Ctrl+C and Ctrl+Break signals (which would have otherwise caused your application to terminate as well), but it doesn't work for the one you're asking about, which is the CTRL_CLOSE_EVENT, generated by the system when the user closes the console window.
Honestly, I don't know how to prevent that. Even the sample in the SDK doesn't actually allow you to ignore the CTRL_CLOSE_EVENT. I tried it in a little test app, and it beeps when you close the window and prints the message, but the process still gets terminated.
Perhaps more worryingly, the documentation makes me think it is not possible to prevent this:
The system generates CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT signals when the user closes the console, logs off, or shuts down the system so that the process has an opportunity to clean up before termination. Console functions, or any C run-time functions that call console functions, may not work reliably during processing of any of the three signals mentioned previously. The reason is that some or all of the internal console cleanup routines may have been called before executing the process signal handler.
It's that last sentence that catches my eye. If the console subsystem starts cleaning up after itself immediately in response to the user attempting to close the window, it may not be possible to halt it after the fact.
(At least now you understand the problem. Maybe someone else can come along with a solution!)
Unfortunately there's nothing you can do to really alter this behaviour.
Console windows are "special" in that they're hosted by another process and do not allow sub-classing. This limits your ability to modify their behaviour.
From what I know, your two options are:
1. Disable the close button altogether. You can do this with the following code fragment:
HWND hwnd = ::GetConsoleWindow();
if (hwnd != NULL)
{
HMENU hMenu = ::GetSystemMenu(hwnd, FALSE);
if (hMenu != NULL) DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
}
2. Stop using consoles altogether, and implement your own text output solution.
Option #2 is the more complicated option but would provide you the greatest control. I found an article on CodeProject that implements a console-like application using a rich edit control to display the text (rich edit controls have the ability to stream text like the console, so they are well suited to this sort of application).
On closing the console window obtained using AllocConsole or AttachConsole, the associated process will exit. There is no escape from that.
Prior to Windows Vista, closing the console window would present a confirmation dialogue to the user asking him whether the process should be terminated or not but Windows Vista and later do not provide any such dialogue and the process gets terminated.
One possible solution to work around this is avoiding AttachConsole altogether and achieving the desired functionality through other means.
For instance in the case described by OP, console window was needed to output some text on Console using Console static class.
This can be achieved very easily using inter-process communication. For example a console application can be developed to act as an echo server
namespace EchoServer
{
public class PipeServer
{
public static void Main()
{
var pipeServer = new NamedPipeServerStream(#"Com.MyDomain.EchoServer.PipeServer", PipeDirection.In);
pipeServer.WaitForConnection();
StreamReader reader = new StreamReader(pipeServer);
try
{
int i = 0;
while (i >= 0)
{
i = reader.Read();
if (i >= 0)
{
Console.Write(Convert.ToChar(i));
}
}
}
catch (IOException)
{
//error handling code here
}
finally
{
pipeServer.Close();
}
}
}
}
and then instead of allocating/attaching a console to the current application, the echo server can be started from within the application and Console's output stream can be redirected to write to the pipe server.
class Program
{
private static NamedPipeClientStream _pipeClient;
static void Main(string[] args)
{
//Current application is a Win32 application without any console window
var processStartInfo = new ProcessStartInfo("echoserver.exe");
Process serverProcess = new Process {StartInfo = processStartInfo};
serverProcess.Start();
_pipeClient = new NamedPipeClientStream(".", #"Com.MyDomain.EchoServer.PipeServer", PipeDirection.Out, PipeOptions.None);
_pipeClient.Connect();
StreamWriter writer = new StreamWriter(_pipeClient) {AutoFlush = true};
Console.SetOut(writer);
Console.WriteLine("Testing");
//Do rest of the work.
//Also detect that the server has terminated (serverProcess.HasExited) and then close the _pipeClient
//Also remember to terminate the server process when current process exits, serverProcess.Kill();
while (true)
continue;
}
}
This is just one of the possible solutions. In essence the work around is to allot the console window to its own process so that it can terminate without affecting the parent process.
You can do this by disabling keyboard mouse input by external program called Keyfreez.
you can use it multiple times in your program where no user input required. And if any user input require u can add a process Takskkill /f /IM .
https://www.sordum.org/7921/bluelife-keyfreeze-v1-4-block-keyboard-and-mouse/
Hope this helps all of you
Is it possible to get shutdown reason in Windows Server 2008 immediately after user choose the reason in dialog window? For the shutdown event I'm using SystemEvents.SessionEnding.
I want to write windows service, which will send e-mail about this event.
Or is there any other way in windows server to send e-mails about shutdown/restart event with getting the reason entered by user? Also, I want to notify about power source change (electic line/battery), but this I have already solved by Kernel32.dll > GetSystemPowerStatus.
You can get the shutdown reason inspecting the EventLog.
I assembled a quick demo on Windows Forms that you can adapt to your Windows service.
I've added a EventLog component to the Form and configured it properly. The snippet below shows the code generated in InitializeComponent() for the settings I've maid through the designer.
this.eventLog1.EnableRaisingEvents = true;
this.eventLog1.Log = "System";
this.eventLog1.Source = "USER32";
this.eventLog1.SynchronizingObject = this;
this.eventLog1.EntryWritten += new System.Diagnostics.EntryWrittenEventHandler(this.eventLog1_EntryWritten);
On the event handler, you'll have something along the following lines:
private void eventLog1_EntryWritten(object sender, System.Diagnostics.EntryWrittenEventArgs e)
{
EventLogEntry entry = e.Entry;
if (e.Entry.EventID == 1074)
{
File.AppendAllText(#"c:\message.txt", entry.Message);
}
}
Take a look at your event log to see the appropriate EventIds to filter out.
The compiler will warn you about EventID being deprecated and telling you that you should use InstanceId, but in the quick tests I've done here, it didn't write to my log file and I think we already have enough information to put you on track.
sure it's possible.
in case you want to get that comboBox value in real-time, you will need to run a Thread monitor on that process to raise an event when that value change.
I am writing a C# console application that connects to a server trough TCP, it uses a separate thread to listen for incoming messages from the server and I want it to write them to the console while at the same time reading a message from the console. I was able to do that, but I have a problem.
The console displays this while I type and a messages comes in:
msg from server
msg from server
my msmsg from server
g to server
And i want it to separate my message from the servers mesages like so:
msg from server
msg from server
msg from server
my msg to server
If I receive a message I still want to keep my typed message, but I don't want it to mix up with the received message, I want it to remain complete on the last line.
Can I do that? And how?
Can I shift my message to the end of the console, when a message from the server comes in?
I believe this is in fact possible with the standard .NET Console API, using a bit of hackery. What you need to do is create an asynchronous Read/ReadLine method (which I assume you have already done, judging by your post) and allow it to be cancelled as soon as new data arrives. I'm going to assume you're sending input line by line for now. The pseudocode for the "new data handler" might be something like this:
Save the current input buffer.
Cancel the current asynchronous read.
Reset the cursor position to the end of the last writing of new data.
Output the new data.
Save the cursor position.
Restart the asynchronous read event.
In particular, you'll need to mess around with Console.CursorLeft and Console.CursorTop properties. You might be able to avoid some of the hackery by interfacing with the Win32 API console functions directly, but it's possibly not worth the bother.
Hope that helps.
You can't do this directly via the BCL in C#. There are two main alternatives, though.
1) Turn this into a GUI app, and have separate input/output areas. This is the most "clear" option from a user's POV, but requires a GUI app instead of a console app.
2) P/Invoke into the console API directly. This gives you complete control of the console's view, point by point. See SetConsoleCursorPosition and WriteConsole, etc.
You need to use a lock on some object to stop both threads using the console at the same time. Declare something like this:
public static class ThreadSafeConsole
{
private static object _lockObject = new object();
public static void WriteLine(string str)
{
lock (_lockObject)
{
Console.WriteLine(str);
}
}
}
Now call ThreadSafeConsole.WriteLine instead of Console.WriteLine.
If I understand you correctly, you'd have to define what the beginning and ending of 'typing to console' is for your application so that you can still lock on an object while that is happening, and not inserting messages from your listener thread into your typed text.
public static Object consoleLock = new Object();
public static void Main(string[] args)
{
lock (consoleLock)
{
// now nothing can write to the console (if it's trying to lock onto it)
Console.WriteLine("Please Input Something");
// read from console
}
// now, your separate thread CAN write to the console - without
// interrupting your input process
}