Skip to content

Commit

Permalink
Implicitly link to input.dll on Windows.
Browse files Browse the repository at this point in the history
Now that we we no longer support Windows XP, we can safely assume
that input.dll is always available and it's OK to implicitly link
to that rather than relying on LoadLibrary and GetProcAddress.

One tricky part is that Windows SDK does not provide the import
library for input.dll.  To work around this, we will create our own
import library as a part of build steps, by following this document.
http://support.microsoft.com/kb/131313/en-us

BUG=none
TEST=compile
  • Loading branch information
yukawa committed May 23, 2015
1 parent a93dd6e commit f470414
Show file tree
Hide file tree
Showing 10 changed files with 219 additions and 416 deletions.
2 changes: 1 addition & 1 deletion src/mozc_version_template.txt
@@ -1,6 +1,6 @@
MAJOR=2
MINOR=17
BUILD=2096
BUILD=2097
REVISION=102
# NACL_DICTIONARY_VERSION is the target version of the system dictionary to be
# downloaded by NaCl Mozc.
Expand Down
49 changes: 8 additions & 41 deletions src/win32/base/imm_util.cc
Expand Up @@ -70,20 +70,12 @@ const wchar_t kCUASValueName[] = L"CUAS";
const uint32 kWaitForAsmCacheReadyEventTimeout = 4500; // 4.5 sec.

bool GetDefaultLayout(LAYOUTORTIPPROFILE *profile) {
if (!InputDll::EnsureInitialized()) {
return false;
}

if (InputDll::enum_enabled_layout_or_tip() == nullptr) {
return false;
}

const UINT num_element = InputDll::enum_enabled_layout_or_tip()(
const UINT num_element = ::EnumEnabledLayoutOrTip(
nullptr, nullptr, nullptr, nullptr, 0);

unique_ptr<LAYOUTORTIPPROFILE[]> buffer(new LAYOUTORTIPPROFILE[num_element]);

const UINT num_copied = InputDll::enum_enabled_layout_or_tip()(
const UINT num_copied =::EnumEnabledLayoutOrTip(
nullptr, nullptr, nullptr, buffer.get(), num_element);

for (size_t i = 0; i < num_copied; ++i) {
Expand Down Expand Up @@ -140,12 +132,6 @@ bool IsDefaultWin8() {
}

bool SetDefaultWin8() {
if (!InputDll::EnsureInitialized()) {
return false;
}
if (InputDll::set_default_layout_or_tip() == nullptr) {
return false;
}
wchar_t clsid[64] = {};
if (!::StringFromGUID2(TsfProfile::GetTextServiceGuid(), clsid,
arraysize(clsid))) {
Expand All @@ -158,11 +144,11 @@ bool SetDefaultWin8() {
}

const wstring &profile = wstring(L"0x0411:") + clsid + profile_id;
if (!InputDll::install_layout_or_tip()(profile.c_str(), 0)) {
if (!::InstallLayoutOrTip(profile.c_str(), 0)) {
DLOG(ERROR) << "InstallLayoutOrTip failed";
return false;
}
if (!InputDll::set_default_layout_or_tip()(profile.c_str(), 0)) {
if (!::SetDefaultLayoutOrTip(profile.c_str(), 0)) {
DLOG(ERROR) << "SetDefaultLayoutOrTip failed";
return false;
}
Expand Down Expand Up @@ -262,29 +248,10 @@ bool ImeUtil::SetDefault() {
return false;
}

if (InputDll::EnsureInitialized() &&
InputDll::set_default_layout_or_tip() != nullptr) {
// In most cases, we can use this method on Vista or later.
const wstring &profile_list = L"0x0411:0x" + mozc_klid.ToString();
if (!InputDll::set_default_layout_or_tip()(profile_list.c_str(), 0)) {
DLOG(ERROR) << "SetDefaultLayoutOrTip failed";
return false;
}
} else {
// We cannot use const HKL because |&mozc_hkl| will be cast into PVOID.
HKL hkl = ::LoadKeyboardLayout(mozc_klid.ToString().c_str(), KLF_ACTIVATE);
if (0 == ::SystemParametersInfo(SPI_SETDEFAULTINPUTLANG,
0,
&hkl,
SPIF_SENDCHANGE)) {
LOG(ERROR) << "SystemParameterInfo failed: " << GetLastError();
return false;
}

if (S_OK != ImmRegistrar::MovePreloadValueToTop(mozc_klid)) {
LOG(ERROR) << "MovePreloadValueToTop failed";
return false;
}
const wstring &profile_list = L"0x0411:0x" + mozc_klid.ToString();
if (!::SetDefaultLayoutOrTip(profile_list.c_str(), 0)) {
DLOG(ERROR) << "SetDefaultLayoutOrTip failed";
return false;
}

if (!ActivateForCurrentSession()) {
Expand Down
163 changes: 55 additions & 108 deletions src/win32/base/input_dll.cc
Expand Up @@ -27,123 +27,70 @@
// (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"
// This file will be used to create an import library. Functions in this
// file must not be called directly.

#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));
#include <windows.h>

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;
}
#include "base/logging.h"

InputDll::FPEnumEnabledLayoutOrTip InputDll::enum_enabled_layout_or_tip() {
return enum_enabled_layout_or_tip_;
struct LAYOUTORTIPPROFILE;
struct LAYOUTORTIP;

extern "C"
UINT WINAPI EnumEnabledLayoutOrTip(
__in_opt LPCWSTR pszUserReg,
__in_opt LPCWSTR pszSystemReg,
__in_opt LPCWSTR pszSoftwareReg,
__out LAYOUTORTIPPROFILE *pLayoutOrTipProfile,
__in UINT uBufLength) {
CHECK(false)
<< "This is a stub function to create an import library. "
<< "Shouldn't be called from anywhere.";
return 0;
}

InputDll::FPEnumLayoutOrTipForSetup InputDll::enum_layout_or_tip_for_setup() {
return enum_layout_or_tip_for_setup_;
extern "C"
UINT WINAPI EnumLayoutOrTipForSetup(
__in LANGID langid,
__out_ecount(uBufLength) LAYOUTORTIP *pLayoutOrTip,
__in UINT uBufLength,
__in DWORD dwFlags) {
CHECK(false)
<< "This is a stub function to create an import library. "
<< "Shouldn't be called from anywhere.";
return 0;
}

InputDll::FPInstallLayoutOrTip InputDll::install_layout_or_tip() {
return install_layout_or_tip_;
extern "C"
BOOL WINAPI InstallLayoutOrTip(
__in LPCWSTR psz,
__in DWORD dwFlags) {
CHECK(false)
<< "This is a stub function to create an import library. "
<< "Shouldn't be called from anywhere.";
return FALSE;
}

InputDll::FPInstallLayoutOrTipUserReg
InputDll::install_layout_or_tip_user_reg() {
return install_layout_or_tip_user_reg_;
extern "C"
BOOL WINAPI InstallLayoutOrTipUserReg(
__in_opt LPCWSTR pszUserReg,
__in_opt LPCWSTR pszSystemReg,
__in_opt LPCWSTR pszSoftwareReg,
__in LPCWSTR psz,
__in DWORD dwFlags) {
CHECK(false)
<< "This is a stub function to create an import library. "
<< "Shouldn't be called from anywhere.";
return FALSE;
}

InputDll::FPSetDefaultLayoutOrTip InputDll::set_default_layout_or_tip() {
return set_default_layout_or_tip_;
extern "C"
BOOL WINAPI SetDefaultLayoutOrTip(
__in LPCWSTR psz,
DWORD dwFlags) {
CHECK(false)
<< "This is a stub function to create an import library. "
<< "Shouldn't be called from anywhere.";
return FALSE;
}

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
8 changes: 8 additions & 0 deletions src/win32/base/input_dll.def
@@ -0,0 +1,8 @@
LIBRARY input.dll

EXPORTS
EnumEnabledLayoutOrTip
EnumLayoutOrTipForSetup
InstallLayoutOrTip
InstallLayoutOrTipUserReg
SetDefaultLayoutOrTip

0 comments on commit f470414

Please sign in to comment.