OSDN Git Service

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