OSDN Git Service

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