2010-08-01 9 views
7

Je veux créer ma propre classe pour gérer la création de fenêtres et la procédure de fenêtre mais j'ai remarqué que la procédure de fenêtre doit être statique! Je me demande maintenant s'il est possible de rendre l'objet de procédure de fenêtre orienté? J'ai lu quelques tutoriels sur les fenêtres orientées objet, mais ils rendent toujours la procédure statique. Quelle est l'utilité de cela? :/Objet orienté C++ win32?

Tous les liens ou informations sur la façon de contourner ce problème serait apprécié,

grâce

+0

Voir [ Meilleure méthode de stockage de ce pointeur pour une utilisation dans WndProc ] (http://stackoverflow.com/questions/117792/best-method-for-storing-this-pointer-for-use-in-wndproc). –

+2

C'est pour cette raison que j'ai toujours souhaité que 'WndProc' ait un paramètre 'void * user_data'. Cela rendrait beaucoup plus facile la création d'un wrapper basé sur un objet. –

+0

@Evan: oui, mais il aurait aussi fallu que quelqu'un * sane * soit responsable de la conception de l'API ... L'API Win32 aurait été une bête très différente si cela avait été le cas. – jalf

Répondre

11

Vous pouvez vous débrouillez en faisant le WndProc statique déléguer tout aux membres:

// Forward declarations 
class MyWindowClass; 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 

std::map<HWND, MyWindowClass *> windowMap; 

// Your class 
class MyWindowClass { 
private: 
    HWND m_handle; 

    // The member WndProc 
    LRESULT MyWndProc(UINT message, WPARAM wParam, LPARAM lParam) { /* ... */ } 

public: 
    MyWindowClass() 
    { 
    /* TODO: Create the window here and assign its handle to m_handle */ 
    /* Pass &WndProc as the pointer to the Window procedure */ 

    // Register the window 
    windowMap[m_handle] = this; 
    } 
}; 

// The delegating WndProc 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    std::map<HWND, MyWindowClass *>::iterator it = windowMap.find(hWnd); 
    if (it != windowMap.end()) 
    return it->second->MyWndProc(message, wParam, lParam); 
    return 0; 
} 
+1

+1, mais vous pouvez également rechercher WM_DESTROY et supprimer la poignée de la carte. – SoapBox

+0

bel exemple, l'air cool. Je vais essayer de l'implémenter dans mon propre, bonne utilisation de std :: map pour trouver la poignée correspondante – Kaije

+0

@SoapBox Il est incomplet à bien des égards, merci de noter celui-ci bien. –

3

Si vous êtes à la recherche de l'API Win32 orientée objet, vous devriez chercher à MFC et/ou WTL.

+0

Des solutions exagérées à de nombreuses fins. MFC peut être * relativement * mince, mais il s'agit toujours d'une API volumineuse et le passage d'une API à une autre nécessite beaucoup de travail. Il est également complètement inutile si tout ce que vous voulez faire est d'utiliser quelques classes C++ de votre cru tout en codant pour Win32. Mon ancien "framework objet" pour Win32 était probablement sur 2 ou 3 côtés de code - un peu plus qu'une classe de base, une certaine initialisation et une boucle principale GetMessage/etc. – Steve314

+0

Question d'opinion –

+0

MFC est un framework méchant, mais il est bien supporté et relativement bien connu dans le monde Win32. – seand

1

Vous pouvez utiliser le handle de fenêtre transmis à WindowProc pour récupérer un objet que vous avez créé pour cette fenêtre particulière et déléguer la gestion des événements à cet objet.

par exemple.

IMyWindowInterface* pWnd = getMyWindowObject(hWnd); 
pWnd->ProcessMessage(uMsg, wParam, lParam); 
+0

Sonne bien, j'ai remarqué que la seule chose unique dans la procédure est la poignée, mais ne savais pas comment trouver ma fenêtre à travers elle. Comme dans votre exemple, getMyWindowObject (hwnd), cette fonction consisterait-elle à parcourir les fenêtres ouvertes pour voir si le handle correspond? parce que si oui, si je manipulais un WM_MOUSEMOVE ou WM_TIMER, cela ne serait-il pas fastidieux sur le processeur? – Kaije

+0

Votre meilleur pari il d'utiliser une forme de hashtable à hash de HWND aux pointeurs-à-votre-fenêtre-objet - qui était les recherches sont rapides. Sauf si vous avez un assez grand nombre de fenêtres ouvertes, je m'attendrais à une boucle à travers toutes les paires (HWND, objet *) serait assez rapide que '. –

6

La technique générale de permettre une instance de fenêtre pour être représentée par exemple que la classe est d'utiliser SetWindowLongPtr et GetWindowLongPtr pour associer votre pointeur d'instance de classe avec le handle de fenêtre. Voici quelques exemples de code pour vous aider à démarrer. Il ne peut pas compiler sans quelques modifications. C'est seulement destiné à être une référence.

Personnellement, j'ai arrêté de rouler mes propres classes de fenêtres il y a quelques années lorsque j'ai découvert la classe de modèles CWindow et CWindowImpl d'ATL. Ils prennent soin de faire tout ce codage banal pour vous permettre de se concentrer uniquement sur les méthodes d'écriture qui traitent les messages de fenêtre. Voir l'exemple de code que j'ai écrit here.

Espérons que cela aide.

class CYourWindowClass 
{ 
private: 
    HWND m_hwnd; 

public: 
    LRESULT WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam) 
    { 
     switch (uMsg) 
     { 
      case WM_CREATE: return OnCreate(wParam, lParam); 
      case wM_PAINT: return OnPaint(wParam, lParam); 
      case WM_DESTROY: 
      { 
       SetWindowLongPtr(m_hwnd, GWLP_USERDATA, NULL); 
       m_hwnd = NULL; 
       return 0; 
      } 
     } 
     return DefWindowProc(m_hwnd, uMsg, wParam, lParam); 

    } 

    CYourWindowClass() 
    { 
     m_hwnd = NULL; 
    } 

    ~CYourWindowClass() 
    { 
     ASSERT(m_hwnd == NULL && "You forgot to destroy your window!"); 
     if (m_hwnd) 
     { 
      SetWindowLong(m_hwnd, GWLP_USERDATA, 0); 
     } 
    } 

    bool Create(...) // add whatever parameters you want 
    { 
     HWND hwnd = CreateWindow("Your Window Class Name", "Your Window title", dwStyle, x, y, width, height, NULL, hMenu, g_hInstance, (LPARAM)this); 
     if (hwnd == NULL) 
      return false; 

     ASSERT(m_hwnd == hwnd); 
     return true; 
    } 


    static LRESULT __stdcall StaticWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
    { 
     CYourWindowClass* pWindow = (CYourWindowClass*)GetWindowLongPtr(hwnd, GWLP_USERDATA); 

     if (uMsg == WM_CREATE) 
     { 
      pWindow = ((CREATESTRUCT*)lParam)->lpCreateParams; 
      SetWindowLongPtr(hwnd, GWLP_USERDATA, (void*)pWindow); 
      m_hWnd = hwnd; 
     } 

     if (pWindow != NULL) 
     { 
      return pWindow->WndProc(uMsg, wParam, lParam); 
     } 

     return DefWindowProc(hwnd, uMsg, wParam, lParam); 
    }; 


}; 
+0

Je me suis toujours demandé à quoi servait lpParam sur la fonction CreateWindowEx, mais je suis d'avis que c'est ce qui pourrait le rendre vulnérable, car quelqu'un pourrait utiliser GetWindowLong pour obtenir vos données utilisateur: P – Kaije

2

Juste pour ajouter à la réponse de Brian mais pour un cadre de win32 qui est plus convivial débutant jeter un oeil à Win32++. La bibliothèque elle-même n'est pas aussi complète en fonctionnalités que MFC ou QT mais c'est un compromis que le concepteur a fait au début pour garder la bibliothèque facile à comprendre et simple à utiliser. Si vous êtes toujours intéressé par ce sujet, je vous encourage fortement à y jeter un coup d'œil, car il utilise encore une autre technique pour enregistrer le pointeur "this" en utilisant le stockage local de threads.