I'd like to add my custom border rectangle to another application window like this:
I wrote this code by surfing from google but didn't help me:
HWND hWndX;
HRGN hRegX;
HDC hdc;
hWndX = FindWindow(NULL, "Untitled - Notepad");
hdc = GetDC(hWndX);
if (hWndX)
{
hRegX = CreateRectRgn(10, 10, 200, 200);
SetWindowLong(hWndX, GWL_STYLE, GetWindowLong(hWndX, GWL_STYLE));
SetWindowPos(hWndX, hWndX, 0, 0, 100, 100, SWP_FRAMECHANGED);
SetWindowRgn(hWndX, hRegX, true);
}
else
MessageBox(hWndX, "Cant find the window handle", "Error!", 0);
This kind of thing /might/ have worked in the old Win16/Windows 95 era, but these days, the OS protects one program from affecting the other. To change the border of another process, you will need to inject your code (as a dll) into the other process (assuming you have the correct security level). It's not that it is impossible, but it's not the sort of thing a beginner coder would be able to do.
Related
Would like to have some insights on how can one wpf application activate another running application and send text messages.
Thank you all for the responses.
In fact I was successful in pointing an answer for self. PFB the steps.
To communicate between two WPF apps without any service connectivity I made use of ClipBoard facility available in Windows
The first WPF app will insert the value which needs to be passed in ClipBoard as below and later will activate the other WPF app who is running in the tray..
Process[] pname = Process.GetProcessesByName("APPNAME");
Clipboard.SetText("TEXT TO BE PASSED");
//Activation
Process[] processes = Process.GetProcessesByName(proc);
if (pname.Length != 0)
{
IntPtr hWnd = processes[0].MainWindowHandle;
SetForegroundWindow(hWnd);
SetWindowPos(p.MainWindowHandle, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
}
Later in the activated app..through the activated method we could read the value as below
string clipboardText = System.Windows.Clipboard.GetText();
and then clear the clip
System.Windows.Clipboard.Clear();
Hopefully this will help someone. Thanks a lot.
WINAPI: I have a simple Win32 application and an OpenGL context.
CAUSE) If I do CTRL-ALT-DELETE and click task manager ...
EFFECT) the application window is black until it is resized. OpenGL will not render.
With a great deal of experimentation, I have largely overcome this huge annoyance ...
Unlikable partial solution --- I cheat resizing the window with no redraw as such, "mostly" tricking Windows
Code:
case WM_SYNCPAINT:
SetWindowPos (hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOOWNERZORDER |
SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE | SWP_HIDEWINDOW);
RedrawWindow (hwnd, NULL, 0, RDW_NOERASE );
SetWindowPos (hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOOWNERZORDER |
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW );
break;
D) However, it is still a suboptimal solution with some minor side effects.
QUESTION 1: Why is my OpenGL getting killed, recreating the context doesn't even work.
QUESTION 2: There has to be a real way to solve this problem without hiding the window and showing it again which causes some repainting side-effects ... does anyone have a solution.
Although not directly related, SDL2 has this problem as well and I often cross-check against their code for winapi messaging/drawing issues like this and their codebase doesn't have a solution and I see this issue posted around the internet for other things like Glut and such. This seems to be a problem that rears its ugly head even in common OpenGL toolkits and such.
Snoop, the spy utility, uses some powerful technique (probably some sort of reflection) to inspect a running WPF application. Most interesting is the fact, that Snnop is able to readout the entire object structure.
A few days ago I downloaded the Snoop source code and spent some time on studying the internal behavior. Unfortunately, I couldn't find out yet how Snoop is doing these things, so I hope that anybody can help me out.
At work I am currently writing a Coded UI Testing-Framework and it would be fantastic if I had access to the application's object structures because this would allow me to not only assert the UI state.
UPDATE:
This is the code needed:
string filePath = "WpfApp.exe";
AppDomain appDomain = AppDomain.CurrentDomain;
byte[] bytes = System.IO.File.ReadAllBytes(filePath);
Assembly ass = appDomain.Load(bytes);
ass.EntryPoint.Invoke(null, new object[] { });
IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;
Window w = System.Windows.Interop.HwndSource.FromHwnd(handle).RootVisual as Window;
This is already a big help for me, but it is also interesting to find out, how Snoop injects itself into another process.
You can accomplish what Snoop does by using the WPF VisualTreeHelper and/or the LogicalTreeHelper. Once you get a hold of any visual element, you can pretty much traverse its entire visual tree to see all the elements it contains. Visual tree helper here
So in your UI test, grab the main window and traverse its visual tree to find any element you want and then perform any validations or operations you want on that element.
Furthermore, you may be able to use System.Diagnostics.Process.MainWindowHandle to get the windows handle from an existing process and then use the window's handle to create a wpf window. Its been a while so I dont remember the specifics without doing more research. The code below may help:
Window window = (Window)System.Windows.Interop.HwndSource.FromHwnd(process.MainWindowHandle).RootVisual;
UPDATE:
Okay, I found the basic code location, that is used by Snoop to provide the injection ability. To my astonishment that code is written C++/CLI. Probably there is a reason for.
And that is the code (I hope that it is okay to post it here):
//-----------------------------------------------------------------------------
//Spying Process functions follow
//-----------------------------------------------------------------------------
void Injector::Launch(System::IntPtr windowHandle, System::String^ assembly, System::String^ className, System::String^ methodName)
{
System::String^ assemblyClassAndMethod = assembly + "$" + className + "$" + methodName;
pin_ptr<const wchar_t> acmLocal = PtrToStringChars(assemblyClassAndMethod);
HINSTANCE hinstDLL;
if (::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)&MessageHookProc, &hinstDLL))
{
LogMessage("GetModuleHandleEx successful", true);
DWORD processID = 0;
DWORD threadID = ::GetWindowThreadProcessId((HWND)windowHandle.ToPointer(), &processID);
if (processID)
{
LogMessage("Got process id", true);
HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
if (hProcess)
{
LogMessage("Got process handle", true);
int buffLen = (assemblyClassAndMethod->Length + 1) * sizeof(wchar_t);
void* acmRemote = ::VirtualAllocEx(hProcess, NULL, buffLen, MEM_COMMIT, PAGE_READWRITE);
if (acmRemote)
{
LogMessage("VirtualAllocEx successful", true);
::WriteProcessMemory(hProcess, acmRemote, acmLocal, buffLen, NULL);
_messageHookHandle = ::SetWindowsHookEx(WH_CALLWNDPROC, &MessageHookProc, hinstDLL, threadID);
if (_messageHookHandle)
{
LogMessage("SetWindowsHookEx successful", true);
::SendMessage((HWND)windowHandle.ToPointer(), WM_GOBABYGO, (WPARAM)acmRemote, 0);
::UnhookWindowsHookEx(_messageHookHandle);
}
::VirtualFreeEx(hProcess, acmRemote, 0, MEM_RELEASE);
}
::CloseHandle(hProcess);
}
}
::FreeLibrary(hinstDLL);
}
}
Snoop doesn't inspect a WPF from the outside. It injects itself into the application and actually adds the magnify or snoop window to it. Thats also why when you exit snoop the inspection windows actually stay open.
So the 'inspection' code simply inspects the window it wants and it can use all avaible WPF functions to do so. Like the VisualTreeHelper and LogicalTreeHelper as mentioned here earlier.
For a small test framework i build i injected code to add a small proxy object so i can control the application easily (press buttons, change values, execute functions on viewmodels etc).
The answer above doesn't work for me. It seems a bit vague. I expanded on accepted answer a little with this code:
var allProcesses = Process.GetProcesses();
var filteredProcess = allProcesses.Where(p => p.ProcessName.Contains(ProcessSearchText)).First();
var windowHandle = filteredProcess.MainWindowHandle;
var hwndSource = HwndSource.FromHwnd(windowHandle);
This answer seems more complete and will work for others if the accepted answer works for anyone. However, this the last line of this code returns null for me.
I'm trying to use the following code to press a button on my other application:
HWND ButtonHandle;
if( (wnd = FindWindow(0, "Do you want to save?")) )
{
ButtonHandle = FindWindowEx(wnd, 0, "SaveButton", "&Save");
SendMessage(wnd, WM_COMMAND, MAKEWORD(GetDlgCtrlID(ButtonHandle), BN_CLICKED ), (LPARAM)ButtonHandle);
}
It doesn't work. I tried passing different handles to MAKEWORD and to change the WPARM and LPARAM but nothing.
Any ideas on how to click a button on another application's window?
Code is appreciated.
Thanks.
EDIT:
The reason it doesn't seem to work permissions. I sent a PostMessage() and the result was an error with GetLastError() = 5 (or Access Denied).
Any ideas?
EDIT2 I don't mean to be rude but please please please, I already searched all the API's including getting and setting the regions for the button and then sending a button down and button up, getting the control ID, getting the class ID and a zillion more.
The reason I asked the question here in the first place is because I already exhausted my search on the internet.
If you know the answer PLEASE POST CODE, do not suggest an API and that's it, show me how does that API solves the problem. It's not hard.
thank you.
EDIT 3: The question's answer was selected automatically when the bounty finished. The question still remains without an answer.
Are you sure that "SaveButton" class name is valid? Do you get the button
handle?
Try to send messages to ButtonHandle window (directly to the button).
Update: I believe this should work,
SendMessage(ButtonHandle, BM_CLICK, 0, 0);
See the following solution, also you can use
SendMessage(ButtonHandle, WM_LBUTTONDOWN, 0, 0);
SendMessage(ButtonHandle, WM_LBUTTONUP, 0, 0);
Or
SendMessage(ButtonHandle, BM_CLICK, 0, 0);
HWND buttonHandle = 0;
BOOL CALLBACK GetButtonHandle(HWND handle, LPARAM)
{
char label[100];
int size = GetWindowTextA(handle,label,sizeof(label));
if(strcmp(label,"&Save") == 0)
{
buttonHandle = handle;
return false;
}
return true;
}
void main()
{
HWND windowHandle = FindWindowA(NULL,"Do you want to Save?");
if(windowHandle != 0)
{
BOOL ret = EnumChildWindows(windowHandle,GetButtonHandle,0);
if(buttonHandle != 0)
{
LRESULT res = SendMessage(buttonHandle,BM_CLICK,0,0);
//SendMessage(buttonHandle,WM_LBUTTONDOWN,0,0);
//SendMessage(buttonHandle,WM_LBUTTONUP,0,0);
}
}
}
Note:
Getting sure from the window text,button text (check if there is space at the end of the window title)
SendMessage(btnHandle, WM_LBUTTONDOWN, 0, 0);
SendMessage(btnHandle, WM_LBUTTONUP, 0, 0);
SendMessage(btnHandle, WM_LBUTTONDOWN, 0, 0);
SendMessage(btnHandle, WM_LBUTTONUP, 0, 0);
You have to send a button click twice. Not sure why (maybe the first click only activates the window of the button), but I'm using this code for a long time and it always worked for me.
maybe this can help:
http://www.cplusplus.com/forum/beginner/8806/
Access Denied errors on SendMessage or PostMessage make no sense unless the process sending the message is running at a lower integrity level than the target process.
This should not be happening unless the process that owns the target window is being run "asAdministrator" or is a service. And its damn hard for services to create windows on the interactive desktop with Windows 6 and up.
You can do some reading about Integrity Levels Here if they apply even remotely to this situation. Internet Explorer is about the only other application that 'opts in' to the integrity security model by purposely lowering the integrity level of itself in order to sandbox itself more effectively.
If you can raise the window containing the button you can send raw mouse event to a position within the boundaries of button.
There are two function to simulate mouse event SendInput and mouse_event. I recommend using mouse_event function. To raise a window you can use ShowWindow. I don't know how to get the handle of a button, but if you have its hWnd its easy to find its absolute position using GetWindowRect function. Try using these, if you run into any problems I will be glad to help.
Or define a custom WM within your application window to handle save request. WM_CUSTOM or WM_USER (cant remember which) marks the start of user defined window messages.
When I have to do these kind of things I use SendKeys. It is VB-ish and C# provides a nice interface to use but for C/C++ you'll have to do it <this way>. What is nice with it is that you could write scripts and run them instead of hard coding it in your code.
Microsoft is now pushing Active Accessibility (MSAA) for UI Automation,
(It has been renamed a number of times over the years)
see
UI Automation and Microsoft Active Accessibility
Using UI Automation for Automated Testing
UI Automation Clients for Managed Code
Sorry I don’t have any simple code to get you started. As “SendMessage()” does not seem to be working for you, I don’t know of another option apart from “UI Automation”
I am assuming you have check with Spy++ (installed with MsDev) that you message are being send to the correct button etc – and that the button is a standard windows buttons. My first instant would say use “SendMessage()" or "PostMessage()” but given the numbers of answers about “SendMessage()” and the fact it is not working for you. I expect someone is going on…
//Send digit 4 to the already opened calc.exe
HWND windowHandle;
windowHandle = FindWindowA(NULL,"Calculator");
if(windowHandle != 0)
ret = EnumChildWindows(windowHandle,GetButtonHandle,0);
BOOL CALLBACK GetButtonHandle(HWND handle, LPARAM)
{
char label[100];
int size = GetWindowTextA(handle,label,sizeof(label));
if(strcmp(label,"4") == 0)
{
PostMessage(handle ,WM_LBUTTONDOWN,(WPARAM)0x0001,0);
PostMessage(handle ,WM_LBUTTONUP,(WPARAM)0x0001,0);
PostMessage(handle ,WM_LBUTTONDOWN,(WPARAM)0x0001,0);
PostMessage(handle ,WM_LBUTTONUP,(WPARAM)0x0001,0);
return false;
}
return true;
}
You can use sendkeys (as tr3 said) to send mouse clicks, which is different than using SendMessage. It is also less direct and more hack-ish, but is useful for automation (in VBS).
Also, just a guess but the problem could be that your message handling is broken somewhere by not calling the base class member. Example:
void CMyClass::OnMessageY(CWnd *cwnd)
{
CBaseClass::OnMessageY(cwnd);
//... my code
}
if you sure ButtonHandle are valid handle you can use pair WM_LBUTTONDOWN and WM_LBUTTONUP message instead of BN_CLICKED
HWND ButtonHandle;
if( (wnd = FindWindow(0, "Do you want to save?")) )
{
SendMessage(ButtonHandle, WM_LBUTTONDOWN, MK_LBUTTON, 0);
SendMessage(ButtonHandle, WM_LBUTTONUP, MK_LBUTTON, 0);
}
A non-C approach: Use Java and the java.awt.Robot class to move the mouse around perform real clicks (I guess there is something in the Windows World for this, too).
Problem: You have to know where your button is :D
I'm currently trying to integrate some animation drawing code of mine into a third party application, under the form of an external plugin.
This animation code in realtime 3d, based on OpenGL, and is supposed to render as fast as it can, usually at 60 frames per second.
In my base application, where I'm the king of the world, I control the application message pump, so that drawing occurs whenever possible. Like that :
for (;;)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
do
{
if (msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE));
}
draw();
}
Now that I'm no more king in the world, I have to play nice with the application messages, so that it keeps being responsive. To my knowledge, as I'm a plugin, I can't hijack the whole application message pump ; so I tried various things, doing my drawing in WM_PAINT message handler :
Use WM_TIMER, which doesn't work :I don't know in advance which time step I need (often not fixed) and the timing in not accurate.
Call InvalidateRect as soon as I'm done drawing, doesn't work : completely prevents the rest of the application of being responsive and doing its own refreshing.
Create a 'worker' thread, whose only job is to post a user message to the plugin window. This message is posted as soon as the drawing is finished (signaled by an event). The user message handler, in turn, calls InvalidateRect (see there).
So far, my last attempt is the better, and sometimes work fine.
DWORD WINAPI PaintCommandThreadProc(LPVOID lpParameter)
{
Plugin* plugin = static_cast<Plugin*>(lpParameter);
HANDLE updateEvent = plugin->updateEvent();
while (updateEvent == plugin->updateEvent())
{
::WaitForSingleObject(updateEvent, 100);
::Sleep(0);
if (updateEvent == plugin->updateEvent())
{
::PostMessage(plugin->hwnd(), WM_USER+0x10, 0, 0);
}
}
return 0;
}
...
LRESULT CALLBACK PluginWinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
bool processDefault = true;
LRESULT result = 0;
Plugin* plugin = reinterpret_cast<Plugin*>( GetWindowLong(hWnd, GWL_USERDATA) );
switch (msg) {
...
case WM_GL_MESSAGE:
{
::InvalidateRect( hWnd, NULL, FALSE );
processDefault = false;
result = TRUE;
}
break;
case WM_PAINT:
{
draw(hWnd);
::SetEvent( plugin->updateEvent() );
processDefault = false;
result = TRUE;
}
break;
...
}
if (processDefault && plugin && plugin->m_wndOldProc)
result = ::CallWindowProc(plugin->m_wndOldProc, hWnd, msg, wParam, lParam);
return result;
}
On some occasions, the host application still seems to miss messages. The main characteristics of the problem are that I have to press the 'Alt' key for modal dialogs to show up ; and I have to move the mouse to give some processing time to the host application !...
Is there any 'industry standard' solution for this kind of as-often-as-you-can animation repaint problem ?
Each thread has its own message queue, and messages sent to a window arrive in the queue of the thread that created the window. If you create your plugin window yourself, you can create it in a separate thread, and that way you will have complete control over its message pump.
An alternative solution (which imho is better), is to only have OpenGL rendering in a separate thread. All OpenGL calls must occur in the thread that created the OpenGL context. However, you can create a window in one thread (your application main thread), but create the OpenGL context in another thread. That way the original application message pumps stays intact, and in your rendering thread you can loop forever doing rendering (with calls to SwapBuffers to vsync).
The main problem with that second solution is that communication between the plugin WindowProc and the rendering loop must take into account threading (ie. use locks when accessing shared memory). However since the message pump is separate from rendering, it can be simultaneous, and your message handling is as responsive as it can get.