Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

Vous n'avez pas encore de compte Developpez.com ? L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Developpez.com

C++

Choisissez la catégorie, puis la rubrique :

logo
Sommaire > Classes Fenêtres et FrameWork > Divers
        Comment chercher la fenêtre d'un programme sur le bureau ?
        Comment sérialiser des données avec les MFC ?
        Comment sérialiser des données avec les conteneurs templates MFC ?
        Comment libérer la mémoire sur les collections de template ?
        Comment fonctionnent les éditions sur une fenêtre de type View ?
        Comment faire une application type SDI ou MDI sans menu général ?
        Comment proposer automatiquement la sauvegarde d'un document modifié avant de le fermer ?
        Comment réaliser un splashscreen ?
        Comment ajouter une form .Net (winform) à mon application MFC ?
        Comment supprimer les ascenseurs d'une View ?



Comment chercher la fenêtre d'un programme sur le bureau ?
auteur : Farscape
En parcourant les fenêtres sur le bureau :
Voici un exemple permettant de trouver le handle de fenêtre de Word et de fermer Word :

char szIdentite[]="Microsoft Word";
CWnd* pWnd = CWnd::GetDesktopWindow( )->GetTopWindow( );
CWnd *pWndWord = 0;
CString s,strWord;
while( 1 )
{
    pWnd = pWnd->GetNextWindow();
    if ( pWnd == NULL ) break;
    pWnd->GetWindowText( s );
    strWord=s;
    if(strWord.Find(szIdentite)!=-1)
    {
        pWndWord = pWnd;
        break;
    }
}
if(pWndWord)
::PostMessage(pWndWord->GetSafeHwnd(),WM_SYSCOMMAND, SC_CLOSE, 0L );
Note: Si le nom de l'application est fixe on pourra utiliser la commande :

CWnd::FindWindow
static CWnd* PASCAL FindWindow( 
LPCTSTR lpszClassName, 
LPCTSTR lpszWindowName ); 

CWnd *pWnd=CWnd::FindWindow( NULL,"MonProg");

Comment sérialiser des données avec les MFC ?
Mise à jour le 23/03/2008[haut]
auteur : Farscape
Les classes MFC proposent des objets permettant de maintenir des collections d'objets en mémoire.
Classiquement on retrouvera des objets gérant des tableaux ,des listes ,et des maps .
On trouve dans les MFC deux générations de ces objets :

CObArray , CObList, CMapPtrToWord
Déclinés avec des string des word ,int etc..

La seconde génération utilise des classes templates :
CArray, CList ,CMap
il est préférable d'utiliser ces classes en remplacement des précédentes.

L'exemple qui suit déclare un objet à sérialiser .
Un tableau de cet objet.
Son remplissage, sa sauvegarde et sa lecture avec la classe CArchive.

// header ..................

// la classe qui contient les données 
class CItem : public CObject
{

public:
    DECLARE_SERIAL( CItem )

    CItem(){Clear();}
    //-----------------------------
    ~CItem(){}
    //-----------------------------
     // constructeur de copie
    CItem(const CItem &rItem)
    {
        CopyFrom(rItem);
    }
    //-----------------------------
    // operateur d'affectation
    const CItem& operator=(const CItem& Src)
    {
        CopyFrom(Src);
        return *this;
    }
    //-----------------------------
    // effacer les données.
    void Clear()
    {
        m_strNom="";
        m_strPrenom="";
        m_strCdp="";
        m_strVille=""; 
    }
    //-----------------------------
    // la methode de serialisation.
    void Serialize(CArchive& ar)
    {
        if(ar.IsStoring())
            ar << m_strNom << m_strPrenom << m_strCdp <<m_strVille;
        else
            ar >> m_strNom >> m_strPrenom >> m_strCdp >> m_strVille;
    }
    //-----------------------------
    // copier les données d'une source.
    void CopyFrom(const CItem & Src )
    {
        if(this==&Src) return;
        
        Clear(); // clear eventuel.
        
        m_strNom    =Src.m_strNom;
        m_strPrenom =Src.m_strPrenom;
        m_strCdp    =Src.m_strCdp;
        m_strVille  =Src.m_strVille;
   }
    //-----------------------------
    // dump pour test
    CString GetStrDump()
    {
        return ( m_strNom + "/" +m_strPrenom + "/" + m_strCdp +"/" + m_strVille);
    }
    
    // les données.
    CString m_strNom;
    CString m_strPrenom;
    CString m_strCdp;
    CString m_strVille;
};

template<> void AFXAPI SerializeElements<CItem> (CArchive& ar, CItem* pElements, int nCount);

// la gestion d'un tableau de cette classe .
typedef CArray<CItem,CItem&> CArrayItem;

// Source.........................
//---------------------------------------------------------------------------------------
// definition de la methode de serialisation de l'objet CItem pour le template CArray.
template <>  void AFXAPI SerializeElements <CItem> ( CArchive& ar, 
    CItem* pItem, int nCount )
{
    for ( int i = 0; i < nCount; i++, pItem++ )            
        pItem->Serialize( ar );    
}

IMPLEMENT_SERIAL( CItem, CObject, 0)

void Test()
{
// un element 
   CItem item;

    item.m_strCdp="06800";
    item.m_strNom="farscape";
    item.m_strPrenom="???";
    item.m_strVille="Nice";

   // un tableau de l'element
    CArrayItem arItem;

     // remplissage.
    arItem.Add(item);
    for(int i=0;i<10;i++)
    {
        item.m_strNom.SetAt(0,'A'+i);
        arItem.Add(item);
    }
     // archivage.
    {
        CFile File;    
        if(File.Open("MyArchive.arc", CFile::modeCreate | CFile::modeWrite ))
        {
            CArchive ar( &File, CArchive::store);
            arItem.Serialize(ar);
        }
    }
    // Lecture de l'archive.
    arItem.RemoveAll();
    CFile File;    
    if(File.Open("MyArchive.arc", CFile::modeRead ))
    {
        CArchive ar( &File, CArchive::load);
        arItem.Serialize(ar);
    }
    // verification du contenu.
    for(i=0;i<arItem.GetSize();i++)
    {
        AfxMessageBox(arItem[i].GetStrDump());
    }

}
Note: il faut inclure le fichier afxtempl.h dans stdafx.h
Voir l'article sur MSDN Collections: How to Make a Type-Safe Collection


Comment sérialiser des données avec les conteneurs templates MFC ?
Créé le 27/11/2005[haut]
auteur : Nourdine Falola
En complément de faq Comment sérialiser des données avec les MFC ?

Pour ceux qui n'ont pas envie d'implémenter eux-même la fonction SerializeElements<CItem> chaque fois qu'ils veulent sérialiser le contenu d'un CArray ou d'un autre conteneur template MFC, il est possible de définir une classe template, héritant du conteneur en question, implémentant déjà ce service.

Exemple du CArray

#include <string>
#include <sstream>
#include <afxtempl.h>

template <class T,class U>
class CArraySer: public CArray<T,U>
{

public:

CArraySer(int line,bool b=true);
virtual ~CArraySer();
virtual void Serialize(CArchive& ar);
void AFXAPI SerializeElts (CArchive& ar, T* pItem, int nCount);

private:

bool isSerializable;
                // si true, alors CArraySer contient des objets sérialisables

std::string msg; 
                // complément au message d'erreur affiché si on
                // tente de sérialiser des objets non-sérialisables
};



template <class T,class U>
CArraySer<T,U>::CArraySer(int line,bool b)
{
    isSerializable = b;
    std::ostringstream oss;
    oss << "Erreur ligne " << line << " : CArraySer contient des objets non-sérialisables";
    msg = oss.str();
}



template <class T,class U>
CArraySer<T,U>::~CArraySer()
{

}



template <class T,class U>
void AFXAPI CArraySer<T,U>::SerializeElts  ( CArchive& ar,T* pItem, int nCount )
{
    for ( int i = 0; i < nCount; i++, pItem++ )            
        pItem->Serialize( ar );    
}



template<class T, class U>
void CArraySer<T, U>::Serialize(CArchive& ar)
{
    ASSERT_VALID(this);
    
    if (isSerializable)
    {
        CObject::Serialize(ar);
        if (ar.IsStoring())
        {
            ar.WriteCount(GetSize());
        }
        else
        {
            DWORD nOldSize = ar.ReadCount();
            SetSize(nOldSize, -1);
        }
        SerializeElts(ar, m_pData, GetSize());
    }
    else
    {
        AfxMessageBox(msg.c_str());
    }
}
L'utilisation de CArraySer est similaire à celle de CArray, cependant il n'est plus nécessaire d'implémenter la fonction statique SerializeElements dans le code appelant. Le constructeur comporte 2 arguments : le 1er correspond à la ligne à laquelle vous déclarerez le CArraySer, le 2è est un booléen qui indique si les objets contenus par le CArraySer sont sérialisables ou non. Reprenons l'exemple du CArray en le remplaçant par CArraySer :

// La macro peut-être mise dans le fichier citem.cpp s'il existe
IMPLEMENT_SERIAL( CItem, CObject, 0)

void Test()
{
   // un element 
   CItem item;

   item.m_strCdp="35200";
   item.m_strNom="Shakala";
   item.m_strPrenom="Bigboom";
   item.m_strVille="Rennes";

   // un tableau de l'element
   CArraySer<CItem,CItem&> arItem(__LINE__);

   // remplissage.
   arItem.Add(item);
   for(int i=0;i<10;i++)
   {
       item.m_strNom.SetAt(0,'A'+i);
       arItem.Add(item);
   }

   // archivage.
   {
       CFile File;    
       if(File.Open("MyArchive.arc", CFile::modeCreate | CFile::modeWrite ))
       {
           CArchive ar( &File, CArchive::store);
           arItem.Serialize(ar);
       }
   }

   // Lecture de l'archive.
   arItem.RemoveAll();
   CFile File;    
   if(File.Open("MyArchive.arc", CFile::modeRead ))
   {
       CArchive ar( &File, CArchive::load);
       arItem.Serialize(ar);
   }

   // verification du contenu.
   for(i=0;i<arItem.GetSize();i++)
   {
       AfxMessageBox(arItem[i].GetStrDump());
   }
}
Si vous déclarez le contenu du CArraySer comme non-sérialisable (isSerializable = false) et que vous tentez tout de même la sérialisation, un AfxMessageBox vous délivre un message vous indiquant votre erreur et la ligne à laquelle vous avez déclarez le CArraySer incriminé.


Comment libérer la mémoire sur les collections de template ?
Créé le 19/09/2005[haut]
auteur : Farscape
Les collections à base de template MFC : CArray ,CMap ,CList disposent de fonctions particulières pour compléter des traitements de construction, de sérialisation ou de destruction d'éléments.

Voici la problématique : Je déclare un CMap sur dont les valeurs sont des pointeurs sur objets Donc l'insertion dans la CMap nécessitera l'allocation de l'objet au préalable.
Exemple :
la déclaration :

CMap<CString ,const char *,_InfosFolder* ,_InfosFolder *> m_mapFilter;
l'insertion:

m_mapFilter.SetAt("clef", new _InfosFolder);
La destruction d'un élément par la fonction RemoveKey ou RemoveAll provoquera une fuite de mémoire puisque la CMap appelle le destructeur de l'élement type ici un pointeur sur objet ,et donc ne libérera pas l'objet lui même.
pour résoudre ce problème on implémentera la fonction DestructElements :

voici son prototype:

template<class TYPE >
void AFXAPI DestructElements( TYPE* pElements, 
int nCount );
implémentation pour le type de donnée _InfosFolder *

template <> void AFXAPI DestructElements <_InfosFolder *> ( _InfosFolder** pItem, int nCount )
{
    for ( int i = 0; i < nCount; i++, pItem++ ) delete *pItem;  
}
Dans ce contexte comment être sûr de ne pas faire un delete sur un élément non alloué par un new ? je propose l'utilisation d'une macro à rajouter dans la définition du type de donnée.

#ifdef _DEBUG 

#define TRACK_ALLOC(_class) void *m_pNew;\
void* operator new(size_t nSize,LPCSTR lpszFileName,int nLine)\
{\
_class *p=static_cast<_class *>(::operator new(nSize, lpszFileName, nLine));\
p->m_pNew=p;return p;\
}\
bool IsAlloc(){return m_pNew==this;}

#else

#define TRACK_ALLOC(_class) void *m_pNew;\
void* operator new(size_t nSize)\
{\
_class *p=static_cast<_class *>(::operator new(nSize));\
p->m_pNew=p;return p;\
}\
bool IsAlloc(){return m_pNew==this;}

#endif
ce qui donnera :

struct _InfosFolder
{
//..............
TRACK_ALLOC(_InfosFolder)
};
template <> void AFXAPI DestructElements <_InfosFolder *> ( _InfosFolder** pItem, int nCount )
{
    for ( int i = 0; i < nCount; i++, pItem++ )            
    {
        if(*pItem->IsAlloc()) delete *pItem;
    }
}
ces macros doivent etre inserées avant le bloc de code:

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
Note:le même traitement peut être appliqué sur la clé de la CMap. en effet la suppression d'un élement invoque la fonction DestructElements sur la clef et sur l'élément associé. Extrait de AfxTempl.h

void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::RemoveAll()
{
    ASSERT_VALID(this);
    if (m_pHashTable != NULL)
    {
        // destroy elements (values and keys)
        for (UINT nHash = 0; nHash < m_nHashTableSize; nHash++)
        {
            CAssoc* pAssoc;
            for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc->pNext)
            {
                DestructElements<VALUE>(&pAssoc->value, 1);
                DestructElements<KEY>(&pAssoc->key, 1);
            }
        }
    }
    // free hash table
    delete[] m_pHashTable;
    m_pHashTable = NULL;
    
    m_nCount = 0;
    m_pFreeList = NULL;
    m_pBlocks->FreeDataChain();
    m_pBlocks = NULL;
}

Comment fonctionnent les éditions sur une fenêtre de type View ?
Créé le 04/04/2005[haut]
auteur : Farscape
Principe de fonctionnement général d'une édition à partir d'une CView CScrollView :

Le traitement normal d'affichage se fait dans la fonction virtuelle OnDraw utilisée aussi pour le dessin écran .

Elle reçoit en argument un objet CDC (contexte de périphérique) .

Si on imprime, la fonction OnDraw est appelée par une autre fonction virtuelle, OnPrint ;le dc sera alors un contexte de périphérique pour imprimante, et CDC::IsPrinting() renvoie TRUE .

Dans le cas de la prévisualisation écran on aura un objet CPreviewDC; OnPrint et OnDraw seront appelées.

Les fonctions disponibles pour le système d'édition sont:

  • OnPreparePrinting : définition de la plage d'édition voir CPrintInfo
  • OnBeginPrinting : créations d'objets gdi personnels.
  • OnPrepareDC : appelée pour chaque page, c'est l'emplacement convenu pour définir le système de coordonnées (autre que MM_TEXT) .
  • OnPrint : Appelée pour chaque page ,traitements spécifiques pour compléter éventuellement le dessin, entêtes, pieds de page, date et heure d'édition. Appelle OnDraw.
  • OnEndPrinting: suppression des objets GDI.
dans une view on trouve généralement les messages suivants:

ON_COMMAND(ID_FILE_PRINT, CFormView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CFormView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CFormView::OnFilePrintPreview)
Correspondant aux différents appels pour l'édition de la fenêtre en cours.

  • ID_FILE_PRINT : impression avec sélection de l'imprimante.
  • ID_FILE_PRINT_DIRECT : impression directe sur l'imprimante en cours.
  • ID_FILE_PRINT_PREVIEW : prévisualisation écran.
Note : le système MFC associe l'édition/prévisualisation à la fenêtre en cours on ne dispose pas en standard d'un objet indépendant pour gérer l'édition comme ça existait chez Borland avec les OWL .


Comment faire une application type SDI ou MDI sans menu général ?
Mise à jour le 17/09/2007[haut]
auteurs : nico-pyright(c), Farscape
On ne peut pas générer une application de type SDI ou MDI sans menu directement.
La solution consiste à le supprimer lors de la création de Mainframe en procédant comme suit :
Pour un projet SDI: Dans la classe CMainFrame, il faut rajouter dans la fonction PreCreateWindow, le code suivant :
  
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
  if (cs.hMenu!=NULL)
    {
        ::DestroyMenu(cs.hMenu);      // delete menu if loaded
        cs.hMenu = NULL;              // no menu for this window
    }
    return CFrameWnd::PreCreateWindow(cs);
}
Pour un projet MDI: Il faudra générer avec l'assistant et modifier les fonctions suivantes comme suit:

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
  if (cs.hMenu!=NULL)
    {
        ::DestroyMenu(cs.hMenu);      // delete menu if loaded
        cs.hMenu = NULL;              // no menu for this window
    }
    return CMDIFrameWnd::PreCreateWindow(cs);
}
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) 
{
// TODO: Add your specialized code here and/or call the base class

    return CreateClient(lpcs,NULL); // a la place de la ligne ci-dessus
//return CMDIFrameWnd::OnCreateClient(lpcs, pContext);
}
BOOL CMainFrame::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext) 
{
// TODO: Add your specialized code here and/or call the base class

return CFrameWnd::LoadFrame(nIDResource, dwDefaultStyle, pParentWnd, pContext);
//return CMDIFrameWnd::LoadFrame(nIDResource, dwDefaultStyle, pParentWnd, pContext);
}
Enfin il faudra supprimer le menu dans les ressources .
c'est à dire le menu correspondant à l'identifiant utilisé dans la déclaration du document template dans la fonction InitInstance de la classe d'application.


Comment proposer automatiquement la sauvegarde d'un document modifié avant de le fermer ?
Créé le 27/11/2005[haut]
auteur : Nourdine Falola
On a pu déjà remarquer que beaucoup d'applications proposent à l'utilisateur d'enregistrer le document en cours de fermeture si celui-ci a été modifié depuis son ouverture. Les MFC proposent également ce mécanisme.

L'architecture d'application gère ce comportement grâce à la donnée membre BOOL m_bModified de la classe CDocument (dirty flag : TRUE si le document a été modifié, FALSE sinon). Cet indicateur est initialisé à false à la création, lecture, enregistrement du document. C'est au programmeur de le mettre à TRUE lorsque le document a été modifié.

Sa valeur peut-être consultée avec la fonction BOOL CDocument::IsModified() et modifiée avec la fonction void SetModifiedFlag(BOOL bModified = TRUE).

Lorsque l'utilisateur ferme un document, l'architecture d'application appelle la fonction virtuelle virtual BOOL SaveModified( ) qui ouvre une boîte de dialogue si m_bModified = TRUE. On peut redéfinir le comportement de la fonction SaveModified( ).

Exemple d'indication de modification du document :
// fonction de la classe dérivée de CDocument
void CMyDoc::ModifData(CString strName,CString strLevel,CString strLoc,CTime tDate)
{
   // m_pData est une donnée membre de CMyDoc
   m_pData->SetName(strName);
   m_pData->SetLevel(strLevel);
   m_pData->SetPlace(strLoc);
   m_pData->SetDate(tDate);

   // les données du document ont été modifiées
   SetModifiedFlag();

   // mise à jour des vues sur le document
   UpdateAllViews(NULL);
}
// modification des données de CMyDoc dans une vue
void CMyView::MyFunction()
{
   CMyDoc * pDoc = static_cast<CMyDoc*>(GetDocument());

   // appel de la fonction modificant les données du document
   pDoc->ModifData("Nom","Niveau","Localisation",CTime::GetCurrentTime());

   // si on n'avait pas écrit la fonction CMyDoc::ModifData(...),
   // on aurait géré les modifications du document ici et écrit :
   // pDoc->SetModifiedFlag();
}

Comment réaliser un splashscreen ?
Créé le 27/11/2005[haut]
auteur : Nourdine Falola
Un splashscreen est une boîte de dialogue qui apparaît au lancement d'une application pendant que celle-ci se charge. Lorsque l'application est prête, le splashscreen disparaît et la fenêtre principale de l'application apparaît.
Pour réaliser un splashscreen il suffit de décocher l'option "Title bar" dans les propriétés de la boîte de dialogue, et d'intercepter le message WM_WINDOWPOSCHANGING (à la main) :
Dans le .h de la dialog

// Generated message map functions
//{{AFX_MSG(CPasBougerDlg)
...
afx_msg void OnWindowPosChanging( WINDOWPOS* lpwndpos );
//}}AFX_MSG
Dans le .cpp de la dialog
BEGIN_MESSAGE_MAP(CPasBougerDlg, CDialog)
//{{AFX_MSG_MAP(CPasBougerDlg)
...
ON_WM_WINDOWPOSCHANGING()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

...
void CPasBougerDlg::OnWindowPosChanging(WINDOWPOS* pWndPos)
{
if (IsWindowVisible())
pWndPos->flags |= SWP_NOMOVE;
}
NOTE : On peut bien sûr utiliser ce principe pour empêcher le redimensionnement et le déplacement d'une fenêtre dérivée de CWnd (view, dialog, framewnd...).

Pour une boîte de dialogue, on procèdera de la même façon en laissant éventuellement la barre de titre.

Dans un contexte SDI, on interceptera le message sur le CMainFrame et on interdira le redimensionnement :

void CMainFrame::OnWindowPosChanging(WINDOWPOS* pWndPos)
{
if (IsWindowVisible())
{
pWndPos->flags |= SWP_NOMOVE;
pWndPos->flags |= SWP_NOSIZE;
}
}

Comment ajouter une form .Net (winform) à mon application MFC ?
Créé le 22/01/2007[haut]
auteur : nico-pyright(c)
Il s'agit tout d'abord de transformer son application MFC en application managée, pour ceci, il faut ajouter le support du CLR.
Bouton droit sur le projet -> Common properties -> general -> Common language runtime support ; Mettre à /clr (common language runtime support).

Ensuite ajoutez simplement une nouvelle winform, rajoutez des composants dessus, etc ...

Instanciez votre nouvelle form,

    mfcPlusWinforms::mfcWinForm dlg;
    dlg.ShowDialog(); // pour qu'elle se comporte comme une dialog

N'oubliez pas bien sûr d'inclure le fichier .h correspondant au code de la winform.

Téléchargez le programme d'exemple : ftp://ftp-developpez.com/nico-pyright/faq/mfcPlusWinforms.rar
voir aussi Mixer du C++/CLI avec du code Win32 ou MFC

lien : Mixer du C++/CLI avec du code Win32 ou MFC

Comment supprimer les ascenseurs d'une View ?
Créé le 17/09/2007[haut]
auteur : Farscape
Dans le cas d'une CFormView, CView les ascenseurs apparaissent automatiquement dès que la surface cliente de la fenêtre devient trop petite par rapport à la surface réelle.
Comment faire dans ce contexte pour supprimer les ascenseurs ?, hé bien une CFormView ou CView hérite de la classe CSCrollView qui dispose d'une fonction spécifique pour adapter la surface de la fenêtre à la taille fenêtrée: SetScaleToFitSize

Exemple réalisé dans la méthode OnInitialUpdate d'une CFormView:

CRect Rect;
    GetParentFrame()->GetWindowRect(&Rect);
    GetParentFrame()->SetWindowPos( NULL,0,0,Rect.Width(),Rect.Height()/2,SWP_NOMOVE | SWP_NOZORDER); //
    SIZE size;
    size.cx=Rect.Width();
    size.cy=Rect.Height()/2;
    SetScaleToFitSize(size);
J'ai diminué la taille de la fenêtre parent (MDIChild) par deux et ajusté la taille réelle avec SetScalToFitSize.



Consultez les autres F.A.Q.


Valid XHTML 1.0 TransitionalValid CSS!

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2004 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Contacter le responsable de la rubrique C++

Partenaire : Hébergement Web