undefined reference to `ChooseColorA@4'



  • Hallo, ich hab mal wieder ein Problem. Da ich keine Ahnung hab, wo der Fehler ist, kommt erstmal ne Menge Quellcode. Ich wäre sehr dankbar, wenn ihr euch das mal Anschauen würdet.
    Stein und Spalte sind selbst geschriebene Klassen.
    Wenn ich den Teil mit ChooseColor rausmache wirds problemlos kompiliert.
    Ein Beispielprogramm aus meinem Buch, das die Funktion verwendet funktioniert
    Edit: Der wichtige Teil ist in LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ ab Zeile 89

    4 Gewinnt.h

    // Windows Header Files:
    #include <windows.h>
    #include <commdlg.h>
    
    //C++ Runtime Header Files
    #include <string>
    #include <vector>
    #include <iostream>
    
    //eigene Header Files
    #include "Spalte.h"
    #include "Resource.h"
    
    //verwendete Konstanten
    const int MAXSTEINE = 6;
    const int ANZSPALTEN = 7;
    
    //globale Variablen
    
    //zweidimensionales Array zum Speichern der gesetzten Steine;
    //0 heisst kein Stein; 1 heißt Stein von Spieler 1; 2 heißt Stein von Spieler 2;
    static BYTE byZustSteine[ANZSPALTEN][MAXSTEINE]={{0}};
    
    //verwendeter Funktionen
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
    LRESULT CALLBACK SpalteWndProc (HWND, UINT, WPARAM, LPARAM);
    BOOL CALLBACK AboutDlgProc (HWND, UINT, WPARAM, LPARAM);
    BOOL CALLBACK SpGwnDlgProc (HWND hDlg, UINT message,WPARAM wParam, LPARAM lParam);
    
    //überprüft ob ein Spieler gewonnen hat
    bool HatGewonnen(BYTE[][MAXSTEINE],BYTE, const int, const int);
    
    BOOL ChooseColor(LPCHOOSECOLOR lpcc);
    
    //eigene Nachrichten
    //WPARAM enthält wessen Farbe geändert wurde
    //LPARAM enthält die Farbe
    UINT PN_CLRCHANGED=WM_APP+1;
    

    4 Gewinnt.cpp

    /*-----------------------------------------------------------------------
      Vier Gewinnt von Jonas Peter.
      Dieses Programm befindet sich noch in der Entwicklung
      -----------------------------------------------------------------------*/
    
    #include "4 Gewinnt.h"
    #include <windows.h>
    #include <commdlg.h>
    
    using namespace std;
    
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        PSTR szCmdLine, int iCmdShow)
    {
         static string sAppName = TEXT ("Vier Gewinnt") ;
         HWND         hwnd ;
         MSG          msg ;
         WNDCLASS     wndclass ;
    
         wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
         wndclass.lpfnWndProc   = WndProc ;
         wndclass.cbClsExtra    = 0 ;
         wndclass.cbWndExtra    = 0;
         wndclass.hInstance     = hInstance ;
         wndclass.hIcon         = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_VIERGEWINNT)) ;
         wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
         wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
         wndclass.lpszMenuName  = MAKEINTRESOURCE(IDR_MENUE) ;
         wndclass.lpszClassName = sAppName.c_str();
    
         if (!RegisterClass (&wndclass))
         {    // UNICODE-Compilierung ist die einzige realistische Fehlermöglichkeit
              MessageBox (NULL, TEXT ("Programm arbeitet mit Unicode und setzt Windows NT voraus!"),
                          sAppName.c_str(), MB_ICONERROR) ;
              return 0 ;
         }
    
         wndclass.lpfnWndProc =SpalteWndProc;
         //Für jedes Childfenster extra Speicherbereich für einen Zeiger vom Typ Spalte anfordern
         wndclass.cbWndExtra =sizeof(long);
    
         wndclass.hIcon=NULL;
         wndclass.lpszClassName="Spalte";
         wndclass.hbrBackground = (HBRUSH) GetStockObject (LTGRAY_BRUSH) ;
    
         RegisterClass (&wndclass);
    
        hwnd = CreateWindow (sAppName.c_str(),                 // Name der Fensterklasse
                    TEXT ("Vier Gewinnt"),  // Fenstertitel
                    WS_OVERLAPPEDWINDOW,
                    CW_USEDEFAULT,                      // X-Position des Fensters
                    CW_USEDEFAULT,                      // Y-Position des Fensters
                    CW_USEDEFAULT,                      // Fensterbreite
                    CW_USEDEFAULT,                      // Fensterhöhe
                    NULL,                               // übergeordnetes Fenster
                    NULL,                               // Menü
                    hInstance,                          // Programm-Kopiezähler (Programm-ID)
                    NULL);                             // zusätzliche Parameter
    
         ShowWindow (hwnd, iCmdShow) ;
         UpdateWindow (hwnd) ;
    
         while (GetMessage (&msg, NULL, 0, 0))
         {
              TranslateMessage (&msg) ;
              DispatchMessage (&msg) ;
         }
         return msg.wParam ;
    }
    
    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
    
        //Handles für die Childfenster
        static HWND hwndSpalte[ANZSPALTEN];
    
        //Größenangaben für die Spalten
        const int lSpalteBreite=50, lSpalteHoehe=lSpalteBreite*MAXSTEINE;
    
        //für die Farbauswahl
        static CHOOSECOLOR  cc;
        static COLORREF     acrCustColors[16];
        static COLORREF     crCurrent=0;
    
         cc.lStructSize    = sizeof (CHOOSECOLOR) ;
         cc.hwndOwner      = NULL ;
         cc.hInstance      = NULL ;
         cc.rgbResult      = RGB (0x80, 0x80, 0x80) ;
         cc.lpCustColors   = acrCustColors ;
         cc.Flags          = CC_RGBINIT | CC_FULLOPEN ;
         cc.lCustData      = 0 ;
         cc.lpfnHook       = NULL ;
         cc.lpTemplateName = NULL ;
    
        switch (message)
        {
    
        case WM_CREATE:
            static HINSTANCE hInstance;
    
            hInstance=((LPCREATESTRUCT) lParam)->hInstance;
    
            //Spalten Erzeugen
            for(int i=1;i<=ANZSPALTEN;i++)
            {
                hwndSpalte[i]=CreateWindow("Spalte",NULL,//KlassenName , Titelleiste
                WS_CHILDWINDOW|WS_VISIBLE, //Fensterstil
                (i*lSpalteBreite),lSpalteBreite, //Position
                lSpalteBreite, lSpalteHoehe, //Breite, Höhe
                hwnd,(HMENU) (i), //Parent Handle,  ChildID
                (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE), //KopieZähler
                NULL);//Extras
            }
    
            return 0 ;
    
        case WM_SYSCOMMAND:
            switch (wParam)
            {
            //Nach Maximieren zum neu zeichnen auffordern
            case SC_MAXIMIZE:
                InvalidateRect(hwnd,NULL,false);
                UpdateWindow(hwnd);
                break;
            default:
                DefWindowProc(hwnd,message,wParam,lParam);
                break;
            }
            return 0;
    
        case WM_COMMAND:
            switch (LOWORD( wParam ))
            {
            case IDM_\1:
                DialogBox( hInstance, MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDlgProc );
                return 0;
            case IDM_OPTIONEN_FARBESP1:
    
                if (ChooseColor(&cc)==TRUE)
                {
                    crCurrent = cc.rgbResult;
                    //Alle Spalten über die Farbänderung informieren
                    for(int i=0;i<ANZSPALTEN;i++)
                    {
                        SendMessage(hwndSpalte[i],PN_CLRCHANGED,(WPARAM)1,(LPARAM)crCurrent);
                    }
    
                }
                return 0;
            }
    
                return 0;
    
        case WM_DESTROY:
            PostQuitMessage (0) ;
            return 0 ;
        }
        return DefWindowProc (hwnd, message, wParam, lParam) ;
    }
    
    LRESULT CALLBACK SpalteWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
    
        HDC             hdc ;
        RECT            rect ;
        PAINTSTRUCT     ps;
        //Zeiger auf den jeweiligen Speicherbereich, in dem die Daten der Spalten sind
        Spalte          *pspSpalte=NULL;
    
        static COLORREF crSteinFarbe=0x0;
        const COLORREF  crSteinRot=RGB(200,0,0),crSteinBlau=RGB(0,0,200);
    
        static BYTE byAktSpieler=1;
        //zweidimensionales Array zum Speichern der gesetzten Steine;
        //0 heisst kein Stein; 1 heißt Stein von Spieler 1; 2 heißt Stein von Spieler 2;
    
        switch (message)
        {
        case WM_CREATE:
            //Größe des Childfensters rausfinden
            GetClientRect(hwnd,&rect);
    
            //Speicherbereich für eine Spalte in der größe des Childfensters anfordern.
            //im extra angeforderten Speicher einen Zeiger auf diesen Bereich speichern
            SetWindowLong(hwnd,0,(long)new Spalte(hwnd, MAXSTEINE, rect.right, rect.bottom,RGB(0,200,0)));
    
            return 0 ;
    
        case WM_PAINT:
            pspSpalte=(Spalte*)GetWindowLong(hwnd,0);
            hdc = BeginPaint(hwnd, &ps);
            pspSpalte->zeichne(hdc);
            EndPaint(hwnd, &ps);
            return 0;
    
        case WM_LBUTTONUP:
            //Überprüfen welcher Spielr Aktiv ist und entsprechende Farbe setzen
            if(1==byAktSpieler)
            {
                crSteinFarbe=crSteinRot;
            }
            else
            {
                crSteinFarbe=crSteinBlau;
            }
    
            //Zeiger auf das Spaltenobjekt holen, der zum aktuellen Fenster gehört
            pspSpalte=(Spalte*)GetWindowLong(hwnd,0);
    
            //Stein in der aktuellen Farbe setzen
            //Wenn die Spalte voll ist, wird der Funktionsaufruf beendet,
            //ohne dass byZustSteine geändert wird und byAktSpieler
            if(!pspSpalte->setzeStein(crSteinFarbe))
            {
                return 0;
            }
            //In byZustSteine speichern, wo der Stein gesetzt wurde
            byZustSteine[GetWindowLong(hwnd,GWL_ID)][pspSpalte->getFuellHoehe()]=byAktSpieler;
    
            //Fenster zum neu zeichnen auffordern
            InvalidateRect(hwnd,NULL,false);
            UpdateWindow(hwnd);
    
            //Steine zu testzwecken ausgeben
            for(int j=0;j<MAXSTEINE;j++)
            {
                cout << endl;
                for(int i=0;i<ANZSPALTEN;i++)
                {
                    cout << (int)byZustSteine[i][j];
                }
            }
    
            //Überprüfen, ob der Spieler gewonnen hat. Wenn ja Programm beenden
            if(HatGewonnen(byZustSteine,byAktSpieler,GetWindowLong(hwnd,GWL_ID),pspSpalte->getFuellHoehe()))
            {
                //Wenn Spieler 1 Aktiv SP1GWN Dialogbox aufrufen
                if(1==byAktSpieler)
                {
                    DialogBox((HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), MAKEINTRESOURCE(IDD_SP1GWN), hwnd, SpGwnDlgProc );
                }
                //Wenn Spieler 2 Aktiv SP2GWN Dialogbox auffrufen
                else
                {
                    DialogBox((HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), MAKEINTRESOURCE(IDD_SP2GWN), hwnd, SpGwnDlgProc );
                }
    
                SendMessage(GetParent(hwnd), WM_DESTROY, 0, 0);
            }
            //anderen Spieler als aktiv setzen
            if(1==byAktSpieler)
            {
                byAktSpieler=2;
            }
            else
            {
                byAktSpieler=1;
            }
    
            return 0;
    
        case WM_DESTROY:
            pspSpalte=(Spalte*)GetWindowLong(hwnd,0);
            delete pspSpalte;
            PostQuitMessage (0) ;
            return 0 ;
        }
        return DefWindowProc (hwnd, message, wParam, lParam) ;
    }
    
    //Prozedur für den About dialog
    BOOL CALLBACK AboutDlgProc (HWND hDlg, UINT message,
                                WPARAM wParam, LPARAM lParam)
    {
         switch (message)
         {
         case WM_INITDIALOG :
              return TRUE ;
    
         case WM_COMMAND :
              switch (LOWORD (wParam))
              {
              case IDOK :
              case IDCANCEL :
                   EndDialog (hDlg, 0) ;
                   return TRUE ;
              }
              break ;
         }
         return FALSE ;
    }
    
    //Prozedur für den About dialog
    BOOL CALLBACK SpGwnDlgProc (HWND hDlg, UINT message,
                                WPARAM wParam, LPARAM lParam)
    {
         switch (message)
         {
         case WM_INITDIALOG :
              return TRUE ;
    
         case WM_COMMAND :
              switch (LOWORD (wParam))
              {
              case IDOK :
              case IDCANCEL :
                   EndDialog (hDlg, 0) ;
                   return TRUE ;
              }
              break ;
         }
         return FALSE ;
    }
    

    Buildlog

    -------------- Build: Debug in Vier Gewinnt ---------------
    Compiling: 4 Gewinnt.cpp
    E:\99VerlegtvonC\Eigene Dateien\Schule\IT Projekt\Vier Gewinnt\4 Gewinnt.cpp:19: warning: unused parameter 'hPrevInstance'
    E:\99VerlegtvonC\Eigene Dateien\Schule\IT Projekt\Vier Gewinnt\4 Gewinnt.cpp:19: warning: unused parameter 'szCmdLine'
    E:\99VerlegtvonC\Eigene Dateien\Schule\IT Projekt\Vier Gewinnt\4 Gewinnt.cpp:286: warning: unused parameter 'lParam'
    E:\99VerlegtvonC\Eigene Dateien\Schule\IT Projekt\Vier Gewinnt\4 Gewinnt.cpp:308: warning: unused parameter 'lParam'
    Linking console executable: bin\Debug\Vier Gewinnt.exe
    obj\Debug\4 Gewinnt.o: In function `Z7WndProcP6HWND__jjl':E:/99VerlegtvonC/Eigene Dateien/Schule/IT Projekt/Vier Gewinnt/4 Gewinnt.cpp:149: undefined reference to `ChooseColorA@4'
    collect2: ld returned 1 exit status
    Process terminated with status 1 (0 minutes, 2 seconds)
    1 errors, 4 warnings

    Held



  • http://msdn2.microsoft.com/en-us/library/ms646912.aspx sagt du musst Comdlg32.lib einbinden!



  • Die müsste ich irgendwo in den Einstellungen bei Codeblocks schon eingebunden haben. Ein anderes Programm, dass diese Funktion benutzt funktioniert ja ohne Probleme mit den selben Einstellungen. Deshalb bin ich ja so ratlos.
    Ich erstell jetzt mal ein neues Projekt mit Standardeinstellungen und schau ob's funktioniert.

    Edit: geht immer noch nicht. Ich hab mal das ganze Projekt hochgeladen.
    http://rapidshare.com/files/35458358/Vier_Gewinnt.rar.html
    Ich wäre wirklich froh, wenn sich jemand die Zeit nähme sich das mal anzuschauen.

    Held



  • Buildlog schrieb:

    undefined reference to `ChooseColorA@4'

    Der sucht den "ChooseColor ()", den Du in der "4 Gewinnt.h" zwar deklariert hast, aber nirgendwo definiert.
    Kommentiere die Deklaration mal aus :

    // in 4 Gewinnt.h
    
    // BOOL ChooseColor(LPCHOOSECOLOR lpcc);
    

  • Mod

    Wie geeky schon schrieb, du musst die comdlg32.lib einbinden.

    Ansonsten kannst Du die Deklaration von BOOL ChooseColor(LPCHOOSECOLOR lpcc); auch weglassen. Die ist ja in der commdlg.h schon drin.



  • Ich hab die Bibliothek nochmal explizit beim Linker angegeben und jetzt funktioniert's auch. Ich dachte, es reicht wenn ich den übergeordneten Ordner angebe.
    Ich frage mich nur noch, warum dieses Programm funktioniert, ohne dass ich die Bibliothek einbinde.

    /*---------------------------------------------------
       COLORS3.C -- COLORS3.C -- Farbauswahl über COMMDLG
                    (c) Charles Petzold, 1998
      ---------------------------------------------------*/
    
    #include <windows.h>
    #include <commdlg.h>
    
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        PSTR szCmdLine, int iCmdShow)
    {
         static CHOOSECOLOR cc ;
         static COLORREF    crCustColors[16] ;
    
         cc.lStructSize    = sizeof (CHOOSECOLOR) ;
         cc.hwndOwner      = NULL ;
         cc.hInstance      = NULL ;
         cc.rgbResult      = RGB (0x80, 0x80, 0x80) ;
         cc.lpCustColors   = crCustColors ;
         cc.Flags          = CC_RGBINIT | CC_FULLOPEN ;
         cc.lCustData      = 0 ;
         cc.lpfnHook       = NULL ;
         cc.lpTemplateName = NULL ;
    
         return ChooseColor (&cc) ;
    }
    

  • Mod

    In diesem Programm sehe ich aber nicht welche Linker Optionen Du angegeben hast.
    Zusätzlich gint es auch #pragma comment(lib,...) was ich imer verwende.



  • Du kannst es bei dir mal ausprobieren. Ich bin mir ziemlich sicher, dass ich die Bibliothek beim Linker nicht explizit angegeben habe. Aber eigentlich ist es egal, Hauptsache mein Programm läuft.
    Danke für die geduldige Hilfe.


Anmelden zum Antworten