From a2771e5d33c77e7a034078c27f8390b7bdc4f2a8 Mon Sep 17 00:00:00 2001 From: Rom Walton Date: Thu, 7 Aug 2008 16:59:52 +0000 Subject: [PATCH] - CLIENT/MGR/TRAY: When installed on Vista and UAC is turned on the user by default cannot create globally shared objects. This becomes a problem when protected application mode is turned off for keyboard and mouse detection. Basically all of the components would start up and fail to create the shared memory segment and report the error through stderr which most people don't look at by default. The client is now the only component that is allowed to create the shared memory segment, if creating the global segment fails it'll create a local one instead. Both the tray and manager now just attach to the existing segment, first trying the global one then the local one. client/ main.C clientgui/ BOINCGUIApp.cpp, .h clientlib/win/ boinc_dll.cpp IdleTracker.cpp clienttray/ tray_win.cpp, .h win_build/ boinc.sln boinctray.vcproj svn path=/trunk/boinc/; revision=15767 --- checkin_notes | 31 ++++++ client/main.C | 32 +++++++ clientgui/BOINCGUIApp.cpp | 20 ++++ clientgui/BOINCGUIApp.h | 2 + clientlib/win/IdleTracker.cpp | 174 +++++++++++++++++++++++++++++++++- clientlib/win/boinc_dll.cpp | 4 - clienttray/tray_win.cpp | 22 +++-- clienttray/tray_win.h | 1 + win_build/boinc.sln | 9 +- win_build/boinctray.vcproj | 16 ---- 10 files changed, 278 insertions(+), 33 deletions(-) diff --git a/checkin_notes b/checkin_notes index 1fc7e6a281..9de35e9dfb 100644 --- a/checkin_notes +++ b/checkin_notes @@ -6241,3 +6241,34 @@ David 6 Aug 2008 sched/ sched_config.C,h sched_result.C + +Rom 7 Aug 2008 + - CLIENT/MGR/TRAY: When installed on Vista and UAC is turned on + the user by default cannot create globally shared objects. This + becomes a problem when protected application mode is turned off + for keyboard and mouse detection. Basically all of the components + would start up and fail to create the shared memory segment + and report the error through stderr which most people don't look + at by default. + + The client is now the only component that is allowed to create the + shared memory segment, if creating the global segment fails it'll + create a local one instead. Both the tray and manager now just attach + to the existing segment, first trying the global one then the local + one. + + + client/ + main.C + clientgui/ + BOINCGUIApp.cpp, .h + clientlib/win/ + boinc_dll.cpp + IdleTracker.cpp + clienttray/ + tray_win.cpp, .h + win_build/ + boinc.sln + boinctray.vcproj + + \ No newline at end of file diff --git a/client/main.C b/client/main.C index 6ad1623802..62d6ae8788 100644 --- a/client/main.C +++ b/client/main.C @@ -33,6 +33,8 @@ static bool requested_suspend = false; static bool requested_resume = false; typedef BOOL (CALLBACK* ClientLibraryStartup)(); +typedef BOOL (CALLBACK* IdleTrackerStartup)(); +typedef void (CALLBACK* IdleTrackerShutdown)(); typedef void (CALLBACK* ClientLibraryShutdown)(); #ifndef _T #define _T(X) X @@ -410,9 +412,28 @@ int initialize() { #ifdef _WIN32 if(g_hClientLibraryDll) { ClientLibraryStartup fnClientLibraryStartup; + IdleTrackerStartup fnIdleTrackerStartup; + fnClientLibraryStartup = (ClientLibraryStartup)GetProcAddress(g_hClientLibraryDll, _T("ClientLibraryStartup")); if(fnClientLibraryStartup) { if(!fnClientLibraryStartup()) { + stprintf(event_message, + TEXT("BOINC Core Client Error Message\n" + "Failed to initialize the BOINC Client Library Interface.\n" + "BOINC will not be able to determine if the user is idle or not...\n" + "Load failed: %s\n"), windows_error_string(event_message, sizeof(event_message)) + ); + if (!gstate.executing_as_daemon) { + fprintf(stderr, event_message); + } else { + LogEventErrorMessage(event_message); + } + } + } + + fnIdleTrackerStartup = (IdleTrackerStartup)GetProcAddress(g_hClientLibraryDll, _T("IdleTrackerStartup")); + if(fnIdleTrackerStartup) { + if(!fnIdleTrackerStartup()) { stprintf(event_message, TEXT("BOINC Core Client Error Message\n" "Failed to initialize the BOINC Idle Detection Interface.\n" @@ -427,6 +448,7 @@ int initialize() { } } } + #endif return 0; } @@ -514,11 +536,19 @@ int finalize() { #ifdef _WIN32 if(g_hClientLibraryDll) { + IdleTrackerShutdown fnIdleTrackerShutdown; ClientLibraryShutdown fnClientLibraryShutdown; + + fnIdleTrackerShutdown = (IdleTrackerShutdown)GetProcAddress(g_hClientLibraryDll, _T("IdleTrackerShutdown")); + if(fnIdleTrackerShutdown) { + fnIdleTrackerShutdown(); + } + fnClientLibraryShutdown = (ClientLibraryShutdown)GetProcAddress(g_hClientLibraryDll, _T("ClientLibraryShutdown")); if(fnClientLibraryShutdown) { fnClientLibraryShutdown(); } + if(!FreeLibrary(g_hClientLibraryDll)) { stprintf(event_message, TEXT("BOINC Core Client Error Message\n" @@ -527,12 +557,14 @@ int finalize() { ), windows_error_string(event_message, sizeof(event_message)) ); + if (!gstate.executing_as_daemon) { fprintf(stderr, event_message); } else { LogEventErrorMessage(event_message); } } + g_hClientLibraryDll = NULL; } diff --git a/clientgui/BOINCGUIApp.cpp b/clientgui/BOINCGUIApp.cpp index 1d2e5ee9f1..4b2f0a29ce 100644 --- a/clientgui/BOINCGUIApp.cpp +++ b/clientgui/BOINCGUIApp.cpp @@ -55,6 +55,8 @@ static bool s_bSkipExitConfirmation = false; #ifdef __WXMSW__ EXTERN_C BOOL ClientLibraryStartup(); +EXTERN_C BOOL IdleTrackerAttach(); +EXTERN_C void IdleTrackerDetach(); EXTERN_C void ClientLibraryShutdown(); EXTERN_C DWORD BOINCGetIdleTickCount(); #endif @@ -397,6 +399,7 @@ bool CBOINCGUIApp::OnInit() { // Startup the System Idle Detection code ClientLibraryStartup(); + IdleTrackerAttach(); #ifdef __WXMAC__ s_bSkipExitConfirmation = false; @@ -450,6 +453,7 @@ bool CBOINCGUIApp::OnInit() { int CBOINCGUIApp::OnExit() { // Shutdown the System Idle Detection code + IdleTrackerDetach(); ClientLibraryShutdown(); if (m_pDocument) { @@ -613,6 +617,22 @@ int CBOINCGUIApp::ClientLibraryStartup() { } +int CBOINCGUIApp::IdleTrackerAttach() { +#ifdef __WXMSW__ + ::IdleTrackerAttach(); +#endif + return 0; +} + + +int CBOINCGUIApp::IdleTrackerDetach() { +#ifdef __WXMSW__ + ::IdleTrackerDetach(); +#endif + return 0; +} + + int CBOINCGUIApp::ClientLibraryShutdown() { #ifdef __WXMSW__ ::ClientLibraryShutdown(); diff --git a/clientgui/BOINCGUIApp.h b/clientgui/BOINCGUIApp.h index 2949d94b01..0652be0dc6 100644 --- a/clientgui/BOINCGUIApp.h +++ b/clientgui/BOINCGUIApp.h @@ -55,6 +55,8 @@ protected: #endif int ClientLibraryStartup(); + int IdleTrackerAttach(); + int IdleTrackerDetach(); int ClientLibraryShutdown(); wxConfig* m_pConfig; diff --git a/clientlib/win/IdleTracker.cpp b/clientlib/win/IdleTracker.cpp index c86f46a36e..10720aabec 100644 --- a/clientlib/win/IdleTracker.cpp +++ b/clientlib/win/IdleTracker.cpp @@ -136,10 +136,11 @@ EXTERN_C __declspec(dllexport) DWORD BOINCGetIdleTickCount() return (dwCurrentTickCount - dwLastTickCount); } + /** * Initialize DLL: install kbd/mouse hooks. **/ -BOOL IdleTrackerStartup() +EXTERN_C __declspec(dllexport) BOOL IdleTrackerStartup() { BOOL bExists = FALSE; BOOL bResult = FALSE; @@ -206,6 +207,18 @@ BOOL IdleTrackerStartup() 4096, "Global\\BoincIdleTracker" ); + if( NULL == g_hMemoryMappedData ) + { + g_hMemoryMappedData = + CreateFileMapping( + INVALID_HANDLE_VALUE, + &sec_attr, + PAGE_READWRITE, + 0, + 4096, + "BoincIdleTracker" + ); + } if( NULL != g_hMemoryMappedData ) { @@ -249,10 +262,131 @@ BOOL IdleTrackerStartup() return bResult; } + +/** + * Initialize DLL: install kbd/mouse hooks. + **/ +EXTERN_C __declspec(dllexport) BOOL IdleTrackerAttach() +{ + BOOL bExists = FALSE; + BOOL bResult = FALSE; + SECURITY_ATTRIBUTES sec_attr; + SECURITY_DESCRIPTOR sd; + + + g_bIsWindows2000Compatible = IsWindows2000Compatible(); + g_bIsTerminalServicesEnabled = IsTerminalServicesEnabled(); + + + if ( !g_bIsWindows2000Compatible ) + { + if ( NULL == g_hHkKeyboard ) + { + g_hHkKeyboard = SetWindowsHookEx( + WH_KEYBOARD, + KeyboardTracker, + g_hModule, + 0 + ); + } + if ( NULL == g_hHkMouse ) + { + g_hHkMouse = SetWindowsHookEx( + WH_MOUSE, + MouseTracker, + g_hModule, + 0 + ); + } + + _ASSERT( g_hHkKeyboard ); + _ASSERT( g_hHkMouse ); + } + else + { + g_hUser32 = LoadLibrary("user32.dll"); + if (g_hUser32) + g_fnGetLastInputInfo = (GETLASTINPUTINFO)GetProcAddress(g_hUser32, "GetLastInputInfo"); + + + /* + * Create a security descriptor that will allow + * everyone full access. + */ + InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION ); + SetSecurityDescriptorDacl( &sd, TRUE, NULL, FALSE ); + + sec_attr.nLength = sizeof(sec_attr); + sec_attr.bInheritHandle = TRUE; + sec_attr.lpSecurityDescriptor = &sd; + + /* + * Create a filemap object that is global for everyone, + * including users logged in via terminal services. + */ + g_hMemoryMappedData = + OpenFileMapping( + FILE_MAP_READ | FILE_MAP_WRITE, + FALSE, + "Global\\BoincIdleTracker" + ); + if( NULL == g_hMemoryMappedData ) + { + g_hMemoryMappedData = + OpenFileMapping( + FILE_MAP_READ | FILE_MAP_WRITE, + FALSE, + "BoincIdleTracker" + ); + } + + if( NULL != g_hMemoryMappedData ) + { + if( ERROR_ALREADY_EXISTS == GetLastError() ) + bExists = TRUE; + + g_pSystemWideIdleData = (struct SystemWideIdleData*) + MapViewOfFile( + g_hMemoryMappedData, + FILE_MAP_ALL_ACCESS, + 0, + 0, + 0 + ); + + _ASSERT( g_pSystemWideIdleData ); + } + + if( !bExists && g_pSystemWideIdleData ) + { + g_pSystemWideIdleData->dwLastTick = GetTickCount(); + } + } + + + if ( !g_bIsWindows2000Compatible ) + { + if ( !g_hHkKeyboard || !g_hHkMouse ) + bResult = FALSE; + else + bResult = TRUE; + } + else + { + if ( !g_hUser32 || !g_fnGetLastInputInfo || !g_hMemoryMappedData || !g_pSystemWideIdleData ) + bResult = FALSE; + else + bResult = TRUE; + } + + return bResult; +} + + /** * Terminate DLL: remove hooks. **/ -void IdleTrackerShutdown() +EXTERN_C __declspec(dllexport) void IdleTrackerDetach() { if ( !g_bIsWindows2000Compatible ) { @@ -283,4 +417,40 @@ void IdleTrackerShutdown() } } + +/** + * Terminate DLL: remove hooks. + **/ +EXTERN_C __declspec(dllexport) void IdleTrackerShutdown() +{ + if ( !g_bIsWindows2000Compatible ) + { + BOOL bResult; + if ( g_hHkKeyboard ) + { + bResult = UnhookWindowsHookEx( g_hHkKeyboard ); + _ASSERT( bResult ); + g_hHkKeyboard = NULL; + } + if ( g_hHkMouse ) + { + bResult = UnhookWindowsHookEx(g_hHkMouse); + _ASSERT( bResult ); + g_hHkMouse = NULL; + } + } + else + { + if( NULL != g_pSystemWideIdleData ) + { + UnmapViewOfFile(g_pSystemWideIdleData); + CloseHandle(g_hMemoryMappedData); + } + + if ( NULL != g_hUser32 ) + FreeLibrary(g_hUser32); + } +} + + const char *BOINC_RCSID_14d432d5b3 = "$Id$"; diff --git a/clientlib/win/boinc_dll.cpp b/clientlib/win/boinc_dll.cpp index 294fc130c1..89f7f6ab6d 100644 --- a/clientlib/win/boinc_dll.cpp +++ b/clientlib/win/boinc_dll.cpp @@ -44,14 +44,10 @@ BOOL APIENTRY DllMain( EXTERN_C __declspec(dllexport) BOOL ClientLibraryStartup() { - if (!IdleTrackerStartup()) - return FALSE; - return TRUE; } EXTERN_C __declspec(dllexport) void ClientLibraryShutdown() { - IdleTrackerShutdown(); } diff --git a/clienttray/tray_win.cpp b/clienttray/tray_win.cpp index 74b106421f..bfaf1defdf 100644 --- a/clienttray/tray_win.cpp +++ b/clienttray/tray_win.cpp @@ -22,9 +22,11 @@ #include "tray_win.h" - BOOL IdleTrackerStartup(); +EXTERN_C BOOL ClientLibraryStartup(); +EXTERN_C BOOL IdleTrackerAttach(); +EXTERN_C void IdleTrackerDetach(); +EXTERN_C void ClientLibraryShutdown(); EXTERN_C DWORD BOINCGetIdleTickCount(); - void IdleTrackerShutdown(); HMODULE g_hModule = NULL; static CBOINCTray* gspBOINCTray = NULL; @@ -41,6 +43,7 @@ CBOINCTray::CBOINCTray() { gspBOINCTray = this; m_hDataManagementThread = NULL; m_bClientLibraryInitialized = FALSE; + m_bIdleTrackerInitialized = FALSE; } @@ -48,9 +51,6 @@ CBOINCTray::CBOINCTray() { // INT CBOINCTray::Run( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { - // Initialize the BOINC client library to setup the idle tracking system. - m_bClientLibraryInitialized = IdleTrackerStartup(); - if (!hPrevInstance) { // Register an appropriate window class for the primary window WNDCLASS cls; @@ -87,7 +87,8 @@ INT CBOINCTray::Run( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi // Cleanup and shutdown the BOINC client library idle tracking system. - IdleTrackerShutdown(); + IdleTrackerDetach(); + ClientLibraryShutdown(); return msg.wParam; } @@ -132,12 +133,17 @@ BOOL CBOINCTray::DestroyDataManagementThread() { // DWORD WINAPI CBOINCTray::DataManagementProc() { while (true) { - if (!m_bClientLibraryInitialized) { + if (!m_bClientLibraryInitialized || !m_bIdleTrackerInitialized) { // On Vista systems, only elevated processes can create shared memory // area's across various user sessions. In this case we need to wait // for BOINC to create the shared memory area and then boinctray can // successfully attach to it. What a PITA. - m_bClientLibraryInitialized = IdleTrackerStartup(); + if (!m_bClientLibraryInitialized) { + m_bClientLibraryInitialized = ClientLibraryStartup(); + } + if (m_bClientLibraryInitialized && !m_bIdleTrackerInitialized) { + m_bIdleTrackerInitialized = IdleTrackerAttach(); + } } BOINCGetIdleTickCount(); diff --git a/clienttray/tray_win.h b/clienttray/tray_win.h index 7177ed4821..6cb07de53c 100644 --- a/clienttray/tray_win.h +++ b/clienttray/tray_win.h @@ -42,6 +42,7 @@ protected: HANDLE m_hDataManagementThread; BOOL m_bClientLibraryInitialized; + BOOL m_bIdleTrackerInitialized; }; #endif diff --git a/win_build/boinc.sln b/win_build/boinc.sln index 3b0277d224..715681bea8 100644 --- a/win_build/boinc.sln +++ b/win_build/boinc.sln @@ -2,8 +2,8 @@ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "boinc", "boinc_cli_curl.vcproj", "{C04F0FCC-BB5D-4627-8656-6173B28BD69E}" ProjectSection(ProjectDependencies) = postProject - {E8F6BD7E-461A-4733-B7D8-37B09A099ED8} = {E8F6BD7E-461A-4733-B7D8-37B09A099ED8} {B06280CB-82A4-46DE-8956-602643078BDF} = {B06280CB-82A4-46DE-8956-602643078BDF} + {E8F6BD7E-461A-4733-B7D8-37B09A099ED8} = {E8F6BD7E-461A-4733-B7D8-37B09A099ED8} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "boinc_dll", "boinc_dll.vcproj", "{B06280CB-82A4-46DE-8956-602643078BDF}" @@ -12,14 +12,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "boinc_ss", "boinc_ss.vcproj EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "boinccmd", "boinccmd.vcproj", "{8F37E1F3-3A68-4A1D-9579-A1210BDD055E}" ProjectSection(ProjectDependencies) = postProject - {E8F6BD7E-461A-4733-B7D8-37B09A099ED8} = {E8F6BD7E-461A-4733-B7D8-37B09A099ED8} {C04F0FCC-BB5D-4627-8656-6173B28BD69E} = {C04F0FCC-BB5D-4627-8656-6173B28BD69E} + {E8F6BD7E-461A-4733-B7D8-37B09A099ED8} = {E8F6BD7E-461A-4733-B7D8-37B09A099ED8} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "boincmgr", "boincmgr_curl.vcproj", "{06113715-AC51-4E91-8B9D-C987CABE0920}" ProjectSection(ProjectDependencies) = postProject - {B06280CB-82A4-46DE-8956-602643078BDF} = {B06280CB-82A4-46DE-8956-602643078BDF} {C04F0FCC-BB5D-4627-8656-6173B28BD69E} = {C04F0FCC-BB5D-4627-8656-6173B28BD69E} + {B06280CB-82A4-46DE-8956-602643078BDF} = {B06280CB-82A4-46DE-8956-602643078BDF} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libboinc", "libboinc.vcproj", "{E8F6BD7E-461A-4733-B7D8-37B09A099ED8}" @@ -32,6 +32,9 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "boincsim", "sim.vcproj", "{B950E31B-C075-4F6D-8A2B-25EAE9D46C93}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "boinctray", "boinctray.vcproj", "{4A2C5963-6A8D-4DA1-A312-C3D749B2EA81}" + ProjectSection(ProjectDependencies) = postProject + {B06280CB-82A4-46DE-8956-602643078BDF} = {B06280CB-82A4-46DE-8956-602643078BDF} + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/win_build/boinctray.vcproj b/win_build/boinctray.vcproj index eda40baecf..a129b4dcaf 100644 --- a/win_build/boinctray.vcproj +++ b/win_build/boinctray.vcproj @@ -676,18 +676,10 @@ Name="Source Files" Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" > - - - - - - - -