Encapsuler une fenêtre windows

jdex Messages postés 11 Date d'inscription jeudi 2 octobre 2008 Statut Membre Dernière intervention 9 décembre 2008 - 1 déc. 2008 à 11:50
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 - 23 déc. 2008 à 15:12
Bonjour à tous!

Je souhaiterais comme le titre l'indique, encapsuler une fenêtre windows dans mon interface GTK+. Je voulais savoir si cela était possible ? En utilisant par exemple , SetParent() ou d'autres fonctions de l'API Win32. Je suis débutant en la matière...

Merci d'avance pour vos réponse.

13 réponses

cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
1 déc. 2008 à 12:44
Salut,

Tu peux spécifier la parent dans CreateWindow, pas besoin de SetParent.

Quant à savoir si cela fonctionnera dans du GTK+, c'est une autre histoire...
0
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
1 déc. 2008 à 12:45
Ah pardon, c'est peut être pas toi qui l'a crée la fenêtre.
0
jdex Messages postés 11 Date d'inscription jeudi 2 octobre 2008 Statut Membre Dernière intervention 9 décembre 2008
1 déc. 2008 à 14:12
Quelle réactivité !   Alors en fait, je lance un programme à partir de mon interface, par un CreateProcess(). Celui ci m'affiche une fenêtre une fenêtre toute conne avec simplement une image dedans. J'aimerais la coller dans un GtkScrolledWindow.
0
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
1 déc. 2008 à 20:46
Quelques éssais sur le sujet. Après l'exécutable encapsulé est plus ou moins consentant... Ici je tente d'encapsuler la calculatrice. Elle a la facheuse tendance à s'afficher même démarrée en SW_HIDE. Le premier refresh n'est aussi pas très propre... Sortir la fenêtre de l'écran pour la forcer à se redessiner. Notepad et mspaint donne de bons résultats.

Attention : risque de boucle infini lors de recherche de la fenêtre de l'application lancée. Déjà, ajouter un test WaitForSingleObject (De 0) sur le processus peut bien limiter les risques (Sortie de boucle si le processus crève).

Application complète, unicode ou non, compilation testée sous VC6 et gcc (Code::Blocks).
<hr size="2" width="100%" />#define UNICODE

/*
Pour compiler sous gcc en release, ajouter :
-nostartfiles -nodefaultlibs -nostdlib
dans les options du lieur.
*/

/* Suppression de la CRT sous VC */
#ifdef NDEBUG
#pragma comment(linker, "/NODEFAULTLIB")
#endif

/* Gestion de la compilation en unicode */
#ifdef UNICODE

#define _T(x) L ## x
typedef unsigned short TCHAR;

#else

#define _T(x) x
typedef char TCHAR;

#endif

#include "windows.h"

HINSTANCE _hThisInstance;                  /* Handle du module                */
HWND _hWnd;                                /* Handle de la fenêtre            */
HWND _hCalcHwnd;                           /* Handle de la fenêtre de calc    */
DWORD _nCalcPid;                           /* PID de la calculatrice          */
TCHAR* _lpAppName = _T("Embedded calc");   /* Nom de l'appli                  */

/**
 * Affiche le message d'erreur associé à la dernière erreur Win32
 *
 * @return Le code de la dernière erreur
 */
DWORD __stdcall ShowLastError()
{
  DWORD nLastError;           /* Code de la dernière erreur                   */
  TCHAR* lpMessageBuffer;     /* Message d'erreur associé                     */

  /* Récupération du numéro de l'erreur */
  nLastError = GetLastError();

  /* Formatage du message */
  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                NULL, nLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                (LPTSTR) &lpMessageBuffer, 0, NULL);

  /* Affichage du message */
  MessageBox(NULL, lpMessageBuffer, _T("ERROR"), MB_OK | MB_ICONERROR);

  return nLastError;
}

/**
 * Traitement des messages
 */
LRESULT __stdcall WindowProcedure(HWND hWnd, UINT nMessage,
                                  WPARAM wParam, LPARAM lParam)
{
  switch (nMessage)
  {
    case WM_DESTROY:
      /* On signale que le thread va s'arrêter */
      PostQuitMessage(0);
      break;
    default:
      /* Application du traitement par défaut */
      return DefWindowProc(hWnd, nMessage, wParam, lParam);
  }
  return 0;
}

/**
 * Initialise la fenêtre principale de l'appli
 */
void __stdcall InitWindow()
{
  WNDCLASSEX wincl;       /* Classe de la fenêtre utilisée                    */

  /* Création de la classe de fenêtre */
  wincl.cbSize = sizeof(WNDCLASSEX);
  wincl.style = 0;
  wincl.lpfnWndProc = WindowProcedure;
  wincl.cbClsExtra = 0;
  wincl.cbWndExtra = 0;
  wincl.hInstance = _hThisInstance;
  wincl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  wincl.hCursor = LoadCursor(NULL, IDC_ARROW);
  wincl.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
  wincl.lpszMenuName = NULL;
  wincl.lpszClassName = _lpAppName;
  wincl.hIconSm = NULL;

  /* Enregistrement de la classe */
  if (RegisterClassEx(&wincl) == 0)
    ExitProcess(ShowLastError());

  /* Création de la fenêtre */
  _hWnd = CreateWindowEx(0, _lpAppName, _lpAppName,
                         WS_OVERLAPPED | WS_SYSMENU |
                         WS_MINIMIZEBOX | WS_VISIBLE,
                         CW_USEDEFAULT, CW_USEDEFAULT,
                         600, 400,
                         HWND_DESKTOP, NULL, _hThisInstance, NULL);
  if (_hWnd == 0)
    ExitProcess(ShowLastError());
}

/**
 * Callback d'énumération des fenêtre pour trouver celle de la calculatrice
 */
BOOL __stdcall RetrieveCalcWindow(HWND hwnd, LPARAM lParam)
{
  DWORD nPid;   /* Récupération du PID associé à la fenêtre                   */
  BOOL bFound;  /* Fenêtre trouvée ?                                          */

  GetWindowThreadProcessId(hwnd, &nPid);
  if (nPid == _nCalcPid)
  {
    _hCalcHwnd = hwnd;
    bFound = TRUE;
  }
  else
    bFound = FALSE;

  /* On arrête l'énumération si on a trouvé */
  return ! bFound;
}

/**
 * Met une calculatrice dans la fenêtre
 */
void __stdcall EmbedCalc()
{
  STARTUPINFO startupInfo;                /* Configuration du démarrage       */
  PROCESS_INFORMATION processInfo;        /* Informations sur le processus    */
  char* lpInfos;                          /* Nettoyage de startupInfo         */
  TCHAR lpCommandLine[20];                /* Pour l'unicode                   */
  DWORD nI;

  /* Nettoyage de startupInfo */
  lpInfos = (char*)&startupInfo;
  for (nI = 0; nI < sizeof(STARTUPINFO); nI++)
  {
    *lpInfos = 0;
    lpInfos++;
  }

  /* Initialisation de startupInfo */
  startupInfo.cb = sizeof(STARTUPINFO);
  startupInfo.dwFlags = STARTF_USESHOWWINDOW;
  startupInfo.wShowWindow = SW_HIDE;

  /* La ligne de commande doit être modifiable en unicode */
  lstrcpy(lpCommandLine, _T("calc"));

  /* Lancement de la calculatrice */
  if (CreateProcess(NULL, lpCommandLine, NULL, NULL,
                    FALSE, CREATE_DEFAULT_ERROR_MODE,
                    NULL, NULL, &startupInfo, &processInfo) == 0)
    ExitProcess(ShowLastError());

  Sleep(2000);

  /* Fermeture des handles inutiles */
  CloseHandle(processInfo.hProcess);
  CloseHandle(processInfo.hThread);

  _hCalcHwnd = 0;
  _nCalcPid = processInfo.dwProcessId;

  /* Récupération d'un handle sur la fenêtre de la calculatrice */
  while (_hCalcHwnd == 0)
  {
    EnumWindows(RetrieveCalcWindow, 0);
    Sleep(1);
  }

  /* Affectation du style de la calculatrice */
  SetWindowLong(_hCalcHwnd, GWL_STYLE, WS_CHILD);

  /* Mise en place de la calculatrice dans notre fenêtre */
  SetParent(_hCalcHwnd, _hWnd);

  /* On réaffiche dans notre fenêtre */
  SetWindowPos(_hCalcHwnd, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
  ShowWindow(_hCalcHwnd, SW_SHOW);

  RedrawWindow(_hWnd, NULL, NULL, RDW_INVALIDATE);
}

/**
 * Point d'entrée du programme
 *
 * @return Code d'erreur du processus
 */
#ifdef NDEBUG
int __cdecl WinMainCRTStartup()
#else
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                      LPSTR lpCmdLine, int nShowCmd)
#endif
{
  MSG messages;           /* Réception des messages envoyés à l'application   */

  /* Récupération du handle du module */
  _hThisInstance = GetModuleHandle(NULL);

  InitWindow();

  EmbedCalc();

  /* Boucle de traitement des messages */
  while (GetMessage(&messages, NULL, 0, 0))
  {
    /* Traduit certains messages */
    TranslateMessage(&messages);

    /* Distribution des messages aux fenêtres */
    DispatchMessage(&messages);
  }

  /* Code d'erreur en sortie */
  return messages.wParam;
}
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
1 déc. 2008 à 20:51
J'y pense... Si c'est juste pour une image, tu peux peut être faire une impression écran de la fenêtre. BitBlt ne fonctionne cependant que si la fenêtre est visible... Sinon, tu peux essayer WM_PRINT et WM_PRINTCLIENT, mais rien ne dit que l'application que tu lances ne les supporte...

Ah oui au fait... Presque une heure avant le premier message, c'est plutôt "lent" pour CS.
0
jdex Messages postés 11 Date d'inscription jeudi 2 octobre 2008 Statut Membre Dernière intervention 9 décembre 2008
2 déc. 2008 à 14:15
Merci bien pour cette réponse complète Je vais analyser le code et te poser une question si il y a des point d'ombre ^^. Sinon je trouve que c'est plus rapide que le forum de Développez!
0
jdex Messages postés 11 Date d'inscription jeudi 2 octobre 2008 Statut Membre Dernière intervention 9 décembre 2008
2 déc. 2008 à 16:05
Alors j'ai testé ton appli qui a l'air de fonctionner, mais il y a un hic avec l'application que je dois lancer. En effet, la fenêtre de mon image s'encastre dans la windows que tu as crée (d'ailleur il manque une partie de la fenêtre), mais impossible d' interagir avec cette fenêtre. Dans un contexte normale, je dois pouvoir sélectionner des zones de l'image à l'aide de la souris, ou encore passer à l'image suivante en appuyant sur Espace, ou Echap pour quitter ce programme. Or aucune de ces fonctionalités ne semble marcher, ce qui est plutôt étrange vu que la calculatrice , elle semble fonctionner.
0
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
2 déc. 2008 à 16:44
"(d'ailleur il manque une partie de la fenêtre)"
Pour ça tu peux ajuster 600 et 400 dans CreateWindow.

Ou utiliser GetClientRect sur la fenêtre encapsulée, puis AdjustWindowRect pour savoir quelle taille donner à ta fenêtre encapsuleuse et finalement SetWindowPos pour adapter la receveuse à la reçue.

Concernant le fait que l'application est gelée... Je n'ai pas la moindre idée de ce qui se passe et de ce qu'il faudrait faire pour contourner ce problème. Peut être que les messages ne parviennent plus à la fenêtre encapsulée. Ou peut être que l'application test si elle est au premier plan, style un appel à GetForeGroundWindow et une comparaison avec le handle de sa fenêtre.

Si tu as Visual Studio, tu as aussi spy++, qui permet d'espionner les messages et de parcourir l'arborescence de fenêtre d'une application. Cela peut éventuellement t'aider à trouver un indice sur ce qu'il se passe.
0
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
3 déc. 2008 à 10:34
Le Sleep(2000) de mon code ne sert à rien si ce n'est à le rendre plus lent.

Le processus calc.exe reste actif après l'arrêt de mon programme. WM_CLOSE sur la fenêtre de la calculatrice semble insuffisant... Reste la solution malheureusement un peu violente du TerminateProcess.
0
jdex Messages postés 11 Date d'inscription jeudi 2 octobre 2008 Statut Membre Dernière intervention 9 décembre 2008
4 déc. 2008 à 14:21
Désolé pour le temps de réponse, mais merci beaucoup d'avoir essayer de m'aider . Hélàs je ne trouve toujours pas la solution au problème. Et je me demande si cette méthode est compatible avec GTK. . Connait tu d'autres outils similaire à Spy++ ?
0
jdex Messages postés 11 Date d'inscription jeudi 2 octobre 2008 Statut Membre Dernière intervention 9 décembre 2008
5 déc. 2008 à 09:35
  Je viens de télécharger l'exe, je sens que ce petit soft va m'être bien utile, je vais analyser un peu le code et voir ce que je peux faire par le suite. Merci encore
0
jdex Messages postés 11 Date d'inscription jeudi 2 octobre 2008 Statut Membre Dernière intervention 9 décembre 2008
8 déc. 2008 à 14:45
Tout comme toi j'ai réussi, à insérér des programmes dans une fenêtre dotée de ScrollBar, hélas je n'arrive pas a faire interagir celles ci en fonction de ce qui se trouve dans cette fenêtre..Et j ai aussi toujours le problème, de pouvoir cliquer  sur la fenêtre afin de selectionner des zones. Dès que je clic dessus, la fenêtre que j 'ai placé dans la windows disparait.
0
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
23 déc. 2008 à 15:12
Manque un LocalFree dans ma ShowLastError.
0
Rejoignez-nous