(Win7 class includes Win8/Vista/Server2012/Server2008/R2)

This new api was introduced in Vista/2K8 to keep track of clipboard changes,
without the need to trust the (mis)behavior of other applications registered
to the clipboard.

If the issue is reproduced on XP as well, it can be hacked by a periodic call
to ChangeClipboardChain & SetClipboardViewer as described in
http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/
521183dc-7872-472e-8104-8c0d75b1bf53

rhbz #919451
---
 vdagent/vdagent.cpp    |   40 ++++++++++++++++++++++++++++++++++++++--
 vdagent/vdagent.vcproj |    4 ++++
 2 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index 1dcfd1a..b5d65cd 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -65,6 +65,8 @@ typedef struct ALIGN_VC VDIChunk {
 #define VD_MESSAGE_HEADER_SIZE (sizeof(VDIChunk) + sizeof(VDAgentMessage))
 #define VD_READ_BUF_SIZE       (sizeof(VDIChunk) + VD_AGENT_MAX_DATA_SIZE)
 
+typedef BOOL (WINAPI *PCLIPBOARD_OP)(HWND);
+
 class VDAgent {
 public:
     static VDAgent* get();
@@ -120,6 +122,10 @@ private:
     static VDAgent* _singleton;
     HWND _hwnd;
     HWND _hwnd_next_viewer;
+    HMODULE _user_lib; 
+    PCLIPBOARD_OP _add_clipboard_listener;
+    PCLIPBOARD_OP _remove_clipboard_listener;
+    int _system_version;
     int _clipboard_owner;
     DWORD _clipboard_tick;
     DWORD _buttons_state;
@@ -174,6 +180,9 @@ VDAgent* VDAgent::get()
 VDAgent::VDAgent()
     : _hwnd (NULL)
     , _hwnd_next_viewer (NULL)
+    , _user_lib (NULL)
+    , _add_clipboard_listener (NULL)
+    , _remove_clipboard_listener (NULL)
     , _clipboard_owner (owner_none)
     , _clipboard_tick (0)
     , _buttons_state (0)
@@ -201,6 +210,7 @@ VDAgent::VDAgent()
     TCHAR log_path[MAX_PATH];
     TCHAR temp_path[MAX_PATH];
 
+    _system_version = supported_system_version();
     if (GetTempPath(MAX_PATH, temp_path)) {
         swprintf_s(log_path, MAX_PATH, VD_AGENT_LOG_PATH, temp_path);
         _log = VDLog::get(log_path);
@@ -262,6 +272,22 @@ bool VDAgent::run()
     if (!SetProcessShutdownParameters(0x100, 0)) {
         vd_printf("SetProcessShutdownParameters failed %lu", GetLastError());
     }
+    if (_system_version == SYS_VER_WIN_7_CLASS) {
+        _user_lib = LoadLibrary(L"User32.dll");
+        if (!_user_lib) {
+            vd_printf("LoadLibrary failed %lu", GetLastError());
+            return false;
+        }
+        _add_clipboard_listener =
+            (PCLIPBOARD_OP)GetProcAddress(_user_lib, 
"AddClipboardFormatListener");
+        _remove_clipboard_listener =
+            (PCLIPBOARD_OP)GetProcAddress(_user_lib, 
"RemoveClipboardFormatListener");
+        if (!_add_clipboard_listener || !_remove_clipboard_listener) {
+            vd_printf("GetProcAddress failed %lu", GetLastError());
+            cleanup();
+            return false;
+        }
+    }
     _control_event = CreateEvent(NULL, FALSE, FALSE, NULL);
     if (!_control_event) {
         vd_printf("CreateEvent() failed: %lu", GetLastError());
@@ -320,6 +346,7 @@ bool VDAgent::run()
 
 void VDAgent::cleanup()
 {
+    FreeLibrary(_user_lib);
     CloseHandle(_stop_event);
     CloseHandle(_control_event);
     CloseHandle(_vio_serial);
@@ -420,7 +447,11 @@ void VDAgent::input_desktop_message_loop()
     if (!WTSRegisterSessionNotification(_hwnd, NOTIFY_FOR_ALL_SESSIONS)) {
         vd_printf("WTSRegisterSessionNotification() failed: %lu", 
GetLastError());
     }
-    _hwnd_next_viewer = SetClipboardViewer(_hwnd);
+    if (_system_version == SYS_VER_WIN_7_CLASS) {
+        _add_clipboard_listener(_hwnd);
+    } else {
+        _hwnd_next_viewer = SetClipboardViewer(_hwnd);
+    }
     while (_running && !_desktop_switch) {
         event_dispatcher(INFINITE, QS_ALLINPUT);
     }
@@ -429,7 +460,11 @@ void VDAgent::input_desktop_message_loop()
         KillTimer(_hwnd, VD_TIMER_ID);
         _pending_input = false;
     }
-    ChangeClipboardChain(_hwnd, _hwnd_next_viewer);
+    if (_system_version == SYS_VER_WIN_7_CLASS) {
+        _remove_clipboard_listener(_hwnd);
+    } else {
+        ChangeClipboardChain(_hwnd, _hwnd_next_viewer);
+    }
     WTSUnRegisterSessionNotification(_hwnd);
     DestroyWindow(_hwnd);
     CloseDesktop(hdesk);
@@ -1343,6 +1378,7 @@ LRESULT CALLBACK VDAgent::wnd_proc(HWND hwnd, UINT 
message, WPARAM wparam, LPARA
             SendMessage(a->_hwnd_next_viewer, message, wparam, lparam);
         }
         break;
+    case WM_CLIPBOARDUPDATE:
     case WM_DRAWCLIPBOARD:
         if (a->_hwnd != GetClipboardOwner()) {
             a->set_clipboard_owner(a->owner_none);
diff --git a/vdagent/vdagent.vcproj b/vdagent/vdagent.vcproj
index 5e7bb43..ed8c58d 100644
--- a/vdagent/vdagent.vcproj
+++ b/vdagent/vdagent.vcproj
@@ -354,6 +354,10 @@
                                >
                        </File>
                        <File
+                               RelativePath="..\common\vdcommon.cpp"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\common\vdlog.cpp"
                                >
                        </File>
-- 
1.7.7.6

_______________________________________________
Spice-devel mailing list
Spice-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/spice-devel

Reply via email to