| OLD | NEW |
| (Empty) |
| 1 // Copyright 2008-2009 Google Inc. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 // ======================================================================== | |
| 15 // | |
| 16 // Implementation of the OneClick Plugin. | |
| 17 | |
| 18 #include "omaha/plugins/update/activex/oneclick_control.h" | |
| 19 | |
| 20 #include <dispex.h> | |
| 21 #include <atlsafe.h> | |
| 22 #include <atlbase.h> | |
| 23 #include <atlcom.h> | |
| 24 | |
| 25 #include "omaha/base/error.h" | |
| 26 #include "omaha/base/exception_barrier.h" | |
| 27 #include "omaha/base/file.h" | |
| 28 #include "omaha/base/scoped_any.h" | |
| 29 #include "omaha/base/scoped_ptr_address.h" | |
| 30 #include "omaha/base/string.h" | |
| 31 #include "omaha/base/vistautil.h" | |
| 32 #include "omaha/common/command_line.h" | |
| 33 #include "omaha/common/command_line_builder.h" | |
| 34 #include "omaha/common/const_cmd_line.h" | |
| 35 #include "omaha/common/goopdate_utils.h" | |
| 36 #include "omaha/common/webplugin_utils.h" | |
| 37 #include "omaha/goopdate/app_command.h" | |
| 38 #include "omaha/goopdate/app_manager.h" | |
| 39 #include "goopdate/omaha3_idl.h" | |
| 40 | |
| 41 namespace omaha { | |
| 42 | |
| 43 OneClickControl::OneClickControl() { | |
| 44 CORE_LOG(L2, (_T("[OneClickControl::OneClickControl]"))); | |
| 45 } | |
| 46 | |
| 47 OneClickControl::~OneClickControl() { | |
| 48 CORE_LOG(L2, (_T("[OneClickControl::~OneClickControl]"))); | |
| 49 } | |
| 50 | |
| 51 STDMETHODIMP OneClickControl::Install(BSTR cmd_line_args, | |
| 52 VARIANT* success_callback, | |
| 53 VARIANT* failure_callback) { | |
| 54 ASSERT1(cmd_line_args && cmd_line_args[0]); | |
| 55 ASSERT1(VariantIsValidCallback(success_callback)); | |
| 56 ASSERT1(VariantIsValidCallback(failure_callback)); | |
| 57 | |
| 58 if (!site_lock_.InApprovedDomain(this)) { | |
| 59 return GOOPDATE_E_ONECLICK_HOSTCHECK_FAILED; | |
| 60 } | |
| 61 | |
| 62 if (!cmd_line_args || | |
| 63 !cmd_line_args[0] || | |
| 64 !VariantIsValidCallback(success_callback) || | |
| 65 !VariantIsValidCallback(failure_callback) ) { | |
| 66 return E_INVALIDARG; | |
| 67 } | |
| 68 | |
| 69 CORE_LOG(L2, (_T("[OneClickControl::Install][cmd_line \"%s\"]"), | |
| 70 CW2CT(cmd_line_args))); | |
| 71 | |
| 72 HRESULT hr = DoInstall(CString(cmd_line_args)); | |
| 73 if (SUCCEEDED(hr)) { | |
| 74 InvokeJavascriptCallback(success_callback, NULL); | |
| 75 } else { | |
| 76 CORE_LOG(LE, (_T("[DoOneClickInstallInternal failed][0x%08x]"), hr)); | |
| 77 InvokeJavascriptCallback(failure_callback, &hr); | |
| 78 } | |
| 79 | |
| 80 // Return success in all cases. The failure callback has already been called | |
| 81 // above, and we don't want to cause a failure path to be called again when | |
| 82 // the JavaScript catches the exception. | |
| 83 | |
| 84 return S_OK; | |
| 85 } | |
| 86 | |
| 87 STDMETHODIMP OneClickControl::Install2(BSTR extra_args) { | |
| 88 ASSERT1(extra_args && extra_args[0]); | |
| 89 | |
| 90 if (!site_lock_.InApprovedDomain(this)) { | |
| 91 return GOOPDATE_E_ONECLICK_HOSTCHECK_FAILED; | |
| 92 } | |
| 93 | |
| 94 if (!extra_args || !extra_args[0]) { | |
| 95 return E_INVALIDARG; | |
| 96 } | |
| 97 | |
| 98 CORE_LOG(L2, (_T("[OneClickControl::Install2][extra_args \"%s\"]"), | |
| 99 CW2CT(extra_args))); | |
| 100 | |
| 101 CommandLineBuilder builder(COMMANDLINE_MODE_INSTALL); | |
| 102 builder.set_extra_args(CString(extra_args)); | |
| 103 return DoInstall(builder.GetCommandLineArgs()); | |
| 104 } | |
| 105 | |
| 106 STDMETHODIMP OneClickControl::GetInstalledVersion(BSTR guid_string, | |
| 107 VARIANT_BOOL is_machine, | |
| 108 BSTR* version_string) { | |
| 109 if (!site_lock_.InApprovedDomain(this)) { | |
| 110 return GOOPDATE_E_ONECLICK_HOSTCHECK_FAILED; | |
| 111 } | |
| 112 | |
| 113 if (!guid_string || !version_string) { | |
| 114 return E_POINTER; | |
| 115 } | |
| 116 *version_string = NULL; | |
| 117 | |
| 118 CORE_LOG(L2, (_T("[OneClickControl::GetInstalledVersion][%s][%d]"), | |
| 119 guid_string, is_machine)); | |
| 120 | |
| 121 CString version; | |
| 122 HRESULT hr = DoGetInstalledVersion(guid_string, | |
| 123 is_machine == VARIANT_TRUE, | |
| 124 &version); | |
| 125 if (SUCCEEDED(hr)) { | |
| 126 *version_string = version.AllocSysString(); | |
| 127 } | |
| 128 | |
| 129 return S_OK; | |
| 130 } | |
| 131 | |
| 132 STDMETHODIMP OneClickControl::GetOneClickVersion(long* version) { // NOLINT | |
| 133 ASSERT1(version); | |
| 134 | |
| 135 if (!site_lock_.InApprovedDomain(this)) { | |
| 136 return GOOPDATE_E_ONECLICK_HOSTCHECK_FAILED; | |
| 137 } | |
| 138 | |
| 139 CORE_LOG(L2, (_T("[OneClickControl::GetOneClickVersion]"))); | |
| 140 | |
| 141 if (!version) { | |
| 142 return E_POINTER; | |
| 143 } | |
| 144 | |
| 145 *version = atoi(ONECLICK_PLUGIN_VERSION_ANSI); // NOLINT | |
| 146 return S_OK; | |
| 147 } | |
| 148 | |
| 149 STDMETHODIMP OneClickControl::LaunchAppCommand(BSTR app_guid, | |
| 150 VARIANT_BOOL is_machine, | |
| 151 BSTR cmd_id) { | |
| 152 if (!site_lock_.InApprovedDomain(this)) { | |
| 153 return GOOPDATE_E_ONECLICK_HOSTCHECK_FAILED; | |
| 154 } | |
| 155 | |
| 156 CORE_LOG(L2, (_T("[OneClickControl::LaunchAppCommand]"))); | |
| 157 | |
| 158 ExceptionBarrier barrier; | |
| 159 | |
| 160 CComPtr<IOneClickProcessLauncher> process_launcher; | |
| 161 HRESULT hr = E_UNEXPECTED; | |
| 162 | |
| 163 hr = process_launcher.CoCreateInstance( | |
| 164 is_machine ? | |
| 165 CLSID_OneClickMachineProcessLauncherClass : | |
| 166 CLSID_OneClickUserProcessLauncherClass); | |
| 167 | |
| 168 if (FAILED(hr)) { | |
| 169 CORE_LOG(LE, (_T("[OneClickControl::LaunchAppCommand]") | |
| 170 _T("[Failed to CoCreate OneClickMachine/User ") | |
| 171 _T("ProcessLauncher implementation: 0x%x"), | |
| 172 hr)); | |
| 173 return hr; | |
| 174 } | |
| 175 | |
| 176 return process_launcher->LaunchAppCommand(app_guid, cmd_id); | |
| 177 } | |
| 178 | |
| 179 HRESULT OneClickControl::DoGetInstalledVersion(const TCHAR* guid_string, | |
| 180 bool is_machine, | |
| 181 CString* version_string) { | |
| 182 ASSERT1(guid_string); | |
| 183 ASSERT1(version_string); | |
| 184 | |
| 185 GUID app_guid = GUID_NULL; | |
| 186 HRESULT hr = StringToGuidSafe(guid_string, &app_guid); | |
| 187 if (FAILED(hr)) { | |
| 188 return hr; | |
| 189 } | |
| 190 | |
| 191 return AppManager::ReadAppVersionNoLock(is_machine, app_guid, version_string); | |
| 192 } | |
| 193 | |
| 194 HRESULT OneClickControl::DoInstall(const TCHAR* cmd_line_args) { | |
| 195 ASSERT1(cmd_line_args); | |
| 196 | |
| 197 CORE_LOG(L2, (_T("[OneClickControl::DoInstall][%s]"), cmd_line_args)); | |
| 198 | |
| 199 #ifdef _DEBUG | |
| 200 // If the args are exactly __DIRECTNOTIFY__ then just fire the event | |
| 201 // out of this thread. This allows for easy testing of the | |
| 202 // browser interface without requiring launch of | |
| 203 // google_update.exe. | |
| 204 if (0 == _wcsicmp(L"__DIRECTNOTIFY__", cmd_line_args)) { | |
| 205 return S_OK; | |
| 206 } | |
| 207 #endif | |
| 208 | |
| 209 CString browser_url; | |
| 210 HRESULT hr = site_lock_.GetCurrentBrowserUrl(this, &browser_url); | |
| 211 if (FAILED(hr)) { | |
| 212 return hr; | |
| 213 } | |
| 214 | |
| 215 CString url_domain; | |
| 216 hr = SiteLock::GetUrlDomain(browser_url, &url_domain); | |
| 217 if (FAILED(hr)) { | |
| 218 return hr; | |
| 219 } | |
| 220 | |
| 221 CString url_domain_encoded; | |
| 222 CString cmd_line_args_encoded; | |
| 223 hr = StringEscape(url_domain, false, &url_domain_encoded); | |
| 224 if (FAILED(hr)) { | |
| 225 return hr; | |
| 226 } | |
| 227 | |
| 228 hr = StringEscape(cmd_line_args, false, &cmd_line_args_encoded); | |
| 229 if (FAILED(hr)) { | |
| 230 return hr; | |
| 231 } | |
| 232 | |
| 233 CommandLineBuilder builder(COMMANDLINE_MODE_WEBPLUGIN); | |
| 234 builder.set_webplugin_url_domain(url_domain_encoded); | |
| 235 builder.set_webplugin_args(cmd_line_args_encoded); | |
| 236 builder.set_install_source(kCmdLineInstallSource_OneClick); | |
| 237 CString final_cmd_line_args = builder.GetCommandLineArgs(); | |
| 238 | |
| 239 CORE_LOG(L2, (_T("[OneClickControl::DoInstall]") | |
| 240 _T("[Final command line params: %s]"), | |
| 241 final_cmd_line_args)); | |
| 242 | |
| 243 scoped_process process_goopdate; | |
| 244 | |
| 245 hr = goopdate_utils::StartGoogleUpdateWithArgs( | |
| 246 goopdate_utils::IsRunningFromOfficialGoopdateDir(true), | |
| 247 final_cmd_line_args, | |
| 248 address(process_goopdate)); | |
| 249 if (FAILED(hr)) { | |
| 250 CORE_LOG(LE, (_T("[OneClickControl::DoInstall]") | |
| 251 _T("[Failed StartGoogleUpdateWithArgs][0x%x]"), hr)); | |
| 252 return hr; | |
| 253 } | |
| 254 | |
| 255 return S_OK; | |
| 256 } | |
| 257 | |
| 258 bool OneClickControl::VariantIsValidCallback(const VARIANT* callback) { | |
| 259 return callback && | |
| 260 (callback->vt == VT_NULL || | |
| 261 callback->vt == VT_EMPTY || | |
| 262 (callback->vt == VT_DISPATCH && callback->pdispVal)); | |
| 263 } | |
| 264 | |
| 265 HRESULT OneClickControl::InvokeJavascriptCallback(VARIANT* callback, | |
| 266 const HRESULT* opt_param) { | |
| 267 if (!callback || callback->vt == VT_NULL || callback->vt == VT_EMPTY) { | |
| 268 return S_FALSE; | |
| 269 } | |
| 270 | |
| 271 if (callback->vt != VT_DISPATCH || !callback->pdispVal) { | |
| 272 return E_FAIL; | |
| 273 } | |
| 274 | |
| 275 const DISPID kDispId0 = 0; | |
| 276 DISPPARAMS dispparams = {0}; | |
| 277 | |
| 278 CComQIPtr<IDispatchEx> dispatchex = callback->pdispVal; | |
| 279 if (dispatchex) { | |
| 280 DISPID disp_this = DISPID_THIS; | |
| 281 VARIANT var[2]; | |
| 282 var[0].vt = VT_DISPATCH; | |
| 283 var[0].pdispVal = dispatchex; | |
| 284 if (opt_param) { | |
| 285 var[1].vt = VT_I4; | |
| 286 var[1].intVal = *opt_param; | |
| 287 } | |
| 288 | |
| 289 dispparams.rgvarg = var; | |
| 290 dispparams.rgdispidNamedArgs = &disp_this; | |
| 291 dispparams.cNamedArgs = 1; | |
| 292 dispparams.cArgs = opt_param ? 2 : 1; | |
| 293 | |
| 294 return dispatchex->InvokeEx(kDispId0, LOCALE_USER_DEFAULT, | |
| 295 DISPATCH_METHOD, &dispparams, | |
| 296 NULL, NULL, NULL); | |
| 297 } else { | |
| 298 // Fallback on IDispatch if needed. (This route will be used for NPAPI | |
| 299 // functions wrapped via NPFunctionHost.) | |
| 300 | |
| 301 UINT arg_err = 0; | |
| 302 VARIANT var[1]; | |
| 303 | |
| 304 if (opt_param) { | |
| 305 var[0].vt = VT_I4; | |
| 306 var[0].intVal = *opt_param; | |
| 307 dispparams.rgvarg = var; | |
| 308 dispparams.cArgs = 1; | |
| 309 } | |
| 310 | |
| 311 return callback->pdispVal->Invoke(kDispId0, | |
| 312 IID_NULL, | |
| 313 LOCALE_SYSTEM_DEFAULT, | |
| 314 DISPATCH_METHOD, | |
| 315 &dispparams, | |
| 316 NULL, | |
| 317 NULL, | |
| 318 &arg_err); | |
| 319 } | |
| 320 } | |
| 321 | |
| 322 // This works during Setup because IsRunningFromOfficialGoopdateDir checks the | |
| 323 // location of the DLL not the exe, which is running from a temp location. | |
| 324 CString OneClickControl::GetGoopdateShellPathForRegMap() { | |
| 325 ASSERT1(goopdate_utils::IsRunningFromOfficialGoopdateDir(false) || | |
| 326 goopdate_utils::IsRunningFromOfficialGoopdateDir(true)); | |
| 327 return goopdate_utils::BuildGoogleUpdateExeDir( | |
| 328 goopdate_utils::IsRunningFromOfficialGoopdateDir(true)); | |
| 329 } | |
| 330 | |
| 331 } // namespace omaha | |
| 332 | |
| 333 // 4505: unreferenced local function has been removed | |
| 334 #pragma warning(disable : 4505) | |
| 335 | |
| OLD | NEW |