PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : TextOut() macht Probleme [C++ & WinAPI]



Ynnus
02.12.2004, 23:16
Hallöchen,

ich orientiere mich gerade an einem Buch über Windowsprogrammierung (mit der WinAPI) in Verbindung mit C++. Dabei gibt es immer wieder Beispielcodes welche nicht funktionieren. Etwa ein Code mit dem WinAPI-Befehl TextOut (hdc, x, y, psText, iLength) ; .
(Das Buch: Windows Programming, by Charles Petzold, Ausgabe 1998)

Ich erhalte immer irgendwelche Fehler bezüglich ungültiger referencen in TextOut. Genaue Fehlermeldung:


[Warning] In function `Z14WndProcnennichP6HWND__jjl':
[Linker error] undefined reference to `TextOutA@20'

[Compiler-log:]

Compiler: Default compiler
Führt g++.exe... aus
g++.exe "C:\Dokumente und Einstellungen\Stefan.HOF\Desktop\Projekte\c++\winAPI\fenster.cpp" -o "C:\Dokumente und Einstellungen\Stefan.HOF\Desktop\Projekte\c++\winAPI\fenster.exe" -g3 -I"D:\Dev-C++\include\c++" -I"D:\Dev-C++\include\c++\mingw32" -I"D:\Dev-C++\include\c++\backward" -I"D:\Dev-C++\include" -L"D:\Dev-C++\lib"
C:\DOKUME~1\Stefan.HOF\LOKALE~1\Temp/ccOEbaaa.o(.text+0x27c): In function `Z7WndProcP6HWND__jjl':
C:/Dokumente und Einstellungen/Stefan.HOF/Desktop/Projekte/c++/winAPI/fenster.cpp:74: undefined reference to `TextOutA@20'

Ausführung beendet
(Ich verwende den Bloodshed Dev C++ Compiler - V. 4.9.8.0).

Dies ist der Code: (Eigentlich nur ein simples Hallo-Welt-Fensterprogramm welches aber schon Probleme macht...):

#include <windows.h>

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int showpref)
{
static TCHAR szAppName[] = TEXT ("HelloWin") ;
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 (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) COLOR_WINDOW ;// (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;

if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, // window class name
TEXT("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters

ShowWindow (hwnd, SW_SHOWNORMAL) ;
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)
{
HDC hdc ;
PAINTSTRUCT ps ;
RECT rect ;
TCHAR zeichen [40] = TEXT("Hallo, Windows XP");
int length = 40;
int pos = 20;

switch (message)
{
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;

GetClientRect (hwnd, &rect) ;

TextOut (hdc, pos, pos, zeichen, length) ;

EndPaint (hwnd, &ps) ;
return 0 ;

case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam);
}

Wenn ich die Zeile mit TextOut() einkommentiere, funktioniert alles wie es soll, es wird ein leeres Fenster erstellt. Mit dieser Zeile sollte eigentlich dann ein Text in dem Clientbereich des Fensters erstellt werden, aber da kommt mir ja diese seltsame Fehlermeldung zuvor.

Ebenso gibt es weitere Beispiele in diesem besagten Buch welche mit TextOut() arbeiten welche nicht funktionieren und immer diesen gleichen Fehler ausgeben, mit der ungültigen Reference in TextOut().
Kennt jemand diesen Fehler oder weiß warum er auftaucht? Es ist ein wenig schlecht wenn man gern das Tutorial verstehen würde aber die Beispiele nicht funktionieren. Liegts vielleicht daran dass die Ausgabe des Buches von 1998 ist?

mfg.

Sunny

Ineluki
03.12.2004, 00:59
ich hab mal ne mutmassung ...

geh mal auf Project->optionen->parameter->linker

und trage ein -lgdi32

bestaetigst mit OK, gehst in deinen Quelltext, fuegst in der Hauptdatei irgendwo ne leerzeile ein, um sicherzugehen, dass er den code fuer geaendert haellt, und garantiert neu compiliert. ohne Leerzeile meint dev-c++ oftmals trotz eines build all nicht alles compilieren und/oder linken zu muessen ....

Dann sollte alles gehen.

Ich hab deinen code auch mal getestet, obs wirklich dadran lag, und bei mir compiliert er fehlerfrei ... auch ohne -lgdi32 ... getestet mit Dev-C++ V. 4.9.9.0, gcc version 3.2 (mingw special 20020817-1)

musst mal sehen, ob in deinem lib verzeichnis eine libgdi32.a drin ist ...

btw ...
(Ich verwende den Bloodshed Dev C++ Compiler - V. 4.9.8.0).
Dev-C++ ist eine IDE und kein Compiler. Der Compiler ist gcc als mingw32.

Gruss Ineluki

Ynnus
03.12.2004, 01:18
Ineluki, du bist mein Retter! Ich war schon am Verzweifeln warum das denn nicht so wollte wie im Buch beschrieben. *FREU* :)

Ich hatte mich auch schon gewundert warum mir das Programm immer neben dem Fenster noch eine Konsole geöffnet hatte. Der Programmtyp stand standard auf Konsolenanwendung in den Optionen.
Noch dazu hatte ich mit Dev C++ erstmal nur eine Quelldatei erstellt ohne Projekt und da kann man die Projektoptionen nicht öffnen und somit nicht festlegen welche Art Programm es ist. Hab jetzt aber das Ganze als Projekt eingebunden.
Danke Ineluki, vielleicht kannst du mir auch noch kurz erklären wo jetzt der Unterschied für den Linker besteht, obs als Console oder Win32 GUI Anwendung eingestellt ist?

Ach ja, im Dev C++ gibts die Möglichkeit der Typuswahl. Es stand vorher, wie gesagt auf Console. Jetzt hab ich es auf Win32 GUI umgestellt und habe jetzt keine Fehler mehr. Dann war es auch nicht nötig, im Linker-Feld den Parameter noch anzugeben.
Allerdings geht es auch, wenn man nur den parameter angibt und den Typ weiterhin auf Console lässt, nur dann öffnet das Programm noch eine Konsole nebenher.
Macht diese Typuswahl im Dev C++ diesen Parameter automatisch für den Linker wenn man da Win32 GUI auswählt? Oder sollte ich den Parameter in jedem Falle zusätzlich noch hinzufügen?


Ich hab deinen code auch mal getestet, obs wirklich dadran lag, und bei mir compiliert er fehlerfrei ... auch ohne -lgdi32 ... getestet mit Dev-C++ V. 4.9.9.0, gcc version 3.2 (mingw special 20020817-1)
Vielleicht steht bei dir standardmäßig der Programmtyp auf GUI-Anwendung? Ich hatte ja nichteinmal ein Projekt erstellt und konnte im Dev C++ somit nicht die Linker-Parameter oder den Programmtyp einsehen oder ändern (Menuitems waren deaktiviert).

//EDIT: libgdi32.a ist im Lib-Ordner drinne, 240 KB. ;)

Ineluki
03.12.2004, 13:46
Ein Windowsprogramm ist etwas von einer Dos-Exe grund verschiedenes ..

Ein Compiler macht aus deinem Code Objectfiles, ohne auf eingebundene Module Ruecksicht zu nehmen. Der Linker macht aus diesen Bausteinen dann erst das fertige Programm.

Wenn du eingestellt hast, dass das Ganze eine Win-Anwendung ist, so linkt der Linker automatisch gegen die standard Windows-Libs, unter anderem auch auf gdi32.lib (libgdi32.a) in welcher erst TextOut definiert ist.

Wenn du das ganze als Consolenanwendung schreibst, linkt er gegen andere Bibliotheken, so dass automatisch ein Dosfenster erzeugt wird. Wenn du ihm dann trotzdem noch sagst, dass TextOut in gdi32.lib gespeichert ist, findet er die Funktion natuerlich , und kann dein Fenster mit Text erzeugen, jedoch bleiben dann die Libs fuer die Console erhalten ... was dennoch sehr nuetzlich sein kann, wenn man schnell debugausgaben oder aehnliches mit printf rauschicken will ...

Natuerlich hatte ich bei meinem Test auf GUI gestellt ... wusste ja nicht, dass du auf Console stehen hattest ^^

Gruss Ineluki

Jesus_666
03.12.2004, 16:26
ohne Leerzeile meint dev-c++ oftmals trotz eines build all nicht alles compilieren und/oder linken zu muessen ....
Ich schätze, daß Dev-C++ sich an die Arbeitsweise von GNU make hält (oder sogar make benutz, kA). make überprüft, welche Teile neu kompiliert werden müssen, indem es nachsieht, welche Quelldateien sich seit dem letzten Mal verändert haben. Das ist praktisch, wenn man zwischen den Builds nur einen Teil des Quellcodes ändert und unpraktisch, wenn man an den Compilerparametern rumschraubt.
Bei make bedeutet das Ziel "all" auch nur, daß alles gebaut wird, wenn es nötig ist.


btw ...
Dev-C++ ist eine IDE und kein Compiler. Der Compiler ist gcc als mingw32.
In, nicht als. MinGW (Minimalist GNU for Windows) ist eine Sammlung von Windows-Ports von bestimmten GNU-Tools wie der GCC oder den binutils (z.B. ld) .

Ich weiß nicht, ob Dev-CPP MSYS mitbringt; das enthält dann Portierungen von Tools wie make oder den fileutils (cp, mv etc.).
Falls man öfter mit CMD arbeitet könnte es übrigens sinnvoll sein, den bin-Ordner von MSYS in %PATH% zu legen - die fileutils sind eine Ecke mächtiger als ihre Windows-Kollegen.