URLDownloadToFile에 대한 좋은 예제가 있어서 긁어왔습니다.

인터넷에서 파일을 다운로드 받는 URLDownloadToFile을 사용할 수 있다.
API 한 번 호출하는 것만으로 파일을 받을 수 있다니 얼마나 훌륭한가?

그런데, 이 URLDownloadToFile을 사용하다보면, 가끔 파일을 받지를 못하고 블럭킹 되는 수가 있다. (만건중 11번 경험) 이 블럭킹 되는 것을 막기위해서 다음과 같이 프로그램 로직을 추가하였다.

1. 다운로드 하는 곳을 쓰레드로 돌린다.
2. URLDownloadToFile에 IBindStatusCallBack을 넣어서, OnProgress가 불려지지 않으면 블럭킹으로 간주한다.
3. 다운로드 함수에서는 블럭킹을 감지하거나, 다운로드가 끝나기를 기다린다.


숏달..


#include "stdafx.h"
#include // link with urlmon.lib

class StatusCallBack : public IBindStatusCallback
{
public:
virtual HRESULT STDMETHODCALLTYPE OnStartBinding(
/* [in] */ DWORD dwReserved,
/* [in] */ IBinding *pib) { return S_OK; }

virtual HRESULT STDMETHODCALLTYPE GetPriority(
/* [out] */ LONG *pnPriority) { return S_OK; }

virtual HRESULT STDMETHODCALLTYPE OnLowResource(
/* [in] */ DWORD reserved) { return S_OK; }

virtual HRESULT STDMETHODCALLTYPE OnProgress(
/* [in] */ ULONG ulProgress,
/* [in] */ ULONG ulProgressMax,
/* [in] */ ULONG ulStatusCode,
/* [in] */ LPCWSTR szStatusText)
{
SetEvent(itsProgressEvent);
return S_OK;
}

virtual HRESULT STDMETHODCALLTYPE OnStopBinding(
/* [in] */ HRESULT hresult,
/* [unique][in] */ LPCWSTR szError) { return S_OK; }


virtual /* [local] */ HRESULT STDMETHODCALLTYPE GetBindInfo(
/* [out] */ DWORD *grfBINDF,
/* [unique][out][in] */ BINDINFO *pbindinfo) { return S_OK; }

virtual /* [local] */ HRESULT STDMETHODCALLTYPE OnDataAvailable(
/* [in] */ DWORD grfBSCF,
/* [in] */ DWORD dwSize,
/* [in] */ FORMATETC *pformatetc,
/* [in] */ STGMEDIUM *pstgmed) { return S_OK; }

virtual HRESULT STDMETHODCALLTYPE OnObjectAvailable(
/* [in] */ REFIID riid,
/* [iid_is][in] */ IUnknown *punk) { return S_OK; }

STDMETHOD_(ULONG, AddRef)() { return 0; }
STDMETHOD_(ULONG, Release)() { return 0; }

STDMETHOD(QueryInterface)(
/* [in] */ REFIID riid,
/* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) { return E_NOTIMPL; }

public:
StatusCallBack(HANDLE progressEvent)
{
itsProgressEvent = progressEvent;
}

private:
HANDLE itsProgressEvent;
};

class ThreadDownloadInfo
{
public:
ThreadDownloadInfo(char* url, char*path)
{
itsUrl = url;
itsPath = path;
itsResult = -1;

itsProgressEvent = CreateEvent(NULL, false, false, NULL);
itsCompleteEvent = CreateEvent(NULL, false, false, NULL);
}

~ThreadDownloadInfo()
{
CloseHandle(itsProgressEvent);
CloseHandle(itsCompleteEvent);
}

HANDLE GetProgressEvent() { return itsProgressEvent; }
HANDLE GetCompleteEvent() { return itsCompleteEvent; }
char* GetUrl() { return itsUrl; }
char* GetPath() { return itsPath; }
void SetResult(HRESULT hr) { itsResult = hr; }
HRESULT GetResult() { return itsResult; }

private:
HANDLE itsProgressEvent;
HANDLE itsCompleteEvent;
char* itsUrl;
char* itsPath;
HRESULT itsResult;
};

DWORD WINAPI ThreaDownloadProc(LPVOID lpParameter)
{
ThreadDownloadInfo* info = (ThreadDownloadInfo*)lpParameter;
StatusCallBack callback(info->GetProgressEvent());
HRESULT hr = URLDownloadToFile(
NULL,
info->GetUrl(),
info->GetPath(),
0,
&callback
);
info->SetResult(hr);
SetEvent(info->GetCompleteEvent());
return hr;
}

#define MAX_TIMEOUT 60*1000

HRESULT DownloadToFile(char* url, char*path)
{
ThreadDownloadInfo threadInfo(url, path);
DWORD threadId;
HANDLE hThread = CreateThread(
NULL,
0,
ThreaDownloadProc,
(LPVOID) &threadInfo,
0,
&threadId
);
HANDLE wait[2];
wait[0] = threadInfo.GetProgressEvent();
wait[1] = threadInfo.GetCompleteEvent();

HRESULT ret = S_FALSE;
while (1)
{
DWORD state = WaitForMultipleObjects(2, wait, false, MAX_TIMEOUT);
if (state == WAIT_OBJECT_0)
{
continue;
}
else if (state == WAIT_OBJECT_0 + 1)
{
ret = threadInfo.GetResult();
break;
}
else if (state == WAIT_TIMEOUT)
{
TerminateThread(hThread, -1);
break;
}
}
CloseHandle(hThread);

return ret;
}

int main(int argc, char* argv[])
{

printf("Hello World! ");

char* url = "http://www.microsoft.co.kr";
char* path = "aaa.html";

printf("download - %s", url);
HRESULT hr = DownloadToFile(url, path);
if (hr != S_OK)
{
printf("fail.. ");
}

return 0;
}
원본 : http://nicejay.egloos.com/1094024

'프로그래밍 팁 > etc' 카테고리의 다른 글

네트워크 정보(사운드카드, 맥어드레스, IP주소)  (0) 2010.04.17
printf와 같은 포멧  (0) 2010.04.15
CImageList예제  (0) 2010.04.12
파일과 폴더 아이콘 핸들 가져오기  (0) 2010.04.12
OS 정보 알기  (1) 2010.04.09
Posted by 띠깜
,