Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1860 lines
62 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 1998
  4. *
  5. * TITLE: MISCUTIL.CPP
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: ShaunIv
  10. *
  11. * DATE: 5/28/1998
  12. *
  13. * DESCRIPTION: Various utility functions we use in more than one place
  14. *
  15. *******************************************************************************/
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. #include <advpub.h> // For RegInstall and related data structures
  19. #include <windowsx.h> // For RegInstall and related data structures
  20. #include "wiaffmt.h"
  21. #include "shellext.h"
  22. namespace WiaUiUtil
  23. {
  24. LONG Align( LONG n , LONG m )
  25. {
  26. return(n % m) ? (((n/m)+1)*m) : (n);
  27. }
  28. /*
  29. * StringToLong: Convert a string to a long. ASCII Arabic numerals only
  30. */
  31. LONG StringToLong( LPCTSTR pszStr )
  32. {
  33. LPTSTR pstr = (LPTSTR)pszStr;
  34. bool bNeg = (*pstr == TEXT('-'));
  35. if (bNeg)
  36. pstr++;
  37. LONG nTotal = 0;
  38. while (*pstr && *pstr >= TEXT('0') && *pstr <= TEXT('9'))
  39. {
  40. nTotal *= 10;
  41. nTotal += *pstr - TEXT('0');
  42. ++pstr;
  43. }
  44. return(bNeg ? -nTotal : nTotal);
  45. }
  46. SIZE MapDialogSize( HWND hwnd, const SIZE &size )
  47. {
  48. RECT rcTmp;
  49. rcTmp.left = rcTmp.top = 0;
  50. rcTmp.right = size.cx;
  51. rcTmp.bottom = size.cy;
  52. MapDialogRect( hwnd, &rcTmp );
  53. SIZE sizeTmp;
  54. sizeTmp.cx = rcTmp.right;
  55. sizeTmp.cy = rcTmp.bottom;
  56. return (sizeTmp);
  57. }
  58. /*******************************************************************************
  59. *
  60. * GetBmiSize
  61. *
  62. * DESCRIPTION:
  63. * Should never get biCompression == BI_RLE.
  64. *
  65. * PARAMETERS:
  66. *
  67. *******************************************************************************/
  68. LONG GetBmiSize(PBITMAPINFO pbmi)
  69. {
  70. WIA_PUSH_FUNCTION((TEXT("WiaUiUtil::GetBmiSize(0x%p)"), pbmi ));
  71. // determine the size of bitmapinfo
  72. LONG lSize = pbmi->bmiHeader.biSize;
  73. // no color table cases
  74. if (
  75. (pbmi->bmiHeader.biBitCount == 24) ||
  76. ((pbmi->bmiHeader.biBitCount == 32) &&
  77. (pbmi->bmiHeader.biCompression == BI_RGB)))
  78. {
  79. // no colors unless stated
  80. lSize += sizeof(RGBQUAD) * pbmi->bmiHeader.biClrUsed;
  81. return(lSize);
  82. }
  83. // bitfields cases
  84. if (((pbmi->bmiHeader.biBitCount == 32) &&
  85. (pbmi->bmiHeader.biCompression == BI_BITFIELDS)) ||
  86. (pbmi->bmiHeader.biBitCount == 16))
  87. {
  88. lSize += 3 * sizeof(RGBQUAD);
  89. return(lSize);
  90. }
  91. // palette cases
  92. if (pbmi->bmiHeader.biBitCount == 1)
  93. {
  94. LONG lPal = pbmi->bmiHeader.biClrUsed;
  95. if ((lPal == 0) || (lPal > 2))
  96. {
  97. lPal = 2;
  98. }
  99. lSize += lPal * sizeof(RGBQUAD);
  100. return(lSize);
  101. }
  102. // palette cases
  103. if (pbmi->bmiHeader.biBitCount == 4)
  104. {
  105. LONG lPal = pbmi->bmiHeader.biClrUsed;
  106. if ((lPal == 0) || (lPal > 16))
  107. {
  108. lPal = 16;
  109. }
  110. lSize += lPal * sizeof(RGBQUAD);
  111. return(lSize);
  112. }
  113. // palette cases
  114. if (pbmi->bmiHeader.biBitCount == 8)
  115. {
  116. LONG lPal = pbmi->bmiHeader.biClrUsed;
  117. if ((lPal == 0) || (lPal > 256))
  118. {
  119. lPal = 256;
  120. }
  121. lSize += lPal * sizeof(RGBQUAD);
  122. return(lSize);
  123. }
  124. // error
  125. return(0);
  126. }
  127. // Simple wrapper for MsgWaitForMultipleObjects
  128. bool MsgWaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds )
  129. {
  130. bool bEventOccurred = false;
  131. const int nCount = 1;
  132. while (true)
  133. {
  134. DWORD dwRes = MsgWaitForMultipleObjects(nCount,&hHandle,FALSE,dwMilliseconds,QS_ALLINPUT|QS_ALLPOSTMESSAGE);
  135. if (WAIT_OBJECT_0==dwRes)
  136. {
  137. // The handle was signalled, so we can break out of our loop, returning true
  138. bEventOccurred = true;
  139. break;
  140. }
  141. else if (WAIT_OBJECT_0+nCount==dwRes)
  142. {
  143. // pull all of the messages out of the queue and process them
  144. MSG msg;
  145. while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
  146. {
  147. if (msg.message == WM_QUIT)
  148. break;
  149. TranslateMessage(&msg);
  150. DispatchMessage(&msg);
  151. }
  152. }
  153. else
  154. {
  155. // The handle either timed out, or the mutex was abandoned, so we can break out of our loop, returning false
  156. break;
  157. }
  158. }
  159. return bEventOccurred;
  160. }
  161. void CenterWindow( HWND hWnd, HWND hWndParent )
  162. {
  163. if (IsWindow(hWnd))
  164. {
  165. if (!hWndParent)
  166. {
  167. //
  168. // If the window to be centered on is NULL, use the desktop window
  169. //
  170. hWndParent = GetDesktopWindow();
  171. }
  172. else
  173. {
  174. //
  175. // If the window to be centered on is minimized, use the desktop window
  176. //
  177. DWORD dwStyle = GetWindowLong(hWndParent, GWL_STYLE);
  178. if (dwStyle & WS_MINIMIZE)
  179. {
  180. hWndParent = GetDesktopWindow();
  181. }
  182. }
  183. //
  184. // Get the window rects
  185. //
  186. RECT rcParent, rcCurrent;
  187. GetWindowRect( hWndParent, &rcParent );
  188. GetWindowRect( hWnd, &rcCurrent );
  189. //
  190. // Get the desired coordinates for the upper-left hand corner
  191. //
  192. RECT rcFinal;
  193. rcFinal.left = rcParent.left + (RectWidth(rcParent) - RectWidth(rcCurrent))/2;
  194. rcFinal.top = rcParent.top + (RectHeight(rcParent) - RectHeight(rcCurrent))/2;
  195. rcFinal.right = rcFinal.left + RectWidth(rcCurrent);
  196. rcFinal.bottom = rcFinal.top + RectHeight(rcCurrent);
  197. //
  198. // Make sure we're not off the screen
  199. //
  200. HMONITOR hMonitor = MonitorFromRect( &rcFinal, MONITOR_DEFAULTTONEAREST );
  201. if (hMonitor)
  202. {
  203. MONITORINFO MonitorInfo = {0};
  204. MonitorInfo.cbSize = sizeof(MonitorInfo);
  205. //
  206. // Get the screen coordinates of this monitor
  207. //
  208. if (GetMonitorInfo(hMonitor, &MonitorInfo))
  209. {
  210. //
  211. // Ensure the window is in the working area's region
  212. //
  213. rcFinal.left = Max<int>(MonitorInfo.rcWork.left, Min<int>( MonitorInfo.rcWork.right - RectWidth(rcCurrent), rcFinal.left ));
  214. rcFinal.top = Max<int>(MonitorInfo.rcWork.top, Min<int>( MonitorInfo.rcWork.bottom - RectHeight(rcCurrent), rcFinal.top ));
  215. }
  216. }
  217. // Move it
  218. SetWindowPos( hWnd, NULL, rcFinal.left, rcFinal.top, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOZORDER );
  219. }
  220. }
  221. // Flip an image horizontally
  222. bool FlipImage( PBYTE pBits, LONG nWidth, LONG nHeight, LONG nBitDepth )
  223. {
  224. bool bResult = false;
  225. if (pBits && nWidth>=0 && nHeight>=0 && nBitDepth>=0)
  226. {
  227. LONG nLineWidthInBytes = WiaUiUtil::Align(nWidth*nBitDepth,sizeof(DWORD)*8)/8;
  228. PBYTE pTempLine = new BYTE[nLineWidthInBytes];
  229. if (pTempLine)
  230. {
  231. for (int i=0;i<nHeight/2;i++)
  232. {
  233. PBYTE pSrc = pBits + (i * nLineWidthInBytes);
  234. PBYTE pDst = pBits + ((nHeight-i-1) * nLineWidthInBytes);
  235. CopyMemory( pTempLine, pSrc, nLineWidthInBytes );
  236. CopyMemory( pSrc, pDst, nLineWidthInBytes );
  237. CopyMemory( pDst, pTempLine, nLineWidthInBytes );
  238. }
  239. bResult = true;
  240. }
  241. delete[] pTempLine;
  242. }
  243. return bResult;
  244. }
  245. HRESULT InstallInfFromResource( HINSTANCE hInstance, LPCSTR pszSectionName )
  246. {
  247. HRESULT hr;
  248. HINSTANCE hInstAdvPackDll = LoadLibrary(TEXT("ADVPACK.DLL"));
  249. if (hInstAdvPackDll)
  250. {
  251. REGINSTALL pfnRegInstall = reinterpret_cast<REGINSTALL>(GetProcAddress( hInstAdvPackDll, "RegInstall" ));
  252. if (pfnRegInstall)
  253. {
  254. #if defined(WINNT)
  255. STRENTRY astrEntry[] =
  256. {
  257. { "25", "%SystemRoot%" },
  258. { "11", "%SystemRoot%\\system32" }
  259. };
  260. STRTABLE strTable = { sizeof(astrEntry)/sizeof(astrEntry[0]), astrEntry };
  261. hr = pfnRegInstall(hInstance, pszSectionName, &strTable);
  262. #else
  263. hr = pfnRegInstall(hInstance, pszSectionName, NULL);
  264. #endif
  265. } else hr = HRESULT_FROM_WIN32(GetLastError());
  266. FreeLibrary(hInstAdvPackDll);
  267. } else hr = HRESULT_FROM_WIN32(GetLastError());
  268. return hr;
  269. }
  270. /******************************************************************************
  271. WriteDIBToFile
  272. Writes a DIB to a file.
  273. ******************************************************************************/
  274. HRESULT
  275. WriteDIBToFile( HBITMAP hDib, HANDLE hFile )
  276. {
  277. if (!hDib)
  278. {
  279. return E_INVALIDARG;
  280. }
  281. // Make sure this is a valid DIB and get this useful info.
  282. DIBSECTION ds;
  283. if (!GetObject( hDib, sizeof(DIBSECTION), &ds ))
  284. {
  285. return E_INVALIDARG;
  286. }
  287. // We only deal with DIBs
  288. if (ds.dsBm.bmPlanes != 1)
  289. {
  290. return E_INVALIDARG;
  291. }
  292. // Calculate some color table sizes
  293. int nColors = ds.dsBmih.biBitCount <= 8 ? 1 << ds.dsBmih.biBitCount : 0;
  294. int nBitfields = ds.dsBmih.biCompression == BI_BITFIELDS ? 3 : 0;
  295. // Calculate the data size
  296. int nImageDataSize = ds.dsBmih.biSizeImage ? ds.dsBmih.biSizeImage : ds.dsBm.bmWidthBytes * ds.dsBm.bmHeight;
  297. // Get the color table (if needed)
  298. RGBQUAD rgbqaColorTable[256] = {0};
  299. if (nColors)
  300. {
  301. HDC hDC = CreateCompatibleDC(NULL);
  302. if (hDC)
  303. {
  304. HBITMAP hOldBitmap = reinterpret_cast<HBITMAP>(SelectObject(hDC,hDib));
  305. GetDIBColorTable( hDC, 0, nColors, rgbqaColorTable );
  306. SelectObject(hDC,hOldBitmap);
  307. DeleteDC( hDC );
  308. }
  309. }
  310. // Create the file header
  311. BITMAPFILEHEADER bmfh;
  312. bmfh.bfType = 'MB';
  313. bmfh.bfSize = 0;
  314. bmfh.bfReserved1 = 0;
  315. bmfh.bfReserved2 = 0;
  316. bmfh.bfOffBits = sizeof(bmfh) + sizeof(ds.dsBmih) + nBitfields*sizeof(DWORD) + nColors*sizeof(RGBQUAD);
  317. // Start writing! Note that we write out the bitfields and the color table. Only one,
  318. // at most, will actually result in data being written
  319. DWORD dwBytesWritten;
  320. if (!WriteFile( hFile, &bmfh, sizeof(bmfh), &dwBytesWritten, NULL ))
  321. return HRESULT_FROM_WIN32(GetLastError());
  322. if (!WriteFile( hFile, &ds.dsBmih, sizeof(ds.dsBmih), &dwBytesWritten, NULL ))
  323. return HRESULT_FROM_WIN32(GetLastError());
  324. if (!WriteFile( hFile, &ds.dsBitfields, nBitfields*sizeof(DWORD), &dwBytesWritten, NULL ))
  325. return HRESULT_FROM_WIN32(GetLastError());
  326. if (!WriteFile( hFile, rgbqaColorTable, nColors*sizeof(RGBQUAD), &dwBytesWritten, NULL ))
  327. return HRESULT_FROM_WIN32(GetLastError());
  328. if (!WriteFile( hFile, ds.dsBm.bmBits, nImageDataSize, &dwBytesWritten, NULL ))
  329. return HRESULT_FROM_WIN32(GetLastError());
  330. return S_OK;
  331. }
  332. HFONT ChangeFontFromWindow( HWND hWnd, int nPointSizeDelta )
  333. {
  334. HFONT hFontResult = NULL;
  335. //
  336. // Get the window's font
  337. //
  338. HFONT hFont = GetFontFromWindow(hWnd);
  339. if (hFont)
  340. {
  341. LOGFONT LogFont = {0};
  342. if (GetObject( hFont, sizeof(LogFont), &LogFont ))
  343. {
  344. HDC hDC = GetDC(hWnd);
  345. if (hDC)
  346. {
  347. HFONT hOldFont = SelectFont(hDC,hFont);
  348. TEXTMETRIC TextMetric = {0};
  349. if (GetTextMetrics( hDC, &TextMetric ))
  350. {
  351. //
  352. // Get the current font's point size
  353. //
  354. int nPointSize = MulDiv( TextMetric.tmHeight-TextMetric.tmInternalLeading, 72, GetDeviceCaps(hDC, LOGPIXELSY) ) + nPointSizeDelta;
  355. //
  356. // Calculate the height of the new font
  357. //
  358. LogFont.lfHeight = -MulDiv(nPointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);
  359. //
  360. // Create the font
  361. //
  362. hFontResult = CreateFontIndirect( &LogFont );
  363. }
  364. if (hOldFont)
  365. {
  366. SelectFont( hDC, hOldFont );
  367. }
  368. ReleaseDC( hWnd, hDC );
  369. }
  370. }
  371. }
  372. return hFontResult;
  373. }
  374. HFONT GetFontFromWindow( HWND hWnd )
  375. {
  376. //
  377. // Get the window's font
  378. //
  379. HFONT hFontResult = reinterpret_cast<HFONT>(SendMessage(hWnd,WM_GETFONT,0,0));
  380. if (!hFontResult)
  381. {
  382. hFontResult = reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT));
  383. }
  384. return hFontResult;
  385. }
  386. HFONT CreateFontWithPointSizeFromWindow( HWND hWnd, int nPointSize, bool bBold, bool bItalic )
  387. {
  388. HFONT hFontResult = NULL;
  389. HFONT hFont = GetFontFromWindow(hWnd);
  390. if (hFont)
  391. {
  392. LOGFONT LogFont = {0};
  393. if (GetObject( hFont, sizeof(LogFont), &LogFont ))
  394. {
  395. HDC hDC = GetDC(NULL);
  396. if (hDC)
  397. {
  398. if (nPointSize)
  399. {
  400. LogFont.lfHeight = -MulDiv(nPointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);
  401. }
  402. if (bBold)
  403. {
  404. LogFont.lfWeight = FW_BOLD;
  405. }
  406. if (bItalic)
  407. {
  408. LogFont.lfItalic = TRUE;
  409. }
  410. hFontResult = CreateFontIndirect( &LogFont );
  411. ReleaseDC( NULL, hDC );
  412. }
  413. }
  414. }
  415. return hFontResult;
  416. }
  417. SIZE GetTextExtentFromWindow( HWND hFontWnd, LPCTSTR pszString )
  418. {
  419. SIZE sizeResult = {0,0};
  420. HDC hDC = GetDC( hFontWnd );
  421. if (hDC)
  422. {
  423. HFONT hFont = GetFontFromWindow(hFontWnd);
  424. if (hFont)
  425. {
  426. HFONT hOldFont = SelectFont( hDC, hFont );
  427. SIZE sizeExtent = {0,0};
  428. if (GetTextExtentPoint32( hDC, pszString, lstrlen(pszString), &sizeExtent ))
  429. {
  430. sizeResult = sizeExtent;
  431. }
  432. //
  433. // Restore the DC
  434. //
  435. if (hOldFont)
  436. {
  437. SelectFont( hDC, hOldFont );
  438. }
  439. }
  440. ReleaseDC( hFontWnd, hDC );
  441. }
  442. return sizeResult;
  443. }
  444. CSimpleString TruncateTextToFitInRect( HWND hFontWnd, LPCTSTR pszString, RECT rectTarget, UINT nDrawTextFormat )
  445. {
  446. WIA_PUSH_FUNCTION((TEXT("WiaUiUtil::TruncateTextToFitInRect( 0x%p, %s, (%d,%d,%d,%d), 0x%08X"), hFontWnd, pszString, rectTarget.left, rectTarget.top, rectTarget.right, rectTarget.bottom, nDrawTextFormat ));
  447. CSimpleString strResult = pszString;
  448. //
  449. // Make sure we have valid parameters
  450. //
  451. if (IsWindow(hFontWnd) && hFontWnd && pszString && lstrlen(pszString))
  452. {
  453. //
  454. // Make a copy of the string. If it fails, we will just return the original string.
  455. //
  456. LPTSTR pszTemp = new TCHAR[lstrlen(pszString)+1];
  457. if (pszTemp)
  458. {
  459. lstrcpy( pszTemp, pszString );
  460. //
  461. // Get a client DC for the window
  462. //
  463. HDC hDC = GetDC( hFontWnd );
  464. if (hDC)
  465. {
  466. //
  467. // Create a memory DC
  468. //
  469. HDC hMemDC = CreateCompatibleDC( hDC );
  470. if (hMemDC)
  471. {
  472. //
  473. // Get the font the window is using and select it into our client dc
  474. //
  475. HFONT hFont = GetFontFromWindow(hFontWnd);
  476. if (hFont)
  477. {
  478. //
  479. // Select the font
  480. //
  481. HFONT hOldFont = SelectFont( hMemDC, hFont );
  482. //
  483. // Modify the string using DrawText
  484. //
  485. if (DrawText( hMemDC, pszTemp, lstrlen(pszTemp), &rectTarget, nDrawTextFormat|DT_MODIFYSTRING|DT_SINGLELINE ))
  486. {
  487. strResult = pszTemp;
  488. }
  489. else
  490. {
  491. WIA_ERROR((TEXT("DrawText failed")));
  492. }
  493. //
  494. // Restore the DC
  495. //
  496. if (hOldFont)
  497. {
  498. SelectFont( hMemDC, hOldFont );
  499. }
  500. }
  501. //
  502. // Clean up the memory DC
  503. //
  504. DeleteDC( hMemDC );
  505. }
  506. else
  507. {
  508. WIA_ERROR((TEXT("Unable to create the compatible DC")));
  509. }
  510. //
  511. // Release the DC
  512. //
  513. ReleaseDC( hFontWnd, hDC );
  514. }
  515. else
  516. {
  517. WIA_ERROR((TEXT("Unable to get the DC")));
  518. }
  519. //
  520. // Clean up our temp buffer
  521. //
  522. delete[] pszTemp;
  523. }
  524. else
  525. {
  526. WIA_ERROR((TEXT("Unable to allocate the temp buffer")));
  527. }
  528. }
  529. else
  530. {
  531. WIA_ERROR((TEXT("Argument validation failed")));
  532. }
  533. return strResult;
  534. }
  535. CSimpleString FitTextInStaticWithEllipsis( LPCTSTR pszString, HWND hWndStatic, UINT nDrawTextStyle )
  536. {
  537. //
  538. // Make sure we have valid parameters
  539. //
  540. if (!hWndStatic || !pszString || !IsWindow(hWndStatic))
  541. {
  542. return pszString;
  543. }
  544. //
  545. // Hide prefix characters?
  546. //
  547. if (GetWindowLong( hWndStatic, GWL_STYLE ) & SS_NOPREFIX)
  548. {
  549. nDrawTextStyle |= DT_NOPREFIX;
  550. }
  551. //
  552. // How big is the area we are trying to fit this in?
  553. //
  554. RECT rcClient;
  555. GetClientRect( hWndStatic, &rcClient );
  556. //
  557. // Calculate the result and return it
  558. //
  559. return TruncateTextToFitInRect( hWndStatic, pszString, rcClient, nDrawTextStyle );
  560. }
  561. //
  562. // Get the size of an icon
  563. //
  564. bool GetIconSize( HICON hIcon, SIZE &sizeIcon )
  565. {
  566. //
  567. // Assume failure
  568. //
  569. bool bSuccess = false;
  570. //
  571. // Get the icon information
  572. //
  573. ICONINFO IconInfo = {0};
  574. if (GetIconInfo( hIcon, &IconInfo ))
  575. {
  576. //
  577. // Get one of the bitmaps
  578. //
  579. BITMAP bm;
  580. if (GetObject( IconInfo.hbmColor, sizeof(bm), &bm ))
  581. {
  582. //
  583. // Save the size of the icon
  584. //
  585. sizeIcon.cx = bm.bmWidth;
  586. sizeIcon.cy = bm.bmHeight;
  587. //
  588. // Everything worked
  589. //
  590. bSuccess = true;
  591. }
  592. //
  593. // Free the bitmaps
  594. //
  595. DeleteObject(IconInfo.hbmMask);
  596. DeleteObject(IconInfo.hbmColor);
  597. }
  598. else
  599. {
  600. WIA_PRINTHRESULT((HRESULT_FROM_WIN32(GetLastError()),TEXT("GetIconInfo failed")));
  601. }
  602. return bSuccess;
  603. }
  604. HBITMAP CreateIconThumbnail( HWND hWnd, int nWidth, int nHeight, HICON hIcon, LPCTSTR pszText )
  605. {
  606. WIA_PUSH_FUNCTION((TEXT("CreateIconThumbnail( hWnd: 0x%p, nWidth: %d, nHeight: %d, hIcon: 0x%p, pszText: \"%s\" )"), hWnd, nWidth, nHeight, hIcon, pszText ? pszText : TEXT("") ));
  607. //
  608. // Initialize return value to NULL
  609. //
  610. HBITMAP hBmp = NULL;
  611. //
  612. // This will be set to true if all steps succeed.
  613. //
  614. bool bSuccess = false;
  615. //
  616. // The minimum whitespace around the icon and the text border
  617. //
  618. const int nIconBorder = 2;
  619. //
  620. // Get the DC to the window
  621. //
  622. HDC hDC = GetDC(hWnd);
  623. if (hDC)
  624. {
  625. //
  626. // Get a halftone palette
  627. //
  628. HPALETTE hHalftonePalette = CreateHalftonePalette(hDC);
  629. if (hHalftonePalette)
  630. {
  631. //
  632. // Initialize the bitmap information
  633. //
  634. BITMAPINFO BitmapInfo = {0};
  635. BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  636. BitmapInfo.bmiHeader.biWidth = nWidth;
  637. BitmapInfo.bmiHeader.biHeight = nHeight;
  638. BitmapInfo.bmiHeader.biPlanes = 1;
  639. BitmapInfo.bmiHeader.biBitCount = 24;
  640. BitmapInfo.bmiHeader.biCompression = BI_RGB;
  641. //
  642. // Create the DIB section
  643. //
  644. PBYTE pBitmapData = NULL;
  645. hBmp = CreateDIBSection( hDC, &BitmapInfo, DIB_RGB_COLORS, (LPVOID*)&pBitmapData, NULL, 0 );
  646. if (hBmp)
  647. {
  648. //
  649. // Create the source dc
  650. //
  651. HDC hMemoryDC = CreateCompatibleDC( hDC );
  652. if (hMemoryDC)
  653. {
  654. //
  655. // Set up the palette
  656. //
  657. HPALETTE hOldPalette = SelectPalette( hMemoryDC, hHalftonePalette , 0 );
  658. RealizePalette( hMemoryDC );
  659. SetBrushOrgEx( hMemoryDC, 0,0, NULL );
  660. //
  661. // Set up the DC
  662. //
  663. int nOldBkMode = SetBkMode( hMemoryDC, TRANSPARENT );
  664. COLORREF crOldTextColor = SetTextColor( hMemoryDC, GetSysColor(COLOR_WINDOWTEXT) );
  665. DWORD dwOldLayout = SetLayout( hMemoryDC, LAYOUT_BITMAPORIENTATIONPRESERVED );
  666. //
  667. // Select the bitmap into the memory DC
  668. //
  669. HBITMAP hOldBitmap = reinterpret_cast<HBITMAP>(SelectObject( hMemoryDC, hBmp ));
  670. //
  671. // Get the font to use
  672. //
  673. HFONT hFont = GetFontFromWindow(hWnd);
  674. //
  675. // Select the font
  676. //
  677. HFONT hOldFont = reinterpret_cast<HFONT>(SelectObject( hMemoryDC, hFont ) );
  678. //
  679. // Ensure we have a valid icon
  680. //
  681. if (hIcon)
  682. {
  683. //
  684. // Try to get the size of the icon
  685. //
  686. SIZE sizeIcon;
  687. if (GetIconSize( hIcon, sizeIcon ))
  688. {
  689. //
  690. // Fill the bitmap with the window color
  691. //
  692. RECT rc = { 0, 0, nWidth, nHeight };
  693. FillRect( hMemoryDC, &rc, GetSysColorBrush( COLOR_WINDOW ) );
  694. //
  695. // Get the text height for one line of text
  696. //
  697. SIZE sizeText = {0};
  698. if (pszText)
  699. {
  700. GetTextExtentPoint32( hMemoryDC, TEXT("X"), 1, &sizeText );
  701. }
  702. //
  703. // Center the icon + 1 line of text + margin in the thumbnail
  704. // We are assuming this bitmap can actually hold an icon + text
  705. //
  706. int nIconTop = rc.top + (RectHeight(rc) - ( sizeIcon.cy + sizeText.cy + nIconBorder )) / 2;
  707. //
  708. // Draw the icon
  709. //
  710. DrawIconEx( hMemoryDC, (nWidth - sizeIcon.cx)/2, nIconTop, hIcon, sizeIcon.cx, sizeIcon.cy, 0, NULL, DI_NORMAL );
  711. //
  712. // Only compute text things if there's text to draw
  713. //
  714. if (pszText && *pszText)
  715. {
  716. //
  717. // Decrease the rectangle's width by the icon border
  718. //
  719. InflateRect( &rc, -nIconBorder, 0 );
  720. //
  721. // Set the top of the text to the bottom of icon + the icon border
  722. //
  723. rc.top = nIconTop + sizeIcon.cy + nIconBorder;
  724. //
  725. // Draw the text
  726. //
  727. DrawTextEx( hMemoryDC, const_cast<LPTSTR>(pszText), -1, &rc, DT_CENTER|DT_END_ELLIPSIS|DT_NOPREFIX|DT_WORDBREAK, NULL );
  728. }
  729. //
  730. // Everything worked OK
  731. //
  732. bSuccess = true;
  733. }
  734. else
  735. {
  736. WIA_ERROR((TEXT("Couldn't get an icon size")));
  737. }
  738. }
  739. else
  740. {
  741. WIA_ERROR((TEXT("Didn't have a valid icon")));
  742. }
  743. //
  744. // Restore the dc's state
  745. //
  746. SelectObject( hMemoryDC, hOldFont );
  747. SelectObject( hMemoryDC, hOldBitmap );
  748. SelectPalette( hMemoryDC, hOldPalette , 0 );
  749. SetBkMode( hMemoryDC, nOldBkMode );
  750. SetTextColor( hMemoryDC, crOldTextColor );
  751. SetLayout( hMemoryDC, dwOldLayout );
  752. //
  753. // Delete the compatible DC
  754. //
  755. DeleteDC( hMemoryDC );
  756. }
  757. else
  758. {
  759. WIA_ERROR((TEXT("Unable to create a memory DC")));
  760. }
  761. }
  762. else
  763. {
  764. WIA_ERROR((TEXT("Unable to create a DIB section")));
  765. }
  766. //
  767. // Delete the halftone palette
  768. //
  769. if (hHalftonePalette)
  770. {
  771. DeleteObject( hHalftonePalette );
  772. }
  773. }
  774. else
  775. {
  776. WIA_ERROR((TEXT("Unable to get a halftone palette")));
  777. }
  778. //
  779. // Release the client DC
  780. //
  781. ReleaseDC( hWnd, hDC );
  782. }
  783. else
  784. {
  785. WIA_ERROR((TEXT("Unable to get a DC")));
  786. }
  787. //
  788. // Clean up in the event of failure
  789. //
  790. if (!bSuccess)
  791. {
  792. if (hBmp)
  793. {
  794. DeleteObject(hBmp);
  795. hBmp = NULL;
  796. }
  797. }
  798. return hBmp;
  799. }
  800. //
  801. // Create a bitmap with an icon and optional text
  802. //
  803. HBITMAP CreateIconThumbnail( HWND hWnd, int nWidth, int nHeight, HINSTANCE hIconInstance, const CResId &resIconId, LPCTSTR pszText )
  804. {
  805. //
  806. // Assume failure
  807. //
  808. HBITMAP hBmp = NULL;
  809. //
  810. // Load the specified icon
  811. //
  812. HICON hIcon = (HICON)LoadImage( hIconInstance, resIconId.ResourceName(), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR );
  813. if (hIcon)
  814. {
  815. //
  816. // Create the thumbnail
  817. //
  818. hBmp = CreateIconThumbnail( hWnd, nWidth, nHeight, hIcon, pszText );
  819. //
  820. // Free the icon (even though MSDN doesn't mention this, it will result in a leak if you don't)
  821. //
  822. DestroyIcon(hIcon);
  823. }
  824. return hBmp;
  825. }
  826. HRESULT SaveWiaItemAudio( IWiaItem *pWiaItem, LPCTSTR pszBaseFilename, CSimpleString &strAudioFilename )
  827. {
  828. //
  829. // Check the arguments
  830. //
  831. if (!pWiaItem || !pszBaseFilename || !lstrlen(pszBaseFilename))
  832. {
  833. return E_INVALIDARG;
  834. }
  835. //
  836. // Get the audio data property, if present
  837. //
  838. CComPtr<IWiaPropertyStorage> pWiaPropertyStorage;
  839. HRESULT hr = pWiaItem->QueryInterface( IID_IWiaPropertyStorage, (void**)(&pWiaPropertyStorage) );
  840. if (SUCCEEDED(hr))
  841. {
  842. PROPVARIANT PropVar[3] = {0};
  843. PROPSPEC PropSpec[3] = {0};
  844. PropSpec[0].ulKind = PRSPEC_PROPID;
  845. PropSpec[0].propid = WIA_IPC_AUDIO_DATA;
  846. PropSpec[1].ulKind = PRSPEC_PROPID;
  847. PropSpec[1].propid = WIA_IPC_AUDIO_AVAILABLE;
  848. PropSpec[2].ulKind = PRSPEC_PROPID;
  849. PropSpec[2].propid = WIA_IPC_AUDIO_DATA_FORMAT;
  850. hr = pWiaPropertyStorage->ReadMultiple( ARRAYSIZE(PropSpec), PropSpec, PropVar );
  851. if (SUCCEEDED(hr))
  852. {
  853. if (PropVar[1].lVal && PropVar[0].caub.cElems)
  854. {
  855. TCHAR szFile[MAX_PATH + 4] = {0};
  856. lstrcpyn( szFile, pszBaseFilename, ARRAYSIZE(szFile) );
  857. //
  858. // Figure out where the extension should go.
  859. //
  860. LPTSTR pszExtensionPoint = PathFindExtension(szFile);
  861. //
  862. // Replace the extension. If the item specifies the clsid, use it. Otherwise assume WAV
  863. //
  864. if (PropVar[2].vt == VT_CLSID && PropVar[2].puuid)
  865. {
  866. _sntprintf( pszExtensionPoint, ARRAYSIZE(szFile) - (pszExtensionPoint - szFile) - 1, TEXT(".%s"), CWiaFileFormat::GetExtension(*PropVar[2].puuid).String() );
  867. }
  868. else
  869. {
  870. lstrcpyn( pszExtensionPoint, TEXT(".wav"), static_cast<int>( ARRAYSIZE(szFile) - (pszExtensionPoint - szFile) ) );
  871. }
  872. //
  873. // Save the filename for the caller
  874. //
  875. strAudioFilename = szFile;
  876. //
  877. // Open the file and save the data to the file
  878. //
  879. HANDLE hFile = CreateFile( szFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  880. if (INVALID_HANDLE_VALUE != hFile)
  881. {
  882. DWORD dwBytesWritten;
  883. if (WriteFile( hFile, PropVar[0].caub.pElems, PropVar[0].caub.cElems, &dwBytesWritten, NULL ))
  884. {
  885. // Success
  886. }
  887. else
  888. {
  889. hr = HRESULT_FROM_WIN32(GetLastError());
  890. }
  891. CloseHandle(hFile);
  892. }
  893. else
  894. {
  895. hr = HRESULT_FROM_WIN32(GetLastError());
  896. }
  897. }
  898. else
  899. {
  900. hr = E_FAIL;
  901. WIA_PRINTHRESULT((hr,TEXT("There is no audio data")));
  902. }
  903. FreePropVariantArray( ARRAYSIZE(PropVar), PropVar );
  904. }
  905. }
  906. return hr;
  907. }
  908. bool IsDeviceCommandSupported( IWiaItem *pWiaItem, const GUID &guidCommand )
  909. {
  910. //
  911. // Assume failure
  912. //
  913. bool bResult = false;
  914. //
  915. // Make sure we have a valid item
  916. //
  917. if (pWiaItem)
  918. {
  919. //
  920. // Get the device capabilities enumerator
  921. //
  922. CComPtr<IEnumWIA_DEV_CAPS> pDeviceCapabilities;
  923. HRESULT hr = pWiaItem->EnumDeviceCapabilities( WIA_DEVICE_COMMANDS, &pDeviceCapabilities );
  924. if (SUCCEEDED(hr))
  925. {
  926. //
  927. // Enumerate the capabilities
  928. //
  929. WIA_DEV_CAP WiaDeviceCapability;
  930. while (!bResult && S_OK == pDeviceCapabilities->Next(1, &WiaDeviceCapability, NULL))
  931. {
  932. //
  933. // If we have a match, set the return value to true
  934. //
  935. if (guidCommand == WiaDeviceCapability.guid)
  936. {
  937. bResult = true;
  938. }
  939. //
  940. // Clean up the allocated data in the dev caps structure
  941. //
  942. if (WiaDeviceCapability.bstrName)
  943. {
  944. SysFreeString(WiaDeviceCapability.bstrName);
  945. }
  946. if (WiaDeviceCapability.bstrDescription)
  947. {
  948. SysFreeString(WiaDeviceCapability.bstrDescription);
  949. }
  950. if (WiaDeviceCapability.bstrIcon)
  951. {
  952. SysFreeString(WiaDeviceCapability.bstrIcon);
  953. }
  954. if (WiaDeviceCapability.bstrCommandline)
  955. {
  956. SysFreeString(WiaDeviceCapability.bstrCommandline);
  957. }
  958. }
  959. }
  960. }
  961. return bResult;
  962. }
  963. HRESULT StampItemTimeOnFile( IWiaItem *pWiaItem, LPCTSTR pszFilename )
  964. {
  965. if (!pWiaItem || !pszFilename || !lstrlen(pszFilename))
  966. {
  967. return E_INVALIDARG;
  968. }
  969. //
  970. // All this, just to set the stinking file time...
  971. // Allows for the possibility of using a VT_FILETIME
  972. // just in case we ever make the intelligent decision
  973. // to support VT_FILETIME
  974. //
  975. CComPtr<IWiaPropertyStorage> pWiaPropertyStorage;
  976. HRESULT hr = pWiaItem->QueryInterface( IID_IWiaPropertyStorage, (void **)&pWiaPropertyStorage );
  977. if (SUCCEEDED(hr))
  978. {
  979. //
  980. // Get the file time
  981. //
  982. PROPSPEC PropSpec[1] = {0};
  983. PROPVARIANT PropVar[1] = {0};
  984. PropSpec[0].ulKind = PRSPEC_PROPID;
  985. PropSpec[0].propid = WIA_IPA_ITEM_TIME;
  986. hr = pWiaPropertyStorage->ReadMultiple( ARRAYSIZE(PropSpec), PropSpec, PropVar );
  987. if (SUCCEEDED(hr))
  988. {
  989. //
  990. // Check to see if we are using a SYSTEMTIME structure
  991. //
  992. if (PropVar[0].vt > VT_NULL && PropVar[0].caub.pElems && PropVar[0].caub.cElems >= (sizeof(SYSTEMTIME)>>1))
  993. {
  994. //
  995. // Convert the systemtime to a local filetime
  996. //
  997. FILETIME FileTimeLocal;
  998. if (SystemTimeToFileTime( reinterpret_cast<SYSTEMTIME*>(PropVar[0].caub.pElems), &FileTimeLocal ))
  999. {
  1000. //
  1001. // Convert the local filetime to a UTC filetime
  1002. //
  1003. FILETIME FileTimeUTC;
  1004. if (LocalFileTimeToFileTime( &FileTimeLocal, &FileTimeUTC ))
  1005. {
  1006. //
  1007. // Open the file handle
  1008. //
  1009. HANDLE hFile = CreateFile( pszFilename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  1010. if (INVALID_HANDLE_VALUE != hFile)
  1011. {
  1012. //
  1013. // Set the file creation time
  1014. //
  1015. if (!SetFileTime( hFile, &FileTimeUTC, NULL, NULL ))
  1016. {
  1017. hr = HRESULT_FROM_WIN32(GetLastError());
  1018. WIA_PRINTHRESULT((hr,TEXT("SetFileTime failed")));
  1019. }
  1020. CloseHandle( hFile );
  1021. }
  1022. else
  1023. {
  1024. hr = HRESULT_FROM_WIN32(GetLastError());
  1025. WIA_PRINTHRESULT((hr,TEXT("CreateFile failed")));
  1026. }
  1027. }
  1028. else
  1029. {
  1030. hr = HRESULT_FROM_WIN32(GetLastError());
  1031. WIA_PRINTHRESULT((hr,TEXT("FileTimeToLocalFileTime failed")));
  1032. }
  1033. }
  1034. else
  1035. {
  1036. hr = HRESULT_FROM_WIN32(GetLastError());
  1037. WIA_PRINTHRESULT((hr,TEXT("SystemTimeToFileTime failed")));
  1038. }
  1039. }
  1040. else if (VT_FILETIME == PropVar[0].vt)
  1041. {
  1042. //
  1043. // Convert the local filetime to a UTC filetime
  1044. //
  1045. FILETIME FileTimeUTC;
  1046. if (LocalFileTimeToFileTime( &PropVar[0].filetime, &FileTimeUTC ))
  1047. {
  1048. //
  1049. // Open the file handle
  1050. //
  1051. HANDLE hFile = CreateFile( pszFilename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  1052. if (INVALID_HANDLE_VALUE != hFile)
  1053. {
  1054. //
  1055. // Set the file creation time
  1056. //
  1057. if (!SetFileTime( hFile, &FileTimeUTC, NULL, NULL ))
  1058. {
  1059. hr = HRESULT_FROM_WIN32(GetLastError());
  1060. WIA_PRINTHRESULT((hr,TEXT("SetFileTime failed")));
  1061. }
  1062. CloseHandle( hFile );
  1063. }
  1064. else
  1065. {
  1066. hr = HRESULT_FROM_WIN32(GetLastError());
  1067. WIA_PRINTHRESULT((hr,TEXT("CreateFile failed")));
  1068. }
  1069. }
  1070. else
  1071. {
  1072. hr = HRESULT_FROM_WIN32(GetLastError());
  1073. WIA_PRINTHRESULT((hr,TEXT("FileTimeToLocalFileTime failed")));
  1074. }
  1075. }
  1076. else
  1077. {
  1078. hr = E_FAIL;
  1079. WIA_PRINTHRESULT((hr,TEXT("The time property is invalid")));
  1080. }
  1081. //
  1082. // Free the propvariant
  1083. //
  1084. FreePropVariantArray( ARRAYSIZE(PropVar), PropVar );
  1085. }
  1086. else
  1087. {
  1088. WIA_ERROR((TEXT("ReadMultiple on WIA_IPA_ITEM_TIME failed")));
  1089. }
  1090. }
  1091. else
  1092. {
  1093. WIA_ERROR((TEXT("QueryInterface on IWiaPropertyStorage failed")));
  1094. }
  1095. return hr;
  1096. }
  1097. HRESULT MoveOrCopyFile( LPCTSTR pszSrc, LPCTSTR pszTgt )
  1098. {
  1099. WIA_PUSH_FUNCTION((TEXT("CDownloadImagesThreadMessage::MoveOrCopyFile( %s, %s )"), pszSrc, pszTgt ));
  1100. //
  1101. // Verify the arguments
  1102. //
  1103. if (!pszSrc || !pszTgt || !lstrlen(pszSrc) || !lstrlen(pszTgt))
  1104. {
  1105. return E_INVALIDARG;
  1106. }
  1107. //
  1108. // Assume everything worked ok
  1109. //
  1110. HRESULT hr = S_OK;
  1111. //
  1112. // First try to move the file, since that will be lots faster
  1113. //
  1114. if (!MoveFile( pszSrc, pszTgt ))
  1115. {
  1116. //
  1117. // If moving the file failed, try to copy it and the delete it
  1118. //
  1119. if (CopyFile( pszSrc, pszTgt, FALSE ))
  1120. {
  1121. //
  1122. // We are going to ignore failures from DeleteFile. It is possible the file is legitimately in
  1123. // use, and there is probably no need to fail the entire operation because of this.
  1124. //
  1125. if (!DeleteFile( pszSrc ))
  1126. {
  1127. WIA_PRINTHRESULT((HRESULT_FROM_WIN32(GetLastError()),TEXT("DeleteFile failed. Ignoring failure.")));
  1128. }
  1129. //
  1130. // Everything worked OK
  1131. //
  1132. hr = S_OK;
  1133. }
  1134. else
  1135. {
  1136. //
  1137. // This is where we catch the main errors
  1138. //
  1139. hr = HRESULT_FROM_WIN32(GetLastError());
  1140. }
  1141. }
  1142. return hr;
  1143. }
  1144. CSimpleString CreateTempFileName( UINT nId )
  1145. {
  1146. //
  1147. // Initialize the return value to an empty string
  1148. //
  1149. CSimpleString strResult(TEXT(""));
  1150. //
  1151. // Get the temp folder path
  1152. //
  1153. TCHAR szTempDirectory[MAX_PATH] = {0};
  1154. DWORD dwResult = GetTempPath( ARRAYSIZE(szTempDirectory), szTempDirectory );
  1155. if (dwResult)
  1156. {
  1157. //
  1158. // Make sure the path length didn't exceed the buffer we allocated on the stack
  1159. //
  1160. if (ARRAYSIZE(szTempDirectory) >= dwResult)
  1161. {
  1162. //
  1163. // Get the temp file name
  1164. //
  1165. TCHAR szFileName[MAX_PATH] = {0};
  1166. if (GetTempFileName( szTempDirectory, TEXT("scw"), nId, szFileName ))
  1167. {
  1168. //
  1169. // Save the filename
  1170. //
  1171. strResult = szFileName;
  1172. }
  1173. }
  1174. }
  1175. //
  1176. // Return the result. An e mpty string denotes an error.
  1177. //
  1178. return strResult;
  1179. }
  1180. bool CanWiaImageBeSafelyRotated( const GUID &guidFormat, LONG nImageWidth, LONG nImageHeight )
  1181. {
  1182. WIA_PUSH_FUNCTION((TEXT("WiaUiUtil::CanWiaImageBeSafelyRotated( guidFormat, %d, %d )"), nImageWidth, nImageHeight ));
  1183. WIA_PRINTGUID((guidFormat,TEXT("guidFormat")));
  1184. //
  1185. // These are the image types we can possibly rotate (there may be exceptions below)
  1186. //
  1187. static const GUID *guidSafeFormats[] = { &WiaImgFmt_BMP, &WiaImgFmt_JPEG, &WiaImgFmt_PNG, &WiaImgFmt_GIF };
  1188. //
  1189. // Search for this image type
  1190. //
  1191. for (int i=0;i<ARRAYSIZE(guidSafeFormats);i++)
  1192. {
  1193. //
  1194. // If we've found it
  1195. //
  1196. if (*guidSafeFormats[i] == guidFormat)
  1197. {
  1198. //
  1199. // Handle exceptions to the rule
  1200. //
  1201. if (guidFormat == WiaImgFmt_JPEG)
  1202. {
  1203. //
  1204. // We can't do lossless rotation on JPG images that are not even multiples of 16 in size
  1205. //
  1206. if ((nImageWidth % 16) || (nImageHeight % 16))
  1207. {
  1208. WIA_TRACE((TEXT("This image is not valid for rotation because it is not an even multiple of 16")));
  1209. return false;
  1210. }
  1211. }
  1212. //
  1213. // If none of the exceptions applied, return TRUE
  1214. //
  1215. WIA_TRACE((TEXT("Returning true")));
  1216. return true;
  1217. }
  1218. }
  1219. //
  1220. // If it is not known that we CAN rotate, we report false
  1221. //
  1222. WIA_TRACE((TEXT("Format type not found in safe list")));
  1223. return false;
  1224. }
  1225. HRESULT ExploreWiaDevice( LPCWSTR pszDeviceId )
  1226. {
  1227. HRESULT hr;
  1228. //
  1229. // Make sure we have a valid device id
  1230. //
  1231. if (!pszDeviceId || !lstrlenW(pszDeviceId))
  1232. {
  1233. return E_INVALIDARG;
  1234. }
  1235. //
  1236. // Load the shell extension's dll
  1237. //
  1238. HINSTANCE hInstWiaShellDll = LoadLibrary(TEXT("WIASHEXT.DLL"));
  1239. if (hInstWiaShellDll)
  1240. {
  1241. //
  1242. // Get the function that creates pidls
  1243. //
  1244. WIAMAKEFULLPIDLFORDEVICE pfnMakeFullPidlForDevice = reinterpret_cast<WIAMAKEFULLPIDLFORDEVICE>(GetProcAddress(hInstWiaShellDll, "MakeFullPidlForDevice"));
  1245. if (pfnMakeFullPidlForDevice)
  1246. {
  1247. //
  1248. // Get the device PIDL
  1249. //
  1250. LPITEMIDLIST pidlDevice = NULL;
  1251. hr = pfnMakeFullPidlForDevice( const_cast<LPWSTR>(pszDeviceId), &pidlDevice );
  1252. if (SUCCEEDED(hr))
  1253. {
  1254. //
  1255. // First, ask the shell to refresh any active views
  1256. //
  1257. SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, pidlDevice, 0);
  1258. //
  1259. // Now show the folder
  1260. //
  1261. SHELLEXECUTEINFO ShellExecuteInfo = {0};
  1262. ShellExecuteInfo.cbSize = sizeof(ShellExecuteInfo);
  1263. ShellExecuteInfo.fMask = SEE_MASK_IDLIST;
  1264. ShellExecuteInfo.nShow = SW_SHOW;
  1265. ShellExecuteInfo.lpIDList = pidlDevice;
  1266. if (ShellExecuteEx( &ShellExecuteInfo ))
  1267. {
  1268. hr = S_OK;
  1269. }
  1270. //
  1271. // Free the pidl
  1272. //
  1273. LPMALLOC pMalloc = NULL;
  1274. if (SUCCEEDED(SHGetMalloc(&pMalloc)) && pMalloc)
  1275. {
  1276. pMalloc->Free(pidlDevice);
  1277. pMalloc->Release();
  1278. }
  1279. }
  1280. }
  1281. else
  1282. {
  1283. hr = E_FAIL;
  1284. }
  1285. //
  1286. // Unload the DLL
  1287. //
  1288. FreeLibrary( hInstWiaShellDll );
  1289. }
  1290. else
  1291. {
  1292. //
  1293. // Can't load the DLL
  1294. //
  1295. hr = E_FAIL;
  1296. }
  1297. return hr;
  1298. }
  1299. //
  1300. // Modify a combo box's drop down list so that it is
  1301. // long enough to store the longest string in the list
  1302. // Taken from TaoYuan's code in photowiz.dll and modified
  1303. // to handle ComboBoxEx32 controls
  1304. //
  1305. BOOL ModifyComboBoxDropWidth( HWND hWndCombobox )
  1306. {
  1307. //
  1308. // Make sure we have a valid window
  1309. //
  1310. if (!hWndCombobox)
  1311. {
  1312. return FALSE;
  1313. }
  1314. //
  1315. // Find out how many items are in the combobox. If there are none, don't bother resizing.
  1316. //
  1317. LRESULT lRes = SendMessage( hWndCombobox, CB_GETCOUNT, 0, 0 );
  1318. if (lRes <= 0)
  1319. {
  1320. return FALSE;
  1321. }
  1322. UINT nCount = static_cast<UINT>(lRes);
  1323. //
  1324. // We only work with fixed-height comboboxes
  1325. //
  1326. lRes = SendMessage( hWndCombobox, CB_GETITEMHEIGHT, 0, 0 );
  1327. if (lRes < 0)
  1328. {
  1329. return FALSE;
  1330. }
  1331. UINT nItemHeight = static_cast<UINT>(lRes);
  1332. //
  1333. // We will be going through to figure out the desired size of the drop down list
  1334. //
  1335. UINT nDesiredWidth = 0;
  1336. //
  1337. // Add the size of the scrollbar to the desired witdth, of there is one
  1338. //
  1339. RECT rcDropped = {0};
  1340. SendMessage( hWndCombobox, CB_GETDROPPEDCONTROLRECT, 0, reinterpret_cast<LPARAM>(&rcDropped) );
  1341. //
  1342. // Get the size of the control's window
  1343. //
  1344. RECT rcWnd = {0};
  1345. GetWindowRect( hWndCombobox, &rcWnd );
  1346. //
  1347. // If not all of the items will fit in the dropped list,
  1348. // we have to account for a vertical scrollbar
  1349. //
  1350. if (((WiaUiUtil::RectHeight(rcDropped) - GetSystemMetrics(SM_CYEDGE)*2) / nItemHeight) < nCount)
  1351. {
  1352. nDesiredWidth += GetSystemMetrics(SM_CXEDGE)*2 + GetSystemMetrics( SM_CXVSCROLL );
  1353. }
  1354. //
  1355. // Find the widest string
  1356. //
  1357. LONG nMaxStringLen = 0;
  1358. HDC hDC = GetDC( hWndCombobox );
  1359. if (hDC)
  1360. {
  1361. //
  1362. // Use the control's font
  1363. //
  1364. HFONT hOldFont = NULL, hFont = reinterpret_cast<HFONT>(SendMessage(hWndCombobox,WM_GETFONT,0,0));
  1365. if (hFont)
  1366. {
  1367. hOldFont = SelectFont( hDC, hFont );
  1368. }
  1369. for (UINT i = 0; i < nCount; i++ )
  1370. {
  1371. //
  1372. // Get the length of this item's text
  1373. //
  1374. LRESULT nLen = SendMessage( hWndCombobox, CB_GETLBTEXTLEN, i, 0 );
  1375. if (nLen > 0)
  1376. {
  1377. //
  1378. // Allocate a buffer for the string
  1379. //
  1380. LPTSTR pszItem = new TCHAR[nLen+1];
  1381. if (pszItem)
  1382. {
  1383. //
  1384. // Get the string
  1385. //
  1386. pszItem[0] = TEXT('\0');
  1387. if (SendMessage( hWndCombobox, CB_GETLBTEXT, i, reinterpret_cast<LPARAM>(pszItem) ) > 0)
  1388. {
  1389. //
  1390. // Measure it
  1391. //
  1392. SIZE sizeText = {0};
  1393. if (GetTextExtentPoint32( hDC, pszItem, lstrlen( pszItem ), &sizeText ))
  1394. {
  1395. //
  1396. // If this is the longest one, save its length
  1397. //
  1398. if (sizeText.cx > nMaxStringLen)
  1399. {
  1400. nMaxStringLen = sizeText.cx;
  1401. }
  1402. }
  1403. }
  1404. //
  1405. // Free the string
  1406. //
  1407. delete[] pszItem;
  1408. }
  1409. }
  1410. }
  1411. //
  1412. // Restore and release the DC
  1413. //
  1414. if (hOldFont)
  1415. {
  1416. SelectFont( hDC, hOldFont );
  1417. }
  1418. ReleaseDC( hWndCombobox, hDC );
  1419. }
  1420. //
  1421. // Add in the longest string's length
  1422. //
  1423. nDesiredWidth += nMaxStringLen;
  1424. //
  1425. // If this is a ComboBoxEx32, add in the width of the icon
  1426. //
  1427. TCHAR szClassName[MAX_PATH] = {0};
  1428. if (GetClassName( hWndCombobox, szClassName, ARRAYSIZE(szClassName)))
  1429. {
  1430. //
  1431. // Compare the classname with ComboBoxEx32
  1432. //
  1433. if (!lstrcmp(szClassName,WC_COMBOBOXEX))
  1434. {
  1435. //
  1436. // Get the image list from the control
  1437. //
  1438. HIMAGELIST hImageList = reinterpret_cast<HIMAGELIST>(SendMessage( hWndCombobox, CBEM_GETIMAGELIST, 0, 0 ));
  1439. if (hImageList)
  1440. {
  1441. //
  1442. // Get the width and add it to the desired size
  1443. //
  1444. INT nWidth=0, nHeight=0;
  1445. if (ImageList_GetIconSize( hImageList, &nWidth, &nHeight ))
  1446. {
  1447. //
  1448. // I don't know what the margin should be, but nWidth*2
  1449. // should account for the width of icon and its margin
  1450. //
  1451. nDesiredWidth += nWidth * 2;
  1452. }
  1453. }
  1454. }
  1455. }
  1456. //
  1457. // Add in the border of the control
  1458. //
  1459. nDesiredWidth += GetSystemMetrics(SM_CXFIXEDFRAME)*2;
  1460. //
  1461. // Make sure our drop down is no wider than the current monitor
  1462. //
  1463. HMONITOR hMonitor = MonitorFromWindow( hWndCombobox, MONITOR_DEFAULTTONEAREST );
  1464. if (hMonitor)
  1465. {
  1466. MONITORINFO MonitorInfo = {0};
  1467. MonitorInfo.cbSize = sizeof(MonitorInfo);
  1468. //
  1469. // Get the screen coordinates of this monitor
  1470. //
  1471. if (GetMonitorInfo(hMonitor, &MonitorInfo))
  1472. {
  1473. //
  1474. // If the desired width is larger than the monitor, shorten it
  1475. //
  1476. if (nDesiredWidth > static_cast<UINT>(WiaUiUtil::RectWidth(MonitorInfo.rcMonitor)))
  1477. {
  1478. nDesiredWidth = RectWidth(MonitorInfo.rcMonitor);
  1479. }
  1480. }
  1481. }
  1482. //
  1483. // If our size is smaller than the control's current size, grow it
  1484. //
  1485. if (static_cast<UINT>(WiaUiUtil::RectWidth(rcDropped)) < nDesiredWidth)
  1486. {
  1487. //
  1488. // Disable redrawing
  1489. //
  1490. SendMessage( hWndCombobox, WM_SETREDRAW, FALSE, 0 );
  1491. SendMessage( hWndCombobox, CB_SETDROPPEDWIDTH, static_cast<WPARAM>(nDesiredWidth), 0 );
  1492. //
  1493. // Allow redrawing
  1494. //
  1495. SendMessage( hWndCombobox, WM_SETREDRAW, TRUE, 0 );
  1496. //
  1497. // Force a repaint
  1498. //
  1499. InvalidateRect( hWndCombobox, NULL, FALSE );
  1500. UpdateWindow( hWndCombobox );
  1501. //
  1502. // TRUE means we actually changed it
  1503. //
  1504. return TRUE;
  1505. }
  1506. return FALSE;
  1507. }
  1508. static LPCTSTR s_pszComboBoxExWndProcPropName = TEXT("WiaComboBoxExWndProcPropName");
  1509. static LRESULT WINAPI ComboBoxExWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
  1510. {
  1511. static WNDPROC s_pfnDefProc = NULL;
  1512. WNDPROC pfnWndProc = reinterpret_cast<WNDPROC>(GetProp( hWnd, s_pszComboBoxExWndProcPropName ));
  1513. if (!s_pfnDefProc)
  1514. {
  1515. WNDCLASS wc = {0};
  1516. GetClassInfo( GetModuleHandle(TEXT("user32.dll")), TEXT("ComboBox"), &wc );
  1517. s_pfnDefProc = wc.lpfnWndProc;
  1518. }
  1519. if (nMsg == WM_LBUTTONDOWN || nMsg == WM_RBUTTONDOWN)
  1520. {
  1521. if (s_pfnDefProc)
  1522. {
  1523. return CallWindowProc( s_pfnDefProc, hWnd, nMsg, wParam, lParam );
  1524. }
  1525. }
  1526. if (nMsg == WM_DESTROY)
  1527. {
  1528. RemoveProp( hWnd, s_pszComboBoxExWndProcPropName );
  1529. }
  1530. if (pfnWndProc)
  1531. {
  1532. return CallWindowProc( pfnWndProc, hWnd, nMsg, wParam, lParam );
  1533. }
  1534. else
  1535. {
  1536. return CallWindowProc( DefWindowProc, hWnd, nMsg, wParam, lParam );
  1537. }
  1538. }
  1539. //
  1540. // This subclasses the ComboBoxEx32 to work around a bug
  1541. // that causes the list to drop down at bad times.
  1542. // Uses a window property to store the previous wndproc.
  1543. // Taken from DavidShi's code in wiashext.dll
  1544. //
  1545. void SubclassComboBoxEx( HWND hWnd )
  1546. {
  1547. HWND hComboBox = FindWindowEx( hWnd, NULL, TEXT("ComboBox"), NULL );
  1548. if (hComboBox)
  1549. {
  1550. LONG_PTR pfnOldWndProc = SetWindowLongPtr( hComboBox, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(ComboBoxExWndProc));
  1551. SetProp( hComboBox, s_pszComboBoxExWndProcPropName, reinterpret_cast<HANDLE>(pfnOldWndProc) );
  1552. }
  1553. }
  1554. HRESULT IssueWiaCancelIO( IUnknown *pUnknown )
  1555. {
  1556. if (!pUnknown)
  1557. {
  1558. return E_POINTER;
  1559. }
  1560. CComPtr<IWiaItemExtras> pWiaItemExtras;
  1561. HRESULT hr = pUnknown->QueryInterface( IID_IWiaItemExtras, (void**)&pWiaItemExtras );
  1562. if (SUCCEEDED(hr))
  1563. {
  1564. hr = pWiaItemExtras->CancelPendingIO();
  1565. }
  1566. return hr;
  1567. }
  1568. HRESULT VerifyScannerProperties( IUnknown *pUnknown )
  1569. {
  1570. HRESULT hr = E_FAIL;
  1571. //
  1572. // Table of required properties
  1573. //
  1574. static const PROPID s_RequiredProperties[] =
  1575. {
  1576. WIA_IPS_CUR_INTENT
  1577. };
  1578. //
  1579. // Make sure we have a valid item
  1580. //
  1581. if (pUnknown)
  1582. {
  1583. //
  1584. // Assume success at this point
  1585. //
  1586. hr = S_OK;
  1587. //
  1588. // Get the IWiaPropertyStorage interface
  1589. //
  1590. CComPtr<IWiaPropertyStorage> pWiaPropertyStorage;
  1591. hr = pUnknown->QueryInterface(IID_IWiaPropertyStorage, (void**)&pWiaPropertyStorage);
  1592. if (SUCCEEDED(hr))
  1593. {
  1594. //
  1595. // Loop through each property and make sure it exists
  1596. // Break out if hr != S_OK
  1597. //
  1598. for (int i=0;i<ARRAYSIZE(s_RequiredProperties) && S_OK==hr;i++)
  1599. {
  1600. //
  1601. // Prepare the propspec
  1602. //
  1603. PROPSPEC PropSpec = {0};
  1604. PropSpec.ulKind = PRSPEC_PROPID;
  1605. PropSpec.propid = s_RequiredProperties[i];
  1606. //
  1607. // Attempt to get the property attributes
  1608. //
  1609. ULONG nAccessFlags = 0;
  1610. PROPVARIANT PropVariant = {0};
  1611. hr = pWiaPropertyStorage->GetPropertyAttributes( 1, &PropSpec, &nAccessFlags, &PropVariant );
  1612. if (SUCCEEDED(hr))
  1613. {
  1614. //
  1615. // Prevent a leak
  1616. //
  1617. PropVariantClear(&PropVariant);
  1618. //
  1619. // If everything is OK so far
  1620. //
  1621. if (S_OK == hr)
  1622. {
  1623. //
  1624. // Zero out the structure
  1625. //
  1626. PropVariantInit(&PropVariant);
  1627. //
  1628. // Attempt to read the actual value
  1629. //
  1630. hr = pWiaPropertyStorage->ReadMultiple( 1, &PropSpec, &PropVariant );
  1631. if (SUCCEEDED(hr))
  1632. {
  1633. //
  1634. // Free the actual value
  1635. //
  1636. PropVariantClear(&PropVariant);
  1637. }
  1638. }
  1639. }
  1640. }
  1641. }
  1642. }
  1643. //
  1644. // S_FALSE means a property doesn't exist, so change this to an error
  1645. //
  1646. if (S_FALSE == hr)
  1647. {
  1648. hr = E_FAIL;
  1649. }
  1650. //
  1651. // All done
  1652. //
  1653. return hr;
  1654. }
  1655. CSimpleString GetErrorTextFromHResult( HRESULT hr )
  1656. {
  1657. CSimpleString strResult;
  1658. LPTSTR szErrMsg = NULL;
  1659. FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  1660. NULL,
  1661. hr,
  1662. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  1663. reinterpret_cast<LPTSTR>(&szErrMsg),
  1664. 0,
  1665. NULL
  1666. );
  1667. if (szErrMsg)
  1668. {
  1669. strResult = szErrMsg;
  1670. LocalFree( szErrMsg );
  1671. }
  1672. return strResult;
  1673. }
  1674. } // End namespace WiaUiUtil