blob: 5d58e2c585e541a225b0035db40f169599d71fe7 [file] [log] [blame]
// Copyright 2010-2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <windows.h>
#include <sstream>
#include <vector>
#include "base/const.h"
#include "base/logging.h"
#include "base/process_mutex.h"
#include "base/scoped_handle.h"
#include "base/system_util.h"
#include "base/win_util.h"
#include "client/client.h"
#include "config/config.pb.h"
#include "config/config_handler.h"
#include "win32/base/imm_registrar.h"
#include "win32/base/imm_util.h"
#include "win32/base/migration_util.h"
DEFINE_int32(ime_switcher_target_process_id, 0,
"The broker send messages to the process specified with this ID");
DEFINE_uint64(ime_switcher_target_process_creation_time, 0,
"The process creation time to specify the actual process with"
" process ID.");
DEFINE_bool(set_default_do_not_ask_again, false,
"Set true if SetDefaultDialog should not be displayed again.");
namespace mozc {
namespace win32 {
namespace {
const char kProcessMutexPrefixForPerUserIMESettings[] =
"mozc_hkcu_manipulation_for_ime.";
// It seems that mozc_tool basically uses the following error levels.
const int kErrorLevelProcessMutexInUse = -1;
const int kErrorLevelSuccess = 0;
const int kErrorLevelGeneralError = 1;
void NotifyFatalMessageImpl(const string &msg) {
#ifdef NO_LOGGING
// Explicitly causes crash so that the migration failure will be notified
// through crash dump.
LOG(FATAL) << msg;
#else
::MessageBoxA(nullptr, msg.c_str(), "GoogleIMEJaBroker",
MB_OK | MB_ICONERROR);
#endif
}
void NotifyFatalMessage(const string &msg, int line) {
ostringstream ostr;
ostr << msg << " (line: " << line << ")";
NotifyFatalMessageImpl(ostr.str());
}
string GetMutexName() {
return (kProcessMutexPrefixForPerUserIMESettings +
SystemUtil::GetDesktopNameAsString());
}
HKL EnsureKeyboardLoaded() {
// Check if the IMM32 version is installed.
const KeyboardLayoutID &target_klid = ImmRegistrar::GetKLIDForIME();
if (!target_klid.has_id()) {
LOG(ERROR) << "KLID is not found.";
return nullptr;
}
HKL hkl = ::LoadKeyboardLayoutW(
target_klid.ToString().c_str(), KLF_ACTIVATE | KLF_SUBSTITUTE_OK);
if (hkl == nullptr) {
const int error = ::GetLastError();
LOG(ERROR) << "LoadKeyboardLayoutW failed. error = " << error;
return nullptr;
}
// Unload the keyboard layout once to ensure that the situation reported in
// b/2958563 will be recovered.
::UnloadKeyboardLayout(hkl);
hkl = ::LoadKeyboardLayoutW(
target_klid.ToString().c_str(), KLF_ACTIVATE | KLF_SUBSTITUTE_OK);
if (hkl == nullptr) {
const int error = ::GetLastError();
LOG(ERROR) << "LoadKeyboardLayoutW failed. error = " << error;
return nullptr;
}
if (!MigrationUtil::RestorePreload()) {
LOG(ERROR) << "RestorePreload() failed";
return nullptr;
}
return hkl;
}
bool ClearCheckDefault() {
client::Client client;
if (!client.PingServer() && !client.EnsureConnection()) {
LOG(ERROR) << "Cannot connect to server";
return false;
}
config::Config config;
if (!config::ConfigHandler::GetConfig(&config)) {
LOG(ERROR) << "Cannot get config";
return false;
}
config.set_check_default(false);
if (!client.SetConfig(config)) {
LOG(ERROR) << "Cannot set config";
return false;
}
return true;
}
int RunSetDefaultWin8() {
if (!ImeUtil::SetDefault()) {
NotifyFatalMessage("SetDefault() failed.", __LINE__);
return kErrorLevelGeneralError;
}
if (FLAGS_set_default_do_not_ask_again) {
if (!ClearCheckDefault()) {
// Notify the error to user but never treat this as an error.
NotifyFatalMessage("ClearCheckDefault() failed.", __LINE__);
}
}
return kErrorLevelSuccess;
}
} // namespace
int RunSetDefault(int argc, char *argv[]) {
if (SystemUtil::IsWindows8OrLater()) {
return RunSetDefaultWin8();
}
const string mutex_name = GetMutexName();
mozc::ProcessMutex mutex(mutex_name.c_str());
if (!mutex.Lock()) {
LOG(INFO) << "Another process is manipulating the IME settings.";
return kErrorLevelProcessMutexInUse;
}
// Some of TSF-related utilities depend on COM runtime libraries.
// We have to make sure that COM is initialized.
mozc::ScopedCOMInitializer com_initializer;
const HKL hkl = EnsureKeyboardLoaded();
if (hkl == nullptr) {
NotifyFatalMessage("EnsureKeyboardLoaded returns nullptr.", __LINE__);
return kErrorLevelGeneralError;
}
if (!ImeUtil::SetDefault()) {
NotifyFatalMessage("SetDefault() failed.", __LINE__);
return kErrorLevelGeneralError;
}
if (FLAGS_set_default_do_not_ask_again) {
if (!ClearCheckDefault()) {
// Notify the error to user but never treat this as an error.
NotifyFatalMessage("ClearCheckDefault() failed.", __LINE__);
}
}
return kErrorLevelSuccess;
}
} // namespace win32
} // namespace mozc