[Spice-commits] 6 commits - common/vdcommon.cpp common/vdcommon.h vdagent_helper/vdagent_helper.cpp vdagent_helper/vdagent_helper.vcproj vdagent.sln vdagent/vdagent.cpp vdagent/vdagent.vcproj vdservice/vdservice.cpp vdservice/vdservice.vcproj

Arnon Gilboa agilboa at kemper.freedesktop.org
Mon Mar 18 08:11:31 PDT 2013


 common/vdcommon.cpp                  |   36 +++
 common/vdcommon.h                    |    9 
 vdagent.sln                          |   10 
 vdagent/vdagent.cpp                  |  130 ++++++++++--
 vdagent/vdagent.vcproj               |    4 
 vdagent_helper/vdagent_helper.cpp    |   46 ++++
 vdagent_helper/vdagent_helper.vcproj |  363 +++++++++++++++++++++++++++++++++++
 vdservice/vdservice.cpp              |   24 --
 vdservice/vdservice.vcproj           |    4 
 9 files changed, 582 insertions(+), 44 deletions(-)

New commits:
commit dd9d1f41cace5e73bfd847ff8d0cfa303e141b1c
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Mon Mar 18 15:38:20 2013 +0200

    vdagent: add vdagent_helper to support mouse when UAC dialog takes focus
    
    Running the helper with ShellExecute(..."runas"...) is the way to SendInput()
    to the UAC dialog in Windows Vista and above.
    
    http://stackoverflow.com/questions/2426594/starting-a-uac-elevated-process-
    from-a-non-interactive-service-win32-net-power
    
    http://www.microsoft-questions.com/microsoft/Platform-SDK-Security/29620442/
    how-to-proper-use-sendinput-to-a-elevated-window-from-a-service.aspx
    
    rhbz #908422

diff --git a/common/vdcommon.h b/common/vdcommon.h
index 177721c..5099fdc 100644
--- a/common/vdcommon.h
+++ b/common/vdcommon.h
@@ -34,6 +34,7 @@ typedef CRITICAL_SECTION mutex_t;
 
 #define VD_AGENT_REGISTRY_KEY "SOFTWARE\\Red Hat\\Spice\\vdagent\\"
 #define VD_AGENT_STOP_EVENT   TEXT("Global\\vdagent_stop_event")
+#define VD_AGENT_NAMED_PIPE   TEXT("\\\\.\\pipe\\vdagent")
 
 #if defined __GNUC__
 #define ALIGN_GCC __attribute__ ((packed))
diff --git a/vdagent.sln b/vdagent.sln
index 2622f2e..0848ced 100644
--- a/vdagent.sln
+++ b/vdagent.sln
@@ -5,6 +5,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vdagent", "vdagent\vdagent.
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vdservice", "vdservice\vdservice.vcproj", "{ADFE5E22-31D0-4343-AE9E-8102CC0051F9}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vdagent_helper", "vdagent_helper\vdagent_helper.vcproj", "{3E459EA7-0252-48E0-A92B-13A66F5F370B}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Win32 = Debug|Win32
@@ -29,6 +31,14 @@ Global
 		{ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Release|Win32.Build.0 = Release|Win32
 		{ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Release|x64.ActiveCfg = Release|x64
 		{ADFE5E22-31D0-4343-AE9E-8102CC0051F9}.Release|x64.Build.0 = Release|x64
+		{3E459EA7-0252-48E0-A92B-13A66F5F370B}.Debug|Win32.ActiveCfg = Debug|Win32
+		{3E459EA7-0252-48E0-A92B-13A66F5F370B}.Debug|Win32.Build.0 = Debug|Win32
+		{3E459EA7-0252-48E0-A92B-13A66F5F370B}.Debug|x64.ActiveCfg = Debug|x64
+		{3E459EA7-0252-48E0-A92B-13A66F5F370B}.Debug|x64.Build.0 = Debug|x64
+		{3E459EA7-0252-48E0-A92B-13A66F5F370B}.Release|Win32.ActiveCfg = Release|Win32
+		{3E459EA7-0252-48E0-A92B-13A66F5F370B}.Release|Win32.Build.0 = Release|Win32
+		{3E459EA7-0252-48E0-A92B-13A66F5F370B}.Release|x64.ActiveCfg = Release|x64
+		{3E459EA7-0252-48E0-A92B-13A66F5F370B}.Release|x64.Build.0 = Release|x64
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index f254d55..24fe1f7 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -111,6 +111,7 @@ private:
     bool write_message(uint32_t type, uint32_t size, void* data);
     bool write_clipboard(VDAgentMessage* msg, uint32_t size);
     bool init_vio_serial();
+    bool launch_helper();
     bool send_input();
     void set_display_depth(uint32_t depth);
     void load_display_setting();
@@ -133,6 +134,7 @@ private:
     ULONG _mouse_y;
     INPUT _input;
     DWORD _input_time;
+    HANDLE _helper_pipe;
     HANDLE _control_event;
     HANDLE _stop_event;
     VDAgentMessage* _in_msg;
@@ -189,6 +191,7 @@ VDAgent::VDAgent()
     , _mouse_x (0)
     , _mouse_y (0)
     , _input_time (0)
+    , _helper_pipe (NULL)
     , _control_event (NULL)
     , _stop_event (NULL)
     , _in_msg (NULL)
@@ -287,6 +290,10 @@ bool VDAgent::run()
             cleanup();
             return false;
         }
+        if (!launch_helper()) {
+            cleanup();
+            return false;
+        }
     }
     _control_event = CreateEvent(NULL, FALSE, FALSE, NULL);
     if (!_control_event) {
@@ -342,6 +349,7 @@ bool VDAgent::run()
 void VDAgent::cleanup()
 {
     FreeLibrary(_user_lib);
+    CloseHandle(_helper_pipe);
     CloseHandle(_stop_event);
     CloseHandle(_control_event);
     CloseHandle(_vio_serial);
@@ -393,6 +401,37 @@ void VDAgent::handle_control_event()
     MUTEX_UNLOCK(_control_mutex);
 }
 
+bool VDAgent::launch_helper()
+{
+    HINSTANCE helper;
+    TCHAR helper_path[MAX_PATH];
+    TCHAR* slash;
+
+    if (!GetModuleFileName(NULL, helper_path, MAX_PATH) ||
+              !(slash = wcsrchr(helper_path, TCHAR('\\')))) {
+        vd_printf("Cannot get file path: %lu", GetLastError());
+    }
+    wcscpy(slash + 1, L"vdagent_helper.exe");
+    helper = ShellExecute(NULL, L"runas", helper_path, NULL, NULL, SW_HIDE);
+    if (helper <= (HINSTANCE)32) {
+        vd_printf("ShellExecute: %lu", helper);
+        return false;
+    }
+    _helper_pipe = CreateNamedPipe(VD_AGENT_NAMED_PIPE, PIPE_ACCESS_OUTBOUND,
+                                   PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+                                   1, 1024, 1024, 0, NULL);
+    if (_helper_pipe == INVALID_HANDLE_VALUE) {
+        vd_printf("CreateNamedPipe() failed: %lu", GetLastError());
+        return false;
+    }
+    if (!ConnectNamedPipe(_helper_pipe, NULL) && GetLastError() != ERROR_PIPE_CONNECTED) {
+        vd_printf("ConnectNamedPipe() failed: %lu", GetLastError());
+        CloseHandle(_helper_pipe);
+        return false;
+    }
+    return true;
+}
+
 void VDAgent::input_desktop_message_loop()
 {
     TCHAR desktop_name[MAX_PATH];
@@ -511,6 +550,8 @@ DWORD VDAgent::get_buttons_change(DWORD last_buttons_state, DWORD new_buttons_st
 bool VDAgent::send_input()
 {
     bool ret = true;
+    DWORD bytes;
+
     _desktop_layout->lock();
     if (_pending_input) {
         if (KillTimer(_hwnd, VD_TIMER_ID)) {
@@ -522,7 +563,14 @@ bool VDAgent::send_input()
             return false;
         }
     }
-    if (!SendInput(1, &_input, sizeof(INPUT))) {
+
+    if (_system_version == SYS_VER_WIN_7_CLASS) {
+        if (!WriteFile(_helper_pipe, &_input, sizeof(_input), &bytes, NULL) ||
+                sizeof(_input) != bytes) {
+            vd_printf("Write to pipe failed: %lu", GetLastError());
+            ret = _running = false;
+        }
+    } else if (!SendInput(1, &_input, sizeof(INPUT))) {
         DWORD err = GetLastError();
         // Don't stop agent due to UIPI blocking, which is usually only for specific windows
         // of system security applications (anti-viruses etc.)
@@ -531,6 +579,7 @@ bool VDAgent::send_input()
             ret = _running = false;
         }
     }
+
     _input_time = GetTickCount();
     _desktop_layout->unlock();
     return ret;
diff --git a/vdagent_helper/vdagent_helper.cpp b/vdagent_helper/vdagent_helper.cpp
new file mode 100644
index 0000000..ebeb77b
--- /dev/null
+++ b/vdagent_helper/vdagent_helper.cpp
@@ -0,0 +1,46 @@
+#include <windows.h>
+#include <stdio.h>
+#include <vdlog.h>
+
+int main(int argc,char **argv)
+{
+    TCHAR log_path[MAX_PATH];
+    HANDLE pipe;
+    INPUT input;
+    HDESK hdesk;
+    DWORD bytes;
+    DWORD err = 0;
+    VDLog* log;
+
+    if (GetTempPath(MAX_PATH, log_path)) {
+        wcscat(log_path, L"vdagent_helper.log");
+        log = VDLog::get(log_path);
+    }
+    vd_printf("***vdagent_helper started***");
+    pipe = CreateFile(VD_AGENT_NAMED_PIPE, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+    if (pipe == INVALID_HANDLE_VALUE) {
+        vd_printf("Cannot open pipe %S: %lu", VD_AGENT_NAMED_PIPE, GetLastError());
+        goto fin;
+    }
+    while (ReadFile(pipe, &input, sizeof(input), &bytes, NULL) && bytes == sizeof(input)) {
+        hdesk = OpenInputDesktop(0, FALSE, GENERIC_ALL);
+        if (!hdesk) {
+            vd_printf("OpenInputDesktop() failed: %lu", GetLastError());
+            break;
+        }
+        if (!SetThreadDesktop(hdesk)) {
+            vd_printf("SetThreadDesktop() failed: %lu", GetLastError());
+            CloseDesktop(hdesk);
+            break;
+        }
+        if (!SendInput(1, &input, sizeof(input)) && err != GetLastError()) {
+            err = GetLastError();
+            vd_printf("SendInput() failed: %lu", err);
+        }
+        CloseDesktop(hdesk);
+    }
+    CloseHandle(pipe);
+fin:
+    delete log;
+    return 0;
+}
\ No newline at end of file
diff --git a/vdagent_helper/vdagent_helper.vcproj b/vdagent_helper/vdagent_helper.vcproj
new file mode 100644
index 0000000..47ccb79
--- /dev/null
+++ b/vdagent_helper/vdagent_helper.vcproj
@@ -0,0 +1,363 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="vdagent_helper"
+	ProjectGUID="{3E459EA7-0252-48E0-A92B-13A66F5F370B}"
+	RootNamespace="cheese"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\common;$(SPICE_PROTOCOL_DIR)"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="Version.lib"
+				LinkIncremental="2"
+				UACUIAccess="false"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				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_PROTOCOL_DIR)"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="Version.lib"
+				LinkIncremental="2"
+				UACUIAccess="false"
+				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="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\common;$(SPICE_PROTOCOL_DIR)"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="Version.lib"
+				LinkIncremental="1"
+				UACUIAccess="false"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<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"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\common;$(SPICE_PROTOCOL_DIR)"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="Version.lib"
+				LinkIncremental="1"
+				UACUIAccess="false"
+				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="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\vdagent_helper.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\common\vdlog.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\common\vdlog.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
commit 136c8d3c9467326b5cd47bfb47241e065a7c72d2
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Mon Mar 18 14:13:04 2013 +0200

    vdagent: don't terminate if stop event cannot be opened
    
    so vdagent can keep running as standalone without dependency on vdservice.
    
    Regression was due to commit c1807e.
    
    rhbz #903379

diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index e20c830..f254d55 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -295,11 +295,6 @@ bool VDAgent::run()
         return false;
     }
     _stop_event = OpenEvent(SYNCHRONIZE, FALSE, VD_AGENT_STOP_EVENT);
-    if (!_stop_event) {
-        vd_printf("OpenEvent() failed: %lu", GetLastError());
-        cleanup();
-        return false;
-    }
     memset(&wcls, 0, sizeof(wcls));
     wcls.lpfnWndProc = &VDAgent::wnd_proc;
     wcls.lpszClassName = VD_AGENT_WINCLASS_NAME;
@@ -472,12 +467,19 @@ void VDAgent::input_desktop_message_loop()
 
 void VDAgent::event_dispatcher(DWORD timeout, DWORD wake_mask)
 {
-    HANDLE events[] = {_control_event, _stop_event};    
-    const DWORD event_count = sizeof(events) / sizeof(events[0]);
+    HANDLE events[] = {_control_event, _stop_event};
+    DWORD event_count = _stop_event ? 2 : 1;
     DWORD wait_ret;
     MSG msg;
 
     wait_ret = MsgWaitForMultipleObjectsEx(event_count, events, timeout, wake_mask, MWMO_ALERTABLE);
+    if (wait_ret == WAIT_OBJECT_0 + event_count) {
+        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+            TranslateMessage(&msg);
+            DispatchMessage(&msg);
+        }
+        return;
+    }
     switch (wait_ret) {
     case WAIT_OBJECT_0:
         handle_control_event();
@@ -485,12 +487,6 @@ void VDAgent::event_dispatcher(DWORD timeout, DWORD wake_mask)
     case WAIT_OBJECT_0 + 1:
         _running = false;
         break;
-    case WAIT_OBJECT_0 + event_count:
-        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
-            TranslateMessage(&msg);
-            DispatchMessage(&msg);
-        }
-        break;
     case WAIT_IO_COMPLETION:
     case WAIT_TIMEOUT:
         break;
commit e364fa7799933c2b31b5755b7f2e881a681c83ff
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Mon Mar 18 13:21:14 2013 +0200

    vdagent: log unsupported grabbed clipboard formats
    
    rhbz #919451 debugging, useful anyway

diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index b5d65cd..e20c830 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -914,13 +914,16 @@ bool VDAgent::write_message(uint32_t type, uint32_t size = 0, void* data = NULL)
 
 void VDAgent::on_clipboard_grab()
 {
-    uint32_t* types = new uint32_t[clipboard_formats_count * VD_CLIPBOARD_FORMAT_MAX_TYPES];
+    uint32_t types[clipboard_formats_count * VD_CLIPBOARD_FORMAT_MAX_TYPES];
     int count = 0;
 
     if (!VD_AGENT_HAS_CAPABILITY(_client_caps, _client_caps_size,
                                  VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) {
         return;
     }
+    if (CountClipboardFormats() == 0) {
+        return;
+    }
     for (unsigned int i = 0; i < clipboard_formats_count; i++) {
         if (IsClipboardFormatAvailable(clipboard_formats[i].format)) {
             for (uint32_t* ptype = clipboard_formats[i].types; *ptype; ptype++) {
@@ -932,9 +935,11 @@ void VDAgent::on_clipboard_grab()
         write_message(VD_AGENT_CLIPBOARD_GRAB, count * sizeof(types[0]), types);
         set_clipboard_owner(owner_guest);
     } else {
-        vd_printf("Unsupported clipboard format");       
+        UINT format = 0;
+        while (format = EnumClipboardFormats(format)) {
+            vd_printf("Unsupported clipboard format %u", format);
+        }
     }  
-    delete[] types;
 }
 
 // In delayed rendering, Windows requires us to SetClipboardData before we return from
commit 482a4980f4a162787baa46aaffe989796e2dfd1a
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Mon Mar 18 13:16:22 2013 +0200

    vdagent: for Win7 class, use ClipboardFormatListener api
    
    (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

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>
commit 877e52386e6a98ec5c5bd54af13a984b571674ea
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Mon Mar 18 12:54:04 2013 +0200

    vdservice: extract supported_system_version() to vdcommon
    
    rhbz #919451 preparation

diff --git a/common/vdcommon.cpp b/common/vdcommon.cpp
new file mode 100644
index 0000000..4dc50b4
--- /dev/null
+++ b/common/vdcommon.cpp
@@ -0,0 +1,36 @@
+/*
+   Copyright (C) 2013 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "vdcommon.h"
+
+int supported_system_version()
+{
+    OSVERSIONINFOEX osvi;
+
+    ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+    if (!GetVersionEx((OSVERSIONINFO*)&osvi)) {
+        vd_printf("GetVersionEx() failed: %lu", GetLastError());
+        return 0;
+    }
+    if (osvi.dwMajorVersion == 5 && (osvi.dwMinorVersion == 1 || osvi.dwMinorVersion == 2)) {
+        return SYS_VER_WIN_XP_CLASS;
+    } else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion >= 0 && osvi.dwMinorVersion <= 2) {
+        return SYS_VER_WIN_7_CLASS;
+    }
+    return 0;
+}
diff --git a/common/vdcommon.h b/common/vdcommon.h
index 605153d..177721c 100644
--- a/common/vdcommon.h
+++ b/common/vdcommon.h
@@ -51,5 +51,13 @@ typedef CRITICAL_SECTION mutex_t;
 #define _ftime_s(timeb) _ftime(timeb)
 #endif
 
+enum SystemVersion {
+    SYS_VER_UNSUPPORTED,
+    SYS_VER_WIN_XP_CLASS, // also Server 2003/R2
+    SYS_VER_WIN_7_CLASS,  // also Windows 8, Server 2012, Server 2008/R2 & Vista
+};
+
+int supported_system_version();
+
 #endif
 
diff --git a/vdservice/vdservice.cpp b/vdservice/vdservice.cpp
index 90a3b26..9134c4b 100644
--- a/vdservice/vdservice.cpp
+++ b/vdservice/vdservice.cpp
@@ -119,30 +119,6 @@ VDService* VDService::get()
     return (VDService*)_singleton;
 }
 
-enum SystemVersion {
-    SYS_VER_UNSUPPORTED,
-    SYS_VER_WIN_XP_CLASS, // also Server 2003/R2
-    SYS_VER_WIN_7_CLASS,  // also Windows 8, Server 2012, Server 2008/R2 & Vista
-};
-
-int supported_system_version()
-{
-    OSVERSIONINFOEX osvi;
-
-    ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
-    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
-    if (!GetVersionEx((OSVERSIONINFO*)&osvi)) {
-        vd_printf("GetVersionEx() failed: %lu", GetLastError());
-        return 0;
-    }
-    if (osvi.dwMajorVersion == 5 && (osvi.dwMinorVersion == 1 || osvi.dwMinorVersion == 2)) {
-        return SYS_VER_WIN_XP_CLASS;
-    } else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion >= 0 && osvi.dwMinorVersion <= 2) {
-        return SYS_VER_WIN_7_CLASS;
-    }
-    return 0;
-}
-
 VDService::VDService()
     : _status_handle (0)
     , _events (NULL)
diff --git a/vdservice/vdservice.vcproj b/vdservice/vdservice.vcproj
index 45af4c5..736f425 100644
--- a/vdservice/vdservice.vcproj
+++ b/vdservice/vdservice.vcproj
@@ -363,6 +363,10 @@
 			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
 			>
 			<File
+				RelativePath="..\common\vdcommon.cpp"
+				>
+			</File>
+			<File
 				RelativePath="..\common\vdlog.cpp"
 				>
 			</File>
commit 9b05b948fce1db343d6d57425194e72d2c850760
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Sun Mar 17 16:54:44 2013 +0200

    vdagent: on encoding only, use HBITMAP to keep the correct palette
    
    for decoding, keep using CF_DIB and CxImage.CopyToHandle() as before.
    
    Regression was due to commit da07ce (rhbz #919150)
    
    rhbz #921980

diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index c56025d..1dcfd1a 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -42,7 +42,7 @@ typedef struct VDClipboardFormat {
 VDClipboardFormat clipboard_formats[] = {
     {CF_UNICODETEXT, {VD_AGENT_CLIPBOARD_UTF8_TEXT, 0}},
     //FIXME: support more image types
-    {CF_BITMAP, {VD_AGENT_CLIPBOARD_IMAGE_PNG, VD_AGENT_CLIPBOARD_IMAGE_BMP, 0}},
+    {CF_DIB, {VD_AGENT_CLIPBOARD_IMAGE_PNG, VD_AGENT_CLIPBOARD_IMAGE_BMP, 0}},
 };
 
 #define clipboard_formats_count (sizeof(clipboard_formats) / sizeof(clipboard_formats[0]))
@@ -1008,6 +1008,10 @@ bool VDAgent::handle_clipboard_request(VDAgentClipboardRequest* clipboard_reques
         vd_printf("Unsupported clipboard type %u", clipboard_request->type);
         return false;
     }
+    // on encoding only, we use HBITMAP to keep the correct palette
+    if (format == CF_DIB) {
+        format = CF_BITMAP;
+    }
     if (!IsClipboardFormatAvailable(format) || !OpenClipboard(_hwnd)) {
         return false;
     }


More information about the Spice-commits mailing list