I am trying to receive messages from QCollector as explained in the QCollector Data Interface developer guide. The process consists of registering predefined messages, finding the QCollector server window, and exchanging data through the registered messages.
My WndProc callback receives lost of messages, but none of those are recognized as one of the registered messages. I'm passing my Form's this.Handle in the request, but I'm unsure if this is correct.
What am I doing wrong?
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace HistDataManager
{
public partial class Form1 : Form
{
[DllImport("user32.dll", EntryPoint = "FindWindow")]
private static extern int FindWindow(string sClass, string sWindow);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, UIntPtr wParam, IntPtr lParam);
int nWinHandle = FindWindow("QCDataInterfaceWndClass", null);
uint wm_QCollectorClientDataRequest = RegisterWindowMessage("QCOLLECTOR_CLIENT_DATA_REQUEST");
uint wm_QCollectorClientPortfolioListRequest = RegisterWindowMessage("QCOLLECTOR_CLIENT_PORTFOLIO_LIST_REQUEST");
uint wm_QCollectorPortfolioListRequestComplete = RegisterWindowMessage("QCOLLECTOR_PORTFOLIO_LIST_REQUEST_COMPLETE ");
public void TestQC()
{
SendMessage(new IntPtr(nWinHandle), wm_QCollectorClientPortfolioListRequest, UIntPtr.Zero, this.Handle);
}
protected override void WndProc(ref Message m)
{
Console.WriteLine(m.HWnd + "," + m.Msg + "," + m.LParam + "," + m.WParam);
base.WndProc(ref m);
if (m.Msg == wm_QCollectorClientPortfolioListRequest || m.Msg == wm_QCollectorPortfolioListRequestComplete)
{
Console.WriteLine("Message from specified application found!");
}
}
}
}
EDIT 1:
Just to be sure that I have the basics working in c# I created a second version of this app and got them to talk to each other. This works, so I know my handles and message structures are correct.
BUT I never get a response from qCollector. Does anyone have experience of using this in any other language perhaps? I suspect qCollector was written in c++.
I dont know if it is fine in .Net but i would like to suggest you to call all the functions in either constructor or in init() function.
Suggested Design
int nWinHandle=0;
uint wm_QCollectorClientDataRequest=0;
uint wm_QCollectorClientPortfolioListRequest=0;
uint wm_QCollectorPortfolioListRequestComplete=0;
void init()
{
nWinHandle = FindWindow("QCDataInterfaceWndClass", null);
wm_QCollectorClientDataRequest = RegisterWindowMessage("QCOLLECTOR_CLIENT_DATA_REQUEST");
wm_QCollectorClientPortfolioListRequest = RegisterWindowMessage("QCOLLECTOR_CLIENT_PORTFOLIO_LIST_REQUEST");
wm_QCollectorPortfolioListRequestComplete = RegisterWindowMessage("QCOLLECTOR_PORTFOLIO_LIST_REQUEST_COMPLETE ");
}
Related
I'm making a program to show another program fullscreen programmatically. To do this, I use MoveWindow() from WinAPI, but it needs a Window Handler. I tried to get it using FindWindow(), but since it uses the window name, I often had situations where the name was in a different language and it didn't work (or it didn't exist at all). So now I need to somehow get the Window Handler of the desired program by PID or even more conveniently by the name of the process. In C++, I found EnumWindows(), but I completely don't understand how to rewrite it in C#.
Question: How do I get the Window Handler using the PID or the program name?
Use EnumWindows to enumerate the handles of all windows and pass the window handle as a parameter to the GetWindowThreadProcessId function.
After obtaining the pid, compare the value with the pid of another program you provided. If it is the same, use MoveWindow to move it.
C# example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace EnumPTW
{
class Program
{
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
// Callback Declaration
public delegate bool EnumWindowsCallback(IntPtr hwnd, int lParam);
[DllImport("user32.dll")]
private static extern int EnumWindows(EnumWindowsCallback callPtr, int lParam);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
public static bool ReportWindow(IntPtr hwnd, int lParam)
{
uint processId = 0;
uint threadId = GetWindowThreadProcessId(hwnd, out processId);
if(processId == 23272) //23272: another program pid
{
Console.WriteLine(string.Format("Enumerated Window Handle 0x{0:X8}, Process {1}, Thread {2}", hwnd.ToInt32(), processId, threadId));
MoveWindow(hwnd, 100, 100, 800, 600, true);
}
return true;
}
static void Main(string[] args)
{
// Have to declare a delegate so that a thunk is created, so that win32 may call us back.
EnumWindowsCallback callBackFn = new EnumWindowsCallback(ReportWindow);
EnumWindows(callBackFn, 0);
Console.WriteLine("Finished. Press any key to continue.");
Console.ReadKey();
}
}
}
You can also use OpenProcess to get the handle of the process based on the pid, then use GetModuleFileNameEx to get the name of the process, and then compare the name with the process name you provided.
Sample: The using of OpenProcess and GetModuleFileNameEx
I have a C# application which uses multiple event handlers which are triggered by various events. As an example:
Global mouse hook event
Global Key hook event which is filtered (the handler only triggers with certain keypresses)
Active window change global hook
Structure Changed application hook (this is an UIAAutomation event where different structure changed event/handlers are created for each application window when it becomes the active window (so, for example, if the application is Internet Explorer then paging down the browser, clicking on another website link are examples of the structure changing on the Internet Explorer application instance)
All these events (running on background threads, e.g. MTA) have the effect of updating the UI window of my application. All of them are working as they should.
My issue is that with certain circumstances multiple events are triggered at the same time. So for example it is feasible that the following events are all triggered within 1 second (such a scenario would occur if I clicked on a different active window):
Global Change of active window
Global Mouse Hook
Application structure changed.
In different circumstances (e.g. different active applications) one event is preferred above the other as the defining event which is ruled by a set of conditions (Booleans) . I do not want to act on more than 1 event at a particular period of time.
What is the best programming mechanism for considering the events triggered and deciding, by a set of conditions, which one to act on? Of course this all has to be done within a very quick period of time (e.g. one second or less). The events if triggered will all occur within this period of time.
I hope this makes sense and if not please ask for clarification. Incidentally the reason I would like to update my UI of my application by a certain defining event is that the information that my UI presents will be slightly different depending on which event is fired (mainly due to the slight difference in timing when the differing events are triggered). Incidentally the time taken to trigger a particular event will vary depending on the action taken (e.g. clicking on a different active window). Sometimes one event type is quicker than another but then in different circumstances a different event type can be the quickest event (or the slowest event triggered)
Thank you for both the answers below very much appreciated. I will check out the System.Reactive library in the first place as it sounds purpose-built for the task.
Microsoft's Reactive Framework (NuGet "System.Reactive") can do this kind of ting superbly and very powerfully. You can do some things very simply, but some queries - especially those dealing with time - can be quite complicated.
Here's a sample of what you might do:
var event1 = new Subject<int>();
var event2 = new Subject<int>();
var query =
event1.Merge(event2).Buffer(TimeSpan.FromSeconds(1.0));
query.Subscribe(xs => Console.WriteLine($"\"{String.Join(", ", xs)}\""));
event1.OnNext(42);
Thread.Sleep(3000);
event2.OnNext(43);
Thread.Sleep(500);
event1.OnNext(44);
That outputs:
"42"
""
""
"43, 44"
""
""
Note that it produces the "43, 44" at the same time even though the events fire 500ms apart.
I've been using code like below to prevent conflicts in event handling :
class Program
{
enum EVENTS
{
EVENT1,
EVENT2,
EVENT3,
EVENT4,
}
static void Main(string[] args)
{
}
static void EventHandler(EVENTS myEvent)
{
Object thisLock = new Object();
lock (thisLock)
{
switch (myEvent)
{
case EVENTS.EVENT1 :
break;
case EVENTS.EVENT2:
break;
case EVENTS.EVENT3:
break;
case EVENTS.EVENT4:
break;
}
}
}
}
Here is a simplified version of my code with several global hooks which are triggered by change of active window and a left mouse click. If you left click on a different active window both the mouse click event and change of active window event will be triggered. If you could show me example code of using the Reactive namespace to deal with the 2 events when they are triggered within milliseconds of each other I would greatly appreciate it.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Testing_multiple_events
{
public partial class Form1 : Form
{
int activeWindowCount = 1;
int activeMouseClickCount = 1;
public Form1()
{
InitializeComponent();
// set up the global hook event for change of active window
GlobalEventHook.Start();
GlobalEventHook.WinEventActive += new EventHandler(GlobalEventHook_WinEventActive);
// Setup global mouse hook to react to mouse clicks under certain conditions, see event handler
MouseHook.Start();
MouseHook.MouseAction += new EventHandler(MouseHook_MouseAction);
}
private void GlobalEventHook_WinEventActive(object sender, EventArgs e)
{
richTextBox1.AppendText("Active Window Change Global Hook Triggered: " + activeWindowCount + "\r\n");
activeWindowCount++;
}
private void MouseHook_MouseAction(object sender, EventArgs e)
{
richTextBox1.AppendText("Global MouseHook Triggered: " + activeMouseClickCount + "\r\n");
activeMouseClickCount++;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace Testing_multiple_events
{
public static class GlobalEventHook
{
[DllImport("user32.dll")]
internal static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc,
WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
[DllImport("user32.dll")]
internal static extern bool UnhookWinEvent(IntPtr hWinEventHook);
public static event EventHandler WinEventActive = delegate { };
public static event EventHandler WinEventContentScrolled = delegate { };
public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject,
int idChild, uint dwEventThread, uint dwmsEventTime);
private static WinEventDelegate dele = null;
private static IntPtr _hookID = IntPtr.Zero;
public static void Start()
{
dele = new WinEventDelegate(WinEventProc);
_hookID = SetWinEventHook(Win32API.EVENT_SYSTEM_FOREGROUND, Win32API.EVENT_OBJECT_CONTENTSCROLLED, IntPtr.Zero, dele, 0, 0, Win32API.WINEVENT_OUTOFCONTEXT);
}
public static void stop()
{
UnhookWinEvent(_hookID);
}
public static void restart()
{
_hookID = SetWinEventHook(Win32API.EVENT_SYSTEM_FOREGROUND, Win32API.EVENT_OBJECT_CONTENTSCROLLED, IntPtr.Zero, dele, 0, 0, Win32API.WINEVENT_OUTOFCONTEXT);
}
public static void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
if (eventType == Win32API.EVENT_SYSTEM_FOREGROUND)
{
WinEventActive(null, new EventArgs());
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace Testing_multiple_events
{
public static class MouseHook
{
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
public static event EventHandler MouseAction = delegate { };
private const int WH_MOUSE_LL = 14;
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
public static void Start()
{
_hookID = SetHook(_proc);
}
public static void stop()
{
UnhookWindowsHookEx(_hookID);
}
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
IntPtr hook = SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle("user32"), 0);
if (hook == IntPtr.Zero) throw new System.ComponentModel.Win32Exception();
return hook;
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && (MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam || MouseMessages.WM_RBUTTONDOWN == (MouseMessages)wParam ||
MouseMessages.WM_MOUSEWHEEL == (MouseMessages)wParam))
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
MouseAction(null, new EventArgs());
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
}
}
UPD: added MCVE.
This is an educational task. I have to use SendMessage() function:
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd,
uint wMsg, UIntPtr wParam, IntPtr lParam);
I have to make two different applications with GUI communicationg by messages. After getting message like "start" 1 app have to start sendinding message "Ask value" to 2 app each 5 seconds. And 2 app send to 1 app message "Send value" with some data.
1 app is WinForms program:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace Oven_Monitor
{
public partial class Form1 : Form
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetCurrentProcessId();
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, UIntPtr wParam, IntPtr lParam);
private uint askMessageID = RegisterWindowMessage("Ask value");
private uint dataMessageID = RegisterWindowMessage("Send value");
private uint registerMessageID = RegisterWindowMessage("Register sensor");
public Form1() {
InitializeComponent();
this.Text = "Really rare title";
}
public void checkSensors() {
while (true) {
SendMessage(secondAppHWnd, askMessageID, (UIntPtr)0, (IntPtr)0);
System.Threading.Thread.Sleep(500);
}
}
private IntPtr secondAppHWnd;
protected override void WndProc(ref Message m) {
if (m.Msg == registerMessageID) {
secondAppHWnd = m.LParam;
Thread tr = new Thread(checkSensors);
tr.Start();
} else if (m.Msg == dataMessageID) {
//do some stuff
}
base.WndProc(ref m);
}
}
}
2 app is console project, but it requires System.Windows.Forms referens:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace HeatSensor
{
class Program
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
static void Main(string[] args)
{
IntPtr mainAppHandle = FindWindow(null, "Really rare title");
while (mainAppHandle == IntPtr.Zero)
{
Console.ReadKey();
mainAppHandle = FindWindow(null, "Really rare title");
}
HiddenForm form = new HiddenForm(mainAppHandle);
while (true) //it's actually not infinit
{
//do some stuff
}
}
}
}
And hidden form class:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace HeatSensor
{
public partial class HiddenForm : Form
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, UIntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);
static private IntPtr mainAppHandle;
public HiddenForm(IntPtr mainAppHWnd)
{
InitializeComponent();
mainAppHandle = mainAppHWnd;
string title = System.DateTime.Now.ToLongDateString();
title += System.DateTime.Now.ToLongTimeString();
title += System.DateTime.Now.Ticks.ToString();
this.Text = title;
this.CreateHandle();
int currentWindowHandle = (int)FindWindow(null, title);
SendMessage(mainAppHandle, RegisterWindowMessage("Register sensor"),
(UIntPtr)0, currentWindowHandle);
}
private uint askMessageID = RegisterWindowMessage("Ask value");
private uint dataMessageID = RegisterWindowMessage("Send value");
private uint registerMessageID = RegisterWindowMessage("Register sensor");
protected override void WndProc(ref Message m)
{
if (m.Msg == askMessageID)
{
SendMessage(mainAppHandle, dataMessageID, (UIntPtr)1, (IntPtr)1);
}
base.WndProc(ref m);
}
}
}
For some reason this programs act strange. Almost everytime 2 app don't getting sended "Ask value" message, sometimes checkSensors() send 1-3 messages and stop.
What is wrong?
Both HWnd is correct.
Update: I tried to check error here:
public void checkSensors() {
while (true) {
SendMessage(secondAppHWnd, askMessageID, (UIntPtr)0, (IntPtr)0);
int error = Marshal.GetLastWin32Error();
System.Threading.Thread.Sleep(500);
}
}
And see. As SendMessage was performed, this thread was blocked (what means, SendMessage was not copleted. After i closed 2 app, thread was unblocked and i got 164 error (ERROR_MAX_THRDS_REACHED: No more threads can be created in the system.). What it's supposed to mean?
Also, added:
protected override void WndProc(ref Message m)
{
//here is all message checks
int erro2r = Marshal.GetLastWin32Error();
if (erro2r != 0) {
int j; //stop to debug here
}
base.WndProc(ref m);
}
And it just constantly return 1400 ERROR_INVALID_WINDOW_HANDLE (i don't send any messages at that moment).
So it looks totaly unclear to me.
update 2: If i call it from WndProc(), everything works:
SendMessage(secondAppHWnd, askMessageID, (UIntPtr)0, (IntPtr)0);
But i need to send this message from different thread each 5 seconds.
So, it finally works if both programs is WinForms projects. I can just run console window from 2 app and hide main window.
I'm using the Sopcast activex plugin (sopocx.ocx) in one of my C# applications.
I would like to retrieve the player status ("Buffering the channel", "Playing the channel", "Channel Offline...") and the buffering percentage. Both of these informationss are displayed on the player (I tried to post a picture but I don't have enough reputation yet).
The problem is the Sopcast activex plugin doesn't provide any methods in order to retrieve these informations.
Does someone has any idea on how this could be done??
GetWindowText results in an empty string...
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace test
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
private void testToolStripMenuItem_Click(object sender, EventArgs e)
{
IntPtr hwnd = sopcast.Handle;
StringBuilder lpString = new StringBuilder(256);
GetWindowText(hwnd, lpString, 256);
MessageBox.Show(lpString.ToString());
}
private void playToolStripMenuItem_Click(object sender, EventArgs e)
{
sopcast.SetSopAddress("sop://broker.sopcast.com:3912/123456789");
sopcast.SetChannelName("Channel");
sopcast.Play();
}
}
}
You can identify Id control and get text with api windows
here a code sample (replace notepad by your application name) the most important for you is to get from your application a way to get ID control of your ocx window
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Security;
namespace Application
{
public class Program
{
public static void Main ( )
{
IntPtr hwnd = UnsafeNativeMethods.FindWindow("Notepad", null);
StringBuilder stringBuilder = new StringBuilder(256);
UnsafeNativeMethods.GetWindowText(hwnd, stringBuilder, stringBuilder.Capacity);
Console.WriteLine(stringBuilder.ToString());
}
}
[SuppressUnmanagedCodeSecurity]
internal static class UnsafeNativeMethods
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern int GetWindowText ( IntPtr hWnd, [Out] StringBuilder lpString, int nMaxCount );
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr FindWindow ( string lpClassName, string lpWindowName );
}
}
I download sopcast and try to get status using spy++:
As you see, caption is status not the channel...
so you can not get it easier
the handle you have catched is for the whole control
Sopcast draws the status text using DrawText (i found out using API Monitor http://www.rohitab.com/apimonitor). So there is no way of getting the text using conventional GetWindowText function or similar. I was able to obtain the text by hooking DrawText function. For .NET EasyHook will enable you to do this.
My scenario:
I have a winforms app that hosts the activex control and i want to obtain the status text.
public class hooklocal : EasyHook.IEntryPoint
{
[DllImport("user32.dll")]
static extern int DrawText(IntPtr hDC, string lpString, int nCount, IntPtr lpRect, uint uFormat);
[UnmanagedFunctionPointer(CallingConvention.StdCall,CharSet = CharSet.Auto,SetLastError = true)]
delegate int DDrawText(IntPtr hDC, string lpString, int nCount, IntPtr lpRect, uint uFormat);
int DrawTextH(IntPtr hDC, string lpString, int nCount, IntPtr lpRect, uint uFormat)
{
//lpString contains the status text
return DrawText(hDC, lpString, nCount, lpRect, uFormat);
}
public hooklocal()
{
try
{
var CreateHook = LocalHook.Create(
LocalHook.GetProcAddress("user32.dll", "DrawTextW"),
new DDrawText(DrawTextH),
this);
CreateHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
}
catch (Exception ExtInfo)
{
Debugger.Break();
}
}
}
To use, instantiate hooklocal class in a new thread at program startup.
EasyHook download
https://easyhook.github.io/downloads.html
I have an WPF application called app1 which has a windows named window1. When the user clicks the close button of window1, the app does not close but the window1 hides (this.hide()).
I want to check if another instance of the application is already running when it is started; if so, I want to show the already running instance and terminate the new one.
How can I do that?
I know how to check the process and how to close the current app but I don't know how to show a window from another WPF process which is running...
In my App startup event I do this :
private void Application_Startup(object sender, StartupEventArgs e)
{
if(Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Count() > 1)
{
Application.Current.Shutdown(0);
}
}
A typical approach to this is to use a Mutex. This allows you to prevent a second instance from being started (or rather, detect it within the second instance of the application).
At that point, you can notify the original application instance to "show" itself. Here is a good article describing the entire process in detail (though using Windows Forms).
For a WPF application, you'll need to put this logic in the Application's startup logic, and add an HwndSourceHook to process the windows message in your WPF window which you want to have show.
I found how to do the work!
My problem solved with "Reed Copsey" help and with Windows SendMessage API.
for doing this thing I wrote these codes in my window1.xaml.cs file :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Interop;
namespace app1
{
public partial class window1: Window
{
public window1()
{
InitializeComponent();
}
private void window1_Loaded(object sender, RoutedEventArgs e)
{
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(new HwndSourceHook(WndProc));
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
System.Windows.Forms.Message m = System.Windows.Forms.Message.Create(hwnd, msg, wParam, lParam);
if (m.Msg == WM_COPYDATA)
{
// Get the COPYDATASTRUCT struct from lParam.
COPYDATASTRUCT cds = (COPYDATASTRUCT)m.GetLParam(typeof(COPYDATASTRUCT));
// If the size matches
if (cds.cbData == Marshal.SizeOf(typeof(MyStruct)))
{
// Marshal the data from the unmanaged memory block to a
// MyStruct managed struct.
MyStruct myStruct = (MyStruct)Marshal.PtrToStructure(cds.lpData,
typeof(MyStruct));
// Display the MyStruct data members.
if (myStruct.Message == "Show Up")
{
this.Show();
}
}
}
return IntPtr.Zero;
}
internal const int WM_COPYDATA = 0x004A;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct MyStruct
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Message;
}
[StructLayout(LayoutKind.Sequential)]
internal struct COPYDATASTRUCT
{
public IntPtr dwData; // Specifies data to be passed
public int cbData; // Specifies the data size in bytes
public IntPtr lpData; // Pointer to data to be passed
}
}
}
And I wrote these codes in my App.xaml.cs :
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;
using System.Windows.Threading;
using System.Runtime.InteropServices;
using System.Security;
namespace app1
{
public partial class App : Application
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct MyStruct
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Message;
}
internal const int WM_COPYDATA = 0x004A;
[StructLayout(LayoutKind.Sequential)]
internal struct COPYDATASTRUCT
{
public IntPtr dwData; // Specifies data to be passed
public int cbData; // Specifies the data size in bytes
public IntPtr lpData; // Pointer to data to be passed
}
[SuppressUnmanagedCodeSecurity]
internal class NativeMethod
{
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg,
IntPtr wParam, ref COPYDATASTRUCT lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
}
private void Application_Startup(object sender, StartupEventArgs e)
{
if (System.Diagnostics.Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Count() > 1)
{
IntPtr hTargetWnd = NativeMethod.FindWindow(null, "window1");
if (hTargetWnd == IntPtr.Zero)
{
return;
}
MyStruct myStruct;
myStruct.Message = "Show Up";
int myStructSize = Marshal.SizeOf(myStruct);
IntPtr pMyStruct = Marshal.AllocHGlobal(myStructSize);
try
{
Marshal.StructureToPtr(myStruct, pMyStruct, true);
COPYDATASTRUCT cds = new COPYDATASTRUCT();
cds.cbData = myStructSize;
cds.lpData = pMyStruct;
NativeMethod.SendMessage(hTargetWnd, WM_COPYDATA, new IntPtr() , ref cds);
int result = Marshal.GetLastWin32Error();
if (result != 0)
{
}
}
finally
{
Marshal.FreeHGlobal(pMyStruct);
}
Application.Current.Shutdown(0);
}
}
}
}
And that's it. :D