I have a program that needs to send the BM_CLICK message to another applications button.
I can get the parent window handle but when I try to get the button handle if always returns 0
I got the button caption name and button type from Spy++ it seems right but I know I must have gotten something wrong. below is my code
public const Int BM_CLICK = 0x00F5;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SendMessage(IntPtr hwnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
private void button1_Click(object sender, EventArgs e)
{
Process[] processes = Process.GetProcessesByName("QSXer");
foreach (Process p in processes)
{
////the Button's Caption is "Send" and it is a "Button".
IntPtr ButtonHandle = FindWindowEx(p.MainWindowHandle, IntPtr.Zero, "Button", "Send");
//ButtonHandle is always zero thats where I think the problem is
SendMessage(ButtonHandle, BM_CLICK, IntPtr.Zero, IntPtr.Zero);
}
}
Spy screen shot
Try to pass null for the window text and instead try to find any button:
IntPtr ButtonHandle = FindWindowEx(p.MainWindowHandle, IntPtr.Zero, "Button", null);
After that you can use the second parameter and a new call to get the next button handle a couple more times.
Also could you please try checking Marshal.GetLastWin32Error to see what the error result is?
Try this:
IntPtr ButtonHandle = FindWindowEx(p.MainWindowHandle, IntPtr.Zero, null, "Send");
You can do somthing like this:
//Program finds a window and looks for button in window and clicks it
HWND buttonHandle = 0;
BOOL CALLBACK GetButtonHandle(HWND handle, LPARAM)
{
char label[100];
int size = GetWindowTextA(handle, label, sizeof(label));
if (strcmp(label, "Send") == 0) // your button name
{
buttonHandle = handle;
cout << "button id is: " << handle << endl;
return false;
}
return true;
}
int main()
{
HWND windowHandle = FindWindowA(NULL, "**Your Window Name**");
if (windowHandle == NULL)
{
cout << "app isn't open." << endl;
}
else
{
cout << "app is open :) " << endl;
cout << "ID is: " << windowHandle << endl;
SetForegroundWindow(windowHandle);
BOOL ret = EnumChildWindows(windowHandle, GetButtonHandle, 0); //find the button
cout << buttonHandle << endl;
if (buttonHandle != 0)
{
LRESULT res = SendMessage(buttonHandle, BM_CLICK, 0, 0);
}
}
}
This should do the trick.
Try to build project as x86. I try and successed!
Related
EDIT: I GOT IT FIXED HERE'S MY WORKING FULL CODES TO SET EXAMPLE TO NEW FRIENDS and my original question is below too.
before the codes let me introduce you to some docs (in order):
https://learn.microsoft.com/en-us/windows/win32/winmsg/about-messages-and-message-queues#message-routing
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendmessage
https://learn.microsoft.com/en-us/windows/win32/winmsg/window-features#message-only-windows
https://learn.microsoft.com/en-us/windows/win32/dataxchg/using-data-copy
http://pinvoke.net/default.aspx/Structures/COPYDATASTRUCT.html
C# program
using System;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Program
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern long SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern IntPtr FindWindow(string classname, string windowname);
[StructLayout(LayoutKind.Sequential)]
struct COPYDATASTRUCT
{
public uint dwData;
public int cbData;
public IntPtr lpData;
}
public static IntPtr IntPtrAlloc<T>(T param)
{
IntPtr retval = Marshal.AllocHGlobal(Marshal.SizeOf(param));
Marshal.StructureToPtr(param, retval, false);
return (retval);
}
public static void IntPtrFree(IntPtr preAllocated)
{
if (IntPtr.Zero == preAllocated) throw (new Exception("Go Home"));
Marshal.FreeHGlobal(preAllocated); preAllocated = IntPtr.Zero;
}
const int WM_COPYDATA = 0x004A;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Thread.Sleep(3000);
string message = "This is a test";
IntPtr hWnd = FindWindow("MyClass", "MyTitle");
if (hWnd == IntPtr.Zero)
{
MessageBox.Show("couldn't find the window");
}
else
{
COPYDATASTRUCT cds;
cds.dwData = 1;
cds.cbData = message.Length + 1;
cds.lpData = Marshal.StringToHGlobalAnsi(message);
IntPtr cdsBuffer = IntPtrAlloc(cds);
SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, cdsBuffer);
IntPtrFree(cds.lpData);
IntPtrFree(cdsBuffer);
}
}
}
}
C++ program
#include <iostream>
#include <Windows.h>
using namespace std;
LRESULT CALLBACK WindProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if (Msg == WM_COPYDATA)
{
PCOPYDATASTRUCT data = (PCOPYDATASTRUCT)lParam;
MessageBoxA(hWnd, (LPSTR)data->lpData, "info", 0); // The character set depends on the characters you send
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
int main(){
WNDCLASSEX wcx = { 0 };
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.lpfnWndProc = WindProc;
wcx.hInstance = GetModuleHandle(NULL);
wcx.lpszClassName = TEXT("MyClass");
RegisterClassEx(&wcx);
HWND hWnd = CreateWindowEx(0, TEXT("MyClass"), TEXT("MyTitle"), 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
MSG message;
for(int i = 0; i < 1000; i++)
{
std::cout << "working" << std::endl;
Sleep(2 * 1000);
if(PeekMessage(&message, NULL, 0, 0, PM_NOREMOVE))
{
break;
}
}
int x;
cout<<"got it!";
cin>>x;
return 0;
}
ORGINIAL QUESTION:
I have a C# application that i want to communicate with a c++ process that i create within my C# app.
I have a code in my hand that is supposed to work i suppose but it doesn't. The message simply is not gotten by c++ app.
my C# program:
namespace ScannerGUI
{
public partial class Form1 : Form
{
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential)]
struct COPYDATASTRUCT
{
public uint dwData;
public int cbData;
public IntPtr lpData;
}
public static IntPtr IntPtrAlloc<T>(T param)
{
IntPtr retval = Marshal.AllocHGlobal(Marshal.SizeOf(param));
Marshal.StructureToPtr(param, retval, false);
return (retval);
}
public static void IntPtrFree(IntPtr preAllocated)
{
if (IntPtr.Zero == preAllocated) throw (new Exception("Go Home"));
Marshal.FreeHGlobal(preAllocated); preAllocated = IntPtr.Zero;
}
const int WM_COPYDATA = 0x004A;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//creating child process
var prcsInfo = new ProcessStartInfo
{
UseShellExecute=true,
CreateNoWindow = false,
FileName = "main.exe",
};
Process myProcess = Process.Start(prcsInfo);
ChildProcessTracker.AddProcess(myProcess);
Thread.Sleep(3000);
string message = "This is a test";
IntPtr hWnd = myProcess.Handle;
if (hWnd == IntPtr.Zero)
{
MessageBox.Show("couldn't find the process");
}
else
{
COPYDATASTRUCT cds;
cds.dwData = 1;
cds.cbData = message.Length + 1;
cds.lpData = Marshal.StringToHGlobalAnsi(message);
IntPtr cdsBuffer = IntPtrAlloc(cds);
PostMessage(hWnd, WM_COPYDATA, IntPtr.Zero, cdsBuffer);
IntPtrFree(cds.lpData);
IntPtrFree(cdsBuffer);
}
}
}
}
my c++ app (main.exe):
int main(){
MSG message;
for(int i = 0; i < 1000; i++)
{
std::cout << "working" << std::endl;
Sleep(2 * 1000);
if(PeekMessage(&message, NULL, 0, 0, PM_NOREMOVE))
{
break;
}
}
int x;
cout<<"got it!";
cin>>x;
return 0;
}
when i start the c# program. no errors, no nothing.
same with c++, no errors, no nothing but never break the for loop :(
thanks for everyone for their time.
First of all, Process.Handle is the handle of the process instead of the window.
Secondly, since your main.exe is a console application and it only has a console window, you can only get the handle of the console window by using MainWindowHandle. However, the console does not belong to the main.exe, So you cannot use PeekMessage to handle the message sent to the console window. Console windows are owned by the console subsystem, csrss.exe(see https://stackoverflow.com/a/28248281/10611792). You should create your own window for your C++ app, or create a Message-Only window. Then, you can use FindWindow to get the window handle in C#:
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern long SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll",CharSet = CharSet.Unicode)]
static extern IntPtr FindWindow(string classname, string windowname);
...
private void Form1_Load(object sender, EventArgs e)
{
...
Thread.Sleep(3000);
string message = "This is a test";
IntPtr hWnd = FindWindow("MyClass", "MyTitle");
if (hWnd == IntPtr.Zero)
{
MessageBox.Show("couldn't find the process");
}
else
{
COPYDATASTRUCT cds;
cds.dwData = 1;
cds.cbData = message.Length + 1;
cds.lpData = Marshal.StringToHGlobalAnsi(message);
IntPtr cdsBuffer = IntPtrAlloc(cds);
SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, cdsBuffer);
IntPtrFree(cds.lpData);
IntPtrFree(cdsBuffer);
}
}
}
C++:
LRESULT CALLBACK WindProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if (Msg == WM_COPYDATA)
{
PCOPYDATASTRUCT data = (PCOPYDATASTRUCT)lParam;
MessageBoxA(hWnd, (LPSTR)data->lpData, "info", 0); // The character set depends on the characters you send
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
int main() {
WNDCLASSEX wcx = { 0 };
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.lpfnWndProc = WindProc;
wcx.hInstance = GetModuleHandle(NULL);
wcx.lpszClassName = TEXT("MyClass");
RegisterClassEx(&wcx);
HWND hWnd = CreateWindowEx(0, TEXT("MyClass"), TEXT("MyTitle"), 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
MSG msg;
for (int i = 0; i < 1000; i++)
{
std::cout << "working" << std::endl;
Sleep(2 * 1000);
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
break;
}
}
int x;
cout << "got it!";
cin >> x;
return 0;
}
Also Note that use SendMessage instead of PostMessage.
In addition, you can also choose other IPC methods.
Why C++ WindowProc function don't receive message from c#?
C# code call c++ ExeC.exe using SendMessage(). However there is no response in Switch case WM_COPYDATA IN WindowProc function.
C# full code :
public partial class MainWindow : Window
{
public const string strFilePath = "C:/Users/gandis/Desktop/Project/ExeC/Release/ExeC.exe";
public const Int32 WM_COPYDATA = 0x004A;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 message, int wParam, ref int lParam);
public MainWindow()
{
InitializeComponent();
}
private void btn_Start_Click(object sender, RoutedEventArgs e)
{
IntPtr hWnd = GetHandle(strFilePath);
if (hWnd.ToInt32() > 0)
{
int cdss = 1;
SendMessage(hWnd, WM_COPYDATA, 1, ref cdss);
}
}
private IntPtr GetHandle(string strFilePath)
{
IntPtr hWnd = IntPtr.Zero;
hWnd = GetProcess(strFilePath).MainWindowHandle;
return hWnd;
}
private Process GetProcess(string strFilePath)
{
Process proc = new Process();
proc.StartInfo.FileName = strFilePath;
proc.Start();
proc.WaitForInputIdle();
return proc;
}
}
I add only WindowProc virtual furction in MFC.
C++ code :
LRESULT CExeCDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COPYDATA:
AfxMessageBox(_T(__FUNCTION__));
break;
}
return CDialog::WindowProc(message, wParam, lParam);
}
Your declaration of SendMessage() is wrong. The wParam should be UIntPtr, and the lParam should be IntPtr. And you are missing the SetLastError=true attribute on your DllImport.
And if (hWnd.ToInt32() > 0) should be if (hWnd != IntPtr.Zero).
And you should call proc.Refresh() after calling proc.WaitForInputIdle() and before querying proc.MainWindowHandle.
But, most importantly, your input values for the WM_COPYDATA message are wrong, so the message is likely failing to be sent at all (but you are ignoring the return values of SendMessage() and Marshal.GetLastWin32Error(), so you wouldn't know that). Read the documentation:
wParam
A handle to the window passing the data.
lParam
A pointer to a COPYDATASTRUCT structure that contains the data to be passed.
You are passing a literal 1 where an HWND is expected, and you are passing a reference to an int where a reference to a COPYDATASTRUCT is expected.
A C# definition of COPYDATASTRUCT, and an example of sending it with SendMessage(), are available on pinvoke.net:
http://www.pinvoke.net/default.aspx/Structures.COPYDATASTRUCT
[StructLayout(LayoutKind.Sequential)]
struct COPYDATASTRUCT
{
public IntPtr dwData; // Any value the sender chooses. Perhaps its main window handle?
public int cbData; // The count of bytes in the message.
public IntPtr lpData; // The address of the message.
}
const int WM_COPYDATA = 0x004A;
// An example of sending a message containing a txStruct.
public SendMessage()
{
IntPtr buffer = IntPtrAlloc(txStruct);
COPYDATASTRUCT copyData = new COPYDATASTRUCT();
copyData.dwData = IntPtr.Zero;
copyData.lpData = buffer;
copyData.cbData = Marshal.SizeOf(txStruct);
IntPtr copyDataBuff = IntPtrAlloc(copyData);
SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, copyDataBuff);
IntPtrFree(ref copyDataBuff);
IntPtrFree(ref buffer);
}
I wrote this code to test the Inject mouse method but it is not working for me. The test is supposed to click in the google text box search area, but the box never gets highlighted. Any idea why?
Google's page does load. The code runs (confirmed through break points), but nothing happens.
public partial class Form1 : Form
{
private IWebView webView;
public Form1()
{
InitializeComponent();
initiate();
}
private void button1_Click(object sender, EventArgs e)
{
click(650, 405);
}
private async void initiate()
{
WebSession session = WebCore.CreateWebSession(
#"C:\SessionDataPath", WebPreferences.Default);
webView = WebCore.CreateWebView(
this.ClientSize.Width,
this.ClientSize.Height, session, WebViewType.Window
);
webView.ParentWindow = this.Handle;
webView.Source = new Uri("http://www.google.com");
await Task.Delay(30000);
click(650, 405);
}
public void click(int x, int y)
{
webView.InjectMouseMove(x, y);
webView.InjectMouseDown(MouseButton.Left);
webView.InjectMouseUp(MouseButton.Left);
}
}
I tried to get this code to work with chromium handle by looking at the proper chromium class but it didn't work
private async Task<bool> clickCoorindate(Point point)
{
webView.FocusView();
int x = point.X; // X coordinate of the click
int y = point.Y; // Y coordinate of the click
IntPtr handle = webView.ProcessHandle;
StringBuilder className = new StringBuilder(100);
while (className.ToString() != "Chrome_RenderWidgetHostHWND") // The class control for the browser
{
handle = GetWindow(handle, 5); // Get a handle to the child window
GetClassName(handle, className, className.Capacity);
if (className.ToString() == "Chrome_RenderWidgetHostHWND")
handle = Handle;
}
IntPtr lParam = (IntPtr)((y << 16) | x); // The coordinates
IntPtr wParam = IntPtr.Zero; // Additional parameters for the click (e.g. Ctrl)
const uint downCode = 0x201; // Left click down code
const uint upCode = 0x202; // Left click up code
const uint moveCode = 0x200;
SendMessage(handle, downCode, wParam, lParam); // Mouse button down
SendMessage(handle, upCode, wParam, lParam); // Mouse button up
Thread.Sleep(20);
SendMessage(handle, downCode, wParam, lParam); // Mouse button down
SendMessage(handle, upCode, wParam, lParam); // Mouse button up
return true;
}
As mentioned in the documentation (see: WebViewType), a windowed view captures all input itself and you cannot inject input programmatically using Awesomium API (you could do this as you tried, by sending native Windows messages to the appropriate HWND but it's not suggested and straightforward procedure).
To be able to inject input programmatically using the InjectXXX methods, make sure your view is of type offscreen.
in my XNA game i use a lot Awesomium and this is my InputSystem i've implemented in my awesomium component, it works very well.
note that this is just a part of my class, so some methods aren't here but they are not needed to understand the process
basically in my thread. basically i hook to the messages in my form and relay them to the WebView. Hope this helps
public partial class BasicAwesomiumComponent : DrawableGameComponent {
private delegate Int32 ProcessMessagesDelegate(Int32 code, Int32 wParam, ref Message lParam);
private static class User32 {
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr SetWindowsHookEx(Int32 windowsHookId, ProcessMessagesDelegate function, IntPtr mod, Int32 threadId);
[DllImport("user32.dll", SetLastError = true)]
internal static extern Int32 UnhookWindowsHookEx(IntPtr hook);
[DllImport("user32.dll", SetLastError = true)]
internal static extern Int32 CallNextHookEx(IntPtr hook, Int32 code, Int32 wParam, ref Message lParam);
[DllImport("user32.dll", SetLastError = true)]
internal static extern Boolean TranslateMessage(ref Message message);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr FindWindow(String className, String windowName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern int RegisterWindowMessage(String msg);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(HandleRef hWnd, Int32 msg, Int32 wParam, Int32 lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern bool SystemParametersInfo(Int32 nAction, Int32 nParam, ref Int32 value, Int32 ignore);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern int GetSystemMetrics(Int32 nIndex);
}
private static class Kernel32 {
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern Int32 GetCurrentThreadId();
}
private static class SystemMetrics {
internal static Int32 MouseWheelScrollDelta {
get {
return 120;
}
}
internal static Int32 MouseWheelScrollLines {
get {
var scrollLines = 0;
if (User32.GetSystemMetrics(75) == 0) {
var hwnd = User32.FindWindow("MouseZ", "Magellan MSWHEEL");
if (hwnd != IntPtr.Zero) {
var windowMessage = User32.RegisterWindowMessage("MSH_SCROLL_LINES_MSG");
scrollLines = (Int32)User32.SendMessage(new HandleRef(null, hwnd), windowMessage, 0, 0);
if (scrollLines != 0) {
return scrollLines;
}
}
return 3;
}
User32.SystemParametersInfo(104, 0, ref scrollLines, 0);
return scrollLines;
}
}
}
private enum WindowsMessage {
KeyDown = 0x0100,
KeyUp = 0x0101,
Char = 0x0102,
MouseMove = 0x0200,
LeftButtonDown = 0x0201,
LeftButtonUp = 0x0202,
LeftButtonDoubleClick = 0x0203,
RightButtonDown = 0x0204,
RightButtonUp = 0x0205,
RightButtonDoubleClick = 0x0206,
MiddleButtonDown = 0x0207,
MiddleButtonUp = 0x0208,
MiddleButtonDoubleClick = 0x0209,
MouseWheel = 0x020A,
}
private struct Message {
internal IntPtr HWnd;
internal Int32 Msg;
internal IntPtr WParam;
internal IntPtr LParam;
internal IntPtr Result;
}
private IntPtr hookHandle;
private ProcessMessagesDelegate processMessages;
private Int32 ProcessMessages(Int32 code, Int32 wParam, ref Message lParam) {
if (this.Enabled && code == 0 && wParam == 1) {
bool processed = false;
switch ((WindowsMessage)lParam.Msg) {
case WindowsMessage.KeyDown:
case WindowsMessage.KeyUp:
case WindowsMessage.Char:
WebKeyboardEvent keyboardEvent = new WebKeyboardEvent((uint)lParam.Msg, lParam.WParam, lParam.LParam, 0);
awesomiumContext.Post(state => {
if (!WebView.IsLive) return;
WebView.InjectKeyboardEvent(keyboardEvent);
}, null);
processed = true;
break;
case WindowsMessage.MouseWheel:
var delta = (((Int32)lParam.WParam) >> 16);
awesomiumContext.Post(state => {
if (!WebView.IsLive) return;
WebView.InjectMouseWheel(delta / SystemMetrics.MouseWheelScrollDelta * 16 * SystemMetrics.MouseWheelScrollLines, 0);
}, null);
processed = true;
break;
}
if (!processed) {
WindowsMessage message = (WindowsMessage)lParam.Msg;
awesomiumContext.Post(state => {
if (!WebView.IsLive) return;
switch (message) {
case WindowsMessage.MouseMove:
var mouse = Mouse.GetState();
WebView.InjectMouseMove(mouse.X - area.X, mouse.Y - area.Y);
break;
case WindowsMessage.LeftButtonDown:
WebView.InjectMouseDown(MouseButton.Left);
break;
case WindowsMessage.LeftButtonUp:
WebView.InjectMouseUp(MouseButton.Left);
break;
case WindowsMessage.LeftButtonDoubleClick:
WebView.InjectMouseDown(MouseButton.Left);
break;
case WindowsMessage.RightButtonDown:
WebView.InjectMouseDown(MouseButton.Right);
break;
case WindowsMessage.RightButtonUp:
WebView.InjectMouseUp(MouseButton.Right);
break;
case WindowsMessage.RightButtonDoubleClick:
WebView.InjectMouseDown(MouseButton.Right);
break;
case WindowsMessage.MiddleButtonDown:
WebView.InjectMouseDown(MouseButton.Middle);
break;
case WindowsMessage.MiddleButtonUp:
WebView.InjectMouseUp(MouseButton.Middle);
break;
case WindowsMessage.MiddleButtonDoubleClick:
WebView.InjectMouseDown(MouseButton.Middle);
break;
}
}, null);
}
User32.TranslateMessage(ref lParam);
}
return User32.CallNextHookEx(IntPtr.Zero, code, wParam, ref lParam);
}
}
update:
note that in my component, to hook the message pump, i use
int currentThread = Kernel32.GetCurrentThreadId();
// Create the message hook.
hookHandle = User32.SetWindowsHookEx(3, ProcessMessages, IntPtr.Zero, currentThread);
my surface in an Offscreen webview so the more complex, this should work for you too
i posted a separated answer to give another direction:
take a look at this gist: https://gist.github.com/robertkhrona/918109
it seems to suggest to do
webView.InjectMouseMove(x,y);
webView.InjectMouseDown(MouseButton.Left);
webView.InjectMouseMove(x,y);
webView.InjectMouseUp(MouseButton.Left);
so moving (to the same position) between the two mousedown/up event
btw i think this shouldn't be needed tho
which version of awesomium are you running?
update:
Remember to set the focus on your WebView before injecting inputs
webView.Focus();
I set the viewtype to offscreen and the injectclick worked fine, when set to window it doesn't work. I don't know why, but I can work with that.
I am developing an application in c#.net,and for that i am writing code to display icon in a system tray,and whenever a new message arrives the balloon tooltip will be shown there,which has click event which will open new message arrived,everything works fine,but the problem is i am getting multiple numbers of icon generated in system tray,which shuld be only one,how can i prevent it?i found on internet how to dispose them,but couldn't find way to prevent more than one.or is there any better way to show notifications for newly received message..please help me if you know the solution..
There are better custom solutions available see here and here for some examples.
However, System Tray doesn't refresh automatically. If you show/hide multiple system tray icons, it can mess the tray up. Normally all disposed icons will disappear when you mouse hover. However, there is a way to refresh the system tray programmatically. Reference here.
Note : SendMessage function, sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message.
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll")]
public static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
public void RefreshTrayArea()
{
IntPtr systemTrayContainerHandle = FindWindow("Shell_TrayWnd", null);
IntPtr systemTrayHandle = FindWindowEx(systemTrayContainerHandle, IntPtr.Zero, "TrayNotifyWnd", null);
IntPtr sysPagerHandle = FindWindowEx(systemTrayHandle, IntPtr.Zero, "SysPager", null);
IntPtr notificationAreaHandle = FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "Notification Area");
if (notificationAreaHandle == IntPtr.Zero)
{
notificationAreaHandle = FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "User Promoted Notification Area");
IntPtr notifyIconOverflowWindowHandle = FindWindow("NotifyIconOverflowWindow", null);
IntPtr overflowNotificationAreaHandle = FindWindowEx(notifyIconOverflowWindowHandle, IntPtr.Zero, "ToolbarWindow32", "Overflow Notification Area");
RefreshTrayArea(overflowNotificationAreaHandle);
}
RefreshTrayArea(notificationAreaHandle);
}
private static void RefreshTrayArea(IntPtr windowHandle)
{
const uint wmMousemove = 0x0200;
RECT rect;
GetClientRect(windowHandle, out rect);
for (var x = 0; x < rect.right; x += 5)
for (var y = 0; y < rect.bottom; y += 5)
SendMessage(windowHandle, wmMousemove, 0, (y << 16) + x);
}
I'm trying to click a Button in another Application (started from my Programm with Process.Start)
The problem: I need to wait until the Loading screen is disappeared and the GUI pop's up...
My idea was to read all (Hwnd)Controls until a specific Control (Button: "Kill Client") from the GUI was found (=GUI Opened).
But this only works if I wait manually for the GUI and press a "Search Control" button.
If I press the "Search Button" if the Loading Screen is aktive I get a Hwnd = 0 (List<'IntPtr> Count is also 0...) and if i press it again if the GUI is opened it is 0 again(List<'IntPtr> Count too...) !!!
Here my Code:
public class WndSearcher
{
[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);
public static List<IntPtr> GetChildWindows(IntPtr parent)
{
List<IntPtr> result = new List<IntPtr>();
GCHandle listHandle = GCHandle.Alloc(result);
try
{
EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
}
finally
{
if (listHandle.IsAllocated)
listHandle.Free();
}
return result;
}
private static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
GCHandle gch = GCHandle.FromIntPtr(pointer);
List<IntPtr> list = gch.Target as List<IntPtr>;
if (list == null)
{
throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
}
list.Add(handle);
return true;
}
}
My Button:
List<IntPtr> AllControlHandles = WndSearcher.GetChildWindows(selectedCharacter.Botprocess.MainWindowHandle);
IntPtr ControlHandle = AllControlHandles.Find(x => PInvoke.GetWindowTextRaw(x) == "Kill Client" ? true : false);
MessageBox.Show(ControlHandle.ToString());
Part of PInvoke (Class):
const int WM_GETTEXT = 0x000D;
const int WM_GETTEXTLENGTH = 0x000E;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, [Out] StringBuilder lParam);
public static string GetWindowTextRaw(IntPtr hwnd)
{
// Allocate correct string length first
int length = (int)SendMessage(hwnd, WM_GETTEXTLENGTH, IntPtr.Zero, null);
StringBuilder sb = new StringBuilder(length + 1);
SendMessage(hwnd, WM_GETTEXT, (IntPtr)sb.Capacity, sb);
return sb.ToString();
}
Found no solution till now.
So I decided to use AutoHotKey in combination with C#.
In C# I start my AutoHotKey Script and wait until the Script is finished. (Then the external Programm is started completely)
Starting Arguments: 1.Processid 2.NewExternalProgramName
Here my AutoHotKey Script:
counter := 0
Loop, %0% ; For each parameter:
{
param := %A_Index%
if (counter = 0) ; do sth with parameter 1
winwait, ahk_pid %param% ; Not logged in ;wait until the text "Not logged in" can be read (Program started completely)
if (counter = 1) ; do sth with parameter 2
WinSetTitle, %param%
counter += 1
}