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.

CleanDesktop.cxx 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. *
  3. * This is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This software is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; if not, write to the Free Software
  15. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  16. * USA.
  17. */
  18. // -=- CleanDesktop.cxx
  19. #include <windows.h>
  20. #include <wininet.h>
  21. #include <shlobj.h>
  22. #include <rfb_win32/CleanDesktop.h>
  23. #include <rfb_win32/CurrentUser.h>
  24. #include <rfb_win32/Registry.h>
  25. #include <rfb/LogWriter.h>
  26. #include <rdr/Exception.h>
  27. #include <os/os.h>
  28. #include <set>
  29. using namespace rfb;
  30. using namespace rfb::win32;
  31. static LogWriter vlog("CleanDesktop");
  32. struct ActiveDesktop {
  33. ActiveDesktop() : handle(0) {
  34. // - Contact Active Desktop
  35. HRESULT result = CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER,
  36. IID_IActiveDesktop, (PVOID*)&handle);
  37. if (result != S_OK)
  38. throw rdr::SystemException("failed to contact Active Desktop", result);
  39. }
  40. ~ActiveDesktop() {
  41. if (handle)
  42. handle->Release();
  43. }
  44. // enableItem
  45. // enables or disables the Nth Active Desktop item
  46. bool enableItem(int i, bool enable_) {
  47. COMPONENT item;
  48. memset(&item, 0, sizeof(item));
  49. item.dwSize = sizeof(item);
  50. HRESULT hr = handle->GetDesktopItem(i, &item, 0);
  51. if (hr != S_OK) {
  52. vlog.error("unable to GetDesktopItem %d: %ld", i, hr);
  53. return false;
  54. }
  55. item.fChecked = enable_;
  56. vlog.debug("%sbling %d: \"%s\"", enable_ ? "ena" : "disa", i, (const char*)CStr(item.wszFriendlyName));
  57. hr = handle->ModifyDesktopItem(&item, COMP_ELEM_CHECKED);
  58. return hr == S_OK;
  59. }
  60. // enable
  61. // Attempts to enable/disable Active Desktop, returns true if the setting changed,
  62. // false otherwise.
  63. // If Active Desktop *can* be enabled/disabled then that is done.
  64. // If Active Desktop is always on (XP/2K3) then instead the individual items are
  65. // disabled, and true is returned to indicate that they need to be restored later.
  66. bool enable(bool enable_) {
  67. bool modifyComponents = false;
  68. vlog.debug("ActiveDesktop::enable");
  69. // - Firstly, try to disable Active Desktop entirely
  70. HRESULT hr;
  71. COMPONENTSOPT adOptions;
  72. memset(&adOptions, 0, sizeof(adOptions));
  73. adOptions.dwSize = sizeof(adOptions);
  74. // Attempt to actually disable/enable AD
  75. hr = handle->GetDesktopItemOptions(&adOptions, 0);
  76. if (hr == S_OK) {
  77. // If Active Desktop is already in the desired state then return false (no change)
  78. // NB: If AD is enabled AND restoreItems is set then we regard it as disabled...
  79. if (((adOptions.fActiveDesktop==0) && restoreItems.empty()) == (enable_==false))
  80. return false;
  81. adOptions.fActiveDesktop = enable_;
  82. hr = handle->SetDesktopItemOptions(&adOptions, 0);
  83. }
  84. // Apply the change, then test whether it actually took effect
  85. if (hr == S_OK)
  86. hr = handle->ApplyChanges(AD_APPLY_REFRESH);
  87. if (hr == S_OK)
  88. hr = handle->GetDesktopItemOptions(&adOptions, 0);
  89. if (hr == S_OK)
  90. modifyComponents = (adOptions.fActiveDesktop==0) != (enable_==false);
  91. if (hr != S_OK) {
  92. vlog.error("failed to get/set Active Desktop options: %ld", hr);
  93. return false;
  94. }
  95. if (enable_) {
  96. // - We are re-enabling Active Desktop. If there are components in restoreItems
  97. // then restore them!
  98. std::set<int>::const_iterator i;
  99. for (i=restoreItems.begin(); i!=restoreItems.end(); i++) {
  100. enableItem(*i, true);
  101. }
  102. restoreItems.clear();
  103. } else if (modifyComponents) {
  104. // - Disable all currently enabled items, and add the disabled ones to restoreItems
  105. int itemCount = 0;
  106. hr = handle->GetDesktopItemCount(&itemCount, 0);
  107. if (hr != S_OK) {
  108. vlog.error("failed to get desktop item count: %ld", hr);
  109. return false;
  110. }
  111. for (int i=0; i<itemCount; i++) {
  112. if (enableItem(i, false))
  113. restoreItems.insert(i);
  114. }
  115. }
  116. // - Apply whatever changes we have made, but DON'T save them!
  117. hr = handle->ApplyChanges(AD_APPLY_REFRESH);
  118. return hr == S_OK;
  119. }
  120. IActiveDesktop* handle;
  121. std::set<int> restoreItems;
  122. };
  123. DWORD SysParamsInfo(UINT action, UINT param, PVOID ptr, UINT ini) {
  124. DWORD r = ERROR_SUCCESS;
  125. if (!SystemParametersInfo(action, param, ptr, ini)) {
  126. r = GetLastError();
  127. vlog.info("SPI error: %lu", r);
  128. }
  129. return r;
  130. }
  131. CleanDesktop::CleanDesktop() : restoreActiveDesktop(false),
  132. restoreWallpaper(false),
  133. restoreEffects(false) {
  134. CoInitialize(0);
  135. }
  136. CleanDesktop::~CleanDesktop() {
  137. enableEffects();
  138. enableWallpaper();
  139. CoUninitialize();
  140. }
  141. void CleanDesktop::disableWallpaper() {
  142. try {
  143. ImpersonateCurrentUser icu;
  144. vlog.debug("disable desktop wallpaper/Active Desktop");
  145. // -=- First attempt to remove the wallpaper using Active Desktop
  146. try {
  147. ActiveDesktop ad;
  148. if (ad.enable(false))
  149. restoreActiveDesktop = true;
  150. } catch (rdr::Exception& e) {
  151. vlog.error("%s", e.str());
  152. }
  153. // -=- Switch of normal wallpaper and notify apps
  154. SysParamsInfo(SPI_SETDESKWALLPAPER, 0, (PVOID) "", SPIF_SENDCHANGE);
  155. restoreWallpaper = true;
  156. } catch (rdr::Exception& e) {
  157. vlog.info("%s", e.str());
  158. }
  159. }
  160. void CleanDesktop::enableWallpaper() {
  161. try {
  162. ImpersonateCurrentUser icu;
  163. if (restoreActiveDesktop) {
  164. vlog.debug("restore Active Desktop");
  165. // -=- First attempt to re-enable Active Desktop
  166. try {
  167. ActiveDesktop ad;
  168. ad.enable(true);
  169. restoreActiveDesktop = false;
  170. } catch (rdr::Exception& e) {
  171. vlog.error("%s", e.str());
  172. }
  173. }
  174. if (restoreWallpaper) {
  175. vlog.debug("restore desktop wallpaper");
  176. // -=- Then restore the standard wallpaper if required
  177. SysParamsInfo(SPI_SETDESKWALLPAPER, 0, NULL, SPIF_SENDCHANGE);
  178. restoreWallpaper = false;
  179. }
  180. } catch (rdr::Exception& e) {
  181. vlog.info("%s", e.str());
  182. }
  183. }
  184. void CleanDesktop::disableEffects() {
  185. try {
  186. ImpersonateCurrentUser icu;
  187. vlog.debug("disable desktop effects");
  188. SysParamsInfo(SPI_SETFONTSMOOTHING, FALSE, 0, SPIF_SENDCHANGE);
  189. if (SysParamsInfo(SPI_GETUIEFFECTS, 0, &uiEffects, 0) == ERROR_CALL_NOT_IMPLEMENTED) {
  190. SysParamsInfo(SPI_GETCOMBOBOXANIMATION, 0, &comboBoxAnim, 0);
  191. SysParamsInfo(SPI_GETGRADIENTCAPTIONS, 0, &gradientCaptions, 0);
  192. SysParamsInfo(SPI_GETHOTTRACKING, 0, &hotTracking, 0);
  193. SysParamsInfo(SPI_GETLISTBOXSMOOTHSCROLLING, 0, &listBoxSmoothScroll, 0);
  194. SysParamsInfo(SPI_GETMENUANIMATION, 0, &menuAnim, 0);
  195. SysParamsInfo(SPI_SETCOMBOBOXANIMATION, 0, FALSE, SPIF_SENDCHANGE);
  196. SysParamsInfo(SPI_SETGRADIENTCAPTIONS, 0, FALSE, SPIF_SENDCHANGE);
  197. SysParamsInfo(SPI_SETHOTTRACKING, 0, FALSE, SPIF_SENDCHANGE);
  198. SysParamsInfo(SPI_SETLISTBOXSMOOTHSCROLLING, 0, FALSE, SPIF_SENDCHANGE);
  199. SysParamsInfo(SPI_SETMENUANIMATION, 0, FALSE, SPIF_SENDCHANGE);
  200. } else {
  201. SysParamsInfo(SPI_SETUIEFFECTS, 0, FALSE, SPIF_SENDCHANGE);
  202. // We *always* restore UI effects overall, since there is no Windows GUI to do it
  203. uiEffects = TRUE;
  204. }
  205. restoreEffects = true;
  206. } catch (rdr::Exception& e) {
  207. vlog.info("%s", e.str());
  208. }
  209. }
  210. void CleanDesktop::enableEffects() {
  211. try {
  212. if (restoreEffects) {
  213. ImpersonateCurrentUser icu;
  214. vlog.debug("restore desktop effects");
  215. RegKey desktopCfg;
  216. desktopCfg.openKey(HKEY_CURRENT_USER, _T("Control Panel\\Desktop"));
  217. SysParamsInfo(SPI_SETFONTSMOOTHING, desktopCfg.getInt(_T("FontSmoothing"), 0) != 0, 0, SPIF_SENDCHANGE);
  218. if (SysParamsInfo(SPI_SETUIEFFECTS, 0, (void*)(intptr_t)uiEffects, SPIF_SENDCHANGE) == ERROR_CALL_NOT_IMPLEMENTED) {
  219. SysParamsInfo(SPI_SETCOMBOBOXANIMATION, 0, (void*)(intptr_t)comboBoxAnim, SPIF_SENDCHANGE);
  220. SysParamsInfo(SPI_SETGRADIENTCAPTIONS, 0, (void*)(intptr_t)gradientCaptions, SPIF_SENDCHANGE);
  221. SysParamsInfo(SPI_SETHOTTRACKING, 0, (void*)(intptr_t)hotTracking, SPIF_SENDCHANGE);
  222. SysParamsInfo(SPI_SETLISTBOXSMOOTHSCROLLING, 0, (void*)(intptr_t)listBoxSmoothScroll, SPIF_SENDCHANGE);
  223. SysParamsInfo(SPI_SETMENUANIMATION, 0, (void*)(intptr_t)menuAnim, SPIF_SENDCHANGE);
  224. }
  225. restoreEffects = false;
  226. }
  227. } catch (rdr::Exception& e) {
  228. vlog.info("%s", e.str());
  229. }
  230. }