-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBindStatusCallback.cpp
executable file
·181 lines (149 loc) · 5.48 KB
/
BindStatusCallback.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//////////////////////////////////////////////////////////////////////
//
// Written by Michael Dunn (mdunn at inreach dot com). Copyright and all
// that stuff. Use however you like but give me credit where it's due. I'll
// know if you don't. bwa ha ha ha ha!
//
// Release history:
// December 24, 1999: Version 1.0. First release.
//
//////////////////////////////////////////////////////////////////////
// BindStatusCallback.cpp: implementation of the CBindStatusCallback class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CdCoverCreator2.h"
#include "BindStatusCallback.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CBindStatusCallback::CBindStatusCallback (BINDVERB dwBindVerb, CString strHeaders, CString strPostData,
DWORD dwDownloadId, std::list<DWORD>* pStkDownloads,
DWORD dwStartTime,
HWND hwndProgress, HWND hwndStatus)
{
m_cRef = 1;
m_dwAction = (BINDVERB_GET == dwBindVerb || BINDVERB_POST == dwBindVerb ? dwBindVerb : BINDVERB_POST);
m_hDataToPost = NULL;
m_cbDataToPost = 0;
m_fRedirect = FALSE;
m_strHeaders = strHeaders;
Init (strPostData);
m_dwDownloadId = dwDownloadId;
m_pStkDownloads = pStkDownloads;
m_dwStartTime = dwStartTime;
m_hwndProgress = hwndProgress;
m_hwndStatus = hwndStatus;
}
CBindStatusCallback::~CBindStatusCallback()
{
if (m_hDataToPost)
{
GlobalFree (m_hDataToPost);
}
}
void CBindStatusCallback::Init (LPCTSTR szData)
{
if (m_hDataToPost)
{
// We're already in use and don't support recycling the same instance
// Some other client may have a reference on us.
// If we were to free this data, the client might crash dereferencing the handle
return;
}
if (szData)
{
// MSINTERNAL: See CINetHttp::INetAsyncSendRequest (cnethttp.cxx) that URLMON calls CINetHttp::GetDataToSend() followed by a call to WININET's HttpSendRequest(). GetDataToSend essentially pulls the data out of the BINDINFO that URLMON has cached away when it calls the host's implementation of IBindStatusCallback::GetBindInfo().
// MSINTERNAL: It doesn't attempt to lock down the HGLOBAL at all, so we need to allocated GMEM_FIXED
m_cbDataToPost = lstrlen(szData);
m_hDataToPost = GlobalAlloc(GPTR, m_cbDataToPost+1); // GMEM_MOVEABLE won't work because URLMON doesn't attempt GlobalLock before dereferencing
if (!m_hDataToPost)
return; // out of memory
// the memory was allocate fixed, so no need to lock it down
lstrcpy((LPTSTR)m_hDataToPost, szData);
}
}
STDMETHODIMP CBindStatusCallback::QueryInterface(REFIID riid, void** ppv)
{
*ppv = NULL;
if (riid == IID_IUnknown || riid == IID_IBindStatusCallback)
{
*ppv = (IBindStatusCallback*) this;
AddRef ();
return S_OK;
}
else if (riid == IID_IHttpNegotiate)
{
*ppv = (IHttpNegotiate*) this;
AddRef ();
return S_OK;
}
return E_NOINTERFACE;
}
HRESULT CBindStatusCallback::OnProgress (ULONG ulProgress, ULONG ulProgressMax,
ULONG ulStatusCode, LPCWSTR wszStatusText)
{
int nProgress = ulProgressMax == 0 ? 0 : int (100.0 * ulProgress / ulProgressMax);
// show the UI controls
if (m_dwDownloadId == m_pStkDownloads->back ())
{
if (m_hwndProgress != NULL)
{
::PostMessage (m_hwndProgress, PBM_SETPOS, nProgress, 0);
if (!IsWindowVisible (m_hwndProgress))
::ShowWindow (m_hwndProgress, SW_SHOW);
}
if (m_hwndStatus != NULL)
{
m_strKB.Format (IDS_DOWNLOADSTATUS_KB,
ulProgress / 1024, // KBs read
ulProgressMax / 1024); // Total size (KBs)
::PostMessage (m_hwndStatus, SB_SETTEXT, 2, (LPARAM) m_strKB.GetBuffer (0));
// percentage
if (ulProgressMax != 0)
{
m_strPercent.Format (IDS_DOWNLOADSTATUS_PERCENT, nProgress);
::PostMessage (m_hwndStatus, SB_SETTEXT, 3, (LPARAM) m_strPercent.GetBuffer (0));
}
// KB/s
m_strKBs.Format (IDS_DOWNLOADSTATUS_KBS, (double) ulProgress / 1024.0 / ((GetTickCount () - m_dwStartTime) / 1000.0 + 1));
::PostMessage (m_hwndStatus, SB_SETTEXT, 4, (LPARAM) m_strKBs.GetBuffer (0));
}
}
return S_OK;
}
STDMETHODIMP CBindStatusCallback::BeginningTransaction (LPCWSTR szURL, LPCWSTR szHeaders,
DWORD dwReserved, LPWSTR __RPC_FAR *pszAdditionalHeaders)
{
// Here's our opportunity to add headers
if (!pszAdditionalHeaders)
return E_POINTER;
*pszAdditionalHeaders = NULL;
// This header is required when performing a POST operation
if (BINDVERB_POST == m_dwAction && m_hDataToPost)
if (m_strHeaders.Find ("Content-Type: application/x-www-form-urlencoded") == -1)
m_strHeaders += "Content-Type: application/x-www-form-urlencoded\r\n";
if (!m_strHeaders.IsEmpty ())
{
*pszAdditionalHeaders = reinterpret_cast<LPWSTR> (CoTaskMemAlloc ((m_strHeaders.GetLength () + 1) * sizeof (WCHAR)));
BSTR bstr = m_strHeaders.AllocSysString ();
wcscpy (*pszAdditionalHeaders, bstr);
::SysFreeString (bstr);
}
return S_OK;
}
STDMETHODIMP CBindStatusCallback::OnResponse (DWORD dwResponseCode, LPCWSTR szResponseHeaders,
LPCWSTR szRequestHeaders, LPWSTR __RPC_FAR *pszAdditionalRequestHeaders)
{
if (!pszAdditionalRequestHeaders)
{
return E_POINTER;
}
*pszAdditionalRequestHeaders = NULL;
return S_OK;
}