Receive WM_COPYDATA struct in WPF or Console C# app - c#

I am writing a C# application that needs to communicate with another application written in native C. So far I have figured out how to send messages from my C# app to the C app with the User32.dll SendMessage. However I am unable to figure out how to get the C# app to RECEIVE messages from the C app.
I have seen WinForms examples of overriding the WndProc method, but there is no WndProc method to override in a WPF or Console application. Surely it's possible to do in a Console application at least. Right?

You can do this in WPF using HwndSource.AddHook:
private HwndSource hwndSource;
void MyWindowClass_Loaded(object sender, RoutedEventArgs e)
{
hwndSource = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
hwndSource.AddHook(new HwndSourceHook(WndProc));
}
private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Process your windows proc message here
}
Unfortunately, there is no real equivelent for a Console Application. Windows messages, by definition, are sent and received by a window handle (HWND), so they really are meant to be used with GUI applications.
There are many other, less odd, means of doing inter-process communication on Windows, however. I personally like using pipes - setting up named pipes works very well in both native and managed code, and is very efficient for communicating between the two programs.

Related

How to get WH_KEYBOARD_LL to work in a Universal Windows Platform Builds

Background: I have a library which requires keyboard scancodes (Not KeyCodes from the enum) which I am trying to get working with Unity for the HoloLens.
The only way to obtain scancodes from C# I have found so far is to use the Windows Hook system through PInvoke by registering a hook for WH_KEYBOARD_LL through SetWindowsHookEx
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
Documentation https://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx
The suggested way is to call it like this
IntPtr hHook;
using (Process process = Process.GetCurrentProcess())
using (ProcessModule module = process.MainModule)
{
IntPtr hModule = GetModuleHandle(module.ModuleName);
hHook = SetWindowsHookEx(HookType.WH_KEYBOARD_LL, hook, hModule, 0);
}
see http://www.pinvoke.net/default.aspx/user32.setwindowshookex
This works well on PC builds, but the Remark for UWP in the documentation for SetWindowsHookEx is confusing me:
Windows Store app development If dwThreadId is zero, then window hook
DLLs are not loaded in-process for the Windows Store app processes and
the Windows Runtime broker process unless they are installed by either
UIAccess processes (accessibility tools). The notification is
delivered on the installer's thread for these hooks:
WH_JOURNALPLAYBACK WH_JOURNALRECORD WH_KEYBOARD WH_KEYBOARD_LL
WH_MOUSE WH_MOUSE_LL This behavior is similar to what happens when
there is an architecture mismatch between the hook DLL and the target
application process, for example, when the hook DLL is 32-bit and the
application process 64-bit.
As I understand I have to specify dwThreadId on UWP, otherwise it will not work. But if I do so using GetCurrentThreadId() (again through pinvoke), I get an error code:
ERROR_GLOBAL_ONLY_HOOK
1429 (0x595)
This hook procedure can only be set globally.
Setting hMod from GetModuleHandle(NULL) and dwThreadId to NULL creates a valid hookID but again no events arrive.
Since then I tried to search for ways to obtain a module handle, but did not find any way that works on UWP:
Process.GetCurrentProcess does not compile, missing
Marshal.GetHINSTANCE missing
GetType().Module.Name missing (for GetModuleHandle)
What else can I try?
The only way to obtain scancodes from C# I have found so far is to use the Windows Hook system through PInvoke by registering a hook for WH_KEYBOARD_LL through SetWindowsHookEx.
Unfortunately, the solution that you have mentioned is not applicable for UWP. For your requirement, you could use the AcceleratorKeyActivatedevent, and the AcceleratorKeyEventArgs provides the ScanCode value directly.
public MainPage()
{
this.InitializeComponent();
Window.Current.Dispatcher.AcceleratorKeyActivated += Dispatcher_AcceleratorKeyActivated;
}
private void Dispatcher_AcceleratorKeyActivated(Windows.UI.Core.CoreDispatcher sender, Windows.UI.Core.AcceleratorKeyEventArgs args)
{
var scanCode = args.KeyStatus.ScanCode;
}

Using SetWaitableTimer in Universal Windows Platform

I use SetWaitableTimer from "kernel32.dll" in my UWP app. I want the computer to wake from sleep because of my application. If I run the app in debug mode it works. If I run it in release mode then the computer doesn't wake up.
How can I do to make my application awakened the computer when it is running in realise mode?
private void Button_Click(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(SetWaitForWakeUpTime);
}
[DllImport("kernel32.dll")]
public static extern IntPtr CreateWaitableTimer(IntPtr lpTimerAttributes, bool bManualReset, string lpTimerName);
[DllImport("kernel32.dll")]
public static extern bool SetWaitableTimer(IntPtr hTimer, [In] ref long pDueTime, int lPeriod,
IntPtr pfnCompletionRoutine, IntPtr lpArgToCompletionRoutine, bool fResume);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern Int32 WaitForSingleObject(IntPtr handle, uint milliseconds);
static IntPtr handle;
static void SetWaitForWakeUpTime()
{
long duetime = -600000000;
handle = CreateWaitableTimer(IntPtr.Zero, true, "MyWaitabletimer");
SetWaitableTimer(handle, ref duetime, 0, IntPtr.Zero, IntPtr.Zero, true);
uint INFINITE = 0xFFFFFFFF;
int ret = WaitForSingleObject(handle, INFINITE);
}
Windows 10 Universal Windows Platform (UWP) apps can use a subset of the Win32 and COM APIs. This subset of APIs was chosen to support key scenarios for Windows Runtime apps that were not already covered by the Windows Runtime, HTML/CSS, or other supported languages or standards. The Windows App Certification Kit ensures that your app uses only this subset of the Win32 and COM API. For the Win32 APIs that can be used in UWP, please see Win32 and COM APIs for UWP apps.
Unfortunately, CreateWaitableTimer and SetWaitableTimer are not in the supported APIs. We can not use them in UWP apps. For a UWP app, it should not be able to wake the system from sleep. But we can prevent the system from sleep by using DisplayRequest class.
Apps that show video or run for extended periods without user input can request that the display remain on by calling DisplayRequest::RequestActive. When a display request is activated, the device's display remains on while the app is visible.
For more info, plesae see Remarks of DisplayRequest class.
But if you are developing apps for enterprise, you can try with Brokered Windows Runtime Components. With this, you have the ability to run existing desktop software assets in one process (desktop component) while interacting with this code in a UWP App. For more info, please check this blog.

How to close a WPF application running in system tray from a C# console application?

I'm developing an application which has 2 parts:
1) A WPF application which runs from the system tray. It does have a GUI window, which can be brought up by right-clicking the sys-tray icon & choosing an option on the context menu, but it is not needed very frequently & the app will run from the sys-tray most of the time. Moreover, I've changed the Closing() event of the MainWindow, so as to minimize the app, if the user tries to close it.
2) A console application which runs without displaying a console & its purpose is to poll for launch/close of another application. As soon as the other application is launched/closed, the console application launches/closes the WPF application too. (Please don't tell me to do this using a Windows Service. I've already explored the route before. It doesn't work for me due to several reasons, which I won't enlist here).
PROBLEM: I am not able to close the WPF application from the console application. What I'm doing is as follows. First I obtain the process for my WPF application:
Process AppProcess = Process.GetProcessById((int)AppID);
After this I've tried a lot of options as follows:
1) Killing the process: AppProcess.Kill();
This is the only one which worked, but is very unelegant. It also leaves the SysTray icon undisposed, so it is not acceptable.
2) AppProcess.Close();
Doesn't work at all & I don't know why.
3) AppProcess.Dispose();
Doesn't work at all & I don't know why.
4) AppProcess.CloseMainWindow();
This only works if the user has kept the GUI of the WPF app opened, which is very rarely the case as I mentioned before. So, normally this also doesn't work. (You might say that I've hacked the Closing() event to prevent closing the window. Don't worry I've taken appropriate care to handle that. I've provided other measures to close the app. There is a boolean variable which decides whether the Closing action is to be cancelled or not.)
5) Passing custom/standard message to the WPF Application's main window.
This also works only if the main window (GUI) of the WPF app is open, else it doesn't receive the message.
So, all in all, no method is working. I need a reliable method to close the WPF app gracefully from the console app. Please suggest something.
The current way I'm doing it is as follows:
In the Console App:
const uint WM_CUSTOMCLOSE = 0xFE;
IntPtr hWnd = AppProcess.MainWindowHandle;
SendMessage(hWnd, WM_CUSTOMCLOSE, 0, 0);
In the WPF app:
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 == 0xFE)
{
ExitFlag = true; //Exitflag is checked later to decide whether closing is to be cancelled.
this.Close();
}
return IntPtr.Zero;
}
Use IPC as JeffRSon suggested. MSMQ is a very easy and effective way when two processes are on the same machine.
Define a queue of your WPF application and when it starts, no matter showing UI or not, let it listen the queue. Console application can send a message to the queue with closing application message. You have to define the data contract. You can refer to:
http://www.codeproject.com/Articles/3944/Programming-MSMQ-in-NET-Part-1
Ok, I found a way to close the WPF app. The reason it wasn't receiving the message was that for some reason, AppProcess.MainWindowHandle was not giving the handle of the main window of the WPF app, when the WPF app ran from the system tray.
So, instead I'm using the user32.dll:FindWindow() method found in the Win32 APIs to find the main window of the WPF app. After that when I pass my custom message to it, the WPF app shuts down gracefully.

Finding the Child Window inside a Microsoft RemoteApp Programmatically

Background
I'm using SendKeys() to send keyboard commands to the active window, but I'm not having any luck finding the child window when the application is running through RemoteApp. It all works as expected when I run the application locally.
Microsoft RemoteApp allows users to connect to applications through the RDP protocol, but instead of showing the entire remote Virtual machine, it just shows the application window. To the end user, there is no difference between an application running under RemoteApp and it running on their desktop.
I've been using ManagedSpy to determine the class name of the .NET application window so that I can use the Win32 API function FindWindowEx to make one of the child windows active, and it works well. However, I'm having a problem when the application is running over RemoteApp.
I can still use the .NET Process.GetProcessesByName() to find the application, I just have to have it invoke mstsc.exe:
IntPtr hwndChild = IntPtr.Zero;
Process[] processess = Process.GetProcessesByName("mstsc");
IntPtr appHandle = IntPtr.Zero;
foreach (Process p in processess)
{
if ((p.MainWindowHandle != IntPtr.Zero))
{
appHandle = p.MainWindowHandle;
}
}
if (appHandle == IntPtr.Zero)
{
MessageBox.Show("Application is not Running.");
return;
}
However, I can't use FindWindowEx in the same way. This question revolves around that.
For the unmanaged code to tell me what windows mstsc.exe has active, I used Spy++, but for mstsc.exe it comes back with a different class name, called RAIL_WINDOW:
Here is the code I'm using to find the Child Window:
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
hwndChild = FindWindowEx(appHandle, IntPtr.Zero, "RAIL_WINDOW", "MyApplication (Remote)");
SetForegroundWindow(hwndChild);
Questions
I can use Spy++ to highlight the active child window in the RemoteApp version of the application, and I get RAIL_WINDOW, but I cannot seem to access this window programmatically. Given the code above, what am I missing to be able to do so?
Are there other ways of sending keyboard strokes to an application running over Remote App?
Knowing how Microsoft does things, I'll bet the "rail window" is nothing more than a dumb, local proxy that doesn't bother responding to what SendKeys is sending. I haven't looked, but I'll bet that ends up sending WM_CHAR messages, to which a dumb proxy probably wouldn't bother responding. Instead, try sending it WM_KEYUP and WM_KEYDOWN messages manually and see if that works, given that I expect it would transmit those and mouse clicks (and what not) rather than the translated versions.
What commands are you sending using SendKeys()?
It may be better to look for an alternative solution instead of using `SendKeys()'.
And you can probably take advantage of handling IMsTscAxEvents::OnRemoteWindowDisplayed event that gives you the proper window handle at the right time without calling FindWindowEx, etc.

Send windows message to a Windows Service

Is there any tool to send (mimic) a windows message like 'WM_ENDSESSION' to a windows service?
OR
How can I send a windows message to a process using C#?
(I know only C#)
EDIT: Purpose: Basically I have to debug a windows service for fixing a bug that occurs only on system shut down.
Services should be controlled using ServiceController class
Represents a Windows service and allows you to connect to a running or stopped service, manipulate it, or get information about it.
You can use it to start, stop and communicate with services using this class.
Generally, services don't have windows (let alone message pumps) to receive a windows message.
If the bug really does only happen on shutdown (as opposed to just stopping the service), it may be the case that something depends on a resource that is going away, which is not being handled gracefully (in which case, the bug fix might be to set up the service dependencies correctly). Have you tried using the remote debugging tools to attach to the process prior to shutdown?
It's worth investigating if you can get the problem to occur without shutting down, perhaps when just stopping the service with the Service Control Manager (no need to do this programmatically, as this is a debugging scenario), in which case, you can breakpoint OnStop() in your service (I'm assuming C#) and watch what happens.
Check out the answers to How to simulate windows shutdown while debugging?
Services have an 'event' called OnShutdown they can subscribe to, so it could be the problem is in that code. If the code is .net you could subclass it so you can call the protected OnShutdown method to debug. But the problem could also be as suggested by others that the service is expecting resources to be available which aren't because they've already been closed.
Also, if the service was written in .net 2.0 note that the Stop() command isn't called automatically on a service when the workstation is being shut down! This is very surprising and was fixed in .net 3.5, but if you're using .net 2.0 you need to call Stop() yourself within OnShutdown().
If you have the hwnd of a window you can send it messages. The only limitation is that you can't send messages that contain pointers like setting window text.
Simply call PostMessage() with the value of the hwnd and the message you want to send.
To find the hwnd you can use spy++.
I'm not sure how you connect all this to windows services since windows services don't have windows.
I would recommend Importing and defining the following:
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern bool PostMessage(IntPtr handleWnd, UInt32 Msg, Int32 wParam, Int32 lParam);
const int WM_ENDSESSION = 0x0016,
WM_TRUE = 0x1,
WM_FALSE = 0x0;
Then send through 0x1 or 0x0 representing true or false as the wParam message.
So in your code you will use:
PostMessage(HandleToSendTo, WM_ENDSESSION, WM_TRUE, 0);
Where HandleToSendTo is the Window Handle of the window you would like to send the message to.
Edit
To get the windows handle if you don't know it, I'm assuming that you will know it's title or name. If so you can use this:
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern int FindWindowEx(int hwndParent, int hwndEnfant, int lpClasse, string lpTitre);
Which more information about can be found in this question.
Or maybe
I don't know if this is a similar handle, I doubt it, but someone could let me know if it is, but you can get a Process handle, which means you could get the process using Process.GetProcessesByName("MyAppName");, althought don't rely on this as I don't think that it will get the handle that you are after. Just a suggestion.
I don't think there is a tool to send arbitrary messages because each message can have arbitrary LPARAM and WPARAM values.
But the most useful tool surrounding windows messages is spy++. Spy++ is included with Visual Studio and it helps you see what messages are sent, window hierarchy, and more.
You can send messages via C# with the SendMessage Win32 API. You can get the window handle it asks for by using a Win32 API like FindWindow or FindWindowEx.
Edit (to match question's edit): Services are stopped by windows automatically on shutdown. So to fix your bug it sounds like you need to modify the code of the service itself to properly shut down.
Edit2: Or if you want to stop the service you should use the Win32 API ControlService passing in SERVICE_CONTROL_STOP 0x00000001.
I don't know if this is a similar handle, I doubt it, but someone could let me know if it is, but you can get a Process handle, which means you could get the process using Process.GetProcessesByName("MyAppName");, althought don't rely on this as I don't think that it will get the handle that you are after. Just a suggestion.
Actually this method will work...you just need to access the 'MainWindowHandle' property of the process object. For Instance...
Process myProcess;
Int handle;
myProcess = Process.GetProcessesByName("MyAppName");
handle = myProcess.MainWindowHandle;

Categories

Resources