FTP-Client
-
Hallo,
ich habe mir das Buch Windows-Programmierung von C. Petzold gekauft und ein paar Probleme mit einem Beispielprogramm.
Da der "originale" Code genau die gleichen Fehler auswirft, bin ich langsam mit meinem Latein am Ende.
Hier der Code:
#include <windows.h> #include <wininet.h> #include <process.h> #include "resource.h" //Selbstdefinierte Nachrichten für WndProc #define WM_USER_CHECKFILES (WM_USER + 1) #define WM_USER_GETFILES (WM_USER + 2) //Informationen für den FTP-Download #define FTPSERVER TEXT ("ftp.petzold.com") #define DIRECTORY TEXT ("cpetzold.com/ProgWin/UpdDemo") #define TEMPLATE TEXT ("UD??????.TXT") //Strukturen für Dateinamen und Inhalte typedef struct { TCHAR * szFilename; char * szContents; } FILEINFO; typedef struct { int iNum; FILEINFO info[1]; } FILELIST; //Kommunikationsstruktur für zweiten Thread typedef struct { BOOL bContinue; HWND hwnd; } PARAMS; //forward-Deklaration LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM); VOID FtpThread(PVOID); VOID ButtonSwitch(HWND, HWND, TCHAR *); FILELIST * GetFileList(VOID); int Compare(const FILEINFO*, const FILEINFO*); //Globale Variablen HINSTANCE hInst; TCHAR szAppName[] = TEXT("SmashFTP"); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { HWND hwnd; MSG msg; WNDCLASS wndclass; hInst = hInstance; wndclass.style = 0; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = NULL; wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if(!RegisterClass(&wndclass)) { //UNICODE-Kompilierung ist die einzige realistische Fehlermöglichkeit MessageBox(NULL, TEXT("Programm arbeitet mit Unicode und setzt Windows NT voraus!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, TEXT("SmashFTP blabla"), WS_OVERLAPPEDWINDOW | WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); //Verbindungsaufnahme und Prüfung, ob der FTP-Server aktualisierte Dateiversion zu bieten hat SendMessage(hwnd, WM_USER_CHECKFILES, 0, 0); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static FILELIST *plist; static int cxClient, cyClient, cxChar, cyChar; HDC hdc; int i; PAINTSTRUCT ps; SCROLLINFO si; SYSTEMTIME st; TCHAR szFilename[MAX_PATH]; switch(message) { case WM_CREATE: cxChar = LOWORD(GetDialogBaseUnits()); cyChar = HIWORD(GetDialogBaseUnits()); return 0; case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_RANGE | SIF_PAGE; si.nMin = 0; si.nMax = plist ? plist->iNum-1:0; si.nPage = cyClient/cyChar; SetScrollInfo(hwnd, SB_VERT, &si, TRUE); return 0; case WM_VSCROLL: si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; GetScrollInfo(hwnd, SB_VERT, &si); switch(LOWORD(wParam)) { case SB_LINEDOWN: si.nPos += 1; break; case SB_LINEUP: si.nPage -= 1; break; case SB_PAGEDOWN: si.nPos += si.nPage; break; case SB_PAGEUP: si.nPos -= si.nPage; break; case SB_THUMBPOSITION: si.nPos = HIWORD(wParam); break; default: return 0; } si.fMask = SIF_POS; SetScrollInfo(hwnd, SB_VERT, &si, TRUE); InvalidateRect(hwnd, NULL, TRUE); return 0; case WM_USER_CHECKFILES: //Systemzeit ermitteln, aus Monat und Jahr einen Dateinamen bilden GetSystemTime(&st); wsprintf(szFilename, TEXT("UD%04%02i.TXT"), st.wYear, st.wMonth); //Gibt es diese Datei lokal? Wenn ja, gleich weiter mit einem Download if(GetFileAttributes(szFilename) != (DWORD)-1) { SendMessage(hwnd, WM_USER_GETFILES, 0, 0); return 0; } //Ansonsten neueste Datei vom FTP-Server holen. Zuerst aber prüfen, ob der Zieldatenträger keine CD-ROM ist! if(GetDriveType(NULL) == DRIVE_CDROM) { MessageBox(hwnd, TEXT("Dieses Programm schreibt in sein eignes Verzeichnis und läßt sich nicht von CD aus ausführen!"), szAppName, MB_OK | MB_ICONEXCLAMATION); return 0; } //Rückfrage an den Benutzer, ob Internetzugriff erwünscht ist if(IDYES == MessageBox(hwnd, TEXT("Information aus dem Internet aktualisieren?"), szAppName, MB_YESNO | MB_ICONQUESTION)) //Dialogfeld anzeigen DialogBox(hInst, szAppName, hwnd, DlgProc); //Anzeige aktualisieren SendMessage(hwnd, WM_USER_GETFILES, 0, 0); case WM_USER_GETFILES: SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); //Dateiliste vom lokalen Datenträger lesen plist = GetFileList(); ShowCursor(FALSE); SetCursor(LoadCursor(NULL, IDC_ARROW)); //WM_SIZE-Nachricht zur Anpassung der Bildlaufleiste erzeugen SendMessage(hwnd, WM_SIZE, 0, MAKELONG(cxClient, cyClient)); InvalidateRect(hwnd, NULL, TRUE); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); SetTextAlign(hdc, TA_UPDATECP); si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS; GetScrollInfo(hwnd, SB_VERT, &si); if(plist) { for(i=0; i<plist->iNum; i++) { MoveToEx(hdc, cxChar, (i-si.nPos)*cyChar, NULL); TextOut(hdc, 0, 0, plist->info[i].szFilename, lstrlen(plist->info[i].szFilename)); TextOut(hdc, 0, 0, TEXT(": "), 2); TextOutA(hdc, 0, 0, plist->info[i].szContents, strlen(plist->info[i].szContents)); } } EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); } BOOL CALLBACK DlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static PARAMS params; switch(message) { case WM_INITDIALOG: params.bContinue = TRUE; params.hwnd = hwnd; _beginthread(FtpThread, 0, ¶ms); return true; case WM_COMMAND: switch(LOWORD (wParam)) { case IDCANCEL: //Benutzer bricht Download ab params.bContinue = FALSE; return TRUE; case IDOK: EndDialog(hwnd, 0); return TRUE; } } return FALSE; } //FtpThread: Liest Dateien von FTP-Server und kopiert sie auf lokalen Datenträger void FtpThread(PVOID parg) { BOOL bSuccess; HINTERNET hIntSession, hFtpSession, hFind; HWND hwndStatus, hwndButton; PARAMS *pparams; TCHAR szBuffer[64]; WIN32_FIND_DATA finddata; pparams = parg; hwndStatus = GetDlgItem(pparams->hwnd, IDC_STATUS); hwndButton = GetDlgItem(pparams->hwnd, IDCANCEL); //Internet-Sitzung anlegen hIntSession = InternetOpen(szAppName, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0) ; if(hIntSession == NULL) { wsprintf(szBuffer, TEXT("InternetOpen: Fehler %i"), GetLastError()); ButtonSwitch(hwndStatus, hwndButton, szBuffer); _endthread(); } SetWindowText(hwndStatus, TEXT("Internet-Sitzung eröffnet...")); //Hat der Besitzer "Abbrechen" geklickt? if(!pparams->bContinue) { InternetCloseHandle(hIntSession); ButtonSwitch(hwndStatus, hwndButton, NULL); _endthread(); } //FTP-Sitzung anlegen hFtpSession = InternetConnect(hIntSession, FTPSERVER, INTERNET_DEFAULT_FTP_PORT, NULL, NULL, INTERNET_SERVICE_FTP, 0, 0); if(hFtpSession == NULL) { InternetCloseHandle(hIntSession); wsprintf(szBuffer, TEXT("InternetConnect: Fehler %i", GetLastError())); ButtonSwitch(hwndStatus, hwndButton, NULL); _endthread(); } SetWindowText(hwndStatus, TEXT("FTP-Sitzung eröffnet...")); //Hat der Besitzer "Abbrechen" geklickt? if(!pparams->bContinue) { InternetCloseHandle(hFtpSession); InternetCloseHandle(hIntSession); ButtonSwitch(hwndStatus, hwndButton, NULL); _endthread(); } //FTP-Verzeichnis wählen bSuccess = FtpSetCurrentDirectory(hFtpSession, DIRECTORY); if(!bSuccess) { InternetCloseHandle(hFtpSession); InternetCloseHandle(hIntSession); wsprintf(szBuffer, TEXT("Fehler beim Wechsel ins FTP-Verzeicnis %s"), DIRECTORY); ButtonSwitch(hwndStatus, hwndButton, NULL); _endthread(); } SetWindowText(hwndStatus, TEXT("Verzeichnis gefunden...")); //Hat Benutzer "Abbrechen" geklickt? if(!pparams->bContinue) { InternetCloseHandle(hFtpSession); InternetCloseHandle(hIntSession); ButtonSwitch(hwndStatus, hwndButton, NULL); _endthread(); } //Erste Datei lesen, die ins Suchmuster passt hFind = FtpFindFirstFile(hFtpSession, TEMPLATE, &finddata, 0, 0); if(hFind == NULL) { InternetCloseHandle(hFtpSession); InternetCloseHandle(hIntSession); ButtonSwitch(hwndStatus, hwndButton, TEXT("Datei(en) nicht gefunden")); _endthread(); } do { if(!pparams->bContinue) //"Abbrechen" { InternetCloseHandle(hFind); InternetCloseHandle(hFtpSession); InternetCloseHandle(hIntSession); ButtonSwitch(hwndStatus, hwndButton, NULL); _endthread(); } //Datei vom FTP-Server auf den lokalen Datenträger kopieren - aber nur, wenn sie dort noch nicht existiert wsprintf(szBuffer, TEXT("Lese Date $s..."), finddata.cFileName, TRUE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_BINARY, 0); } while(InternetFindNextFile(hFind, &finddata)); InternetCloseHandle(hFind); InternetCloseHandle(hFtpSession); InternetCloseHandle(hIntSession); ButtonSwitch(hwndStatus, hwndButton, TEXT("Download aus dem Internet beendet")); } // ButtonSwitch: Ausgabe der letzten Statusmeldung und Umbennenung der Schaltfläche "Abbrechen" in OK VOID ButtonSwitch(HWND hwndStatus, HWND hwndButton, TCHAR *szText) { if(szText) SetWindowText(hwndStatus, szText); else SetWindowText(hwndStatus, TEXT("Internet-Sitzung abgebrochen")); SetWindowText(hwndButton, TEXT("OK")); SetWindowLong(hwndButton, GWL_ID, IDOK); } //GetFileList: Daten von lokalem Datenträger lesen, Namen und Inhalte speichern FILELIST *GetFileList(void) { DWORD dwRead; FILELIST *plist; HANDLE hFile, hFind; int iSize, iNum; WIN32_FIND_DATA finddata; hFind = FindFirstFile(TEMPLATE, &finddata); if(hFind == INVALID_HANDLE_VALUE) return NULL; plist = NULL; iNum = 0; do { //Datei öffnen und Größe ermitteln hFile = CreateFile(finddata.cFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if(hFile == INVALID_HANDLE_VALUE) continue; iSize = GetFileSize(hFile, NULL); if(iSize == (DWORD)-1) { CloseHandle(hFile); continue; } //FILELIST-Struktur für den neuen Eintrag umkopieren und vergrößern plist = realloc(plist, sizeof(FILELIST)+iNum*sizeof(FILEINFO)); //Speicherplatz für den Dateinamen anfordern, Dateinamen speichern plist->info[iNum].szFilename = malloc(lstrlen(finddata.cFileName)+sizeof(TCHAR)); lstrcpy(plist->info[iNum].szFilename, finddata.cFileName); //Speicherplatz für den Dateiinhalt anfordern, Dateiinhalt speichern plist->info[iNum].szContents = malloc(iSize+1); ReadFile(hFile, plist->info[iNum].szContents, iSize, &dwRead, NULL); plist->info[iNum].szContents[iSize] = 0; CloseHandle(hFile); iNum++; } while(FindNextFile (hFile, &finddata)); FindClose(hFile); //Dateien nach Namen sortieren qsort(plist->info, iNum, sizeof(FILEINFO), Compare); plist->iNum = iNum; return plist; } //Vergleich für qsort int Compare(const FILEINFO *pinfo1, const FILEINFO *pinfo2) { return lstrcmp(pinfo2->szFilename, pinfo1->szFilename); }
Ich habe mittlerweile schon 6 Fehler behoben, 5 sind leider noch übrig:
main.cpp(409): error C2440: '=' : 'void *' kann nicht in 'char *' konvertiert werden main.cpp(250): error C2440: '=' : 'PVOID' kann nicht in 'PARAMS *' konvertiert werden main.cpp(402): error C2440: '=' : 'void *' kann nicht in 'FILELIST *' konvertiert werden main.cpp(405): error C2440: '=' : 'void *' kann nicht in 'TCHAR *' konvertiert werden main.cpp(421): error C2664: 'qsort' : Konvertierung des Parameters 4 von 'int (const FILEINFO *,const FILEINFO *)' in 'int (__cdecl *)(const void *,const void *)' nicht möglich main.cpp(281): warning C4002: Zu viele übergebene Parameter für das Makro 'TEXT' main.cpp(89): warning C4244: 'return' : Konvertierung von 'WPARAM' in 'int', möglicher Datenverlust main.cpp(199): warning C4267: 'Argument' : Konvertierung von 'size_t' nach 'int', Datenverlust möglich
Ich hoffe mir kann jemand etwas unter die Arme greifen dabei.
MfG,
Zoran
-
schonmal mit dateiendung .c versucht?
-
Frag im C++ Forum oder im Compilerforum...
Beim Borland würdest du andere Fehler angezeigt bekommen...
Und dein Problem ist wie an den Fehlermeldungen erkennbar ein C-Problem.MfG.
-
Dank der Änderung auf .c und ein paar Änderungen im Code klappt es. Vielen Dank!