| // Copyright (c) 2011 The WebM project authors. All Rights Reserved. | |
| // | |
| // Use of this source code is governed by a BSD-style license | |
| // that can be found in the LICENSE file in the root of the source | |
| // tree. An additional intellectual property rights grant can be found | |
| // in the file PATENTS. All contributing project authors may | |
| // be found in the AUTHORS file in the root of the source tree. | |
| #include <windows.h> | |
| #include <cassert> | |
| #include <memory> | |
| #include <string> | |
| #include <sstream> | |
| #include "omahautil.hpp" | |
| #include "debugutil.hpp" | |
| //#include "memutil.hpp" | |
| #include "registry.hpp" | |
| namespace WebmUtil | |
| { | |
| class OmahaStats | |
| { | |
| public: | |
| OmahaStats(); | |
| ~OmahaStats(); | |
| HRESULT SetUsageFlags(const GUID& app_id); | |
| private: | |
| bool UserHasEnabledStats_(); | |
| HRESULT CreateHkcuClientStateSubKey_(); | |
| HRESULT MakeAppKeyStr_(); | |
| HRESULT SetUsageFlags_(); | |
| bool stats_enabled_; | |
| GUID app_id_guid_; | |
| Registry::Key app_key_; // App's key (might be in HKLM) | |
| Registry::Key user_key_; // App's key in HKCU | |
| std::wstring app_key_str_; | |
| DISALLOW_COPY_AND_ASSIGN(OmahaStats); | |
| }; | |
| } // WebmUtil namespace | |
| HRESULT WebmUtil::set_omaha_usage_flags(const GUID& app_id) | |
| { | |
| OmahaStats stats; | |
| return stats.SetUsageFlags(app_id); | |
| } | |
| namespace WebmUtil | |
| { | |
| const int kOmahaAppIdStrLen = 40; | |
| OmahaStats::OmahaStats(): | |
| app_id_guid_(GUID_NULL), | |
| stats_enabled_(false) | |
| { | |
| } | |
| OmahaStats::~OmahaStats() | |
| { | |
| } | |
| HRESULT OmahaStats::SetUsageFlags(const GUID& app_id) | |
| { | |
| HRESULT hr; | |
| // store the user guid | |
| app_id_guid_ = app_id; | |
| // let's make our app sub key string... | |
| CHK(hr, MakeAppKeyStr_()); | |
| if (FAILED(hr)) | |
| { | |
| return hr; | |
| } | |
| // survived putting the sub key string in |app_key_str_|, let's see if | |
| // the user enabled stats at install time... | |
| if (UserHasEnabledStats_() == false) | |
| { | |
| // nope! Everything's ok, nothing to see here... | |
| return S_OK; | |
| } | |
| // stats enabled! Let's set the usage flags... | |
| CHK(hr, SetUsageFlags_()); | |
| return hr; | |
| } | |
| bool OmahaStats::UserHasEnabledStats_() | |
| { | |
| if (GUID_NULL != app_id_guid_ && app_key_str_.length()) | |
| { | |
| // We support Omaha client installs that live in HKLM and HKCU... | |
| const int num_keys = 2; | |
| HKEY keys_to_check[num_keys] = {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE}; | |
| for (int i = 0; i < num_keys; ++i) | |
| { | |
| // loop through |keys_to_check| and try each with the generated | |
| // key string in |app_key_str_| | |
| LONG reg_error = app_key_.open(keys_to_check[i], app_key_str_); | |
| if (ERROR_SUCCESS == reg_error) | |
| { | |
| assert(app_key_.is_open()); | |
| // key is open, let's read (query) the usagestats val... | |
| DWORD usage_stats_value = 0; | |
| reg_error = app_key_.query("usagestats", usage_stats_value); | |
| if (ERROR_SUCCESS == reg_error && usage_stats_value) | |
| { | |
| // the user enabled usage tracking at install time | |
| stats_enabled_ = true; | |
| } | |
| } | |
| } | |
| } | |
| return stats_enabled_; | |
| } | |
| HRESULT OmahaStats::CreateHkcuClientStateSubKey_() | |
| { | |
| // .. and set the "dr" flag | |
| // TODO(tomfinegan): flag setting should probably move elsewhere, and | |
| // wrapping the subkey creation is sort of silly given | |
| // how easy matthewjheaney's Registry class is to use... | |
| LONG reg_error = user_key_.create(HKEY_CURRENT_USER, app_key_str_); | |
| if (ERROR_SUCCESS == reg_error) | |
| { | |
| reg_error = user_key_.set(L"dr", L"1", REG_SZ); | |
| } | |
| return ERROR_SUCCESS == reg_error ? S_OK : E_FAIL; | |
| } | |
| // Build the subkey path for the Omaha application we're working with using | |
| // the GUID passed to |WebmUtil::set_omaha_usage_flag| | |
| HRESULT OmahaStats::MakeAppKeyStr_() | |
| { | |
| if (GUID_NULL == app_id_guid_) | |
| { | |
| DBGLOG("need a valid guid."); | |
| return E_INVALIDARG; | |
| } | |
| wchar_t app_id_wchars[kOmahaAppIdStrLen] = {0}; | |
| int wchars_converted = StringFromGUID2(app_id_guid_, &app_id_wchars[0], | |
| kOmahaAppIdStrLen); | |
| assert(wchars_converted > 0); | |
| if (!wchars_converted) | |
| { | |
| DBGLOG("conversion of app_id to string failed."); | |
| return E_FAIL; | |
| } | |
| std::wostringstream key_stream; | |
| key_stream << "Software\\"; | |
| #ifdef _WIN64 | |
| // At present we use a 32 bit NSIS installer, and it writes to the tree | |
| // under Wow6432Node when the NSIS registry utility functions are used. | |
| // Omaha reads the values from there as well, so let's keep it simple and | |
| // write there from our 64bit builds as well. | |
| key_stream << L"Wow6432Node\\"; | |
| #endif | |
| key_stream << L"Google\\Update\\ClientState\\" << app_id_wchars; | |
| app_key_str_ = key_stream.str(); | |
| return S_OK; | |
| } | |
| // Note: SetUsageFlags_ is a bit of a misnomer-- we're setting only the "dr" | |
| // flag, which tells Omaha that the tracked application has been run | |
| // since it was last updated. | |
| HRESULT OmahaStats::SetUsageFlags_() | |
| { | |
| REGSAM access_flags = KEY_QUERY_VALUE | KEY_SET_VALUE; | |
| LONG reg_error = user_key_.open(HKEY_CURRENT_USER, app_key_str_, | |
| access_flags); | |
| if (ERROR_FILE_NOT_FOUND == reg_error) | |
| { | |
| HRESULT hr; | |
| // Note: |CreateHkcuClientStateSubKey_| sets the "dr" flag | |
| CHK(hr, CreateHkcuClientStateSubKey_()); | |
| return hr; | |
| } | |
| else if (ERROR_SUCCESS == reg_error) | |
| { | |
| // Set only if not present. This should help prevent repeated nag | |
| // dialogs for users running registry monitoring software that notifies | |
| // on all registry writes. | |
| std::wstring dr_value; | |
| reg_error = user_key_.query(L"dr", dr_value); | |
| if (ERROR_FILE_NOT_FOUND == reg_error) | |
| { | |
| reg_error = user_key_.set(L"dr", L"1", REG_SZ); | |
| } | |
| } | |
| return ERROR_SUCCESS == reg_error ? S_OK : E_FAIL; | |
| } | |
| } // WebmUtil namespace |