X-Git-Url: http://git.osdn.net/view?p=yamy%2Fyamy.git;a=blobdiff_plain;f=mayu.cpp;h=f83f19e812ecbba262041d7bff433329bcd9aa99;hp=1b9fe73cd1c27bfb1ed7a908f80ead5a94c142c7;hb=ff1830fb4a33718abe1280ee7b835cedffd54aac;hpb=fbcb2a315a085366916e2a465d0a9d4b30811a23 diff --git a/mayu.cpp b/mayu.cpp index 1b9fe73..f83f19e 100644 --- a/mayu.cpp +++ b/mayu.cpp @@ -24,11 +24,13 @@ #include "setting.h" #include "target.h" #include "windowstool.h" +#include "fixscancodemap.h" #include "vk2tchar.h" #include #include #include #include +#include /// @@ -62,8 +64,11 @@ class Mayu #endif // LOG_TO_FILE HMENU m_hMenuTaskTray; /// tasktray menu +#ifdef _WIN64 + HANDLE m_hMutexYamyd; STARTUPINFO m_si; PROCESS_INFORMATION m_pi; +#endif // _WIN64 HANDLE m_mutex; #ifdef USE_MAILSLOT HANDLE m_hNotifyMailslot; /// mailslot to receive notify @@ -71,6 +76,12 @@ class Mayu OVERLAPPED m_olNotify; /// BYTE m_notifyBuf[NOTIFY_MESSAGE_SIZE]; #endif // USE_MAILSLOT + static const DWORD SESSION_LOCKED = 1<<0; + static const DWORD SESSION_DISCONNECTED = 1<<1; + static const DWORD SESSION_END_QUERIED = 1<<2; + DWORD m_sessionState; + int m_escapeNlsKeys; + FixScancodeMap m_fixScancodeMap; Setting *m_setting; /// current setting bool m_isSettingDialogOpened; /// is setting dialog opened ? @@ -83,16 +94,23 @@ class Mayu enum { WM_APP_taskTrayNotify = WM_APP + 101, /// WM_APP_msgStreamNotify = WM_APP + 102, /// + WM_APP_escapeNLSKeysFailed = WM_APP + 121, /// ID_TaskTrayIcon = 1, /// }; + enum { + YAMY_TIMER_ESCAPE_NLS_KEYS = 0, /// + }; + private: #ifdef USE_MAILSLOT static VOID CALLBACK mailslotProc(DWORD i_code, DWORD i_len, LPOVERLAPPED i_ol) { Mayu *pThis; - pThis = reinterpret_cast(CONTAINING_RECORD(i_ol, Mayu, m_olNotify)); - pThis->mailslotHandler(i_code, i_len); + if (i_code == ERROR_SUCCESS) { + pThis = reinterpret_cast(CONTAINING_RECORD(i_ol, Mayu, m_olNotify)); + pThis->mailslotHandler(i_code, i_len); + } return; } @@ -265,6 +283,10 @@ private: case WM_CREATE: This = reinterpret_cast( reinterpret_cast(i_lParam)->lpCreateParams); + This->m_fixScancodeMap.init(i_hwnd, WM_APP_escapeNLSKeysFailed); + if (This->m_escapeNlsKeys) { + This->m_fixScancodeMap.escape(true); + } #ifdef MAYU64 SetWindowLongPtr(i_hwnd, 0, (LONG_PTR)This); #else @@ -280,6 +302,12 @@ private: return This->notifyHandler(cd); } case WM_QUERYENDSESSION: + if (!This->m_sessionState) { + if (This->m_escapeNlsKeys && This->m_engine.getIsEnabled()) { + This->m_fixScancodeMap.escape(false); + } + } + This->m_sessionState |= Mayu::SESSION_END_QUERIED; This->m_engine.prepairQuit(); PostQuitMessage(0); return TRUE; @@ -300,16 +328,45 @@ private: # define WTS_SESSION_LOCK 0x7 # define WTS_SESSION_UNLOCK 0x8 #endif + /* + restore NLS keys when any bits of m_sessionState is on + and + escape NLS keys when all bits of m_sessionState cleared + */ case WTS_CONSOLE_CONNECT: + This->m_sessionState &= ~Mayu::SESSION_DISCONNECTED; + if (!This->m_sessionState) { + if (This->m_escapeNlsKeys && This->m_engine.getIsEnabled()) { + This->m_fixScancodeMap.escape(true); + } + } m = "WTS_CONSOLE_CONNECT"; break; case WTS_CONSOLE_DISCONNECT: + if (!This->m_sessionState) { + if (This->m_escapeNlsKeys && This->m_engine.getIsEnabled()) { + This->m_fixScancodeMap.escape(false); + } + } + This->m_sessionState |= Mayu::SESSION_DISCONNECTED; m = "WTS_CONSOLE_DISCONNECT"; break; case WTS_REMOTE_CONNECT: + This->m_sessionState &= ~Mayu::SESSION_DISCONNECTED; + if (!This->m_sessionState) { + if (This->m_escapeNlsKeys && This->m_engine.getIsEnabled()) { + This->m_fixScancodeMap.escape(true); + } + } m = "WTS_REMOTE_CONNECT"; break; case WTS_REMOTE_DISCONNECT: + if (!This->m_sessionState) { + if (This->m_escapeNlsKeys && This->m_engine.getIsEnabled()) { + This->m_fixScancodeMap.escape(false); + } + } + This->m_sessionState |= Mayu::SESSION_DISCONNECTED; m = "WTS_REMOTE_DISCONNECT"; break; case WTS_SESSION_LOGON: @@ -318,12 +375,26 @@ private: case WTS_SESSION_LOGOFF: m = "WTS_SESSION_LOGOFF"; break; - case WTS_SESSION_LOCK: + case WTS_SESSION_LOCK: { + if (!This->m_sessionState) { + if (This->m_escapeNlsKeys && This->m_engine.getIsEnabled()) { + This->m_fixScancodeMap.escape(false); + } + } + This->m_sessionState |= Mayu::SESSION_LOCKED; m = "WTS_SESSION_LOCK"; break; - case WTS_SESSION_UNLOCK: + } + case WTS_SESSION_UNLOCK: { + This->m_sessionState &= ~Mayu::SESSION_LOCKED; + if (!This->m_sessionState) { + if (This->m_escapeNlsKeys && This->m_engine.getIsEnabled()) { + This->m_fixScancodeMap.escape(true); + } + } m = "WTS_SESSION_UNLOCK"; break; + } //case WTS_SESSION_REMOTE_CONTROL: m = "WTS_SESSION_REMOTE_CONTROL"; break; } This->m_log << _T("WM_WTSESSION_CHANGE(") @@ -408,6 +479,21 @@ private: return 0; } + case WM_APP_escapeNLSKeysFailed: + if (i_lParam) { + This->m_log << _T("escape NLS keys done code=") << i_wParam << std::endl; + if (i_wParam != YAMY_SUCCESS && i_wParam != YAMY_ERROR_RETRY_INJECTION_SUCCESS) { + int ret = This->errorDialogWithCode(IDS_escapeNlsKeysFailed, i_wParam, MB_RETRYCANCEL | MB_ICONSTOP); + if (ret == IDRETRY) { + This->m_fixScancodeMap.escape(true); + } + } + } else { + This->m_log << _T("restore NLS keys done with code=") << i_wParam << std::endl; + } + return 0; + break; + case WM_COMMAND: { int notify_code = HIWORD(i_wParam); int id = LOWORD(i_wParam); @@ -503,6 +589,11 @@ private: } case ID_MENUITEM_disable: This->m_engine.enable(!This->m_engine.getIsEnabled()); + if (This->m_engine.getIsEnabled()) { + This->m_fixScancodeMap.escape(true); + } else { + This->m_fixScancodeMap.escape(false); + } This->showTasktrayIcon(); break; case ID_MENUITEM_quit: @@ -589,6 +680,11 @@ private: wtsUnRegisterSessionNotification(i_hwnd); This->m_usingSN = false; } + if (!This->m_sessionState) { + if (This->m_escapeNlsKeys && This->m_engine.getIsEnabled()) { + This->m_fixScancodeMap.escape(false); + } + } return 0; default: @@ -605,6 +701,11 @@ private: switch (static_cast(i_wParam)) { case MayuIPCCommand_Enable: This->m_engine.enable(!!i_lParam); + if (This->m_engine.getIsEnabled()) { + This->m_fixScancodeMap.escape(true); + } else { + This->m_fixScancodeMap.escape(false); + } This->showTasktrayIcon(); if (i_lParam) { Acquire a(&This->m_log, 1); @@ -733,6 +834,164 @@ private: } } + int errorDialogWithCode(UINT ids, int code, UINT style = MB_OK | MB_ICONSTOP) + { + _TCHAR title[1024]; + _TCHAR text[1024]; + + _sntprintf_s(title, NUMBER_OF(title), _TRUNCATE, loadString(IDS_mayu).c_str()); + _sntprintf_s(text, NUMBER_OF(text), _TRUNCATE, loadString(ids).c_str(), code); + return MessageBox((HWND)NULL, text, title, style); + } + + int enableToWriteByUser(HANDLE hdl) + { + TCHAR userName[GANA_MAX_ATOM_LENGTH]; + DWORD userNameSize = NUMBER_OF(userName); + + SID_NAME_USE sidType; + PSID pSid = NULL; + DWORD sidSize = 0; + TCHAR *pDomain = NULL; + DWORD domainSize = 0; + + PSECURITY_DESCRIPTOR pSd; + PACL pOrigDacl; + ACL_SIZE_INFORMATION aclInfo; + + PACL pNewDacl; + DWORD newDaclSize; + + DWORD aceIndex; + DWORD newAceIndex = 0; + + BOOL ret; + int err = 0; + + ret = GetUserName(userName, &userNameSize); + if (ret == FALSE) { + err = YAMY_ERROR_ON_GET_USERNAME; + goto exit; + } + + // get buffer size for pSid (and pDomain) + ret = LookupAccountName(NULL, userName, pSid, &sidSize, pDomain, &domainSize, &sidType); + if (ret != FALSE || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + // above call should fail by ERROR_INSUFFICIENT_BUFFER + err = YAMY_ERROR_ON_GET_LOGONUSERNAME; + goto exit; + } + + pSid = reinterpret_cast(LocalAlloc(LPTR, sidSize)); + pDomain = reinterpret_cast(LocalAlloc(LPTR, domainSize * sizeof(TCHAR))); + if (pSid == NULL || pDomain == NULL) { + err = YAMY_ERROR_NO_MEMORY; + goto exit; + } + + // get SID (and Domain) for logoned user + ret = LookupAccountName(NULL, userName, pSid, &sidSize, pDomain, &domainSize, &sidType); + if (ret == FALSE) { + // LookupAccountName() should success in this time + err = YAMY_ERROR_ON_GET_LOGONUSERNAME; + goto exit; + } + + // get DACL for hdl + ret = GetSecurityInfo(hdl, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pOrigDacl, NULL, &pSd); + if (ret != ERROR_SUCCESS) { + err = YAMY_ERROR_ON_GET_SECURITYINFO; + goto exit; + } + + // get size for original DACL + ret = GetAclInformation(pOrigDacl, &aclInfo, sizeof(aclInfo), AclSizeInformation); + if (ret == FALSE) { + err = YAMY_ERROR_ON_GET_DACL; + goto exit; + } + + // compute size for new DACL + newDaclSize = aclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pSid) - sizeof(DWORD); + + // allocate memory for new DACL + pNewDacl = reinterpret_cast(LocalAlloc(LPTR, newDaclSize)); + if (pNewDacl == NULL) { + err = YAMY_ERROR_NO_MEMORY; + goto exit; + } + + // initialize new DACL + ret = InitializeAcl(pNewDacl, newDaclSize, ACL_REVISION); + if (ret == FALSE) { + err = YAMY_ERROR_ON_INITIALIZE_ACL; + goto exit; + } + + // copy original DACL to new DACL + for (aceIndex = 0; aceIndex < aclInfo.AceCount; aceIndex++) { + LPVOID pAce; + + ret = GetAce(pOrigDacl, aceIndex, &pAce); + if (ret == FALSE) { + err = YAMY_ERROR_ON_GET_ACE; + goto exit; + } + + if ((reinterpret_cast(pAce))->Header.AceFlags & INHERITED_ACE) { + break; + } + + if (EqualSid(pSid, &(reinterpret_cast(pAce))->SidStart) != FALSE) { + continue; + } + + ret = AddAce(pNewDacl, ACL_REVISION, MAXDWORD, pAce, (reinterpret_cast(pAce))->AceSize); + if (ret == FALSE) { + err = YAMY_ERROR_ON_ADD_ACE; + goto exit; + } + + newAceIndex++; + } + + ret = AddAccessAllowedAce(pNewDacl, ACL_REVISION, GENERIC_ALL, pSid); + if (ret == FALSE) { + err = YAMY_ERROR_ON_ADD_ALLOWED_ACE; + goto exit; + } + + // copy the rest of inherited ACEs + for (; aceIndex < aclInfo.AceCount; aceIndex++) { + LPVOID pAce; + + ret = GetAce(pOrigDacl, aceIndex, &pAce); + if (ret == FALSE) { + err = YAMY_ERROR_ON_GET_ACE; + goto exit; + } + + ret = AddAce(pNewDacl, ACL_REVISION, MAXDWORD, pAce, (reinterpret_cast(pAce))->AceSize); + if (ret == FALSE) { + err = YAMY_ERROR_ON_ADD_ACE; + goto exit; + } + } + + ret = SetSecurityInfo(hdl, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, pNewDacl, NULL); + if (ret != ERROR_SUCCESS) { + err = YAMY_ERROR_ON_SET_SECURITYINFO; + } + +exit: + LocalFree(pSd); + LocalFree(pSid); + LocalFree(pDomain); + LocalFree(pNewDacl); + + return err; + } + public: /// Mayu(HANDLE i_mutex) @@ -746,10 +1005,21 @@ public: m_log(WM_APP_msgStreamNotify), m_setting(NULL), m_isSettingDialogOpened(false), + m_sessionState(0), m_engine(m_log) { + Registry reg(MAYU_REGISTRY_ROOT); + reg.read(_T("escapeNLSKeys"), &m_escapeNlsKeys, 0); #ifdef USE_MAILSLOT m_hNotifyMailslot = CreateMailslot(NOTIFY_MAILSLOT_NAME, 0, MAILSLOT_WAIT_FOREVER, (SECURITY_ATTRIBUTES *)NULL); ASSERT(m_hNotifyMailslot != INVALID_HANDLE_VALUE); + int err; + if (checkWindowsVersion(6, 0) != FALSE) { // enableToWriteByUser() is available only Vista or later + err = enableToWriteByUser(m_hNotifyMailslot); + if (err) { + errorDialogWithCode(IDS_cannotPermitStandardUser, err); + } + } + m_hNotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); ASSERT(m_hNotifyEvent); m_olNotify.Offset = 0; @@ -843,7 +1113,7 @@ public: tstring tip = loadString(IDS_mayu); tcslcpy(m_ni.szTip, tip.c_str(), NUMBER_OF(m_ni.szTip)); if (m_canUseTasktrayBaloon) { - m_ni.cbSize = sizeof(m_ni); + m_ni.cbSize = NOTIFYICONDATA_V3_SIZE; m_ni.uFlags |= NIF_INFO; } else m_ni.cbSize = NOTIFYICONDATA_V1_SIZE; @@ -856,35 +1126,54 @@ public: // set initial lock state notifyLockState(); - BOOL result; - +#ifdef _WIN64 ZeroMemory(&m_pi,sizeof(m_pi)); ZeroMemory(&m_si,sizeof(m_si)); m_si.cb=sizeof(m_si); -#ifdef _WIN64 - result = CreateProcess(_T("yamyd32"), _T("yamyd32"), NULL, NULL, FALSE, + + // create mutex to block yamyd + m_hMutexYamyd = CreateMutex((SECURITY_ATTRIBUTES *)NULL, TRUE, MUTEX_YAMYD_BLOCKER); + + tstring yamydPath; + _TCHAR exePath[GANA_MAX_PATH]; + _TCHAR exeDrive[GANA_MAX_PATH]; + _TCHAR exeDir[GANA_MAX_PATH]; + + GetModuleFileName(NULL, exePath, GANA_MAX_PATH); + _tsplitpath_s(exePath, exeDrive, GANA_MAX_PATH, exeDir, GANA_MAX_PATH, NULL, 0, NULL, 0); + yamydPath = exeDrive; + yamydPath += exeDir; + yamydPath += _T("yamyd32"); + + BOOL result = CreateProcess(yamydPath.c_str(), NULL, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, 0, NULL, &m_si, &m_pi); if (result == FALSE) { TCHAR buf[1024]; TCHAR text[1024]; TCHAR title[1024]; + m_pi.hProcess = NULL; LoadString(GetModuleHandle(NULL), IDS_cannotInvoke, text, sizeof(text)/sizeof(text[0])); LoadString(GetModuleHandle(NULL), IDS_mayu, title, sizeof(title)/sizeof(title[0])); _stprintf_s(buf, sizeof(buf)/sizeof(buf[0]), text, _T("yamyd32"), GetLastError()); - MessageBox((HWND)NULL, buf, title, MB_OK | MB_ICONSTOP); + MessageBox((HWND)NULL, buf, title, MB_OK | MB_ICONSTOP); } else { CloseHandle(m_pi.hThread); - CloseHandle(m_pi.hProcess); } #endif // _WIN64 } /// ~Mayu() { +#ifdef USE_MAILSLOT + CancelIo(m_hNotifyMailslot); + SleepEx(0, TRUE); + CloseHandle(m_hNotifyMailslot); + CloseHandle(m_hNotifyEvent); +#endif // USE_MAILSLOT ReleaseMutex(m_mutex); WaitForSingleObject(m_mutex, INFINITE); // first, detach log from edit control to avoid deadlock @@ -896,7 +1185,19 @@ public: // stop notify from mayu.dll g_hookData->m_hwndTaskTray = NULL; CHECK_FALSE( uninstallMessageHook() ); - PostMessage(HWND_BROADCAST, WM_NULL, 0, 0); + +#ifdef _WIN64 + ReleaseMutex(m_hMutexYamyd); + if (m_pi.hProcess) { + WaitForSingleObject(m_pi.hProcess, 5000); + CloseHandle(m_pi.hProcess); + } + CloseHandle(m_hMutexYamyd); +#endif // _WIN64 + if (!(m_sessionState & SESSION_END_QUERIED)) { + DWORD_PTR result; + SendMessageTimeout(HWND_BROADCAST, WM_NULL, 0, 0, SMTO_ABORTIFHUNG, 3000, &result); + } // destroy windows CHECK_TRUE( DestroyWindow(m_hwndVersion) ); @@ -917,11 +1218,6 @@ public: // remove setting; delete m_setting; - -#ifdef USE_MAILSLOT - CloseHandle(m_hNotifyEvent); - CloseHandle(m_hNotifyMailslot); -#endif // USE_MAILSLOT } /// message loop