Problem bei file Download



  • konnte ich mir schon denken hab auch schon nach Threads gesucht nur bin ich noch nicht ganz da hinter gestiegen

    😕 😃



  • Und Wie Packe ich jetzt meine funktion in einen thread

    bsp.: so rufe ich InternetOpenUrl auf

    [code]
    BOOL GetFile (HWND hwndProgress,HWND hwndStaticText,HINTERNET IN hOpen, CHAR *szUrl, CHAR *szFileName)
       {
           DWORD dwSize;
           CHAR   szHead[] = "Accept: */*\r\n\r\n";
           VOID * szTemp[16384];
           HINTERNET  hConnect;
           FILE * pFile;
    
           if ( !(hConnect = InternetOpenUrl ( hOpen, szUrl, szHead, lstrlen (szHead), INTERNET_FLAG_DONT_CACHE, 0)))
           {
    		   MessageBox(hWWnd,"Error ! : URL Fehler","Error",0);
               return 0;
           }
    
           if  ( !(pFile = fopen (szFileName, "wb" ) ) )
           {
    		  MessageBox(hWWnd,"Error ! 2","Error",0);
              return FALSE;
           }
    	   DWORD dwByteToRead = 0;
    	   DWORD dwSizeOfRq = 4;
    	   DWORD dwBytes = 0;
    
    	   if (!HttpQueryInfo(hConnect, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwByteToRead, &dwSizeOfRq, NULL))
    	   {
    			dwByteToRead = 0;
    	   }
    
    	   DWORD start;
    	   DWORD end;
    	   DWORD time;
    	   time = 10;
    	   start = timeGetTime();
    
           do
           {
              if (!InternetReadFile (hConnect, szTemp, 16384,  &dwSize) )
              {
                  fclose (pFile);
    			  MessageBox(hWWnd,"Error ! 3","Error",0);
                return FALSE;
              }
              if (!dwSize)
                  break;  // Condition of dwSize=0 indicate EOF. Stop.
              else
                 fwrite(szTemp, sizeof (char), dwSize , pFile);
    			 dwBytes+=dwSize;
    			 if(dwByteToRead && hwndProgress)
    			 {
    				SendMessage(hwndProgress, PBM_SETPOS,(dwBytes*100)/dwByteToRead,0);
    				UpdateWindow(hwndProgress);
    			 }
    			 FLOAT fSpeed = 0;
    			 fSpeed = (float)dwBytes;
    			 fSpeed /= ((float)time)/1000.0f;
    			 fSpeed /= 1024.0f;
    			 if(hwndProgress)
    			 {
    				char s[260];
    				sprintf(s, "%d KB / %d KB @ %1.1f KB/s", dwBytes/1024, dwByteToRead/1024, fSpeed);
    				SetWindowText(hwndStaticText, s);
    				UpdateWindow(hwndStaticText);
    			 }
    			 end = timeGetTime();
    			 time = end - start;
    			 if(time == 0)
    			 time = 10;
           }   // do
          while (TRUE);
          fflush (pFile);
          fclose (pFile);
          return TRUE;
       }
    
    int InternetDownloadFile(HWND hwndProgress,HWND hwndStaticText, char *URL, char *FileDest)
    {
    	DWORD dwFlags;
    	DWORD dwResult = INTERNET_ERROR_OPEN;
    
    	InternetGetConnectedState(&dwFlags, 0);
    
    	if(dwFlags & INTERNET_CONNECTION_OFFLINE)//take appropriate steps
    	return INTERNET_ERROR_OPEN;
    
    	char strAgent[64];
    
    	sprintf(strAgent, "Agent%ld", timeGetTime());
    
    	HINTERNET hOpen;
    
    	if(!(dwFlags & INTERNET_CONNECTION_PROXY))
    		hOpen = InternetOpenA(strAgent, INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY, NULL, NULL, 0);
    	else
    		hOpen = InternetOpenA(strAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    	if(hOpen)
    	{
    		dwResult = GetFile (hwndProgress,hwndStaticText,hOpen, URL, FileDest);
    		InternetCloseHandle(hOpen);
    	}
        else return INTERNET_ERROR_OPEN;
    	return dwResult;
    }
    [/code]
    


  • Threads in der WinApi:
    http://msdn2.microsoft.com/en-us/library/ms682453.aspx

    HANDLE WINAPI CreateThread(
      LPSECURITY_ATTRIBUTES lpThreadAttributes,
      SIZE_T dwStackSize,
      LPTHREAD_START_ROUTINE lpStartAddress,
      LPVOID lpParameter,
      DWORD dwCreationFlags,
      LPDWORD lpThreadId
    );
    

    Wichtig ist dort LPTHREAD_START_ROUTINE lpStartAddress. Das ist ein Pointer auf eine ThreadProc funktion. Wie diese auszusehen hat kannste hier nachlesen:
    http://msdn2.microsoft.com/en-us/library/ms686736.aspx

    Alles was dann in der ThreadProc gemacht wird, wird in einem seperaten Thread ausgeführt

    Wenn du den BCB benutzt gibts da glaub ich auch noch BeginThreadEx.Da kenn ich mich aber net so gut aus.

    MFG
    Ace



  • Ne Benutze Visual Studio 2005



  • Prinzipiell brauchst du ne ThreadProc(), in der du quasi deine fertige GetFile() Funktion aufrufen könntest. Parameter kannst du an die ThreadProc() über den lpParam übergeben (z.B. über nen Pointer auf ne Struktur)

    Den Thread selbst erzeugst du mittels CreateThread() wo du dann die ThreadProc angibst.

    Aufpassen muss du allerdings ein wenig mit Variablen-Zugriffen. Wenn du innerhalb des Threads z.B. auf globale Variablen zugreifen willst musst du das syncronisieren (da gibt es z.B. CreateCriticalSection() ...), sonst könnte es crashen 😉

    Auch aufpassen musst du bei SetWindowText() und solchen GUI-Funktionen. Die Controls mögen es nämlich leider nicht so gerne was von nem Fremd-Thread zu bekommen. Nen Status-Text könnte man z.B. in ne syncronisierte Variable schreiben und an das Fenster dann via PostMessage() ne benutzer-definierte Nachricht schicken, die dann die eigentliche Arbeit macht 😉



  • aja schnall ich zwar noch net ganz werds aber mal probieren



  • hab mal ne frage muss ich für ThreadProc einen struct erzeugen

    wie das bsp. von msdn

    typedef struct _MyData {
        int val1;
        int val2;
    } MYDATA, *PMYDATA;
    


  • generell ist es dafür gedacht Informationen mit in den Thread zu geben.
    Nen struct macht bei dir wohl Sinn, da könntest du direkt die Handles, die zu downloadene Datei etc. reinpacken...



  • ok dann werd ichs mal probieren



  • Kennt noch einer n Gutes Tutorial für threads

    thx 😃



  • Bei codeproject findet sich da was:
    http://www.codeproject.com/threads/#Threads

    Pseudo-Code:

    typedef struct _MyDownloadData {
        HWND hwndProgress;
        HWND hwndStaticText;
        HINTERNET hOpen;
        CHAR *szUrl;
        CHAR *szFileName;    
    } MyDownloadData, *PMyDownloadData;
    
    DWORD WINAPI MyDownloadThread(LPVOID lpParameter)
    {
        PMyDownloadData myData=(PMyDownloadData)lpParameter;
    
        // Deine GetFile aufrufen:
       GetFile (myData->hwndProgress,myData->hwndStaticText,myData->hOpen,myData->szUrl, myData->szFileName);
    
       // Thread hat fertig:
       ExitThread(0);
    }
    
    // Irgendwo deinen Thread starten:
    
    DWORD dwThreadId; // Thread-ID
    
    MyDownloadData threadData;
    
    threadData.hwndProgress=...;
    threadData.hwndStaticText=...;
    threadData.hOpen=...;
    threadData.szUrl="http://www.bluppdidupp.de";
    threadData.szFileName="c:\\test.html";    
    
    HANDLE hThread = CreateThread( 
                NULL,              // default security attributes
                0,                 // use default stack size  
                MyDownloadThread,        // thread function 
                &threadData,             // argument to thread function 
                0,                 // use default creation flags 
                &dwThreadId);   // returns the thread identifier 
    
            // Check the return value for success. 
    
            if (hThread == NULL) 
            {
                OutputDebugString("fehler! meeeeeep!!");
            }    
            else
            {
                OutputDebugString("Thread rennt!");
            }
    

    Problem wird allerdings z.B. SendMessage(), SetWindowText() und UpdateWindow() im Thread sein!
    GUI-Elemente niemals versuchen von nem Fremdthread anzusprechen!
    Aber die Dinger kannste ja zu Testzwecken erstmal auskommentieren und im zweiten Step mal an Thread-Syncronisation gehen 😉



  • @geeky bist der beste 😃 werds heut gleich mal probieren kann aber spät werden hab heut zweite schicht



  • also dieser thread den du gepostet hast funktioniert musste aber wie du schon sagtest einiges auskomentieren

    bsp.:

    //threadData.hwndProgress=...;
    //threadData.hwndStaticText=...;
    threadData.hOpen=hOpen; 
    threadData.szUrl=buffer_a; 
    threadData.szFileName=buffer_b;
    

    aber mal ne frage wie finde ich heraus das der thread beendet ist



  • habs schon Denke ich !
    mit

    WaitForSingleObject(hThread, INFINITE);
    CloseHandle(hThread);



  • Wie Syncronisiere ich jetzt den thread mein programm hängt sich auf oder bracuht ewig



  • Das is ne gute Frage 😉 (/me kennt sich mit Threads in WinAPI quasi eigentlich gar nicht aus ;D)

    Aufhängen? hmm. ungewollte Endlosschleife oder blockierende Funktion im Thread? Evtl. ein wenig mit OutputDebugString() und/oder Debugger rumspielen?

    WaitForSingleObject() macht außer beim Programmende mit INFINITE nicht viel Sinn oder? WaitForSingleObject() blockiert dann doch auch, oder nich? hmm...



  • dafür haste mich aber ziemlich weit gebracht muss dafür aber unbedingt nochmal danke sagen ohne dich bin ich echt aufgeschmissen



  • hab den hinweis bekommen das ich diese while schleife (bsp) in der Do While Schleife einfügen soll

    MSG msg;
    while( PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE ) )
    {       
       if( GetMessage(&msg, NULL, 0, 0))     
      {      
        TranslateMessage(&msg);      
        DispatchMessage(&msg);   
      } 
      else 
      {        	 	
         break;    
      }
    }
    


  • Das sieht für mich ziemlich beknackt aus 😉

    Die Standard MessageLoop sieht so aus:

    while (GetMessage(&msg, NULL, 0, 0)) // Hier wird quasi die Nachricht abgeholt oder gewartet bis eine da ist ;D
    {      
        TranslateMessage(&msg);      // Hier noch ein wenig verarbeitet
        DispatchMessage(&msg);       // Hier kommt die WndProc zum Zuge
    }
    

    PeekMessage() sollte man möglichst vermeiden (da non-blocking und somit CPU-Zeit raubend)
    GetMessage() ist quasi dasselbe nur wartet es bis ne neue Message da ist.
    Wenn das Programm beendet wird liefert GetMessage() false!
    GetMessage und PeekMessage in der Form macht irgendwie gar keinen Sinn, oder?!



  • das hab ich mir auch gedacht aber mein programm ladet konstant ohne zu blockieren, aber ich bastl trotzdem noch an der thread version


Anmelden zum Antworten