home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 December / PCWKCD1296.iso / vjplusb / activex / inetsdk / samples / progress / progress.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-11  |  18.3 KB  |  537 lines

  1. // ===========================================================================
  2. // File: P R O G R E S S . C P P
  3. //
  4. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  5. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  6. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  7. // PARTICULAR PURPOSE.
  8. //
  9. // Description:
  10. //
  11. //  This sample demonstrates using a URL moniker to download information.
  12. // The key routines include the implementation of IBindStatusCallback
  13. // and the CDownload::DoDownload routine, which creates and binds to the
  14. // URL moniker.
  15. //
  16. // Instructions:
  17. //
  18. //  To use this sample:
  19. //   * build it using the NMAKE command. NMAKE will create PROGRESS.EXE.
  20. //   * run PROGRESS.EXE. specify the resource to download by passing an
  21. //     URL on the command-line. use no command-line argument to default to
  22. //     downloading "http://www.msn.com".
  23. //  * The program displays a dialog box containing information about the
  24. //    download:
  25. //     - a status message, describing the current status of the download
  26. //     - a progress message, describing the amount of information that
  27. //       has been downloaded.
  28. //     - a text box, which displays chunks of the download information as
  29. //       it arrives.
  30. //  * Press the "GO" button to begin the download.
  31. //
  32. // Sample update:-
  33. //   * New feature include Progress Bar to indicated progress of the download
  34. //     * Edit box replaces the old text box. Also the whole file can be viewed. 
  35. //     If the file exceeds 32KB then only the first 32 KB from the last data
  36. //       pull will be displayed.  If the pull exceeds 32 KB, then only the first
  37. //     32 KB of the last Read will be displayed.
  38. // 
  39. ///
  40. // File updated by Jobi George 19-June-1996
  41. // File updated by Ramesha Gopalakrishna 28-June-1996
  42. // File updated by Oliver Wallace 9-July-1996
  43. // Copyright 1995-1996 Microsoft Corporation.  All Rights Reserved.
  44. // ===========================================================================
  45. #include "urlmon.h"
  46. #include "wininet.h"
  47. #include "resource.h"
  48. #include "commctrl.h"
  49.  
  50. #define EDIT_BOX_LIMIT 0x7FFF    //  The Edit box limit
  51.  
  52. // %%Classes: ----------------------------------------------------------------
  53. class CDownload {
  54.   public:
  55.     CDownload(LPCWSTR szURL);
  56.     ~CDownload();
  57.     HRESULT DoDownload(HWND,HWND,HWND,HWND);
  58.     LPCWSTR              m_url;
  59.  
  60.   private:
  61.     IMoniker*            m_pmk;
  62.     IBindCtx*            m_pbc;
  63.     IBindStatusCallback* m_pbsc;
  64. };
  65.  
  66. class CBindStatusCallback : public IBindStatusCallback {
  67.   public:
  68.     // IUnknown methods
  69.     STDMETHODIMP    QueryInterface(REFIID riid,void ** ppv);
  70.     STDMETHODIMP_(ULONG)    AddRef()    { return m_cRef++; }
  71.     STDMETHODIMP_(ULONG)    Release()   { if (--m_cRef == 0) { delete this; return 0; } return m_cRef; }
  72.  
  73.     // IBindStatusCallback methods
  74.     STDMETHODIMP    OnStartBinding(DWORD dwReserved, IBinding* pbinding);
  75.     STDMETHODIMP    GetPriority(LONG* pnPriority);
  76.     STDMETHODIMP    OnLowResource(DWORD dwReserved);
  77.     STDMETHODIMP    OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode,
  78.                         LPCWSTR pwzStatusText);
  79.     STDMETHODIMP    OnStopBinding(HRESULT hrResult, LPCWSTR szError);
  80.     STDMETHODIMP    GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindinfo);
  81.     STDMETHODIMP    OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC *pfmtetc,
  82.                         STGMEDIUM* pstgmed);
  83.     STDMETHODIMP    OnObjectAvailable(REFIID riid, IUnknown* punk);
  84.  
  85.     // constructors/destructors
  86.     CBindStatusCallback(HWND hwndStatus, HWND hwndProgress, HWND hwndText, HWND hwndProgressBar);
  87.     ~CBindStatusCallback();
  88.  
  89.     inline void SetStatus(LPCWSTR szStatus)     { SetWndText(m_hwndStatus, szStatus); }
  90.     void SetProgress(LPCWSTR szProgress)        { SetWndText(m_hwndProgress, szProgress); }
  91.     void SetProgressBar(ULONG cProgress, ULONG maxProgress) 
  92.     {
  93.         // Set the range and increment of the progress bar. 
  94.         SendMessage(m_hwndProgressBar, PBM_SETRANGE, 0, 100); 
  95.         SendMessage(m_hwndProgressBar, PBM_SETPOS, (WPARAM) (maxProgress ? cProgress * 100 / maxProgress : 0), 0);
  96.     }
  97.     void SetWndText(HWND hwnd, LPCWSTR szText);
  98.  
  99.     // data members
  100.     DWORD           m_cRef;
  101.     IBinding*       m_pbinding;
  102.     IStream*        m_pstm;
  103.     HWND            m_hwndStatus;
  104.     HWND            m_hwndProgress;
  105.     HWND            m_hwndText;
  106.     HWND            m_hwndProgressBar;
  107.     DWORD           m_cbOld;
  108. };
  109.  
  110.  
  111. // ===========================================================================
  112. //                     CBindStatusCallback Implementation
  113. // ===========================================================================
  114.  
  115. // ---------------------------------------------------------------------------
  116. // %%Function: CBindStatusCallback::CBindStatusCallback
  117. // ---------------------------------------------------------------------------
  118. CBindStatusCallback::CBindStatusCallback(HWND hwndStatus, HWND hwndProgress, HWND hwndText, HWND hwndProgressBar)
  119. {
  120.     m_hwndStatus = hwndStatus;
  121.     m_hwndProgress = hwndProgress;
  122.     m_hwndText = hwndText;
  123.     m_hwndProgressBar = hwndProgressBar;
  124.     m_pbinding = NULL;
  125.     m_pstm = NULL;
  126.     m_cRef = 1;
  127.     m_cbOld = 0;
  128. }  // CBindStatusCallback
  129.  
  130. // ---------------------------------------------------------------------------
  131. // %%Function: CBindStatusCallback::~CBindStatusCallback
  132. // ---------------------------------------------------------------------------
  133. CBindStatusCallback::~CBindStatusCallback()
  134. {
  135. }  // ~CBindStatusCallback
  136.  
  137. // ---------------------------------------------------------------------------
  138. // %%Function: CBindStatusCallback::SetWndText
  139. // ---------------------------------------------------------------------------
  140.  inline void
  141. CBindStatusCallback::SetWndText(HWND hwnd,LPCWSTR szText)
  142. {
  143.     if (IsWindow(hwnd))
  144.         {
  145.         char    rgchBuf[INTERNET_MAX_PATH_LENGTH];
  146.         WideCharToMultiByte(CP_ACP, 0, szText, -1, rgchBuf, INTERNET_MAX_PATH_LENGTH, 0, 0);
  147.     SetWindowText(hwnd, rgchBuf);
  148.     }
  149. }  // CBindStatusCallback::SetWndText
  150.  
  151. // ---------------------------------------------------------------------------
  152. // %%Function: CBindStatusCallback::QueryInterface
  153. // ---------------------------------------------------------------------------
  154.  STDMETHODIMP
  155. CBindStatusCallback::QueryInterface(REFIID riid, void** ppv)
  156. {
  157.     *ppv = NULL;
  158.  
  159.     if (riid==IID_IUnknown || riid==IID_IBindStatusCallback)
  160.         {
  161.         *ppv = this;
  162.         AddRef();
  163.         return S_OK;
  164.         }
  165.     return E_NOINTERFACE;
  166. }  // CBindStatusCallback::QueryInterface
  167.  
  168. // ---------------------------------------------------------------------------
  169. // %%Function: CBindStatusCallback::OnStartBinding
  170. // ---------------------------------------------------------------------------
  171.  STDMETHODIMP
  172. CBindStatusCallback::OnStartBinding(DWORD dwReserved, IBinding* pbinding)
  173. {
  174.     if (m_pbinding != NULL)
  175.         m_pbinding->Release();
  176.     m_pbinding = pbinding;
  177.     if (m_pbinding != NULL)
  178.         {
  179.         m_pbinding->AddRef();
  180.         SetStatus(L"Status: Starting to bind...");
  181.         }
  182.     return S_OK;
  183. }  // CBindStatusCallback::OnStartBinding
  184.  
  185. // ---------------------------------------------------------------------------
  186. // %%Function: CBindStatusCallback::GetPriority
  187. // ---------------------------------------------------------------------------
  188.  STDMETHODIMP
  189. CBindStatusCallback::GetPriority(LONG* pnPriority)
  190. {
  191.     return E_NOTIMPL;
  192. }  // CBindStatusCallback::GetPriority
  193.  
  194. // ---------------------------------------------------------------------------
  195. // %%Function: CBindStatusCallback::OnLowResource
  196. // ---------------------------------------------------------------------------
  197.  STDMETHODIMP
  198. CBindStatusCallback::OnLowResource(DWORD dwReserved)
  199. {
  200.     return E_NOTIMPL;
  201. }  // CBindStatusCallback::OnLowResource
  202.  
  203. // ---------------------------------------------------------------------------
  204. // %%Function: CBindStatusCallback::OnProgress
  205. // ---------------------------------------------------------------------------
  206.  STDMETHODIMP
  207. CBindStatusCallback::OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
  208. {
  209.     char    sz[255];
  210.  
  211.     if(szStatusText!=NULL)
  212.         WideCharToMultiByte(CP_ACP, 0, szStatusText,-1, sz, 255, 0,0);
  213.  
  214.     char    msg[100];
  215.     WCHAR   out[200];
  216.  
  217.     wsprintf(msg,"Progress: %s %d of %d ", sz, ulProgress, (ulProgress>ulProgressMax)?ulProgress:ulProgressMax);
  218.     MultiByteToWideChar(CP_ACP, 0, msg, -1, out, sizeof(out));
  219.  
  220.     SetProgress(out);
  221.     SetProgressBar(ulProgress, ulProgressMax);
  222.     return(NOERROR);
  223. }  // CBindStatusCallback::OnProgress
  224.  
  225. // ---------------------------------------------------------------------------
  226. // %%Function: CBindStatusCallback::OnStopBinding
  227. // ---------------------------------------------------------------------------
  228.  STDMETHODIMP
  229. CBindStatusCallback::OnStopBinding(HRESULT hrStatus, LPCWSTR pszError)
  230. {
  231.     if (hrStatus)
  232.         SetStatus(L"Status: File download Failed.");
  233.  
  234.     if (m_pbinding)
  235.     {
  236.         m_pbinding->Release();
  237.         m_pbinding = NULL;
  238.     }
  239.  
  240.     return S_OK;
  241. }  // CBindStatusCallback::OnStopBinding
  242.  
  243. // ---------------------------------------------------------------------------
  244. // %%Function: CBindStatusCallback::GetBindInfo
  245. // ---------------------------------------------------------------------------
  246.  STDMETHODIMP
  247. CBindStatusCallback::GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindInfo)
  248. {
  249.     *pgrfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
  250.     *pgrfBINDF |= BINDF_GETNEWESTVERSION | BINDF_NOWRITECACHE;
  251.     pbindInfo->cbSize = sizeof(BINDINFO);
  252.     pbindInfo->szExtraInfo = NULL;
  253.     memset(&pbindInfo->stgmedData, 0, sizeof(STGMEDIUM));
  254.     pbindInfo->grfBindInfoF = 0;
  255.     pbindInfo->dwBindVerb = BINDVERB_GET;
  256.     pbindInfo->szCustomVerb = NULL;
  257.     return S_OK;
  258. }  // CBindStatusCallback::GetBindInfo
  259.  
  260. // ---------------------------------------------------------------------------
  261. // %%Function: CBindStatusCallback::OnDataAvailable
  262. // ---------------------------------------------------------------------------
  263.  STDMETHODIMP
  264. CBindStatusCallback::OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC* pfmtetc, STGMEDIUM* pstgmed)
  265. {
  266.      HRESULT hr=S_OK;
  267.      DWORD dStrlength=0;
  268.  
  269.     // Get the Stream passed
  270.     if (BSCF_FIRSTDATANOTIFICATION & grfBSCF)
  271.     {
  272.         if (!m_pstm && pstgmed->tymed == TYMED_ISTREAM)
  273.         {
  274.             m_pstm = pstgmed->pstm;
  275.             if (m_pstm)
  276.                 m_pstm->AddRef();
  277.         }
  278.     }
  279.  
  280.     // If there is some data to be read then go ahead and read them
  281.     if (m_pstm && dwSize > m_cbOld)
  282.     {
  283.         DWORD dwRead = dwSize - m_cbOld; // Minimum amount available that hasn't been read
  284.         DWORD dwActuallyRead = 0;            // Placeholder for amount read during this pull
  285.  
  286.         if (dwRead > 0)
  287.         do
  288.         {
  289.             char * pNewstr = new char[dwRead + 1];
  290.             if (pNewstr==NULL)
  291.                 return S_FALSE;
  292.             hr=m_pstm->Read(pNewstr,dwRead,&dwActuallyRead);
  293.             pNewstr[dwActuallyRead] = 0;
  294.             // If we really read something then lets add it to the Edit box
  295.             if (dwActuallyRead>0)
  296.             {
  297.                 dStrlength=GetWindowTextLength(m_hwndText);
  298.  
  299.                 char *pOldstr=NULL;
  300.                 if (dwActuallyRead>=EDIT_BOX_LIMIT)  // Read exceeded Edit box size
  301.                 {
  302.                     pOldstr= new char[EDIT_BOX_LIMIT];
  303.                     if (pOldstr==NULL)
  304.                     {
  305.                         delete[] pNewstr;    
  306.                         return S_FALSE;
  307.                     }
  308.                     lstrcpyn(pOldstr,pNewstr,EDIT_BOX_LIMIT-1);
  309.                 }
  310.                 else if (dStrlength + dwActuallyRead >= EDIT_BOX_LIMIT)
  311.                 {
  312.                     // This pull exceeded the edit box size.  Only copy the last read.
  313.                     pOldstr = new char[dwActuallyRead+1];
  314.                     if (pOldstr==NULL)
  315.                     {
  316.                         delete[] pNewstr;
  317.                         return S_FALSE;
  318.                     }
  319.                     lstrcpyn(pOldstr,pNewstr,dwActuallyRead);
  320.                 }
  321.                   else
  322.                 {
  323.                     pOldstr= new char[dStrlength+dwActuallyRead+1];
  324.                     if (pOldstr==NULL)
  325.                     {
  326.                         delete[] pNewstr;
  327.                         return S_FALSE;
  328.                      }
  329.                     GetWindowText(m_hwndText,pOldstr,(dStrlength+dwActuallyRead+1));
  330.                     lstrcat(pOldstr,pNewstr);
  331.                 }
  332.                 SetWindowText(m_hwndText,pOldstr);
  333.                 m_cbOld += dwActuallyRead;
  334.                 delete[] pOldstr;
  335.             }
  336.             delete[] pNewstr;
  337.  
  338.                 } while (!(hr == E_PENDING || hr == S_FALSE) && SUCCEEDED(hr));
  339.     }//     if (m_pstm && dwSize > m_cbOld)
  340.  
  341.     if (BSCF_LASTDATANOTIFICATION & grfBSCF)
  342.     {
  343.         if (m_pstm)
  344.             m_pstm->Release();
  345.         hr=S_OK;  // If it was the last data then we should return S_OK as we just finished reading everything
  346.         SetStatus(L"Status: File downloaded.");
  347.     }
  348.  
  349.     return hr;
  350. }  // CBindStatusCallback::OnDataAvailable
  351.  
  352. // ---------------------------------------------------------------------------
  353. // %%Function: CBindStatusCallback::OnObjectAvailable
  354. // ---------------------------------------------------------------------------
  355.  STDMETHODIMP
  356. CBindStatusCallback::OnObjectAvailable(REFIID riid, IUnknown* punk)
  357. {
  358.     return E_NOTIMPL;
  359. }  // CBindStatusCallback::OnObjectAvailable
  360.  
  361.  
  362. // ===========================================================================
  363. //                           CDownload Implementation
  364. // ===========================================================================
  365.  
  366. // ---------------------------------------------------------------------------
  367. // %%Function: CDownload::CDownload
  368. // ---------------------------------------------------------------------------
  369. CDownload::CDownload(LPCWSTR szURL)
  370. {
  371.     m_url = szURL;
  372.     m_pmk = 0;
  373.     m_pbc = 0;
  374.     m_pbsc = 0;
  375. }  // CDownload
  376.  
  377. // ---------------------------------------------------------------------------
  378. // %%Function: CDownload::~CDownload
  379. // ---------------------------------------------------------------------------
  380. CDownload::~CDownload()
  381. {
  382.     if (m_pmk)
  383.         m_pmk->Release();
  384.     if (m_pbc)
  385.         m_pbc->Release();
  386.     if (m_pbsc)
  387.         m_pbsc->Release();
  388. }  // ~CDownload
  389.  
  390. // ---------------------------------------------------------------------------
  391. // %%Function: CDownload::DoDownload
  392. // ---------------------------------------------------------------------------
  393.  HRESULT
  394. CDownload::DoDownload(HWND hwndStatus, HWND hwndProgress, HWND hwndText, HWND hwndProgressBar)
  395. {
  396.     IStream* pstm = NULL;
  397.     HRESULT hr;
  398.  
  399.     hr = CreateURLMoniker(NULL, m_url, &m_pmk);
  400.     if (FAILED(hr))
  401.         goto LErrExit;
  402.  
  403.     m_pbsc = new CBindStatusCallback(hwndStatus, hwndProgress, hwndText, hwndProgressBar);
  404.     if (m_pbsc == NULL)
  405.         {
  406.         hr = E_OUTOFMEMORY;
  407.         goto LErrExit;
  408.         }
  409.  
  410.     hr = CreateBindCtx(0, &m_pbc);
  411.     if (FAILED(hr))
  412.         goto LErrExit;
  413.  
  414.     hr = RegisterBindStatusCallback(m_pbc,
  415.             m_pbsc,
  416.             0,
  417.             0L);
  418.     if (FAILED(hr))
  419.         goto LErrExit;
  420.  
  421.     hr = m_pmk->BindToStorage(m_pbc, 0, IID_IStream, (void**)&pstm);
  422.     if (FAILED(hr))
  423.         goto LErrExit;
  424.  
  425.     return hr;
  426.  
  427. LErrExit:
  428.     if (m_pbc != NULL)
  429.         {
  430.         m_pbc->Release();
  431.         m_pbc = NULL;
  432.         }
  433.     if (m_pbsc != NULL)
  434.         {
  435.         m_pbsc->Release();
  436.         m_pbsc = NULL;
  437.         }
  438.     if (m_pmk != NULL)
  439.         {
  440.         m_pmk->Release();
  441.         m_pmk = NULL;
  442.         }
  443.     if (pstm)
  444.         {
  445.         pstm->Release();
  446.         pstm = NULL;
  447.         }
  448.     return hr;
  449. }  // CDownload::DoDownload
  450.  
  451.  
  452. // ===========================================================================
  453. //                  User Interface and Initialization Routines
  454. // ===========================================================================
  455.  
  456. // ---------------------------------------------------------------------------
  457. // %%Function: DialogProc
  458. // ---------------------------------------------------------------------------
  459.  BOOL CALLBACK
  460. DialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
  461. {
  462.     static CDownload* pcdl = NULL;
  463.  
  464.     switch(message)
  465.         {
  466.         case WM_INITDIALOG:
  467.             EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE);
  468.             EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), TRUE);
  469.             pcdl = (CDownload*)(LPVOID)(lParam);
  470.             break;
  471.  
  472.         case WM_COMMAND:
  473.             {
  474.             switch (LOWORD(wParam))
  475.                 {
  476.                 case IDOK:
  477.                     {
  478.                     char rgchBuf[INTERNET_MAX_PATH_LENGTH];
  479.                     HWND hwndStatus = GetDlgItem(hwndDlg, IDC_DISPLAY);
  480.                     HWND hwndProgress = GetDlgItem(hwndDlg, IDC_PROGRESS);
  481.                     HWND hwndText = GetDlgItem(hwndDlg, IDC_EDIT);
  482.                     HWND hwndProgressBar = GetDlgItem(hwndDlg, IDC_PROGRESSBAR);
  483.  
  484.                     EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
  485.                     EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE);
  486.  
  487.                     WideCharToMultiByte(CP_ACP, 0, pcdl->m_url, -1, rgchBuf, MAX_PATH, 0, 0);
  488.                     SetWindowText(hwndDlg, rgchBuf);
  489.  
  490.                     SetWindowText(hwndStatus, TEXT("Status: Initiating Bind..."));
  491.                     pcdl->DoDownload(hwndStatus, hwndProgress, hwndText, hwndProgressBar);
  492.                     EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), TRUE);
  493.                     break;
  494.                     }
  495.  
  496.                 case IDCANCEL:
  497.                     EndDialog(hwndDlg,0);
  498.                     return 1;
  499.                 }
  500.             break;
  501.             }
  502.         }
  503.  
  504.     return 0;
  505. }  // DialogProc
  506.  
  507. // ---------------------------------------------------------------------------
  508. // %%Function: WinMain
  509. // ---------------------------------------------------------------------------
  510.  int WINAPI
  511. WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR szCmdLine, int nCmdShow)
  512. {
  513.     static WCHAR    szDefaultURL[] = L"http://www.msn.com";
  514.     WCHAR           rgwchCmdLine[MAX_PATH];
  515.     HRESULT         hr;
  516.  
  517.     InitCommonControls();
  518.  
  519.     hr = CoInitialize(NULL);
  520.     if (FAILED(hr))
  521.         return hr;
  522.  
  523.     MultiByteToWideChar(CP_ACP, 0, szCmdLine, -1, rgwchCmdLine, MAX_PATH);
  524.  
  525.     CDownload download(rgwchCmdLine[0] ? rgwchCmdLine : szDefaultURL);
  526.  
  527.     int x = DialogBoxParam(hinst, MAKEINTRESOURCE(IDD_DIALOG1), HWND_DESKTOP,
  528.         (FARPROC)&DialogProc, (LPARAM)(LPVOID)&download);
  529.  
  530.     CoUninitialize();
  531.  
  532.     return 0;
  533. }  // WinMain
  534.  
  535. // EOF =======================================================================
  536.  
  537.