Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to draw graphics/text on top of another application

I want to enhance an application, but there is no 3:e party API available. So basically the idea is to draw graphics/text on top of the applications windows.

There are problems with z order, clipping, and directing mouse clicks either to my application or the other application.

What is an elegant way of doing this?

Example image here. It is a trading application where my application wants to add extra information into the trading application's windows. [URL=http://img104.imageshack.us/my.php?image=windowontop.png][/URL]

like image 738
s5804 Avatar asked May 02 '09 21:05

s5804


3 Answers

There are no nice ways to do this, but one approach that may work for you is to hook the application in question using SetWindowsHookEx(...) to add a GetMsgProc, which draws your overlay in response to WM_PAINT messages. The basic idea is that you're drawing YOUR graphics right after the application finishes its own drawing.

In your main app:

....
HMODULE hDllInstance = LoadLibrary("myFavoriteDll");
HOOKPROC pOverlayHook = (HOOKPROC)GetProcAddress(hDllInstance, "OverlayHook");
SetWindowsHookEx(WH_GETMESSAGE, pOverlayHook, hDllInstance, threadId);

Off in a DLL somewhere:

LRESULT CALLBACK OverlayHook(int code, WPARAM wParam, LPARAM lParam)
{
  //Try and be the LAST responder to WM_PAINT messages;
  //Of course, if some other application tries this all bets are off
  LRESULT retCode = CallNextHookEx(NULL, code, wParam, lParam);

  //Per GetMsgProc documentation, don't do anything fancy
  if(code < 0) return retCode;

  //Assumes that target application only draws when WM_PAINT message is
  //removed from input queue.
  if(wParam == PM_NOREMOVE) return retCode;

  MSG* message = (MSG*)lParam;

  //Ignore everything that isn't a paint request
  if(message->message != WM_PAINT) return retCode;

  PAINTSTRUCT psPaint;    

  BeginPaint(message->hwnd, &psPaint);
  //Draw your overlay here
  ...
  EndPaint(message->hwnd, &psPaint);

  return retCode;
}

This is all win32 so your C# code will be p/invoke heavy and correspondingly quite ugly. Your DLL must be unmanaged as well (if you intend to inject into a process other than your own), making this an even nastier solution.

This would solve your issue with z-order and clipping issues, as you're rendering into the window itself. However, if the application you're targeting does any drawing outside of the WinProc responding to WM_PAINT things fall apart; this is not an entirely uncommon occurence.

like image 140
Kevin Montrose Avatar answered Oct 22 '22 19:10

Kevin Montrose


You might want to draw it on top of directX for games

http://spazzarama.com/2011/03/14/c-screen-capture-and-overlays-for-direct3d-9-10-and-11-using-api-hooks/

like image 22
Barsham Avatar answered Oct 22 '22 18:10

Barsham


There are problems with z order, clipping, and directing mouse clicks either to my application or the other application.

These are all tasks that the window manager was designed to deal with. You should create a layered window on top of the apps' windows.

See also: Prevent repainting of window in C++

like image 1
tenfour Avatar answered Oct 22 '22 19:10

tenfour