OSDN Git Service

add log on fail to escape NLS keys
[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                                                         int ret;\r
335                                                         \r
336                                                         ret = This->m_fixScancodeMap.fix();\r
337                                                         if (ret) {\r
338                                                                 This->m_log << _T("escape NLS keys failed: ") << ret << std::endl;\r
339                                                         }\r
340                                                 }\r
341                                         }\r
342                                         m = "WTS_CONSOLE_CONNECT";\r
343                                         break;\r
344                                 case WTS_CONSOLE_DISCONNECT:\r
345                                         This->m_isConsoleConnected = false;\r
346                                         m = "WTS_CONSOLE_DISCONNECT";\r
347                                         break;\r
348                                 case WTS_REMOTE_CONNECT:\r
349                                         m = "WTS_REMOTE_CONNECT";\r
350                                         break;\r
351                                 case WTS_REMOTE_DISCONNECT:\r
352                                         m = "WTS_REMOTE_DISCONNECT";\r
353                                         break;\r
354                                 case WTS_SESSION_LOGON:\r
355                                         m = "WTS_SESSION_LOGON";\r
356                                         break;\r
357                                 case WTS_SESSION_LOGOFF:\r
358                                         m = "WTS_SESSION_LOGOFF";\r
359                                         break;\r
360                                 case WTS_SESSION_LOCK: {\r
361                                         if (This->m_escapeNlsKeys) {\r
362                                                 int ret;\r
363 \r
364                                                 ret = This->m_fixScancodeMap.restore();\r
365                                                 if (ret) {\r
366                                                         This->m_log << _T("restore NLS keys failed: ") << ret << std::endl;\r
367                                                 }\r
368                                         }\r
369                                         m = "WTS_SESSION_LOCK";\r
370                                         break;\r
371                            }\r
372                                 case WTS_SESSION_UNLOCK: {\r
373                                         if (This->m_isConsoleConnected == true) {\r
374                                                 if (This->m_escapeNlsKeys) {\r
375                                                         int ret;\r
376 \r
377                                                         ret = This->m_fixScancodeMap.fix();\r
378                                                         if (ret) {\r
379                                                                 This->m_log << _T("escape NLS keys failed: ") << ret << std::endl;\r
380                                                         }\r
381                                                 }\r
382                                         }\r
383                                         m = "WTS_SESSION_UNLOCK";\r
384                                         break;\r
385                                 }\r
386                                         //case WTS_SESSION_REMOTE_CONTROL: m = "WTS_SESSION_REMOTE_CONTROL"; break;\r
387                                 }\r
388                                 This->m_log << _T("WM_WTSESSION_CHANGE(")\r
389                                 << i_wParam << ", " << i_lParam << "): "\r
390                                 << m << std::endl;\r
391                                 return TRUE;\r
392                         }\r
393                         case WM_APP_msgStreamNotify: {\r
394                                 tomsgstream::StreamBuf *log =\r
395                                         reinterpret_cast<tomsgstream::StreamBuf *>(i_lParam);\r
396                                 const tstring &str = log->acquireString();\r
397 #ifdef LOG_TO_FILE\r
398                                 This->m_logFile << str << std::flush;\r
399 #endif // LOG_TO_FILE\r
400                                 editInsertTextAtLast(GetDlgItem(This->m_hwndLog, IDC_EDIT_log),\r
401                                                                          str, 65000);\r
402                                 log->releaseString();\r
403                                 return 0;\r
404                         }\r
405 \r
406                         case WM_APP_taskTrayNotify: {\r
407                                 if (i_wParam == ID_TaskTrayIcon)\r
408                                         switch (i_lParam) {\r
409                                         case WM_RBUTTONUP: {\r
410                                                 POINT p;\r
411                                                 CHECK_TRUE( GetCursorPos(&p) );\r
412                                                 SetForegroundWindow(i_hwnd);\r
413                                                 HMENU hMenuSub = GetSubMenu(This->m_hMenuTaskTray, 0);\r
414                                                 if (This->m_engine.getIsEnabled())\r
415                                                         CheckMenuItem(hMenuSub, ID_MENUITEM_disable,\r
416                                                                                   MF_UNCHECKED | MF_BYCOMMAND);\r
417                                                 else\r
418                                                         CheckMenuItem(hMenuSub, ID_MENUITEM_disable,\r
419                                                                                   MF_CHECKED | MF_BYCOMMAND);\r
420                                                 CHECK_TRUE( SetMenuDefaultItem(hMenuSub,\r
421                                                                                                            ID_MENUITEM_investigate, FALSE) );\r
422 \r
423                                                 // create reload menu\r
424                                                 HMENU hMenuSubSub = GetSubMenu(hMenuSub, 1);\r
425                                                 Registry reg(MAYU_REGISTRY_ROOT);\r
426                                                 int mayuIndex;\r
427                                                 reg.read(_T(".mayuIndex"), &mayuIndex, 0);\r
428                                                 while (DeleteMenu(hMenuSubSub, 0, MF_BYPOSITION))\r
429                                                         ;\r
430                                                 tregex getName(_T("^([^;]*);"));\r
431                                                 for (int index = 0; ; index ++) {\r
432                                                         _TCHAR buf[100];\r
433                                                         _sntprintf(buf, NUMBER_OF(buf), _T(".mayu%d"), index);\r
434                                                         tstringi dot_mayu;\r
435                                                         if (!reg.read(buf, &dot_mayu))\r
436                                                                 break;\r
437                                                         tsmatch what;\r
438                                                         if (boost::regex_search(dot_mayu, what, getName)) {\r
439                                                                 MENUITEMINFO mii;\r
440                                                                 std::memset(&mii, 0, sizeof(mii));\r
441                                                                 mii.cbSize = sizeof(mii);\r
442                                                                 mii.fMask = MIIM_ID | MIIM_STATE | MIIM_TYPE;\r
443                                                                 mii.fType = MFT_STRING;\r
444                                                                 mii.fState =\r
445                                                                         MFS_ENABLED | ((mayuIndex == index) ? MFS_CHECKED : 0);\r
446                                                                 mii.wID = ID_MENUITEM_reloadBegin + index;\r
447                                                                 tstringi name(what.str(1));\r
448                                                                 mii.dwTypeData = const_cast<_TCHAR *>(name.c_str());\r
449                                                                 mii.cch = name.size();\r
450 \r
451                                                                 InsertMenuItem(hMenuSubSub, index, TRUE, &mii);\r
452                                                         }\r
453                                                 }\r
454 \r
455                                                 // show popup menu\r
456                                                 TrackPopupMenu(hMenuSub, TPM_LEFTALIGN,\r
457                                                                            p.x, p.y, 0, i_hwnd, NULL);\r
458                                                 // TrackPopupMenu may fail (ERROR_POPUP_ALREADY_ACTIVE)\r
459                                                 break;\r
460                                         }\r
461 \r
462                                         case WM_LBUTTONDBLCLK:\r
463                                                 SendMessage(i_hwnd, WM_COMMAND,\r
464                                                                         MAKELONG(ID_MENUITEM_investigate, 0), 0);\r
465                                                 break;\r
466                                         }\r
467                                 return 0;\r
468                         }\r
469 \r
470                         case WM_COMMAND: {\r
471                                 int notify_code = HIWORD(i_wParam);\r
472                                 int id = LOWORD(i_wParam);\r
473                                 if (notify_code == 0) // menu\r
474                                         switch (id) {\r
475                                         default:\r
476                                                 if (ID_MENUITEM_reloadBegin <= id) {\r
477                                                         Registry reg(MAYU_REGISTRY_ROOT);\r
478                                                         reg.write(_T(".mayuIndex"), id - ID_MENUITEM_reloadBegin);\r
479                                                         This->load();\r
480                                                 }\r
481                                                 break;\r
482                                         case ID_MENUITEM_reload:\r
483                                                 This->load();\r
484                                                 break;\r
485                                         case ID_MENUITEM_investigate: {\r
486                                                 ShowWindow(This->m_hwndLog, SW_SHOW);\r
487                                                 ShowWindow(This->m_hwndInvestigate, SW_SHOW);\r
488 \r
489                                                 RECT rc1, rc2;\r
490                                                 GetWindowRect(This->m_hwndInvestigate, &rc1);\r
491                                                 GetWindowRect(This->m_hwndLog, &rc2);\r
492 \r
493                                                 MoveWindow(This->m_hwndLog, rc1.left, rc1.bottom,\r
494                                                                    rcWidth(&rc1), rcHeight(&rc2), TRUE);\r
495 \r
496                                                 SetForegroundWindow(This->m_hwndLog);\r
497                                                 SetForegroundWindow(This->m_hwndInvestigate);\r
498                                                 break;\r
499                                         }\r
500                                         case ID_MENUITEM_setting:\r
501                                                 if (!This->m_isSettingDialogOpened) {\r
502                                                         This->m_isSettingDialogOpened = true;\r
503                                                         if (DialogBox(g_hInst, MAKEINTRESOURCE(IDD_DIALOG_setting),\r
504                                                                                   NULL, dlgSetting_dlgProc))\r
505                                                                 This->load();\r
506                                                         This->m_isSettingDialogOpened = false;\r
507                                                 }\r
508                                                 break;\r
509                                         case ID_MENUITEM_log:\r
510                                                 ShowWindow(This->m_hwndLog, SW_SHOW);\r
511                                                 SetForegroundWindow(This->m_hwndLog);\r
512                                                 break;\r
513                                         case ID_MENUITEM_check: {\r
514                                                 BOOL ret;\r
515                                                 BYTE keys[256];\r
516                                                 ret = GetKeyboardState(keys);\r
517                                                 if (ret == 0) {\r
518                                                         This->m_log << _T("Check Keystate Failed(%d)")\r
519                                                         << GetLastError() << std::endl;\r
520                                                 } else {\r
521                                                         This->m_log << _T("Check Keystate: ") << std::endl;\r
522                                                         for (int i = 0; i < 0xff; i++) {\r
523                                                                 USHORT asyncKey;\r
524                                                                 asyncKey = GetAsyncKeyState(i);\r
525                                                                 This->m_log << std::hex;\r
526                                                                 if (asyncKey & 0x8000) {\r
527                                                                         This->m_log << _T("  ") << VK2TCHAR[i]\r
528                                                                         << _T("(0x") << i << _T("): pressed!")\r
529                                                                         << std::endl;\r
530                                                                 }\r
531                                                                 if (i == 0x14 || // VK_CAPTITAL\r
532                                                                                 i == 0x15 || // VK_KANA\r
533                                                                                 i == 0x19 || // VK_KANJI\r
534                                                                                 i == 0x90 || // VK_NUMLOCK\r
535                                                                                 i == 0x91    // VK_SCROLL\r
536                                                                    ) {\r
537                                                                         if (keys[i] & 1) {\r
538                                                                                 This->m_log << _T("  ") << VK2TCHAR[i]\r
539                                                                                 << _T("(0x") << i << _T("): locked!")\r
540                                                                                 << std::endl;\r
541                                                                         }\r
542                                                                 }\r
543                                                                 This->m_log << std::dec;\r
544                                                         }\r
545                                                         This->m_log << std::endl;\r
546                                                 }\r
547                                                 break;\r
548                                         }\r
549                                         case ID_MENUITEM_version:\r
550                                                 ShowWindow(This->m_hwndVersion, SW_SHOW);\r
551                                                 SetForegroundWindow(This->m_hwndVersion);\r
552                                                 break;\r
553                                         case ID_MENUITEM_help: {\r
554                                                 _TCHAR buf[GANA_MAX_PATH];\r
555                                                 CHECK_TRUE( GetModuleFileName(g_hInst, buf, NUMBER_OF(buf)) );\r
556                                                 tstringi helpFilename = pathRemoveFileSpec(buf);\r
557                                                 helpFilename += _T("\\");\r
558                                                 helpFilename += loadString(IDS_helpFilename);\r
559                                                 ShellExecute(NULL, _T("open"), helpFilename.c_str(),\r
560                                                                          NULL, NULL, SW_SHOWNORMAL);\r
561                                                 break;\r
562                                         }\r
563                                         case ID_MENUITEM_disable:\r
564                                                 This->m_engine.enable(!This->m_engine.getIsEnabled());\r
565                                                 This->showTasktrayIcon();\r
566                                                 break;\r
567                                         case ID_MENUITEM_quit:\r
568                                                 This->m_engine.prepairQuit();\r
569                                                 PostQuitMessage(0);\r
570                                                 break;\r
571                                         }\r
572                                 return 0;\r
573                         }\r
574 \r
575                         case WM_APP_engineNotify: {\r
576                                 switch (i_wParam) {\r
577                                 case EngineNotify_shellExecute:\r
578                                         This->m_engine.shellExecute();\r
579                                         break;\r
580                                 case EngineNotify_loadSetting:\r
581                                         This->load();\r
582                                         break;\r
583                                 case EngineNotify_helpMessage:\r
584                                         This->showHelpMessage(false);\r
585                                         if (i_lParam)\r
586                                                 This->showHelpMessage(true);\r
587                                         break;\r
588                                 case EngineNotify_showDlg: {\r
589                                         // show investigate/log window\r
590                                         int sw = (i_lParam & ~MayuDialogType_mask);\r
591                                         HWND hwnd = NULL;\r
592                                         switch (static_cast<MayuDialogType>(\r
593                                                                 i_lParam & MayuDialogType_mask)) {\r
594                                         case MayuDialogType_investigate:\r
595                                                 hwnd = This->m_hwndInvestigate;\r
596                                                 break;\r
597                                         case MayuDialogType_log:\r
598                                                 hwnd = This->m_hwndLog;\r
599                                                 break;\r
600                                         }\r
601                                         if (hwnd) {\r
602                                                 ShowWindow(hwnd, sw);\r
603                                                 switch (sw) {\r
604                                                 case SW_SHOWNORMAL:\r
605                                                 case SW_SHOWMAXIMIZED:\r
606                                                 case SW_SHOW:\r
607                                                 case SW_RESTORE:\r
608                                                 case SW_SHOWDEFAULT:\r
609                                                         SetForegroundWindow(hwnd);\r
610                                                         break;\r
611                                                 }\r
612                                         }\r
613                                         break;\r
614                                 }\r
615                                 case EngineNotify_setForegroundWindow:\r
616                                         // FIXME: completely useless. why ?\r
617                                         setForegroundWindow(reinterpret_cast<HWND>(i_lParam));\r
618                                         {\r
619                                                 Acquire a(&This->m_log, 1);\r
620                                                 This->m_log << _T("setForegroundWindow(0x")\r
621                                                 << std::hex << i_lParam << std::dec << _T(")")\r
622                                                 << std::endl;\r
623                                         }\r
624                                         break;\r
625                                 case EngineNotify_clearLog:\r
626                                         SendMessage(This->m_hwndLog, WM_COMMAND,\r
627                                                                 MAKELONG(IDC_BUTTON_clearLog, 0), 0);\r
628                                         break;\r
629                                 default:\r
630                                         break;\r
631                                 }\r
632                                 return 0;\r
633                         }\r
634 \r
635                         case WM_APP_dlglogNotify: {\r
636                                 switch (i_wParam) {\r
637                                 case DlgLogNotify_logCleared:\r
638                                         This->showBanner(true);\r
639                                         break;\r
640                                 default:\r
641                                         break;\r
642                                 }\r
643                                 return 0;\r
644                         }\r
645 \r
646                         case WM_DESTROY:\r
647                                 if (This->m_usingSN) {\r
648                                         wtsUnRegisterSessionNotification(i_hwnd);\r
649                                         This->m_usingSN = false;\r
650                                 }\r
651                                 if (This->m_escapeNlsKeys) {\r
652                                         int err;\r
653                                         err = This->m_fixScancodeMap.restore();\r
654                                         if (err) {\r
655                                                 This->errorDialogWithCode(IDS_escapeNlsKeysFailed, err);\r
656                                         }\r
657                                 }\r
658                                 return 0;\r
659 \r
660                         default:\r
661                                 if (i_message == This->m_WM_TaskbarRestart) {\r
662                                         if (This->showTasktrayIcon(true)) {\r
663                                                 Acquire a(&This->m_log, 0);\r
664                                                 This->m_log << _T("Tasktray icon is updated.") << std::endl;\r
665                                         } else {\r
666                                                 Acquire a(&This->m_log, 1);\r
667                                                 This->m_log << _T("Tasktray icon already exists.") << std::endl;\r
668                                         }\r
669                                         return 0;\r
670                                 } else if (i_message == This->m_WM_MayuIPC) {\r
671                                         switch (static_cast<MayuIPCCommand>(i_wParam)) {\r
672                                         case MayuIPCCommand_Enable:\r
673                                                 This->m_engine.enable(!!i_lParam);\r
674                                                 This->showTasktrayIcon();\r
675                                                 if (i_lParam) {\r
676                                                         Acquire a(&This->m_log, 1);\r
677                                                         This->m_log << _T("Enabled by another application.")\r
678                                                         << std::endl;\r
679                                                 } else {\r
680                                                         Acquire a(&This->m_log, 1);\r
681                                                         This->m_log << _T("Disabled by another application.")\r
682                                                         << std::endl;\r
683                                                 }\r
684                                                 break;\r
685                                         }\r
686                                 }\r
687                         }\r
688                 return DefWindowProc(i_hwnd, i_message, i_wParam, i_lParam);\r
689         }\r
690 \r
691         /// load setting\r
692         void load() {\r
693                 Setting *newSetting = new Setting;\r
694 \r
695                 // set symbol\r
696                 for (int i = 1; i < __argc; ++ i) {\r
697                         if (__targv[i][0] == _T('-') && __targv[i][1] == _T('D'))\r
698                                 newSetting->m_symbols.insert(__targv[i] + 2);\r
699                 }\r
700 \r
701                 if (!SettingLoader(&m_log, &m_log).load(newSetting)) {\r
702                         ShowWindow(m_hwndLog, SW_SHOW);\r
703                         SetForegroundWindow(m_hwndLog);\r
704                         delete newSetting;\r
705                         Acquire a(&m_log, 0);\r
706                         m_log << _T("error: failed to load.") << std::endl;\r
707                         return;\r
708                 }\r
709                 m_log << _T("successfully loaded.") << std::endl;\r
710                 while (!m_engine.setSetting(newSetting))\r
711                         Sleep(1000);\r
712                 delete m_setting;\r
713                 m_setting = newSetting;\r
714         }\r
715 \r
716         // show message (a baloon from the task tray icon)\r
717         void showHelpMessage(bool i_doesShow = true) {\r
718                 if (m_canUseTasktrayBaloon) {\r
719                         if (i_doesShow) {\r
720                                 tstring helpMessage, helpTitle;\r
721                                 m_engine.getHelpMessages(&helpMessage, &helpTitle);\r
722                                 tcslcpy(m_ni.szInfo, helpMessage.c_str(), NUMBER_OF(m_ni.szInfo));\r
723                                 tcslcpy(m_ni.szInfoTitle, helpTitle.c_str(),\r
724                                                 NUMBER_OF(m_ni.szInfoTitle));\r
725                                 m_ni.dwInfoFlags = NIIF_INFO;\r
726                         } else\r
727                                 m_ni.szInfo[0] = m_ni.szInfoTitle[0] = _T('\0');\r
728                         CHECK_TRUE( Shell_NotifyIcon(NIM_MODIFY, &m_ni) );\r
729                 }\r
730         }\r
731 \r
732         // change the task tray icon\r
733         bool showTasktrayIcon(bool i_doesAdd = false) {\r
734                 m_ni.hIcon  = m_tasktrayIcon[m_engine.getIsEnabled() ? 1 : 0];\r
735                 m_ni.szInfo[0] = m_ni.szInfoTitle[0] = _T('\0');\r
736                 if (i_doesAdd) {\r
737                         // http://support.microsoft.com/kb/418138/JA/\r
738                         int guard = 60;\r
739                         for (; !Shell_NotifyIcon(NIM_ADD, &m_ni) && 0 < guard; -- guard) {\r
740                                 if (Shell_NotifyIcon(NIM_MODIFY, &m_ni)) {\r
741                                         return true;\r
742                                 }\r
743                                 Sleep(1000);                            // 1sec\r
744                         }\r
745                         return 0 < guard;\r
746                 } else {\r
747                         return !!Shell_NotifyIcon(NIM_MODIFY, &m_ni);\r
748                 }\r
749         }\r
750 \r
751         void showBanner(bool i_isCleared) {\r
752                 time_t now;\r
753                 time(&now);\r
754 \r
755                 _TCHAR starttimebuf[1024];\r
756                 _TCHAR timebuf[1024];\r
757 \r
758 #ifdef __BORLANDC__\r
759 #pragma message("\t\t****\tAfter std::ostream() is called,  ")\r
760 #pragma message("\t\t****\tstrftime(... \"%%#c\" ...) fails.")\r
761 #pragma message("\t\t****\tWhy ? Bug of Borland C++ 5.5.1 ? ")\r
762 #pragma message("\t\t****\t                         - nayuta")\r
763                 _tcsftime(timebuf, NUMBER_OF(timebuf), _T("%Y/%m/%d %H:%M:%S"),\r
764                                   localtime(&now));\r
765                 _tcsftime(starttimebuf, NUMBER_OF(starttimebuf), _T("%Y/%m/%d %H:%M:%S"),\r
766                                   localtime(&m_startTime));\r
767 #else\r
768                 _tcsftime(timebuf, NUMBER_OF(timebuf), _T("%#c"), localtime(&now));\r
769                 _tcsftime(starttimebuf, NUMBER_OF(starttimebuf), _T("%#c"),\r
770                                   localtime(&m_startTime));\r
771 #endif\r
772 \r
773                 Acquire a(&m_log, 0);\r
774                 m_log << _T("------------------------------------------------------------") << std::endl;\r
775                 m_log << loadString(IDS_mayu) << _T(" ") _T(VERSION);\r
776 #ifndef NDEBUG\r
777                 m_log << _T(" (DEBUG)");\r
778 #endif\r
779 #ifdef _UNICODE\r
780                 m_log << _T(" (UNICODE)");\r
781 #endif\r
782                 m_log << std::endl;\r
783                 m_log << _T("  built by ")\r
784                 << _T(LOGNAME) << _T("@") << toLower(_T(COMPUTERNAME))\r
785                 << _T(" (") << _T(__DATE__) <<  _T(" ")\r
786                 << _T(__TIME__) << _T(", ")\r
787                 << getCompilerVersionString() << _T(")") << std::endl;\r
788                 _TCHAR modulebuf[1024];\r
789                 CHECK_TRUE( GetModuleFileName(g_hInst, modulebuf,\r
790                                                                           NUMBER_OF(modulebuf)) );\r
791                 m_log << _T("started at ") << starttimebuf << std::endl;\r
792                 m_log << modulebuf << std::endl;\r
793                 m_log << _T("------------------------------------------------------------") << std::endl;\r
794 \r
795                 if (i_isCleared) {\r
796                         m_log << _T("log was cleared at ") << timebuf << std::endl;\r
797                 } else {\r
798                         m_log << _T("log begins at ") << timebuf << std::endl;\r
799                 }\r
800         }\r
801 \r
802         bool errorDialogWithCode(UINT ids, int code)\r
803         {\r
804                 _TCHAR title[1024];\r
805                 _TCHAR text[1024];\r
806 \r
807                 _sntprintf_s(title, NUMBER_OF(title), _TRUNCATE, loadString(IDS_mayu).c_str());\r
808                 _sntprintf_s(text, NUMBER_OF(text), _TRUNCATE, loadString(ids).c_str(), code);\r
809                 MessageBox((HWND)NULL, text, title, MB_OK | MB_ICONSTOP);\r
810                 return true;\r
811         }\r
812 \r
813         int enableToWriteByUser(HANDLE hdl)\r
814         {\r
815                 TCHAR userName[GANA_MAX_ATOM_LENGTH];\r
816                 DWORD userNameSize = NUMBER_OF(userName);\r
817 \r
818                 SID_NAME_USE sidType;\r
819                 PSID pSid = NULL;\r
820                 DWORD sidSize = 0;\r
821                 TCHAR *pDomain = NULL;\r
822                 DWORD domainSize = 0;\r
823 \r
824                 PSECURITY_DESCRIPTOR pSd;\r
825                 PACL pOrigDacl;\r
826                 ACL_SIZE_INFORMATION aclInfo;\r
827 \r
828                 PACL pNewDacl;\r
829                 DWORD newDaclSize;\r
830 \r
831                 DWORD aceIndex;\r
832                 DWORD newAceIndex = 0;\r
833 \r
834                 BOOL ret;\r
835                 int err = 0;\r
836 \r
837                 ret = GetUserName(userName, &userNameSize);\r
838                 if (ret == FALSE) {\r
839                         err = 1;\r
840                         goto exit;\r
841                 }\r
842 \r
843                 // get buffer size for pSid (and pDomain)\r
844                 ret = LookupAccountName(NULL, userName, pSid, &sidSize, pDomain, &domainSize, &sidType);\r
845                 if (ret != FALSE || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {\r
846                         // above call should fail by ERROR_INSUFFICIENT_BUFFER\r
847                         err = 2;\r
848                         goto exit;\r
849                 }\r
850 \r
851                 pSid = reinterpret_cast<PSID>(LocalAlloc(LPTR, sidSize));\r
852                 pDomain = reinterpret_cast<TCHAR*>(LocalAlloc(LPTR, domainSize * sizeof(TCHAR)));\r
853                 if (pSid == NULL || pDomain == NULL) {\r
854                         err = 3;\r
855                         goto exit;\r
856                 }\r
857 \r
858                 // get SID (and Domain) for logoned user\r
859                 ret = LookupAccountName(NULL, userName, pSid, &sidSize, pDomain, &domainSize, &sidType);\r
860                 if (ret == FALSE) {\r
861                         // LookupAccountName() should success in this time\r
862                         err = 4;\r
863                         goto exit;\r
864                 }\r
865 \r
866                 // get DACL for hdl\r
867                 ret = GetSecurityInfo(hdl, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pOrigDacl, NULL, &pSd);\r
868                 if (ret != ERROR_SUCCESS) {\r
869                         err = 5;\r
870                         goto exit;\r
871                 }\r
872 \r
873                 // get size for original DACL\r
874                 ret = GetAclInformation(pOrigDacl, &aclInfo, sizeof(aclInfo), AclSizeInformation);\r
875                 if (ret == FALSE) {\r
876                         err = 6;\r
877                         goto exit;\r
878                 }\r
879 \r
880                 // compute size for new DACL\r
881                 newDaclSize = aclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pSid) - sizeof(DWORD);\r
882 \r
883                 // allocate memory for new DACL\r
884                 pNewDacl = reinterpret_cast<PACL>(LocalAlloc(LPTR, newDaclSize));\r
885                 if (pNewDacl == NULL) {\r
886                         err = 7;\r
887                         goto exit;\r
888                 }\r
889 \r
890                 // initialize new DACL\r
891                 ret = InitializeAcl(pNewDacl, newDaclSize, ACL_REVISION);\r
892                 if (ret == FALSE) {\r
893                         err = 8;\r
894                         goto exit;\r
895                 }\r
896 \r
897                 // copy original DACL to new DACL\r
898                 for (aceIndex = 0; aceIndex < aclInfo.AceCount; aceIndex++) {\r
899                         LPVOID pAce;\r
900 \r
901                         ret = GetAce(pOrigDacl, aceIndex, &pAce);\r
902                         if (ret == FALSE) {\r
903                                 err = 9;\r
904                                 goto exit;\r
905                         }\r
906 \r
907                         if ((reinterpret_cast<ACCESS_ALLOWED_ACE*>(pAce))->Header.AceFlags & INHERITED_ACE) {\r
908                                 break;\r
909                         }\r
910 \r
911                         if (EqualSid(pSid, &(reinterpret_cast<ACCESS_ALLOWED_ACE*>(pAce))->SidStart) != FALSE) {\r
912                                 continue;\r
913                         }\r
914 \r
915                         ret = AddAce(pNewDacl, ACL_REVISION, MAXDWORD, pAce, (reinterpret_cast<PACE_HEADER>(pAce))->AceSize);\r
916                         if (ret == FALSE) {\r
917                                 err = 10;\r
918                                 goto exit;\r
919                         }\r
920 \r
921                         newAceIndex++;\r
922                 }\r
923 \r
924                 ret = AddAccessAllowedAce(pNewDacl, ACL_REVISION, GENERIC_ALL, pSid);\r
925                 if (ret == FALSE) {\r
926                         err = 11;\r
927                         goto exit;\r
928                 }\r
929 \r
930                 // copy the rest of inherited ACEs\r
931                 for (; aceIndex < aclInfo.AceCount; aceIndex++) {\r
932                         LPVOID pAce;\r
933 \r
934                         ret = GetAce(pOrigDacl, aceIndex, &pAce);\r
935                         if (ret == FALSE) {\r
936                                 err = 12;\r
937                                 goto exit;\r
938                         }\r
939 \r
940                         ret = AddAce(pNewDacl, ACL_REVISION, MAXDWORD, pAce, (reinterpret_cast<PACE_HEADER>(pAce))->AceSize);\r
941                         if (ret == FALSE) {\r
942                                 err = 13;\r
943                                 goto exit;\r
944                         }\r
945                 }\r
946 \r
947                 ret = SetSecurityInfo(hdl, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, pNewDacl, NULL);\r
948                 if (ret != ERROR_SUCCESS) {\r
949                         err = 14;\r
950                 }\r
951 \r
952 exit:\r
953                 LocalFree(pSd);\r
954                 LocalFree(pSid);\r
955                 LocalFree(pDomain);\r
956                 LocalFree(pNewDacl);\r
957 \r
958                 return err;\r
959         }\r
960 \r
961 public:\r
962         ///\r
963         Mayu(HANDLE i_mutex)\r
964                         : m_hwndTaskTray(NULL),\r
965                         m_mutex(i_mutex),\r
966                         m_hwndLog(NULL),\r
967                         m_WM_TaskbarRestart(RegisterWindowMessage(_T("TaskbarCreated"))),\r
968                         m_WM_MayuIPC(RegisterWindowMessage(WM_MayuIPC_NAME)),\r
969                         m_canUseTasktrayBaloon(\r
970                                 PACKVERSION(5, 0) <= getDllVersion(_T("shlwapi.dll"))),\r
971                         m_log(WM_APP_msgStreamNotify),\r
972                         m_setting(NULL),\r
973                         m_isSettingDialogOpened(false),\r
974                         m_isConsoleConnected(true),\r
975                         m_engine(m_log) {\r
976                 Registry reg(MAYU_REGISTRY_ROOT);\r
977                 reg.read(_T("escapeNLSKeys"), &m_escapeNlsKeys, 0);\r
978 #ifdef USE_MAILSLOT\r
979                 m_hNotifyMailslot = CreateMailslot(NOTIFY_MAILSLOT_NAME, 0, MAILSLOT_WAIT_FOREVER, (SECURITY_ATTRIBUTES *)NULL);\r
980                 ASSERT(m_hNotifyMailslot != INVALID_HANDLE_VALUE);\r
981                 int err;\r
982                 if (checkWindowsVersion(6, 0) != FALSE) { // enableToWriteByUser() is available only Vista or later\r
983                         err = enableToWriteByUser(m_hNotifyMailslot);\r
984                         if (err) {\r
985                                 errorDialogWithCode(IDS_cannotPermitStandardUser, err);\r
986                         }\r
987                 }\r
988 \r
989                 m_hNotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);\r
990                 ASSERT(m_hNotifyEvent);\r
991                 m_olNotify.Offset = 0;\r
992                 m_olNotify.OffsetHigh = 0;\r
993                 m_olNotify.hEvent = m_hNotifyEvent;\r
994 #endif // USE_MAILSLOT\r
995                 time(&m_startTime);\r
996 \r
997                 CHECK_TRUE( Register_focus() );\r
998                 CHECK_TRUE( Register_target() );\r
999                 CHECK_TRUE( Register_tasktray() );\r
1000 \r
1001                 // change dir\r
1002 #if 0\r
1003                 HomeDirectories pathes;\r
1004                 getHomeDirectories(&pathes);\r
1005                 for (HomeDirectories::iterator i = pathes.begin(); i != pathes.end(); ++ i)\r
1006                         if (SetCurrentDirectory(i->c_str()))\r
1007                                 break;\r
1008 #endif\r
1009 \r
1010                 // create windows, dialogs\r
1011                 tstringi title = loadString(IDS_mayu);\r
1012                 m_hwndTaskTray = CreateWindow(_T("mayuTasktray"), title.c_str(),\r
1013                                                                           WS_OVERLAPPEDWINDOW,\r
1014                                                                           CW_USEDEFAULT, CW_USEDEFAULT,\r
1015                                                                           CW_USEDEFAULT, CW_USEDEFAULT,\r
1016                                                                           NULL, NULL, g_hInst, this);\r
1017                 CHECK_TRUE( m_hwndTaskTray );\r
1018 \r
1019                 // set window handle of tasktray to hooks\r
1020 #ifndef USE_MAILSLOT\r
1021                 g_hookData->m_hwndTaskTray = reinterpret_cast<DWORD>(m_hwndTaskTray);\r
1022 #endif // !USE_MAILSLOT\r
1023                 CHECK_FALSE( installMessageHook() );\r
1024                 m_usingSN = wtsRegisterSessionNotification(m_hwndTaskTray,\r
1025                                         NOTIFY_FOR_THIS_SESSION);\r
1026 \r
1027                 DlgLogData dld;\r
1028                 dld.m_log = &m_log;\r
1029                 dld.m_hwndTaskTray = m_hwndTaskTray;\r
1030                 m_hwndLog =\r
1031                         CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_DIALOG_log), NULL,\r
1032                                                           dlgLog_dlgProc, (LPARAM)&dld);\r
1033                 CHECK_TRUE( m_hwndLog );\r
1034 \r
1035                 DlgInvestigateData did;\r
1036                 did.m_engine = &m_engine;\r
1037                 did.m_hwndLog = m_hwndLog;\r
1038                 m_hwndInvestigate =\r
1039                         CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_DIALOG_investigate), NULL,\r
1040                                                           dlgInvestigate_dlgProc, (LPARAM)&did);\r
1041                 CHECK_TRUE( m_hwndInvestigate );\r
1042 \r
1043                 m_hwndVersion =\r
1044                         CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_DIALOG_version),\r
1045                                                           NULL, dlgVersion_dlgProc,\r
1046                                                           (LPARAM)m_engine.getMayudVersion().c_str());\r
1047                 CHECK_TRUE( m_hwndVersion );\r
1048 \r
1049                 // attach log\r
1050 #ifdef LOG_TO_FILE\r
1051                 tstring path;\r
1052                 _TCHAR exePath[GANA_MAX_PATH];\r
1053                 _TCHAR exeDrive[GANA_MAX_PATH];\r
1054                 _TCHAR exeDir[GANA_MAX_PATH];\r
1055                 GetModuleFileName(NULL, exePath, GANA_MAX_PATH);\r
1056                 _tsplitpath_s(exePath, exeDrive, GANA_MAX_PATH, exeDir, GANA_MAX_PATH, NULL, 0, NULL, 0);\r
1057                 path = exeDrive;\r
1058                 path += exeDir;\r
1059                 path += _T("mayu.log");\r
1060                 m_logFile.open(path.c_str(), std::ios::app);\r
1061                 m_logFile.imbue(std::locale("japanese"));\r
1062 #endif // LOG_TO_FILE\r
1063                 SendMessage(GetDlgItem(m_hwndLog, IDC_EDIT_log), EM_SETLIMITTEXT, 0, 0);\r
1064                 m_log.attach(m_hwndTaskTray);\r
1065 \r
1066                 // start keyboard handler thread\r
1067                 m_engine.setAssociatedWndow(m_hwndTaskTray);\r
1068                 m_engine.start();\r
1069 \r
1070                 // show tasktray icon\r
1071                 m_tasktrayIcon[0] = loadSmallIcon(IDI_ICON_mayu_disabled);\r
1072                 m_tasktrayIcon[1] = loadSmallIcon(IDI_ICON_mayu);\r
1073                 std::memset(&m_ni, 0, sizeof(m_ni));\r
1074                 m_ni.uID    = ID_TaskTrayIcon;\r
1075                 m_ni.hWnd   = m_hwndTaskTray;\r
1076                 m_ni.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;\r
1077                 m_ni.hIcon  = m_tasktrayIcon[1];\r
1078                 m_ni.uCallbackMessage = WM_APP_taskTrayNotify;\r
1079                 tstring tip = loadString(IDS_mayu);\r
1080                 tcslcpy(m_ni.szTip, tip.c_str(), NUMBER_OF(m_ni.szTip));\r
1081                 if (m_canUseTasktrayBaloon) {\r
1082                         m_ni.cbSize = sizeof(m_ni);\r
1083                         m_ni.uFlags |= NIF_INFO;\r
1084                 } else\r
1085                         m_ni.cbSize = NOTIFYICONDATA_V1_SIZE;\r
1086                 showTasktrayIcon(true);\r
1087 \r
1088                 // create menu\r
1089                 m_hMenuTaskTray = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_MENU_tasktray));\r
1090                 ASSERT(m_hMenuTaskTray);\r
1091 \r
1092                 // set initial lock state\r
1093                 notifyLockState();\r
1094 \r
1095                 BOOL result;\r
1096 \r
1097                 ZeroMemory(&m_pi,sizeof(m_pi));\r
1098                 ZeroMemory(&m_si,sizeof(m_si));\r
1099                 m_si.cb=sizeof(m_si);\r
1100 #ifdef _WIN64\r
1101                 result = CreateProcess(_T("yamyd32"), _T("yamyd32"), NULL, NULL, FALSE,\r
1102                                                            NORMAL_PRIORITY_CLASS, 0, NULL, &m_si, &m_pi);\r
1103                 if (result == FALSE) {\r
1104                         TCHAR buf[1024];\r
1105                         TCHAR text[1024];\r
1106                         TCHAR title[1024];\r
1107 \r
1108                         LoadString(GetModuleHandle(NULL), IDS_cannotInvoke,\r
1109                                            text, sizeof(text)/sizeof(text[0]));\r
1110                         LoadString(GetModuleHandle(NULL), IDS_mayu,\r
1111                                            title, sizeof(title)/sizeof(title[0]));\r
1112                         _stprintf_s(buf, sizeof(buf)/sizeof(buf[0]),\r
1113                                                 text, _T("yamyd32"), GetLastError());\r
1114                         MessageBox((HWND)NULL, buf, title, MB_OK | MB_ICONSTOP);\r
1115                 } else {\r
1116                         CloseHandle(m_pi.hThread);\r
1117                         CloseHandle(m_pi.hProcess);\r
1118                 }\r
1119 #endif // _WIN64\r
1120         }\r
1121 \r
1122         ///\r
1123         ~Mayu() {\r
1124 #ifdef USE_MAILSLOT\r
1125                 CancelIo(m_hNotifyMailslot);\r
1126                 SleepEx(0, TRUE);\r
1127                 CloseHandle(m_hNotifyMailslot);\r
1128                 CloseHandle(m_hNotifyEvent);\r
1129 #endif // USE_MAILSLOT\r
1130                 ReleaseMutex(m_mutex);\r
1131                 WaitForSingleObject(m_mutex, INFINITE);\r
1132                 // first, detach log from edit control to avoid deadlock\r
1133                 m_log.detach();\r
1134 #ifdef LOG_TO_FILE\r
1135                 m_logFile.close();\r
1136 #endif // LOG_TO_FILE\r
1137 \r
1138                 // stop notify from mayu.dll\r
1139                 g_hookData->m_hwndTaskTray = NULL;\r
1140                 CHECK_FALSE( uninstallMessageHook() );\r
1141                 PostMessage(HWND_BROADCAST, WM_NULL, 0, 0);\r
1142 \r
1143                 // destroy windows\r
1144                 CHECK_TRUE( DestroyWindow(m_hwndVersion) );\r
1145                 CHECK_TRUE( DestroyWindow(m_hwndInvestigate) );\r
1146                 CHECK_TRUE( DestroyWindow(m_hwndLog) );\r
1147                 CHECK_TRUE( DestroyWindow(m_hwndTaskTray) );\r
1148 \r
1149                 // destroy menu\r
1150                 DestroyMenu(m_hMenuTaskTray);\r
1151 \r
1152                 // delete tasktray icon\r
1153                 CHECK_TRUE( Shell_NotifyIcon(NIM_DELETE, &m_ni) );\r
1154                 CHECK_TRUE( DestroyIcon(m_tasktrayIcon[1]) );\r
1155                 CHECK_TRUE( DestroyIcon(m_tasktrayIcon[0]) );\r
1156 \r
1157                 // stop keyboard handler thread\r
1158                 m_engine.stop();\r
1159 \r
1160                 // remove setting;\r
1161                 delete m_setting;\r
1162         }\r
1163 \r
1164         /// message loop\r
1165         WPARAM messageLoop() {\r
1166                 showBanner(false);\r
1167                 load();\r
1168 \r
1169 #ifdef USE_MAILSLOT\r
1170                 mailslotHandler(0, 0);\r
1171                 while (1) {\r
1172                         HANDLE handles[] = { m_hNotifyEvent };\r
1173                         DWORD ret;\r
1174                         switch (ret = MsgWaitForMultipleObjectsEx(NUMBER_OF(handles), &handles[0],\r
1175                                                   INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE)) {\r
1176                         case WAIT_OBJECT_0:                     // m_hNotifyEvent\r
1177                                 break;\r
1178 \r
1179                         case WAIT_OBJECT_0 + NUMBER_OF(handles): {\r
1180                                 MSG msg;\r
1181                                 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0) {\r
1182                                         if (msg.message == WM_QUIT) {\r
1183                                                 return msg.wParam;\r
1184                                         }\r
1185                                         if (IsDialogMessage(m_hwndLog, &msg))\r
1186                                                 break;\r
1187                                         if (IsDialogMessage(m_hwndInvestigate, &msg))\r
1188                                                 break;\r
1189                                         if (IsDialogMessage(m_hwndVersion, &msg))\r
1190                                                 break;\r
1191                                         TranslateMessage(&msg);\r
1192                                         DispatchMessage(&msg);\r
1193                                         break;\r
1194                                 }\r
1195                                 break;\r
1196                         }\r
1197 \r
1198                         case WAIT_IO_COMPLETION:\r
1199                                 break;\r
1200 \r
1201                         case 0x102:\r
1202                         default:\r
1203                                 break;\r
1204                         }\r
1205                 }\r
1206 #else // !USE_MAILSLOT\r
1207                 MSG msg;\r
1208                 while (0 < GetMessage(&msg, NULL, 0, 0)) {\r
1209                         if (IsDialogMessage(m_hwndLog, &msg))\r
1210                                 continue;\r
1211                         if (IsDialogMessage(m_hwndInvestigate, &msg))\r
1212                                 continue;\r
1213                         if (IsDialogMessage(m_hwndVersion, &msg))\r
1214                                 continue;\r
1215                         TranslateMessage(&msg);\r
1216                         DispatchMessage(&msg);\r
1217                 }\r
1218                 return msg.wParam;\r
1219 #endif // !USE_MAILSLOT\r
1220         }\r
1221 };\r
1222 \r
1223 \r
1224 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
1225 // Functions\r
1226 \r
1227 \r
1228 /// convert registry\r
1229 void convertRegistry()\r
1230 {\r
1231         Registry reg(MAYU_REGISTRY_ROOT);\r
1232         tstringi dot_mayu;\r
1233         bool doesAdd = false;\r
1234         DWORD index;\r
1235         if (reg.read(_T(".mayu"), &dot_mayu)) {\r
1236                 reg.write(_T(".mayu0"), _T(";") + dot_mayu + _T(";"));\r
1237                 reg.remove(_T(".mayu"));\r
1238                 doesAdd = true;\r
1239                 index = 0;\r
1240         } else if (!reg.read(_T(".mayu0"), &dot_mayu)) {\r
1241                 reg.write(_T(".mayu0"), loadString(IDS_readFromHomeDirectory) + _T(";;"));\r
1242                 doesAdd = true;\r
1243                 index = 1;\r
1244         }\r
1245         if (doesAdd) {\r
1246                 Registry commonreg(HKEY_LOCAL_MACHINE, _T("Software\\GANAware\\mayu"));\r
1247                 tstringi dir, layout;\r
1248                 if (commonreg.read(_T("dir"), &dir) &&\r
1249                                 commonreg.read(_T("layout"), &layout)) {\r
1250                         tstringi tmp = _T(";") + dir + _T("\\dot.mayu");\r
1251                         if (layout == _T("109")) {\r
1252                                 reg.write(_T(".mayu1"), loadString(IDS_109Emacs) + tmp\r
1253                                                   + _T(";-DUSE109") _T(";-DUSEdefault"));\r
1254                                 reg.write(_T(".mayu2"), loadString(IDS_104on109Emacs) + tmp\r
1255                                                   + _T(";-DUSE109") _T(";-DUSEdefault") _T(";-DUSE104on109"));\r
1256                                 reg.write(_T(".mayu3"), loadString(IDS_109) + tmp\r
1257                                                   + _T(";-DUSE109"));\r
1258                                 reg.write(_T(".mayu4"), loadString(IDS_104on109) + tmp\r
1259                                                   + _T(";-DUSE109") _T(";-DUSE104on109"));\r
1260                         } else {\r
1261                                 reg.write(_T(".mayu1"), loadString(IDS_104Emacs) + tmp\r
1262                                                   + _T(";-DUSE104") _T(";-DUSEdefault"));\r
1263                                 reg.write(_T(".mayu2"), loadString(IDS_109on104Emacs) + tmp\r
1264                                                   + _T(";-DUSE104") _T(";-DUSEdefault") _T(";-DUSE109on104"));\r
1265                                 reg.write(_T(".mayu3"), loadString(IDS_104) + tmp\r
1266                                                   + _T(";-DUSE104"));\r
1267                                 reg.write(_T(".mayu4"), loadString(IDS_109on104) + tmp\r
1268                                                   + _T(";-DUSE104") _T(";-DUSE109on104"));\r
1269                         }\r
1270                         reg.write(_T(".mayuIndex"), index);\r
1271                 }\r
1272         }\r
1273 }\r
1274 \r
1275 \r
1276 /// main\r
1277 int WINAPI _tWinMain(HINSTANCE i_hInstance, HINSTANCE /* i_hPrevInstance */,\r
1278                                          LPTSTR /* i_lpszCmdLine */, int /* i_nCmdShow */)\r
1279 {\r
1280         g_hInst = i_hInstance;\r
1281 \r
1282         // set locale\r
1283         CHECK_TRUE( _tsetlocale(LC_ALL, _T("")) );\r
1284 \r
1285         // common controls\r
1286 #if defined(_WIN95)\r
1287         InitCommonControls();\r
1288 #else\r
1289         INITCOMMONCONTROLSEX icc;\r
1290         icc.dwSize = sizeof(icc);\r
1291         icc.dwICC = ICC_LISTVIEW_CLASSES;\r
1292         CHECK_TRUE( InitCommonControlsEx(&icc) );\r
1293 #endif\r
1294 \r
1295         // convert old registry to new registry\r
1296 #ifndef USE_INI\r
1297         convertRegistry();\r
1298 #endif // !USE_INI\r
1299 \r
1300         // is another mayu running ?\r
1301         HANDLE mutex = CreateMutex((SECURITY_ATTRIBUTES *)NULL, TRUE,\r
1302                                                            MUTEX_MAYU_EXCLUSIVE_RUNNING);\r
1303         if (GetLastError() == ERROR_ALREADY_EXISTS) {\r
1304                 // another mayu already running\r
1305                 tstring text = loadString(IDS_mayuAlreadyExists);\r
1306                 tstring title = loadString(IDS_mayu);\r
1307                 if (g_hookData) {\r
1308                         UINT WM_TaskbarRestart = RegisterWindowMessage(_T("TaskbarCreated"));\r
1309                         PostMessage(reinterpret_cast<HWND>(g_hookData->m_hwndTaskTray),\r
1310                                                 WM_TaskbarRestart, 0, 0);\r
1311                 }\r
1312                 MessageBox((HWND)NULL, text.c_str(), title.c_str(), MB_OK | MB_ICONSTOP);\r
1313                 return 1;\r
1314         }\r
1315 \r
1316         try {\r
1317                 Mayu(mutex).messageLoop();\r
1318         } catch (ErrorMessage &i_e) {\r
1319                 tstring title = loadString(IDS_mayu);\r
1320                 MessageBox((HWND)NULL, i_e.getMessage().c_str(), title.c_str(),\r
1321                                    MB_OK | MB_ICONSTOP);\r
1322         }\r
1323 \r
1324         CHECK_TRUE( CloseHandle(mutex) );\r
1325         return 0;\r
1326 }\r