[Spice-commits] 10 commits - vdagent/vdagent.cpp vdagent/vdagent.vcproj vdservice/vdi_port.cpp vdservice/vdservice.cpp vdservice/vdservice.vcproj

Arnon Gilboa agilboa at kemper.freedesktop.org
Mon Oct 11 08:59:21 PDT 2010


 vdagent/vdagent.cpp        |  414 +++++++++++++++++++++++++++++++++++----------
 vdagent/vdagent.vcproj     |  157 -----------------
 vdservice/vdi_port.cpp     |   64 ------
 vdservice/vdservice.cpp    |   12 -
 vdservice/vdservice.vcproj |  160 -----------------
 5 files changed, 333 insertions(+), 474 deletions(-)

New commits:
commit 1e7f9e85a78be3a6d70557de43f968387278bd05
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Mon Oct 11 15:10:04 2010 +0200

    vdagent: handle multiple types on clipboard grab send & receive

diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index 6c5f73a..c210016 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -31,10 +31,12 @@ typedef struct VDClipboardFormat {
     uint32_t type;
 } VDClipboardFormat;
 
-VDClipboardFormat supported_clipboard_formats[] = {
+VDClipboardFormat clipboard_formats[] = {
     {CF_UNICODETEXT, VD_AGENT_CLIPBOARD_UTF8_TEXT},
     {0, 0}};
 
+#define clipboard_formats_count (sizeof(clipboard_formats) / sizeof(clipboard_formats[0]))
+
 class VDAgent {
 public:
     static VDAgent* get();
@@ -49,7 +51,7 @@ private:
                                       uint32_t msg_size);
     bool handle_mon_config(VDAgentMonitorsConfig* mon_config, uint32_t port);
     bool handle_clipboard(VDAgentClipboard* clipboard, uint32_t size);
-    bool handle_clipboard_grab(VDAgentClipboardGrab* clipboard_grab);
+    bool handle_clipboard_grab(VDAgentClipboardGrab* clipboard_grab, uint32_t size);
     bool handle_clipboard_request(VDAgentClipboardRequest* clipboard_request);
     void handle_clipboard_release();
     bool handle_display_config(VDAgentDisplayConfig* display_config, uint32_t port);
@@ -794,27 +796,27 @@ bool VDAgent::write_message(uint32_t type, uint32_t size = 0, void* data = NULL)
     return true;
 }
 
-//FIXME: send grab for all available types rather than just the first one
 void VDAgent::on_clipboard_grab()
 {
-    uint32_t type = 0;
+    uint32_t* types = new uint32_t[clipboard_formats_count];
+    int count = 0;
 
-    for (VDClipboardFormat* iter = supported_clipboard_formats; iter->format && !type; iter++) {
-        if (IsClipboardFormatAvailable(iter->format)) {
-            type = iter->type;
-        }
-    }
-    if (!type) {
-        vd_printf("Unsupported clipboard format");
-        return;
-    }  
     if (!VD_AGENT_HAS_CAPABILITY(_client_caps, _client_caps_size,
                                  VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) {
         return;
     } 
-    uint32_t grab_types[] = {type};
-    write_message(VD_AGENT_CLIPBOARD_GRAB, sizeof(grab_types), &grab_types);
-    set_clipboard_owner(owner_guest);
+    for (VDClipboardFormat* iter = clipboard_formats; iter->format; iter++) {
+        if (IsClipboardFormatAvailable(iter->format)) {
+            types[count++] = iter->type;
+        }
+    }
+    if (count) {
+        write_message(VD_AGENT_CLIPBOARD_GRAB, count * sizeof(types[0]), types);
+        set_clipboard_owner(owner_guest);
+    } else {
+        vd_printf("Unsupported clipboard format");       
+    }  
+    delete[] types;
 }
 
 // In delayed rendering, Windows requires us to SetClipboardData before we return from
@@ -861,20 +863,30 @@ void VDAgent::on_clipboard_release()
     }
 }
 
-bool VDAgent::handle_clipboard_grab(VDAgentClipboardGrab* clipboard_grab)
+bool VDAgent::handle_clipboard_grab(VDAgentClipboardGrab* clipboard_grab, uint32_t size)
 {
-    //FIXME: use all types rather than just the first one 
-    uint32_t format = get_clipboard_format(clipboard_grab->types[0]);
+    bool has_supported_type = false;
+    uint32_t format;
 
-    if (!format) {
-        vd_printf("Unsupported clipboard type %u", clipboard_grab->types[0]);
-        return true;
+    for (uint32_t i = 0; i < size / sizeof(clipboard_grab->types[0]); i++) {
+        format = get_clipboard_format(clipboard_grab->types[i]);
+        //On first supported type, open and empty the clipboard
+        if (format && !has_supported_type) {
+            has_supported_type = true;
+            if (!OpenClipboard(_hwnd)) {
+                return false;
+            }
+            EmptyClipboard();
+        }
+        //For all supported type set delayed rendering
+        if (format) {
+            SetClipboardData(format, NULL);
+        }
     }
-    if (!OpenClipboard(_hwnd)) {
-        return false;
+    if (!has_supported_type) {
+        vd_printf("No supported clipboard types in client grab");
+        return true;
     }
-    EmptyClipboard();
-    SetClipboardData(format, NULL);
     CloseClipboard();
     set_clipboard_owner(owner_client);
     return true;
@@ -956,7 +968,7 @@ void VDAgent::handle_clipboard_release()
 
 uint32_t VDAgent::get_clipboard_format(uint32_t type)
 {
-    for (VDClipboardFormat* iter = supported_clipboard_formats; iter->format && iter->type; iter++) {
+    for (VDClipboardFormat* iter = clipboard_formats; iter->format && iter->type; iter++) {
         if (iter->type == type) {
             return iter->format;
         }
@@ -966,7 +978,7 @@ uint32_t VDAgent::get_clipboard_format(uint32_t type)
 
 uint32_t VDAgent::get_clipboard_type(uint32_t format)
 {
-    for (VDClipboardFormat* iter = supported_clipboard_formats; iter->format && iter->type; iter++) {
+    for (VDClipboardFormat* iter = clipboard_formats; iter->format && iter->type; iter++) {
         if (iter->format == format) {
             return iter->type;
         }
@@ -1027,7 +1039,7 @@ void VDAgent::dispatch_message(VDAgentMessage* msg, uint32_t port)
         a->handle_clipboard((VDAgentClipboard*)msg->data, msg->size - sizeof(VDAgentClipboard));
         break;
     case VD_AGENT_CLIPBOARD_GRAB:
-        a->handle_clipboard_grab((VDAgentClipboardGrab*)msg->data);        
+        a->handle_clipboard_grab((VDAgentClipboardGrab*)msg->data, msg->size);        
         break;
     case VD_AGENT_CLIPBOARD_REQUEST:
         res = a->handle_clipboard_request((VDAgentClipboardRequest*)msg->data);
commit d9c16de42956abe76a7c7710346abde2740093ab
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Wed Oct 6 16:35:55 2010 +0200

    vdagent: remove clipboard_changer hack
    
    Instead of keeping a flag, we simply check wether the new owner is usor not

diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index 32ad102..6c5f73a 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -83,7 +83,6 @@ private:
     static VDAgent* _singleton;
     HWND _hwnd;
     HWND _hwnd_next_viewer;
-    bool _clipboard_changer;
     int _clipboard_owner;
     DWORD _buttons_state;
     LONG _mouse_x;
@@ -128,7 +127,6 @@ VDAgent* VDAgent::get()
 VDAgent::VDAgent()
     : _hwnd (NULL)
     , _hwnd_next_viewer (NULL)
-    , _clipboard_changer (true)
     , _clipboard_owner (owner_none)
     , _buttons_state (0)
     , _mouse_x (0)
@@ -875,7 +873,6 @@ bool VDAgent::handle_clipboard_grab(VDAgentClipboardGrab* clipboard_grab)
     if (!OpenClipboard(_hwnd)) {
         return false;
     }
-    _clipboard_changer = true;
     EmptyClipboard();
     SetClipboardData(format, NULL);
     CloseClipboard();
@@ -1199,12 +1196,13 @@ LRESULT CALLBACK VDAgent::wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARA
         }
         break;
     case WM_DRAWCLIPBOARD:
-        if (!a->_clipboard_changer) {
+        if (a->_hwnd != GetClipboardOwner()) {
+            a->set_clipboard_owner(a->owner_none);
             a->on_clipboard_grab();
-        } else {
-            a->_clipboard_changer = false;
         }
-        SendMessage(a->_hwnd_next_viewer, message, wparam, lparam);
+        if (a->_hwnd_next_viewer) {
+            SendMessage(a->_hwnd_next_viewer, message, wparam, lparam);
+        }
         break;
     case WM_RENDERFORMAT:
         a->on_clipboard_request((UINT)wparam);
commit f58826a83f84d95d50a761835d7d716d7a939391
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Wed Oct 6 13:31:15 2010 +0200

    vdagent: Keep track of clipboard ownership
    
    Given that all clipboard handling is async, it is possible to for
    example receive a request for clipboard data from the client
    while the agent no longer owns the clipboard (ie a
    VD_AGENT_CLIPBOARD_RELEASE message is in transit to the client).
    
    Thus it is necessary to keep track of our notion of clipboard ownership
    and check received clipboard messages (both from other apps on the client
    machine and from the agent) to see if they match our notion and if not
    drop, or in case were a counter message is expected nack the clipboard
    message.(citing hansg)
    
    clean ups: capability checks, return values

diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index f3f571b..32ad102 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -51,11 +51,12 @@ private:
     bool handle_clipboard(VDAgentClipboard* clipboard, uint32_t size);
     bool handle_clipboard_grab(VDAgentClipboardGrab* clipboard_grab);
     bool handle_clipboard_request(VDAgentClipboardRequest* clipboard_request);
-    bool handle_clipboard_release();
+    void handle_clipboard_release();
     bool handle_display_config(VDAgentDisplayConfig* display_config, uint32_t port);
     bool handle_control(VDPipeMessage* msg);
-    bool on_clipboard_grab();
-    bool on_clipboard_request(UINT format);
+    void on_clipboard_grab();
+    void on_clipboard_request(UINT format);
+    void on_clipboard_release();
     DWORD get_buttons_change(DWORD last_buttons_state, DWORD new_buttons_state,
                              DWORD mask, DWORD down_flag, DWORD up_flag);
     static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
@@ -65,6 +66,8 @@ private:
     static void dispatch_message(VDAgentMessage* msg, uint32_t port);
     static uint32_t get_clipboard_format(uint32_t type);
     static uint32_t get_clipboard_type(uint32_t format);
+    enum { owner_none, owner_guest, owner_client };
+    void set_clipboard_owner(int new_owner);
     uint8_t* write_lock(DWORD bytes = 0);
     void write_unlock(DWORD bytes = 0);
     bool write_message(uint32_t type, uint32_t size, void* data);
@@ -81,6 +84,7 @@ private:
     HWND _hwnd;
     HWND _hwnd_next_viewer;
     bool _clipboard_changer;
+    int _clipboard_owner;
     DWORD _buttons_state;
     LONG _mouse_x;
     LONG _mouse_y;
@@ -125,6 +129,7 @@ VDAgent::VDAgent()
     : _hwnd (NULL)
     , _hwnd_next_viewer (NULL)
     , _clipboard_changer (true)
+    , _clipboard_owner (owner_none)
     , _buttons_state (0)
     , _mouse_x (0)
     , _mouse_y (0)
@@ -491,7 +496,6 @@ bool VDAgent::handle_mon_config(VDAgentMonitorsConfig* mon_config, uint32_t port
     return true;
 }
 
-//FIXME: handle clipboard->type == VD_AGENT_CLIPBOARD_NONE
 bool VDAgent::handle_clipboard(VDAgentClipboard* clipboard, uint32_t size)
 {
     HGLOBAL clip_data;
@@ -501,6 +505,15 @@ bool VDAgent::handle_clipboard(VDAgentClipboard* clipboard, uint32_t size)
     UINT format;
     bool ret = false;
 
+    if (_clipboard_owner != owner_client) {
+        vd_printf("Received clipboard data from client while clipboard is not owned by client");
+        SetEvent(_clipboard_event);
+        return false;
+    }
+    if (clipboard->type == VD_AGENT_CLIPBOARD_NONE) {
+        SetEvent(_clipboard_event);
+        return false;
+    }
     // Get the required clipboard size
     switch (clipboard->type) {
     case VD_AGENT_CLIPBOARD_UTF8_TEXT:
@@ -513,7 +526,7 @@ bool VDAgent::handle_clipboard(VDAgentClipboard* clipboard, uint32_t size)
         break;
     default:
         vd_printf("Unsupported clipboard type %u", clipboard->type);
-        return false;
+        return true;
     }
     // Allocate and lock clipboard memory
     if (!(clip_data = GlobalAlloc(GMEM_DDESHARE, clip_size))) {
@@ -783,14 +796,11 @@ bool VDAgent::write_message(uint32_t type, uint32_t size = 0, void* data = NULL)
     return true;
 }
 
-bool VDAgent::on_clipboard_grab()
+//FIXME: send grab for all available types rather than just the first one
+void VDAgent::on_clipboard_grab()
 {
     uint32_t type = 0;
 
-    if (!_client_caps || !VD_AGENT_HAS_CAPABILITY(_client_caps, _client_caps_size,
-                                                  VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) {
-        return true;
-    }
     for (VDClipboardFormat* iter = supported_clipboard_formats; iter->format && !type; iter++) {
         if (IsClipboardFormatAvailable(iter->format)) {
             type = iter->type;
@@ -798,38 +808,59 @@ bool VDAgent::on_clipboard_grab()
     }
     if (!type) {
         vd_printf("Unsupported clipboard format");
-        return false;
-    }
-    
-    //FIXME: use all available types rather than just the first one 
+        return;
+    }  
+    if (!VD_AGENT_HAS_CAPABILITY(_client_caps, _client_caps_size,
+                                 VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) {
+        return;
+    } 
     uint32_t grab_types[] = {type};
-    return write_message(VD_AGENT_CLIPBOARD_GRAB, sizeof(grab_types), &grab_types);
+    write_message(VD_AGENT_CLIPBOARD_GRAB, sizeof(grab_types), &grab_types);
+    set_clipboard_owner(owner_guest);
 }
 
 // In delayed rendering, Windows requires us to SetClipboardData before we return from
 // handling WM_RENDERFORMAT. Therefore, we try our best by sending CLIPBOARD_REQUEST to the
 // agent, while waiting alertably for a while (hoping for good) for receiving CLIPBOARD data
 // or CLIPBOARD_RELEASE from the agent, which both will signal clipboard_event.
-bool VDAgent::on_clipboard_request(UINT format)
+// In case of unsupported format, wrong clipboard owner or no clipboard capability, we do nothing in
+// WM_RENDERFORMAT and return immediately.
+// FIXME: need to be handled using request queue
+void VDAgent::on_clipboard_request(UINT format)
 {
     uint32_t type;
 
-    if (!_client_caps || !VD_AGENT_HAS_CAPABILITY(_client_caps, _client_caps_size,
-                                                  VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) {
-        return true;
+    if (_clipboard_owner != owner_client) {
+        vd_printf("Received render request event for format %u"
+                  "while clipboard is not owned by client", format);
+        return;
     }
     if (!(type = get_clipboard_type(format))) {
         vd_printf("Unsupported clipboard format %u", format);
-        return false;
+        return;
+    }
+    if (!VD_AGENT_HAS_CAPABILITY(_client_caps, _client_caps_size,
+                                 VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) {
+        return;
     }
     VDAgentClipboardRequest request = {type};
     if (!write_message(VD_AGENT_CLIPBOARD_REQUEST, sizeof(request), &request)) {
-        return false;
+        return;
     }
     DWORD start_tick = GetTickCount();
     while (WaitForSingleObjectEx(_clipboard_event, 1000, TRUE) != WAIT_OBJECT_0 &&
            GetTickCount() < start_tick + VD_CLIPBOARD_TIMEOUT_MS);
-    return true;
+}
+
+void VDAgent::on_clipboard_release()
+{
+    if (!VD_AGENT_HAS_CAPABILITY(_client_caps, _client_caps_size,
+                                 VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) {
+        return;
+    }
+    if (_clipboard_owner == owner_guest) {
+        write_message(VD_AGENT_CLIPBOARD_RELEASE, 0, NULL);
+    }
 }
 
 bool VDAgent::handle_clipboard_grab(VDAgentClipboardGrab* clipboard_grab)
@@ -839,7 +870,7 @@ bool VDAgent::handle_clipboard_grab(VDAgentClipboardGrab* clipboard_grab)
 
     if (!format) {
         vd_printf("Unsupported clipboard type %u", clipboard_grab->types[0]);
-        return false;
+        return true;
     }
     if (!OpenClipboard(_hwnd)) {
         return false;
@@ -848,10 +879,12 @@ bool VDAgent::handle_clipboard_grab(VDAgentClipboardGrab* clipboard_grab)
     EmptyClipboard();
     SetClipboardData(format, NULL);
     CloseClipboard();
+    set_clipboard_owner(owner_client);
     return true;
 }
 
-//FIXME: when req type not supported, send (VD_AGENT_CLIPBOARD_NONE, NULL, 0)
+// If handle_clipboard_request() fails, its caller sends VD_AGENT_CLIPBOARD message with type
+// VD_AGENT_CLIPBOARD_NONE and no data, so the client will know the request failed.
 bool VDAgent::handle_clipboard_request(VDAgentClipboardRequest* clipboard_request)
 {
     UINT format;
@@ -860,6 +893,10 @@ bool VDAgent::handle_clipboard_request(VDAgentClipboardRequest* clipboard_reques
     int clip_size;
     size_t len;
 
+    if (_clipboard_owner != owner_guest) {
+        vd_printf("Received clipboard request from client while clipboard is not owned by guest");
+        return false;
+    }
     if (!(format = get_clipboard_format(clipboard_request->type))) {
         vd_printf("Unsupported clipboard type %u", clipboard_request->type);
         return false;
@@ -910,10 +947,14 @@ bool VDAgent::handle_clipboard_request(VDAgentClipboardRequest* clipboard_reques
     return true;
 }
 
-bool VDAgent::handle_clipboard_release()
+void VDAgent::handle_clipboard_release()
 {
+    if (_clipboard_owner != owner_client) {
+        vd_printf("Received clipboard release from client while clipboard is not owned by client");
+        return;
+    }
     SetEvent(_clipboard_event);
-    return true;
+    set_clipboard_owner(owner_none);
 }
 
 uint32_t VDAgent::get_clipboard_format(uint32_t type)
@@ -936,6 +977,15 @@ uint32_t VDAgent::get_clipboard_type(uint32_t format)
     return 0;
 }
 
+void VDAgent::set_clipboard_owner(int new_owner)
+{
+    // FIXME: Clear requests, clipboard data and state
+    if (new_owner == owner_none) {
+        on_clipboard_release();
+    }
+    _clipboard_owner = new_owner;
+}
+
 bool VDAgent::connect_pipe()
 {
     VDAgent* a = _singleton;
@@ -977,11 +1027,10 @@ void VDAgent::dispatch_message(VDAgentMessage* msg, uint32_t port)
         res = a->handle_mon_config((VDAgentMonitorsConfig*)msg->data, port);
         break;
     case VD_AGENT_CLIPBOARD:
-        res = a->handle_clipboard((VDAgentClipboard*)msg->data,
-                                  msg->size - sizeof(VDAgentClipboard));
+        a->handle_clipboard((VDAgentClipboard*)msg->data, msg->size - sizeof(VDAgentClipboard));
         break;
     case VD_AGENT_CLIPBOARD_GRAB:
-        res = a->handle_clipboard_grab((VDAgentClipboardGrab*)msg->data);
+        a->handle_clipboard_grab((VDAgentClipboardGrab*)msg->data);        
         break;
     case VD_AGENT_CLIPBOARD_REQUEST:
         res = a->handle_clipboard_request((VDAgentClipboardRequest*)msg->data);
@@ -991,7 +1040,7 @@ void VDAgent::dispatch_message(VDAgentMessage* msg, uint32_t port)
         }
         break;
     case VD_AGENT_CLIPBOARD_RELEASE:
-        res = a->handle_clipboard_release();
+        a->handle_clipboard_release();
         break;
     case VD_AGENT_DISPLAY_CONFIG:
         res = a->handle_display_config((VDAgentDisplayConfig*)msg->data, port);
commit 1d095da5d8b0c662d5f4b9b58b851d2066acef01
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Tue Oct 5 16:02:52 2010 +0200

    vdagent: receiving a clipboard request with an unsupported type is replied by data with a none type
    
    Currently we send a VD_AGENT_CLIPBOARD_RELEASE when we receive a
    VD_AGENT_CLIPBOARD_REQUEST with a type which we do not support. This is not
    correct, as this means given up clipboard ownership while we may be able
    to answer requests with different types. The correct response is to
    nack the request by sending a VD_AGENT_CLIPBOARD (data) message with a type
    of VD_AGENT_CLIPBOARD_NONE.(citing hansg)

diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index bf48e17..f3f571b 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -803,7 +803,7 @@ bool VDAgent::on_clipboard_grab()
     
     //FIXME: use all available types rather than just the first one 
     uint32_t grab_types[] = {type};
-    return write_message(VD_AGENT_CLIPBOARD_GRAB, sizeof(grab_types), &grab_types);  
+    return write_message(VD_AGENT_CLIPBOARD_GRAB, sizeof(grab_types), &grab_types);
 }
 
 // In delayed rendering, Windows requires us to SetClipboardData before we return from
@@ -986,7 +986,8 @@ void VDAgent::dispatch_message(VDAgentMessage* msg, uint32_t port)
     case VD_AGENT_CLIPBOARD_REQUEST:
         res = a->handle_clipboard_request((VDAgentClipboardRequest*)msg->data);
         if (!res) {
-            res = a->write_message(VD_AGENT_CLIPBOARD_RELEASE);
+            VDAgentClipboard clipboard = {VD_AGENT_CLIPBOARD_NONE};
+            res = a->write_message(VD_AGENT_CLIPBOARD, sizeof(clipboard), &clipboard);
         }
         break;
     case VD_AGENT_CLIPBOARD_RELEASE:
commit 9115c0397326c961bd2681878a56f12aad2a03dc
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Tue Oct 5 15:27:53 2010 +0200

    vdagent: remove windows-specific bitmap cut & paste support
    
    will wait until png comes in

diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index c65259d..bf48e17 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -33,7 +33,6 @@ typedef struct VDClipboardFormat {
 
 VDClipboardFormat supported_clipboard_formats[] = {
     {CF_UNICODETEXT, VD_AGENT_CLIPBOARD_UTF8_TEXT},
-    {CF_DIB, VD_AGENT_CLIPBOARD_BITMAP},
     {0, 0}};
 
 class VDAgent {
@@ -492,6 +491,7 @@ bool VDAgent::handle_mon_config(VDAgentMonitorsConfig* mon_config, uint32_t port
     return true;
 }
 
+//FIXME: handle clipboard->type == VD_AGENT_CLIPBOARD_NONE
 bool VDAgent::handle_clipboard(VDAgentClipboard* clipboard, uint32_t size)
 {
     HGLOBAL clip_data;
@@ -502,8 +502,8 @@ bool VDAgent::handle_clipboard(VDAgentClipboard* clipboard, uint32_t size)
     bool ret = false;
 
     // Get the required clipboard size
-    switch (format = get_clipboard_format(clipboard->type)) {
-    case CF_UNICODETEXT:
+    switch (clipboard->type) {
+    case VD_AGENT_CLIPBOARD_UTF8_TEXT:
         // Received utf8 string is not null-terminated   
         if (!(clip_len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)clipboard->data, size, NULL, 0))) {
             return false;
@@ -511,9 +511,6 @@ bool VDAgent::handle_clipboard(VDAgentClipboard* clipboard, uint32_t size)
         clip_len++;
         clip_size = clip_len * sizeof(WCHAR);
         break;
-    case CF_DIB:
-        clip_size = size;
-        break;
     default:
         vd_printf("Unsupported clipboard type %u", clipboard->type);
         return false;
@@ -527,21 +524,18 @@ bool VDAgent::handle_clipboard(VDAgentClipboard* clipboard, uint32_t size)
         return false;
     }
     // Translate data and set clipboard content
-    switch (format) {
-    case CF_UNICODETEXT:
+    switch (clipboard->type) {
+    case VD_AGENT_CLIPBOARD_UTF8_TEXT:
         ret = !!MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)clipboard->data, size, (LPWSTR)clip_buf,
                                     clip_len);
         ((LPWSTR)clip_buf)[clip_len - 1] = L'\0';
         break;
-    case CF_DIB:
-        memcpy(clip_buf, clipboard->data, size);
-        ret = true;
-        break;
     }
     GlobalUnlock(clip_data);
     if (!ret) {
         return false;
     }
+    format = get_clipboard_format(clipboard->type);
     if (SetClipboardData(format, clip_data)) {
         SetEvent(_clipboard_event);
         return true;
@@ -806,8 +800,10 @@ bool VDAgent::on_clipboard_grab()
         vd_printf("Unsupported clipboard format");
         return false;
     }
-    VDAgentClipboardGrab grab = {type};
-    return write_message(VD_AGENT_CLIPBOARD_GRAB, sizeof(grab), &grab);  
+    
+    //FIXME: use all available types rather than just the first one 
+    uint32_t grab_types[] = {type};
+    return write_message(VD_AGENT_CLIPBOARD_GRAB, sizeof(grab_types), &grab_types);  
 }
 
 // In delayed rendering, Windows requires us to SetClipboardData before we return from
@@ -838,10 +834,11 @@ bool VDAgent::on_clipboard_request(UINT format)
 
 bool VDAgent::handle_clipboard_grab(VDAgentClipboardGrab* clipboard_grab)
 {
-    uint32_t format = get_clipboard_format(clipboard_grab->type);
+    //FIXME: use all types rather than just the first one 
+    uint32_t format = get_clipboard_format(clipboard_grab->types[0]);
 
     if (!format) {
-        vd_printf("Unsupported clipboard type %u", clipboard_grab->type);
+        vd_printf("Unsupported clipboard type %u", clipboard_grab->types[0]);
         return false;
     }
     if (!OpenClipboard(_hwnd)) {
@@ -854,6 +851,7 @@ bool VDAgent::handle_clipboard_grab(VDAgentClipboardGrab* clipboard_grab)
     return true;
 }
 
+//FIXME: when req type not supported, send (VD_AGENT_CLIPBOARD_NONE, NULL, 0)
 bool VDAgent::handle_clipboard_request(VDAgentClipboardRequest* clipboard_request)
 {
     UINT format;
@@ -877,14 +875,11 @@ bool VDAgent::handle_clipboard_request(VDAgentClipboardRequest* clipboard_reques
         CloseClipboard();
         return false;
     }
-    switch (format) {
-    case CF_UNICODETEXT:
+    switch (clipboard_request->type) {
+    case VD_AGENT_CLIPBOARD_UTF8_TEXT:
         len = wcslen((wchar_t*)clip_buf);
         clip_size = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)clip_buf, (int)len, NULL, 0, NULL, NULL);
         break;
-    case CF_DIB:
-        clip_size = (int)GlobalSize(clip_data);
-        break;
     }
 
     if (!clip_size) {
@@ -902,14 +897,11 @@ bool VDAgent::handle_clipboard_request(VDAgentClipboardRequest* clipboard_reques
     VDAgentClipboard* clipboard = (VDAgentClipboard*)_out_msg->data;
     clipboard->type = clipboard_request->type;
 
-    switch (format) {
-    case CF_UNICODETEXT:
+    switch (clipboard_request->type) {
+    case VD_AGENT_CLIPBOARD_UTF8_TEXT:
         WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)clip_buf, (int)len, (LPSTR)clipboard->data,
                             clip_size, NULL, NULL);
         break;
-    case CF_DIB:
-        memcpy(clipboard->data, clip_buf, clip_size);
-        break;
     }
 
     GlobalUnlock(clip_data);
commit 23b5c1e068fc33a1467df774549ef0ccdea59983
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Wed Sep 29 14:24:44 2010 +0200

    vdagent: support & check VD_AGENT_CAP_CLIPBOARD_BY_DEMAND
    
    cleanup, rename change -> grab, render->request

diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index 5ff595f..c65259d 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -55,8 +55,8 @@ private:
     bool handle_clipboard_release();
     bool handle_display_config(VDAgentDisplayConfig* display_config, uint32_t port);
     bool handle_control(VDPipeMessage* msg);
-    bool on_clipboard_change();
-    bool on_clipboard_render(UINT format);
+    bool on_clipboard_grab();
+    bool on_clipboard_request(UINT format);
     DWORD get_buttons_change(DWORD last_buttons_state, DWORD new_buttons_state,
                              DWORD mask, DWORD down_flag, DWORD up_flag);
     static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
@@ -546,7 +546,7 @@ bool VDAgent::handle_clipboard(VDAgentClipboard* clipboard, uint32_t size)
         SetEvent(_clipboard_event);
         return true;
     }
-    // We retry clipboard open-empty-set-close only when there is a timeout in on_clipboard_render()
+    // We retry clipboard open-empty-set-close only when there is a timeout in on_clipboard_request()
     if (!OpenClipboard(_hwnd)) {
         return false;
     }
@@ -593,7 +593,6 @@ bool VDAgent::send_announce_capabilities(bool request)
     if (!caps_pipe_msg) {
         return false;
     }
-
     caps_size = VD_AGENT_CAPS_SIZE;
     caps_pipe_msg->type = VD_AGENT_COMMAND;
     caps_pipe_msg->opaque = VDP_CLIENT_PORT;
@@ -609,9 +608,9 @@ bool VDAgent::send_announce_capabilities(bool request)
     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_MOUSE_STATE);
     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_MONITORS_CONFIG);
     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_REPLY);
-    VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD);
     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_DISPLAY_CONFIG);
-    vd_printf("sending capabilities:");
+    VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND);
+    vd_printf("Sending capabilities:");
     for (uint32_t i = 0 ; i < caps_size; ++i) {
         vd_printf("%X", caps->caps[i]);
     }
@@ -622,29 +621,25 @@ bool VDAgent::send_announce_capabilities(bool request)
     return true;
 }
 
-bool VDAgent::handle_announce_capabilities(
-    VDAgentAnnounceCapabilities* announce_capabilities, uint32_t msg_size)
+bool VDAgent::handle_announce_capabilities(VDAgentAnnounceCapabilities* announce_capabilities,
+                                           uint32_t msg_size)
 {
     uint32_t caps_size = VD_AGENT_CAPS_SIZE_FROM_MSG_SIZE(msg_size);
 
-    vd_printf("got capabilities (%d)", caps_size);
+    vd_printf("Got capabilities (%d)", caps_size);
     for (uint32_t i = 0 ; i < caps_size; ++i) {
         vd_printf("%X", announce_capabilities->caps[i]);
     }
-
     if (caps_size != _client_caps_size) {
         delete[] _client_caps;
         _client_caps = new uint32_t[caps_size];
         ASSERT(_client_caps != NULL);
         _client_caps_size = caps_size;
     }
-    memcpy(_client_caps, announce_capabilities->caps,
-                         sizeof(_client_caps[0]) * caps_size);
-
+    memcpy(_client_caps, announce_capabilities->caps, sizeof(_client_caps[0]) * caps_size);
     if (announce_capabilities->request) {
         return send_announce_capabilities(false);
     }
-
     return true;
 }
 
@@ -794,10 +789,14 @@ bool VDAgent::write_message(uint32_t type, uint32_t size = 0, void* data = NULL)
     return true;
 }
 
-bool VDAgent::on_clipboard_change()
+bool VDAgent::on_clipboard_grab()
 {
     uint32_t type = 0;
 
+    if (!_client_caps || !VD_AGENT_HAS_CAPABILITY(_client_caps, _client_caps_size,
+                                                  VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) {
+        return true;
+    }
     for (VDClipboardFormat* iter = supported_clipboard_formats; iter->format && !type; iter++) {
         if (IsClipboardFormatAvailable(iter->format)) {
             type = iter->type;
@@ -815,11 +814,15 @@ bool VDAgent::on_clipboard_change()
 // handling WM_RENDERFORMAT. Therefore, we try our best by sending CLIPBOARD_REQUEST to the
 // agent, while waiting alertably for a while (hoping for good) for receiving CLIPBOARD data
 // or CLIPBOARD_RELEASE from the agent, which both will signal clipboard_event.
-bool VDAgent::on_clipboard_render(UINT format)
+bool VDAgent::on_clipboard_request(UINT format)
 {
-    uint32_t type = get_clipboard_type(format);
+    uint32_t type;
 
-    if (!type) {
+    if (!_client_caps || !VD_AGENT_HAS_CAPABILITY(_client_caps, _client_caps_size,
+                                                  VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) {
+        return true;
+    }
+    if (!(type = get_clipboard_type(format))) {
         vd_printf("Unsupported clipboard format %u", format);
         return false;
     }
@@ -1155,14 +1158,14 @@ LRESULT CALLBACK VDAgent::wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARA
         break;
     case WM_DRAWCLIPBOARD:
         if (!a->_clipboard_changer) {
-            a->on_clipboard_change();
+            a->on_clipboard_grab();
         } else {
             a->_clipboard_changer = false;
         }
         SendMessage(a->_hwnd_next_viewer, message, wparam, lparam);
         break;
     case WM_RENDERFORMAT:
-        a->on_clipboard_render((UINT)wparam);
+        a->on_clipboard_request((UINT)wparam);
         break;
     case WM_RENDERALLFORMATS:
         vd_printf("WM_RENDERALLFORMATS");
commit b5edf7c800bb4e13aa5c6ab6f41e95262a813fc1
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Wed Sep 22 08:55:03 2010 +0200

    vdservice: use "com.redhat.spice.0" symbolic link as virtio-serial port path
    
    remove get_device_path() by GUID & dependency on setupapi.lib

diff --git a/vdservice/vdi_port.cpp b/vdservice/vdi_port.cpp
index 8af95b2..e36ff86 100644
--- a/vdservice/vdi_port.cpp
+++ b/vdservice/vdi_port.cpp
@@ -15,23 +15,15 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include <windows.h>
-#include <setupapi.h>
 #include "stdio.h"
 #include "vdi_port.h"
 #include "vdlog.h"
 
-const GUID GUID_VIOSERIAL_PORT =
-    {0x6fde7521, 0x1b65, 0x48ae, 0xb6, 0x28, 0x80, 0xbe, 0x62, 0x1, 0x60, 0x26};
+#define VIOSERIAL_PORT_PATH                 L"\\\\.\\Global\\com.redhat.spice.0"
 
 // Current limitation of virtio-serial windows driver (RHBZ 617000)
 #define VIOSERIAL_PORT_MAX_WRITE_BYTES      2048
 
-// Retry initial connection to device. On boot when vdservice is started the device is
-// not immediately available (takes 2 seconds, 30 is for extreme load).
-#define VIOSERIAL_PORT_DEVICE_OPEN_MAX_RETRIES          30
-#define VIOSERIAL_PORT_DEVICE_OPEN_RETRY_INTERVAL_MS    1000
-
 #define MIN(a, b) ((a) > (b) ? (b) : (a))
 
 VDIPort* VDIPort::_singleton;
@@ -59,61 +51,9 @@ VDIPort::~VDIPort()
     }
 }
 
-//Based on device.cpp from vioserial test app
-//FIXME: remove this call & lib?
-PTCHAR get_device_path(IN LPGUID interface_guid)
-{
-    HDEVINFO dev_info;
-    SP_DEVICE_INTERFACE_DATA dev_interface;
-    PSP_DEVICE_INTERFACE_DETAIL_DATA dev_interface_detail = NULL;
-    ULONG len, req_len = 0;
-
-    dev_info = SetupDiGetClassDevs(interface_guid, NULL, NULL,
-                                   DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
-    if (dev_info == INVALID_HANDLE_VALUE) {
-        vd_printf("Cannot get class devices");
-        return NULL;
-    }
-    dev_interface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
-    if (!SetupDiEnumDeviceInterfaces(dev_info, 0, interface_guid, 0, &dev_interface)) {
-        vd_printf("Cannot get enumerate device interfaces");
-        SetupDiDestroyDeviceInfoList(dev_info);
-        return NULL;
-    }
-    SetupDiGetDeviceInterfaceDetail(dev_info, &dev_interface, NULL, 0, &req_len, NULL);
-    dev_interface_detail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LMEM_FIXED, req_len);
-    if (dev_interface_detail == NULL) {
-        vd_printf("Cannot allocate memory");
-        SetupDiDestroyDeviceInfoList(dev_info);
-        return NULL;
-    }
-    dev_interface_detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
-    len = req_len;
-    if (!SetupDiGetDeviceInterfaceDetail(dev_info, &dev_interface, dev_interface_detail, len,
-                                         &req_len, NULL)) {
-        vd_printf("Cannot get device interface details");
-        SetupDiDestroyDeviceInfoList(dev_info);
-        LocalFree(dev_interface_detail);
-        return NULL;
-    }
-    return dev_interface_detail->DevicePath;
-}
-
 bool VDIPort::init()
 {
-    PTCHAR path = NULL;
-
-    for (int retry = 0; retry < VIOSERIAL_PORT_DEVICE_OPEN_MAX_RETRIES && path == NULL; retry++) {
-        if (path = get_device_path((LPGUID)&GUID_VIOSERIAL_PORT)) {
-            break;
-        }
-        Sleep(VIOSERIAL_PORT_DEVICE_OPEN_RETRY_INTERVAL_MS);
-    }
-    if (path == NULL) {
-        vd_printf("GetDevicePath failed - device/driver missing?");
-        return false;
-    }
-    _handle = CreateFile(path, GENERIC_READ | GENERIC_WRITE , 0, NULL,
+    _handle = CreateFile(VIOSERIAL_PORT_PATH, GENERIC_READ | GENERIC_WRITE , 0, NULL,
                          OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
     if (_handle == INVALID_HANDLE_VALUE) {
         vd_printf("CreateFile() failed: %u", GetLastError());
diff --git a/vdservice/vdservice.vcproj b/vdservice/vdservice.vcproj
index f7aa4a8..e23d235 100644
--- a/vdservice/vdservice.vcproj
+++ b/vdservice/vdservice.vcproj
@@ -65,7 +65,7 @@
 			/>
 			<Tool
 				Name="VCLinkerTool"
-				AdditionalDependencies="WtsApi32.lib Userenv.lib Version.lib setupapi.lib"
+				AdditionalDependencies="WtsApi32.lib Userenv.lib Version.lib"
 				LinkIncremental="2"
 				GenerateDebugInformation="true"
 				SubSystem="1"
@@ -142,7 +142,7 @@
 			/>
 			<Tool
 				Name="VCLinkerTool"
-				AdditionalDependencies="WtsApi32.lib Userenv.lib Version.lib setupapi.lib"
+				AdditionalDependencies="WtsApi32.lib Userenv.lib Version.lib"
 				LinkIncremental="2"
 				GenerateDebugInformation="true"
 				SubSystem="1"
@@ -216,7 +216,7 @@
 			/>
 			<Tool
 				Name="VCLinkerTool"
-				AdditionalDependencies="WtsApi32.lib Userenv.lib Version.lib setupapi.lib"
+				AdditionalDependencies="WtsApi32.lib Userenv.lib Version.lib"
 				LinkIncremental="1"
 				GenerateDebugInformation="true"
 				SubSystem="1"
@@ -293,7 +293,7 @@
 			/>
 			<Tool
 				Name="VCLinkerTool"
-				AdditionalDependencies="WtsApi32.lib Userenv.lib Version.lib setupapi.lib"
+				AdditionalDependencies="WtsApi32.lib Userenv.lib Version.lib"
 				LinkIncremental="1"
 				GenerateDebugInformation="true"
 				SubSystem="1"
commit f2f2f874e1de885f9585c62742b1088f855c3df4
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Tue Sep 21 19:14:17 2010 +0200

    vd_agent: support clipboard/selection-owner model
    
    -enable the clipboard support
    -support the GRAB/REQUEST/DATA/RELEASE verbs in both ways.
    -pasting clipboard data is now "only-by-demand" from both sides (client and agent), whose behavior is symmetric.
    -client and agent don't read or send the contents of the clipboard unnecessarily (e.g. copy, internal paste, repeating paste, focus change)
    -bonus (no cost): support image cut & paste, currently only with win client

diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index 8ef1a68..5ff595f 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -20,12 +20,21 @@
 #include "display_setting.h"
 #include <lmcons.h>
 
-//#define CLIPBOARD_ENABLED
-
 #define VD_AGENT_LOG_PATH       TEXT("%svdagent.log")
 #define VD_AGENT_WINCLASS_NAME  TEXT("VDAGENT")
 #define VD_INPUT_INTERVAL_MS    20
 #define VD_TIMER_ID             1
+#define VD_CLIPBOARD_TIMEOUT_MS 10000
+
+typedef struct VDClipboardFormat {
+    uint32_t format;
+    uint32_t type;
+} VDClipboardFormat;
+
+VDClipboardFormat supported_clipboard_formats[] = {
+    {CF_UNICODETEXT, VD_AGENT_CLIPBOARD_UTF8_TEXT},
+    {CF_DIB, VD_AGENT_CLIPBOARD_BITMAP},
+    {0, 0}};
 
 class VDAgent {
 public:
@@ -37,13 +46,17 @@ private:
     VDAgent();
     void input_desktop_message_loop();
     bool handle_mouse_event(VDAgentMouseState* state);
-    bool handle_announce_capabilities(
-        VDAgentAnnounceCapabilities* announce_capabilities, uint32_t msg_size);
+    bool handle_announce_capabilities(VDAgentAnnounceCapabilities* announce_capabilities,
+                                      uint32_t msg_size);
     bool handle_mon_config(VDAgentMonitorsConfig* mon_config, uint32_t port);
     bool handle_clipboard(VDAgentClipboard* clipboard, uint32_t size);
+    bool handle_clipboard_grab(VDAgentClipboardGrab* clipboard_grab);
+    bool handle_clipboard_request(VDAgentClipboardRequest* clipboard_request);
+    bool handle_clipboard_release();
     bool handle_display_config(VDAgentDisplayConfig* display_config, uint32_t port);
     bool handle_control(VDPipeMessage* msg);
     bool on_clipboard_change();
+    bool on_clipboard_render(UINT format);
     DWORD get_buttons_change(DWORD last_buttons_state, DWORD new_buttons_state,
                              DWORD mask, DWORD down_flag, DWORD up_flag);
     static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
@@ -51,14 +64,18 @@ private:
     static VOID CALLBACK write_completion(DWORD err, DWORD bytes, LPOVERLAPPED overlap);
     static DWORD WINAPI event_thread_proc(LPVOID param);
     static void dispatch_message(VDAgentMessage* msg, uint32_t port);
+    static uint32_t get_clipboard_format(uint32_t type);
+    static uint32_t get_clipboard_type(uint32_t format);
     uint8_t* write_lock(DWORD bytes = 0);
     void write_unlock(DWORD bytes = 0);
+    bool write_message(uint32_t type, uint32_t size, void* data);
     bool write_clipboard();
     bool connect_pipe();
     bool send_input();
     void set_display_depth(uint32_t depth);
     void load_display_setting();
     bool send_announce_capabilities(bool request);
+    void cleanup();
 
 private:
     static VDAgent* _singleton;
@@ -71,6 +88,7 @@ private:
     INPUT _input;
     DWORD _input_time;
     HANDLE _desktop_switch_event;
+    HANDLE _clipboard_event;
     VDAgentMessage* _in_msg;
     uint32_t _in_msg_pos;
     VDAgentMessage* _out_msg;
@@ -107,11 +125,13 @@ VDAgent* VDAgent::get()
 VDAgent::VDAgent()
     : _hwnd (NULL)
     , _hwnd_next_viewer (NULL)
-    , _clipboard_changer (false)
+    , _clipboard_changer (true)
     , _buttons_state (0)
     , _mouse_x (0)
     , _mouse_y (0)
     , _input_time (0)
+    , _desktop_switch_event (NULL)
+    , _clipboard_event (NULL)
     , _in_msg (NULL)
     , _in_msg_pos (0)
     , _out_msg (NULL)
@@ -189,8 +209,10 @@ bool VDAgent::run()
         vd_printf("SetProcessShutdownParameters failed %u", GetLastError());
     }
     _desktop_switch_event = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (!_desktop_switch_event) {
+    _clipboard_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (!_desktop_switch_event || !_clipboard_event) {
         vd_printf("CreateEvent() failed: %d", GetLastError());
+        cleanup();
         return false;
     }
     memset(&wcls, 0, sizeof(wcls));
@@ -198,6 +220,7 @@ bool VDAgent::run()
     wcls.lpszClassName = VD_AGENT_WINCLASS_NAME;
     if (!RegisterClass(&wcls)) {
         vd_printf("RegisterClass() failed: %d", GetLastError());
+        cleanup();
         return false;
     }
     _desktop_layout = new DesktopLayout();
@@ -205,8 +228,7 @@ bool VDAgent::run()
         vd_printf("No QXL devices!");
     }
     if (!connect_pipe()) {
-        CloseHandle(_desktop_switch_event);
-        delete _desktop_layout;
+        cleanup();
         return false;
     }
     _running = true;
@@ -214,9 +236,7 @@ bool VDAgent::run()
         &event_thread_id);
     if (!event_thread) {
         vd_printf("CreateThread() failed: %d", GetLastError());
-        CloseHandle(_desktop_switch_event);
-        CloseHandle(_pipe_state.pipe);
-        delete _desktop_layout;
+        cleanup();
         return false;
     }
     send_announce_capabilities(true);
@@ -226,10 +246,16 @@ bool VDAgent::run()
     }
     vd_printf("Agent stopped");
     CloseHandle(event_thread);
+    cleanup();
+    return true;
+}
+
+void VDAgent::cleanup()
+{
     CloseHandle(_desktop_switch_event);
+    CloseHandle(_clipboard_event);
     CloseHandle(_pipe_state.pipe);
     delete _desktop_layout;
-    return true;
 }
 
 void VDAgent::input_desktop_message_loop()
@@ -466,44 +492,66 @@ bool VDAgent::handle_mon_config(VDAgentMonitorsConfig* mon_config, uint32_t port
     return true;
 }
 
-//FIXME: currently supports text only
 bool VDAgent::handle_clipboard(VDAgentClipboard* clipboard, uint32_t size)
 {
     HGLOBAL clip_data;
     LPVOID clip_buf;
     int clip_size;
+    int clip_len;
     UINT format;
-    bool ret;
+    bool ret = false;
 
-    switch (clipboard->type) {
-    case VD_AGENT_CLIPBOARD_UTF8_TEXT:
-        format = CF_UNICODETEXT;
+    // Get the required clipboard size
+    switch (format = get_clipboard_format(clipboard->type)) {
+    case CF_UNICODETEXT:
+        // Received utf8 string is not null-terminated   
+        if (!(clip_len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)clipboard->data, size, NULL, 0))) {
+            return false;
+        }
+        clip_len++;
+        clip_size = clip_len * sizeof(WCHAR);
+        break;
+    case CF_DIB:
+        clip_size = size;
         break;
     default:
         vd_printf("Unsupported clipboard type %u", clipboard->type);
         return false;
     }
-    if (!OpenClipboard(_hwnd)) {
-        return false;
-    }
-    clip_size = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)clipboard->data, -1, NULL, 0);
-    if (!clip_size || !(clip_data = GlobalAlloc(GMEM_DDESHARE, clip_size * sizeof(WCHAR)))) {
-        CloseClipboard();
+    // Allocate and lock clipboard memory
+    if (!(clip_data = GlobalAlloc(GMEM_DDESHARE, clip_size))) {
         return false;
     }
     if (!(clip_buf = GlobalLock(clip_data))) {
         GlobalFree(clip_data);
-        CloseClipboard();
         return false;
     }
-    ret = !!MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)clipboard->data, -1, (LPWSTR)clip_buf, clip_size);
+    // Translate data and set clipboard content
+    switch (format) {
+    case CF_UNICODETEXT:
+        ret = !!MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)clipboard->data, size, (LPWSTR)clip_buf,
+                                    clip_len);
+        ((LPWSTR)clip_buf)[clip_len - 1] = L'\0';
+        break;
+    case CF_DIB:
+        memcpy(clip_buf, clipboard->data, size);
+        ret = true;
+        break;
+    }
     GlobalUnlock(clip_data);
-    if (ret) {
-        EmptyClipboard();
-        //FIXME: nicify (compare clip_data)
-        _clipboard_changer = true;
-        ret = !!SetClipboardData(format, clip_data);
+    if (!ret) {
+        return false;
     }
+    if (SetClipboardData(format, clip_data)) {
+        SetEvent(_clipboard_event);
+        return true;
+    }
+    // We retry clipboard open-empty-set-close only when there is a timeout in on_clipboard_render()
+    if (!OpenClipboard(_hwnd)) {
+        return false;
+    }
+    EmptyClipboard();
+    ret = !!SetClipboardData(format, clip_data);
     CloseClipboard();
     return ret;
 }
@@ -526,7 +574,6 @@ void VDAgent::set_display_depth(uint32_t depth)
     }
 }
 
-
 void VDAgent::load_display_setting()
 {
     _display_setting.load();
@@ -562,9 +609,7 @@ bool VDAgent::send_announce_capabilities(bool request)
     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_MOUSE_STATE);
     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_MONITORS_CONFIG);
     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_REPLY);
-#ifdef CLIPBOARD_ENABLED
     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD);
-#endif
     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_DISPLAY_CONFIG);
     vd_printf("sending capabilities:");
     for (uint32_t i = 0 ; i < caps_size; ++i) {
@@ -694,7 +739,6 @@ bool VDAgent::handle_control(VDPipeMessage* msg)
 
 #define MIN(a, b) ((a) > (b) ? (b) : (a))
 
-//FIXME: cleanup
 //FIXME: division to max size chunks should NOT be here, but in the service
 //       here we should write the max possible size to the pipe
 bool VDAgent::write_clipboard()
@@ -706,8 +750,7 @@ bool VDAgent::write_clipboard()
         return false;
     }
     pipe_msg->type = VD_AGENT_COMMAND;
-    //FIXME: client port should be in vd_agent.h
-    pipe_msg->opaque = 1;
+    pipe_msg->opaque = VDP_CLIENT_PORT;
     pipe_msg->size = n - sizeof(VDPipeMessage);
     memcpy(pipe_msg->data, (char*)_out_msg + _out_msg_pos, n - sizeof(VDPipeMessage));
     write_unlock(n);
@@ -724,14 +767,102 @@ bool VDAgent::write_clipboard()
     return true;
 }
 
-//FIXME: currently supports text only
+bool VDAgent::write_message(uint32_t type, uint32_t size = 0, void* data = NULL)
+{
+    VDPipeMessage* pipe_msg;
+    VDAgentMessage* msg;
+
+    pipe_msg = (VDPipeMessage*)write_lock(VD_MESSAGE_HEADER_SIZE + size);
+    if (!pipe_msg) {
+        return false;
+    }
+    pipe_msg->type = VD_AGENT_COMMAND;
+    pipe_msg->opaque = VDP_CLIENT_PORT;
+    pipe_msg->size = sizeof(VDAgentMessage) + size;
+    msg = (VDAgentMessage*)pipe_msg->data;
+    msg->protocol = VD_AGENT_PROTOCOL;
+    msg->type = type;
+    msg->opaque = 0;
+    msg->size = size;
+    if (size && data) {
+        memcpy(msg->data, data, size);
+    }
+    write_unlock(VD_MESSAGE_HEADER_SIZE + size);
+    if (!_pending_write) {
+        write_completion(0, 0, &_pipe_state.write.overlap);
+    }
+    return true;
+}
+
 bool VDAgent::on_clipboard_change()
 {
-    UINT format = CF_UNICODETEXT;
+    uint32_t type = 0;
+
+    for (VDClipboardFormat* iter = supported_clipboard_formats; iter->format && !type; iter++) {
+        if (IsClipboardFormatAvailable(iter->format)) {
+            type = iter->type;
+        }
+    }
+    if (!type) {
+        vd_printf("Unsupported clipboard format");
+        return false;
+    }
+    VDAgentClipboardGrab grab = {type};
+    return write_message(VD_AGENT_CLIPBOARD_GRAB, sizeof(grab), &grab);  
+}
+
+// In delayed rendering, Windows requires us to SetClipboardData before we return from
+// handling WM_RENDERFORMAT. Therefore, we try our best by sending CLIPBOARD_REQUEST to the
+// agent, while waiting alertably for a while (hoping for good) for receiving CLIPBOARD data
+// or CLIPBOARD_RELEASE from the agent, which both will signal clipboard_event.
+bool VDAgent::on_clipboard_render(UINT format)
+{
+    uint32_t type = get_clipboard_type(format);
+
+    if (!type) {
+        vd_printf("Unsupported clipboard format %u", format);
+        return false;
+    }
+    VDAgentClipboardRequest request = {type};
+    if (!write_message(VD_AGENT_CLIPBOARD_REQUEST, sizeof(request), &request)) {
+        return false;
+    }
+    DWORD start_tick = GetTickCount();
+    while (WaitForSingleObjectEx(_clipboard_event, 1000, TRUE) != WAIT_OBJECT_0 &&
+           GetTickCount() < start_tick + VD_CLIPBOARD_TIMEOUT_MS);
+    return true;
+}
+
+bool VDAgent::handle_clipboard_grab(VDAgentClipboardGrab* clipboard_grab)
+{
+    uint32_t format = get_clipboard_format(clipboard_grab->type);
+
+    if (!format) {
+        vd_printf("Unsupported clipboard type %u", clipboard_grab->type);
+        return false;
+    }
+    if (!OpenClipboard(_hwnd)) {
+        return false;
+    }
+    _clipboard_changer = true;
+    EmptyClipboard();
+    SetClipboardData(format, NULL);
+    CloseClipboard();
+    return true;
+}
+
+bool VDAgent::handle_clipboard_request(VDAgentClipboardRequest* clipboard_request)
+{
+    UINT format;
     HANDLE clip_data;
     LPVOID clip_buf;
     int clip_size;
+    size_t len;
 
+    if (!(format = get_clipboard_format(clipboard_request->type))) {
+        vd_printf("Unsupported clipboard type %u", clipboard_request->type);
+        return false;
+    }
     if (_out_msg) {
         vd_printf("clipboard change is already pending");
         return false;
@@ -743,7 +874,16 @@ bool VDAgent::on_clipboard_change()
         CloseClipboard();
         return false;
     }
-    clip_size = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)clip_buf, -1, NULL, 0, NULL, NULL);
+    switch (format) {
+    case CF_UNICODETEXT:
+        len = wcslen((wchar_t*)clip_buf);
+        clip_size = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)clip_buf, (int)len, NULL, 0, NULL, NULL);
+        break;
+    case CF_DIB:
+        clip_size = (int)GlobalSize(clip_data);
+        break;
+    }
+
     if (!clip_size) {
         GlobalUnlock(clip_data);
         CloseClipboard();
@@ -757,11 +897,48 @@ bool VDAgent::on_clipboard_change()
     _out_msg->opaque = 0;
     _out_msg->size = (uint32_t)(sizeof(VDAgentClipboard) + clip_size);
     VDAgentClipboard* clipboard = (VDAgentClipboard*)_out_msg->data;
-    clipboard->type = VD_AGENT_CLIPBOARD_UTF8_TEXT;
-    WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)clip_buf, -1, (LPSTR)clipboard->data, clip_size, NULL, NULL);
+    clipboard->type = clipboard_request->type;
+
+    switch (format) {
+    case CF_UNICODETEXT:
+        WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)clip_buf, (int)len, (LPSTR)clipboard->data,
+                            clip_size, NULL, NULL);
+        break;
+    case CF_DIB:
+        memcpy(clipboard->data, clip_buf, clip_size);
+        break;
+    }
+
     GlobalUnlock(clip_data);
     CloseClipboard();
-    return write_clipboard();
+    write_clipboard();
+    return true;
+}
+
+bool VDAgent::handle_clipboard_release()
+{
+    SetEvent(_clipboard_event);
+    return true;
+}
+
+uint32_t VDAgent::get_clipboard_format(uint32_t type)
+{
+    for (VDClipboardFormat* iter = supported_clipboard_formats; iter->format && iter->type; iter++) {
+        if (iter->type == type) {
+            return iter->format;
+        }
+    }
+    return 0;
+}
+
+uint32_t VDAgent::get_clipboard_type(uint32_t format)
+{
+    for (VDClipboardFormat* iter = supported_clipboard_formats; iter->format && iter->type; iter++) {
+        if (iter->format == format) {
+            return iter->type;
+        }
+    }
+    return 0;
 }
 
 bool VDAgent::connect_pipe()
@@ -791,48 +968,48 @@ bool VDAgent::connect_pipe()
     vd_printf("Connected to service pipe");
     return true;
 }
+
 void VDAgent::dispatch_message(VDAgentMessage* msg, uint32_t port)
 {
     VDAgent* a = _singleton;
+    bool res = true;
 
     switch (msg->type) {
     case VD_AGENT_MOUSE_STATE:
-        if (!a->handle_mouse_event((VDAgentMouseState*)msg->data)) {
-            vd_printf("handle_mouse_event failed: %u", GetLastError());
-            a->_running = false;
-        }
+        res = a->handle_mouse_event((VDAgentMouseState*)msg->data);
         break;
     case VD_AGENT_MONITORS_CONFIG:
-        if (!a->handle_mon_config((VDAgentMonitorsConfig*)msg->data, port)) {
-            vd_printf("handle_mon_config failed: %u", GetLastError());
-            a->_running = false;
-        }
+        res = a->handle_mon_config((VDAgentMonitorsConfig*)msg->data, port);
         break;
-#ifdef CLIPBOARD_ENABLED
     case VD_AGENT_CLIPBOARD:
-        if (!a->handle_clipboard((VDAgentClipboard*)msg->data,
-                                 msg->size - sizeof(VDAgentClipboard))) {
-            vd_printf("handle_clipboard failed: %u", GetLastError());
-            a->_running = false;
+        res = a->handle_clipboard((VDAgentClipboard*)msg->data,
+                                  msg->size - sizeof(VDAgentClipboard));
+        break;
+    case VD_AGENT_CLIPBOARD_GRAB:
+        res = a->handle_clipboard_grab((VDAgentClipboardGrab*)msg->data);
+        break;
+    case VD_AGENT_CLIPBOARD_REQUEST:
+        res = a->handle_clipboard_request((VDAgentClipboardRequest*)msg->data);
+        if (!res) {
+            res = a->write_message(VD_AGENT_CLIPBOARD_RELEASE);
         }
         break;
-#endif // CLIPBOARD_ENABLED
+    case VD_AGENT_CLIPBOARD_RELEASE:
+        res = a->handle_clipboard_release();
+        break;
     case VD_AGENT_DISPLAY_CONFIG:
-        if (!a->handle_display_config((VDAgentDisplayConfig*)msg->data, port)) {
-            vd_printf("handle_display_config failed");
-            a->_running = false;
-        }
+        res = a->handle_display_config((VDAgentDisplayConfig*)msg->data, port);
         break;
     case VD_AGENT_ANNOUNCE_CAPABILITIES:
-        if (!a->handle_announce_capabilities((VDAgentAnnounceCapabilities*)msg->data,
-                msg->size)) {
-            vd_printf("handle_announce_capabilities failed");
-            a->_running = false;
-        }
+        res = a->handle_announce_capabilities((VDAgentAnnounceCapabilities*)msg->data, msg->size);
         break;
     default:
         vd_printf("Unsupported message type %u size %u", msg->type, msg->size);
     }
+    if (!res) {
+        vd_printf("handling message type %u failed: %u", msg->type, GetLastError());
+        a->_running = false;
+    }
 }
 
 VOID CALLBACK VDAgent::read_completion(DWORD err, DWORD bytes, LPOVERLAPPED overlap)
@@ -862,8 +1039,8 @@ VOID CALLBACK VDAgent::read_completion(DWORD err, DWORD bytes, LPOVERLAPPED over
             break;
         }
 
-        //FIXME: cleanup, specific to one port
-        if (a->_in_msg_pos == 0 || pipe_msg->opaque == 2 /*FIXME!*/) {
+        //FIXME: currently assumes that multi-part msg arrives only from client port
+        if (a->_in_msg_pos == 0 || pipe_msg->opaque == VDP_SERVER_PORT) {
             if (len < VD_MESSAGE_HEADER_SIZE) {
                 break;
             }
@@ -885,7 +1062,6 @@ VOID CALLBACK VDAgent::read_completion(DWORD err, DWORD bytes, LPOVERLAPPED over
         } else {
             memcpy((uint8_t*)a->_in_msg + a->_in_msg_pos, pipe_msg->data, pipe_msg->size);
             a->_in_msg_pos += pipe_msg->size;
-            //vd_printf("DEBUG: pipe_msg size %u pos %u total %u", pipe_msg->size, a->_in_msg_pos, sizeof(VDAgentMessage) + a->_in_msg->size);
             if (a->_in_msg_pos == sizeof(VDAgentMessage) + a->_in_msg->size) {
                 dispatch_message(a->_in_msg, 0);
                 a->_in_msg_pos = 0;
@@ -970,7 +1146,6 @@ LRESULT CALLBACK VDAgent::wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARA
     case WM_TIMER:
         a->send_input();
         break;
-#ifdef CLIPBOARD_ENABLED
     case WM_CHANGECBCHAIN:
         if (a->_hwnd_next_viewer == (HWND)wparam) {
             a->_hwnd_next_viewer = (HWND)lparam;
@@ -986,7 +1161,15 @@ LRESULT CALLBACK VDAgent::wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARA
         }
         SendMessage(a->_hwnd_next_viewer, message, wparam, lparam);
         break;
-#endif // CLIPBOARD_ENABLED
+    case WM_RENDERFORMAT:
+        a->on_clipboard_render((UINT)wparam);
+        break;
+    case WM_RENDERALLFORMATS:
+        vd_printf("WM_RENDERALLFORMATS");
+        break;
+    case WM_DESTROYCLIPBOARD:
+        vd_printf("WM_DESTROYCLIPBOARD");
+        break;
     default:
         return DefWindowProc(hwnd, message, wparam, lparam);
     }
commit d3154e89a29a335acd99e588e306656ac72101fd
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Tue Sep 21 19:03:09 2010 +0200

    vdservice: replace VDAgentDataChunk with VDIChunkHeader

diff --git a/vdservice/vdi_port.cpp b/vdservice/vdi_port.cpp
index 0d5c0e1..8af95b2 100644
--- a/vdservice/vdi_port.cpp
+++ b/vdservice/vdi_port.cpp
@@ -91,7 +91,7 @@ PTCHAR get_device_path(IN LPGUID interface_guid)
     len = req_len;
     if (!SetupDiGetDeviceInterfaceDetail(dev_info, &dev_interface, dev_interface_detail, len,
                                          &req_len, NULL)) {
-        vd_printf("Cannot get device interface details.\n");
+        vd_printf("Cannot get device interface details");
         SetupDiDestroyDeviceInfoList(dev_info);
         LocalFree(dev_interface_detail);
         return NULL;
diff --git a/vdservice/vdservice.cpp b/vdservice/vdservice.cpp
index 8cd485e..1e63694 100644
--- a/vdservice/vdservice.cpp
+++ b/vdservice/vdservice.cpp
@@ -411,12 +411,6 @@ VOID WINAPI VDService::main(DWORD argc, TCHAR* argv[])
 #endif //DEBUG_VDSERVICE
 }
 
-typedef __declspec (align(1)) struct VDAgentDataChunk {
-    uint32_t port;
-    uint32_t size;
-    uint8_t data[0];
-} VDAgentDataChunk;
-
 bool VDService::execute()
 {
     SECURITY_ATTRIBUTES sec_attr;
@@ -1006,12 +1000,12 @@ void VDService::handle_pipe_data(DWORD bytes)
         if (read_size < sizeof(VDPipeMessage) + pipe_msg->size) {
             break;
         }
-        if (_vdi_port->write_ring_free_space() < sizeof(VDAgentDataChunk) + pipe_msg->size) {
+        if (_vdi_port->write_ring_free_space() < sizeof(VDIChunkHeader) + pipe_msg->size) {
             //vd_printf("DEBUG: no space in write ring %u", _vdi_port->write_ring_free_space());
             break;
         }
         if (!_pending_reset) {
-            VDAgentDataChunk chunk;
+            VDIChunkHeader chunk;
             chunk.port = pipe_msg->opaque;
             chunk.size = pipe_msg->size;
             if (_vdi_port->ring_write(&chunk, sizeof(chunk)) != sizeof(chunk) ||
@@ -1035,7 +1029,7 @@ void VDService::handle_pipe_data(DWORD bytes)
 void VDService::handle_port_data()
 {
     VDPipeMessage* pipe_msg;
-    VDAgentDataChunk chunk;
+    VDIChunkHeader chunk;
     int chunks_count = 0;
     DWORD count = 0;
 
commit abf69059834b15bd82f78a5ecbc82e8422e040e8
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Tue Sep 21 19:00:05 2010 +0200

    vdservice: cleanup vcprojs
    
    -remove deprecated Detect64BitPortabilityProblems
    -add setupapi.lib to AdditionalDependencies in x64

diff --git a/vdagent/vdagent.vcproj b/vdagent/vdagent.vcproj
index 2c91185..ec703a5 100644
--- a/vdagent/vdagent.vcproj
+++ b/vdagent/vdagent.vcproj
@@ -327,163 +327,6 @@
 				Name="VCPostBuildEventTool"
 			/>
 		</Configuration>
-		<Configuration
-			Name="Debug|x64"
-			OutputDirectory="$(PlatformName)\$(ConfigurationName)"
-			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
-			ConfigurationType="1"
-			CharacterSet="1"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-				TargetEnvironment="3"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				Optimization="0"
-				AdditionalIncludeDirectories="..\common;$(SPICE_COMMON_DIR)"
-				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS,_WIN32_WINNT=0x0501"
-				MinimalRebuild="true"
-				BasicRuntimeChecks="3"
-				RuntimeLibrary="1"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="3"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				AdditionalDependencies="Version.lib"
-				LinkIncremental="2"
-				GenerateDebugInformation="true"
-				SubSystem="2"
-				TargetMachine="17"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCWebDeploymentTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-		<Configuration
-			Name="Release|x64"
-			OutputDirectory="$(PlatformName)\$(ConfigurationName)"
-			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
-			ConfigurationType="1"
-			CharacterSet="1"
-			WholeProgramOptimization="1"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-				TargetEnvironment="3"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				AdditionalIncludeDirectories="..\common;$(SPICE_COMMON_DIR)"
-				AdditionalUsingDirectories=""
-				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS,_WIN32_WINNT=0x0501"
-				RuntimeLibrary="0"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="3"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				AdditionalDependencies="Version.lib"
-				LinkIncremental="1"
-				GenerateDebugInformation="true"
-				SubSystem="2"
-				OptimizeReferences="2"
-				EnableCOMDATFolding="2"
-				TargetMachine="17"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCWebDeploymentTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
 	</Configurations>
 	<References>
 	</References>
diff --git a/vdservice/vdservice.vcproj b/vdservice/vdservice.vcproj
index 61fbedc..f7aa4a8 100644
--- a/vdservice/vdservice.vcproj
+++ b/vdservice/vdservice.vcproj
@@ -142,7 +142,7 @@
 			/>
 			<Tool
 				Name="VCLinkerTool"
-				AdditionalDependencies="WtsApi32.lib Userenv.lib Version.lib"
+				AdditionalDependencies="WtsApi32.lib Userenv.lib Version.lib setupapi.lib"
 				LinkIncremental="2"
 				GenerateDebugInformation="true"
 				SubSystem="1"
@@ -293,7 +293,7 @@
 			/>
 			<Tool
 				Name="VCLinkerTool"
-				AdditionalDependencies="WtsApi32.lib Userenv.lib Version.lib"
+				AdditionalDependencies="WtsApi32.lib Userenv.lib Version.lib setupapi.lib"
 				LinkIncremental="1"
 				GenerateDebugInformation="true"
 				SubSystem="1"
@@ -325,162 +325,6 @@
 				Name="VCPostBuildEventTool"
 			/>
 		</Configuration>
-		<Configuration
-			Name="Debug|x64"
-			OutputDirectory="$(PlatformName)\$(ConfigurationName)"
-			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
-			ConfigurationType="1"
-			CharacterSet="1"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-				TargetEnvironment="3"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				Optimization="0"
-				AdditionalIncludeDirectories="..\common;$(SPICE_COMMON_DIR)"
-				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE,_WIN32_WINNT=0x0501"
-				MinimalRebuild="true"
-				BasicRuntimeChecks="3"
-				RuntimeLibrary="1"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="3"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				AdditionalDependencies="WtsApi32.lib Userenv.lib Version.lib"
-				LinkIncremental="2"
-				GenerateDebugInformation="true"
-				SubSystem="1"
-				TargetMachine="17"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCWebDeploymentTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-		<Configuration
-			Name="Release|x64"
-			OutputDirectory="$(PlatformName)\$(ConfigurationName)"
-			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
-			ConfigurationType="1"
-			CharacterSet="1"
-			WholeProgramOptimization="1"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-				TargetEnvironment="3"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				AdditionalIncludeDirectories="..\common;$(SPICE_COMMON_DIR)"
-				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE,_WIN32_WINNT=0x0501"
-				RuntimeLibrary="0"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="3"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				AdditionalDependencies="WtsApi32.lib Userenv.lib Version.lib"
-				LinkIncremental="1"
-				GenerateDebugInformation="true"
-				SubSystem="1"
-				OptimizeReferences="2"
-				EnableCOMDATFolding="2"
-				TargetMachine="17"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCWebDeploymentTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
 	</Configurations>
 	<References>
 	</References>


More information about the Spice-commits mailing list