extract.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 29k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "precomp.h"
  2. #include "ocmm.h"
  3. CHAR const c_szShellEx[] = "ShellEx";
  4. UINT CalcImageSize( const SIZE * prgSize, DWORD dwClrDepth );
  5. CThumbnailShrinker::CThumbnailShrinker()
  6. {
  7. }
  8. CThumbnailShrinker::~CThumbnailShrinker()
  9. {
  10. }
  11. STDMETHODIMP CThumbnailShrinker::ScaleSharpen2( BITMAPINFO * pbi,
  12.                                                 LPVOID pBits,
  13.                                                 HBITMAP * phBmpThumbnail,
  14.                                                 const SIZE * prgSize,
  15.                                                 DWORD dwRecClrDepth,
  16.                                                 HPALETTE hpal,
  17.                                                 UINT uiSharpPct,
  18.                                                 BOOL fOrigSize )
  19. {
  20.     BOOL fRes = ConvertDIBSECTIONToThumbnail( pbi,
  21.                                               pBits,
  22.                                               phBmpThumbnail,
  23.                                               prgSize,
  24.                                               dwRecClrDepth,
  25.                                               hpal,
  26.                                               uiSharpPct,
  27.                                               fOrigSize );
  28.     return ( fRes ) ? NOERROR : E_FAIL;
  29. }
  30. ////////////////////////////////////////////////////////////////////////////////////
  31. BOOL ConvertDIBSECTIONToThumbnail( BITMAPINFO * pbi,
  32.                                    LPVOID pBits,
  33.                                    HBITMAP * phBmpThumbnail,
  34.                                    const SIZE * prgSize,
  35.                                    DWORD dwRecClrDepth,
  36.                                    HPALETTE hpal,
  37.                                    UINT uiSharpPct,
  38.                                    BOOL fOrigSize)
  39. {
  40.     IThumbnailMaker *   pThumbMaker = NULL;
  41.     LPBITMAPINFO        pbiScaled = pbi, pbiUsed = pbi;
  42.     LPBITMAPINFOHEADER  pbih = ( LPBITMAPINFOHEADER )pbi;
  43.     BOOL                bRetVal = FALSE, bInverted = FALSE;
  44.     RECT                rect;
  45.     HRESULT             hr;
  46.     LPVOID              pScaledBits = pBits;
  47.     // the scaling code doesn't handle inverted bitmaps, so we treat
  48.     // them as if they were normal, by inverting the height here and
  49.     // then setting it back before doing a paint.
  50.     if ( pbi->bmiHeader.biHeight < 0 )
  51.     {
  52.         pbi->bmiHeader.biHeight *= -1;
  53.         bInverted = TRUE;
  54.     }
  55.     rect.left = 0;
  56.     rect.top = 0;
  57.     rect.right = pbih->biWidth;
  58.     rect.bottom = pbih->biHeight;
  59.     
  60.     CalculateAspectRatio( prgSize, &rect );
  61.     // only both with the scaling and sharpening if we are messing with the size...
  62.     if (( rect.right - rect.left != pbih->biWidth ) || ( rect.bottom - rect.top != pbih->biHeight ))
  63.     {
  64.         hr = ThumbnailMaker_Create( &pThumbMaker );
  65.         if ( SUCCEEDED( hr ))
  66.         {
  67.             // initialize thumbnail maker. 
  68.             hr = pThumbMaker->Init( rect.right - rect.left, rect.bottom - rect.top, 
  69.                                     pbi->bmiHeader.biWidth, abs( pbi->bmiHeader.biHeight ) );
  70.         }
  71.         if ( SUCCEEDED( hr ) )
  72.         {
  73.             // scale image.
  74.             hr = pThumbMaker->AddDIBSECTION( pbiUsed, pBits );
  75.             if ( SUCCEEDED( hr ) )
  76.             {
  77.                 DWORD   dwSize;
  78.                 hr = pThumbMaker->GetSharpenedBITMAPINFO( uiSharpPct, &pbiScaled, &dwSize );
  79.             }
  80.         }
  81.         if ( SUCCEEDED( hr ) )
  82.         {
  83.             pScaledBits = ( LPBYTE )pbiScaled + sizeof( BITMAPINFOHEADER );
  84.         }
  85.         if ( pThumbMaker )
  86.         {
  87.             pThumbMaker->Release( );
  88.         }
  89.         if ( FAILED( hr ))
  90.         {
  91.             return hr;
  92.         }
  93.     }
  94.     // set the height back to negative if that's the way it was before.
  95.     if ( bInverted == TRUE )
  96.         pbiScaled->bmiHeader.biHeight *= -1;
  97.     // now if they have asked for origsize rather than the boxed one, and the colour depth is OK, then 
  98.     // return it...
  99.     if ( fOrigSize && pbiScaled->bmiHeader.biBitCount <= dwRecClrDepth )
  100.     {
  101.         SIZE rgCreateSize = { pbiScaled->bmiHeader.biWidth, pbiScaled->bmiHeader.biHeight };
  102.         LPVOID pNewBits;
  103.         
  104.         // turn the PbiScaled DIB into a HBITMAP...., note we pass the old biInfo so that it can get the palette form
  105.         // it if need be.
  106.         bRetVal = CreateSizedDIBSECTION( & rgCreateSize, pbiScaled->bmiHeader.biBitCount, NULL, pbiScaled, phBmpThumbnail, NULL, &pNewBits );
  107.         if ( bRetVal )
  108.         {
  109.             // copy the image data accross...
  110.             CopyMemory( pNewBits, pScaledBits, CalcImageSize( &rgCreateSize, pbiScaled->bmiHeader.biBitCount )); 
  111.         }
  112.         
  113.         return bRetVal;
  114.     }
  115.     
  116.     bRetVal = FactorAspectRatio( pbiScaled,
  117.                                  pScaledBits,
  118.                                  prgSize,
  119.                                  rect,
  120.                                  dwRecClrDepth,
  121.                                  hpal,
  122.                                  fOrigSize,
  123.                                  phBmpThumbnail );
  124.     if ( pbiScaled != pbi )
  125.     {
  126.         // free the allocated image...
  127.         CoTaskMemFree( pbiScaled );
  128.     }
  129.     return bRetVal;
  130. }
  131. ////////////////////////////////////////////////////////////////////////////////////
  132. // This function makes no assumption about whether the thumbnail is square, so 
  133. // it calculates the scaling ratio for both dimensions and the uses that as
  134. // the scaling to maintain the aspect ratio.
  135. void CalcAspectScaledRect( const SIZE * prgSize, RECT * pRect )
  136. {
  137.     Assert( pRect->left == 0 );
  138.     Assert( pRect->top == 0 );
  139.     int iWidth = pRect->right;
  140.     int iHeight = pRect->bottom;
  141.     int iXRatio = (iWidth * 1000) / prgSize->cx;
  142.     int iYRatio = (iHeight * 1000) / prgSize->cy;
  143.     if ( iXRatio > iYRatio )
  144.     {
  145.         pRect->right = prgSize->cx;
  146.         
  147.         // work out the blank space and split it evenly between the top and the bottom...
  148.         int iNewHeight = (( iHeight * 1000 ) / iXRatio); 
  149.         if ( iNewHeight == 0 )
  150.         {
  151.             iNewHeight = 1;
  152.         }
  153.         
  154.         int iRemainder = prgSize->cy - iNewHeight;
  155.         pRect->top = iRemainder / 2;
  156.         pRect->bottom = iNewHeight + pRect->top;
  157.     }
  158.     else
  159.     {
  160.         pRect->bottom = prgSize->cy;
  161.         // work out the blank space and split it evenly between the left and the right...
  162.         int iNewWidth = (( iWidth * 1000 ) / iYRatio);
  163.         if ( iNewWidth == 0 )
  164.         {
  165.             iNewWidth = 1;
  166.         }
  167.         int iRemainder = prgSize->cx - iNewWidth;
  168.         
  169.         pRect->left = iRemainder / 2;
  170.         pRect->right = iNewWidth + pRect->left;
  171.     }
  172. }
  173.     
  174. void CalculateAspectRatio( const SIZE * prgSize, RECT * pRect )
  175. {
  176.     int iHeight = abs( pRect->bottom - pRect->top );
  177.     int iWidth = abs( pRect->right - pRect->left );
  178.     // check if the initial bitmap is larger than the size of the thumbnail.
  179.     if ( iWidth > prgSize->cx || iHeight > prgSize->cy )
  180.     {
  181.         pRect->left = 0;
  182.         pRect->top = 0;
  183.         pRect->right = iWidth;
  184.         pRect->bottom = iHeight;
  185.         CalcAspectScaledRect( prgSize, pRect );
  186.     }
  187.     else
  188.     {
  189.         // if the bitmap was smaller than the thumbnail, just center it.
  190.         pRect->left = ( prgSize->cx - iWidth ) / 2;
  191.         pRect->top = ( prgSize->cy- iHeight ) / 2;
  192.         pRect->right = pRect->left + iWidth;
  193.         pRect->bottom = pRect->top + iHeight;
  194.     }
  195. }
  196. ////////////////////////////////////////////////////////////////////////////////////
  197. LPBYTE g_pbCMAP = NULL;
  198. #define CMAP_SIZE 32768
  199. BOOL FactorAspectRatio( LPBITMAPINFO pbiScaled, LPVOID pScaledBits, const SIZE * prgSize, 
  200.                         RECT rect, DWORD dwClrDepth, HPALETTE hpal, BOOL fOrigSize, HBITMAP * phBmpThumbnail )
  201. {
  202.     HWND                hwnd = GetDesktopWindow( );
  203.     HDC                 hdcWnd = GetDC( hwnd );
  204.     HDC                 hdc = CreateCompatibleDC( hdcWnd );
  205.     PBITMAPINFOHEADER   pbih = ( PBITMAPINFOHEADER )pbiScaled;
  206.     BOOL                bRetVal = FALSE;
  207.     int                 iRetVal = GDI_ERROR;
  208.     BITMAPINFO *        pDitheredInfo = NULL;
  209.     LPVOID              pDitheredBits = NULL;
  210.     HBITMAP             hbmpDithered = NULL;
  211.     if ( dwClrDepth == 8 )
  212.     {
  213.         RGBQUAD * pSrcColors = NULL;
  214.         LONG nSrcPitch = pbiScaled->bmiHeader.biWidth;
  215.         
  216.         // we are going to 8 bits per pixel, we had better dither everything 
  217.         // to the same palette, otherwise we are going to suck.
  218.         GUID guidType = CLSID_NULL;
  219.         switch( pbiScaled->bmiHeader.biBitCount )
  220.         {
  221.             case 32:
  222.                 guidType = BFID_RGB_32;
  223.                 nSrcPitch *= sizeof( DWORD );
  224.                 break;
  225.                 
  226.             case 24:
  227.                 guidType = BFID_RGB_24;
  228.                 nSrcPitch *= 3;
  229.                 break;
  230.                 
  231.             case 16:
  232.                 // default is 555
  233.                 guidType = BFID_RGB_555;
  234.                 // 5-6-5 bitfields has the second DWORD (the green component) as 0x7e00
  235.                 if ( pbiScaled->bmiHeader.biCompression == BI_BITFIELDS && 
  236.                      pbiScaled->bmiColors[1].rgbGreen == 0x7E )
  237.                 {
  238.                     guidType = BFID_RGB_565;
  239.                 }
  240.                 nSrcPitch *= sizeof( WORD );
  241.                 break;
  242.                 
  243.             case 8:
  244.                 guidType = BFID_RGB_8;
  245.                 pSrcColors = pbiScaled->bmiColors;
  246.                 // nSrcPitch is already in bytes...
  247.                 break;
  248.         };
  249.         if ( nSrcPitch % 4 )
  250.         {
  251.             // round up to the nearest DWORD...
  252.             nSrcPitch = nSrcPitch + 4 - (nSrcPitch %4);
  253.         }
  254.         // we are going to 8bpp
  255.         LONG nDestPitch = pbiScaled->bmiHeader.biWidth;
  256.         if ( nDestPitch % 4 )
  257.         {
  258.             // round up to the nearest DWORD...
  259.             nDestPitch = nDestPitch + 4 - (nDestPitch % 4);
  260.         }
  261.         
  262.         if ( guidType != CLSID_NULL )
  263.         {
  264.             if ( g_pbCMAP == NULL )
  265.             {
  266.                 g_pbCMAP = (LPBYTE) LocalAlloc( LPTR, CMAP_SIZE );
  267.                 if ( !g_pbCMAP )
  268.                 {
  269.                     return FALSE;
  270.                 }
  271.                 // we are always going to the shell halftone palette right now, otherwise
  272.                 // computing this inverse colour map sucks a lot of time (approx 2 seconds on
  273.                 // a p200 )
  274.                 if ( FAILED( SHGetInverseCMAP( g_pbCMAP, CMAP_SIZE )))
  275.                 {
  276.                     return FALSE;
  277.                 }
  278.             }   
  279.             SIZE rgDithered = {pbiScaled->bmiHeader.biWidth, pbiScaled->bmiHeader.biHeight};
  280.             if ( rgDithered.cy < 0 )
  281.             {
  282.                 // invert it
  283.                 rgDithered.cy = -rgDithered.cy;
  284.             }
  285.             
  286.             if ( CreateSizedDIBSECTION( &rgDithered, dwClrDepth, hpal, NULL, &hbmpDithered, &pDitheredInfo, &pDitheredBits ))
  287.             {
  288.                 Assert( pDitheredInfo && pDitheredBits );
  289.                 
  290.                 // dither....
  291.                 IIntDitherer * pDither;
  292.                 HRESULT hr = CoCreateInstance( CLSID_IntDitherer,
  293.                                                NULL,
  294.                                                CLSCTX_INPROC_SERVER,
  295.                                                IID_IIntDitherer,
  296.                                                (LPVOID *) &pDither );
  297.                 if ( SUCCEEDED( hr ))
  298.                 {
  299.                     hr = pDither->DitherTo8bpp ( (LPBYTE) pDitheredBits, nDestPitch, 
  300.                                                  (LPBYTE) pScaledBits, nSrcPitch, guidType, 
  301.                                                  pDitheredInfo->bmiColors, pSrcColors,
  302.                                                  g_pbCMAP, 0, 0, rgDithered.cx, rgDithered.cy,
  303.                                                  -1, -1 );
  304.                     pDither->Release();
  305.                 }
  306.                 if ( SUCCEEDED( hr ))
  307.                 {
  308.                     // if the height was inverted, then invert it in the destination bitmap
  309.                     if ( rgDithered.cy != pbiScaled->bmiHeader.biHeight )
  310.                     {
  311.                         pDitheredInfo->bmiHeader.biHeight = - rgDithered.cy;
  312.                     }
  313.                     
  314.                     // switch to the new image .....
  315.                     pbiScaled = pDitheredInfo;
  316.                     pScaledBits = pDitheredBits;
  317.                 }
  318.             }
  319.         }
  320.     }
  321.     
  322.     // create thumbnail bitmap and copy image into it.
  323.     if (CreateSizedDIBSECTION( prgSize, dwClrDepth, hpal, NULL, phBmpThumbnail, NULL, NULL ))
  324.     {
  325.         
  326.         HBITMAP hBmpOld = (HBITMAP) SelectObject( hdc, *phBmpThumbnail );
  327.         SetStretchBltMode( hdc, COLORONCOLOR);
  328.         HGDIOBJ hBrush = GetStockObject( THUMBNAIL_BACKGROUND_BRUSH );
  329.         HGDIOBJ hPen = GetStockObject( THUMBNAIL_BACKGROUND_PEN );
  330.         HGDIOBJ hOldBrush = SelectObject( hdc, hBrush );
  331.         HGDIOBJ hOldPen = SelectObject( hdc, hPen );
  332.         HPALETTE hpalOld;
  333.         if ( hpal )
  334.         {
  335.             hpalOld = SelectPalette( hdc, hpal, TRUE );
  336.             RealizePalette( hdc);
  337.         }
  338.         
  339.         SetMapMode( hdc, MM_TEXT );
  340.         
  341.         Rectangle( hdc, 0, 0, prgSize->cx, prgSize->cy );
  342.         int iDstHt = rect.bottom - rect.top;
  343.         int iDstTop = rect.top, iSrcTop = 0;
  344.         if ( pbih->biHeight < 0 )
  345.         {
  346.             iDstHt *= -1;
  347.             iDstTop = rect.bottom;
  348.             iSrcTop = abs( pbih->biHeight );
  349.         }
  350.         iRetVal = StretchDIBits( hdc, 
  351.                                      rect.left, iDstTop, rect.right - rect.left, iDstHt, 
  352.                                      0, iSrcTop, pbih->biWidth, pbih->biHeight, 
  353.                                      pScaledBits, 
  354.                                      pbiScaled,
  355.                                      DIB_RGB_COLORS, 
  356.                                      SRCCOPY );
  357.         SelectObject( hdc, hOldBrush );
  358.         SelectObject( hdc, hOldPen );
  359.         if ( hpal )
  360.         {
  361.             SelectPalette( hdc, hpalOld, TRUE );
  362.             RealizePalette( hdc );
  363.         }
  364.         
  365.         SelectObject( hdc, hBmpOld );
  366.         ReleaseDC( hwnd, hdcWnd );
  367.         DeleteDC( hdc );
  368.     }
  369.     if ( hbmpDithered )
  370.     {
  371.         DeleteObject( hbmpDithered );
  372.     }
  373.     if ( pDitheredInfo )
  374.     {
  375.         LocalFree( pDitheredInfo );
  376.     }
  377.     
  378.     return ( iRetVal != GDI_ERROR );
  379. }
  380. ///////////////////////////////////////////////////////////////////////////////////////////////////
  381. HRESULT RegisterHandler( LPCSTR pszExts, UINT cExts, UINT cEntrySize, LPCSTR pszIID, LPCSTR pszCLSID )
  382. {
  383.     for ( UINT cKey = 0; cKey < cExts; cKey ++ )
  384.     {
  385.         HKEY hKey1;
  386.         DWORD dwAction;
  387.         LONG lRes = RegCreateKeyExA( HKEY_CLASSES_ROOT,
  388.                                     pszExts,
  389.                                     0,
  390.                                     NULL,
  391.                                     REG_OPTION_NON_VOLATILE,
  392.                                     KEY_WRITE | KEY_READ,
  393.                                     NULL,
  394.                                     &hKey1,
  395.                                     &dwAction );
  396.         if ( lRes != ERROR_SUCCESS )
  397.         {
  398.             return E_FAIL;
  399.         }
  400.         // specific APP hack for office95
  401.         CHAR szProgID[MAX_PATH];
  402.         szProgID[0] = 0;
  403.         DWORD cbSize = sizeof( szProgID );
  404.         if ( StrCmpA( pszExts, ".pot") == 0 || StrCmpA( pszExts, ".ppt") == 0 )
  405.         {
  406.             // if they key was created, check to see if the progID is empty
  407.             // this might have been left by us in Beta1
  408.             if ( dwAction != REG_CREATED_NEW_KEY )
  409.             {
  410.                 lRes = RegQueryValueExA( hKey1, "", NULL, NULL, (BYTE *) szProgID, &cbSize );
  411.                 if ( szProgID[0] == 0 )
  412.                 {
  413.                     dwAction = REG_CREATED_NEW_KEY;
  414.                 }
  415.             }
  416.             if ( dwAction == REG_CREATED_NEW_KEY )
  417.             {
  418.                 const CHAR c_szPPT[] = "Powerpoint.Show.7";
  419.                 const CHAR c_szPOT[] = "Powerpoint.Template";
  420.                 LPCSTR pszText = ( StrCmpA( pszExts, ".pot") == 0 ) ? c_szPOT : c_szPPT;
  421.                 
  422.                 RegSetValueExA( hKey1, "", 0, REG_SZ, (const BYTE *)pszText, (lstrlenA( pszText ) + 1 ) * sizeof( CHAR ));
  423.             }
  424.         }
  425.         
  426.         HKEY hKey2;
  427.         lRes = RegCreateKeyA( hKey1, c_szShellEx, &hKey2 );
  428.         RegCloseKey( hKey1 );
  429.         
  430.         if ( lRes != ERROR_SUCCESS )
  431.         {
  432.             return E_FAIL;
  433.         }
  434.         // to check for old versions....
  435.         RegDeleteValueA( hKey2, pszIID );
  436.         lRes = RegSetValueA( hKey2,
  437.                             pszIID,
  438.                             REG_SZ,
  439.                             pszCLSID,
  440.                             lstrlenA( pszCLSID ) * sizeof(CHAR));
  441.         RegCloseKey( hKey2 );
  442.         if ( lRes != ERROR_SUCCESS )
  443.         {
  444.             return E_FAIL;
  445.         }
  446.         pszExts += cEntrySize;
  447.     }
  448.     return NOERROR;
  449. }
  450. //////////////////////////////////////////////////////////////////////////////////////////////////
  451. HRESULT UnregisterHandler( LPCSTR pszExts, UINT cExts, UINT cEntrySize, LPCSTR pszIID, LPCSTR pszCLSID )
  452. {
  453.     for ( UINT cKey = 0; cKey < cExts; cKey ++ )
  454.     {
  455.         HKEY hKey1;
  456.         LONG lRes = RegOpenKeyA( HKEY_CLASSES_ROOT, pszExts, &hKey1 );
  457.         if ( lRes != ERROR_SUCCESS )
  458.         {
  459.             continue;
  460.         }
  461.         HKEY hKey2;
  462.         lRes = RegOpenKeyA( hKey1, c_szShellEx, &hKey2 );
  463.         RegCloseKey( hKey1 );
  464.         
  465.         if ( lRes != ERROR_SUCCESS )
  466.         {
  467.             continue;
  468.         }
  469.         lRes = RegDeleteKeyA( hKey2, pszIID );
  470.         RegCloseKey( hKey2 );
  471.         pszExts += cEntrySize;
  472.     }
  473.     return NOERROR;
  474. }
  475. ///////////////////////////////////////////////////////////////////////////////////////////
  476. ///////////////////////////CExtractImageTask///////////////////////////////////////////////
  477. ///////////////////////////////////////////////////////////////////////////////////////////
  478. HRESULT CExtractImageTask_Create( CThumbnailView * pView,
  479.                                   LPEXTRACTIMAGE pExtract,
  480.                                   LPCWSTR pszCache,
  481.                                   LPCWSTR pszFullPath,
  482.                                   LPCITEMIDLIST pidl,
  483.                                   const FILETIME * pftNewDateStamp,
  484.                                   int iItem,
  485.                                   DWORD dwFlags,
  486.                                   LPRUNNABLETASK * ppTask )
  487. {
  488.     Assert( ppTask );
  489.     Assert( pView );
  490.     Assert( pExtract );
  491.     Assert( pidl );
  492.     
  493.     CExtractImageTask * pNewTask = new CComObject<CExtractImageTask>;
  494.     if ( !pNewTask )
  495.     {
  496.         return E_OUTOFMEMORY;
  497.     }
  498.     pNewTask->m_pView = pView;
  499.     pNewTask->m_pExtract = pExtract;
  500.     pView->InternalAddRef();
  501.     pExtract->AddRef();
  502.     StrCpyNW( pNewTask->m_szCache, pszCache, ARRAYSIZE( pNewTask->m_szCache));
  503.     StrCpyNW( pNewTask->m_szFullPath, pszFullPath, ARRAYSIZE( pNewTask->m_szFullPath ));
  504.     
  505.     pNewTask->m_pidl = ILClone( pidl );
  506.     if (!(pNewTask->m_pidl))
  507.     {
  508.         return E_OUTOFMEMORY;
  509.     }
  510.     pNewTask->m_dwMask = pView->GetOverlayMask( pidl );
  511.     pNewTask->m_dwFlags = dwFlags;
  512.     if ( pftNewDateStamp )
  513.     {
  514.         pNewTask->m_ftDateStamp = * pftNewDateStamp;
  515.     }
  516.     pNewTask->m_fNoDateStamp = (pftNewDateStamp == NULL );
  517.     if ( iItem == -1 )
  518.     {
  519.         pNewTask->m_iItem = pView->FindItem( pidl );
  520.     }
  521.     else
  522.     {
  523.         pNewTask->m_iItem = iItem;
  524.     }
  525.     pNewTask->AddRef();
  526.     *ppTask = pNewTask;
  527.     return NOERROR;
  528. }
  529. //////////////////////////////////////////////////////////////////////////////////////////
  530. STDMETHODIMP CExtractImageTask::Run ( void )
  531. {
  532.     HRESULT hr = E_FAIL;
  533.     if ( m_lState == IRTIR_TASK_RUNNING )
  534.     {
  535.         hr = S_FALSE;
  536.     }
  537.     else if ( m_lState == IRTIR_TASK_PENDING )
  538.     {
  539.         hr = E_FAIL;
  540.     }
  541.     else if ( m_lState == IRTIR_TASK_NOT_RUNNING )
  542.     {
  543.         LONG lRes = InterlockedExchange( & m_lState, IRTIR_TASK_RUNNING);
  544.         if ( lRes == IRTIR_TASK_PENDING )
  545.         {
  546.             m_lState = IRTIR_TASK_FINISHED;
  547.             return NOERROR;
  548.         }
  549.         // see if it supports IRunnableTask
  550.         m_pExtract->QueryInterface( IID_IRunnableTask, (LPVOID *) & m_pTask );
  551.         m_pView->ThreadUpdateStatusBar(IDS_EXTRACTING, m_iItem );
  552.         
  553.         if ( m_lState == IRTIR_TASK_RUNNING )
  554.         {
  555.             // start the extractor....
  556.             hr = m_pExtract->Extract( &m_hBmp );
  557.         }
  558.         if ( SUCCEEDED( hr ) && m_lState == IRTIR_TASK_RUNNING )
  559.         {
  560.             hr = InternalResume();
  561.         }
  562.         if ( SUCCEEDED( hr ) && m_lState == IRTIR_TASK_RUNNING )
  563.         {
  564.             // reset the status bar....
  565.             m_pView->ThreadUpdateStatusBar();
  566.         }
  567.         
  568.         if ( m_lState != IRTIR_TASK_SUSPENDED || hr != E_PENDING )
  569.         {
  570.             m_lState = IRTIR_TASK_FINISHED;
  571.         }
  572.     }
  573.     
  574.     return hr;
  575. }
  576. /////////////////////////////////////////////////////////////////////////////////////////////////////
  577. STDMETHODIMP CExtractImageTask::Kill ( BOOL fWait )
  578. {
  579.     if ( m_lState != IRTIR_TASK_RUNNING )
  580.     {
  581.         return S_FALSE;
  582.     }
  583.     LONG lRes = InterlockedExchange( &m_lState, IRTIR_TASK_PENDING );
  584.     if ( lRes == IRTIR_TASK_FINISHED )
  585.     {
  586.         m_lState = lRes;
  587.         return NOERROR;
  588.     }
  589.     // does it support IRunnableTask ? Can we kill it ?
  590.     if ( m_pExtract != NULL )
  591.     {
  592.         LPRUNNABLETASK pTask = NULL;
  593.         HRESULT hr = m_pExtract->QueryInterface( IID_IRunnableTask, (LPVOID *) &pTask );
  594.         if ( SUCCEEDED( hr ))
  595.         {
  596.             hr = pTask->Kill( FALSE );
  597.             pTask->Release();
  598.         }
  599.     }
  600.     return NOERROR;
  601. }
  602. ///////////////////////////////////////////////////////////////////////////////////////
  603. STDMETHODIMP CExtractImageTask::Suspend( void )
  604. {
  605.     if ( !m_pTask )
  606.     {
  607.         return E_NOTIMPL;
  608.     }
  609.     if ( m_lState != IRTIR_TASK_RUNNING )
  610.     {
  611.         return E_FAIL;
  612.     }
  613.     
  614.     LONG lRes = InterlockedExchange( &m_lState, IRTIR_TASK_SUSPENDED );
  615.     HRESULT hr = m_pTask->Suspend();
  616.     if ( SUCCEEDED( hr ))
  617.     {
  618.         lRes = (LONG) m_pTask->IsRunning();
  619.         if ( lRes == IRTIR_TASK_SUSPENDED )
  620.         {
  621.             if ( lRes != IRTIR_TASK_RUNNING )
  622.             {
  623.                 m_lState = lRes;
  624.             }
  625.         }
  626.     }
  627.     else
  628.     {
  629.         m_lState = lRes;
  630.     }
  631.     return hr;
  632. }
  633. ////////////////////////////////////////////////////////////////////////////////////////
  634. STDMETHODIMP CExtractImageTask::Resume( void )
  635. {
  636.     if ( !m_pTask )
  637.     {
  638.         return E_NOTIMPL;
  639.     }
  640.     if ( m_lState != IRTIR_TASK_SUSPENDED )
  641.     {
  642.         return E_FAIL;
  643.     }
  644.     m_lState = IRTIR_TASK_RUNNING;
  645.     m_pView->ThreadUpdateStatusBar(IDS_EXTRACTING, m_iItem );
  646.     
  647.     HRESULT hr = m_pTask->Resume();
  648.     if ( SUCCEEDED( hr ))
  649.     {
  650.         hr = InternalResume();
  651.     }
  652.     if ( SUCCEEDED( hr ) && m_lState == IRTIR_TASK_RUNNING)
  653.     {
  654.         // reset the status bar....
  655.         m_pView->ThreadUpdateStatusBar( );
  656.     }
  657.     
  658.     return hr;
  659. }
  660. /////////////////////////////////////////////////////////////////////////////////////////////////////
  661. HRESULT CExtractImageTask::InternalResume()
  662. {
  663.     Assert( m_hBmp != NULL );
  664.     HRESULT hr = m_pView->UpdateImageForItem( m_hBmp, 
  665.                                               m_iItem,
  666.                                               m_pidl,
  667.                                               m_szCache,
  668.                                               m_szFullPath,
  669.                                               ( m_fNoDateStamp ? NULL : &m_ftDateStamp),
  670.                                               (m_dwFlags & IEIFLAG_CACHE) ? TRUE : FALSE );
  671.     
  672.     // reset the status bar....
  673.     m_pView->ThreadUpdateStatusBar();
  674.     
  675.     m_lState = IRTIR_TASK_FINISHED;
  676.     return hr;
  677. }
  678. /////////////////////////////////////////////////////////////////////////////////////////////////////
  679. STDMETHODIMP_( ULONG ) CExtractImageTask:: IsRunning ( void )
  680. {
  681.     return m_lState;
  682. }
  683. /////////////////////////////////////////////////////////////////////////////////////////////////////
  684. CExtractImageTask::~CExtractImageTask()
  685. {
  686.     if ( m_pView )
  687.     {
  688.         m_pView->InternalRelease();
  689.     }
  690.     if ( m_pExtract )
  691.     {
  692.         m_pExtract->Release();
  693.     }
  694.     if ( m_pTask )
  695.     {
  696.         m_pTask->Release();
  697.     }
  698.     
  699.     if ( m_pidl )
  700.     {
  701.         SHFree((LPVOID) m_pidl );
  702.     }
  703.     if ( m_hBmp )
  704.     {
  705.         DeleteObject( m_hBmp );
  706.     }
  707.     
  708. }
  709. /////////////////////////////////////////////////////////////////////////////////////////////////////
  710. CExtractImageTask::CExtractImageTask()
  711. {
  712.     m_lState = IRTIR_TASK_NOT_RUNNING;
  713.     m_pView = NULL;
  714.     m_pExtract = NULL;
  715.     m_pidl = NULL;
  716.     m_hBmp = NULL;
  717. }
  718. /////////////////////////////////////////////////////////////////////////////////////////////////////
  719. UINT CalcImageSize( const SIZE * prgSize, DWORD dwClrDepth )
  720. {
  721.     UINT uSize = prgSize->cx * dwClrDepth;
  722.     
  723.     uSize *= ( prgSize->cy < 0 ) ? (- prgSize->cy) : prgSize->cy;
  724.     // divide by 8
  725.     UINT uRetVal = uSize >> 3;
  726.     if ( uSize & 7 )
  727.     {
  728.         uRetVal ++;
  729.     }
  730.     return uRetVal;
  731. }
  732. /////////////////////////////////////////////////////////////////////////////////////////////////////
  733. BOOL CreateSizedDIBSECTION( const SIZE * prgSize, 
  734.      DWORD dwClrDepth,
  735.      HPALETTE hpal,
  736.      const BITMAPINFO * pCurInfo,
  737.      HBITMAP * phBmp, 
  738.      BITMAPINFO ** ppBMI,
  739.      LPVOID * ppBits )
  740. {
  741.     *phBmp = NULL;
  742.     
  743.     HDC hdc = GetDC( NULL );
  744.     HDC hdcBmp = CreateCompatibleDC( hdc );
  745.     if ( hdcBmp && hdc )
  746.     {
  747.         struct {
  748.             BITMAPINFOHEADER bi;
  749.             DWORD            ct[256];
  750.         } dib;
  751.         dib.bi.biSize            = sizeof(BITMAPINFOHEADER);
  752.         dib.bi.biWidth           = prgSize->cx;
  753.         dib.bi.biHeight          = prgSize->cy;
  754.         dib.bi.biPlanes          = 1;
  755.         dib.bi.biBitCount        = (WORD) dwClrDepth;
  756.         dib.bi.biCompression     = BI_RGB;
  757.         dib.bi.biSizeImage       = CalcImageSize( prgSize, dwClrDepth );
  758.         dib.bi.biXPelsPerMeter   = 0;
  759.         dib.bi.biYPelsPerMeter   = 0;
  760.         dib.bi.biClrUsed         = ( dwClrDepth <= 8 ) ? (1 << dwClrDepth) : 0;
  761.         dib.bi.biClrImportant    = 0;
  762.         HPALETTE hpalOld = NULL;
  763.         
  764.         if ( dwClrDepth <= 8 )
  765.         {
  766.             // if they passed us the old structure with colour info, and we are the same bit depth, then copy it...
  767.             if ( pCurInfo && pCurInfo->bmiHeader.biBitCount == dwClrDepth )
  768.             {
  769.                 // use the passed in colour info to generate the DIBSECTION
  770.                 int iColours = pCurInfo->bmiHeader.biClrUsed;
  771.                 if ( !iColours )
  772.                 {
  773.                     iColours = dib.bi.biClrUsed;
  774.                 }
  775.                 // copy the data accross...
  776.                 CopyMemory( dib.ct, pCurInfo->bmiColors, sizeof( RGBQUAD) * iColours );
  777.             }
  778.             else
  779.             {
  780.                 // need to get the right palette....
  781.                 hpalOld = SelectPalette( hdcBmp, hpal, TRUE );
  782.                 RealizePalette( hdcBmp );
  783.             
  784.                 int n = GetPaletteEntries(hpal, 0, 256, (LPPALETTEENTRY)&dib.ct[0]);
  785.                 Assert( n >= (int) dib.bi.biClrUsed );
  786.                 // now convert the PALETTEENTRY to RGBQUAD
  787.                 for (int i = 0; i < (int)dib.bi.biClrUsed; i ++)
  788.                 {
  789.                     dib.ct[i] = RGB(GetBValue(dib.ct[i]),GetGValue(dib.ct[i]),GetRValue(dib.ct[i]));
  790.                 }
  791.             }
  792.         }
  793.  
  794.         LPVOID lpBits;
  795.         *phBmp = CreateDIBSection(hdcBmp, (LPBITMAPINFO)&dib, DIB_RGB_COLORS, &lpBits, NULL, 0);
  796.         if ( *phBmp )
  797.         {
  798.             if ( ppBMI )
  799.             {
  800.                 *ppBMI = (BITMAPINFO *) LocalAlloc( LPTR, sizeof( dib ));
  801.                 if ( *ppBMI )
  802.                 {
  803.                     CopyMemory( *ppBMI, &dib, sizeof( dib ));
  804.                 }
  805.             }
  806.             if ( ppBits )
  807.             {
  808.                 *ppBits = lpBits;
  809.             }
  810.         }
  811.         DeleteDC( hdcBmp );
  812.         ReleaseDC( NULL, hdc );
  813.     }
  814.     return (*phBmp != NULL );
  815. }
  816. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  817. LPVOID CalcBitsOffsetInDIB( LPBITMAPINFO pBMI )
  818. {
  819.     int ncolors = pBMI->bmiHeader.biClrUsed;
  820.     if (ncolors == 0 && pBMI->bmiHeader.biBitCount <= 8)
  821.         ncolors = 1 << pBMI->bmiHeader.biBitCount;
  822.         
  823.     if (pBMI->bmiHeader.biBitCount == 16 ||
  824.         pBMI->bmiHeader.biBitCount == 32)
  825.     {
  826.         if (pBMI->bmiHeader.biCompression == BI_BITFIELDS)
  827.         {
  828.             ncolors = 3;
  829.         }
  830.     }
  831.     return (LPVOID) ((UCHAR *)&pBMI->bmiColors[0] + ncolors * sizeof(RGBQUAD));
  832. }