[WinAPI]UrlDownloadToFile i progress bar

0

Może najpierw kod:

#include<windows.h>
#include <commctrl.h>
#include <shlwapi.h> 
#include<atlstr.h>



typedef HRESULT (*P_URLDownloadToFile)(      
   LPUNKNOWN pCaller,
   LPCTSTR szURL,
   LPCTSTR szFileName,
   DWORD dwReserved,
   void*
); 


using namespace std;

 HWND hwnd;


LPSTR NazwaKlasy = "Klasa Okienka";
MSG Komunikat;
HWND hProgress;
DWORD ThreadId;
HANDLE hThread;
DWORD WINAPI Thread(PVOID pVoid);
HINSTANCE hInstance;
INITCOMMONCONTROLSEX cc;
HWND g_hPrzycisk;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
HWND hText;
HWND label,label2,label3;
int dl;
HRESULT uRet=1;
P_URLDownloadToFile _URLDownloadToFile;
DWORD com;


//klasa
class CBind: public IBindStatusCallback
{
public:
	virtual HRESULT STDMETHODCALLTYPE QueryInterface(const IID &riid,void **ppvObject)
	{
		return S_OK;
	}
	virtual ULONG STDMETHODCALLTYPE AddRef( void)
		{
		return S_OK;
	}
    virtual ULONG STDMETHODCALLTYPE Release( void)
		{
		return S_OK;
	}
	 virtual HRESULT STDMETHODCALLTYPE OnStartBinding(DWORD dwReserved, IBinding *pib)
		 {
		return S_OK;
	}
        
        virtual HRESULT STDMETHODCALLTYPE GetPriority(LONG *pnPriority)
			{
		return S_OK;
	}
        
        virtual HRESULT STDMETHODCALLTYPE OnLowResource(DWORD reserved)
			{
		return S_OK;
	}
        
        virtual HRESULT STDMETHODCALLTYPE OnProgress(ULONG ulProgress,ULONG ulProgressMax,ULONG ulStatusCode,LPCWSTR szStatusText)
			{
				 CString sIEStatusMsg;
                 TCHAR   szCustomStatusMsg [256];
				 TCHAR pm [256];
				 TCHAR p [256];
                 TCHAR   szAmtDownloaded [256], szTotalSize [256];
			switch(ulStatusCode)
		{
		case BINDSTATUS_DOWNLOADINGDATA:
			StrFormatByteSize ( ulProgress, szAmtDownloaded, 256 );
             StrFormatByteSize ( ulProgressMax, szTotalSize, 256 );
			 SendMessage(hProgress,PBM_SETRANGE,0,(LPARAM)MAKELONG(0,ulProgressMax));
			//SendMessage(hProgress,PBM_SETPOS,(WPARAM)(100*ulProgress/ulProgressMax),0);
			 SendMessage(hProgress,PBM_SETSTEP,(WPARAM)(100*ulProgress/ulProgressMax),0);
			SendMessage(hProgress,PBM_STEPIT,0,0);
			
			if ( 0 != ulProgressMax )
        {
        wsprintf ( szCustomStatusMsg, _T("ściągnieto %s z %s"),szAmtDownloaded, szTotalSize );
		
        }
    else
        {
        wsprintf ( szCustomStatusMsg, _T("Ściągnieto %s (rozmiar nieznany)"),szAmtDownloaded );
        }
			//wsprintf(pm,_T("%s"),ulProgressMax);
		//wsprintf(p,_T("%s"),ulProgress);
			SetWindowText(label,szCustomStatusMsg);
			//SetWindowText(label2,p);
			SetWindowText(label3,"lipa");
			break;

		case BINDSTATUS_ENDDOWNLOADDATA:
              MessageBox(hwnd,"sciagnelo sie!", "hurra!", MB_ICONINFORMATION);
			  TerminateThread(hThread,0);
			break;
		}
		return S_OK;
		
	}
        
        virtual HRESULT STDMETHODCALLTYPE OnStopBinding(HRESULT hresult,LPCWSTR szError)
			{
		return S_OK;
	}
        
        virtual HRESULT STDMETHODCALLTYPE GetBindInfo(DWORD *grfBINDF,BINDINFO *pbindinfo)
			{
		return S_OK;
	}
        
        virtual HRESULT STDMETHODCALLTYPE OnDataAvailable(DWORD grfBSCF,DWORD dwSize,FORMATETC *pformatetc,STGMEDIUM *pstgmed)
			{
		return S_OK;
	}
        
        virtual HRESULT STDMETHODCALLTYPE OnObjectAvailable(REFIID riid,IUnknown *punk)
			{
		return S_OK;
	}

};


CBind *bind=new CBind;

   HINSTANCE hLib;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{

//WYPEŁNIANIE STRUKTURY
 WNDCLASSEX wc;

 wc.cbSize = sizeof(WNDCLASSEX);
 wc.style = 0;
 wc.lpfnWndProc = WndProc;
 wc.cbClsExtra = 0;
 wc.cbWndExtra = 0;
 wc.hInstance = hInstance;
 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
 wc.hbrBackground =(HBRUSH)(COLOR_WINDOW);
 wc.lpszMenuName = NULL;
 wc.lpszClassName = NazwaKlasy;
 wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);




//REJESTROWANIE KLASY OKNA
 if(!RegisterClassEx(&wc))
 {
  MessageBox(NULL, "Wysoka Komisja odmawia rejestracji tego okna!", "Niestety...", MB_ICONEXCLAMATION | MB_OK);
   return 1;
 }


   HMODULE urlmon=LoadLibrary("urlmon.dll");
   if(urlmon)
   {
   _URLDownloadToFile=(P_URLDownloadToFile)GetProcAddress(urlmon,"URLDownloadToFileA");
   }


   //progresbar
INITCOMMONCONTROLSEX cc;
cc.dwSize=sizeof(INITCOMMONCONTROLSEX);
cc.dwICC=ICC_BAR_CLASSES;
InitCommonControlsEx(&cc);






//TWORZENIE OKNA


 hwnd = CreateWindowEx(0, NazwaKlasy, "Oto okienko", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 500, NULL, NULL, hInstance, NULL);

g_hPrzycisk = CreateWindowEx(0, "BUTTON", "Nasz przycisk", WS_CHILD | WS_VISIBLE, 100, 100, 150, 30, hwnd, NULL, hInstance, NULL);
label=CreateWindow("STATIC","asd",WS_CHILD | WS_VISIBLE | SS_LEFT,60,300,200,20,hwnd,NULL,hInstance,NULL);
label2=CreateWindow("STATIC","asd",WS_CHILD | WS_VISIBLE | SS_LEFT,60,350,200,20,hwnd,NULL,hInstance,NULL);
label3=CreateWindow("STATIC","asd",WS_CHILD | WS_VISIBLE | SS_LEFT,60,400,200,20,hwnd,NULL,hInstance,NULL);
 hText = CreateWindowEx(0, "EDIT", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER, 50, 50, 400, 20, hwnd, NULL, hInstance, NULL);
 if(hwnd==NULL)
 {
	 
  MessageBox(NULL, "Okno odmówiło przyjścia na świat!", "Ale kicha...", MB_ICONEXCLAMATION);
  return 1;
 }

 ShowWindow(hwnd, nCmdShow); //Pokaż okienko...
 UpdateWindow(hwnd);

//Pętla komunikatów
 while(GetMessage(&Komunikat, NULL, 0, 0))
 {
  TranslateMessage(&Komunikat);
  DispatchMessage(&Komunikat);
 }
 return Komunikat.wParam;
}

//OBSŁUGA ZDARZEŃ
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

 switch(msg)
 {
 case WM_CREATE:
	 hProgress=CreateWindowEx(0,PROGRESS_CLASS,0,WS_VISIBLE|WS_CHILD,20,20,300,20,hwnd,0,hInstance,0);
	
	 break;
  case WM_CLOSE:
   DestroyWindow(hwnd);
  break;
  case WM_COMMAND:
	  
	  if((HWND)lParam == g_hPrzycisk)
	  {
		 
            
	hThread = CreateThread(NULL, 0, Thread, NULL, 0, &ThreadId);
			

		
       /*if(uRet==S_OK)
	   {
			  MessageBox(hwnd,"zassao sie!", "Ha!", MB_ICONINFORMATION);
			  
			  			 }
    else 
	{ 
		 MessageBox(hwnd,"lipla nie dziala", ";/", MB_ICONINFORMATION);
					 }*/
		
			
			
			
	  }
	  break;
  case WM_DESTROY:
	  FreeLibrary(hLib);
   PostQuitMessage(0);
   delete [] bind;
  break;
  default:
   return DefWindowProc(hwnd, msg, wParam, lParam);
  }
 return 0;
}

DWORD WINAPI Thread(PVOID pVoid)
{
 _URLDownloadToFile(NULL,link.c_str(),t.c_str(),0,bind);
 return 1;
}

Proszę nie patrzeć na jego czytelność, ani na to, że są jakieś niepotrzebne zmienne lub niektórych brakuje, bo trochę go poucinałem żeby dać tu na forum bez niepotrzebnych funkcji. Na czytelność też nie patrzcie, bo to kod roboczy, który doprowadzam do stanu "aby działało" i potem dopiero zabiore się za pisanie właściwej aplikacji, jak już to będę miał gotowe...

Ma to być okno, w nim edit, guzik, progressbar i kilka static'ów. W edita wklejamy link do pliku i klikamy guzik. Tworzy nam się nowy wątek (bo UrlDownloadToFile jest blokujące jak wiadomo) i ściąga się plik. To działa, problem polega na tym, że chcę dołączyć progress bar. Z tym jest kłopot... Na górze jest klasa z interfejsem, który to niby umożliwia, a jednak nie... W odpowiednim zdarzeniu, po ściągnięciu pliku kończy się wątek i powinien wyświetlać progress. Te labele czy tam jak to w WinAPI STATIC są pomocnicze, wyświetlają progress i wielkość pliku, ale coś to chyba błędnie pobiera te dane, albo ja namotałem. PRóbowałem już na różne sposoby operować tymi danymi i nic z tego...

Gdyby ktoś miał chwilę i chciał zerknąć na ten bałagan... byłbym bardzo wdzięczny.

0
khali napisał(a)

bo UrlDownloadToFile jest blokujące jak wiadomo
I tu się mylisz.

Jak ściągnąć plik z Internetu - zerknij na komentarz Szczawika.

0

No właśnie czytałem, bardzo mi to pomogło. Ale jak to zaprogramowałem w taki sposób, to bez nowego wątku funkcja blokuje mi program, no i progress bar działa niepoprawnie (np. przeleci półtora raza, albo niecały raz)...

0

Ajć sorry, oczywiście, że blokuje.
U mnie po drobnych poprawkach hula. Najważniejszy problem to to, że używałeś ilości bajtów do ustalania postępu progress-bara.
Ilość to 32-bitowy DWORD, a postęp to 16-bitowy WORD, przy większych wartościach liczba była ucinana.
Teraz jest użyta domyślna skala od 0 do 100: http://pastebin.4programmers.net/264

Poza tym po kiego grzyba dynamicznie ładujesz URLDownloadToFile ? Zalinkuj urlmon.lib, zaincluduj urlmon.h i używaj jak normalną funkcje.

I strasznie mi się nie podoba, że używać LPSTR'ów w funkcjach które oczekują LPTSTR'ów, szybkie przypomnienie poprawnego użycia:

Funkcja(_T("Parametr"));
FunkcjaA("Parametr");
FunkcjaW(L"Parametr");
0

Panie khali, po kiego ustawiasz zakres progressbara, skoro jego pozycję obliczasz dla domyślnego zakresu 100? Usuń PBM_SETRANGE, PBM_SETSTEP, PBM_STEPIT, a pozostaw PBM_SETPOS.
PBM_SETSTEP jest dobre gdy za każdym razem ściągniesz tyle samo bajtów, dlatego PBM_SETPOS jest tu bardziej odpowiednie.
Jeżeli ulProgressMax jest zerowe, to ukryj progressbar bo i tak nie pokaże postępu.

QueryInterface - tu jest full wypas katastrofa. Zwróć chociaż E_NOINTERFACE i wyzeruj *ppvObject. Jeżeli boisz się porównywania GUID'ów, to w shlwapi masz całkiem znośną funkcję QISearch (od windowsa 2000, import by ordinal 219) która powoduje że implementacja QueryInterface zamyka się w jednej linijce kodu z jednym średnikiem.

//gdzieś w kodzie
QITAB qitab = {IID_IBindStatusCallback,0,0,0};
// w metodzie QueryInterface
return QISearch(this, &qitab, riid, ppvObject);

Wystawiam Ci receptę byś zaraz po skopiowaniu kodu z dev-cpp zapewne, najpierw go wkleił do notatnika i poprawił wcięcia, bo np. ja widząc takiego "gniota" natychmiast cofam stronę. Jeżeli chcesz pomocy to zachęć nas.

0

Dziękuję bardzo Panowie! Bardzo mi pomogliście i dzięki za cenne wskazówki :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1