OSDN Git Service

0380688af0e0e60fa6e77218a1916a4b5484e223
[yamy/yamy.git] / mayu.cpp
1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
2 // mayu.cpp\r
3 \r
4 \r
5 #define APSTUDIO_INVOKED\r
6 \r
7 #include "misc.h"\r
8 #include "compiler_specific_func.h"\r
9 #include "dlginvestigate.h"\r
10 #include "dlglog.h"\r
11 #include "dlgsetting.h"\r
12 #include "dlgversion.h"\r
13 #include "engine.h"\r
14 #include "errormessage.h"\r
15 #include "focus.h"\r
16 #include "function.h"\r
17 #include "hook.h"\r
18 #include "mayu.h"\r
19 #include "mayuipc.h"\r
20 #include "mayurc.h"\r
21 #include "msgstream.h"\r
22 #include "multithread.h"\r
23 #include "registry.h"\r
24 #include "setting.h"\r
25 #include "target.h"\r
26 #include "windowstool.h"\r
27 #include "fixscancodemap.h"\r
28 #include "vk2tchar.h"\r
29 #include <process.h>\r
30 #include <time.h>\r
31 #include <commctrl.h>\r
32 #include <wtsapi32.h>\r
33 #include <aclapi.h>\r
34 \r
35 \r
36 ///\r
37 #define ID_MENUITEM_reloadBegin _APS_NEXT_COMMAND_VALUE\r
38 \r
39 \r
40 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
41 // Mayu\r
42 \r
43 \r
44 ///\r
45 class Mayu\r
46 {\r
47         HWND m_hwndTaskTray;                            /// tasktray window\r
48         HWND m_hwndLog;                         /// log dialog\r
49         HWND m_hwndInvestigate;                 /// investigate dialog\r
50         HWND m_hwndVersion;                             /// version dialog\r
51 \r
52         UINT m_WM_TaskbarRestart;                       /** window message sent when\r
53                                                     taskber restarts */\r
54         UINT m_WM_MayuIPC;                              /** IPC message sent from\r
55                                                     other applications */\r
56         NOTIFYICONDATA m_ni;                            /// taskbar icon data\r
57         HICON m_tasktrayIcon[2];                        /// taskbar icon\r
58         bool m_canUseTasktrayBaloon;                    ///\r
59 \r
60         tomsgstream m_log;                              /** log stream (output to log\r
61                                                     dialog's edit) */\r
62 #ifdef LOG_TO_FILE\r
63         tofstream m_logFile;\r
64 #endif // LOG_TO_FILE\r
65 \r
66         HMENU m_hMenuTaskTray;                  /// tasktray menu\r
67 #ifdef _WIN64\r
68         HANDLE m_hMutexYamyd;\r
69         STARTUPINFO m_si;\r
70         PROCESS_INFORMATION m_pi;\r
71 #endif // _WIN64\r
72         HANDLE m_mutex;\r
73 #ifdef USE_MAILSLOT\r
74         HANDLE m_hNotifyMailslot;                       /// mailslot to receive notify\r
75         HANDLE m_hNotifyEvent;                  /// event on receive notify\r
76         OVERLAPPED m_olNotify;                  ///\r
77         BYTE m_notifyBuf[NOTIFY_MESSAGE_SIZE];\r
78 #endif // USE_MAILSLOT\r
79         static const DWORD SESSION_LOCKED = 1<<0;\r
80         static const DWORD SESSION_DISCONNECTED = 1<<1;\r
81         static const DWORD SESSION_END_QUERIED = 1<<2;\r
82         DWORD m_sessionState;\r
83         int m_escapeNlsKeys;\r
84         FixScancodeMap m_fixScancodeMap;\r
85 \r
86         Setting *m_setting;                             /// current setting\r
87         bool m_isSettingDialogOpened;                   /// is setting dialog opened ?\r
88 \r
89         Engine m_engine;                                /// engine\r
90 \r
91         bool m_usingSN;            /// using WTSRegisterSessionNotification() ?\r
92         time_t m_startTime;                             /// mayu started at ...\r
93 \r
94         enum {\r
95                 WM_APP_taskTrayNotify = WM_APP + 101,   ///\r
96                 WM_APP_msgStreamNotify = WM_APP + 102,  ///\r
97                 WM_APP_escapeNLSKeysFailed = WM_APP + 121,      ///\r
98                 ID_TaskTrayIcon = 1,                    ///\r
99         };\r
100 \r
101         enum {\r
102                 YAMY_TIMER_ESCAPE_NLS_KEYS = 0, ///\r
103         };\r
104 \r
105 private:\r
106 #ifdef USE_MAILSLOT\r
107         static VOID CALLBACK mailslotProc(DWORD i_code, DWORD i_len, LPOVERLAPPED i_ol) {\r
108                 Mayu *pThis;\r
109 \r
110                 if (i_code == ERROR_SUCCESS) {\r
111                         pThis = reinterpret_cast<Mayu*>(CONTAINING_RECORD(i_ol, Mayu, m_olNotify));\r
112                         pThis->mailslotHandler(i_code, i_len);\r
113                 }\r
114                 return;\r
115         }\r
116 \r
117         BOOL mailslotHandler(DWORD i_code, DWORD i_len) {\r
118                 BOOL result;\r
119 \r
120                 if (i_len) {\r
121                         COPYDATASTRUCT cd;\r
122 \r
123                         cd.dwData = reinterpret_cast<Notify *>(m_notifyBuf)->m_type;\r
124                         cd.cbData = i_len;\r
125                         cd.lpData = m_notifyBuf;\r
126                         notifyHandler(&cd);\r
127                 }\r
128 \r
129                 memset(m_notifyBuf, 0, sizeof(m_notifyBuf));\r
130                 result = ReadFileEx(m_hNotifyMailslot, m_notifyBuf, sizeof(m_notifyBuf),\r
131                                                         &m_olNotify, Mayu::mailslotProc);\r
132                 return result;\r
133         }\r
134 #endif // USE_MAILSLOT\r
135 \r
136         /// register class for tasktray\r
137         ATOM Register_tasktray() {\r
138                 WNDCLASS wc;\r
139                 wc.style         = 0;\r
140                 wc.lpfnWndProc   = tasktray_wndProc;\r
141                 wc.cbClsExtra    = 0;\r
142                 wc.cbWndExtra    = sizeof(Mayu *);\r
143                 wc.hInstance     = g_hInst;\r
144                 wc.hIcon         = NULL;\r
145                 wc.hCursor       = NULL;\r
146                 wc.hbrBackground = NULL;\r
147                 wc.lpszMenuName  = NULL;\r
148                 wc.lpszClassName = _T("mayuTasktray");\r
149                 return RegisterClass(&wc);\r
150         }\r
151 \r
152         /// notify handler\r
153         BOOL notifyHandler(COPYDATASTRUCT *cd) {\r
154                 switch (cd->dwData) {\r
155                 case Notify::Type_setFocus:\r
156                 case Notify::Type_name: {\r
157                         NotifySetFocus *n = (NotifySetFocus *)cd->lpData;\r
158                         n->m_className[NUMBER_OF(n->m_className) - 1] = _T('\0');\r
159                         n->m_titleName[NUMBER_OF(n->m_titleName) - 1] = _T('\0');\r
160 \r
161                         if (n->m_type == Notify::Type_setFocus)\r
162                                 m_engine.setFocus(reinterpret_cast<HWND>(n->m_hwnd), n->m_threadId,\r
163                                                                   n->m_className, n->m_titleName, false);\r
164 \r
165                         {\r
166                                 Acquire a(&m_log, 1);\r
167                                 m_log << _T("HWND:\t") << std::hex\r
168                                 << n->m_hwnd\r
169                                 << std::dec << std::endl;\r
170                                 m_log << _T("THREADID:") << static_cast<int>(n->m_threadId)\r
171                                 << std::endl;\r
172                         }\r
173                         Acquire a(&m_log, (n->m_type == Notify::Type_name) ? 0 : 1);\r
174                         m_log << _T("CLASS:\t") << n->m_className << std::endl;\r
175                         m_log << _T("TITLE:\t") << n->m_titleName << std::endl;\r
176 \r
177                         bool isMDI = true;\r
178                         HWND hwnd = getToplevelWindow(reinterpret_cast<HWND>(n->m_hwnd), &isMDI);\r
179                         RECT rc;\r
180                         if (isMDI) {\r
181                                 getChildWindowRect(hwnd, &rc);\r
182                                 m_log << _T("MDI Window Position/Size: (")\r
183                                 << rc.left << _T(", ") << rc.top << _T(") / (")\r
184                                 << rcWidth(&rc) << _T("x") << rcHeight(&rc) << _T(")")\r
185                                 << std::endl;\r
186                                 hwnd = getToplevelWindow(reinterpret_cast<HWND>(n->m_hwnd), NULL);\r
187                         }\r
188 \r
189                         GetWindowRect(hwnd, &rc);\r
190                         m_log << _T("Toplevel Window Position/Size: (")\r
191                         << rc.left << _T(", ") << rc.top << _T(") / (")\r
192                         << rcWidth(&rc) << _T("x") << rcHeight(&rc) << _T(")")\r
193                         << std::endl;\r
194 \r
195                         SystemParametersInfo(SPI_GETWORKAREA, 0, (void *)&rc, FALSE);\r
196                         m_log << _T("Desktop Window Position/Size: (")\r
197                         << rc.left << _T(", ") << rc.top << _T(") / (")\r
198                         << rcWidth(&rc) << _T("x") << rcHeight(&rc) << _T(")")\r
199                         << std::endl;\r
200 \r
201                         m_log << std::endl;\r
202                         break;\r
203                 }\r
204 \r
205                 case Notify::Type_lockState: {\r
206                         NotifyLockState *n = (NotifyLockState *)cd->lpData;\r
207                         m_engine.setLockState(n->m_isNumLockToggled,\r
208                                                                   n->m_isCapsLockToggled,\r
209                                                                   n->m_isScrollLockToggled,\r
210                                                                   n->m_isKanaLockToggled,\r
211                                                                   n->m_isImeLockToggled,\r
212                                                                   n->m_isImeCompToggled);\r
213 #if 0\r
214                         Acquire a(&m_log, 0);\r
215                         if (n->m_isKanaLockToggled) {\r
216                                 m_log << _T("Notify::Type_lockState Kana on  : ");\r
217                         } else {\r
218                                 m_log << _T("Notify::Type_lockState Kana off : ");\r
219                         }\r
220                         m_log << n->m_debugParam << ", "\r
221                         << g_hookData->m_correctKanaLockHandling << std::endl;\r
222 #endif\r
223                         break;\r
224                 }\r
225 \r
226                 case Notify::Type_sync: {\r
227                         m_engine.syncNotify();\r
228                         break;\r
229                 }\r
230 \r
231                 case Notify::Type_threadDetach: {\r
232                         NotifyThreadDetach *n = (NotifyThreadDetach *)cd->lpData;\r
233                         m_engine.threadDetachNotify(n->m_threadId);\r
234                         break;\r
235                 }\r
236 \r
237                 case Notify::Type_command: {\r
238                         NotifyCommand *n = (NotifyCommand *)cd->lpData;\r
239                         m_engine.commandNotify(n->m_hwnd, n->m_message,\r
240                                                                    n->m_wParam, n->m_lParam);\r
241                         break;\r
242                 }\r
243 \r
244                 case Notify::Type_show: {\r
245                         NotifyShow *n = (NotifyShow *)cd->lpData;\r
246                         switch (n->m_show) {\r
247                         case NotifyShow::Show_Maximized:\r
248                                 m_engine.setShow(true, false, n->m_isMDI);\r
249                                 break;\r
250                         case NotifyShow::Show_Minimized:\r
251                                 m_engine.setShow(false, true, n->m_isMDI);\r
252                                 break;\r
253                         case NotifyShow::Show_Normal:\r
254                         default:\r
255                                 m_engine.setShow(false, false, n->m_isMDI);\r
256                                 break;\r
257                         }\r
258                         break;\r
259                 }\r
260 \r
261                 case Notify::Type_log: {\r
262                         Acquire a(&m_log, 1);\r
263                         NotifyLog *n = (NotifyLog *)cd->lpData;\r
264                         m_log << _T("hook log: ") << n->m_msg << std::endl;\r
265                         break;\r
266                 }\r
267                 }\r
268                 return true;\r
269         }\r
270 \r
271         /// window procedure for tasktray\r
272         static LRESULT CALLBACK\r
273         tasktray_wndProc(HWND i_hwnd, UINT i_message,\r
274                                          WPARAM i_wParam, LPARAM i_lParam) {\r
275 #ifdef MAYU64\r
276                 Mayu *This = reinterpret_cast<Mayu *>(GetWindowLongPtr(i_hwnd, 0));\r
277 #else\r
278                 Mayu *This = reinterpret_cast<Mayu *>(GetWindowLong(i_hwnd, 0));\r
279 #endif\r
280 \r
281                 if (!This)\r
282                         switch (i_message) {\r
283                         case WM_CREATE:\r
284                                 This = reinterpret_cast<Mayu *>(\r
285                                                    reinterpret_cast<CREATESTRUCT *>(i_lParam)->lpCreateParams);\r
286                                 This->m_fixScancodeMap.init(i_hwnd, WM_APP_escapeNLSKeysFailed);\r
287                                 if (This->m_escapeNlsKeys) {\r
288                                         This->m_fixScancodeMap.escape(true);\r
289                                 }\r
290 #ifdef MAYU64\r
291                                 SetWindowLongPtr(i_hwnd, 0, (LONG_PTR)This);\r
292 #else\r
293                                 SetWindowLong(i_hwnd, 0, (long)This);\r
294 #endif\r
295                                 return 0;\r
296                         }\r
297                 else\r
298                         switch (i_message) {\r
299                         case WM_COPYDATA: {\r
300                                 COPYDATASTRUCT *cd;\r
301                                 cd = reinterpret_cast<COPYDATASTRUCT *>(i_lParam);\r
302                                 return This->notifyHandler(cd);\r
303                         }\r
304                         case WM_QUERYENDSESSION:\r
305                                 if (!This->m_sessionState) {\r
306                                         if (This->m_escapeNlsKeys && This->m_engine.getIsEnabled()) {\r
307                                                 This->m_fixScancodeMap.escape(false);\r
308                                         }\r
309                                 }\r
310                                 This->m_sessionState |= Mayu::SESSION_END_QUERIED;\r
311                                 This->m_engine.prepairQuit();\r
312                                 PostQuitMessage(0);\r
313                                 return TRUE;\r
314 \r
315 #ifndef WM_WTSSESSION_CHANGE                    // WinUser.h\r
316 #  define WM_WTSSESSION_CHANGE            0x02B1\r
317 #endif\r
318                         case WM_WTSSESSION_CHANGE: {\r
319                                 const char *m = "";\r
320                                 switch (i_wParam) {\r
321 #ifndef WTS_CONSOLE_CONNECT                     // WinUser.h\r
322 #  define WTS_CONSOLE_CONNECT                0x1\r
323 #  define WTS_CONSOLE_DISCONNECT             0x2\r
324 #  define WTS_REMOTE_CONNECT                 0x3\r
325 #  define WTS_REMOTE_DISCONNECT              0x4\r
326 #  define WTS_SESSION_LOGON                  0x5\r
327 #  define WTS_SESSION_LOGOFF                 0x6\r
328 #  define WTS_SESSION_LOCK                   0x7\r
329 #  define WTS_SESSION_UNLOCK                 0x8\r
330 #endif\r
331                                 /*\r
332                                         restore NLS keys when any bits of m_sessionState is on\r
333                                         and\r
334                                         escape NLS keys when all bits of m_sessionState cleared\r
335                                 */\r
336                                 case WTS_CONSOLE_CONNECT:\r
337                                         This->m_sessionState &= ~Mayu::SESSION_DISCONNECTED;\r
338                                         if (!This->m_sessionState) {\r
339                                                 if (This->m_escapeNlsKeys && This->m_engine.getIsEnabled()) {\r
340                                                         This->m_fixScancodeMap.escape(true);\r
341                                                 }\r
342                                         }\r
343                                         m = "WTS_CONSOLE_CONNECT";\r
344                                         break;\r
345                                 case WTS_CONSOLE_DISCONNECT:\r
346                                         if (!This->m_sessionState) {\r
347                                                 if (This->m_escapeNlsKeys && This->m_engine.getIsEnabled()) {\r
348                                                         This->m_fixScancodeMap.escape(false);\r
349                                                 }\r
350                                         }\r
351                                         This->m_sessionState |= Mayu::SESSION_DISCONNECTED;\r
352                                         m = "WTS_CONSOLE_DISCONNECT";\r
353                                         break;\r
354                                 case WTS_REMOTE_CONNECT:\r
355                                         This->m_sessionState &= ~Mayu::SESSION_DISCONNECTED;\r
356                                         if (!This->m_sessionState) {\r
357                                                 if (This->m_escapeNlsKeys && This->m_engine.getIsEnabled()) {\r
358                                                         This->m_fixScancodeMap.escape(true);\r
359                                                 }\r
360                                         }\r
361                                         m = "WTS_REMOTE_CONNECT";\r
362                                         break;\r
363                                 case WTS_REMOTE_DISCONNECT:\r
364                                         if (!This->m_sessionState) {\r
365                                                 if (This->m_escapeNlsKeys && This->m_engine.getIsEnabled()) {\r
366                                                         This->m_fixScancodeMap.escape(false);\r
367                                                 }\r
368                                         }\r
369                                         This->m_sessionState |= Mayu::SESSION_DISCONNECTED;\r
370                                         m = "WTS_REMOTE_DISCONNECT";\r
371                                         break;\r
372                                 case WTS_SESSION_LOGON:\r
373                                         m = "WTS_SESSION_LOGON";\r
374                                         break;\r
375                                 case WTS_SESSION_LOGOFF:\r
376                                         m = "WTS_SESSION_LOGOFF";\r
377                                         break;\r
378                                 case WTS_SESSION_LOCK: {\r
379                                         if (!This->m_sessionState) {\r
380                                                 if (This->m_escapeNlsKeys && This->m_engine.getIsEnabled()) {\r
381                                                         This->m_fixScancodeMap.escape(false);\r
382                                                 }\r
383                                         }\r
384                                         This->m_sessionState |= Mayu::SESSION_LOCKED;\r
385                                         m = "WTS_SESSION_LOCK";\r
386                                         break;\r
387                            }\r
388                                 case WTS_SESSION_UNLOCK: {\r
389                                         This->m_sessionState &= ~Mayu::SESSION_LOCKED;\r
390                                         if (!This->m_sessionState) {\r
391                                                 if (This->m_escapeNlsKeys && This->m_engine.getIsEnabled()) {\r
392                                                         This->m_fixScancodeMap.escape(true);\r
393                                                 }\r
394                                         }\r
395                                         m = "WTS_SESSION_UNLOCK";\r
396                                         break;\r
397                                 }\r
398                                         //case WTS_SESSION_REMOTE_CONTROL: m = "WTS_SESSION_REMOTE_CONTROL"; break;\r
399                                 }\r
400                                 This->m_log << _T("WM_WTSESSION_CHANGE(")\r
401                                 << i_wParam << ", " << i_lParam << "): "\r
402                                 << m << std::endl;\r
403                                 return TRUE;\r
404                         }\r
405                         case WM_APP_msgStreamNotify: {\r
406                                 tomsgstream::StreamBuf *log =\r
407                                         reinterpret_cast<tomsgstream::StreamBuf *>(i_lParam);\r
408                                 const tstring &str = log->acquireString();\r
409 #ifdef LOG_TO_FILE\r
410                                 This->m_logFile << str << std::flush;\r
411 #endif // LOG_TO_FILE\r
412                                 editInsertTextAtLast(GetDlgItem(This->m_hwndLog, IDC_EDIT_log),\r
413                                                                          str, 65000);\r
414                                 log->releaseString();\r
415                                 return 0;\r
416                         }\r
417 \r
418                         case WM_APP_taskTrayNotify: {\r
419                                 if (i_wParam == ID_TaskTrayIcon)\r
420                                         switch (i_lParam) {\r
421                                         case WM_RBUTTONUP: {\r
422                                                 POINT p;\r
423                                                 CHECK_TRUE( GetCursorPos(&p) );\r
424                                                 SetForegroundWindow(i_hwnd);\r
425                                                 HMENU hMenuSub = GetSubMenu(This->m_hMenuTaskTray, 0);\r
426                                                 if (This->m_engine.getIsEnabled())\r
427                                                         CheckMenuItem(hMenuSub, ID_MENUITEM_disable,\r
428                                                                                   MF_UNCHECKED | MF_BYCOMMAND);\r
429                                                 else\r
430                                                         CheckMenuItem(hMenuSub, ID_MENUITEM_disable,\r
431                                                                                   MF_CHECKED | MF_BYCOMMAND);\r
432                                                 CHECK_TRUE( SetMenuDefaultItem(hMenuSub,\r
433                                                                                                            ID_MENUITEM_investigate, FALSE) );\r
434 \r
435                                                 // create reload menu\r
436                                                 HMENU hMenuSubSub = GetSubMenu(hMenuSub, 1);\r
437                                                 Registry reg(MAYU_REGISTRY_ROOT);\r
438                                                 int mayuIndex;\r
439                                                 reg.read(_T(".mayuIndex"), &mayuIndex, 0);\r
440                                                 while (DeleteMenu(hMenuSubSub, 0, MF_BYPOSITION))\r
441                                                         ;\r
442                                                 tregex getName(_T("^([^;]*);"));\r
443                                                 for (int index = 0; ; index ++) {\r
444                                                         _TCHAR buf[100];\r
445                                                         _sntprintf(buf, NUMBER_OF(buf), _T(".mayu%d"), index);\r
446                                                         tstringi dot_mayu;\r
447                                                         if (!reg.read(buf, &dot_mayu))\r
448                                                                 break;\r
449                                                         tsmatch what;\r
450                                                         if (boost::regex_search(dot_mayu, what, getName)) {\r
451                                                                 MENUITEMINFO mii;\r
452                                                                 std::memset(&mii, 0, sizeof(mii));\r
453                                                                 mii.cbSize = sizeof(mii);\r
454                                                                 mii.fMask = MIIM_ID | MIIM_STATE | MIIM_TYPE;\r
455                                                                 mii.fType = MFT_STRING;\r
456                                                                 mii.fState =\r
457                                                                         MFS_ENABLED | ((mayuIndex == index) ? MFS_CHECKED : 0);\r
458                                                                 mii.wID = ID_MENUITEM_reloadBegin + index;\r
459                                                                 tstringi name(what.str(1));\r
460                                                                 mii.dwTypeData = const_cast<_TCHAR *>(name.c_str());\r
461                                                                 mii.cch = name.size();\r
462 \r
463                                                                 InsertMenuItem(hMenuSubSub, index, TRUE, &mii);\r
464                                                         }\r
465                                                 }\r
466 \r
467                                                 // show popup menu\r
468                                                 TrackPopupMenu(hMenuSub, TPM_LEFTALIGN,\r
469                                                                            p.x, p.y, 0, i_hwnd, NULL);\r
470                                                 // TrackPopupMenu may fail (ERROR_POPUP_ALREADY_ACTIVE)\r
471                                                 break;\r
472                                         }\r
473 \r
474                                         case WM_LBUTTONDBLCLK:\r
475                                                 SendMessage(i_hwnd, WM_COMMAND,\r
476                                                                         MAKELONG(ID_MENUITEM_investigate, 0), 0);\r
477                                                 break;\r
478                                         }\r
479                                 return 0;\r
480                         }\r
481 \r
482                         case WM_APP_escapeNLSKeysFailed:\r
483                                 if (i_lParam) {\r
484                                         This->m_log << _T("escape NLS keys done code=") << i_wParam << std::endl;\r
485                                         if (i_wParam != YAMY_SUCCESS && i_wParam != YAMY_ERROR_RETRY_INJECTION_SUCCESS) {\r
486                                                 int ret = This->errorDialogWithCode(IDS_escapeNlsKeysFailed, i_wParam, MB_RETRYCANCEL | MB_ICONSTOP);\r
487                                                 if (ret == IDRETRY) {\r
488                                                         This->m_fixScancodeMap.escape(true);\r
489                                                 }\r
490                                         }\r
491                                 } else {\r
492                                         This->m_log << _T("restore NLS keys done with code=") << i_wParam << std::endl;\r
493                                 }\r
494                                 return 0;\r
495                                 break;\r
496 \r
497                         case WM_COMMAND: {\r
498                                 int notify_code = HIWORD(i_wParam);\r
499                                 int id = LOWORD(i_wParam);\r
500                                 if (notify_code == 0) // menu\r
501                                         switch (id) {\r
502                                         default:\r
503                                                 if (ID_MENUITEM_reloadBegin <= id) {\r
504                                                         Registry reg(MAYU_REGISTRY_ROOT);\r
505                                                         reg.write(_T(".mayuIndex"), id - ID_MENUITEM_reloadBegin);\r
506                                                         This->load();\r
507                                                 }\r
508                                                 break;\r
509                                         case ID_MENUITEM_reload:\r
510                                                 This->load();\r
511                                                 break;\r
512                                         case ID_MENUITEM_investigate: {\r
513                                                 ShowWindow(This->m_hwndLog, SW_SHOW);\r
514                                                 ShowWindow(This->m_hwndInvestigate, SW_SHOW);\r
515 \r
516                                                 RECT rc1, rc2;\r
517                                                 GetWindowRect(This->m_hwndInvestigate, &rc1);\r
518                                                 GetWindowRect(This->m_hwndLog, &rc2);\r
519 \r
520                                                 MoveWindow(This->m_hwndLog, rc1.left, rc1.bottom,\r
521                                                                    rcWidth(&rc1), rcHeight(&rc2), TRUE);\r
522 \r
523                                                 SetForegroundWindow(This->m_hwndLog);\r
524                                                 SetForegroundWindow(This->m_hwndInvestigate);\r
525                                                 break;\r
526                                         }\r
527                                         case ID_MENUITEM_setting:\r
528                                                 if (!This->m_isSettingDialogOpened) {\r
529                                                         This->m_isSettingDialogOpened = true;\r
530                                                         if (DialogBox(g_hInst, MAKEINTRESOURCE(IDD_DIALOG_setting),\r
531                                                                                   NULL, dlgSetting_dlgProc))\r
532                                                                 This->load();\r
533                                                         This->m_isSettingDialogOpened = false;\r
534                                                 }\r
535                                                 break;\r
536                                         case ID_MENUITEM_log:\r
537                                                 ShowWindow(This->m_hwndLog, SW_SHOW);\r
538                                                 SetForegroundWindow(This->m_hwndLog);\r
539                                                 break;\r
540                                         case ID_MENUITEM_check: {\r
541                                                 BOOL ret;\r
542                                                 BYTE keys[256];\r
543                                                 ret = GetKeyboardState(keys);\r
544                                                 if (ret == 0) {\r
545                                                         This->m_log << _T("Check Keystate Failed(%d)")\r
546                                                         << GetLastError() << std::endl;\r
547                                                 } else {\r
548                                                         This->m_log << _T("Check Keystate: ") << std::endl;\r
549                                                         for (int i = 0; i < 0xff; i++) {\r
550                                                                 USHORT asyncKey;\r
551                                                                 asyncKey = GetAsyncKeyState(i);\r
552                                                                 This->m_log << std::hex;\r
553                                                                 if (asyncKey & 0x8000) {\r
554                                                                         This->m_log << _T("  ") << VK2TCHAR[i]\r
555                                                                         << _T("(0x") << i << _T("): pressed!")\r
556                                                                         << std::endl;\r
557                                                                 }\r
558                                                                 if (i == 0x14 || // VK_CAPTITAL\r
559                                                                                 i == 0x15 || // VK_KANA\r
560                                                                                 i == 0x19 || // VK_KANJI\r
561                                                                                 i == 0x90 || // VK_NUMLOCK\r
562                                                                                 i == 0x91    // VK_SCROLL\r
563                                                                    ) {\r
564                                                                         if (keys[i] & 1) {\r
565                                                                                 This->m_log << _T("  ") << VK2TCHAR[i]\r
566                                                                                 << _T("(0x") << i << _T("): locked!")\r
567                                                                                 << std::endl;\r
568                                                                         }\r
569                                                                 }\r
570                                                                 This->m_log << std::dec;\r
571                                                         }\r
572                                                         This->m_log << std::endl;\r
573                                                 }\r
574                                                 break;\r
575                                         }\r
576                                         case ID_MENUITEM_version:\r
577                                                 ShowWindow(This->m_hwndVersion, SW_SHOW);\r
578                                                 SetForegroundWindow(This->m_hwndVersion);\r
579                                                 break;\r
580                                         case ID_MENUITEM_help: {\r
581                                                 _TCHAR buf[GANA_MAX_PATH];\r
582                                                 CHECK_TRUE( GetModuleFileName(g_hInst, buf, NUMBER_OF(buf)) );\r
583                                                 tstringi helpFilename = pathRemoveFileSpec(buf);\r
584                                                 helpFilename += _T("\\");\r
585                                                 helpFilename += loadString(IDS_helpFilename);\r
586                                                 ShellExecute(NULL, _T("open"), helpFilename.c_str(),\r
587                                                                          NULL, NULL, SW_SHOWNORMAL);\r
588                                                 break;\r
589                                         }\r
590                                         case ID_MENUITEM_disable:\r
591                                                 This->m_engine.enable(!This->m_engine.getIsEnabled());\r
592                                                 if (This->m_engine.getIsEnabled()) {\r
593                                                         This->m_fixScancodeMap.escape(true);\r
594                                                 } else {\r
595                                                         This->m_fixScancodeMap.escape(false);\r
596                                                 }\r
597                                                 This->showTasktrayIcon();\r
598                                                 break;\r
599                                         case ID_MENUITEM_quit:\r
600                                                 This->m_engine.prepairQuit();\r
601                                                 PostQuitMessage(0);\r
602                                                 break;\r
603                                         }\r
604                                 return 0;\r
605                         }\r
606 \r
607                         case WM_APP_engineNotify: {\r
608                                 switch (i_wParam) {\r
609                                 case EngineNotify_shellExecute:\r
610                                         This->m_engine.shellExecute();\r
611                                         break;\r
612                                 case EngineNotify_loadSetting:\r
613                                         This->load();\r
614                                         break;\r
615                                 case EngineNotify_helpMessage:\r
616                                         This->showHelpMessage(false);\r
617                                         if (i_lParam)\r
618                                                 This->showHelpMessage(true);\r
619                                         break;\r
620                                 case EngineNotify_showDlg: {\r
621                                         // show investigate/log window\r
622                                         int sw = (i_lParam & ~MayuDialogType_mask);\r
623                                         HWND hwnd = NULL;\r
624                                         switch (static_cast<MayuDialogType>(\r
625                                                                 i_lParam & MayuDialogType_mask)) {\r
626                                         case MayuDialogType_investigate:\r
627                                                 hwnd = This->m_hwndInvestigate;\r
628                                                 break;\r
629                                         case MayuDialogType_log:\r
630                                                 hwnd = This->m_hwndLog;\r
631                                                 break;\r
632                                         }\r
633                                         if (hwnd) {\r
634                                                 ShowWindow(hwnd, sw);\r
635                                                 switch (sw) {\r
636                                                 case SW_SHOWNORMAL:\r
637                                                 case SW_SHOWMAXIMIZED:\r
638                                                 case SW_SHOW:\r
639                                                 case SW_RESTORE:\r
640                                                 case SW_SHOWDEFAULT:\r
641                                                         SetForegroundWindow(hwnd);\r
642                                                         break;\r
643                                                 }\r
644                                         }\r
645                                         break;\r
646                                 }\r
647                                 case EngineNotify_setForegroundWindow:\r
648                                         // FIXME: completely useless. why ?\r
649                                         setForegroundWindow(reinterpret_cast<HWND>(i_lParam));\r
650                                         {\r
651                                                 Acquire a(&This->m_log, 1);\r
652                                                 This->m_log << _T("setForegroundWindow(0x")\r
653                                                 << std::hex << i_lParam << std::dec << _T(")")\r
654                                                 << std::endl;\r
655                                         }\r
656                                         break;\r
657                                 case EngineNotify_clearLog:\r
658                                         SendMessage(This->m_hwndLog, WM_COMMAND,\r
659                                                                 MAKELONG(IDC_BUTTON_clearLog, 0), 0);\r
660                                         break;\r
661                                 default:\r
662                                         break;\r
663                                 }\r
664                                 return 0;\r
665                         }\r
666 \r
667                         case WM_APP_dlglogNotify: {\r
668                                 switch (i_wParam) {\r
669                                 case DlgLogNotify_logCleared:\r
670                                         This->showBanner(true);\r
671                                         break;\r
672                                 default:\r
673                                         break;\r
674                                 }\r
675                                 return 0;\r
676                         }\r
677 \r
678                         case WM_DESTROY:\r
679                                 if (This->m_usingSN) {\r
680                                         wtsUnRegisterSessionNotification(i_hwnd);\r
681                                         This->m_usingSN = false;\r
682                                 }\r
683                                 if (!This->m_sessionState) {\r
684                                         if (This->m_escapeNlsKeys && This->m_engine.getIsEnabled()) {\r
685                                                 This->m_fixScancodeMap.escape(false);\r
686                                         }\r
687                                 }\r
688                                 return 0;\r
689 \r
690                         default:\r
691                                 if (i_message == This->m_WM_TaskbarRestart) {\r
692                                         if (This->showTasktrayIcon(true)) {\r
693                                                 Acquire a(&This->m_log, 0);\r
694                                                 This->m_log << _T("Tasktray icon is updated.") << std::endl;\r
695                                         } else {\r
696                                                 Acquire a(&This->m_log, 1);\r
697                                                 This->m_log << _T("Tasktray icon already exists.") << std::endl;\r
698                                         }\r
699                                         return 0;\r
700                                 } else if (i_message == This->m_WM_MayuIPC) {\r
701                                         switch (static_cast<MayuIPCCommand>(i_wParam)) {\r
702                                         case MayuIPCCommand_Enable:\r
703                                                 This->m_engine.enable(!!i_lParam);\r
704                                                 if (This->m_engine.getIsEnabled()) {\r
705                                                         This->m_fixScancodeMap.escape(true);\r
706                                                 } else {\r
707                                                         This->m_fixScancodeMap.escape(false);\r
708                                                 }\r
709                                                 This->showTasktrayIcon();\r
710                                                 if (i_lParam) {\r
711                                                         Acquire a(&This->m_log, 1);\r
712                                                         This->m_log << _T("Enabled by another application.")\r
713                                                         << std::endl;\r
714                                                 } else {\r
715                                                         Acquire a(&This->m_log, 1);\r
716                                                         This->m_log << _T("Disabled by another application.")\r
717                                                         << std::endl;\r
718                                                 }\r
719                                                 break;\r
720                                         }\r
721                                 }\r
722                         }\r
723                 return DefWindowProc(i_hwnd, i_message, i_wParam, i_lParam);\r
724         }\r
725 \r
726         /// load setting\r
727         void load() {\r
728                 Setting *newSetting = new Setting;\r
729 \r
730                 // set symbol\r
731                 for (int i = 1; i < __argc; ++ i) {\r
732                         if (__targv[i][0] == _T('-') && __targv[i][1] == _T('D'))\r
733                                 newSetting->m_symbols.insert(__targv[i] + 2);\r
734                 }\r
735 \r
736                 if (!SettingLoader(&m_log, &m_log).load(newSetting)) {\r
737                         ShowWindow(m_hwndLog, SW_SHOW);\r
738                         SetForegroundWindow(m_hwndLog);\r
739                         delete newSetting;\r
740                         Acquire a(&m_log, 0);\r
741                         m_log << _T("error: failed to load.") << std::endl;\r
742                         return;\r
743                 }\r
744                 m_log << _T("successfully loaded.") << std::endl;\r
745                 while (!m_engine.setSetting(newSetting))\r
746                         Sleep(1000);\r
747                 delete m_setting;\r
748                 m_setting = newSetting;\r
749         }\r
750 \r
751         // show message (a baloon from the task tray icon)\r
752         void showHelpMessage(bool i_doesShow = true) {\r
753                 if (m_canUseTasktrayBaloon) {\r
754                         if (i_doesShow) {\r
755                                 tstring helpMessage, helpTitle;\r
756                                 m_engine.getHelpMessages(&helpMessage, &helpTitle);\r
757                                 tcslcpy(m_ni.szInfo, helpMessage.c_str(), NUMBER_OF(m_ni.szInfo));\r
758                                 tcslcpy(m_ni.szInfoTitle, helpTitle.c_str(),\r
759                                                 NUMBER_OF(m_ni.szInfoTitle));\r
760                                 m_ni.dwInfoFlags = NIIF_INFO;\r
761                         } else\r
762                                 m_ni.szInfo[0] = m_ni.szInfoTitle[0] = _T('\0');\r
763                         CHECK_TRUE( Shell_NotifyIcon(NIM_MODIFY, &m_ni) );\r
764                 }\r
765         }\r
766 \r
767         // change the task tray icon\r
768         bool showTasktrayIcon(bool i_doesAdd = false) {\r
769                 m_ni.hIcon  = m_tasktrayIcon[m_engine.getIsEnabled() ? 1 : 0];\r
770                 m_ni.szInfo[0] = m_ni.szInfoTitle[0] = _T('\0');\r
771                 if (i_doesAdd) {\r
772                         // http://support.microsoft.com/kb/418138/JA/\r
773                         int guard = 60;\r
774                         for (; !Shell_NotifyIcon(NIM_ADD, &m_ni) && 0 < guard; -- guard) {\r
775                                 if (Shell_NotifyIcon(NIM_MODIFY, &m_ni)) {\r
776                                         return true;\r
777                                 }\r
778                                 Sleep(1000);                            // 1sec\r
779                         }\r
780                         return 0 < guard;\r
781                 } else {\r
782                         return !!Shell_NotifyIcon(NIM_MODIFY, &m_ni);\r
783                 }\r
784         }\r
785 \r
786         void showBanner(bool i_isCleared) {\r
787                 time_t now;\r
788                 time(&now);\r
789 \r
790                 _TCHAR starttimebuf[1024];\r
791                 _TCHAR timebuf[1024];\r
792 \r
793 #ifdef __BORLANDC__\r
794 #pragma message("\t\t****\tAfter std::ostream() is called,  ")\r
795 #pragma message("\t\t****\tstrftime(... \"%%#c\" ...) fails.")\r
796 #pragma message("\t\t****\tWhy ? Bug of Borland C++ 5.5.1 ? ")\r
797 #pragma message("\t\t****\t                         - nayuta")\r
798                 _tcsftime(timebuf, NUMBER_OF(timebuf), _T("%Y/%m/%d %H:%M:%S"),\r
799                                   localtime(&now));\r
800                 _tcsftime(starttimebuf, NUMBER_OF(starttimebuf), _T("%Y/%m/%d %H:%M:%S"),\r
801                                   localtime(&m_startTime));\r
802 #else\r
803                 _tcsftime(timebuf, NUMBER_OF(timebuf), _T("%#c"), localtime(&now));\r
804                 _tcsftime(starttimebuf, NUMBER_OF(starttimebuf), _T("%#c"),\r
805                                   localtime(&m_startTime));\r
806 #endif\r
807 \r
808                 Acquire a(&m_log, 0);\r
809                 m_log << _T("------------------------------------------------------------") << std::endl;\r
810                 m_log << loadString(IDS_mayu) << _T(" ") _T(VERSION);\r
811 #ifndef NDEBUG\r
812                 m_log << _T(" (DEBUG)");\r
813 #endif\r
814 #ifdef _UNICODE\r
815                 m_log << _T(" (UNICODE)");\r
816 #endif\r
817                 m_log << std::endl;\r
818                 m_log << _T("  built by ")\r
819                 << _T(LOGNAME) << _T("@") << toLower(_T(COMPUTERNAME))\r
820                 << _T(" (") << _T(__DATE__) <<  _T(" ")\r
821                 << _T(__TIME__) << _T(", ")\r
822                 << getCompilerVersionString() << _T(")") << std::endl;\r
823                 _TCHAR modulebuf[1024];\r
824                 CHECK_TRUE( GetModuleFileName(g_hInst, modulebuf,\r
825                                                                           NUMBER_OF(modulebuf)) );\r
826                 m_log << _T("started at ") << starttimebuf << std::endl;\r
827                 m_log << modulebuf << std::endl;\r
828                 m_log << _T("------------------------------------------------------------") << std::endl;\r
829 \r
830                 if (i_isCleared) {\r
831                         m_log << _T("log was cleared at ") << timebuf << std::endl;\r
832                 } else {\r
833                         m_log << _T("log begins at ") << timebuf << std::endl;\r
834                 }\r
835         }\r
836 \r
837         int errorDialogWithCode(UINT ids, int code, UINT style = MB_OK | MB_ICONSTOP)\r
838         {\r
839                 _TCHAR title[1024];\r
840                 _TCHAR text[1024];\r
841 \r
842                 _sntprintf_s(title, NUMBER_OF(title), _TRUNCATE, loadString(IDS_mayu).c_str());\r
843                 _sntprintf_s(text, NUMBER_OF(text), _TRUNCATE, loadString(ids).c_str(), code);\r
844                 return MessageBox((HWND)NULL, text, title, style);\r
845         }\r
846 \r
847         int enableToWriteByUser(HANDLE hdl)\r
848         {\r
849                 TCHAR userName[GANA_MAX_ATOM_LENGTH];\r
850                 DWORD userNameSize = NUMBER_OF(userName);\r
851 \r
852                 SID_NAME_USE sidType;\r
853                 PSID pSid = NULL;\r
854                 DWORD sidSize = 0;\r
855                 TCHAR *pDomain = NULL;\r
856                 DWORD domainSize = 0;\r
857 \r
858                 PSECURITY_DESCRIPTOR pSd;\r
859                 PACL pOrigDacl;\r
860                 ACL_SIZE_INFORMATION aclInfo;\r
861 \r
862                 PACL pNewDacl;\r
863                 DWORD newDaclSize;\r
864 \r
865                 DWORD aceIndex;\r
866                 DWORD newAceIndex = 0;\r
867 \r
868                 BOOL ret;\r
869                 int err = 0;\r
870 \r
871                 ret = GetUserName(userName, &userNameSize);\r
872                 if (ret == FALSE) {\r
873                         err = YAMY_ERROR_ON_GET_USERNAME;\r
874                         goto exit;\r
875                 }\r
876 \r
877                 // get buffer size for pSid (and pDomain)\r
878                 ret = LookupAccountName(NULL, userName, pSid, &sidSize, pDomain, &domainSize, &sidType);\r
879                 if (ret != FALSE || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {\r
880                         // above call should fail by ERROR_INSUFFICIENT_BUFFER\r
881                         err = YAMY_ERROR_ON_GET_LOGONUSERNAME;\r
882                         goto exit;\r
883                 }\r
884 \r
885                 pSid = reinterpret_cast<PSID>(LocalAlloc(LPTR, sidSize));\r
886                 pDomain = reinterpret_cast<TCHAR*>(LocalAlloc(LPTR, domainSize * sizeof(TCHAR)));\r
887                 if (pSid == NULL || pDomain == NULL) {\r
888                         err = YAMY_ERROR_NO_MEMORY;\r
889                         goto exit;\r
890                 }\r
891 \r
892                 // get SID (and Domain) for logoned user\r
893                 ret = LookupAccountName(NULL, userName, pSid, &sidSize, pDomain, &domainSize, &sidType);\r
894                 if (ret == FALSE) {\r
895                         // LookupAccountName() should success in this time\r
896                         err = YAMY_ERROR_ON_GET_LOGONUSERNAME;\r
897                         goto exit;\r
898                 }\r
899 \r
900                 // get DACL for hdl\r
901                 ret = GetSecurityInfo(hdl, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pOrigDacl, NULL, &pSd);\r
902                 if (ret != ERROR_SUCCESS) {\r
903                         err = YAMY_ERROR_ON_GET_SECURITYINFO;\r
904                         goto exit;\r
905                 }\r
906 \r
907                 // get size for original DACL\r
908                 ret = GetAclInformation(pOrigDacl, &aclInfo, sizeof(aclInfo), AclSizeInformation);\r
909                 if (ret == FALSE) {\r
910                         err = YAMY_ERROR_ON_GET_DACL;\r
911                         goto exit;\r
912                 }\r
913 \r
914                 // compute size for new DACL\r
915                 newDaclSize = aclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pSid) - sizeof(DWORD);\r
916 \r
917                 // allocate memory for new DACL\r
918                 pNewDacl = reinterpret_cast<PACL>(LocalAlloc(LPTR, newDaclSize));\r
919                 if (pNewDacl == NULL) {\r
920                         err = YAMY_ERROR_NO_MEMORY;\r
921                         goto exit;\r
922                 }\r
923 \r
924                 // initialize new DACL\r
925                 ret = InitializeAcl(pNewDacl, newDaclSize, ACL_REVISION);\r
926                 if (ret == FALSE) {\r
927                         err = YAMY_ERROR_ON_INITIALIZE_ACL;\r
928                         goto exit;\r
929                 }\r
930 \r
931                 // copy original DACL to new DACL\r
932                 for (aceIndex = 0; aceIndex < aclInfo.AceCount; aceIndex++) {\r
933                         LPVOID pAce;\r
934 \r
935                         ret = GetAce(pOrigDacl, aceIndex, &pAce);\r
936                         if (ret == FALSE) {\r
937                                 err = YAMY_ERROR_ON_GET_ACE;\r
938                                 goto exit;\r
939                         }\r
940 \r
941                         if ((reinterpret_cast<ACCESS_ALLOWED_ACE*>(pAce))->Header.AceFlags & INHERITED_ACE) {\r
942                                 break;\r
943                         }\r
944 \r
945                         if (EqualSid(pSid, &(reinterpret_cast<ACCESS_ALLOWED_ACE*>(pAce))->SidStart) != FALSE) {\r
946                                 continue;\r
947                         }\r
948 \r
949                         ret = AddAce(pNewDacl, ACL_REVISION, MAXDWORD, pAce, (reinterpret_cast<PACE_HEADER>(pAce))->AceSize);\r
950                         if (ret == FALSE) {\r
951                                 err = YAMY_ERROR_ON_ADD_ACE;\r
952                                 goto exit;\r
953                         }\r
954 \r
955                         newAceIndex++;\r
956                 }\r
957 \r
958                 ret = AddAccessAllowedAce(pNewDacl, ACL_REVISION, GENERIC_ALL, pSid);\r
959                 if (ret == FALSE) {\r
960                         err = YAMY_ERROR_ON_ADD_ALLOWED_ACE;\r
961                         goto exit;\r
962                 }\r
963 \r
964                 // copy the rest of inherited ACEs\r
965                 for (; aceIndex < aclInfo.AceCount; aceIndex++) {\r
966                         LPVOID pAce;\r
967 \r
968                         ret = GetAce(pOrigDacl, aceIndex, &pAce);\r
969                         if (ret == FALSE) {\r
970                                 err = YAMY_ERROR_ON_GET_ACE;\r
971                                 goto exit;\r
972                         }\r
973 \r
974                         ret = AddAce(pNewDacl, ACL_REVISION, MAXDWORD, pAce, (reinterpret_cast<PACE_HEADER>(pAce))->AceSize);\r
975                         if (ret == FALSE) {\r
976                                 err = YAMY_ERROR_ON_ADD_ACE;\r
977                                 goto exit;\r
978                         }\r
979                 }\r
980 \r
981                 ret = SetSecurityInfo(hdl, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, pNewDacl, NULL);\r
982                 if (ret != ERROR_SUCCESS) {\r
983                         err = YAMY_ERROR_ON_SET_SECURITYINFO;\r
984                 }\r
985 \r
986 exit:\r
987                 LocalFree(pSd);\r
988                 LocalFree(pSid);\r
989                 LocalFree(pDomain);\r
990                 LocalFree(pNewDacl);\r
991 \r
992                 return err;\r
993         }\r
994 \r
995 public:\r
996         ///\r
997         Mayu(HANDLE i_mutex)\r
998                         : m_hwndTaskTray(NULL),\r
999                         m_mutex(i_mutex),\r
1000                         m_hwndLog(NULL),\r
1001                         m_WM_TaskbarRestart(RegisterWindowMessage(_T("TaskbarCreated"))),\r
1002                         m_WM_MayuIPC(RegisterWindowMessage(WM_MayuIPC_NAME)),\r
1003                         m_canUseTasktrayBaloon(\r
1004                                 PACKVERSION(5, 0) <= getDllVersion(_T("shlwapi.dll"))),\r
1005                         m_log(WM_APP_msgStreamNotify),\r
1006                         m_setting(NULL),\r
1007                         m_isSettingDialogOpened(false),\r
1008                         m_sessionState(0),\r
1009                         m_engine(m_log) {\r
1010                 Registry reg(MAYU_REGISTRY_ROOT);\r
1011                 reg.read(_T("escapeNLSKeys"), &m_escapeNlsKeys, 0);\r
1012 #ifdef USE_MAILSLOT\r
1013                 m_hNotifyMailslot = CreateMailslot(NOTIFY_MAILSLOT_NAME, 0, MAILSLOT_WAIT_FOREVER, (SECURITY_ATTRIBUTES *)NULL);\r
1014                 ASSERT(m_hNotifyMailslot != INVALID_HANDLE_VALUE);\r
1015                 int err;\r
1016                 if (checkWindowsVersion(6, 0) != FALSE) { // enableToWriteByUser() is available only Vista or later\r
1017                         err = enableToWriteByUser(m_hNotifyMailslot);\r
1018                         if (err) {\r
1019                                 errorDialogWithCode(IDS_cannotPermitStandardUser, err);\r
1020                         }\r
1021                 }\r
1022 \r
1023                 m_hNotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);\r
1024                 ASSERT(m_hNotifyEvent);\r
1025                 m_olNotify.Offset = 0;\r
1026                 m_olNotify.OffsetHigh = 0;\r
1027                 m_olNotify.hEvent = m_hNotifyEvent;\r
1028 #endif // USE_MAILSLOT\r
1029                 time(&m_startTime);\r
1030 \r
1031                 CHECK_TRUE( Register_focus() );\r
1032                 CHECK_TRUE( Register_target() );\r
1033                 CHECK_TRUE( Register_tasktray() );\r
1034 \r
1035                 // change dir\r
1036 #if 0\r
1037                 HomeDirectories pathes;\r
1038                 getHomeDirectories(&pathes);\r
1039                 for (HomeDirectories::iterator i = pathes.begin(); i != pathes.end(); ++ i)\r
1040                         if (SetCurrentDirectory(i->c_str()))\r
1041                                 break;\r
1042 #endif\r
1043 \r
1044                 // create windows, dialogs\r
1045                 tstringi title = loadString(IDS_mayu);\r
1046                 m_hwndTaskTray = CreateWindow(_T("mayuTasktray"), title.c_str(),\r
1047                                                                           WS_OVERLAPPEDWINDOW,\r
1048                                                                           CW_USEDEFAULT, CW_USEDEFAULT,\r
1049                                                                           CW_USEDEFAULT, CW_USEDEFAULT,\r
1050                                                                           NULL, NULL, g_hInst, this);\r
1051                 CHECK_TRUE( m_hwndTaskTray );\r
1052 \r
1053                 // set window handle of tasktray to hooks\r
1054 #ifndef USE_MAILSLOT\r
1055                 g_hookData->m_hwndTaskTray = reinterpret_cast<DWORD>(m_hwndTaskTray);\r
1056 #endif // !USE_MAILSLOT\r
1057                 CHECK_FALSE( installMessageHook() );\r
1058                 m_usingSN = wtsRegisterSessionNotification(m_hwndTaskTray,\r
1059                                         NOTIFY_FOR_THIS_SESSION);\r
1060 \r
1061                 DlgLogData dld;\r
1062                 dld.m_log = &m_log;\r
1063                 dld.m_hwndTaskTray = m_hwndTaskTray;\r
1064                 m_hwndLog =\r
1065                         CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_DIALOG_log), NULL,\r
1066                                                           dlgLog_dlgProc, (LPARAM)&dld);\r
1067                 CHECK_TRUE( m_hwndLog );\r
1068 \r
1069                 DlgInvestigateData did;\r
1070                 did.m_engine = &m_engine;\r
1071                 did.m_hwndLog = m_hwndLog;\r
1072                 m_hwndInvestigate =\r
1073                         CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_DIALOG_investigate), NULL,\r
1074                                                           dlgInvestigate_dlgProc, (LPARAM)&did);\r
1075                 CHECK_TRUE( m_hwndInvestigate );\r
1076 \r
1077                 m_hwndVersion =\r
1078                         CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_DIALOG_version),\r
1079                                                           NULL, dlgVersion_dlgProc,\r
1080                                                           (LPARAM)m_engine.getMayudVersion().c_str());\r
1081                 CHECK_TRUE( m_hwndVersion );\r
1082 \r
1083                 // attach log\r
1084 #ifdef LOG_TO_FILE\r
1085                 tstring path;\r
1086                 _TCHAR exePath[GANA_MAX_PATH];\r
1087                 _TCHAR exeDrive[GANA_MAX_PATH];\r
1088                 _TCHAR exeDir[GANA_MAX_PATH];\r
1089                 GetModuleFileName(NULL, exePath, GANA_MAX_PATH);\r
1090                 _tsplitpath_s(exePath, exeDrive, GANA_MAX_PATH, exeDir, GANA_MAX_PATH, NULL, 0, NULL, 0);\r
1091                 path = exeDrive;\r
1092                 path += exeDir;\r
1093                 path += _T("mayu.log");\r
1094                 m_logFile.open(path.c_str(), std::ios::app);\r
1095                 m_logFile.imbue(std::locale("japanese"));\r
1096 #endif // LOG_TO_FILE\r
1097                 SendMessage(GetDlgItem(m_hwndLog, IDC_EDIT_log), EM_SETLIMITTEXT, 0, 0);\r
1098                 m_log.attach(m_hwndTaskTray);\r
1099 \r
1100                 // start keyboard handler thread\r
1101                 m_engine.setAssociatedWndow(m_hwndTaskTray);\r
1102                 m_engine.start();\r
1103 \r
1104                 // show tasktray icon\r
1105                 m_tasktrayIcon[0] = loadSmallIcon(IDI_ICON_mayu_disabled);\r
1106                 m_tasktrayIcon[1] = loadSmallIcon(IDI_ICON_mayu);\r
1107                 std::memset(&m_ni, 0, sizeof(m_ni));\r
1108                 m_ni.uID    = ID_TaskTrayIcon;\r
1109                 m_ni.hWnd   = m_hwndTaskTray;\r
1110                 m_ni.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;\r
1111                 m_ni.hIcon  = m_tasktrayIcon[1];\r
1112                 m_ni.uCallbackMessage = WM_APP_taskTrayNotify;\r
1113                 tstring tip = loadString(IDS_mayu);\r
1114                 tcslcpy(m_ni.szTip, tip.c_str(), NUMBER_OF(m_ni.szTip));\r
1115                 if (m_canUseTasktrayBaloon) {\r
1116                         m_ni.cbSize = NOTIFYICONDATA_V3_SIZE;\r
1117                         m_ni.uFlags |= NIF_INFO;\r
1118                 } else\r
1119                         m_ni.cbSize = NOTIFYICONDATA_V1_SIZE;\r
1120                 showTasktrayIcon(true);\r
1121 \r
1122                 // create menu\r
1123                 m_hMenuTaskTray = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_MENU_tasktray));\r
1124                 ASSERT(m_hMenuTaskTray);\r
1125 \r
1126                 // set initial lock state\r
1127                 notifyLockState();\r
1128 \r
1129 #ifdef _WIN64\r
1130                 ZeroMemory(&m_pi,sizeof(m_pi));\r
1131                 ZeroMemory(&m_si,sizeof(m_si));\r
1132                 m_si.cb=sizeof(m_si);\r
1133 \r
1134                 // create mutex to block yamyd\r
1135                 m_hMutexYamyd = CreateMutex((SECURITY_ATTRIBUTES *)NULL, TRUE, MUTEX_YAMYD_BLOCKER);\r
1136 \r
1137                 BOOL result = CreateProcess(_T("yamyd32"), _T("yamyd32"), NULL, NULL, FALSE,\r
1138                                                            NORMAL_PRIORITY_CLASS, 0, NULL, &m_si, &m_pi);\r
1139                 if (result == FALSE) {\r
1140                         TCHAR buf[1024];\r
1141                         TCHAR text[1024];\r
1142                         TCHAR title[1024];\r
1143 \r
1144                         m_pi.hProcess = NULL;\r
1145                         LoadString(GetModuleHandle(NULL), IDS_cannotInvoke,\r
1146                                            text, sizeof(text)/sizeof(text[0]));\r
1147                         LoadString(GetModuleHandle(NULL), IDS_mayu,\r
1148                                            title, sizeof(title)/sizeof(title[0]));\r
1149                         _stprintf_s(buf, sizeof(buf)/sizeof(buf[0]),\r
1150                                                 text, _T("yamyd32"), GetLastError());\r
1151                         MessageBox((HWND)NULL, buf, title, MB_OK | MB_ICONSTOP);\r
1152                 } else {\r
1153                         CloseHandle(m_pi.hThread);\r
1154                 }\r
1155 #endif // _WIN64\r
1156         }\r
1157 \r
1158         ///\r
1159         ~Mayu() {\r
1160 #ifdef USE_MAILSLOT\r
1161                 CancelIo(m_hNotifyMailslot);\r
1162                 SleepEx(0, TRUE);\r
1163                 CloseHandle(m_hNotifyMailslot);\r
1164                 CloseHandle(m_hNotifyEvent);\r
1165 #endif // USE_MAILSLOT\r
1166                 ReleaseMutex(m_mutex);\r
1167                 WaitForSingleObject(m_mutex, INFINITE);\r
1168                 // first, detach log from edit control to avoid deadlock\r
1169                 m_log.detach();\r
1170 #ifdef LOG_TO_FILE\r
1171                 m_logFile.close();\r
1172 #endif // LOG_TO_FILE\r
1173 \r
1174                 // stop notify from mayu.dll\r
1175                 g_hookData->m_hwndTaskTray = NULL;\r
1176                 CHECK_FALSE( uninstallMessageHook() );\r
1177 \r
1178 #ifdef _WIN64\r
1179                 ReleaseMutex(m_hMutexYamyd);\r
1180                 if (m_pi.hProcess) {\r
1181                         WaitForSingleObject(m_pi.hProcess, 5000);\r
1182                         CloseHandle(m_pi.hProcess);\r
1183                 }\r
1184                 CloseHandle(m_hMutexYamyd);\r
1185 #endif // _WIN64\r
1186                 if (!(m_sessionState & SESSION_END_QUERIED)) {\r
1187                         DWORD_PTR result;\r
1188                         SendMessageTimeout(HWND_BROADCAST, WM_NULL, 0, 0, SMTO_ABORTIFHUNG, 3000, &result);\r
1189                 }\r
1190 \r
1191                 // destroy windows\r
1192                 CHECK_TRUE( DestroyWindow(m_hwndVersion) );\r
1193                 CHECK_TRUE( DestroyWindow(m_hwndInvestigate) );\r
1194                 CHECK_TRUE( DestroyWindow(m_hwndLog) );\r
1195                 CHECK_TRUE( DestroyWindow(m_hwndTaskTray) );\r
1196 \r
1197                 // destroy menu\r
1198                 DestroyMenu(m_hMenuTaskTray);\r
1199 \r
1200                 // delete tasktray icon\r
1201                 CHECK_TRUE( Shell_NotifyIcon(NIM_DELETE, &m_ni) );\r
1202                 CHECK_TRUE( DestroyIcon(m_tasktrayIcon[1]) );\r
1203                 CHECK_TRUE( DestroyIcon(m_tasktrayIcon[0]) );\r
1204 \r
1205                 // stop keyboard handler thread\r
1206                 m_engine.stop();\r
1207 \r
1208                 // remove setting;\r
1209                 delete m_setting;\r
1210         }\r
1211 \r
1212         /// message loop\r
1213         WPARAM messageLoop() {\r
1214                 showBanner(false);\r
1215                 load();\r
1216 \r
1217 #ifdef USE_MAILSLOT\r
1218                 mailslotHandler(0, 0);\r
1219                 while (1) {\r
1220                         HANDLE handles[] = { m_hNotifyEvent };\r
1221                         DWORD ret;\r
1222                         switch (ret = MsgWaitForMultipleObjectsEx(NUMBER_OF(handles), &handles[0],\r
1223                                                   INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE)) {\r
1224                         case WAIT_OBJECT_0:                     // m_hNotifyEvent\r
1225                                 break;\r
1226 \r
1227                         case WAIT_OBJECT_0 + NUMBER_OF(handles): {\r
1228                                 MSG msg;\r
1229                                 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0) {\r
1230                                         if (msg.message == WM_QUIT) {\r
1231                                                 return msg.wParam;\r
1232                                         }\r
1233                                         if (IsDialogMessage(m_hwndLog, &msg))\r
1234                                                 break;\r
1235                                         if (IsDialogMessage(m_hwndInvestigate, &msg))\r
1236                                                 break;\r
1237                                         if (IsDialogMessage(m_hwndVersion, &msg))\r
1238                                                 break;\r
1239                                         TranslateMessage(&msg);\r
1240                                         DispatchMessage(&msg);\r
1241                                         break;\r
1242                                 }\r
1243                                 break;\r
1244                         }\r
1245 \r
1246                         case WAIT_IO_COMPLETION:\r
1247                                 break;\r
1248 \r
1249                         case 0x102:\r
1250                         default:\r
1251                                 break;\r
1252                         }\r
1253                 }\r
1254 #else // !USE_MAILSLOT\r
1255                 MSG msg;\r
1256                 while (0 < GetMessage(&msg, NULL, 0, 0)) {\r
1257                         if (IsDialogMessage(m_hwndLog, &msg))\r
1258                                 continue;\r
1259                         if (IsDialogMessage(m_hwndInvestigate, &msg))\r
1260                                 continue;\r
1261                         if (IsDialogMessage(m_hwndVersion, &msg))\r
1262                                 continue;\r
1263                         TranslateMessage(&msg);\r
1264                         DispatchMessage(&msg);\r
1265                 }\r
1266                 return msg.wParam;\r
1267 #endif // !USE_MAILSLOT\r
1268         }\r
1269 };\r
1270 \r
1271 \r
1272 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
1273 // Functions\r
1274 \r
1275 \r
1276 /// convert registry\r
1277 void convertRegistry()\r
1278 {\r
1279         Registry reg(MAYU_REGISTRY_ROOT);\r
1280         tstringi dot_mayu;\r
1281         bool doesAdd = false;\r
1282         DWORD index;\r
1283         if (reg.read(_T(".mayu"), &dot_mayu)) {\r
1284                 reg.write(_T(".mayu0"), _T(";") + dot_mayu + _T(";"));\r
1285                 reg.remove(_T(".mayu"));\r
1286                 doesAdd = true;\r
1287                 index = 0;\r
1288         } else if (!reg.read(_T(".mayu0"), &dot_mayu)) {\r
1289                 reg.write(_T(".mayu0"), loadString(IDS_readFromHomeDirectory) + _T(";;"));\r
1290                 doesAdd = true;\r
1291                 index = 1;\r
1292         }\r
1293         if (doesAdd) {\r
1294                 Registry commonreg(HKEY_LOCAL_MACHINE, _T("Software\\GANAware\\mayu"));\r
1295                 tstringi dir, layout;\r
1296                 if (commonreg.read(_T("dir"), &dir) &&\r
1297                                 commonreg.read(_T("layout"), &layout)) {\r
1298                         tstringi tmp = _T(";") + dir + _T("\\dot.mayu");\r
1299                         if (layout == _T("109")) {\r
1300                                 reg.write(_T(".mayu1"), loadString(IDS_109Emacs) + tmp\r
1301                                                   + _T(";-DUSE109") _T(";-DUSEdefault"));\r
1302                                 reg.write(_T(".mayu2"), loadString(IDS_104on109Emacs) + tmp\r
1303                                                   + _T(";-DUSE109") _T(";-DUSEdefault") _T(";-DUSE104on109"));\r
1304                                 reg.write(_T(".mayu3"), loadString(IDS_109) + tmp\r
1305                                                   + _T(";-DUSE109"));\r
1306                                 reg.write(_T(".mayu4"), loadString(IDS_104on109) + tmp\r
1307                                                   + _T(";-DUSE109") _T(";-DUSE104on109"));\r
1308                         } else {\r
1309                                 reg.write(_T(".mayu1"), loadString(IDS_104Emacs) + tmp\r
1310                                                   + _T(";-DUSE104") _T(";-DUSEdefault"));\r
1311                                 reg.write(_T(".mayu2"), loadString(IDS_109on104Emacs) + tmp\r
1312                                                   + _T(";-DUSE104") _T(";-DUSEdefault") _T(";-DUSE109on104"));\r
1313                                 reg.write(_T(".mayu3"), loadString(IDS_104) + tmp\r
1314                                                   + _T(";-DUSE104"));\r
1315                                 reg.write(_T(".mayu4"), loadString(IDS_109on104) + tmp\r
1316                                                   + _T(";-DUSE104") _T(";-DUSE109on104"));\r
1317                         }\r
1318                         reg.write(_T(".mayuIndex"), index);\r
1319                 }\r
1320         }\r
1321 }\r
1322 \r
1323 \r
1324 /// main\r
1325 int WINAPI _tWinMain(HINSTANCE i_hInstance, HINSTANCE /* i_hPrevInstance */,\r
1326                                          LPTSTR /* i_lpszCmdLine */, int /* i_nCmdShow */)\r
1327 {\r
1328         g_hInst = i_hInstance;\r
1329 \r
1330         // set locale\r
1331         CHECK_TRUE( _tsetlocale(LC_ALL, _T("")) );\r
1332 \r
1333         // common controls\r
1334 #if defined(_WIN95)\r
1335         InitCommonControls();\r
1336 #else\r
1337         INITCOMMONCONTROLSEX icc;\r
1338         icc.dwSize = sizeof(icc);\r
1339         icc.dwICC = ICC_LISTVIEW_CLASSES;\r
1340         CHECK_TRUE( InitCommonControlsEx(&icc) );\r
1341 #endif\r
1342 \r
1343         // convert old registry to new registry\r
1344 #ifndef USE_INI\r
1345         convertRegistry();\r
1346 #endif // !USE_INI\r
1347 \r
1348         // is another mayu running ?\r
1349         HANDLE mutex = CreateMutex((SECURITY_ATTRIBUTES *)NULL, TRUE,\r
1350                                                            MUTEX_MAYU_EXCLUSIVE_RUNNING);\r
1351         if (GetLastError() == ERROR_ALREADY_EXISTS) {\r
1352                 // another mayu already running\r
1353                 tstring text = loadString(IDS_mayuAlreadyExists);\r
1354                 tstring title = loadString(IDS_mayu);\r
1355                 if (g_hookData) {\r
1356                         UINT WM_TaskbarRestart = RegisterWindowMessage(_T("TaskbarCreated"));\r
1357                         PostMessage(reinterpret_cast<HWND>(g_hookData->m_hwndTaskTray),\r
1358                                                 WM_TaskbarRestart, 0, 0);\r
1359                 }\r
1360                 MessageBox((HWND)NULL, text.c_str(), title.c_str(), MB_OK | MB_ICONSTOP);\r
1361                 return 1;\r
1362         }\r
1363 \r
1364         try {\r
1365                 Mayu(mutex).messageLoop();\r
1366         } catch (ErrorMessage &i_e) {\r
1367                 tstring title = loadString(IDS_mayu);\r
1368                 MessageBox((HWND)NULL, i_e.getMessage().c_str(), title.c_str(),\r
1369                                    MB_OK | MB_ICONSTOP);\r
1370         }\r
1371 \r
1372         CHECK_TRUE( CloseHandle(mutex) );\r
1373         return 0;\r
1374 }\r