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.

836 lines
22 KiB

  1. #include "precomp.h"
  2. #include "mcinc.h"
  3. #include "util.h"
  4. #include "intshcut.h"
  5. #include "optary.h"
  6. #define COMPILE_MULTIMON_STUBS
  7. #include "multimon.h"
  8. #undef COMPILE_MULTIMON_STUBS
  9. BOOL IsSysKeyMessage(MSG *pMsg)
  10. {
  11. switch(pMsg->message)
  12. {
  13. case WM_SYSKEYDOWN:
  14. case WM_SYSKEYUP :
  15. case WM_SYSCHAR :
  16. if(pMsg->wParam == VK_MENU) break; // Alt key alone.
  17. if(pMsg->wParam >= L'0' && pMsg->wParam <= L'9' ) break; // ALT+<digit> should pass through.
  18. if(pMsg->wParam >= VK_NUMPAD0 && pMsg->wParam <= VK_NUMPAD9) break; // ALT+<numpad> should pass through.
  19. case WM_SYSDEADCHAR:
  20. return TRUE;
  21. }
  22. return FALSE;
  23. }
  24. BOOL IsGlobalKeyMessage(MSG *pMsg)
  25. {
  26. BOOL fRet = IsSysKeyMessage( pMsg );
  27. if(!fRet)
  28. {
  29. switch(pMsg->message)
  30. {
  31. case WM_KEYDOWN:
  32. case WM_KEYUP:
  33. // Allow ESC and CTRL-E as well...
  34. fRet = ((pMsg->wParam == VK_ESCAPE ) ||
  35. (pMsg->wParam == L'E' && GetAsyncKeyState( VK_CONTROL ) < 0) );
  36. }
  37. }
  38. return fRet;
  39. }
  40. int IsVK_TABCycler(MSG *pMsg)
  41. {
  42. int result;
  43. if (pMsg &&
  44. (pMsg->message == WM_KEYDOWN) &&
  45. ((pMsg->wParam == VK_TAB) || (pMsg->wParam == VK_F6)))
  46. {
  47. result = (GetKeyState(VK_SHIFT) < 0) ? -1 : 1;
  48. }
  49. else
  50. {
  51. result = 0;
  52. }
  53. return result;
  54. }
  55. DWORD CThreadData::s_dwTlsIndex = 0xffffffff;
  56. CThreadData::CThreadData()
  57. {
  58. }
  59. CThreadData::~CThreadData()
  60. {
  61. }
  62. BOOL CThreadData::TlsSetValue(CThreadData *ptd)
  63. {
  64. ATLASSERT(s_dwTlsIndex != 0xffffffff);
  65. // Don't call set twice except to clear
  66. ATLASSERT((NULL == ptd) || (NULL == ::TlsGetValue(s_dwTlsIndex)));
  67. return ::TlsSetValue(s_dwTlsIndex, ptd);
  68. }
  69. BOOL CThreadData::HaveData()
  70. {
  71. ATLASSERT(s_dwTlsIndex != 0xffffffff);
  72. return NULL != ::TlsGetValue(s_dwTlsIndex);
  73. }
  74. CThreadData *CThreadData::TlsGetValue()
  75. {
  76. ATLASSERT(s_dwTlsIndex != 0xffffffff);
  77. CThreadData *ptd = (CThreadData *)::TlsGetValue(s_dwTlsIndex);
  78. ATLASSERT(NULL != ptd);
  79. return ptd;
  80. }
  81. BOOL CThreadData::TlsAlloc()
  82. {
  83. ATLASSERT(s_dwTlsIndex == 0xffffffff); // Don't call this twice
  84. s_dwTlsIndex = ::TlsAlloc();
  85. return (s_dwTlsIndex != 0xffffffff) ? TRUE : FALSE;
  86. }
  87. BOOL CThreadData::TlsFree()
  88. {
  89. BOOL bResult;
  90. if (s_dwTlsIndex != 0xffffffff)
  91. {
  92. bResult = ::TlsFree(s_dwTlsIndex);
  93. s_dwTlsIndex = 0xffffffff;
  94. }
  95. else
  96. {
  97. bResult = FALSE;
  98. }
  99. return bResult;
  100. }
  101. HRESULT GetMarsTypeLib(ITypeLib **ppTypeLib)
  102. {
  103. ATLASSERT(NULL != ppTypeLib);
  104. CThreadData *pThreadData = CThreadData::TlsGetValue();
  105. if (!pThreadData->m_spTypeLib)
  106. {
  107. // Load our typelib, to be used for our automation interfaces
  108. WCHAR wszModule[_MAX_PATH+10];
  109. GetModuleFileNameW(_Module.GetModuleInstance(), wszModule, _MAX_PATH);
  110. LoadTypeLib(wszModule, &pThreadData->m_spTypeLib);
  111. }
  112. pThreadData->m_spTypeLib.CopyTo(ppTypeLib);
  113. return ((NULL != ppTypeLib) && (NULL != *ppTypeLib)) ? S_OK : E_FAIL;
  114. }
  115. UINT HashKey(LPCWSTR pwszName)
  116. {
  117. int hash = 0;
  118. while (*pwszName)
  119. {
  120. hash += (hash << 5) + *pwszName++;
  121. }
  122. return hash;
  123. }
  124. void AsciiToLower(LPWSTR pwsz)
  125. {
  126. while (*pwsz)
  127. {
  128. if ((*pwsz >= L'A') && (*pwsz <= L'Z'))
  129. {
  130. *pwsz += L'a' - L'A';
  131. }
  132. pwsz++;
  133. }
  134. }
  135. HRESULT PIDLToVariant(LPCITEMIDLIST pidl, CComVariant& v)
  136. {
  137. // the variant must be empty since we don't clear or initialize it
  138. HRESULT hr = S_OK;
  139. // NULL pidls are valid, so we just leave the variant empty and return S_OK
  140. if (pidl)
  141. {
  142. v.bstrVal = SysAllocStringLen(NULL, MAX_PATH);
  143. if (v.bstrVal)
  144. {
  145. // make this an official BSTR since the alloc succeeded
  146. v.vt = VT_BSTR;
  147. if (!SHGetPathFromIDListW(pidl, v.bstrVal))
  148. {
  149. // CComVariant will handle cleanup
  150. hr = E_FAIL;
  151. }
  152. }
  153. else
  154. {
  155. hr = E_OUTOFMEMORY;
  156. }
  157. }
  158. return hr;
  159. }
  160. // Checks if global state is offline
  161. BOOL IsGlobalOffline(void)
  162. {
  163. DWORD dwState = 0, dwSize = sizeof(DWORD);
  164. BOOL fRet = FALSE;
  165. HANDLE hModuleHandle = LoadLibraryA("wininet.dll");
  166. if (!hModuleHandle)
  167. {
  168. return FALSE;
  169. }
  170. if (InternetQueryOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &dwState, &dwSize))
  171. {
  172. if(dwState & INTERNET_STATE_DISCONNECTED_BY_USER)
  173. fRet = TRUE;
  174. }
  175. return fRet;
  176. }
  177. void SetGlobalOffline(BOOL fOffline)
  178. {
  179. INTERNET_CONNECTED_INFO ci;
  180. memset(&ci, 0, sizeof(ci));
  181. if (fOffline)
  182. {
  183. ci.dwConnectedState = INTERNET_STATE_DISCONNECTED_BY_USER;
  184. ci.dwFlags = ISO_FORCE_DISCONNECTED;
  185. }
  186. else
  187. {
  188. ci.dwConnectedState = INTERNET_STATE_CONNECTED;
  189. }
  190. InternetSetOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &ci, sizeof(ci));
  191. }
  192. HRESULT
  193. _WriteDIBToFile(HBITMAP hDib, HANDLE hFile)
  194. {
  195. if (!hDib)
  196. {
  197. return E_INVALIDARG;
  198. }
  199. // Make sure this is a valid DIB and get this useful info.
  200. DIBSECTION ds;
  201. if (!GetObject( hDib, sizeof(DIBSECTION), &ds ))
  202. {
  203. return E_INVALIDARG;
  204. }
  205. // We only deal with DIBs
  206. if (ds.dsBm.bmPlanes != 1)
  207. {
  208. return E_INVALIDARG;
  209. }
  210. // Calculate some color table sizes
  211. int nColors = ds.dsBmih.biBitCount <= 8 ? 1 << ds.dsBmih.biBitCount : 0;
  212. int nBitfields = ds.dsBmih.biCompression == BI_BITFIELDS ? 3 : 0;
  213. // Calculate the data size
  214. int nImageDataSize = ds.dsBmih.biSizeImage ? ds.dsBmih.biSizeImage : ds.dsBm.bmWidthBytes * ds.dsBm.bmHeight;
  215. // Get the color table (if needed)
  216. RGBQUAD rgbqaColorTable[256] = {0};
  217. if (nColors)
  218. {
  219. HDC hDC = CreateCompatibleDC(NULL);
  220. if (hDC)
  221. {
  222. HBITMAP hOldBitmap = reinterpret_cast<HBITMAP>(SelectObject(hDC,hDib));
  223. GetDIBColorTable( hDC, 0, nColors, rgbqaColorTable );
  224. SelectObject(hDC,hOldBitmap);
  225. DeleteDC( hDC );
  226. }
  227. }
  228. // Create the file header
  229. BITMAPFILEHEADER bmfh;
  230. bmfh.bfType = 'MB';
  231. bmfh.bfSize = 0;
  232. bmfh.bfReserved1 = 0;
  233. bmfh.bfReserved2 = 0;
  234. bmfh.bfOffBits = sizeof(bmfh) + sizeof(ds.dsBmih) + nBitfields*sizeof(DWORD) + nColors*sizeof(RGBQUAD);
  235. // Start writing! Note that we write out the bitfields and the color table. Only one,
  236. // at most, will actually result in data being written
  237. DWORD dwBytesWritten;
  238. if (!WriteFile( hFile, &bmfh, sizeof(bmfh), &dwBytesWritten, NULL ))
  239. return HRESULT_FROM_WIN32(GetLastError());
  240. if (!WriteFile( hFile, &ds.dsBmih, sizeof(ds.dsBmih), &dwBytesWritten, NULL ))
  241. return HRESULT_FROM_WIN32(GetLastError());
  242. if (!WriteFile( hFile, &ds.dsBitfields, nBitfields*sizeof(DWORD), &dwBytesWritten, NULL ))
  243. return HRESULT_FROM_WIN32(GetLastError());
  244. if (!WriteFile( hFile, rgbqaColorTable, nColors*sizeof(RGBQUAD), &dwBytesWritten, NULL ))
  245. return HRESULT_FROM_WIN32(GetLastError());
  246. if (!WriteFile( hFile, ds.dsBm.bmBits, nImageDataSize, &dwBytesWritten, NULL ))
  247. return HRESULT_FROM_WIN32(GetLastError());
  248. return S_OK;
  249. }
  250. HRESULT SaveDIBToFile(HBITMAP hbm, WCHAR *pszPath)
  251. {
  252. HRESULT hr = E_INVALIDARG;
  253. if (hbm != NULL &&
  254. hbm != INVALID_HANDLE_VALUE)
  255. {
  256. HANDLE hFile;
  257. hr = E_FAIL;
  258. hFile = CreateFileWrapW(pszPath, GENERIC_WRITE, FILE_SHARE_READ, NULL,
  259. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  260. if (hFile != INVALID_HANDLE_VALUE)
  261. {
  262. hr = _WriteDIBToFile(hbm, hFile);
  263. CloseHandle(hFile);
  264. }
  265. }
  266. return hr;
  267. }
  268. // BoundWindowRect will nudge a rectangle so that it stays fully on its current monitor.
  269. // pRect must be in workspace coordinates
  270. void BoundWindowRectToMonitor(HWND hwnd, RECT *pRect)
  271. {
  272. MONITORINFO mi;
  273. mi.cbSize = sizeof(mi);
  274. GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST), &mi);
  275. OffsetRect(&mi.rcWork,
  276. mi.rcMonitor.left - mi.rcWork.left,
  277. mi.rcMonitor.top - mi.rcWork.top);
  278. LONG lDeltaX = 0, lDeltaY = 0;
  279. if (pRect->left < mi.rcWork.left)
  280. lDeltaX = mi.rcWork.left - pRect->left;
  281. if (pRect->top < mi.rcWork.top)
  282. lDeltaY = mi.rcWork.top - pRect->top;
  283. if (pRect->right > mi.rcWork.right)
  284. lDeltaX = mi.rcWork.right - pRect->right;
  285. if (pRect->bottom > mi.rcWork.bottom)
  286. lDeltaY = mi.rcWork.bottom - pRect->bottom;
  287. RECT rc = *pRect;
  288. OffsetRect(&rc, lDeltaX, lDeltaY);
  289. IntersectRect(pRect, &rc, &mi.rcWork);
  290. }
  291. // Moves a rectangle down and to the right, by the same amount Windows would use
  292. // to cascade. If the new position is partially off-screen, then the rect is either
  293. // moved up to the top, or back to the origin.
  294. void CascadeWindowRectOnMonitor(HWND hwnd, RECT *pRect)
  295. {
  296. int delta = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYSIZEFRAME) - 1;
  297. OffsetRect(pRect, delta, delta);
  298. // test if the new rect will end up getting moved later on
  299. RECT rc = *pRect;
  300. BoundWindowRectToMonitor(hwnd, &rc);
  301. if (!EqualRect(pRect, &rc))
  302. {
  303. // rc had to be moved, so we'll restart the cascade using the best monitor
  304. MONITORINFO mi;
  305. mi.cbSize = sizeof(mi);
  306. GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST), &mi);
  307. if (rc.bottom < pRect->bottom && rc.left == pRect->left)
  308. {
  309. // Too tall to cascade further down, but we can keep the X and just
  310. // reset the Y. This fixes the bug of having a tall windows piling up
  311. // on the top left corner -- instead they will be offset to the right
  312. OffsetRect(pRect, 0, mi.rcMonitor.top - pRect->top);
  313. }
  314. else
  315. {
  316. // we've really run out of room, so restart cascade at top left
  317. OffsetRect(pRect,
  318. mi.rcMonitor.left - pRect->left,
  319. mi.rcMonitor.top - pRect->top);
  320. }
  321. }
  322. }
  323. struct WINDOWSEARCHSTRUCT
  324. {
  325. LONG x;
  326. LONG y;
  327. ATOM atomClass;
  328. BOOL fFoundWindow;
  329. };
  330. BOOL CALLBACK EnumWindowSearchProc(HWND hwnd, LPARAM lParam)
  331. {
  332. WINDOWSEARCHSTRUCT *pSearch = (WINDOWSEARCHSTRUCT *) lParam;
  333. if ((ATOM) GetClassLong(hwnd, GCW_ATOM) == pSearch->atomClass)
  334. {
  335. // Only check the rest if we find a window that matches our class
  336. WINDOWPLACEMENT wp;
  337. wp.length = sizeof(wp);
  338. GetWindowPlacement(hwnd, &wp);
  339. pSearch->fFoundWindow =
  340. pSearch->x == wp.rcNormalPosition.left &&
  341. pSearch->y == wp.rcNormalPosition.top &&
  342. IsWindowVisible(hwnd);
  343. }
  344. // return TRUE if we want to continue the enumeration
  345. return !pSearch->fFoundWindow;
  346. }
  347. // Checks whether there is a window of the same class at some location on screen.
  348. // x and y are in workspace coords because we need to use GetWindowPlacement to
  349. // retrieve the rect of the restored window.
  350. BOOL IsWindowOverlayed(HWND hwndMatch, LONG x, LONG y)
  351. {
  352. WINDOWSEARCHSTRUCT search = { x, y, (ATOM) GetClassLong(hwndMatch, GCW_ATOM), FALSE };
  353. EnumWindows(EnumWindowSearchProc, (LPARAM) &search);
  354. return search.fFoundWindow;
  355. }
  356. BOOL CInterfaceMarshal::Init()
  357. {
  358. m_hresMarshal = E_FAIL;
  359. m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  360. return m_hEvent != NULL;
  361. }
  362. CInterfaceMarshal::~CInterfaceMarshal()
  363. {
  364. if (m_hEvent)
  365. CloseHandle(m_hEvent);
  366. SAFERELEASE2(m_pStream);
  367. }
  368. HRESULT CInterfaceMarshal::Marshal(REFIID riid, IUnknown *pUnk)
  369. {
  370. ATLASSERT(pUnk);
  371. m_hresMarshal = CoMarshalInterThreadInterfaceInStream(riid, pUnk, &m_pStream);
  372. // We must signal the other thread regardless of whether the marshal was
  373. // successful, otherwise it will be blocked for a very long time.
  374. Signal();
  375. return m_hresMarshal;
  376. }
  377. HRESULT CInterfaceMarshal::UnMarshal(REFIID riid, void ** ppv)
  378. {
  379. HRESULT hr;
  380. ATLASSERT(ppv);
  381. if (S_OK == m_hresMarshal)
  382. {
  383. hr = CoGetInterfaceAndReleaseStream(m_pStream, riid, ppv);
  384. m_pStream = NULL;
  385. }
  386. else
  387. {
  388. hr = m_hresMarshal;
  389. }
  390. return hr;
  391. }
  392. void CInterfaceMarshal::Signal()
  393. {
  394. ATLASSERT(m_hEvent);
  395. SetEvent(m_hEvent);
  396. }
  397. // This waiting code was copied from Shdocvw iedisp.cpp
  398. //
  399. // hSignallingThread is the handle of the thread that will be setting the m_hEvent.
  400. // If that thread terminates before marshalling an interface, we can detect this
  401. // condition and not hang around pointlessly.
  402. HRESULT CInterfaceMarshal::WaitForSignal(HANDLE hSignallingThread, DWORD dwSecondsTimeout)
  403. {
  404. ATLASSERT(m_hEvent);
  405. HANDLE ah[] = { m_hEvent, hSignallingThread };
  406. DWORD dwStart = GetTickCount();
  407. DWORD dwMaxWait = 1000 * dwSecondsTimeout;
  408. DWORD dwWait = dwMaxWait;
  409. DWORD dwWaitResult;
  410. do {
  411. // dwWait is the number of millseconds we still need to wait for
  412. dwWaitResult = MsgWaitForMultipleObjects(
  413. ARRAYSIZE(ah), ah, FALSE, dwWait, QS_SENDMESSAGE);
  414. if (dwWaitResult == WAIT_OBJECT_0 + ARRAYSIZE(ah))
  415. {
  416. // Msg input. We allow the pending SendMessage() to go through
  417. MSG msg;
  418. PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  419. }
  420. else
  421. {
  422. // signaled or timed out, so we exit the loop
  423. break;
  424. }
  425. // Update dwWait. It will become larger than dwMaxWait if we
  426. // wait more than that
  427. dwWait = dwStart + dwMaxWait - GetTickCount();
  428. } while (dwWait <= dwMaxWait);
  429. HRESULT hr = E_FAIL;
  430. switch (dwWaitResult)
  431. {
  432. case WAIT_OBJECT_0:
  433. // Event signaled -- this is what should happen every time
  434. hr = m_hresMarshal;
  435. break;
  436. case WAIT_OBJECT_0 + 1:
  437. // Thread terminated before signalling
  438. break;
  439. case WAIT_OBJECT_0 + ARRAYSIZE(ah): // msg input -- fall through
  440. case WAIT_TIMEOUT:
  441. // Timed out while waiting for signal
  442. break;
  443. }
  444. return hr;
  445. }
  446. ////////////////////////////////////////////////////////////////////////////////
  447. HRESULT MarsNavigateShortcut(IUnknown *pBrowser, IUniformResourceLocator* pUrl, LPCWSTR pszPath)
  448. {
  449. HRESULT hr;
  450. if (pBrowser )
  451. {
  452. CComPtr<IMoniker> spMkUrl;
  453. CComPtr<IBindCtx> spBindCtx;
  454. // Create moniker
  455. LPWSTR pszURL = NULL;
  456. hr = pUrl->GetURL(&pszURL);
  457. if (pszURL)
  458. {
  459. hr = CreateURLMoniker(NULL, pszURL, &spMkUrl);
  460. SHFree(pszURL);
  461. }
  462. if (SUCCEEDED(hr) && spMkUrl)
  463. {
  464. // create bind context and register load options
  465. // NOTE: errors here are not fatal, as the bind context is optional, so hr is not set
  466. CreateBindCtx(0, &spBindCtx);
  467. if (spBindCtx)
  468. {
  469. CComPtr<IHtmlLoadOptions> spLoadOpt;
  470. if (SUCCEEDED(CoCreateInstance(CLSID_HTMLLoadOptions, NULL, CLSCTX_INPROC_SERVER,
  471. IID_IHtmlLoadOptions, (void**)&spLoadOpt)))
  472. {
  473. if (pszPath)
  474. {
  475. spLoadOpt->SetOption(HTMLLOADOPTION_INETSHORTCUTPATH, (void*)pszPath,
  476. (lstrlen(pszPath) + 1) * sizeof(WCHAR));
  477. }
  478. spBindCtx->RegisterObjectParam(L"__HTMLLOADOPTIONS", spLoadOpt);
  479. }
  480. }
  481. // create hyperlink using URL moniker
  482. CComPtr<IHlink> spHlink;
  483. hr = HlinkCreateFromMoniker(spMkUrl, NULL, NULL, NULL, 0, NULL, IID_IHlink, (void **)&spHlink);
  484. if (spHlink)
  485. {
  486. // navigate frame using hyperlink and bind context
  487. CComQIPtr<IHlinkFrame> spFrame(pBrowser);
  488. if (spFrame)
  489. {
  490. hr = spFrame->Navigate(0, spBindCtx, NULL, spHlink);
  491. }
  492. else
  493. {
  494. hr = E_NOINTERFACE;
  495. }
  496. }
  497. }
  498. }
  499. else
  500. {
  501. // L"MarsNavigateShortcut: target or path is NULL";
  502. hr = E_INVALIDARG;
  503. }
  504. return hr;
  505. }
  506. HRESULT MarsNavigateShortcut(IUnknown *pBrowser, LPCWSTR lpszPath)
  507. {
  508. HRESULT hr;
  509. if (pBrowser && lpszPath)
  510. {
  511. // create internet shortcut object
  512. CComPtr<IPersistFile> spPersistFile;
  513. hr = CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,
  514. IID_IPersistFile, (void **)&spPersistFile);
  515. if (SUCCEEDED(hr))
  516. {
  517. // persist from file
  518. hr = spPersistFile->Load(lpszPath, STGM_READ);
  519. if (SUCCEEDED(hr))
  520. {
  521. CComQIPtr<IUniformResourceLocator, &IID_IUniformResourceLocator> spURL(spPersistFile);
  522. if (spURL)
  523. {
  524. hr = MarsNavigateShortcut(pBrowser, spURL, lpszPath);
  525. }
  526. else
  527. {
  528. hr = E_NOINTERFACE;
  529. }
  530. }
  531. }
  532. }
  533. else
  534. {
  535. hr = E_INVALIDARG;
  536. }
  537. return hr;
  538. }
  539. HRESULT MarsVariantToPath(VARIANT &varItem, CComBSTR &strPath)
  540. {
  541. HRESULT hr = E_INVALIDARG;
  542. if (API_IsValidVariant(varItem))
  543. {
  544. switch (varItem.vt)
  545. {
  546. case VT_EMPTY:
  547. case VT_NULL:
  548. case VT_ERROR:
  549. // return path empty when undefined, null, or omitted
  550. strPath.Empty();
  551. hr = S_OK;
  552. break;
  553. case VT_BSTR:
  554. // make a copy of the supplied path
  555. strPath = varItem.bstrVal;
  556. hr = S_OK;
  557. break;
  558. case VT_DISPATCH:
  559. {
  560. // query for FolderItem interface
  561. CComQIPtr<FolderItem> spFolderItem(varItem.pdispVal);
  562. // if we don't have a FolderItem, try to get one
  563. if (!spFolderItem)
  564. {
  565. // if we got a Folder2 object instead of a FolderItem object
  566. CComQIPtr<Folder2> spFolder2(varItem.pdispVal);
  567. if (spFolder2)
  568. {
  569. // get FolderItem object from Folder2 interface
  570. spFolder2->get_Self(&spFolderItem);
  571. }
  572. }
  573. // if we managed to get a folder item
  574. if (spFolderItem)
  575. {
  576. // get the path from it
  577. CComBSTR bstr;
  578. hr = spFolderItem->get_Path(&bstr);
  579. strPath = bstr;
  580. }
  581. }
  582. break;
  583. }
  584. }
  585. return hr;
  586. }
  587. BOOL PathIsURLFileW(LPCWSTR lpszPath)
  588. {
  589. BOOL fDoesMatch = FALSE;
  590. if (lpszPath)
  591. {
  592. LPCWSTR lpszExt = PathFindExtensionW(lpszPath);
  593. if (lpszExt && (StrCmpIW(lpszExt, L".url") == 0))
  594. {
  595. fDoesMatch = TRUE;
  596. }
  597. }
  598. return fDoesMatch;
  599. }
  600. ////////////////////////////////////////////////////////////////////////////////
  601. #define GLOBAL_SETTINGS_PATH L"Software\\Microsoft\\PCHealth\\Global"
  602. //==================================================================
  603. // Registry helpers
  604. //==================================================================
  605. LONG CRegistryKey::QueryLongValue(LONG& lValue, LPCWSTR pwszValueName)
  606. {
  607. DWORD dwValue;
  608. LONG lResult = QueryValue(dwValue, pwszValueName);
  609. if (lResult == ERROR_SUCCESS)
  610. {
  611. lValue = (LONG) dwValue;
  612. }
  613. return lResult;
  614. }
  615. LONG CRegistryKey::SetLongValue(LONG lValue, LPCWSTR pwszValueName)
  616. {
  617. return SetValue((DWORD) lValue, pwszValueName);
  618. }
  619. LONG CRegistryKey::QueryBoolValue(BOOL& bValue, LPCWSTR pwszValueName)
  620. {
  621. DWORD dwValue;
  622. LONG lResult = QueryValue(dwValue, pwszValueName);
  623. if (lResult == ERROR_SUCCESS)
  624. {
  625. bValue = (BOOL) dwValue;
  626. }
  627. return lResult;
  628. }
  629. LONG CRegistryKey::SetBoolValue(BOOL bValue, LPCWSTR pwszValueName)
  630. {
  631. return SetValue((DWORD) bValue, pwszValueName);
  632. }
  633. LONG CRegistryKey::QueryBinaryValue(LPVOID pData, DWORD cbData, LPCWSTR pwszValueName)
  634. {
  635. DWORD dwType;
  636. DWORD lResult = RegQueryValueEx(m_hKey, pwszValueName, NULL, &dwType, (BYTE *) pData, &cbData);
  637. return (lResult == ERROR_SUCCESS) && (dwType != REG_BINARY) ? ERROR_INVALID_DATA : lResult;
  638. }
  639. LONG CRegistryKey::SetBinaryValue(LPVOID pData, DWORD cbData, LPCWSTR pwszValueName)
  640. {
  641. return RegSetValueEx(m_hKey, pwszValueName, NULL, REG_BINARY, (BYTE *) pData, cbData);
  642. }
  643. LONG CGlobalSettingsRegKey::CreateGlobalSubkey(LPCWSTR pwszSubkey)
  644. {
  645. CComBSTR strPath = GLOBAL_SETTINGS_PATH;
  646. if (pwszSubkey)
  647. {
  648. strPath += L"\\";
  649. strPath += pwszSubkey;
  650. }
  651. return Create(HKEY_CURRENT_USER, strPath);
  652. }
  653. LONG CGlobalSettingsRegKey::OpenGlobalSubkey(LPCWSTR pwszSubkey)
  654. {
  655. CComBSTR strPath = GLOBAL_SETTINGS_PATH;
  656. if (pwszSubkey)
  657. {
  658. strPath += L"\\";
  659. strPath += pwszSubkey;
  660. }
  661. return Open(HKEY_CURRENT_USER, strPath);
  662. }