Scanneur de ports v1.2 win32 (sans mfc)

Description

Encor une fois, g copier pas mal de truc sur d'autre source (hé ouais, jsui un débutant en c++), mé bon, vu que la source d'origine du scanner (http://www.cppfrance.com/article.aspx?Val=1859) est en mode console et relativement lente, g voulu la faire en win32 en rajoutant d'autres petits truc.

Cette mise a jour suporte le style XP, le changement de focus avec tab, et quelque petits changements. Dans le fichier zip, j'ai en plus rajouté la liste d'un bon nombre de ports connus.

Source / Exemple :


#include <windows.h>
#include <stdlib.h>

// ID du EditBox
#define ID_EDITBOX 100
// ID du Button
#define ID_BUTTON 101
#define ID_BUTTON_QUIT 102
#define ID_BUTTON_AIDE 103
#define ID_BUTTON_VIDER 104
// ID de la ListBox
#define ID_LISTBOX 105

// Nom de la classe
char MainClassName[] = "Scanneur de ports";
// Instance du programme
HINSTANCE MainInstance;
// Handle de la fenêtre
HWND MainHandle;
// Handle des EditBox
HWND OrdiHandle;
HWND IPHandle;
HWND OrdiScanHandle;
HWND MinHandle;
HWND MaxHandle;
HWND AttenteHandle;
HWND ListHandle;
// Handle des Boutons
HWND ButtonHandle;
HWND ButtonAideHandle;
HWND ButtonViderHandle;
HWND ButtonQuitHandle;

// Handle d'un des labels
HWND lblhWnd6;

// ID du thread
DWORD threadID;

// Pour le hook (capture d'une touche)
HHOOK hhk = 0;

///////////Fonction qui affiche l'adresse ip et le nom de l'ordi////////////////
void adresseIP()
{
    // Ne sert strictement à rien mais permet un affichage avec style Xp normal (???)
    ShellExecute (NULL, NULL, NULL, NULL, NULL, 0);
    
    struct sockaddr_in sin;
    struct hostent * phe;
    char FAR buffer[64] ;

    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
    wVersionRequested = MAKEWORD(1, 1);
    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0)
    {
    MessageBox(MainHandle, "Impossible de trouver winsock.dll", "Erreur", MB_ICONERROR | MB_OK);
    }
    gethostname(buffer, sizeof(buffer));
    phe = gethostbyname(buffer);
    if(phe==NULL)
    {
    MessageBox(MainHandle, "Erreur : pointeur nul", "Erreur", MB_ICONERROR | MB_OK);
    WSACleanup();
    exit(1);
    }
    int I = 0 ;
    while((phe->h_addr_list[I+1])!=NULL)
    {
    I++;
    }
    memcpy(&sin.sin_addr.s_addr, phe->h_addr_list[I], phe->h_length);
    SetWindowText(OrdiHandle, buffer); 
    SetWindowText(IPHandle, inet_ntoa(sin.sin_addr)); 
    
    WSACleanup();
}
////////////////////////////////////////////////////////////////////////////////

char PortOuvert[255], NbPChar[255], PortChar[255], *Ordi = NULL;
int PORT, PortMax, PortMin, n=5, NbP=0, affichage=0, AttenteInt;

/////////////////////////////Thread du scanner//////////////////////////////////
DWORD WINAPI ScanThread(LPVOID param)
{  
 if (affichage==0)
   {
    wsprintf(PortChar,"Scan : port %i", PORT-1);
    SetWindowText(MainHandle, PortChar);
    UpdateWindow(MainHandle);
   }
 int PORT=(int)param;
 WSADATA WSAData;                      // tout les prog de
 WSAStartup(MAKEWORD(2,0),&WSAData);   // sockets commence par ca

 struct hostent * sock2;       
 SOCKET sock;                          // declare la socket  
 SOCKADDR_IN sin;                      // pareil          
 sin.sin_family = AF_INET;             // de la socket
 sock2 = gethostbyname(Ordi);        
 memcpy(&sin.sin_addr.s_addr, sock2->h_addr_list[0], sock2->h_length);
    
 sock = socket(AF_INET,SOCK_STREAM,0); // initialise la socket
 sin.sin_port = htons(PORT); // le port du socket (qui change, c'est le but !)
   
 n = connect(sock,(SOCKADDR *)&sin,sizeof(sin));     
 if(n == 0)      // si on peut se connecter (donc si le port est ouvert)
   {  
    NbP++;
    wsprintf(PortOuvert,"Port %i : OUVERT", PORT);
    SendMessage(ListHandle, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)PortOuvert);         
   }
 wsprintf(NbPChar,"Nb de ports ouverts : %i", NbP);
 SetWindowText(lblhWnd6, NbPChar);   
                              
 closesocket(sock);       // ferme la socket
 WSACleanup(); 

 return 0;
}
////////////////////////////////////////////////////////////////////////////////

//////////////////Thread qui répète en boucle le 1er thread/////////////////////
DWORD WINAPI BoucleThread(LPVOID param)
{
 for(PORT = PortMin; PORT <= PortMax; PORT++)  // boucle pour lancer le scan 
     {                                         // plusieurs fois...
      Sleep(AttenteInt);
      CreateThread(NULL, 0, ScanThread, (LPVOID)PORT, 0, &threadID);    
     }
 Sleep(200);
 affichage=1;
 SetWindowText(MainHandle, "Scan terminé");
 UpdateWindow(MainHandle);
 return 0;
}
////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////Hook/////////////////////////////////////////  
// le HOOK LOCAL est ICI
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
  MSG *lpmsg;
  lpmsg = (MSG*) lParam;
  if(nCode < 0) goto defRet; // NE JAMAIS TOUCHER DANS CE CAS
  // Hook sur la touche Tab
  if(lpmsg->message == WM_KEYDOWN && lpmsg->wParam == VK_TAB && IsChild(MainHandle, lpmsg->hwnd))
   {
    HWND Focus;
    // Change le focus si on appui sur tab
    if(GetFocus()==OrdiHandle) Focus=IPHandle;
    if(GetFocus()==IPHandle) Focus=OrdiScanHandle;
    if(GetFocus()==OrdiScanHandle) Focus=MinHandle;
    if(GetFocus()==MinHandle) Focus=MaxHandle;
    if(GetFocus()==MaxHandle) Focus=AttenteHandle;
    if(GetFocus()==AttenteHandle) Focus=OrdiHandle;
    SetFocus(Focus);
   }
defRet:
  return (CallNextHookEx(hhk, nCode, wParam, lParam));
}
////////////////////////////////////////////////////////////////////////////////
// Prototype
LRESULT CALLBACK WinProc(HWND, UINT, WPARAM, LPARAM);

/*************************************************/

// Entré du programme
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE PrevInstance, LPSTR CmdLine, int CmdShow)
{

// Pour recevoir et transmettre les messages
MSG msg;
// Pour créé la fenêtre
WNDCLASSEX wc;

// Sauvegarde l'instance
MainInstance = hInstance;

// Création de la classe
wc.hInstance = MainInstance; // Instance du programme
wc.lpszClassName = MainClassName; // Nom de la classe
wc.lpfnWndProc = WinProc; // Procédure qui va recevoir les messages
wc.style = CS_DBLCLKS; // Le style...
wc.cbSize = sizeof(WNDCLASSEX); // Taille de la struct
wc.hIcon = LoadIcon(hInstance, "A"); // L'icône(grande)
wc.hIconSm = LoadIcon(hInstance, "A"); // L'icône(petite)
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Le curseur
wc.lpszMenuName = NULL; // Menu
wc.cbClsExtra = 0; // ...
wc.cbWndExtra = 0; // ...
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW); // BackColor(Couleur de fond)

// Enregistre la classe
if (!RegisterClassEx(&wc))
return 0; // Erreur ...

// Hook
hhk = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, 0, GetCurrentThreadId());

// Crée la fenêtre principale
MainHandle = CreateWindowEx(0, MainClassName, "Scanneur de ports", WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, 327, 230, HWND_DESKTOP, NULL,hInstance, NULL);

if (MainHandle == NULL)
return 0; // Erreur ...

// Crée le label pour avoir une couleur uniforme
HWND lblhWnd0 = CreateWindowEx(0, "STATIC", "", WS_VISIBLE|WS_CHILD, 0, 0, 327, 230, MainHandle, (HMENU)ID_EDITBOX, hInstance, NULL);

// Crée les 2 cadres avec les titres
HWND lblhWndCadre1 = CreateWindowEx(0, "STATIC", "", WS_VISIBLE|WS_CHILD|SS_SUNKEN, 5, 12, 137, 60, MainHandle, (HMENU)ID_EDITBOX, hInstance, NULL);
HWND lblhWndTitre1 = CreateWindowEx(0, "STATIC", " Cet ordinateur", WS_VISIBLE|WS_CHILD, 35, 5, 72, 50, MainHandle, (HMENU)ID_EDITBOX, hInstance, NULL);

HWND lblhWndCadre2 = CreateWindowEx(0, "STATIC", "", WS_VISIBLE|WS_CHILD|SS_SUNKEN, 150, 12, 165, 60, MainHandle, (HMENU)ID_EDITBOX, hInstance, NULL);
HWND lblhWndTitre2 = CreateWindowEx(0, "STATIC", " Ordi à scanner", WS_VISIBLE|WS_CHILD, 195, 5, 75, 50, MainHandle, (HMENU)ID_EDITBOX, hInstance, NULL);

// Crée tous les autres textes
HWND lblhWnd1 = CreateWindowEx(0, "STATIC", "Nom :", WS_VISIBLE|WS_CHILD, 10, 24, 100, 13, MainHandle, (HMENU)ID_EDITBOX, hInstance, NULL);
HWND lblhWnd2 = CreateWindowEx(0, "STATIC", "IP :", WS_VISIBLE|WS_CHILD, 10, 49, 100, 13, MainHandle, (HMENU)ID_EDITBOX, hInstance, NULL); 
HWND lblhWnd3 = CreateWindowEx(0, "STATIC", "Nom ou IP :", WS_VISIBLE|WS_CHILD, 155, 24, 100, 13, MainHandle, (HMENU)ID_EDITBOX, hInstance, NULL);    
HWND lblhWnd4 = CreateWindowEx(0, "STATIC", "Ports de                   à", WS_VISIBLE|WS_CHILD, 155, 49, 150, 13, MainHandle, (HMENU)ID_EDITBOX, hInstance, NULL);    
HWND lblhWnd5 = CreateWindowEx(0, "STATIC", "Liste des ports ouverts :", WS_VISIBLE|WS_CHILD, 10, 80, 300, 13, MainHandle, (HMENU)ID_EDITBOX, hInstance, NULL);
lblhWnd6 = CreateWindowEx(0, "STATIC", "Nb de ports ouverts :", WS_VISIBLE|WS_CHILD, 167, 115, 150, 13, MainHandle, (HMENU)ID_EDITBOX, hInstance, NULL);    
HWND lblhWnd7 = CreateWindowEx(0, "STATIC", "Temps d'attente :                  ms", WS_VISIBLE|WS_CHILD, 167, 90, 150, 13, MainHandle, (HMENU)ID_EDITBOX, hInstance, NULL);
      
// Crée les 2 EditBox (ordi et IP)
OrdiHandle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "EDIT", "", ES_READONLY|WS_VISIBLE|WS_CHILD|ES_AUTOHSCROLL|ES_NOHIDESEL,
45, 22, 90, 20, MainHandle, (HMENU)ID_EDITBOX, hInstance, NULL);

IPHandle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "EDIT", "", ES_READONLY|WS_VISIBLE|WS_CHILD|ES_AUTOHSCROLL|ES_NOHIDESEL,
45, 47, 90, 20, MainHandle, (HMENU)ID_EDITBOX, hInstance, NULL);

OrdiScanHandle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "EDIT", "", WS_VISIBLE|WS_CHILD|ES_AUTOHSCROLL|ES_NOHIDESEL,
217, 22, 90, 20, MainHandle, (HMENU)ID_EDITBOX, hInstance, NULL);

MinHandle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "EDIT", "", WS_VISIBLE|WS_CHILD|ES_RIGHT|ES_NUMBER|ES_NOHIDESEL,
202, 47, 45, 20, MainHandle, (HMENU)ID_EDITBOX, hInstance, NULL);

MaxHandle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "EDIT", "", WS_VISIBLE|WS_CHILD|ES_RIGHT|ES_NUMBER|ES_NOHIDESEL,
263, 47, 45, 20, MainHandle, (HMENU)ID_EDITBOX, hInstance, NULL);

AttenteHandle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "EDIT", "50", WS_VISIBLE|WS_CHILD|ES_RIGHT|ES_NUMBER|ES_NOHIDESEL,
260, 87, 38, 20, MainHandle, (HMENU)ID_EDITBOX, hInstance, NULL);

ListHandle = CreateWindowEx(WS_EX_CLIENTEDGE, "LISTBOX", NULL, WS_VISIBLE|WS_CHILD|LBS_NOSEL|LBS_NOTIFY|WS_VSCROLL|ES_AUTOVSCROLL, 
5, 100, 150, 100, MainHandle, (HMENU)ID_LISTBOX, hInstance, NULL);

// Cré le Button Scanner
ButtonHandle = CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "Scanner", 
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
167, 140, 66, 25, MainHandle, (HMENU)ID_BUTTON, hInstance, NULL);

// Cré le Button Aide
ButtonAideHandle = CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "Aide", 
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
244, 140, 66, 25, MainHandle, (HMENU)ID_BUTTON_AIDE, hInstance, NULL);

// Cré le Button Effacer
ButtonViderHandle = CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "Effacer", 
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
167, 170, 66, 25, MainHandle, (HMENU)ID_BUTTON_VIDER, hInstance, NULL);

// Cré le Button Quitter
ButtonQuitHandle = CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "Quitter", 
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
244, 170, 66, 25, MainHandle, (HMENU)ID_BUTTON_QUIT, hInstance, NULL);

// Changements des polices
SendMessage(OrdiHandle, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(IPHandle, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(ListHandle, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(OrdiScanHandle, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(MaxHandle, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(MinHandle, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(AttenteHandle, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(ButtonHandle, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(ButtonQuitHandle, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(ButtonViderHandle, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(ButtonAideHandle, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(lblhWnd1, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(lblhWnd2, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(lblhWnd3, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(lblhWnd4, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(lblhWnd5, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(lblhWnd6, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(lblhWnd7, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(lblhWndTitre1, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
SendMessage(lblhWndTitre2, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));

// Appelle la fontion adresseIP
adresseIP();

// Affiche la fenêtre
ShowWindow(MainHandle, SW_SHOW);
// Met à jour la fenêtre
UpdateWindow(MainHandle);

// Recoie et transmet les messages à WinProc
while (GetMessage(&msg, NULL, 0, 0))
{

TranslateMessage(&msg);
DispatchMessage(&msg);

}

// Fin du programme
return msg.wParam;

}

/*************************************************/

// Réception des messages
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

switch (msg)
{
// Ferme le programme
case WM_DESTROY:
if(hhk) UnhookWindowsHookEx(hhk);  // enleve le hook
PostQuitMessage(0);
break;

// Reception des commandes
case WM_COMMAND:
// Détruit la fenètre si on clique sur le boutton quitter
if((LOWORD(wParam) == ID_BUTTON_QUIT) && (HIWORD(wParam) == BN_CLICKED))
	DestroyWindow(hwnd);
// Vide la liste si on à cliquer sur le bouton vider
if((LOWORD(wParam) == ID_BUTTON_VIDER) && (HIWORD(wParam) == BN_CLICKED))
	SendMessage(ListHandle, LB_RESETCONTENT, 0, 0);
// Affiche l'aide si on clique sur le boutton aide
if((LOWORD(wParam) == ID_BUTTON_AIDE) && (HIWORD(wParam) == BN_CLICKED))
    MessageBox(MainHandle, "Ce logiciel permet de scanner plusieurs ports très rapidemment. Ceci afin "
                           "de savoir si votre ordi à été affecté par un trojan ou pour connaître les "
                           "ports ouverts d'un serveur. Vous pouvez augmenter ou diminuer la vitesse en "
                           "choisissant la durée d'attente entre chaque scan (en millisecondes).\n\nSi"
                           " le scan est mauvais et qu'il saute certains ports, il faut le recommencer "
                           "avec une durée plus importante...\n\nPS : Sachez que le fait de scanner les"
                           " ports d'un serveur par exemple vous log directement (l'administrateur peut "
                           "connaître votre IP), donc à utiliser avec précaution pour un éventuel hack "
                           "risqué !!", "Aide", MB_OK);
// Vérifie si on à cliquer sur le bouton
if ((LOWORD(wParam) == ID_BUTTON) && (HIWORD(wParam) == BN_CLICKED))
{

// Va contenir le texte du EditBox
char *Min = NULL;
char *Max = NULL;
char *Attente = NULL;

// Va contenir le nombres de caractères dans le EditBox
unsigned int OrdiLen = 0;
unsigned int MinLen = 0;
unsigned int MaxLen = 0;
unsigned int AttenteLen = 0;

// Récupère le nombres de caractères dans le EditBox
OrdiLen = GetWindowTextLength(OrdiScanHandle);
MinLen = GetWindowTextLength(MinHandle);
MaxLen = GetWindowTextLength(MaxHandle);
AttenteLen = GetWindowTextLength(AttenteHandle);

// S'il n'est pas vide
if (OrdiLen && MinLen && MaxLen && AttenteLen)   
{

// Alloue de la mémoire pour stocker le texte
Ordi = new char[(OrdiLen + 2)];
Min = new char[(MinLen + 2)];
Max = new char[(MaxLen + 2)];
Attente = new char[(AttenteLen + 2)];

// Récupère le texte
OrdiLen = GetWindowText(OrdiScanHandle, Ordi, (OrdiLen + 1));
MinLen = GetWindowText(MinHandle, Min, (MinLen + 1));
MaxLen = GetWindowText(MaxHandle, Max, (MaxLen + 1));
AttenteLen = GetWindowText(AttenteHandle, Attente, (AttenteLen + 1));

// Conversion des variable char en int 
PortMin = atoi(Min);
PortMax = atoi(Max);
AttenteInt = atoi(Attente);

// Si aucune erreur et le EditBox contient bien quelque chose
if (OrdiLen && MinLen && MaxLen && AttenteLen)
{
////////////////////////////Scanneur de ports///////////////////////////////////
if (PortMin>PortMax)
 {
  MessageBox(MainHandle, "Le deuxième nombre doit être plus grand que le premier", "Erreur", MB_ICONERROR | MB_OK);
 }

else
 {
  WSADATA WSAData;                      // tout les prog de
  WSAStartup(MAKEWORD(2,0),&WSAData);   // sockets commence par ca

  struct hostent * sock2;       
  SOCKET sock;               // declare la socket            

  sock2 = gethostbyname(Ordi); 

  if (sock2==NULL) 
    MessageBox(MainHandle, "Impossible de se connecter à cet ordi, dsl...", "Erreur", MB_ICONERROR | MB_OK);
  else
   {
    // Remet les variables utilisés à 0
    PORT=0;     
    NbP=0;
    affichage=0;
    
    CreateThread(NULL, 0, BoucleThread, (LPVOID)PORT, 0, &threadID);   // lance le thread de la boucle
}}               
////////////////////////////////////////////////////////////////////////////////
}
 
if (!OrdiLen || !MinLen || !MaxLen || !AttenteLen)
 {
  MessageBox(MainHandle, "Erreur lors de la récupération du texte", "Erreur", MB_ICONERROR | MB_OK);
 }

// Libère la mémoire
delete [] Ordi;
delete [] Min;
delete [] Max;
delete [] Attente;

}
if (!OrdiLen || !MinLen || !MaxLen || !AttenteLen)
 {
  MessageBox(MainHandle, "Il faut tout remplir bordel...", "Erreur", MB_ICONERROR | MB_OK);
 }
break;
}

default: // Par default...
return DefWindowProc(hwnd, msg, wParam, lParam);
break;

}

return 0;
}

Conclusion :


ATTENTION : vous devez mettre la librairie wsock32 dans les options du compilateur pour que ca marche

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.