2010-11-02 42 views
4

Je développe un système composé de nombreux sous-systèmes indépendants. Deux de ces sous-systèmes sont le sous-système Window et le sous-système GraphicsAdapter. GraphicsAdapter requiert un handle de fenêtre de bas niveau (HWND ou X11 Window Handle, selon le système d'exploitation), et le sous-système Window est un moyen de résumer ces API spécifiques au système d'exploitation.Comment encapsuler au mieux les poignées de fenêtre?

Si le sous-système Window donnait accès à des poignées d'API de bas niveau, l'encapsulation risquait fort d'être interrompue. Et si cela permettait aux fenêtres de passer en plein écran et de revenir en arrière, mais qu'elles devaient déclencher des événements avertissant le système de ces changements, et que la poignée de bas niveau était utilisée pour passer en plein écran à son insu? Comment puis-je m'assurer que le handle sera transporté du sous-système Window vers GraphicsAdapter sans être abusé, tout en étant suffisamment flexible pour permettre l'ajout ultérieur d'autres sous-systèmes comme GraphicsAdapter, tout en conservant la sécurité du type ?

Existe-t-il un moyen d'encapsuler les handles d'une manière que Direct3D et OpenGL peuvent accéder juste assez de la poignée pour fonctionner correctement?

- modifier

En plus de poignées de transport en toute sécurité d'un sous-système à un autre, sachant que les sous-systèmes peuvent être écrits par une autre équipe de codeurs, par exemple, est-il un moyen de leur rappeler la façon dont la poignée est destiné à être utilisé?

Les commentaires sont le choix évident, mais quelque chose imposé par le compilateur est ce que je regarde vraiment ...

+0

Je l'encapsulerais dans wxWidgets ou Qt ou GTK ou ... –

+1

Pourquoi est-ce que j'utiliserais wxWidgets, Qt ou GTK ou n'importe quelle interface graphique à part entière si tout ce que je veux est une fenêtre vide pour afficher des choses? En outre, je devrais encore accéder à une sorte de _nativeHandle() pour choisir le handle et mettre OpenGL/D3D si je voulais rendre sur ceux-ci, donc ce n'est pas ce que je cherche. Je veux une nouvelle solution. –

+0

À quoi le GraphicsAdapter a-t-il besoin? Et pourquoi ne pouvez-vous pas faire confiance au code GraphicsAdapter? –

Répondre

6

les deux HWNDs et X11 poignées de fenêtres sont des types pointeur. Vous pouvez utiliser ça à votre avantage. Faites quelque chose comme ceci:

struct WindowHandleImpl; 
typedef WindowHandleImpl *WindowHandle; 

C++ vous permet de travailler avec des pointeurs vers des types incomplets très bien - mais ne définit pas le contenu de WindowHandleImpl partout et WindowHandle est un type parfaitement opaque qui peut être passé autour de l'App sans divulguer les détails de mise en œuvre. Parce que HWND, X11 Window et WindowHandle sont tous les types de pointeurs, vous pouvez les couler librement et sans perte. Donc, chaque fois que vous avez besoin de retourner une poignée de fenêtre enveloppée à l'application, vous faites un static_cast<WindowHandle>(some_hwnd), et la même astuce fonctionne en sens inverse lorsque vous devez convertir un WindowHandle spécifié par l'application dans le type de plate-forme réelle.

Si vous avez besoin de porter sur une plate-forme qui n'utilise pas de type de pointeur pour désigner les poignées de fenêtres, vous pouvez l'insérer dans une structure/classe et y renvoyer un pointeur.

+0

Je l'aurais probablement enveloppé dans une structure pour commencer, juste pour être sûr .. Je ne ferais pas confiance à Microsoft pour * laisser * HWNDs comme des poignées. Il y a probablement un obscur '# define' qui le redéfinit comme quelque chose d'autre pour une raison quelconque. Et s'il n'y en a pas, alors ce n'est qu'une question de temps avant de l'ajouter. ;) +1, car vous décrivez très bien les deux cas, et c'est une bonne solution. – jalf

+0

@jalf: Eh bien, ils sont restés avec des types de pointeurs pour Win16, Win32 et maintenant 64 bits. Ceci est pratiquement impossible à changer en dehors des changements drastiques, comme le passage à une autre plate-forme, car cela romprait la compatibilité binaire, et chaque application Windows (à l'exception des applications console) dépend de l'interface binaire de user32.dll. En cas de doute, gardez les choses simples. Si vous n'êtes pas sûr de pouvoir le modifier ultérieurement, écrivez deux fonctions d'aide 'WindowHandleFromHWND' et' HWNDFromWindowHandle' et laissez-les faire les typecasts. De cette façon, il n'y a que deux endroits à éditer si vous en avez besoin. –

2

Expose les opérations sur la poignée par des fonctions virtuelles:

class GenericHandle 
{ 
    public: 
     virtual void some_operation() = 0; 
}; 

// Windows API 
class WindowsHandle : public GenericHandle 
{ 
    public: 
     virtual void some_operation() 
     { 
      WndOperation (handle_); 
     } 
    private: 
     HANDLE* handle_; 
}; 

// Some X system API 
class XHandle : public GenericHandle 
{ 
    public: 
     virtual void some_operation() 
     { 
      XOperation (handle_); 
     } 
    private: 
     XVOID* handle_; 
}; 

Une façon probable de configurer le GraphicsAdapter:

GraphicsAdapter* ga = new GraphicsAdapter(GenericHandleFactory::get_handle(SYSTEM_ID)); 
+2

Le problème est OpenGL et Direct3D ne comprendra pas ce qu'est un WindowsHandle ou XHandle ou quoi que ce soit. Il veut soit le Windows HWND ou le X11 Window Handle. –

+2

En fait, pour être plus précis, OpenGL nécessite un contexte de périphérique sous Windows pour créer son contexte de rendu. Direct3D, cependant, nécessite le HWND. Les deux cas sont difficiles à encapsuler, bien que le cas D3D soit beaucoup plus spectaculaire, comme d'habitude, car il ronge beaucoup plus que nécessaire pour le rendu (une poignée de fenêtre entière, au lieu de quelque chose représentant un endroit à dessiner, qui est vraiment devrait exiger, imo). –

+0

@ n2liquid: il n'y a aucun moyen d'éviter le downcasting dans la situation décrite. Utilisez RTTI sur GenericHandle dans GraphicsAdapter pour obtenir des données brutes ou des fonctionnalités spécifiques dont vous avez besoin. – Basilevs

-1

Documentez la façon dont vous prévoyez l'utiliser.

Faites confiance aux autres codeurs de votre équipe.N'écrivez pas beaucoup de code en essayant d'inciter votre équipe à coder comme vous le souhaitez. Plus de code signifie plus de code à maintenir, plus de chances de bugs, plus de confusion pour la prochaine personne regardant ce code se demandant ce que le diable est en train de faire.

+0

La documentation est placée à l'endroit où vous acquérez le HWND. Plus tard, vous pouvez le passer si souvent que personne ne saura qu'il doit utiliser la façon dont il a été documenté. Ce n'est plus une fonction get: c'est une variable libre. Ça ne devrait pas être comme ça. OOP combat exactement ce genre de philosophie. Il devrait y avoir un moyen de les faire bien jouer, de la manière OOP. Si je ne trouve pas le chemin, je vais certainement le documenter. –