Capturer le contenu d'une fenetre - Win32

Capturer le contenu d'une fenetre - Win32 - C++ - Programmation

Marsh Posté le 08-08-2005 à 23:27:24    

je cherche a capturer le contenu d'une fenetre de n'importe quelle application meme si celle si est cachée ou partiellement recouverte
 
j'ai deja essaye plusieurs pistes ....

Code :
  1. Bitblt(getDC(0),....) => ne fonctionne pa si la fenetre est recouverte ou cachee
  2. PrintWindow => impeccable, juste ce qu'il me faut .... sauf que cette fct n'est disponible que sous WinXP et Win Server 2003 :(
  3. SendMessage(hwnd,WM_PRINT,hdc,.....) (sense etre lequivalent du PrintWindow sous 2000) => je n'ai jamais reussi a obtenir un resultat correct, cela me donne un rectangle noir a chaque fois :S


 Winplosion le fait sans prob que se soit sous xp ou 2000 :o


Message édité par red faction le 09-08-2005 à 17:00:15
Reply

Marsh Posté le 08-08-2005 à 23:27:24   

Reply

Marsh Posté le 09-08-2005 à 10:18:20    

C'est assez coton, mais y'a un bon article sur le sujet:
http://www.fengyuan.com/article/wmprint.html


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 09-08-2005 à 17:05:35    

oui, je connais cet article mais cela fonctionne uniquement lorsque que c l'appli elle meme qui lance le WM_PRINT
 
javai essaye ceci mais sans succes  
 

Code :
  1. void PrintWindow(HWND hWnd)
  2. {
  3.     HDC hDCMem = CreateCompatibleDC(NULL);
  4.     RECT rect;
  5.     GetWindowRect(hWnd, & rect);
  6.     HBITMAP hBmp = NULL;
  7.     {
  8.         HDC hDC = GetDC(hWnd);
  9.         hBmp = CreateCompatibleBitmap(hDC, rect.right - rect.left, rect.bottom - rect.top);
  10.         ReleaseDC(hWnd, hDC);
  11.     }
  12.     HGDIOBJ hOld = SelectObject(hDCMem, hBmp);
  13.     SendMessage(hWnd, WM_PRINT, (WPARAM) hDCMem, PRF_CHILDREN | PRF_CLIENT | PRF_ERASEBKGND | PRF_NONCLIENT | PRF_OWNED);
  14.     SelectObject(hDCMem, hOld);
  15.     DeleteObject(hDCMem);
  16.     OpenClipboard(hWnd);
  17.     EmptyClipboard();
  18.     SetClipboardData(CF_BITMAP, hBmp);
  19.     CloseClipboard();
  20. }


 
en passant PrintWindow(FindWindow(NULL,"WM_PRINT" ));
avec leur prog (ou nimporte quel autre dailleur), ca ne fonctionne jamais :( (teste sous WinXP SP2)
 
qd je paste le bitmap jobtient un rectangle noir  [:red faction]

Reply

Marsh Posté le 10-08-2005 à 13:52:25    

C'est loin d'être aussi simple. Tu peux pas filer un HDC comme ça. C'est un objet GDI, et les objets GDI sont spécifiques à chaque process, ne sont pas partageables.
Selon ton approche, tu peux pas aller plus loin que blitter la fenêtre dans ton HDC, mais si elle est cachee, t'auras pas son contenu.
Relis bien l'article, plusieurs fois, car c'est de la haute voltige. Y'a du subclassing et du thunking.


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 10-08-2005 à 14:32:58    

la seule chose que je fourni ici c le handle de la fenetre et non un hdc
lexemple repris ici (void PrintWindow...) proviens du site jai juste fait un copier-coller
 
qd a leur histoire d'injection de code c uniquement si la fenetre nest pa capable de traiter ce genre de message hors ici l'utilitaire fourni sur le site le fait  
 
ou alors jai rien compris a ce que tu viens de me dire


Message édité par red faction le 10-08-2005 à 14:34:43
Reply

Marsh Posté le 10-08-2005 à 17:44:17    

Code :
  1. SendMessage(hWnd, WM_PRINT, (WPARAM) hDCMem


hDCMem, c'est un HDC.
L'utilitaire fournit sur le site ne traite pas WM_PRINT.


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 10-08-2005 à 21:40:03    

edit : reflexion en cours   :whistle:


Message édité par red faction le 10-08-2005 à 21:42:30
Reply

Marsh Posté le 11-08-2005 à 04:52:16    

Code :
  1. #include <windows.h>
  2. /*  Declare Windows procedure  */
  3. LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
  4. void ImportDialog(HWND parent, HWND child)
  5. {
  6. int width, heigth;
  7. RECT r;
  8. GetWindowRect(parent, &r);
  9. width = r.right - r.left;
  10. heigth = r.bottom - r.top;   
  11. MoveWindow(parent, 0, GetSystemMetrics(SM_CYCAPTION), width, heigth, 0);   
  12. SetWindowPos(child, 0, 100, 100, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
  13. LONG OldParent = GetWindowLong(child, GWL_HWNDPARENT);
  14. SetParent(child, parent);
  15. }
  16. void ExportDialog(HWND parent, HWND child)
  17. {
  18. SetParent(child, parent);   
  19. }
  20. /*  Make the class name into a global variable  */
  21. char szClassName[ ] = "WindowsApp";
  22. int WINAPI WinMain (HINSTANCE hThisInstance,
  23.                     HINSTANCE hPrevInstance,
  24.                     LPSTR lpszArgument,
  25.                     int nFunsterStil)
  26. {
  27.     HWND hwnd;               /* This is the handle for our window */
  28.     MSG messages;            /* Here messages to the application are saved */
  29.     WNDCLASSEX wincl;        /* Data structure for the windowclass */
  30.     /* The Window structure */
  31.     wincl.hInstance = hThisInstance;
  32.     wincl.lpszClassName = szClassName;
  33.     wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
  34.     wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
  35.     wincl.cbSize = sizeof (WNDCLASSEX);
  36.     /* Use default icon and mouse-pointer */
  37.     wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
  38.     wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
  39.     wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
  40.     wincl.lpszMenuName = NULL;                 /* No menu */
  41.     wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
  42.     wincl.cbWndExtra = 0;                      /* structure or the window instance */
  43.     /* Use Windows's default color as the background of the window */
  44.     wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
  45.     /* Register the window class, and if it fails quit the program */
  46.     if (!RegisterClassEx (&wincl))
  47.         return 0;
  48.     /* The class is registered, let's create the program*/
  49.     hwnd = CreateWindowEx (
  50.            0,                   /* Extended possibilites for variation */
  51.            szClassName,         /* Classname */
  52.            "Windows App",       /* Title Text */
  53.            WS_OVERLAPPEDWINDOW, /* default window */
  54.            CW_USEDEFAULT,       /* Windows decides the position */
  55.            CW_USEDEFAULT,       /* where the window ends up on the screen */
  56.            1024,                 /* The programs width */
  57.            768,                 /* and height in pixels */
  58.            HWND_DESKTOP,        /* The window is a child-window to desktop */
  59.            NULL,                /* No menu */
  60.            hThisInstance,       /* Program Instance handler */
  61.            NULL                 /* No Window Creation data */
  62.            );
  63.     /* Make the window visible on the screen */
  64.     ShowWindow (hwnd, nFunsterStil);
  65.     HWND child = FindWindow("{E7076D1C-A7BF-4f39-B771-BCBE88F2A2A8}", "foobar2000 v0.9 beta 5" );
  66.     if (child != NULL)
  67.         ImportDialog(hwnd, child);
  68.     else
  69.         MessageBox(hwnd, "Can't find foobar2000 v0.9 beta5 :(", "Error !", MB_OK);
  70.     /* Run the message loop. It will run until GetMessage() returns 0 */
  71.     while (GetMessage (&messages, NULL, 0, 0))
  72.     {
  73.         /* Translate virtual-key messages into character messages */
  74.         TranslateMessage(&messages);
  75.         /* Send message to WindowProcedure */
  76.         DispatchMessage(&messages);
  77.     }
  78.     /* The program return-value is 0 - The value that PostQuitMessage() gave */
  79.     return messages.wParam;
  80. }
  81. /*  This function is called by the Windows function DispatchMessage()  */
  82. LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  83. {
  84.     switch (message)                  /* handle the messages */
  85.     {
  86.         case WM_DESTROY:
  87.             PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
  88.             break;
  89.         default:                      /* for messages that we don't deal with */
  90.             return DefWindowProc (hwnd, message, wParam, lParam);
  91.     }
  92.     return 0;
  93. }


 
Il y a un petit problème de rafraichissement, mais bon, la flemme de corriger (go to WM_PAINT  :p )

Reply

Marsh Posté le 11-08-2005 à 22:09:48    

ok merci beacoup jvais regarder a ca  :)


Message édité par red faction le 11-08-2005 à 22:14:44
Reply

Marsh Posté le 12-08-2005 à 10:33:09    

Personnelement je vois pas trop le rapport...


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 12-08-2005 à 10:33:09   

Reply

Marsh Posté le 12-08-2005 à 11:49:55    

Le mot capturer à deux sens d'un point de vue gestion des fenêtres sous windows, j'ai pris l'une des deux, la mauvaise apparamment.  :ange:


Message édité par karlkox le 12-08-2005 à 12:06:27
Reply

Marsh Posté le 12-08-2005 à 13:50:28    

Ah ok.


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 12-08-2005 à 19:25:40    

me suis demandé si tu t'etais pa trompé de topic au début , puis bon jme suis dit que le fait de changer le parent d'une fenetre permeterait peut etre de la capturer apres :sarcastic:


Message édité par red faction le 17-08-2005 à 23:00:34
Reply

Marsh Posté le 12-08-2005 à 20:58:45    

J'ai lu en diagonal et j'avais la tête dans le c.. (cf l'heure du post), je vais voir si je peut trouver un début de solution pour me rattraper  :ange:

Reply

Marsh Posté le 17-08-2005 à 22:25:21    

Y'a un projet qui a l'air abandonné qui peut faire ça :
 
http://expire.free.fr/board/index. [...] wtopic=114
 
( demo video là : http://www.logiccubed.com/cgi-bin/ [...] 1100311193 )
 
Le code permet de récupérer directement la zone memoire utilisé pour le dessin des fenetres.
Je n'ai testé que sous XP, ça fonctionne bien mais le code semble spécifique à la machine ( faut executé un prog : infofetch.exe qui crée un fichier contenant des infos graphiques pour l'execution )
L'exemple fournit est tres simple.

Reply

Marsh Posté le 18-08-2005 à 09:49:17    

En plus simple y'a la fonction PrintWindow.
Mais c'est dispo qu'à partir de XP...


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 18-08-2005 à 09:56:02    

D'ailleurs il en parle dans son Readme dans le lien que tu donnes, et dit qu'il s'est mis en tête de la coder sous Win2K.
Son soft c'est l'artillerie lourde : il a codé un driver.  
J'avais lu des dissussions sur la théorie, mais je conaissais pas de soft non comercial qui l'ai mise en pratique. C'est beaucoup de courage :jap:
Dommage qu'il donne pas le code source :/


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 18-08-2005 à 22:12:19    

J'ai commencé à faire un truc mais par manque de temps, je vous propose cette idée qui me parait assez simple en fait : chercher l'appli que l'on souhaite screenshoter (FindWindow), faire une capture du bureau, récupérer sa position (GetWindowRect), le mettre en avant plan (j'ai une fonction à vous proposer si vous voulez) et recadrer l'image du bureau suivant les positions précédemment récupérées. (BitBlt)


Message édité par karlkox le 18-08-2005 à 22:13:06
Reply

Marsh Posté le 18-08-2005 à 23:28:16    

Tu peux par cette même méthode faire une screenshot de la fenêtre voulue uniquement (le bureau est une fenêtre en fait).
Le problème ici c'est d'arriver à capturer le contenu d'une fenêtre partiellement / totalement cachée...

Reply

Marsh Posté le 18-08-2005 à 23:51:06    

Bah, c'est ce que j'ai tenté d'expliquer : tu fais un screenshot du bureau (oui, je sais que le bureau est une fenêtre) mais en ayant mis en avant plan la fenêtre de l'application que tu souhaites screenshoter, donc la, tu as une image de ton bureau avec la fenêtre en avant plan.
Si ton bureau est en 1024x768 et que la position de la fenêtre que tu as mis en avant plan est à 500, 80, il suffit de créér une deuxième image en ne blittant que la portion de cette fenêtre d'où l'utilité de préalablement récupérer la position de la fenêtre.
Si c'est pas clair la [:airforceone]


Message édité par karlkox le 19-08-2005 à 09:07:11
Reply

Marsh Posté le 19-08-2005 à 00:34:03    

moi jai tjs rien compris :D

Reply

Marsh Posté le 19-08-2005 à 09:09:12    

[:bertie wooster]

Reply

Marsh Posté le 19-08-2005 à 09:40:32    

Citation :

ayant mis en avant plan la fenêtre de l'application que tu souhaites screenshoter


sauf que sa question c'est comment le faire sans mettre en avant plan.
Sinon c'est beaucoup plus simple. Pas besoin de prendre le bureau en screenshot, tu blit le DC de la fenêtre directement, de la même manière que tu blit le DC du bureau.


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 19-08-2005 à 11:03:50    

J'ai relu toute la discussion et je ne vois nul part red faction disant qu'il veut le faire sans mettre la fenêtre en avant plan, il a juste dit toutes les fenêtres, même lorsqu'elles sont en arrière plan, rien ne nous empêche d'utiliser l'avant plan pour récupérer la fenêtre.
Bref, je vais voire s'il est possible de le faire comme tu l'as compris :)

Reply

Marsh Posté le 19-08-2005 à 14:27:42    

Moui, c'est vrai, il suffit de mettre au premier plan.
Pour le "comme j'ai dit", c'est simplement comme tu l'a dit, mais en utilisant le HDC de la fenêtre (GetWindowDC(hWnd)) au lieu du bureau (GetDC(NULL)).
Tant qu'on y est, pour les fenêtres video etc... :
http://www.codeproject.com/dialog/screencap.asp


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 20-08-2005 à 00:18:54    

bon jvous montre qd mm a quoi ca va servir
 
http://membres.lycos.fr/manga4free/test.jpg
 
l'idée c de remplacer le alt-tab actuel par une version 3d
le screenshot quon voit ici ne correspond pas vraiment au programme,dans la version actuelle les fenetre rangees les une derriere les autres, ici juste un screen shot fait lors d'un test   :o  

Reply

Marsh Posté le 03-09-2005 à 19:47:58    

bon apparament ya pa vraiment moyen de faire qqch
 
soit lorsque je veux afficher tout les fenetre je les passe en avant plan (vu que yen a une vingtaine + certaines cachees bonjour leffet tout pourri)
 
ou alors je stoque chaque nouvelle fenetre ouverte dans un bitmap lorsque lutilisateur louvre la premiere fois (nivo ram ca risque detre drole)

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed