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.8KB

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