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.

712 lines
22 KiB

  1. #include "shellprv.h"
  2. #include "util.h"
  3. #include "idlcomm.h"
  4. #include <uxtheme.h>
  5. #include <tmschema.h>
  6. // shdocvw and browseui share brutil and menubands need it too
  7. // unfortunately shell32 isnt set up quite like shdocvw and browseui so
  8. // these have to be hacked in a little
  9. #define MAX_BROWSER_WINDOW_TITLE 128
  10. #define g_fRunningOnNT TRUE
  11. #define InitClipboardFormats IDLData_InitializeClipboardFormats
  12. #define g_cfFileDescA g_cfFileGroupDescriptorA
  13. #define g_cfFileDescW g_cfFileGroupDescriptorW
  14. #define g_cfURL g_cfShellURL
  15. #define PVAREMPTY ((VARIANT*)&c_vaEmpty)
  16. #define NO_MLUI_IN_SHELL32
  17. #include "..\inc\brutil.cpp"
  18. const VARIANT c_vaEmpty = {0};
  19. HRESULT QueryService_SID_IBandProxy(IUnknown * punkParent, REFIID riid, IBandProxy ** ppbp, void **ppvObj)
  20. {
  21. HRESULT hr = E_FAIL;
  22. if (ppbp)
  23. {
  24. if (NULL == (*ppbp))
  25. hr = IUnknown_QueryService(punkParent, SID_IBandProxy, IID_PPV_ARG(IBandProxy, ppbp));
  26. if (*ppbp && ppvObj)
  27. hr = (*ppbp)->QueryInterface(riid, ppvObj); // They already have the object.
  28. }
  29. return hr;
  30. }
  31. HRESULT CreateIBandProxyAndSetSite(IUnknown * punkParent, REFIID riid, IBandProxy ** ppbp, void **ppvObj)
  32. {
  33. ASSERT(ppbp);
  34. HRESULT hr = CoCreateInstance(CLSID_BandProxy, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IBandProxy, ppbp));
  35. if (SUCCEEDED(hr))
  36. {
  37. // Set the site
  38. ASSERT(*ppbp);
  39. (*ppbp)->SetSite(punkParent);
  40. if (ppvObj)
  41. hr = (*ppbp)->QueryInterface(riid, ppvObj);
  42. }
  43. else
  44. {
  45. if (ppvObj)
  46. *ppvObj = NULL;
  47. }
  48. return hr;
  49. }
  50. typedef struct tagINIPAIR
  51. {
  52. DWORD dwFlags;
  53. LPCTSTR pszSection;
  54. }
  55. INIPAIR;
  56. const INIPAIR c_aIniPairs[] =
  57. {
  58. EICH_KINET, TEXT("Software\\Microsoft\\Internet Explorer"),
  59. EICH_KINETMAIN, TEXT("Software\\Microsoft\\Internet Explorer\\Main"),
  60. EICH_KWIN, TEXT("Software\\Microsoft\\Windows\\CurrentVersion"),
  61. EICH_KWINEXPLORER, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"),
  62. EICH_KWINEXPLSMICO, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SmallIcons"),
  63. EICH_KWINPOLICY, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies"),
  64. EICH_SSAVETASKBAR, TEXT("SaveTaskbar"),
  65. EICH_SWINDOWMETRICS, TEXT("WindowMetrics"),
  66. EICH_SSHELLMENU, TEXT("ShellMenu"),
  67. EICH_SPOLICY, TEXT("Policy"),
  68. EICH_SWINDOWS, TEXT("Windows"),
  69. };
  70. DWORD SHIsExplorerIniChange(WPARAM wParam, LPARAM lParam)
  71. {
  72. DWORD dwFlags = 0;
  73. if (lParam == 0)
  74. {
  75. if (wParam == 0)
  76. {
  77. dwFlags = EICH_UNKNOWN;
  78. }
  79. }
  80. else
  81. {
  82. //
  83. // In the wacky world of browseui, UNICODE-ANSI doesn't vary from
  84. // window to window. Instead, on NT browseui registers all windows
  85. // UNICODE, while on 9x user browseui registers all windows ANSI.
  86. //
  87. LPCTSTR pszSection = (LPCWSTR)lParam;
  88. for (int i = 0; !dwFlags && i < ARRAYSIZE(c_aIniPairs); i++)
  89. {
  90. if (StrCmpI(pszSection, c_aIniPairs[i].pszSection) == 0)
  91. {
  92. dwFlags = c_aIniPairs[i].dwFlags;
  93. }
  94. }
  95. }
  96. return dwFlags;
  97. }
  98. ULONG RegisterNotify(HWND hwnd, UINT nMsg, LPCITEMIDLIST pidl, DWORD dwEvents, UINT uFlags, BOOL fRecursive)
  99. {
  100. SHChangeNotifyEntry fsne;
  101. uFlags |= SHCNRF_NewDelivery;
  102. fsne.fRecursive = fRecursive;
  103. fsne.pidl = pidl;
  104. return SHChangeNotifyRegister(hwnd, uFlags, dwEvents, nMsg, 1, &fsne);
  105. }
  106. BOOL GetInfoTipEx(IShellFolder* psf, DWORD dwFlags, LPCITEMIDLIST pidl, LPTSTR pszText, int cchTextMax)
  107. {
  108. BOOL fRet = FALSE;
  109. *pszText = 0; // empty for failure
  110. if (pidl)
  111. {
  112. IQueryInfo *pqi;
  113. if (SUCCEEDED(psf->GetUIObjectOf(NULL, 1, &pidl, IID_X_PPV_ARG(IQueryInfo, NULL, &pqi))))
  114. {
  115. WCHAR *pwszTip;
  116. pqi->GetInfoTip(dwFlags, &pwszTip);
  117. if (pwszTip)
  118. {
  119. fRet = TRUE;
  120. SHUnicodeToTChar(pwszTip, pszText, cchTextMax);
  121. SHFree(pwszTip);
  122. }
  123. pqi->Release();
  124. }
  125. }
  126. return fRet;
  127. }
  128. BOOL GetInfoTip(IShellFolder* psf, LPCITEMIDLIST pidl, LPTSTR pszText, int cchTextMax)
  129. {
  130. return GetInfoTipEx(psf, 0, pidl, pszText, cchTextMax);
  131. }
  132. // does filename based lookup to see if a file is browsable or not.
  133. // this is probably vulnerable to ::$DATA stuff so DO NOT use it for deciding whether to
  134. // shellexecute or something.
  135. // right now all its used for is if a menu should cascade on the file.
  136. BOOL IsBrowsableShellExt(LPCITEMIDLIST pidl)
  137. {
  138. DWORD cb;
  139. LPCTSTR pszExt;
  140. TCHAR szFile[MAX_PATH];
  141. TCHAR szProgID[80]; // From ..\shell32\fstreex.c
  142. TCHAR szCLSID[GUIDSTR_MAX], szCATID[GUIDSTR_MAX];
  143. TCHAR szKey[GUIDSTR_MAX * 4];
  144. HKEY hkeyProgID = NULL;
  145. BOOL fRet = FALSE;
  146. for (;;)
  147. {
  148. // Make sure we have a file extension
  149. if (
  150. !SHGetPathFromIDList(pidl, szFile)
  151. ||
  152. ((pszExt = PathFindExtension(szFile)) == NULL)
  153. ||
  154. (pszExt[0] != TEXT('.'))
  155. )
  156. {
  157. break;
  158. }
  159. // Get the ProgID.
  160. cb = sizeof(szProgID);
  161. if (
  162. (SHGetValue(HKEY_CLASSES_ROOT, pszExt, NULL, NULL, szProgID, &cb) != ERROR_SUCCESS)
  163. ||
  164. (RegOpenKeyEx(HKEY_CLASSES_ROOT, szProgID, 0, KEY_READ, &hkeyProgID) != ERROR_SUCCESS)
  165. )
  166. {
  167. break;
  168. }
  169. // From the ProgID, get the CLSID.
  170. cb = sizeof(szCLSID);
  171. if (SHGetValue(hkeyProgID, TEXT("CLSID"), NULL, NULL, szCLSID, &cb) != ERROR_SUCCESS)
  172. break;
  173. // Construct the registry key that detects if
  174. // a CLSID is a member of a CATID.
  175. SHStringFromGUID(CATID_BrowsableShellExt, szCATID, ARRAYSIZE(szCATID));
  176. wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("CLSID\\%s\\Implemented Categories\\%s"),
  177. szCLSID, szCATID);
  178. // See if it's there.
  179. cb = 0;
  180. if (SHGetValue(HKEY_CLASSES_ROOT, szKey, NULL, NULL, NULL, &cb) != ERROR_SUCCESS)
  181. break;
  182. fRet = TRUE;
  183. break;
  184. }
  185. if (hkeyProgID != NULL)
  186. RegCloseKey(hkeyProgID);
  187. return fRet;
  188. }
  189. void OpenFolderPidl(LPCITEMIDLIST pidl)
  190. {
  191. SHELLEXECUTEINFO shei = { 0 };
  192. shei.cbSize = sizeof(shei);
  193. shei.fMask = SEE_MASK_INVOKEIDLIST;
  194. shei.nShow = SW_SHOWNORMAL;
  195. shei.lpIDList = (LPITEMIDLIST)pidl;
  196. // callers are responsible -- this is called only from sftbar in response to invokecommand
  197. ShellExecuteEx(&shei);
  198. }
  199. // As perf, share IShellLink implementations between bands and ask
  200. // the bandsite for an implementation. Don't rely on the bandsite
  201. // because you never know who will host us in the future. (And bandsite
  202. // can change to not have us hosted at save/load time. Ex: it doesn't
  203. // set our site before loading us from the stream, which sounds buggy.)
  204. //
  205. HRESULT SavePidlAsLink(IUnknown* punkSite, IStream *pstm, LPCITEMIDLIST pidl)
  206. {
  207. HRESULT hr = E_FAIL;
  208. IShellLinkA* psl;
  209. if (punkSite)
  210. hr = IUnknown_QueryService(punkSite, IID_IBandSite, IID_PPV_ARG(IShellLinkA, &psl));
  211. if (FAILED(hr))
  212. hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLinkA, &psl));
  213. if (SUCCEEDED(hr))
  214. {
  215. IPersistStream *pps;
  216. hr = psl->QueryInterface(IID_PPV_ARG(IPersistStream, &pps));
  217. if (EVAL(SUCCEEDED(hr)))
  218. {
  219. ASSERT(pidl);
  220. psl->SetIDList(pidl);
  221. hr = pps->Save(pstm, FALSE);
  222. pps->Release();
  223. }
  224. psl->Release();
  225. }
  226. return hr;
  227. }
  228. HRESULT LoadPidlAsLink(IUnknown* punkSite, IStream *pstm, LPITEMIDLIST *ppidl)
  229. {
  230. IShellLinkA* psl;
  231. HRESULT hr = IUnknown_QueryService(punkSite, IID_IBandSite, IID_PPV_ARG(IShellLinkA, &psl));
  232. if (FAILED(hr))
  233. hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLinkA, &psl));
  234. if (SUCCEEDED(hr))
  235. {
  236. IPersistStream *pps;
  237. hr = psl->QueryInterface(IID_PPV_ARG(IPersistStream, &pps));
  238. if (EVAL(SUCCEEDED(hr)))
  239. {
  240. // link responsible for loading correctly
  241. hr = pps->Load(pstm);
  242. if (EVAL(SUCCEEDED(hr)))
  243. {
  244. hr = psl->GetIDList(ppidl);
  245. // Don't make me resolve the link because it's soo slow because
  246. // it often loads 80k of networking dlls.
  247. if (!EVAL(SUCCEEDED(hr)))
  248. {
  249. hr = psl->Resolve(NULL, SLR_NOUPDATE | SLR_NO_UI);
  250. if (EVAL(SUCCEEDED(hr)))
  251. hr = psl->GetIDList(ppidl);
  252. }
  253. hr = *ppidl ? S_OK : E_FAIL;
  254. }
  255. pps->Release();
  256. }
  257. psl->Release();
  258. }
  259. return hr;
  260. }
  261. // Review chrisny: this can be moved into an object easily to handle generic droptarget, dropcursor
  262. // , autoscrool, etc. . .
  263. void _DragEnter(HWND hwndTarget, const POINTL ptStart, IDataObject *pdtObject)
  264. {
  265. RECT rc;
  266. POINT pt;
  267. GetWindowRect(hwndTarget, &rc);
  268. //
  269. // If hwndTarget is RTL mirrored, then measure the
  270. // the client point from the visual right edge
  271. // (near edge in RTL mirrored windows). [samera]
  272. //
  273. if (IS_WINDOW_RTL_MIRRORED(hwndTarget))
  274. pt.x = rc.right - ptStart.x;
  275. else
  276. pt.x = ptStart.x - rc.left;
  277. pt.y = ptStart.y - rc.top;
  278. DAD_DragEnterEx2(hwndTarget, pt, pdtObject);
  279. return;
  280. }
  281. void _DragMove(HWND hwndTarget, const POINTL ptStart)
  282. {
  283. RECT rc;
  284. POINT pt;
  285. GetWindowRect(hwndTarget, &rc);
  286. //
  287. // If hwndTarget is RTL mirrored, then measure the
  288. // the client point from the visual right edge
  289. // (near edge in RTL mirrored windows). [samera]
  290. //
  291. if (IS_WINDOW_RTL_MIRRORED(hwndTarget))
  292. pt.x = rc.right - ptStart.x;
  293. else
  294. pt.x = ptStart.x - rc.left;
  295. pt.y = ptStart.y - rc.top;
  296. DAD_DragMove(pt);
  297. return;
  298. }
  299. // Can we browse or navigate to this pidl? If not, need
  300. BOOL ILIsBrowsable(LPCITEMIDLIST pidl, BOOL *pfIsFolder)
  301. {
  302. if (!pidl)
  303. return FALSE;
  304. DWORD dwAttributes = SFGAO_FOLDER | SFGAO_BROWSABLE;
  305. HRESULT hr = IEGetAttributesOf(pidl, &dwAttributes);
  306. if (pfIsFolder && SUCCEEDED(hr))
  307. *pfIsFolder = dwAttributes & SFGAO_FOLDER;
  308. return SUCCEEDED(hr) && (dwAttributes & (SFGAO_FOLDER | SFGAO_BROWSABLE));
  309. }
  310. // gets a target pidl given a name space item. typically this is a .lnk or .url file
  311. //
  312. // in:
  313. // psf shell folder for item
  314. // pidl item relative to psf, single level
  315. //
  316. // in/out
  317. // pdwAttribs [optional] attributes mask to filter on (returned).
  318. // must be initalized
  319. //
  320. //
  321. // returns
  322. // *ppidl the target pidl
  323. // *pdwAttribs [optional] attributes of the source object
  324. STDAPI SHGetNavigateTarget(IShellFolder *psf, LPCITEMIDLIST pidl, LPITEMIDLIST *ppidl, DWORD *pdwAttribs)
  325. {
  326. ASSERT(IS_VALID_CODE_PTR(psf, IShellFolder));
  327. ASSERT(IS_VALID_PIDL(pidl));
  328. ASSERT(NULL == pdwAttribs || IS_VALID_WRITE_PTR(pdwAttribs, DWORD));
  329. ASSERT(ILFindLastID(pidl) == pidl); // must be single level PIDL
  330. *ppidl = NULL; // assume failure
  331. DWORD dwAttribs = SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_LINK | SFGAO_BROWSABLE;
  332. if (pdwAttribs)
  333. dwAttribs |= *pdwAttribs;
  334. HRESULT hr = psf->GetAttributesOf(1, &pidl, &dwAttribs);
  335. if (SUCCEEDED(hr))
  336. {
  337. // first try the most efficient way
  338. IShellLinkA *psl; // "A" so this works on Win95
  339. hr = psf->GetUIObjectOf(NULL, 1, &pidl, IID_X_PPV_ARG(IShellLinkA, NULL, &psl));
  340. if (SUCCEEDED(hr))
  341. {
  342. hr = psl->GetIDList(ppidl);
  343. psl->Release();
  344. }
  345. // this is for .lnk and .url files that don't register properly
  346. if (FAILED(hr) && (dwAttribs & (SFGAO_FILESYSTEM | SFGAO_LINK)) == (SFGAO_FILESYSTEM | SFGAO_LINK))
  347. {
  348. TCHAR szPath[MAX_PATH];
  349. hr = GetPathForItem(psf, pidl, szPath, NULL);
  350. if (SUCCEEDED(hr))
  351. hr = GetLinkTargetIDList(szPath, NULL, 0, ppidl);
  352. }
  353. // .doc or .html. return the pidl for this.
  354. // (fully qualify against the folder pidl)
  355. if (FAILED(hr) && (dwAttribs & SFGAO_BROWSABLE))
  356. {
  357. LPITEMIDLIST pidlFolder;
  358. hr = SHGetIDListFromUnk(psf, &pidlFolder);
  359. if (SUCCEEDED(hr))
  360. {
  361. *ppidl = ILCombine(pidlFolder, pidl); // navigate to this thing...
  362. hr = *ppidl ? S_OK : E_OUTOFMEMORY;
  363. ILFree(pidlFolder);
  364. }
  365. }
  366. // Callers of SHGetNavigateTarget assume that the returned pidl
  367. // is navigatable (SFGAO_FOLDER or SFGAO_BROWSER), which isn't
  368. // the case for a link (it could be a link to an exe).
  369. //
  370. if (SUCCEEDED(hr) && !ILIsBrowsable(*ppidl, NULL))
  371. {
  372. ILFree(*ppidl);
  373. *ppidl = NULL;
  374. hr = E_FAIL;
  375. }
  376. if (SUCCEEDED(hr) && pdwAttribs)
  377. *pdwAttribs = dwAttribs;
  378. }
  379. return hr;
  380. }
  381. STDAPI SHNavigateToFavorite(IShellFolder* psf, LPCITEMIDLIST pidl, IUnknown* punkSite, DWORD dwFlags)
  382. {
  383. HRESULT hr = S_FALSE;
  384. TCHAR szPath[MAX_PATH];
  385. // Can we navigate to this favorite?
  386. BOOL fNavigateDone = SUCCEEDED(GetPathForItem(psf, pidl, szPath, NULL)) &&
  387. SUCCEEDED(NavFrameWithFile(szPath, punkSite));
  388. if (fNavigateDone)
  389. return S_OK;
  390. LPITEMIDLIST pidlGoto;
  391. ASSERT(!(dwFlags & (SBSP_NEWBROWSER | SBSP_SAMEBROWSER)));
  392. if (SUCCEEDED(SHGetNavigateTarget(psf, pidl, &pidlGoto, NULL)))
  393. {
  394. IShellBrowser* psb;
  395. if (SUCCEEDED(IUnknown_QueryService(punkSite, SID_STopLevelBrowser,
  396. IID_PPV_ARG(IShellBrowser, &psb))))
  397. {
  398. hr = psb->BrowseObject(pidlGoto, dwFlags | SBSP_SAMEBROWSER);
  399. psb->Release();
  400. }
  401. ILFree(pidlGoto);
  402. }
  403. return hr;
  404. }
  405. STDAPI SHGetTopBrowserWindow(IUnknown* punk, HWND* phwnd)
  406. {
  407. IOleWindow* pOleWindow;
  408. HRESULT hr = IUnknown_QueryService(punk, SID_STopLevelBrowser, IID_PPV_ARG(IOleWindow, &pOleWindow));
  409. if (SUCCEEDED(hr))
  410. {
  411. hr = pOleWindow->GetWindow(phwnd);
  412. pOleWindow->Release();
  413. }
  414. return hr;
  415. }
  416. void SHOutlineRect(HDC hdc, const RECT* prc, COLORREF cr)
  417. {
  418. RECT rc;
  419. COLORREF clrSave = SetBkColor(hdc, cr);
  420. //top
  421. rc.left = prc->left;
  422. rc.top = prc->top;
  423. rc.right = prc->right;
  424. rc.bottom = prc->top + 1;
  425. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  426. //left
  427. rc.left = prc->left;
  428. rc.top = prc->top;
  429. rc.right = prc->left + 1;
  430. rc.bottom = prc->bottom;
  431. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  432. //right
  433. rc.left = prc->right - 1;
  434. rc.top = prc->top;
  435. rc.right = prc->right;
  436. rc.bottom = prc->bottom;
  437. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  438. // bottom
  439. rc.left = prc->left;
  440. rc.top = prc->bottom - 1;
  441. rc.right = prc->right;
  442. rc.bottom = prc->bottom;
  443. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  444. SetBkColor(hdc, clrSave);
  445. }
  446. STDAPI NavigateToPIDL(IWebBrowser2* pwb, LPCITEMIDLIST pidl)
  447. {
  448. ASSERT(pwb);
  449. ASSERT(pidl);
  450. VARIANT varThePidl;
  451. HRESULT hr = InitVariantFromIDList(&varThePidl, pidl);
  452. if (SUCCEEDED(hr))
  453. {
  454. hr = pwb->Navigate2(&varThePidl, PVAREMPTY, PVAREMPTY, PVAREMPTY, PVAREMPTY);
  455. VariantClear(&varThePidl); // Needed to free the copy of the PIDL in varThePidl.
  456. }
  457. return hr;
  458. }
  459. HRESULT Channels_OpenBrowser(IWebBrowser2 **ppwb, BOOL fInPlace)
  460. {
  461. HRESULT hr;
  462. IWebBrowser2* pwb;
  463. if (fInPlace)
  464. {
  465. ASSERT(ppwb && *ppwb != NULL);
  466. pwb = *ppwb;
  467. hr = S_OK;
  468. }
  469. else
  470. {
  471. hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARG(IWebBrowser2, &pwb));
  472. }
  473. if (SUCCEEDED(hr))
  474. {
  475. // Don't special case full-screen mode for channels post IE4. Use the
  476. // browser's full screen setting.
  477. //
  478. //BOOL fTheater = SHRegGetBoolUSValue(TEXT("Software\\Microsoft\\Internet Explorer\\Channels"),
  479. BOOL fTheater = SHRegGetBoolUSValue(TEXT("Software\\Microsoft\\Internet Explorer\\Main"),
  480. TEXT("FullScreen"), FALSE, FALSE);
  481. pwb->put_TheaterMode( fTheater ? VARIANT_TRUE : VARIANT_FALSE);
  482. pwb->put_Visible(VARIANT_TRUE);
  483. if (!SHRestricted2(REST_NoChannelUI, NULL, 0))
  484. {
  485. SA_BSTRGUID strGuid;
  486. VARIANT vaGuid;
  487. InitFakeBSTR(&strGuid, CLSID_FavBand);
  488. vaGuid.vt = VT_BSTR;
  489. vaGuid.bstrVal = strGuid.wsz;
  490. pwb->ShowBrowserBar(&vaGuid, PVAREMPTY, PVAREMPTY);
  491. }
  492. // don't release, we're going to return pwb.
  493. }
  494. if (ppwb)
  495. *ppwb = pwb;
  496. else if (pwb)
  497. pwb->Release();
  498. return hr;
  499. }
  500. //
  501. // Just like TB_GETBUTTONSIZE except that theme borders are subtracted out.
  502. //
  503. LRESULT TB_GetButtonSizeWithoutThemeBorder(HWND hwndTB, HTHEME hThemeParent)
  504. {
  505. LRESULT lButtonSize = SendMessage(hwndTB, TB_GETBUTTONSIZE, 0, 0L);
  506. if (hThemeParent)
  507. {
  508. HTHEME hTheme = OpenThemeData(hwndTB, L"Toolbar");
  509. if (hTheme)
  510. {
  511. RECT rc = { 0, 0, 0, 0 };
  512. if (SUCCEEDED(GetThemeBackgroundExtent(hTheme, NULL, TP_BUTTON, TS_NORMAL, &rc, &rc)))
  513. {
  514. lButtonSize = MAKELONG(LOWORD(lButtonSize) - RECTWIDTH(rc),
  515. HIWORD(lButtonSize) - RECTHEIGHT(rc));
  516. }
  517. CloseThemeData(hTheme);
  518. }
  519. }
  520. return lButtonSize;
  521. }
  522. #ifdef DEBUG
  523. extern "C" void DumpMsg(LPCTSTR pszLabel, MSG * pmsg)
  524. {
  525. ASSERT(IS_VALID_STRING_PTR(pszLabel, -1));
  526. ASSERT(pmsg);
  527. switch (pmsg->message)
  528. {
  529. case WM_LBUTTONDOWN:
  530. TraceMsg(TF_ALWAYS, "%s: msg = WM_LBUTTONDOWN hwnd = %#08lx x = %d y = %d",
  531. pszLabel, pmsg->hwnd, pmsg->pt.x, pmsg->pt.y);
  532. TraceMsg(TF_ALWAYS, " keys = %#04lx x = %d y = %d",
  533. pmsg->wParam, LOWORD(pmsg->lParam), HIWORD(pmsg->lParam));
  534. break;
  535. case WM_LBUTTONUP:
  536. TraceMsg(TF_ALWAYS, "%s: msg = WM_LBUTTONUP hwnd = %#08lx x = %d y = %d",
  537. pszLabel, pmsg->hwnd, pmsg->pt.x, pmsg->pt.y);
  538. TraceMsg(TF_ALWAYS, " keys = %#04lx x = %d y = %d",
  539. pmsg->wParam, LOWORD(pmsg->lParam), HIWORD(pmsg->lParam));
  540. break;
  541. case WM_KEYDOWN:
  542. case WM_SYSKEYDOWN:
  543. case WM_KEYUP:
  544. case WM_SYSKEYUP:
  545. BLOCK
  546. {
  547. LPTSTR pcsz = TEXT("(unknown)");
  548. switch (pmsg->message)
  549. {
  550. STRING_CASE(WM_KEYDOWN);
  551. STRING_CASE(WM_SYSKEYDOWN);
  552. STRING_CASE(WM_KEYUP);
  553. STRING_CASE(WM_SYSKEYUP);
  554. }
  555. TraceMsg(TF_ALWAYS, "%s: msg = %s hwnd = %#08lx",
  556. pszLabel, pcsz, pmsg->hwnd);
  557. TraceMsg(TF_ALWAYS, " vk = %#04lx count = %u flags = %#04lx",
  558. pmsg->wParam, LOWORD(pmsg->lParam), HIWORD(pmsg->lParam));
  559. }
  560. break;
  561. case WM_CHAR:
  562. case WM_SYSCHAR:
  563. BLOCK
  564. {
  565. LPTSTR pcsz = TEXT("(unknown)");
  566. switch (pmsg->message)
  567. {
  568. STRING_CASE(WM_CHAR);
  569. STRING_CASE(WM_SYSCHAR);
  570. }
  571. TraceMsg(TF_ALWAYS, "%s: msg = %s hwnd = %#08lx",
  572. pszLabel, pcsz, pmsg->hwnd);
  573. TraceMsg(TF_ALWAYS, " char = '%c' count = %u flags = %#04lx",
  574. pmsg->wParam, LOWORD(pmsg->lParam), HIWORD(pmsg->lParam));
  575. }
  576. break;
  577. case WM_MOUSEMOVE:
  578. #if 0
  579. TraceMsg(TF_ALWAYS, "%s: msg = WM_MOUSEMOVE hwnd = %#08lx x=%d y=%d",
  580. pszLabel, pmsg->hwnd, LOWORD(pmsg->lParam), HIWORD(pmsg->lParam));
  581. #endif
  582. break;
  583. case WM_TIMER:
  584. #if 0
  585. TraceMsg(TF_ALWAYS, "%s: msg = WM_TIMER hwnd = %#08lx x = %d y = %d",
  586. pszLabel, pmsg->hwnd, pmsg->pt.x, pmsg->pt.y);
  587. TraceMsg(TF_ALWAYS, " id = %#08lx",
  588. pmsg->wParam);
  589. #endif
  590. break;
  591. case WM_MENUSELECT:
  592. TraceMsg(TF_ALWAYS, "%s: msg = WM_MENUSELECT hwnd = %#08lx x = %d y = %d",
  593. pszLabel, pmsg->hwnd, pmsg->pt.x, pmsg->pt.y);
  594. TraceMsg(TF_ALWAYS, " uItem = %#04lx flags = %#04lx hmenu = %#08lx",
  595. GET_WM_MENUSELECT_CMD(pmsg->wParam, pmsg->lParam),
  596. GET_WM_MENUSELECT_FLAGS(pmsg->wParam, pmsg->lParam),
  597. GET_WM_MENUSELECT_HMENU(pmsg->wParam, pmsg->lParam));
  598. break;
  599. default:
  600. if (WM_USER > pmsg->message)
  601. {
  602. TraceMsg(TF_ALWAYS, "%s: msg = %#04lx hwnd=%#04lx wP=%#08lx lP=%#08lx",
  603. pszLabel, pmsg->message, pmsg->hwnd, pmsg->wParam, pmsg->lParam);
  604. }
  605. break;
  606. }
  607. }
  608. #endif