Source code of Windows XP (NT5)
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.

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