IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C++ Discussion :

Débuter en Programation win32


Sujet :

C++

  1. #1
    Futur Membre du Club
    Inscrit en
    Janvier 2009
    Messages
    13
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 13
    Points : 7
    Points
    7
    Par défaut Débuter en Programation win32
    Bonjour à tous, je fais mes premiers essais de programmation avec un projet win32.
    Je commence comme aux tous débuts avec hello World mais j’ai vraiment un problème avec ce code source.
    Je suis en panne d’idées, pourriez vous me dire ce qui coince?
    Merci a vous
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    // projet-win -32 -1.cpp : définit le point d'entrée pour l'application.
    //
     
    #include "stdafx.h"
    #include "projet-win -32 -1.h"
    #define MAX_LOADSTRING 100
     
    // Variables globales*:
    HINSTANCE hInst;								// instance actuelle
    TCHAR szTitle[MAX_LOADSTRING];					// Le texte de la barre de titre
    TCHAR szWindowClass[MAX_LOADSTRING];			// le nom de la classe de fenêtre principale
     
    // Pré-déclarations des fonctions incluses dans ce module de code*:
    ATOM				MyRegisterClass(HINSTANCE hInstance);
    BOOL				InitInstance(HINSTANCE, int);
    LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
    LRESULT CALLBACK	About(HWND, UINT, WPARAM, LPARAM);
     
    int APIENTRY _tWinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPTSTR    lpCmdLine,
                         int       nCmdShow)
    {
     	// TODO*: placez ici le code.
     
    	MSG msg;
    	HACCEL hAccelTable;
     
    	// Initialise les chaînes globales
    	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    	LoadString(hInstance, IDC_PROJETWIN321, szWindowClass, MAX_LOADSTRING);
    	MyRegisterClass(hInstance);
     
    	// Effectue l'initialisation de l'application*:
    	if (!InitInstance (hInstance, nCmdShow)) 
    	{
     
    		return FALSE;
    	}
     
    	hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_PROJETWIN321);
     
    	// Boucle de messages principale*:
    	while (GetMessage(&msg, NULL, 0, 0)) 
    	{
    		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
    		{
    			TranslateMessage(&msg);
    			DispatchMessage(&msg);
    		}
    	}
     
    	return (int) msg.wParam;
    }
     
     
     
    //
    //  FONCTION*: MyRegisterClass()
    //
    //  BUT*: inscrit la classe de fenêtre.
    //
    //  COMMENTAIRES*:
    //
    //    Cette fonction et son utilisation sont nécessaires uniquement si vous souhaitez que ce code
    //    soit compatible avec les systèmes Win32 avant la fonction 'RegisterClassEx'
    //    qui a été ajoutée à Windows*95. Il est important d'appeler cette fonction
    //    afin que l'application dispose des petites icônes correctes qui lui sont
    //    associées.
    //
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
    	WNDCLASSEX wcex;
     
    	wcex.cbSize = sizeof(WNDCLASSEX); 
     
    	wcex.style			= CS_HREDRAW | CS_VREDRAW;
    	wcex.lpfnWndProc	= (WNDPROC)WndProc;
    	wcex.cbClsExtra		= 0;
    	wcex.cbWndExtra		= 0;
    	wcex.hInstance		= hInstance;
    	wcex.hIcon			= LoadIcon(hInstance, (LPCTSTR)IDI_PROJETWIN321);
    	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
    	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
    	wcex.lpszMenuName	= (LPCTSTR)IDC_PROJETWIN321;
    	wcex.lpszClassName	= szWindowClass;
    	wcex.hIconSm		= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
     
    	return RegisterClassEx(&wcex);
    }
     
    //
    //   FONCTION*: InitInstance(HANDLE, int)
    //
    //   BUT*: enregistre le handle de l'instance et crée une fenêtre principale
    //
    //   COMMENTAIRES*:
    //
    //        Dans cette fonction, nous enregistrons le handle de l'instance dans une variable globale, puis
    //        créons et affichons la fenêtre principale du programme.
    //
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
       HWND hWnd;
     
       hInst = hInstance; // Stocke le handle d'instance dans la variable globale
     
       hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
     
       if (!hWnd)
       {
          return FALSE;
       }
     
       ShowWindow(hWnd, nCmdShow);
       UpdateWindow(hWnd);
     
       return TRUE;
    }
     
    //
    //  FONCTION*: WndProc(HWND, unsigned, WORD, LONG)
    //
    //  BUT*:  traite les messages pour la fenêtre principale.
    //
    //  WM_COMMAND	- traite le menu de l'application
    //  WM_PAINT	- dessine la fenêtre principale
    //  WM_DESTROY	- génère un message d'arrêt et retourne
    //
    //
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	int wmId, wmEvent;
    	PAINTSTRUCT ps;
    	HDC hdc;
     
    	switch (message) 
    	{
    	case WM_COMMAND:
    		wmId    = LOWORD(wParam); 
    		wmEvent = HIWORD(wParam); 
    		// Analyse les sélections de menu*:
    		switch (wmId)
    		{
    		case IDM_ABOUT:
    			DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
    			break;
    		case IDM_EXIT:
    			DestroyWindow(hWnd);
    			break;
    		default:
    			return DefWindowProc(hWnd, message, wParam, lParam);
    		}
    		break;
    	case WM_PAINT:
    		hdc = BeginPaint(hWnd, &ps);
    		// TODO*: ajoutez ici le code de dessin...
     
     
    		SetBkMode(hdc,TRANSPARENT);
    		DrawText(hdc,
    			"Mes début en C++ ",
     
    			-1,
    			& aRect,
    			DT_SINGLELINE|
    			DT_CENTER|
    			DT_VCENTER);
     
     
    		EndPaint(hWnd, &ps);
    		break;
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		break;
    	default:
    		return DefWindowProc(hWnd, message, wParam, lParam);
    	}
    	return 0;
    }
     
    // Gestionnaire de messages pour la boîte de dialogue À propos de.
    LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	switch (message)
    	{
    	case WM_INITDIALOG:
    		return TRUE;
     
    	case WM_COMMAND:
    		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
    		{
    			EndDialog(hDlg, LOWORD(wParam));
    			return TRUE;
    		}
    		break;
    	}
    	return FALSE;
    }

  2. #2
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 860
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 860
    Points : 219 062
    Points
    219 062
    Billets dans le blog
    120
    Par défaut
    Bonjour,

    Je ne comprends pas ton problème.
    Visual Studion ( ou autre IDE que t'utilise ) t'indique une erreur?
    Ou alors est ce pendant l'execution que cela coince ?

    Je ne peux pas tester sur le coup je suis pas sous windows...
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  3. #3
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    J'ai l'impression qu'il manque la déclaration et l'initialisation de la variable aRect passée à DrawText()...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  4. #4
    Futur Membre du Club
    Inscrit en
    Janvier 2009
    Messages
    13
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 13
    Points : 7
    Points
    7
    Par défaut
    Merci a vous mais je vais chercher plus en profondeur et reprendre tout le code , j’utilise VS.NET 2003 et lui aussi à ses bugs même avec un code source qui est cohérent
    Trouver une erreur de syntaxe ce n’est pas trop dure mais trouver le bug du compilo c’est vraiment prise de tête quand il y à 100 a 200 lignes de code.
    Je pense quand même que Médinoc n’est pas trop loin de la vérité mais avec VS.NET quand la compilation à eu lieu et qu’une déclaration n’était pas correct et bien cherche !!!
    Il m’est quelque fois arrivé d’avoir à faire un copier coller du code pour me sortir d’affaire

  5. #5
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Points : 50 367
    Points
    50 367
    Par défaut
    Citation Envoyé par yvesb73 Voir le message
    Merci a vous mais je vais chercher plus en profondeur et reprendre tout le code , j’utilise VS.NET 2003 et lui aussi à ses bugs même avec un code source qui est cohérent
    Trouver une erreur de syntaxe ce n’est pas trop dure mais trouver le bug du compilo c’est vraiment prise de tête quand il y à 100 a 200 lignes de code.
    Faut pas rejeter la faute au compilateur, je suppose que si tu élèves le niveau de warning, tu aurais une erreur du genre "variable 'machin' may be used before set"
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  6. #6
    Futur Membre du Club
    Inscrit en
    Janvier 2009
    Messages
    13
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 13
    Points : 7
    Points
    7
    Par défaut
    Citation Envoyé par ram-0000 Voir le message
    Faut pas rejeter la faute au compilateur, je suppose que si tu élèves le niveau de warning, tu aurais une erreur du genre "variable 'machin' may be used before set"


    Non je ne mets pas systématiquement le compilateur en cause bien au contraire mais c’est une éventualité que je n’écarte pas pour avoir passé des heures à chercher une erreur de syntaxe qui n’existait pas.

  7. #7
    Futur Membre du Club
    Inscrit en
    Janvier 2009
    Messages
    13
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 13
    Points : 7
    Points
    7
    Par défaut
    Ok problème réglé, j’avais le problème devant les yeux voici le code.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
     
    #include "stdafx.h"
    #include "projet-win -32 -1.h"
    #define MAX_LOADSTRING 100
     
    // Variables globales*:
    HINSTANCE hInst;								// instance actuelle
    TCHAR szTitle[MAX_LOADSTRING];					// Le texte de la barre de titre
    TCHAR szWindowClass[MAX_LOADSTRING];			// le nom de la classe de fenêtre principale
     
    // Pré-déclarations des fonctions incluses dans ce module de code*:
    ATOM				MyRegisterClass(HINSTANCE hInstance);
    BOOL				InitInstance(HINSTANCE, int);
    LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
    LRESULT CALLBACK	About(HWND, UINT, WPARAM, LPARAM);
     
    int APIENTRY _tWinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPTSTR    lpCmdLine,
                         int       nCmdShow)
    {
     	// TODO*: placez ici le code.
     
    	MSG msg;
    	HACCEL hAccelTable;
     
    	// Initialise les chaînes globales
    	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    	LoadString(hInstance, IDC_PROJETWIN321, szWindowClass, MAX_LOADSTRING);
    	MyRegisterClass(hInstance);
     
    	// Effectue l'initialisation de l'application*:
    	if (!InitInstance (hInstance, nCmdShow)) 
    	{
     
    		return FALSE;
    	}
     
    	hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_PROJETWIN321);
     
    	// Boucle de messages principale*:
    	while (GetMessage(&msg, NULL, 0, 0)) 
    	{
    		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
    		{
    			TranslateMessage(&msg);
    			DispatchMessage(&msg);
    		}
    	}
     
    	return (int) msg.wParam;
    }
     
    //
    //  FONCTION*: MyRegisterClass()
    //
    //  BUT*: inscrit la classe de fenêtre.
    //
    //  COMMENTAIRES*:
    //
    //    Cette fonction et son utilisation sont nécessaires uniquement si vous souhaitez que ce code
    //    soit compatible avec les systèmes Win32 avant la fonction 'RegisterClassEx'
    //    qui a été ajoutée à Windows*95. Il est important d'appeler cette fonction
    //    afin que l'application dispose des petites icônes correctes qui lui sont
    //    associées.
    //
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
    	WNDCLASSEX wcex;
     
    	wcex.cbSize = sizeof(WNDCLASSEX); 
     
    	wcex.style			= CS_HREDRAW | CS_VREDRAW;
    	wcex.lpfnWndProc	= (WNDPROC)WndProc;
    	wcex.cbClsExtra		= 0;
    	wcex.cbWndExtra		= 0;
    	wcex.hInstance		= hInstance;
    	wcex.hIcon			= LoadIcon(hInstance, (LPCTSTR)IDI_PROJETWIN321);
    	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
    	wcex.hbrBackground	= (HBRUSH)( GRAY_BRUSH);//COLOR_WINDOW+1  GRAY_BRUSH
    	wcex.lpszMenuName	= (LPCTSTR)IDC_PROJETWIN321;
    	wcex.lpszClassName	= szWindowClass;
    	wcex.hIconSm		= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
     
    	return RegisterClassEx(&wcex);
    }
     
    //
    //   FONCTION*: InitInstance(HANDLE, int)
    //
    //   BUT*: enregistre le handle de l'instance et crée une fenêtre principale
    //
    //   COMMENTAIRES*:
    //
    //        Dans cette fonction, nous enregistrons le handle de l'instance dans une variable globale, puis
    //        créons et affichons la fenêtre principale du programme.
    //
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
       HWND hWnd;
     
       hInst = hInstance; // Stocke le handle d'instance dans la variable globale
     
       hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
     
       if (!hWnd)
       {
          return FALSE;
       }
     
       ShowWindow(hWnd, nCmdShow);
       UpdateWindow(hWnd);
     
       return TRUE;
    }
     
    //
    //  FONCTION*: WndProc(HWND, unsigned, WORD, LONG)
    //
    //  BUT*:  traite les messages pour la fenêtre principale.
    //
    //  WM_COMMAND	- traite le menu de l'application
    //  WM_PAINT	- dessine la fenêtre principale
    //  WM_DESTROY	- génère un message d'arrêt et retourne
    //
    //
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	int wmId, wmEvent;
    	PAINTSTRUCT ps;
    	HDC hdc;                 
    	switch (message) 
    	{
    	case WM_COMMAND:
    		wmId    = LOWORD(wParam); 
    		wmEvent = HIWORD(wParam); 
    		// Analyse les sélections de menu*:
    		switch (wmId)
    		{
    		case IDM_ABOUT:
    			DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
    			break;
    		case IDM_EXIT:
    			DestroyWindow(hWnd);
    			break;
    		default:
    			return DefWindowProc(hWnd, message, wParam, lParam);
    		}
    		break;
     
    	    case WM_PAINT:
    		hdc = BeginPaint(hWnd, &ps);
    		RECT aRect;                     
    		//TODO*: ajoutez ici le code de dessin...
    		GetClientRect(hWnd, &aRect);
    		SetBkMode(hdc,TRANSPARENT);                  
    		DrawText(hdc,"Mon premier programme win32 , 2 ou 3 DAFALGANS ,une bonne nuit de sommeil et le problème est réglé.",
    		-1,&aRect,                                                                
            DT_SINGLELINE|                          
            DT_CENTER|                            
            DT_VCENTER);         
     
    		EndPaint(hWnd, &ps); // Fin de traitement du message
    		break;
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		break;
    	default:
    		return DefWindowProc(hWnd, message, wParam, lParam);
    	}
    	return 0;
    }
     
    // Gestionnaire de messages pour la boîte de dialogue À propos de.
    LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	switch (message)
    	{
    	case WM_INITDIALOG:
    		return TRUE;
     
    	case WM_COMMAND:
    		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
    		{
    			EndDialog(hDlg, LOWORD(wParam));
    			return TRUE;
    		}
    		break;
    	}
    	return FALSE;
    }

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Quel logiciel (EDI) pour débuter en programmation ?
    Par mimosa69 dans le forum Débats sur le développement - Le Best Of
    Réponses: 13
    Dernier message: 17/01/2016, 16h45
  2. Débat : quelle distribution Linux choisir pour débuter ?
    Par Anonymous dans le forum Distributions
    Réponses: 227
    Dernier message: 18/02/2015, 10h09
  3. Réponses: 0
    Dernier message: 05/06/2014, 12h02
  4. utiliser les tag [MFC] [Win32] [.NET] [C++/CLI]
    Par hiko-seijuro dans le forum Visual C++
    Réponses: 8
    Dernier message: 08/06/2005, 15h57
  5. Comment débuter en programmation ?
    Par Marc Lussac dans le forum Débuter
    Réponses: 0
    Dernier message: 08/04/2002, 11h29

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo