blob: 54bcd7745017d7f3906351fe1352d1e5b51ebff3 [file] [log] [blame]
// Copyright 2010-2014, 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 "win32/base/input_dll.h"
#include "base/logging.h"
#include "base/util.h"
#include "base/win_util.h"
namespace mozc {
namespace win32 {
const wchar_t kInputDllName[] = L"input.dll";
const char kEnumEnabledLayoutOrTipName[] = "EnumEnabledLayoutOrTip";
const char kEnumLayoutOrTipForSetup[] = "EnumLayoutOrTipForSetup";
const char kInstallLayoutOrTipName[] = "InstallLayoutOrTip";
const char kInstallLayoutOrTipUserRegName[] = "InstallLayoutOrTipUserReg";
const char kSetDefaultLayoutOrTipName[] = "SetDefaultLayoutOrTip";
bool InputDll::EnsureInitialized() {
if (not_found_) {
// Previous trial was not successful. give up.
return false;
}
if (module_ != nullptr) {
// Already initialized.
return true;
}
bool lock_held = false;
if (!WinUtil::IsDLLSynchronizationHeld(&lock_held)) {
LOG(ERROR) << "IsDLLSynchronizationHeld failed.";
return false;
}
if (lock_held) {
LOG(INFO) << "This thread has loader lock. "
<< "LoadLibrary should not be called.";
return false;
}
const HMODULE input_dll = WinUtil::LoadSystemLibrary(kInputDllName);
if (input_dll == nullptr) {
const int last_error = ::GetLastError();
DLOG(INFO) << "LoadSystemLibrary(\"" << kInputDllName << "\") failed. "
<< "error = " << last_error;
if (last_error == ERROR_MOD_NOT_FOUND) {
not_found_ = true;
}
return false;
}
enum_enabled_layout_or_tip_ =
reinterpret_cast<FPEnumEnabledLayoutOrTip>(
::GetProcAddress(input_dll, kEnumEnabledLayoutOrTipName));
enum_layout_or_tip_for_setup_ =
reinterpret_cast<FPEnumLayoutOrTipForSetup>(
::GetProcAddress(input_dll, kEnumLayoutOrTipForSetup));
install_layout_or_tip_ =
reinterpret_cast<FPInstallLayoutOrTip>(
::GetProcAddress(input_dll, kInstallLayoutOrTipName));
install_layout_or_tip_user_reg_ =
reinterpret_cast<FPInstallLayoutOrTipUserReg>(
::GetProcAddress(input_dll, kInstallLayoutOrTipUserRegName));
set_default_layout_or_tip_ =
reinterpret_cast<FPSetDefaultLayoutOrTip>(
::GetProcAddress(input_dll, kSetDefaultLayoutOrTipName));
// Other threads may load the same DLL concurrently.
// Check if this thread is the first thread which updated the |module_|.
const HMODULE original = static_cast<HMODULE>(
::InterlockedCompareExchangePointer(
reinterpret_cast<volatile PVOID *>(&module_), input_dll, nullptr));
if (original == nullptr) {
// This is the first thread which updated the |module_| with valid handle.
// Do not call FreeLibrary to keep the reference count positive.
} else {
// |module_| has already been updated by another thread. Call FreeLibrary
// to decrement the reference count which this thread owns.
::FreeLibrary(input_dll);
}
return true;
}
InputDll::FPEnumEnabledLayoutOrTip InputDll::enum_enabled_layout_or_tip() {
return enum_enabled_layout_or_tip_;
}
InputDll::FPEnumLayoutOrTipForSetup InputDll::enum_layout_or_tip_for_setup() {
return enum_layout_or_tip_for_setup_;
}
InputDll::FPInstallLayoutOrTip InputDll::install_layout_or_tip() {
return install_layout_or_tip_;
}
InputDll::FPInstallLayoutOrTipUserReg
InputDll::install_layout_or_tip_user_reg() {
return install_layout_or_tip_user_reg_;
}
InputDll::FPSetDefaultLayoutOrTip InputDll::set_default_layout_or_tip() {
return set_default_layout_or_tip_;
}
bool InputDll::not_found_;
volatile HMODULE InputDll::module_;
InputDll::FPEnumEnabledLayoutOrTip InputDll::enum_enabled_layout_or_tip_;
InputDll::FPEnumLayoutOrTipForSetup InputDll::enum_layout_or_tip_for_setup_;
InputDll::FPInstallLayoutOrTip InputDll::install_layout_or_tip_;
InputDll::FPInstallLayoutOrTipUserReg
InputDll::install_layout_or_tip_user_reg_;
InputDll::FPSetDefaultLayoutOrTip InputDll::set_default_layout_or_tip_;
} // namespace win32
} // namespace mozc