diff --git a/gui/ITHVNR.rc b/gui/ITHVNR.rc index 3f66f64..7cc7e84 100644 --- a/gui/ITHVNR.rc +++ b/gui/ITHVNR.rc @@ -19,14 +19,14 @@ STYLE DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYS CAPTION "Process Explorer" FONT 8, "MS Shell Dlg", 400, 0, 1 { - DEFPUSHBUTTON "È®ÀÎ", IDOK, 281, 189, 53, 14, 0, WS_EX_LEFT - PUSHBUTTON "ÇÁ·ÎÇÊ Á¦°Å", IDC_BUTTON6, 226, 189, 53, 14, 0, WS_EX_LEFT - CONTROL "", IDC_LIST1, WC_LISTVIEW, WS_TABSTOP | WS_BORDER | LVS_ALIGNLEFT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_REPORT, 7, 20, 327, 164, WS_EX_LEFT - LTEXT "ÇÁ·Î¼¼½º", IDC_STATIC, 7, 7, 65, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT - PUSHBUTTON "ºÎÂø", IDC_BUTTON2, 61, 189, 53, 14, 0, WS_EX_LEFT - PUSHBUTTON "Å»Âø", IDC_BUTTON3, 116, 189, 53, 14, 0, WS_EX_LEFT - PUSHBUTTON "ÇÁ·ÎÇÊ Ãß°¡", IDC_BUTTON5, 171, 189, 53, 14, 0, WS_EX_LEFT - PUSHBUTTON "»õ·Î°íħ", IDC_BUTTON1, 7, 189, 53, 14, 0, WS_EX_LEFT + DEFPUSHBUTTON "OK", IDOK, 281, 189, 53, 14, 0, WS_EX_LEFT + PUSHBUTTON "Remove Profile", IDC_BUTTON6, 226, 189, 53, 14, 0, WS_EX_LEFT + CONTROL "", IDC_LIST1, WC_LISTVIEW, WS_TABSTOP | WS_BORDER | LVS_ALIGNLEFT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_REPORT, 7, 20, 327, 164, WS_EX_LEFT + LTEXT "Process", IDC_STATIC, 7, 7, 65, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT + PUSHBUTTON "Attach", IDC_BUTTON2, 61, 189, 53, 14, 0, WS_EX_LEFT + PUSHBUTTON "Detach", IDC_BUTTON3, 116, 189, 53, 14, 0, WS_EX_LEFT + PUSHBUTTON "Add Profile", IDC_BUTTON5, 171, 189, 53, 14, 0, WS_EX_LEFT + PUSHBUTTON "Refresh", IDC_BUTTON1, 7, 189, 53, 14, 0, WS_EX_LEFT } @@ -37,22 +37,22 @@ STYLE DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYS CAPTION "Option" FONT 8, "MS Shell Dlg", 400, 0, 1 { - DEFPUSHBUTTON "È®ÀÎ", IDOK, 8, 164, 50, 14, 0, WS_EX_LEFT - PUSHBUTTON "Ãë¼Ò", IDCANCEL, 65, 164, 50, 14, 0, WS_EX_LEFT - EDITTEXT IDC_EDIT1, 60, 7, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT - LTEXT "¹®´Ü³ª´©±â", IDC_STATIC, 7, 7, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT - EDITTEXT IDC_EDIT2, 60, 25, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT - LTEXT "ÇÁ·Î¼¼½º ´ë±â", IDC_STATIC, 7, 26, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT - EDITTEXT IDC_EDIT3, 60, 45, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT - LTEXT "ÀÎÁ§¼Ç ´ë±â", IDC_STATIC, 7, 45, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT - EDITTEXT IDC_EDIT4, 60, 65, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT - LTEXT "»ðÀÔ ´ë±â", IDC_STATIC, 7, 65, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT - AUTOCHECKBOX "ÀÚµ¿ ºÎÂø", IDC_CHECK1, 7, 87, 54, 10, 0, WS_EX_LEFT - AUTOCHECKBOX "ÀÚµ¿ »ðÀÔ", IDC_CHECK2, 62, 87, 50, 10, 0, WS_EX_LEFT - AUTOCHECKBOX "Ŭ¸³º¸µå·Î ÀÚµ¿ º¹»ç", IDC_CHECK3, 7, 103, 88, 10, 0, WS_EX_LEFT - AUTOCHECKBOX "ÀÚµ¿ ¹Ýº¹¹® Á¦°Å", IDC_CHECK4, 7, 119, 95, 10, 0, WS_EX_LEFT - AUTOCHECKBOX "¹®ÀÚÇÊÅÍ ÃʱâÈ­", IDC_CHECK6, 7, 149, 81, 8, 0, WS_EX_LEFT - AUTOCHECKBOX "±Û·Î¹ú ÇÊÅÍ È°¼ºÈ­", IDC_CHECK5, 7, 134, 75, 10, 0, WS_EX_LEFT + DEFPUSHBUTTON "OK", IDOK, 8, 164, 50, 14, 0, WS_EX_LEFT + PUSHBUTTON "Cancel", IDCANCEL, 65, 164, 50, 14, 0, WS_EX_LEFT + EDITTEXT IDC_EDIT1, 60, 7, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT + LTEXT "Split time", IDC_STATIC, 7, 7, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT + EDITTEXT IDC_EDIT2, 60, 25, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT + LTEXT "Process delay", IDC_STATIC, 7, 26, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT + EDITTEXT IDC_EDIT3, 60, 45, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT + LTEXT "Inject delay", IDC_STATIC, 7, 45, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT + EDITTEXT IDC_EDIT4, 60, 65, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT + LTEXT "Insert delay", IDC_STATIC, 7, 65, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT + AUTOCHECKBOX "Auto attach", IDC_CHECK1, 7, 87, 54, 10, 0, WS_EX_LEFT + AUTOCHECKBOX "Auto insert", IDC_CHECK2, 62, 87, 50, 10, 0, WS_EX_LEFT + AUTOCHECKBOX "Auto copy to clipboard", IDC_CHECK3, 7, 103, 88, 10, 0, WS_EX_LEFT + AUTOCHECKBOX "Auto suppress repetition", IDC_CHECK4, 7, 119, 95, 10, 0, WS_EX_LEFT + AUTOCHECKBOX "Reset character filter", IDC_CHECK6, 7, 149, 81, 8, 0, WS_EX_LEFT + AUTOCHECKBOX "Enable global filter", IDC_CHECK5, 7, 134, 75, 10, 0, WS_EX_LEFT } diff --git a/gui/command.cpp b/gui/command.cpp index 79d5fb4..bfd8220 100644 --- a/gui/command.cpp +++ b/gui/command.cpp @@ -50,24 +50,24 @@ DWORD ProcessCommand(const std::wstring& cmd, DWORD pid) if (Parse(m[1].str(), hp)) Host_InsertHook(pid, &hp); } - else if (regex_match(cmd, m, wregex(L"(?::|)(?:¤·|¿¬|l|)([[:xdigit:]]+)(?:-| )([[:xdigit:]]+)", wregex::icase))) + else if (regex_match(cmd, m, wregex(L":l([[:xdigit:]]+)-([[:xdigit:]]+)", wregex::icase))) { DWORD from = std::stoul(m[1].str(), NULL, 16); DWORD to = std::stoul(m[2].str(), NULL, 16); Host_AddLink(from, to); } - else if (regex_match(cmd, m, wregex(L"(?::|)(?:¤¾|ÇØ|ÇØÁ¦|u)([[:xdigit:]]+)", wregex::icase))) + else if (regex_match(cmd, m, wregex(L":u([[:xdigit:]]+)", wregex::icase))) { DWORD from = std::stoul(m[1].str(), NULL, 16); Host_UnLink(from); } - else if (regex_match(cmd, m, wregex(L"(?::|)(?:¤§|µµ|µµ¿ò|µµ¿ò¸»|h|help)", wregex::icase))) + else if (regex_match(cmd, m, wregex(L":(?:h|help)", wregex::icase))) { ConsoleOutput(Usage); } else { - ConsoleOutput(L"¾Ë ¼ö ¾ø´Â ¸í·É¾î. µµ¿ò¸»À» º¸½Ã·Á¸é, :h ³ª :help¸¦ ÀÔ·ÂÇϼ¼¿ä."); + ConsoleOutput(L"Unknown command. Type :h or :help for help."); } return 0; } diff --git a/gui/language.cpp b/gui/language.cpp index ee33716..6149eb9 100644 --- a/gui/language.cpp +++ b/gui/language.cpp @@ -14,44 +14,44 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -const wchar_t* Warning = L"°æ°í!"; +const wchar_t* Warning=L"Warning!"; //command.cpp -const wchar_t* ErrorSyntax = L"¸í·É¾î ¿À·ù"; -const wchar_t* Usage = L"¸í·É¾î:\r\n\ +const wchar_t* ErrorSyntax=L"Syntax error"; +const wchar_t* Usage = L"Syntax:\r\n\ \r\n\ -µµ¿ò¸» //µµ¿ò¸»À» Ãâ·ÂÇÕ´Ï´Ù\r\n\ -Ãâ¹ß µµÂø // 'Ãâ¹ß'½º·¹µå¿¡¼­ 'µµÂø'½º·¹µå·Î ¿¬°áÇÕ´Ï´Ù\r\n\ -¤¾Ãâ¹ß // 'Ãâ¹ß'½º·¹µå¿¡ ¿¬°áµÈ ¸µÅ©¸¦ ÇØÁ¦ÇÕ´Ï´Ù\r\n\ +:H[ELP] - print help\r\n\ +:Lfrom-to - link from thread 'from' to thread 'to'\r\n\ +:Ufrom - unlink link from thread 'from'\r\n\ \r\n\ -'Ãâ¹ß'°ú 'µµÂø'¿¡´Â 16Áø¹ý(Çí»çÄÚµå) ½º·¹µå¹øÈ£¸¦ ÀÔ·ÂÇÕ´Ï´Ù. ½º·¹µå ¹øÈ£´Â ¸Ç ¾Õ¿¡ Àִ ù ¹ø° ¼ýÀÚ¿­ÀÔ´Ï´Ù.\r\n\ +'from' and 'to' and hexadecimal thread numbers. The thread number is the first number in the combo box.\r\n\ \r\n\ -·Î´õ ¿É¼Ç:\r\n\ -/P[{process_id|Nprocess_name}] //ÇÁ·Î¼¼½º¿¡ ºÎÂø\r\n\ +Loader options:\r\n\ +/P[{process_id|Nprocess_name}] - attach to process\r\n\ \r\n\ -HÄÚµå ÈÄÅ· ¿É¼Ç:\r\n\ +Hook options:\r\n\ /H[X]{A|B|W|S|Q}[N][data_offset[*drdo]][:sub_offset[*drso]]@addr[:module[:{name|#ordinal}]]\r\n\ \r\n\ -(¼­¼ö¸¦ Á¦¿ÜÇÑ) /HÄÚµåÀÇ ¸ðµç ¼ýÀÚ´Â ¾Æ¹«°Íµµ 󸮵ÇÁö ¾ÊÀº 16Áø¹ý(Çí»çÄÚµå)ÀÔ´Ï´Ù"; +All numbers in /H (except ordinal) are hexadecimal without any prefixes"; const wchar_t* ExtendedUsage = L"/H[X]{A|B|W|S|Q}[N][data_offset[*drdo]][:sub_offset[*drso]]@addr[:[module[:{name|#ordinal}]]]\r\n\ \r\n\ -Ãß°¡ »ç¿ëÀÚÁ¤ÀÇ ÈÄÅ·¼³Á¤\r\n\ +Set additional custom hook\r\n\ \r\n\ -ÈÄÅ· Á¾·ù :\r\n\ -A - DBCS ¹®ÀÚ\r\n\ -B - DBCS ¹®ÀÚ(big-endian)\r\n\ -W - UCS2 ¹®ÀÚ\r\n\ -S - MBCS ¹®ÀÚ¿­\r\n\ -Q - UTF-16 ¹®ÀÚ¿­\r\n\ +Hook types :\r\n\ +A - DBCS char\r\n\ +B - DBCS char(big-endian)\r\n\ +W - UCS2 char\r\n\ +S - MBCS string\r\n\ +Q - UTF-16 string\r\n\ \r\n\ -¸Å°³º¯¼ö:\r\n\ -X - Çϵå¿þ¾î ±¸È¹Á¡ »ç¿ë\r\n\ -N - ¹®¹ýÀ» »ç¿ëÇÏÁö ¾ÊÀ½\r\n\ +Parameters:\r\n\ +X - use hardware breakpoints\r\n\ +N - don't use contexts\r\n\ data_offset - stack offset to char / string pointer\r\n\ drdo - add a level of indirection to data_offset\r\n\ sub_offset - stack offset to subcontext\r\n\ drso - add a level of indirection to sub_offset\r\n\ -addr - ÈÄÅ·ÇÒ ÁÖ¼Ò\r\n\ +addr - address of the hook\r\n\ module - name of the module to use as base for 'addr'\r\n\ name - name of the 'module' export to use as base for 'addr'\r\n\ ordinal - number of the 'module' export ordinal to use as base for 'addr'\r\n\ @@ -64,70 +64,69 @@ Negative values of 'data_offset' and 'sub_offset' refer to registers: \r\n\ All numbers except ordinal are hexadecimal without any prefixes"; //inject.cpp -const wchar_t* ErrorRemoteThread = L"¿ø°Ý ½º·¹µå¸¦ »ý¼ºÇÒ ¼ö ¾øÀ½."; -const wchar_t* ErrorOpenProcess = L"ÇÁ·Î¼¼½º¸¦ ¿­ ¼ö ¾øÀ½."; -const wchar_t* ErrorNoProcess = L"ÇÁ·Î¼¼½º¸¦ ãÀ» ¼ö ¾øÀ½"; -const wchar_t* SelfAttach = L"ITH.exe¿¡ ºÎÂøÇÏÁö ¸»¾Æ ÁÖ¼¼¿ä"; -const wchar_t* AlreadyAttach = L"ÇÁ·Î¼¼½º°¡ ÀÌ¹Ì ºÎÂøµÊ."; -const wchar_t* FormatInject = L"ÇÁ·Î¼¼½º %d¿¡ ÀÎÁ§¼Ç. ¸ðµâ ±â¹Ý %.8X"; +const wchar_t* ErrorRemoteThread=L"Can't create remote thread."; +const wchar_t* ErrorOpenProcess=L"Can't open process."; +const wchar_t* ErrorNoProcess=L"Process not found"; +const wchar_t* SelfAttach=L"Please do not attach to ITH.exe"; +const wchar_t* AlreadyAttach=L"Process already attached."; +const wchar_t* FormatInject=L"Inject process %d. Module base %.8X"; //main.cpp -const wchar_t* NotAdmin = L"SeDebugPrevilegeÀ» È°¼ºÈ­ ÇÒ ¼ö ¾ø½À´Ï´Ù. ITH°¡ Á¦´ë·Î ÀÛµ¿ÇÏÁö ¸øÇÕ´Ï´Ù.\r\n\ -°ü¸®ÀÚ °èÁ¤À¸·Î ½ÇÇàÇϽðųª UAC¸¦ ²ô½Ã°í ITH¸¦ ½ÇÇàÇØ ÁÖ¼¼¿ä."; +const wchar_t* NotAdmin=L"Can't enable SeDebugPrevilege. ITH might malfunction.\r\n\ +Please run ITH as administrator or turn off UAC."; //pipe.cpp -const wchar_t* ErrorCreatePipe = L"ÅؽºÆ® ÆÄÀÌÇÁ¸¦ »ý¼ºÇÒ ¼ö ¾ø°Å³ª, ¿äûÀÌ ³Ê¹« ¸¹½À´Ï´Ù."; -const wchar_t* FormatDetach = L"ÇÁ·Î¼¼½º %d°¡ Å»ÂøµÊ."; -const wchar_t* ErrorCmdQueueFull = L"¸í·É¾î ´ë±â¿­ÀÌ °¡µæÂü."; -const wchar_t* ErrorNoAttach = L"ÇÁ·Î¼¼½º°¡ ºÎÂøµÇÁö ¾ÊÀ½."; +const wchar_t* ErrorCreatePipe=L"Can't create text pipe or too many instance."; +const wchar_t* FormatDetach=L"Process %d detached."; +const wchar_t* ErrorCmdQueueFull=L"Command queue full."; +const wchar_t* ErrorNoAttach=L"No process attached."; //profile.cpp -const wchar_t* ErrorMonitor = L"ÇÁ·Î¼¼½º¸¦ °¨½ÃÇÒ ¼ö ¾øÀ½."; +const wchar_t* ErrorMonitor=L"Can't monitor process."; //utility.cpp -const wchar_t* InitMessage = L"Copyright (C) 2010-2012 kaosu \r\n\ +const wchar_t* InitMessage=L"Copyright (C) 2010-2012 kaosu \r\n\ Copyright (C) 2015 zorkzero \r\n\ -¼Ò½ºÄÚµå \r\n\ -ÀϹÝÅä·Ð \r\n\ -ÇѱÛÈ­ @mireado"; -const wchar_t* BackgroundMsg = L"µµ¿ò¸»À» º¸½Ã·Á¸é, \"help\", \"µµ¿ò¸»\"À̳ª \"µµ¿ò\"À» ÀÔ·ÂÇϼ¼¿ä."; -const wchar_t* ErrorLinkExist = L"¿¬°áÀÌ Á¸ÀçÇÔ."; -const wchar_t* ErrorCylicLink = L"¿¬°á½ÇÆÐ. ¼øȯ¿¬°áÀº Çã¿ëµÇÁö ¾Ê½À´Ï´Ù."; -const wchar_t* FormatLink = L"Ãâ¹ß½º·¹µå%.4x¿¡¼­ µµÂø½º·¹µå%.4x·Î ¿¬°á."; -const wchar_t* ErrorLink = L"¿¬°á½ÇÆÐ. Ãâ¹ß/µµÂø ½º·¹µå¸¦ ãÀ» ¼ö ¾øÀ½."; -const wchar_t* ErrorDeleteCombo = L"±Û»óÀÚ¿¡¼­ Áö¿ì±â ½ÇÆÐ."; +Source code \r\n\ +General discussion "; +const wchar_t* BackgroundMsg=L"Type \":h\" or \":help\" for help."; +const wchar_t* ErrorLinkExist=L"Link exist."; +const wchar_t* ErrorCylicLink=L"Link failed. No cyclic link allowed."; +const wchar_t* FormatLink=L"Link from thread%.4x to thread%.4x."; +const wchar_t* ErrorLink=L"Link failed. Source or/and destination thread not found."; +const wchar_t* ErrorDeleteCombo=L"Error delete from combo."; //window.cpp -const wchar_t* ClassName = L"ITH"; -const wchar_t* ClassNameAdmin = L"ITH (°ü¸®ÀÚ)"; -const wchar_t* ErrorNotSplit = L"¸ÕÀú ¹®´Ü ³ª´©±â¸¦ È°¼ºÈ­ÇØÁÖ¼¼¿ä!"; -const wchar_t* ErrorNotModule = L"¸ÕÀú ¸ðµâÀ» È°¼ºÈ­ÇØÁÖ¼¼¿ä!"; +const wchar_t* ClassName=L"ITH"; +const wchar_t* ClassNameAdmin=L"ITH (Administrator)"; +const wchar_t* ErrorNotSplit=L"Need to enable split first!"; +const wchar_t* ErrorNotModule=L"Need to enable module first!"; //Main window buttons -const wchar_t* ButtonTitleProcess = L"ÇÁ·Î¼¼½º"; -const wchar_t* ButtonTitleThread = L"½º·¹µå"; -const wchar_t* ButtonTitleHook = L"ÈÄÅ·"; -const wchar_t* ButtonTitleProfile = L"ÇÁ·ÎÇÊ"; -const wchar_t* ButtonTitleOption = L"¿É¼Ç"; -const wchar_t* ButtonTitleClear = L"Áö¿ì±â"; -const wchar_t* ButtonTitleSave = L"ÀúÀå"; -const wchar_t* ButtonTitleTop = L"Ç×»óÀ§"; +const wchar_t* ButtonTitleProcess=L"Process"; +const wchar_t* ButtonTitleThread=L"Thread"; +const wchar_t* ButtonTitleHook=L"Hook"; +const wchar_t* ButtonTitleProfile=L"Profile"; +const wchar_t* ButtonTitleOption=L"Option"; +const wchar_t* ButtonTitleClear=L"Clear"; +const wchar_t* ButtonTitleSave=L"Save"; +const wchar_t* ButtonTitleTop=L"Top"; //Hook window -const wchar_t* SpecialHook = L"HÄÚµå ÈÄÅ·, AGTH ÄÚµå´Â Áö¿øÇÏÁö ¾Ê½À´Ï´Ù."; +const wchar_t* SpecialHook=L"Special hook, no AGTH equivalent."; //Process window -const wchar_t* TabTitlePID = L"PID"; -const wchar_t* TabTitleMemory = L"¸Þ¸ð¸®"; -const wchar_t* TabTitleName = L"À̸§"; -const wchar_t* TabTitleTID = L"TID"; -const wchar_t* TabTitleStart = L"½ÃÀÛ"; -const wchar_t* TabTitleModule = L"¸ðµâ"; -const wchar_t* TabTitleState = L"»óÅÂ"; -const wchar_t* SuccessAttach = L"ÇÁ·Î¼¼½º¿¡ ITH ºÎÂø¼º°ø."; -const wchar_t* FailAttach = L"ÇÁ·Î¼¼½º¿¡ ITH ºÎÂø½ÇÆÐ."; -const wchar_t* SuccessDetach = L"ÇÁ·Î¼¼½º¿¡¼­ ITH Å»Âø¼º°ø."; -const wchar_t* FailDetach = L"ITH Å»Âø½ÇÆÐ."; +const wchar_t* TabTitlePID=L"PID"; +const wchar_t* TabTitleMemory=L"Memory"; +const wchar_t* TabTitleName=L"Name"; +const wchar_t* TabTitleTID=L"TID"; +const wchar_t* TabTitleStart=L"Start"; +const wchar_t* TabTitleModule=L"Module"; +const wchar_t* TabTitleState=L"State"; +const wchar_t* SuccessAttach=L"Attach ITH to process successfully."; +const wchar_t* FailAttach=L"Failed to attach ITH to process."; +const wchar_t* SuccessDetach=L"ITH detach from process."; +const wchar_t* FailDetach=L"Detach failed."; //Profile window -const wchar_t* ProfileExist = L"ÇÁ·ÎÇÊÀÌ ÀÌ¹Ì Á¸ÀçÇÔ."; -const wchar_t* SuccessAddProfile = L"ÇÁ·ÎÇÊ Ãß°¡µÊ."; -const wchar_t* FailAddProfile = L"ÇÁ·ÎÇÊ Ãß°¡½ÇÆÐ"; -const wchar_t* TabTitleNumber = L"No."; -const wchar_t* NoFile = L"ÆÄÀÏÀ» ãÀ» ¼ö ¾øÀ½."; -const wchar_t* PathDismatch = L"ÇÁ·Î¼¼½º À̸§ÀÌ ÀÏÄ¡ÇÏÁö ¾Ê½À´Ï´Ù, °è¼ÓÇϽðڽÀ´Ï±î?"; -const wchar_t* SuccessImportProfile = L"ÇÁ·ÎÇÊ °¡Á®¿À±â ¼º°ø"; +const wchar_t* ProfileExist=L"Profile already exists."; +const wchar_t* SuccessAddProfile=L"Profile added."; +const wchar_t* FailAddProfile=L"Fail to add profile"; +const wchar_t* TabTitleNumber=L"No."; +const wchar_t* NoFile=L"Can't find file."; +const wchar_t* PathDismatch=L"Process name dismatch, continue?"; +const wchar_t* SuccessImportProfile=L"Import profile success"; //const wchar_t* SuccessAddProfile=L"Profile added."; \ No newline at end of file diff --git a/gui/window.cpp b/gui/window.cpp index df24e62..0f3a862 100644 --- a/gui/window.cpp +++ b/gui/window.cpp @@ -280,19 +280,19 @@ LRESULT CALLBACK EditCmdProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPar void CreateButtons(HWND hWnd) { - hwndProcess = CreateWindow(L"Button", L"ÇÁ·Î¼¼½º", WS_CHILD | WS_VISIBLE, + hwndProcess = CreateWindow(L"Button", L"Process", WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hWnd, 0, hIns, NULL); - hwndOption = CreateWindow(L"Button", L"¿É¼Ç", WS_CHILD | WS_VISIBLE, + hwndOption = CreateWindow(L"Button", L"Option", WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hWnd, 0, hIns, NULL); - hwndClear = CreateWindow(L"Button", L"Áö¿ì±â", WS_CHILD | WS_VISIBLE, + hwndClear = CreateWindow(L"Button", L"Clear", WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hWnd, 0, hIns, NULL); - hwndSave = CreateWindow(L"Button", L"ÀúÀå", WS_CHILD | WS_VISIBLE, + hwndSave = CreateWindow(L"Button", L"Save", WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hWnd, 0, hIns, NULL); - hwndRemoveLink = CreateWindow(L"Button", L"¸µÅ©ÇØÁ¦", WS_CHILD | WS_VISIBLE, + hwndRemoveLink = CreateWindow(L"Button", L"Unlink", WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hWnd, 0, hIns, NULL); - hwndRemoveHook = CreateWindow(L"Button", L"ÈÄÅ·ÇØÁ¦", WS_CHILD | WS_VISIBLE, + hwndRemoveHook = CreateWindow(L"Button", L"Unhook", WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hWnd, 0, hIns, NULL); - hwndTop = CreateWindow(L"Button", L"Ç×»óÀ§", WS_CHILD | WS_VISIBLE | BS_PUSHLIKE | BS_CHECKBOX, + hwndTop = CreateWindow(L"Button", L"Top", WS_CHILD | WS_VISIBLE | BS_PUSHLIKE | BS_CHECKBOX, 0, 0, 0, 0, hWnd, 0, hIns, NULL); hwndProcessComboBox = CreateWindow(L"ComboBox", NULL, WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | diff --git a/i18n/gui_korean/CustomFilter.cpp b/i18n/gui_korean/CustomFilter.cpp new file mode 100644 index 0000000..9fe03f0 --- /dev/null +++ b/i18n/gui_korean/CustomFilter.cpp @@ -0,0 +1,44 @@ +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com) + * This file is part of the Interactive Text Hooker. + + * Interactive Text Hooker is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "CustomFilter.h" + +void CustomFilter::Insert(WORD number) +{ + set.insert(number); +} + +void CustomFilter::Erase(WORD number) +{ + set.erase(number); +} + +bool CustomFilter::Find(WORD number) const +{ + return set.find(number) != set.end(); +} + +void CustomFilter::Clear() +{ + set.clear(); +} + +void CustomFilter::Traverse(CustomFilterCallBack callback, PVOID param) +{ + for (auto ch = set.begin(); ch != set.end(); ++ch) + callback(*ch, param); +} diff --git a/i18n/gui_korean/CustomFilter.h b/i18n/gui_korean/CustomFilter.h new file mode 100644 index 0000000..fb298a0 --- /dev/null +++ b/i18n/gui_korean/CustomFilter.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com) + * This file is part of the Interactive Text Hooker. + + * Interactive Text Hooker is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "ITH.h" + +typedef void (*CustomFilterCallBack) (WORD, PVOID); + +class CustomFilter +{ +public: + bool Find(WORD number) const; + void Insert(WORD number); + void Erase(WORD number); + void Clear(); + void Traverse(CustomFilterCallBack callback, PVOID param); +private: + std::set set; +}; diff --git a/i18n/gui_korean/ITH.h b/i18n/gui_korean/ITH.h new file mode 100644 index 0000000..0701399 --- /dev/null +++ b/i18n/gui_korean/ITH.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com) + * This file is part of the Interactive Text Hooker. + + * Interactive Text Hooker is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "profile/pugixml.hpp" +#pragma warning(disable: 4146) diff --git a/i18n/gui_korean/ITHVNR.rc b/i18n/gui_korean/ITHVNR.rc new file mode 100644 index 0000000..3f66f64 --- /dev/null +++ b/i18n/gui_korean/ITHVNR.rc @@ -0,0 +1,82 @@ +// Generated by ResEdit 1.6.5 +// Copyright (C) 2006-2015 +// http://www.resedit.net + +#include +#include +#include +#include "resource.h" + + + + +// +// Dialog resources +// +LANGUAGE LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN +IDD_DIALOG2 DIALOGEX 100, 100, 341, 210 +STYLE DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU +CAPTION "Process Explorer" +FONT 8, "MS Shell Dlg", 400, 0, 1 +{ + DEFPUSHBUTTON "È®ÀÎ", IDOK, 281, 189, 53, 14, 0, WS_EX_LEFT + PUSHBUTTON "ÇÁ·ÎÇÊ Á¦°Å", IDC_BUTTON6, 226, 189, 53, 14, 0, WS_EX_LEFT + CONTROL "", IDC_LIST1, WC_LISTVIEW, WS_TABSTOP | WS_BORDER | LVS_ALIGNLEFT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_REPORT, 7, 20, 327, 164, WS_EX_LEFT + LTEXT "ÇÁ·Î¼¼½º", IDC_STATIC, 7, 7, 65, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT + PUSHBUTTON "ºÎÂø", IDC_BUTTON2, 61, 189, 53, 14, 0, WS_EX_LEFT + PUSHBUTTON "Å»Âø", IDC_BUTTON3, 116, 189, 53, 14, 0, WS_EX_LEFT + PUSHBUTTON "ÇÁ·ÎÇÊ Ãß°¡", IDC_BUTTON5, 171, 189, 53, 14, 0, WS_EX_LEFT + PUSHBUTTON "»õ·Î°íħ", IDC_BUTTON1, 7, 189, 53, 14, 0, WS_EX_LEFT +} + + + +LANGUAGE LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN +IDD_DIALOG4 DIALOGEX 150, 100, 123, 185 +STYLE DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU +CAPTION "Option" +FONT 8, "MS Shell Dlg", 400, 0, 1 +{ + DEFPUSHBUTTON "È®ÀÎ", IDOK, 8, 164, 50, 14, 0, WS_EX_LEFT + PUSHBUTTON "Ãë¼Ò", IDCANCEL, 65, 164, 50, 14, 0, WS_EX_LEFT + EDITTEXT IDC_EDIT1, 60, 7, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT + LTEXT "¹®´Ü³ª´©±â", IDC_STATIC, 7, 7, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT + EDITTEXT IDC_EDIT2, 60, 25, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT + LTEXT "ÇÁ·Î¼¼½º ´ë±â", IDC_STATIC, 7, 26, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT + EDITTEXT IDC_EDIT3, 60, 45, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT + LTEXT "ÀÎÁ§¼Ç ´ë±â", IDC_STATIC, 7, 45, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT + EDITTEXT IDC_EDIT4, 60, 65, 55, 14, ES_AUTOHSCROLL, WS_EX_LEFT + LTEXT "»ðÀÔ ´ë±â", IDC_STATIC, 7, 65, 47, 13, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT + AUTOCHECKBOX "ÀÚµ¿ ºÎÂø", IDC_CHECK1, 7, 87, 54, 10, 0, WS_EX_LEFT + AUTOCHECKBOX "ÀÚµ¿ »ðÀÔ", IDC_CHECK2, 62, 87, 50, 10, 0, WS_EX_LEFT + AUTOCHECKBOX "Ŭ¸³º¸µå·Î ÀÚµ¿ º¹»ç", IDC_CHECK3, 7, 103, 88, 10, 0, WS_EX_LEFT + AUTOCHECKBOX "ÀÚµ¿ ¹Ýº¹¹® Á¦°Å", IDC_CHECK4, 7, 119, 95, 10, 0, WS_EX_LEFT + AUTOCHECKBOX "¹®ÀÚÇÊÅÍ ÃʱâÈ­", IDC_CHECK6, 7, 149, 81, 8, 0, WS_EX_LEFT + AUTOCHECKBOX "±Û·Î¹ú ÇÊÅÍ È°¼ºÈ­", IDC_CHECK5, 7, 134, 75, 10, 0, WS_EX_LEFT +} + + + +// +// Icon resources +// +LANGUAGE LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN +IDI_ICON1 ICON "icon1.ico" + + + +// +// Version Information resources +// +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +1 VERSIONINFO + FILEVERSION 0,0,0,0 + PRODUCTVERSION 0,0,0,0 + FILEOS VOS_UNKNOWN + FILETYPE VFT_UNKNOWN + FILESUBTYPE VFT2_UNKNOWN + FILEFLAGSMASK 0 + FILEFLAGS 0 +{ + +} diff --git a/i18n/gui_korean/ProcessWindow.cpp b/i18n/gui_korean/ProcessWindow.cpp new file mode 100644 index 0000000..b7906c9 --- /dev/null +++ b/i18n/gui_korean/ProcessWindow.cpp @@ -0,0 +1,145 @@ +#include "ProcessWindow.h" +#include "resource.h" +#include "host/host.h" +#include "host/hookman.h" +#include "ProfileManager.h" +#include "profile/Profile.h" + +extern HookManager* man; // main.cpp +extern ProfileManager* pfman; // ProfileManager.cpp + +ProcessWindow::ProcessWindow(HWND hDialog) : hDlg(hDialog) +{ + hbRefresh = GetDlgItem(hDlg, IDC_BUTTON1); + hbAttach = GetDlgItem(hDlg, IDC_BUTTON2); + hbDetach = GetDlgItem(hDlg, IDC_BUTTON3); + hbAddProfile = GetDlgItem(hDlg, IDC_BUTTON5); + hbRemoveProfile = GetDlgItem(hDlg, IDC_BUTTON6); + EnableWindow(hbAddProfile, FALSE); + EnableWindow(hbRemoveProfile, FALSE); + hlProcess = GetDlgItem(hDlg, IDC_LIST1); + heOutput = GetDlgItem(hDlg, IDC_EDIT1); + ListView_SetExtendedListViewStyleEx(hlProcess, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); + InitProcessDlg(); + RefreshProcess(); + EnableWindow(hbDetach, FALSE); + EnableWindow(hbAttach, FALSE); +} + +void ProcessWindow::InitProcessDlg() +{ + LVCOLUMN lvc = {}; + lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; + lvc.fmt = LVCFMT_RIGHT; // left-aligned column + lvc.cx = 40; + lvc.pszText = L"PID"; + ListView_InsertColumn(hlProcess, 0, &lvc); + lvc.cx = 100; + lvc.fmt = LVCFMT_LEFT; // left-aligned column + lvc.pszText = L"Name"; + ListView_InsertColumn(hlProcess, 1, &lvc); +} + +void ProcessWindow::RefreshProcess() +{ + ListView_DeleteAllItems(hlProcess); + LVITEM item = {}; + item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; + DWORD idProcess[1024], cbNeeded; + WCHAR path[MAX_PATH]; + + if (EnumProcesses(idProcess, sizeof(idProcess), &cbNeeded)) + { + DWORD len = cbNeeded / sizeof(DWORD); + for (DWORD i = 0; i < len; ++i) + { + DWORD pid = idProcess[i]; + UniqueHandle hProcess(OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid)); + if (hProcess) + { + if (GetProcessImageFileName(hProcess.get(), path, MAX_PATH)) + { + WCHAR buffer[256]; + std::swprintf(buffer, L"%d", pid); + PWCHAR name = wcsrchr(path, L'\\') + 1; + item.pszText = buffer; + item.lParam = pid; + ListView_InsertItem(hlProcess, &item); + ListView_SetItemText(hlProcess, item.iItem, 1, name); + } + } + } + } +} + +void ProcessWindow::AttachProcess() +{ + DWORD pid = GetSelectedPID(); + if (Host_InjectByPID(pid)) + { + Host_HijackProcess(pid); + RefreshThreadWithPID(pid, true); + } +} + +void ProcessWindow::DetachProcess() +{ + DWORD pid = GetSelectedPID(); + if (Host_ActiveDetachProcess(pid) == 0) + RefreshThreadWithPID(pid, false); +} + +void ProcessWindow::CreateProfileForSelectedProcess() +{ + DWORD pid = GetSelectedPID(); + auto path = GetProcessPath(pid); + if (!path.empty()) + { + Profile* pf = pfman->CreateProfile(pid); + pfman->SaveProfiles(); + RefreshThread(ListView_GetSelectionMark(hlProcess)); + } +} + +void ProcessWindow::DeleteProfileForSelectedProcess() +{ + DWORD pid = GetSelectedPID(); + auto path = GetProcessPath(pid); + if (!path.empty()) + { + pfman->DeleteProfile(path); + RefreshThread(ListView_GetSelectionMark(hlProcess)); + } +} + +void ProcessWindow::RefreshThread(int index) +{ + LVITEM item = {}; + item.mask = LVIF_PARAM; + item.iItem = index; + ListView_GetItem(hlProcess, &item); + DWORD pid = item.lParam; + bool isAttached = man->GetProcessRecord(pid) != NULL; + RefreshThreadWithPID(pid, isAttached); +} + +void ProcessWindow::RefreshThreadWithPID(DWORD pid, bool isAttached) +{ + EnableWindow(hbDetach, isAttached); + EnableWindow(hbAttach, !isAttached); + auto path = GetProcessPath(pid); + bool hasProfile = !path.empty() && pfman->HasProfile(path); + EnableWindow(hbAddProfile, isAttached && !hasProfile); + EnableWindow(hbRemoveProfile, hasProfile); + if (pid == GetCurrentProcessId()) + EnableWindow(hbAttach, FALSE); +} + +DWORD ProcessWindow::GetSelectedPID() +{ + LVITEM item = {}; + item.mask = LVIF_PARAM; + item.iItem = ListView_GetSelectionMark(hlProcess); + ListView_GetItem(hlProcess, &item); + return item.lParam; +} diff --git a/i18n/gui_korean/ProcessWindow.h b/i18n/gui_korean/ProcessWindow.h new file mode 100644 index 0000000..ffa584e --- /dev/null +++ b/i18n/gui_korean/ProcessWindow.h @@ -0,0 +1,23 @@ +#pragma once + +#include "ITH.h" + +class ProcessWindow +{ +public: + ProcessWindow(HWND hDialog); + void InitProcessDlg(); + void RefreshProcess(); + void AttachProcess(); + void DetachProcess(); + void CreateProfileForSelectedProcess(); + void DeleteProfileForSelectedProcess(); + void RefreshThread(int index); +private: + void RefreshThreadWithPID(DWORD pid, bool isAttached); + DWORD GetSelectedPID(); + HWND hDlg; + HWND hlProcess; + HWND hbRefresh,hbAttach,hbDetach,hbAddProfile,hbRemoveProfile; + HWND heOutput; +}; diff --git a/i18n/gui_korean/ProfileManager.cpp b/i18n/gui_korean/ProfileManager.cpp new file mode 100644 index 0000000..f60d517 --- /dev/null +++ b/i18n/gui_korean/ProfileManager.cpp @@ -0,0 +1,218 @@ +#include "ProfileManager.h" +#include "profile/Profile.h" +#include "host/host.h" +#include "host/hookman.h" +#include "vnrhook/include/types.h" +#include "vnrhook/include/const.h" +#include "utility.h" +#include "profile/misc.h" + +extern HookManager* man; // main.cpp +extern LONG auto_inject, auto_insert, inject_delay; // main.cpp +extern LONG insert_delay, process_time; // main.cpp +bool MonitorFlag; +ProfileManager* pfman; + +DWORD WINAPI MonitorThread(LPVOID lpThreadParameter); + +ProfileManager::ProfileManager() : +hMonitorThread(IthCreateThread(MonitorThread, 0)) +{ + LoadProfiles(); +} + +ProfileManager::~ProfileManager() +{ + SaveProfiles(); + WaitForSingleObject(hMonitorThread.get(), 0); +} + +Profile* ProfileManager::GetProfile(DWORD pid) +{ + std::wstring path = GetProcessPath(pid); + if (!path.empty()) + { + auto node = profile_tree.find(path); + if (node != profile_tree.end()) + return node->second.get(); + } + return NULL; +} + +bool ProfileManager::CreateProfile(pugi::xml_node game) +{ + auto file = game.child(L"File"); + auto profile = game.child(L"Profile"); + if (!file || !profile) + return false; + auto path = file.attribute(L"Path"); + if (!path) + return false; + auto profile_title = game.attribute(L"Title"); + auto title = profile_title ? profile_title.value() : L""; + auto pf = new Profile(title); + if (!pf->XmlReadProfile(profile)) + return false; + CSLock lock(cs); + auto& oldProfile = profile_tree[path.value()]; + if (!oldProfile) + oldProfile.swap(profile_ptr(pf)); + return true; +} + +Profile* ProfileManager::CreateProfile(DWORD pid) +{ + CSLock lock(cs); + auto path = GetProcessPath(pid); + auto& pf = profile_tree[path]; + if (!pf) + { + std::wstring title = GetProcessTitle(pid); + pf.reset(new Profile(title)); + } + return pf.get(); +} + +void ProfileManager::WriteProfileXml(const std::wstring& path, Profile& pf, pugi::xml_node root) +{ + auto game = root.append_child(L"Game"); + auto file_node = game.append_child(L"File"); + file_node.append_attribute(L"Path") = path.c_str(); + auto profile_node = game.append_child(L"Profile"); + pf.XmlWriteProfile(profile_node); + if (!pf.Title().empty()) + { + if (!game.attribute(L"Title")) + game.append_attribute(L"Title"); + game.attribute(L"Title") = pf.Title().c_str(); + } +} + +void ProfileManager::LoadProfiles() +{ + pugi::xml_document doc; + UniqueHandle hFile(IthCreateFile(L"ITH_Profile.xml", GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING)); + if (hFile.get() == INVALID_HANDLE_VALUE) + return; + DWORD size = GetFileSize(hFile.get(), NULL); + std::unique_ptr buffer(new char[size]); + ReadFile(hFile.get(), buffer.get(), size, &size, NULL); + auto result = doc.load_buffer(buffer.get(), size); + if (!result) + return; + auto root = doc.root().child(L"ITH_Profile"); + if (!root) + return; + for (auto game = root.begin(); game != root.end(); ++game) + CreateProfile(*game); +} + +void ProfileManager::SaveProfiles() +{ + pugi::xml_document doc; + auto root = doc.append_child(L"ITH_Profile"); + for (auto it = profile_tree.begin(); it != profile_tree.end(); ++it) { + auto& path = it->first; + auto& profile = it->second; + WriteProfileXml(path, *profile, root); + } + UniqueHandle hFile(IthCreateFile(L"ITH_Profile.xml", GENERIC_WRITE, 0, CREATE_ALWAYS)); + if (hFile.get() != INVALID_HANDLE_VALUE) + { + FileWriter fw(hFile.get()); + doc.save(fw); + } +} + +void ProfileManager::DeleteProfile(const std::wstring& path) +{ + CSLock lock(cs); + profile_tree.erase(profile_tree.find(path)); +} + +Profile* ProfileManager::GetProfile(const std::wstring& path) +{ + if (path.empty()) + return nullptr; + auto it = profile_tree.find(path); + if (it == profile_tree.end()) + return nullptr; + return it->second.get(); +} + +bool ProfileManager::HasProfile(const std::wstring& path) +{ + return profile_tree.find(path) != profile_tree.end(); +} + +DWORD ProfileManager::CountProfiles() +{ + return profile_tree.size(); +} + +DWORD WINAPI InjectThread(LPVOID lpThreadParameter) +{ + DWORD pid = (DWORD)lpThreadParameter; + Sleep(inject_delay); + if (man == NULL) + return 0; + DWORD status = Host_InjectByPID(pid); + if (!auto_insert) + return status; + if (status == -1) + return status; + Sleep(insert_delay); + const Profile* pf = pfman->GetProfile(pid); + if (pf) + { + SendParam sp; + sp.type = 0; + for (auto hp = pf->Hooks().begin(); hp != pf->Hooks().end(); ++hp) + { + std::string name = toMultiByteString((*hp)->Name()); + Host_InsertHook(pid, const_cast(&(*hp)->HP()), name.c_str()); + } + } + return status; +} + +DWORD WINAPI MonitorThread(LPVOID lpThreadParameter) +{ + while (MonitorFlag) + { + DWORD aProcesses[1024], cbNeeded, cProcesses; + if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) + break; + cProcesses = cbNeeded / sizeof(DWORD); + for (size_t i = 0; i < cProcesses; ++i) + { + Sleep(process_time); + if (!auto_inject || man == NULL || man->GetProcessRecord(aProcesses[i])) + continue; + std::wstring process_path = GetProcessPath(aProcesses[i]); + if (!process_path.empty() && pfman->HasProfile(process_path)) + { + UniqueHandle hThread(IthCreateThread(InjectThread, aProcesses[i])); + WaitForSingleObject(hThread.get(), 0); + } + } + } + return 0; +} + +DWORD SaveProcessProfile(DWORD pid) +{ + std::wstring path = GetProcessPath(pid); + if (path.empty()) + return 0; + pugi::xml_document doc; + pugi::xml_node profile_node = doc.append_child(L"Profile"); + man->GetProfile(pid, profile_node); + Profile* pf = pfman->GetProfile(pid); + if (pf != NULL) + pf->Clear(); + else + pf = pfman->CreateProfile(pid); + pf->XmlReadProfile(profile_node); + return 0; +} diff --git a/i18n/gui_korean/ProfileManager.h b/i18n/gui_korean/ProfileManager.h new file mode 100644 index 0000000..64ed6d0 --- /dev/null +++ b/i18n/gui_korean/ProfileManager.h @@ -0,0 +1,35 @@ +#pragma once + +#include "ITH.h" +#include "utility.h" // UniqueHandle, CriticalSection + +class Profile; + +class ProfileManager +{ +public: + ProfileManager(); + ~ProfileManager(); + Profile* CreateProfile(DWORD pid); + Profile* GetProfile(DWORD pid); + Profile* GetProfile(const std::wstring& path); + void LoadProfiles(); + void SaveProfiles(); + void DeleteProfile(const std::wstring& path); + void UpdateHookAddresses(DWORD pid); + bool HasProfile(const std::wstring& path); +private: + typedef std::unique_ptr profile_ptr; + typedef std::map profile_map; + + ProfileManager(const ProfileManager&); + ProfileManager operator=(const ProfileManager&); + + DWORD CountProfiles(); + bool CreateProfile(pugi::xml_node game); + void WriteProfileXml(const std::wstring& path, Profile& pf, pugi::xml_node doc); + // locate profile with executable path + profile_map profile_tree; + CriticalSection cs; + UniqueHandle hMonitorThread; +}; diff --git a/i18n/gui_korean/TextBuffer.cpp b/i18n/gui_korean/TextBuffer.cpp new file mode 100644 index 0000000..ad3025c --- /dev/null +++ b/i18n/gui_korean/TextBuffer.cpp @@ -0,0 +1,41 @@ +#include "TextBuffer.h" + +DWORD WINAPI FlushThread(LPVOID lParam); // window.cpp + +TextBuffer::TextBuffer(HWND edit) : hThread(IthCreateThread(FlushThread, (DWORD)this)), +hEdit(edit), +running(true) +{ +} + +TextBuffer::~TextBuffer() +{ + running = false; + WaitForSingleObject(hThread.get(), 0); +} + +void TextBuffer::AddText(LPCWSTR str, int len, bool line) +{ + CSLock lock(cs); + if (len > 0) + this->str.append(str, len); + line_break = line; +} + +void TextBuffer::Flush() +{ + CSLock lock(cs); + if (line_break || str.empty()) + return; + DWORD t = Edit_GetTextLength(hEdit); + Edit_SetSel(hEdit, t, -1); + Edit_ReplaceSel(hEdit, str.c_str()); + str.clear(); +} + +void TextBuffer::ClearBuffer() +{ + CSLock lock(cs); + str.clear(); + line_break = false; +} diff --git a/i18n/gui_korean/TextBuffer.h b/i18n/gui_korean/TextBuffer.h new file mode 100644 index 0000000..20bd63f --- /dev/null +++ b/i18n/gui_korean/TextBuffer.h @@ -0,0 +1,21 @@ +#pragma once + +#include "ITH.h" +#include "utility.h" // UniqueHandle, CriticalSection + +class TextBuffer +{ +public: + TextBuffer(HWND edit); + ~TextBuffer(); + void Flush(); + void AddText(LPCWSTR str, int len, bool line); + void ClearBuffer(); + bool Running() { return running; } +private: + CriticalSection cs; + bool line_break, running; + UniqueHandle hThread; + HWND hEdit; + std::wstring str; +}; diff --git a/i18n/gui_korean/command.cpp b/i18n/gui_korean/command.cpp new file mode 100644 index 0000000..79d5fb4 --- /dev/null +++ b/i18n/gui_korean/command.cpp @@ -0,0 +1,73 @@ +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com) + * This file is part of the Interactive Text Hooker. + + * Interactive Text Hooker is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ITH.h" +#include "host/host.h" +#include "vnrhook/include/const.h" +#include "vnrhook/include/types.h" +#include "language.h" +#include "utility.h" +#include "profile/misc.h" + +extern HookManager* man; +extern HWND hwndProcessComboBox; + +DWORD ProcessCommand(const std::wstring& cmd, DWORD pid) +{ + using std::wregex; + using std::regex_match; + std::match_results m; + + if (regex_match(cmd, m, wregex(L"/pn(.+)", wregex::icase))) + { + pid = Host_GetPIDByName(m[1].str().c_str()); + if (pid == 0) + return 0; + Host_InjectByPID(pid); + } + else if (regex_match(cmd, m, wregex(L"/p(\\d+)", wregex::icase))) + { + pid = std::stoul(m[1].str()); + Host_InjectByPID(pid); + } + else if (regex_match(cmd, m, wregex(L"/h(.+)", wregex::icase))) + { + HookParam hp = {}; + if (Parse(m[1].str(), hp)) + Host_InsertHook(pid, &hp); + } + else if (regex_match(cmd, m, wregex(L"(?::|)(?:¤·|¿¬|l|)([[:xdigit:]]+)(?:-| )([[:xdigit:]]+)", wregex::icase))) + { + DWORD from = std::stoul(m[1].str(), NULL, 16); + DWORD to = std::stoul(m[2].str(), NULL, 16); + Host_AddLink(from, to); + } + else if (regex_match(cmd, m, wregex(L"(?::|)(?:¤¾|ÇØ|ÇØÁ¦|u)([[:xdigit:]]+)", wregex::icase))) + { + DWORD from = std::stoul(m[1].str(), NULL, 16); + Host_UnLink(from); + } + else if (regex_match(cmd, m, wregex(L"(?::|)(?:¤§|µµ|µµ¿ò|µµ¿ò¸»|h|help)", wregex::icase))) + { + ConsoleOutput(Usage); + } + else + { + ConsoleOutput(L"¾Ë ¼ö ¾ø´Â ¸í·É¾î. µµ¿ò¸»À» º¸½Ã·Á¸é, :h ³ª :help¸¦ ÀÔ·ÂÇϼ¼¿ä."); + } + return 0; +} diff --git a/i18n/gui_korean/icon1.ico b/i18n/gui_korean/icon1.ico new file mode 100644 index 0000000..bfc3455 Binary files /dev/null and b/i18n/gui_korean/icon1.ico differ diff --git a/i18n/gui_korean/language.cpp b/i18n/gui_korean/language.cpp new file mode 100644 index 0000000..ee33716 --- /dev/null +++ b/i18n/gui_korean/language.cpp @@ -0,0 +1,133 @@ +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com) + * This file is part of the Interactive Text Hooker. + + * Interactive Text Hooker is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +const wchar_t* Warning = L"°æ°í!"; +//command.cpp +const wchar_t* ErrorSyntax = L"¸í·É¾î ¿À·ù"; +const wchar_t* Usage = L"¸í·É¾î:\r\n\ +\r\n\ +µµ¿ò¸» //µµ¿ò¸»À» Ãâ·ÂÇÕ´Ï´Ù\r\n\ +Ãâ¹ß µµÂø // 'Ãâ¹ß'½º·¹µå¿¡¼­ 'µµÂø'½º·¹µå·Î ¿¬°áÇÕ´Ï´Ù\r\n\ +¤¾Ãâ¹ß // 'Ãâ¹ß'½º·¹µå¿¡ ¿¬°áµÈ ¸µÅ©¸¦ ÇØÁ¦ÇÕ´Ï´Ù\r\n\ +\r\n\ +'Ãâ¹ß'°ú 'µµÂø'¿¡´Â 16Áø¹ý(Çí»çÄÚµå) ½º·¹µå¹øÈ£¸¦ ÀÔ·ÂÇÕ´Ï´Ù. ½º·¹µå ¹øÈ£´Â ¸Ç ¾Õ¿¡ Àִ ù ¹ø° ¼ýÀÚ¿­ÀÔ´Ï´Ù.\r\n\ +\r\n\ +·Î´õ ¿É¼Ç:\r\n\ +/P[{process_id|Nprocess_name}] //ÇÁ·Î¼¼½º¿¡ ºÎÂø\r\n\ +\r\n\ +HÄÚµå ÈÄÅ· ¿É¼Ç:\r\n\ +/H[X]{A|B|W|S|Q}[N][data_offset[*drdo]][:sub_offset[*drso]]@addr[:module[:{name|#ordinal}]]\r\n\ +\r\n\ +(¼­¼ö¸¦ Á¦¿ÜÇÑ) /HÄÚµåÀÇ ¸ðµç ¼ýÀÚ´Â ¾Æ¹«°Íµµ 󸮵ÇÁö ¾ÊÀº 16Áø¹ý(Çí»çÄÚµå)ÀÔ´Ï´Ù"; + +const wchar_t* ExtendedUsage = L"/H[X]{A|B|W|S|Q}[N][data_offset[*drdo]][:sub_offset[*drso]]@addr[:[module[:{name|#ordinal}]]]\r\n\ +\r\n\ +Ãß°¡ »ç¿ëÀÚÁ¤ÀÇ ÈÄÅ·¼³Á¤\r\n\ +\r\n\ +ÈÄÅ· Á¾·ù :\r\n\ +A - DBCS ¹®ÀÚ\r\n\ +B - DBCS ¹®ÀÚ(big-endian)\r\n\ +W - UCS2 ¹®ÀÚ\r\n\ +S - MBCS ¹®ÀÚ¿­\r\n\ +Q - UTF-16 ¹®ÀÚ¿­\r\n\ +\r\n\ +¸Å°³º¯¼ö:\r\n\ +X - Çϵå¿þ¾î ±¸È¹Á¡ »ç¿ë\r\n\ +N - ¹®¹ýÀ» »ç¿ëÇÏÁö ¾ÊÀ½\r\n\ +data_offset - stack offset to char / string pointer\r\n\ +drdo - add a level of indirection to data_offset\r\n\ +sub_offset - stack offset to subcontext\r\n\ +drso - add a level of indirection to sub_offset\r\n\ +addr - ÈÄÅ·ÇÒ ÁÖ¼Ò\r\n\ +module - name of the module to use as base for 'addr'\r\n\ +name - name of the 'module' export to use as base for 'addr'\r\n\ +ordinal - number of the 'module' export ordinal to use as base for 'addr'\r\n\ +\r\n\ +Negative values of 'data_offset' and 'sub_offset' refer to registers: \r\n\ +- 4 for EAX, -8 for ECX, -C for EDX, -10 for EBX, -14 for ESP, -18 for EBP, -1C for ESI, -20 for EDI\r\n\ +\r\n\ +\"Add a level of indirection\" means in C/C++ style: (*(ESP+data_offset)+drdo) instead of (ESP+data_offset)\r\n\ +\r\n\ +All numbers except ordinal are hexadecimal without any prefixes"; + +//inject.cpp +const wchar_t* ErrorRemoteThread = L"¿ø°Ý ½º·¹µå¸¦ »ý¼ºÇÒ ¼ö ¾øÀ½."; +const wchar_t* ErrorOpenProcess = L"ÇÁ·Î¼¼½º¸¦ ¿­ ¼ö ¾øÀ½."; +const wchar_t* ErrorNoProcess = L"ÇÁ·Î¼¼½º¸¦ ãÀ» ¼ö ¾øÀ½"; +const wchar_t* SelfAttach = L"ITH.exe¿¡ ºÎÂøÇÏÁö ¸»¾Æ ÁÖ¼¼¿ä"; +const wchar_t* AlreadyAttach = L"ÇÁ·Î¼¼½º°¡ ÀÌ¹Ì ºÎÂøµÊ."; +const wchar_t* FormatInject = L"ÇÁ·Î¼¼½º %d¿¡ ÀÎÁ§¼Ç. ¸ðµâ ±â¹Ý %.8X"; +//main.cpp +const wchar_t* NotAdmin = L"SeDebugPrevilegeÀ» È°¼ºÈ­ ÇÒ ¼ö ¾ø½À´Ï´Ù. ITH°¡ Á¦´ë·Î ÀÛµ¿ÇÏÁö ¸øÇÕ´Ï´Ù.\r\n\ +°ü¸®ÀÚ °èÁ¤À¸·Î ½ÇÇàÇϽðųª UAC¸¦ ²ô½Ã°í ITH¸¦ ½ÇÇàÇØ ÁÖ¼¼¿ä."; +//pipe.cpp +const wchar_t* ErrorCreatePipe = L"ÅؽºÆ® ÆÄÀÌÇÁ¸¦ »ý¼ºÇÒ ¼ö ¾ø°Å³ª, ¿äûÀÌ ³Ê¹« ¸¹½À´Ï´Ù."; +const wchar_t* FormatDetach = L"ÇÁ·Î¼¼½º %d°¡ Å»ÂøµÊ."; +const wchar_t* ErrorCmdQueueFull = L"¸í·É¾î ´ë±â¿­ÀÌ °¡µæÂü."; +const wchar_t* ErrorNoAttach = L"ÇÁ·Î¼¼½º°¡ ºÎÂøµÇÁö ¾ÊÀ½."; + +//profile.cpp +const wchar_t* ErrorMonitor = L"ÇÁ·Î¼¼½º¸¦ °¨½ÃÇÒ ¼ö ¾øÀ½."; +//utility.cpp +const wchar_t* InitMessage = L"Copyright (C) 2010-2012 kaosu \r\n\ +Copyright (C) 2015 zorkzero \r\n\ +¼Ò½ºÄÚµå \r\n\ +ÀϹÝÅä·Ð \r\n\ +ÇѱÛÈ­ @mireado"; +const wchar_t* BackgroundMsg = L"µµ¿ò¸»À» º¸½Ã·Á¸é, \"help\", \"µµ¿ò¸»\"À̳ª \"µµ¿ò\"À» ÀÔ·ÂÇϼ¼¿ä."; +const wchar_t* ErrorLinkExist = L"¿¬°áÀÌ Á¸ÀçÇÔ."; +const wchar_t* ErrorCylicLink = L"¿¬°á½ÇÆÐ. ¼øȯ¿¬°áÀº Çã¿ëµÇÁö ¾Ê½À´Ï´Ù."; +const wchar_t* FormatLink = L"Ãâ¹ß½º·¹µå%.4x¿¡¼­ µµÂø½º·¹µå%.4x·Î ¿¬°á."; +const wchar_t* ErrorLink = L"¿¬°á½ÇÆÐ. Ãâ¹ß/µµÂø ½º·¹µå¸¦ ãÀ» ¼ö ¾øÀ½."; +const wchar_t* ErrorDeleteCombo = L"±Û»óÀÚ¿¡¼­ Áö¿ì±â ½ÇÆÐ."; + +//window.cpp +const wchar_t* ClassName = L"ITH"; +const wchar_t* ClassNameAdmin = L"ITH (°ü¸®ÀÚ)"; +const wchar_t* ErrorNotSplit = L"¸ÕÀú ¹®´Ü ³ª´©±â¸¦ È°¼ºÈ­ÇØÁÖ¼¼¿ä!"; +const wchar_t* ErrorNotModule = L"¸ÕÀú ¸ðµâÀ» È°¼ºÈ­ÇØÁÖ¼¼¿ä!"; +//Main window buttons +const wchar_t* ButtonTitleProcess = L"ÇÁ·Î¼¼½º"; +const wchar_t* ButtonTitleThread = L"½º·¹µå"; +const wchar_t* ButtonTitleHook = L"ÈÄÅ·"; +const wchar_t* ButtonTitleProfile = L"ÇÁ·ÎÇÊ"; +const wchar_t* ButtonTitleOption = L"¿É¼Ç"; +const wchar_t* ButtonTitleClear = L"Áö¿ì±â"; +const wchar_t* ButtonTitleSave = L"ÀúÀå"; +const wchar_t* ButtonTitleTop = L"Ç×»óÀ§"; +//Hook window +const wchar_t* SpecialHook = L"HÄÚµå ÈÄÅ·, AGTH ÄÚµå´Â Áö¿øÇÏÁö ¾Ê½À´Ï´Ù."; +//Process window +const wchar_t* TabTitlePID = L"PID"; +const wchar_t* TabTitleMemory = L"¸Þ¸ð¸®"; +const wchar_t* TabTitleName = L"À̸§"; +const wchar_t* TabTitleTID = L"TID"; +const wchar_t* TabTitleStart = L"½ÃÀÛ"; +const wchar_t* TabTitleModule = L"¸ðµâ"; +const wchar_t* TabTitleState = L"»óÅÂ"; +const wchar_t* SuccessAttach = L"ÇÁ·Î¼¼½º¿¡ ITH ºÎÂø¼º°ø."; +const wchar_t* FailAttach = L"ÇÁ·Î¼¼½º¿¡ ITH ºÎÂø½ÇÆÐ."; +const wchar_t* SuccessDetach = L"ÇÁ·Î¼¼½º¿¡¼­ ITH Å»Âø¼º°ø."; +const wchar_t* FailDetach = L"ITH Å»Âø½ÇÆÐ."; +//Profile window +const wchar_t* ProfileExist = L"ÇÁ·ÎÇÊÀÌ ÀÌ¹Ì Á¸ÀçÇÔ."; +const wchar_t* SuccessAddProfile = L"ÇÁ·ÎÇÊ Ãß°¡µÊ."; +const wchar_t* FailAddProfile = L"ÇÁ·ÎÇÊ Ãß°¡½ÇÆÐ"; +const wchar_t* TabTitleNumber = L"No."; +const wchar_t* NoFile = L"ÆÄÀÏÀ» ãÀ» ¼ö ¾øÀ½."; +const wchar_t* PathDismatch = L"ÇÁ·Î¼¼½º À̸§ÀÌ ÀÏÄ¡ÇÏÁö ¾Ê½À´Ï´Ù, °è¼ÓÇϽðڽÀ´Ï±î?"; +const wchar_t* SuccessImportProfile = L"ÇÁ·ÎÇÊ °¡Á®¿À±â ¼º°ø"; +//const wchar_t* SuccessAddProfile=L"Profile added."; \ No newline at end of file diff --git a/i18n/gui_korean/language.h b/i18n/gui_korean/language.h new file mode 100644 index 0000000..141bf40 --- /dev/null +++ b/i18n/gui_korean/language.h @@ -0,0 +1,86 @@ +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com) + * This file is part of the Interactive Text Hooker. + + * Interactive Text Hooker is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +extern const wchar_t* Warning; +//command.cpp +extern const wchar_t* ErrorSyntax; +extern const wchar_t* Usage; +extern const wchar_t* ExtendedUsage; +//inject.cpp +extern const wchar_t* ErrorRemoteThread; +extern const wchar_t* ErrorOpenProcess; +extern const wchar_t* ErrorNoProcess; +extern const wchar_t* SelfAttach; +extern const wchar_t* AlreadyAttach; +extern const wchar_t* FormatInject; +//main.cpp +extern const wchar_t* NotAdmin; +//pipe.cpp +extern const wchar_t* ErrorCreatePipe; +extern const wchar_t* FormatDetach; +extern const wchar_t* ErrorCmdQueueFull; +extern const wchar_t* ErrorNoAttach; + +//profile.cpp +extern const wchar_t* ErrorMonitor; + +//utility.cpp +extern const wchar_t* InitMessage; +extern const wchar_t* BackgroundMsg; +extern const wchar_t* ErrorLinkExist; +extern const wchar_t* ErrorCylicLink; +extern const wchar_t* FormatLink; +extern const wchar_t* ErrorLink; +extern const wchar_t* ErrorDeleteCombo; + +//window.cpp +extern const wchar_t* ClassName; +extern const wchar_t* ClassNameAdmin; +extern const wchar_t* ErrorNotSplit; +extern const wchar_t* ErrorNotModule; +//Main window buttons +extern const wchar_t* ButtonTitleProcess; +extern const wchar_t* ButtonTitleThread; +extern const wchar_t* ButtonTitleHook; +extern const wchar_t* ButtonTitleProfile; +extern const wchar_t* ButtonTitleOption; +extern const wchar_t* ButtonTitleClear; +extern const wchar_t* ButtonTitleSave; +extern const wchar_t* ButtonTitleTop; +//Hook window +extern const wchar_t* SpecialHook; +//Process window +extern const wchar_t* TabTitlePID; +extern const wchar_t* TabTitleMemory; +extern const wchar_t* TabTitleName; +extern const wchar_t* TabTitleTID; +extern const wchar_t* TabTitleStart; +extern const wchar_t* TabTitleModule; +extern const wchar_t* TabTitleState; +extern const wchar_t* SuccessAttach; +extern const wchar_t* FailAttach; +extern const wchar_t* SuccessDetach; +extern const wchar_t* FailDetach; +//Profile window +extern const wchar_t* ProfileExist; +extern const wchar_t* SuccessAddProfile; +extern const wchar_t* FailAddProfile; +extern const wchar_t* TabTitleNumber; +extern const wchar_t* NoFile; +extern const wchar_t* PathDismatch; +extern const wchar_t* SuccessImportProfile; \ No newline at end of file diff --git a/i18n/gui_korean/main.cpp b/i18n/gui_korean/main.cpp new file mode 100644 index 0000000..d48fd46 --- /dev/null +++ b/i18n/gui_korean/main.cpp @@ -0,0 +1,286 @@ +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com) + * This file is part of the Interactive Text Hooker. + + * Interactive Text Hooker is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ITH.h" +#include "host/host.h" +#include "host/hookman.h" +#include "host/settings.h" +#include "CustomFilter.h" +#include "profile/Profile.h" +#include "ProfileManager.h" + +HINSTANCE hIns; +ATOM MyRegisterClass(HINSTANCE hInstance); +BOOL InitInstance(HINSTANCE hInstance, DWORD nCmdShow, RECT *rc); +RECT window; +extern HWND hMainWnd; // windows.cpp +extern bool MonitorFlag; // ProfileManager.cpp +extern ProfileManager* pfman; // ProfileManager.cpp + +extern "C" { + BOOL IthInitSystemService(); + void IthCloseSystemService(); +} + +CustomFilter* uni_filter; +CustomFilter* mb_filter; +HookManager* man; +Settings* setman; +LONG split_time, cyclic_remove, global_filter; +LONG process_time, inject_delay, insert_delay, +auto_inject, auto_insert, clipboard_flag; + +std::map setting; + +void RecordMBChar(WORD mb, PVOID f) +{ + auto filter = (pugi::xml_node*)f; + DWORD m = mb; + WCHAR buffer[16]; + std::swprintf(buffer, L"m%04X", m); + filter->append_attribute(buffer) = L"0"; +} + +void RecordUniChar(WORD uni, PVOID f) +{ + auto filter = (pugi::xml_node*)f; + DWORD m = uni; + WCHAR buffer[16]; + std::swprintf(buffer, L"u%04X", m); + filter->append_attribute(buffer) = L"0"; + std::wstring text = filter->text().get(); + text += (wchar_t)m; + filter->text().set(text.c_str()); +} + +void SaveSettings() +{ + WINDOWPLACEMENT wndpl; + wndpl.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement(hMainWnd, &wndpl); + setting[L"window_left"] = wndpl.rcNormalPosition.left; + setting[L"window_right"] = wndpl.rcNormalPosition.right; + setting[L"window_top"] = wndpl.rcNormalPosition.top; + setting[L"window_bottom"] = wndpl.rcNormalPosition.bottom; + setting[L"split_time"] = split_time; + setting[L"process_time"] = process_time; + setting[L"inject_delay"] = inject_delay; + setting[L"insert_delay"] = insert_delay; + setting[L"auto_inject"] = auto_inject; + setting[L"auto_insert"] = auto_insert; + setting[L"auto_copy"] = clipboard_flag; + setting[L"auto_suppress"] = cyclic_remove; + setting[L"global_filter"] = global_filter; + + UniqueHandle hFile(IthCreateFile(L"ITH.xml", GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS)); + if (hFile.get() != INVALID_HANDLE_VALUE) + { + FileWriter fw(hFile.get()); + pugi::xml_document doc; + auto root = doc.root().append_child(L"ITH_Setting"); + for (auto it = setting.begin(); it != setting.end(); ++it) + root.append_attribute(it->first.c_str()).set_value(it->second); + auto filter = root.append_child(L"SingleCharFilter"); + filter.append_child(pugi::xml_node_type::node_pcdata); + mb_filter->Traverse(RecordMBChar, &filter); + uni_filter->Traverse(RecordUniChar, &filter); + doc.save(fw); + } +} + +void DefaultSettings() +{ + setting[L"split_time"] = 200; + setting[L"process_time"] = 50; + setting[L"inject_delay"] = 3000; + setting[L"insert_delay"] = 500; + setting[L"auto_inject"] = 1; + setting[L"auto_insert"] = 1; + setting[L"auto_copy"] = 0; + setting[L"auto_suppress"] = 0; + setting[L"global_filter"] = 0; + setting[L"window_left"] = 100; + setting[L"window_right"] = 800; + setting[L"window_top"] = 100; + setting[L"window_bottom"] = 600; +} + +void InitializeSettings() +{ + split_time = setting[L"split_time"]; + process_time = setting[L"process_time"]; + inject_delay = setting[L"inject_delay"]; + insert_delay = setting[L"insert_delay"]; + auto_inject = setting[L"auto_inject"]; + auto_insert = setting[L"auto_insert"]; + clipboard_flag = setting[L"auto_copy"]; + cyclic_remove = setting[L"auto_suppress"]; + global_filter = setting[L"global_filter"]; + window.left = setting[L"window_left"]; + window.right = setting[L"window_right"]; + window.top = setting[L"window_top"]; + window.bottom = setting[L"window_bottom"]; + + if (auto_inject > 1) + auto_inject = 1; + if (auto_insert > 1) + auto_insert = 1; + if (clipboard_flag > 1) + clipboard_flag = 1; + if (cyclic_remove > 1) + cyclic_remove = 1; + + if (window.right < window.left || window.right - window.left < 600) + window.right = window.left + 600; + if (window.bottom < window.top || window.bottom - window.top < 200) + window.bottom = window.top + 200; +} + +void LoadSettings() +{ + UniqueHandle hFile(IthCreateFile(L"ITH.xml", GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING)); + if (hFile.get() != INVALID_HANDLE_VALUE) + { + DWORD size = GetFileSize(hFile.get(), NULL); + std::unique_ptr buffer(new char[size]); + ReadFile(hFile.get(), buffer.get(), size, &size, NULL); + pugi::xml_document doc; + auto result = doc.load_buffer_inplace(buffer.get(), size); + if (!result) + return; + auto root = doc.root().child(L"ITH_Setting"); + for (auto attr = root.attributes_begin(); attr != root.attributes_end(); ++attr) + { + auto it = setting.find(attr->name()); + if (it != setting.end()) + it->second = std::stoul(attr->value()); + } + auto filter = root.child(L"SingleCharFilter"); + if (filter) + { + for (auto attr = filter.attributes_begin(); attr != filter.attributes_end(); ++attr) + { + if (attr->name()[0] == L'm') + { + DWORD c = std::stoul(attr->name() + 1, NULL, 16); + mb_filter->Insert(c & 0xFFFF); + } + else if (attr->name()[0] == L'u') + { + DWORD c = std::stoul(attr->name() + 1, NULL, 16); + uni_filter->Insert(c & 0xFFFF); + } + } + std::wstring filter_value = filter.text().get(); + for (auto it = filter_value.begin(); it != filter_value.end(); ++it) + { + WCHAR filter_unichar[2] = { *it, L'\0' }; + char filter_mbchar[4]; + WC_MB(filter_unichar, filter_mbchar, 4); + mb_filter->Insert(*(WORD*)filter_mbchar); + uni_filter->Insert(*it); + } + } + } +} + +extern LPCWSTR ClassName, ClassNameAdmin; +static WCHAR mutex[] = L"ITH_RUNNING"; +DWORD FindITH() +{ + HWND hwnd = FindWindow(ClassName, ClassName); + if (hwnd == NULL) + hwnd = FindWindow(ClassName, ClassNameAdmin); + if (hwnd) + { + ShowWindow(hwnd, SW_SHOWNORMAL); + SetForegroundWindow(hwnd); + return 0; + } + return 1; +} +LONG WINAPI UnhandledExcept(_EXCEPTION_POINTERS *ExceptionInfo) +{ + wchar_t path_name[512]; // fully qualified path name + WCHAR code[16]; + EXCEPTION_RECORD* rec = ExceptionInfo->ExceptionRecord; + std::swprintf(code, L"%08X", rec->ExceptionCode); + MEMORY_BASIC_INFORMATION info; + if (VirtualQuery(rec->ExceptionAddress, &info, sizeof(info))) + { + if (GetModuleFileName((HMODULE)info.AllocationBase, path_name, 512)) + { + LPWSTR name = wcsrchr(path_name, L'\\'); + if (name) + { + DWORD addr = (DWORD)rec->ExceptionAddress; + std::swprintf(name, L"%s:%08X", name + 1, addr - (DWORD)info.AllocationBase); + MessageBox(NULL, name, code, MB_OK); + TerminateProcess(GetCurrentProcess(), 0); + } + } + } + std::swprintf(path_name, L"%08X", rec->ExceptionAddress); + MessageBox(NULL, path_name, code, MB_OK); + TerminateProcess(GetCurrentProcess(), 0); + return 0; +} + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + InitCommonControls(); + if (!IthInitSystemService()) + TerminateProcess(GetCurrentProcess(), 0); + CreateMutex(NULL, TRUE, L"ITH_MAIN_RUNNING"); + if (Host_Open()) + { + SetUnhandledExceptionFilter(UnhandledExcept); + Host_GetHookManager(&man); + Host_GetSettings(&setman); + setman->splittingInterval = 200; + MonitorFlag = true; + pfman = new ProfileManager(); + mb_filter = new CustomFilter(); + uni_filter = new CustomFilter(); + DefaultSettings(); + LoadSettings(); + InitializeSettings(); + setman->splittingInterval = split_time; + setman->clipboardFlag = clipboard_flag > 0; + hIns = hInstance; + MyRegisterClass(hIns); + InitInstance(hIns, FALSE, &window); + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + //delete mb_filter; + //delete uni_filter; + delete pfman; + MonitorFlag = false; + man = NULL; + } + else + { + FindITH(); + } + Host_Close(); + IthCloseSystemService(); + TerminateProcess(GetCurrentProcess(), 0); +} diff --git a/i18n/gui_korean/resource.h b/i18n/gui_korean/resource.h new file mode 100644 index 0000000..73edb41 --- /dev/null +++ b/i18n/gui_korean/resource.h @@ -0,0 +1,23 @@ +#ifndef IDC_STATIC +#define IDC_STATIC (-1) +#endif + +#define IDD_DIALOG2 102 +#define IDD_DIALOG4 104 +#define IDI_ICON1 110 +#define IDC_CHECK1 1000 +#define IDC_CHECK2 1001 +#define IDC_CHECK3 1002 +#define IDC_CHECK4 1003 +#define IDC_CHECK5 1004 +#define IDC_EDIT1 1011 +#define IDC_EDIT2 1012 +#define IDC_EDIT3 1013 +#define IDC_EDIT4 1014 +#define IDC_BUTTON1 1020 +#define IDC_BUTTON2 1021 +#define IDC_BUTTON3 1022 +#define IDC_BUTTON5 1024 +#define IDC_LIST1 1028 +#define IDC_BUTTON6 40000 +#define IDC_CHECK6 40001 diff --git a/i18n/gui_korean/utility.cpp b/i18n/gui_korean/utility.cpp new file mode 100644 index 0000000..2c47320 --- /dev/null +++ b/i18n/gui_korean/utility.cpp @@ -0,0 +1,303 @@ +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com) + * This file is part of the Interactive Text Hooker. + + * Interactive Text Hooker is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "utility.h" +#include "host/host.h" +#include "host/hookman.h" +#include "vnrhook/include/types.h" +#include "vnrhook/include/const.h" +#include "profile/misc.h" + +extern HookManager* man; // main.cpp + +std::wstring GetDriveLetter(const std::wstring& devicePath); +std::wstring GetWindowsPath(const std::wstring& fileObjectPath); +PVOID GetAllocationBase(DWORD pid, LPCVOID); +std::wstring GetModuleFileNameAsString(DWORD pid, PVOID allocationBase); +std::wstring GetModuleFileNameAsString(); +std::wstring GetProcessPath(HANDLE hProc); + +void ConsoleOutput(LPCWSTR text) +{ + man->AddConsoleOutput(text); +} + +void ConsoleOutput(LPCSTR text) +{ + int wc_length = MB_WC_count(text, -1); + LPWSTR wc = new WCHAR[wc_length]; + MB_WC(text, wc, wc_length); + man->AddConsoleOutput(wc); + delete wc; +} + +std::wstring GetProcessPath(DWORD pid) +{ + UniqueHandle hProc(OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid)); + if (hProc) + return GetProcessPath(hProc.get()); + else + return L""; +} + +std::wstring GetProcessPath(HANDLE hProc) +{ + wchar_t path[MAX_PATH]; + GetProcessImageFileName(hProc, path, MAX_PATH); + return GetWindowsPath(path); +} + +std::wstring GetWindowsPath(const std::wstring& path) +{ + // path is in device form + // \Device\HarddiskVolume2\Windows\System32\taskhost.exe + auto pathOffset = path.find(L'\\', 1) + 1; + pathOffset = path.find(L'\\', pathOffset); + std::wstring devicePath = path.substr(0, pathOffset); // \Device\HarddiskVolume2 + std::wstring dosDrive = GetDriveLetter(devicePath); // C: + if (dosDrive.empty()) + return path; + std::wstring dosPath = dosDrive; // C: + dosPath += path.substr(pathOffset); // C:\Windows\System32\taskhost.exe + return dosPath; +} + +std::wstring GetDriveLetter(const std::wstring& devicePath) +{ + for (wchar_t drive = L'A'; drive <= L'Z'; drive++) + { + wchar_t szDriveName[3] = { drive, L':', L'\0' }; + wchar_t szTarget[512]; + if (QueryDosDevice(szDriveName, szTarget, 512)) + if (devicePath.compare(szTarget) == 0) + return szDriveName; + } + return L""; +} + +std::wstring GetCode(const HookParam& hp, DWORD pid) +{ + std::wstring code(L"/H"); + WCHAR c; + if (hp.type & PRINT_DWORD) + c = L'H'; + else if (hp.type & USING_UNICODE) + { + if (hp.type & USING_STRING) + c = L'Q'; + else if (hp.type & STRING_LAST_CHAR) + c = L'L'; + else + c = L'W'; + } + else + { + if (hp.type & USING_STRING) + c = L'S'; + else if (hp.type & BIG_ENDIAN) + c = L'A'; + else if (hp.type & STRING_LAST_CHAR) + c = L'E'; + else + c = L'B'; + } + code += c; + if (hp.type & NO_CONTEXT) + code += L'N'; + if (hp.offset >> 31) + code += L"-" + ToHexString(-(hp.offset + 4)); + else + code += ToHexString(hp.offset); + if (hp.type & DATA_INDIRECT) + { + if (hp.index >> 31) + code += L"*-" + ToHexString(-hp.index); + else + code += L"*" + ToHexString(hp.index); + } + if (hp.type & USING_SPLIT) + { + if (hp.split >> 31) + code += L":-" + ToHexString(-(4 + hp.split)); + else + code += L":" + ToHexString(hp.split); + } + if (hp.type & SPLIT_INDIRECT) + { + if (hp.split_index >> 31) + code += L"*-" + ToHexString(-hp.split_index); + else + code += L"*" + ToHexString(hp.split_index); + } + if (pid) + { + PVOID allocationBase = GetAllocationBase(pid, (LPCVOID)hp.address); + if (allocationBase) + { + std::wstring path = GetModuleFileNameAsString(pid, allocationBase); + if (!path.empty()) + { + auto fileName = path.substr(path.rfind(L'\\') + 1); + DWORD relativeHookAddress = hp.address - (DWORD)allocationBase; + code += L"@" + ToHexString(relativeHookAddress) + L":" + fileName; + return code; + } + } + } + if (hp.module) + { + code += L"@" + ToHexString(hp.address) + L"!" + ToHexString(hp.module); + if (hp.function) + code += L"!" + ToHexString(hp.function); + } + else + { + // Hack. The original address is stored in the function field + // if (module == NULL && function != NULL). + // MODULE_OFFSET and FUNCTION_OFFSET are removed from HookParam.type in + // TextHook::UnsafeInsertHookCode() and can not be used here. + if (hp.function) + code += L"@" + ToHexString(hp.function); + else + code += L"@" + ToHexString(hp.address) + L":"; + } + return code; +} + +std::wstring GetModuleFileNameAsString(DWORD pid, PVOID allocationBase) +{ + const ProcessRecord* pr = man->GetProcessRecord(pid); + if (pr) + { + HANDLE hProc = pr->process_handle; + WCHAR path[MAX_PATH]; + if (GetModuleFileNameEx(hProc, (HMODULE)allocationBase, path, MAX_PATH)) + return path; + } + return L""; +} + +PVOID GetAllocationBase(DWORD pid, LPCVOID addr) +{ + const ProcessRecord *pr = man->GetProcessRecord(pid); + if (pr) + { + MEMORY_BASIC_INFORMATION info; + HANDLE hProc = pr->process_handle; + if (VirtualQueryEx(hProc, addr, &info, sizeof(info))) + { + if (info.Type & MEM_IMAGE) + return info.AllocationBase; + } + } + return NULL; +} + +struct TitleParam +{ + DWORD pid, buffer_len, retn_len; + std::wstring buffer; +}; + +BOOL CALLBACK EnumProc(HWND hwnd, LPARAM lParam) +{ + TitleParam* p = (TitleParam*)lParam; + DWORD pid; + GetWindowThreadProcessId(hwnd, &pid); + if (pid == p->pid) + { + if (GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE) + { + int len = GetWindowTextLength(hwnd); + std::unique_ptr result(new wchar_t[len + 1]); + GetWindowText(hwnd, result.get(), len + 1); + p->buffer = result.get(); + p->retn_len = p->buffer.size(); + if (!p->buffer.empty()) + return FALSE; + } + } + return TRUE; +} + +std::wstring GetProcessTitle(DWORD pid) +{ + TitleParam p; + p.pid = pid; + p.buffer_len = 0; + p.retn_len = 0; + EnumWindows(EnumProc, (LPARAM)&p); + return p.buffer; +} + +WindowsError::WindowsError(DWORD error_code) : error_code(error_code), msg("") +{ + CHAR str[512]; + std::sprintf(str, "error code 0x%8x", error_code); + msg = str; +} + +const char *WindowsError::what() const +{ + return msg.c_str(); +} + +HANDLE IthCreateThread(LPVOID start_addr, DWORD param) +{ + return CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)start_addr, (LPVOID)param, 0, NULL); +} + +std::wstring GetModuleFileNameAsString() +{ + WCHAR path[MAX_PATH]; + GetModuleFileName(NULL, path, MAX_PATH); + return path; +} + +bool IthCreateDirectory(LPCWSTR name) +{ + std::wstring path = GetModuleFileNameAsString(); + path = path.substr(0, path.rfind(L'\\') + 1) + name; + BOOL error_code = CreateDirectory(path.c_str(), NULL); + return error_code != 0 || GetLastError() == ERROR_ALREADY_EXISTS; +} + +HANDLE IthCreateFile(LPCWSTR name, DWORD option, DWORD share, DWORD disposition) +{ + std::wstring path = GetModuleFileNameAsString(); + path = path.substr(0, path.rfind(L'\\') + 1) + name; + return CreateFile(path.c_str(), option, share, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL); +} + +//SJIS->Unicode. mb must be null-terminated. wc_length is the length of wc in characters. +int MB_WC(const char* mb, wchar_t* wc, int wc_length) +{ + return MultiByteToWideChar(932, 0, mb, -1, wc, wc_length); +} + +// Count characters in wide string. mb_length is the number of bytes from mb to convert or +// -1 if the string is null terminated. +int MB_WC_count(const char* mb, int mb_length) +{ + return MultiByteToWideChar(932, 0, mb, mb_length, NULL, 0); +} + +// Unicode->SJIS. Analogous to MB_WC. +int WC_MB(const wchar_t *wc, char* mb, int mb_length) +{ + return WideCharToMultiByte(932, 0, wc, -1, mb, mb_length, NULL, NULL); +} diff --git a/i18n/gui_korean/utility.h b/i18n/gui_korean/utility.h new file mode 100644 index 0000000..5c8a065 --- /dev/null +++ b/i18n/gui_korean/utility.h @@ -0,0 +1,105 @@ +#pragma once + +#include "ITH.h" + +struct HookParam; +struct ProcessRecord; + +DWORD ProcessCommand(const std::wstring& cmd, DWORD pid); +std::wstring GetProcessPath(DWORD pid); +void ConsoleOutput(LPCWSTR); +void ConsoleOutput(LPCSTR text); +std::wstring GetProcessTitle(DWORD pid); +std::wstring GetCode(const HookParam& hp, DWORD pid = 0); + +// http://codesequoia.wordpress.com/2012/08/26/stdunique_ptr-for-windows-handles/ +struct HandleDeleter +{ + typedef HANDLE pointer; + void operator() (HANDLE h) + { + if (h != INVALID_HANDLE_VALUE) { + CloseHandle(h); + } + } +}; + +typedef std::unique_ptr UniqueHandle; + +class FileWriter : public pugi::xml_writer +{ + HANDLE hFile; +public: + FileWriter(HANDLE hFile) : hFile(hFile) {}; + ~FileWriter() {}; + + virtual void write(const void* data, size_t size) + { + DWORD dwNumberOfBytesWritten; + WriteFile(hFile, data, size, &dwNumberOfBytesWritten, NULL); + } +}; + +class WindowsError : public std::exception +{ +private: + std::string msg; + DWORD error_code; +public: + WindowsError(DWORD error_code); + virtual const char *what() const; +}; + +HANDLE IthCreateThread(LPVOID start_addr, DWORD param); +bool IthCreateDirectory(LPCWSTR name); +HANDLE IthCreateFile(LPCWSTR name, DWORD option, DWORD share, DWORD disposition); +int MB_WC(const char* mb, wchar_t* wc, int wc_length); +int MB_WC_count(const char* mb, int mb_length); +int WC_MB(const wchar_t *wc, char* mb, int mb_length); +bool Parse(const std::wstring& cmd, HookParam& hp); + +// http://jrdodds.blogs.com/blog/2004/08/raii_in_c.html +class CriticalSection +{ +public: + CriticalSection() + { + ::InitializeCriticalSection(&m_rep); + } + ~CriticalSection() + { + ::DeleteCriticalSection(&m_rep); + } + void Enter() + { + ::EnterCriticalSection(&m_rep); + } + void Leave() + { + ::LeaveCriticalSection(&m_rep); + } +private: + CriticalSection(const CriticalSection&); + CriticalSection& operator=(const CriticalSection&); + + CRITICAL_SECTION m_rep; +}; + +class CSLock +{ +public: + CSLock(CriticalSection& a_section) + : m_section(a_section) + { + m_section.Enter(); + } + ~CSLock() + { + m_section.Leave(); + } +private: + CSLock(const CSLock&); + CSLock& operator=(const CSLock&); + + CriticalSection& m_section; +}; diff --git a/i18n/gui_korean/version.h.in b/i18n/gui_korean/version.h.in new file mode 100644 index 0000000..051edda --- /dev/null +++ b/i18n/gui_korean/version.h.in @@ -0,0 +1,2 @@ +const wchar_t* build_date=L"27.01.2013"; +const WCHAR program_version[] = L"@CPACK_PACKAGE_VERSION_MAJOR@.@CPACK_PACKAGE_VERSION_MINOR@.@CPACK_PACKAGE_VERSION_PATCH@"; diff --git a/i18n/gui_korean/window.cpp b/i18n/gui_korean/window.cpp new file mode 100644 index 0000000..df24e62 --- /dev/null +++ b/i18n/gui_korean/window.cpp @@ -0,0 +1,866 @@ +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com) + * This file is part of the Interactive Text Hooker. + + * Interactive Text Hooker is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "window.h" +#include "ProcessWindow.h" +#include "resource.h" +#include "language.h" +#include "host/host.h" +#include "host/hookman.h" +#include "vnrhook/include/const.h" +#include "version.h" +#include "ProfileManager.h" +#include "host/settings.h" +#include "CustomFilter.h" +#include "profile/Profile.h" +#include "TextBuffer.h" +#include "profile/misc.h" + +#define CMD_SIZE 512 + +static WNDPROC proc, proccmd, procChar; +static WCHAR last_cmd[CMD_SIZE]; +extern HINSTANCE hIns; // main.cpp + +HWND hMainWnd, hwndCombo, hwndProcessComboBox, hwndEdit, hwndCmd; +HWND hwndProcess; +HWND hwndOption, hwndTop, hwndClear, hwndSave, hwndRemoveLink, hwndRemoveHook; +HWND hProcDlg, hOptionDlg; +HBRUSH hWhiteBrush; +DWORD background; +ProcessWindow* pswnd; +TextBuffer* texts; +extern ProfileManager* pfman; // ProfileManager.cpp +extern HookManager* man; // main.cpp +extern CustomFilter* mb_filter; // main.cpp +extern CustomFilter* uni_filter; // main.cpp +extern Settings* setman; // main.cpp +#define COMMENT_BUFFER_LENGTH 512 +static WCHAR comment_buffer[COMMENT_BUFFER_LENGTH]; + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +void SaveSettings(); // main.cpp +extern LONG split_time, process_time, inject_delay, insert_delay, +auto_inject, auto_insert, clipboard_flag, cyclic_remove, global_filter; //main.cpp +static int last_select, last_edit; + +ATOM MyRegisterClass(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = NULL; + wcex.hCursor = NULL; + wcex.hbrBackground = GetStockBrush(WHITE_BRUSH); + wcex.lpszMenuName = NULL; + wcex.lpszClassName = ClassName; + wcex.hIconSm = LoadIcon(hInstance, (LPWSTR)IDI_ICON1); + return RegisterClassEx(&wcex); +} + +BOOL InitInstance(HINSTANCE hInstance, DWORD nAdmin, RECT* rc) +{ + hIns = hInstance; + LPCWSTR name = (nAdmin) ? ClassNameAdmin : ClassName; + hMainWnd = CreateWindow(ClassName, name, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, + rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top, NULL, NULL, hInstance, 0); + if (!hMainWnd) + return FALSE; + ShowWindow(hMainWnd, SW_SHOWNORMAL); + UpdateWindow(hMainWnd); + return TRUE; +} + +DWORD SaveProcessProfile(DWORD pid); // ProfileManager.cpp + +BOOL CALLBACK OptionDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + SetWindowText(GetDlgItem(hDlg, IDC_EDIT1), std::to_wstring((long long)split_time).c_str()); + SetWindowText(GetDlgItem(hDlg, IDC_EDIT2), std::to_wstring((long long)process_time).c_str()); + SetWindowText(GetDlgItem(hDlg, IDC_EDIT3), std::to_wstring((long long)inject_delay).c_str()); + SetWindowText(GetDlgItem(hDlg, IDC_EDIT4), std::to_wstring((long long)insert_delay).c_str()); + CheckDlgButton(hDlg, IDC_CHECK1, auto_inject); + CheckDlgButton(hDlg, IDC_CHECK2, auto_insert); + CheckDlgButton(hDlg, IDC_CHECK3, clipboard_flag); + CheckDlgButton(hDlg, IDC_CHECK4, cyclic_remove); + CheckDlgButton(hDlg, IDC_CHECK5, global_filter); + } + return TRUE; + case WM_COMMAND: + { + DWORD wmId = LOWORD(wParam); + DWORD wmEvent = HIWORD(wParam); + switch (wmId) + { + case IDOK: + { + WCHAR str[128]; + GetWindowText(GetDlgItem(hDlg, IDC_EDIT1), str, 0x80); + DWORD st = std::stoul(str); + split_time = st > 100 ? st : 100; + GetWindowText(GetDlgItem(hDlg, IDC_EDIT2), str, 0x80); + DWORD pt = std::stoul(str); + process_time = pt > 50 ? pt : 50; + GetWindowText(GetDlgItem(hDlg, IDC_EDIT3), str, 0x80); + DWORD jd = std::stoul(str); + inject_delay = jd > 1000 ? jd : 1000; + GetWindowText(GetDlgItem(hDlg, IDC_EDIT4), str, 0x80); + DWORD sd = std::stoul(str); + insert_delay = sd > 200 ? sd : 200; + if (IsDlgButtonChecked(hDlg, IDC_CHECK6)) + { + man->ResetRepeatStatus(); + } + auto_inject = IsDlgButtonChecked(hDlg, IDC_CHECK1); + auto_insert = IsDlgButtonChecked(hDlg, IDC_CHECK2); + clipboard_flag = IsDlgButtonChecked(hDlg, IDC_CHECK3); + cyclic_remove = IsDlgButtonChecked(hDlg, IDC_CHECK4); + global_filter = IsDlgButtonChecked(hDlg, IDC_CHECK5); + setman->clipboardFlag = clipboard_flag; + setman->splittingInterval = split_time; + if (auto_inject == 0) auto_insert = 0; + } + case IDCANCEL: + EndDialog(hDlg, 0); + hOptionDlg = NULL; + break; + } + return TRUE; + } + default: + return FALSE; + } + return FALSE; +} + +BOOL CALLBACK ProcessDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + pswnd = new ProcessWindow(hDlg); + return TRUE; + } + case WM_COMMAND: + { + DWORD wmId, wmEvent; + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + switch (wmId) + { + case WM_DESTROY: + case IDOK: + EndDialog(hDlg, NULL); + hProcDlg = NULL; + delete pswnd; + pswnd = NULL; + break; + case IDC_BUTTON1: + pswnd->RefreshProcess(); + break; + case IDC_BUTTON2: + pswnd->AttachProcess(); + break; + case IDC_BUTTON3: + pswnd->DetachProcess(); + break; + case IDC_BUTTON5: + pswnd->CreateProfileForSelectedProcess(); + break; + case IDC_BUTTON6: + pswnd->DeleteProfileForSelectedProcess(); + break; + } + } + return TRUE; + + case WM_NOTIFY: + { + LPNMHDR dr = (LPNMHDR)lParam; + switch (dr->code) + { + case LVN_ITEMCHANGED: + if (dr->idFrom == IDC_LIST1) + { + NMLISTVIEW *nmlv = (LPNMLISTVIEW)lParam; + if (nmlv->uNewState & LVIS_SELECTED) + pswnd->RefreshThread(nmlv->iItem); + } + break; + } + } + return TRUE; + default: + return FALSE; + } +} + +LRESULT CALLBACK EditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + + switch (message) + { + case WM_CHAR: //Filter user input. + if (GetKeyState(VK_CONTROL) & 0x8000) + { + if (wParam == 1) + { + Edit_SetSel(hwndEdit, 0, -1); + SendMessage(hwndEdit, WM_COPY, 0, 0); + } + } + return 0; + case WM_LBUTTONUP: + if (hwndEdit) + SendMessage(hwndEdit, WM_COPY, 0, 0); + default: + { + return proc(hWnd, message, wParam, lParam); + } + + } +} + +LRESULT CALLBACK EditCmdProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_KEYDOWN: + if (wParam == VK_UP) + { + SetWindowText(hWnd, last_cmd); + SetFocus(hWnd); + return 0; + } + break; + case WM_CHAR: + if (wParam == VK_RETURN) + { + DWORD s = 0, pid = 0; + WCHAR str[32]; + if (GetWindowTextLength(hWnd) == 0) + break; + GetWindowText(hWnd, last_cmd, CMD_SIZE); + //IthBreak(); + if (GetWindowText(hwndProcessComboBox, str, 32)) + pid = std::stoul(str); + ProcessCommand(last_cmd, pid); + Edit_SetSel(hWnd, 0, -1); + Edit_ReplaceSel(hWnd, &s); + SetFocus(hWnd); + return 0; + } + default: + break; + } + return CallWindowProc(proccmd, hWnd, message, wParam, lParam); +} + +void CreateButtons(HWND hWnd) +{ + hwndProcess = CreateWindow(L"Button", L"ÇÁ·Î¼¼½º", WS_CHILD | WS_VISIBLE, + 0, 0, 0, 0, hWnd, 0, hIns, NULL); + hwndOption = CreateWindow(L"Button", L"¿É¼Ç", WS_CHILD | WS_VISIBLE, + 0, 0, 0, 0, hWnd, 0, hIns, NULL); + hwndClear = CreateWindow(L"Button", L"Áö¿ì±â", WS_CHILD | WS_VISIBLE, + 0, 0, 0, 0, hWnd, 0, hIns, NULL); + hwndSave = CreateWindow(L"Button", L"ÀúÀå", WS_CHILD | WS_VISIBLE, + 0, 0, 0, 0, hWnd, 0, hIns, NULL); + hwndRemoveLink = CreateWindow(L"Button", L"¸µÅ©ÇØÁ¦", WS_CHILD | WS_VISIBLE, + 0, 0, 0, 0, hWnd, 0, hIns, NULL); + hwndRemoveHook = CreateWindow(L"Button", L"ÈÄÅ·ÇØÁ¦", WS_CHILD | WS_VISIBLE, + 0, 0, 0, 0, hWnd, 0, hIns, NULL); + hwndTop = CreateWindow(L"Button", L"Ç×»óÀ§", WS_CHILD | WS_VISIBLE | BS_PUSHLIKE | BS_CHECKBOX, + 0, 0, 0, 0, hWnd, 0, hIns, NULL); + hwndProcessComboBox = CreateWindow(L"ComboBox", NULL, + WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | + CBS_SORT | WS_VSCROLL | WS_TABSTOP, + 0, 0, 0, 0, hWnd, 0, hIns, NULL); + hwndCmd = CreateWindowEx(WS_EX_CLIENTEDGE, L"Edit", NULL, + WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | ES_LEFT | ES_AUTOHSCROLL, + 0, 0, 0, 0, hWnd, 0, hIns, NULL); + hwndEdit = CreateWindowEx(WS_EX_CLIENTEDGE, L"Edit", NULL, + WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | WS_VSCROLL | + ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, + 0, 0, 0, 0, hWnd, 0, hIns, NULL); +} + +void ClickButton(HWND hWnd, HWND h) +{ + if (h == hwndProcess) + { + if (hProcDlg) + SetForegroundWindow(hProcDlg); + else + hProcDlg = CreateDialog(hIns, (LPWSTR)IDD_DIALOG2, 0, ProcessDlgProc); + } + else if (h == hwndOption) + { + if (hOptionDlg) + SetForegroundWindow(hOptionDlg); + else + hOptionDlg = CreateDialog(hIns, (LPWSTR)IDD_DIALOG4, 0, OptionDlgProc); + } + else if (h == hwndClear) + { + WCHAR pwcEntry[128] = {}; + DWORD dwId = ComboBox_GetCurSel(hwndCombo); + int len = ComboBox_GetLBText(hwndCombo, dwId, pwcEntry); + dwId = std::stoul(pwcEntry, NULL, 16); + if (dwId == 0) + man->ClearCurrent(); + else + man->RemoveSingleThread(dwId); + } + else if (h == hwndTop) + { + if (Button_GetCheck(h) == BST_CHECKED) + { + Button_SetCheck(h, BST_UNCHECKED); + SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + if (hProcDlg) + SetWindowPos(hProcDlg, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + if (hOptionDlg) + SetWindowPos(hOptionDlg, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + } + else + { + Button_SetCheck(h, BST_CHECKED); + SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + if (hProcDlg) + SetWindowPos(hProcDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + if (hOptionDlg) + SetWindowPos(hOptionDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + } + } + else if (h == hwndSave) + { + WCHAR str[32]; + if (GetWindowText(hwndProcessComboBox, str, 32)) + { + DWORD pid = std::stoul(str); + SaveProcessProfile(pid); + } + pfman->SaveProfiles(); + } + else if (h == hwndRemoveLink) + { + WCHAR str[32]; + if (GetWindowText(hwndCombo, str, 32)) + { + DWORD from = std::stoul(str, NULL, 16); + if (from != 0) + Host_UnLink(from); + } + } + else if (h == hwndRemoveHook) + { + WCHAR str[32]; + if (GetWindowText(hwndCombo, str, 32)) + { + std::wstring entry(str); + std::size_t i; + DWORD threadNumber = std::stoul(entry, &i, 16); + entry = entry.substr(i + 1); + DWORD pid = std::stoul(entry, &i); + entry = entry.substr(i + 1); + DWORD addr = std::stoul(entry, NULL, 16); + if (threadNumber != 0) + Host_RemoveHook(pid, addr); + } + } +} + +DWORD ThreadFilter(TextThread* thread, BYTE* out, DWORD len, DWORD new_line, PVOID data, bool space) +{ + DWORD status = thread->Status(); + if (global_filter && !new_line && thread->Number() != 0) + { + if (status & USING_UNICODE) + { + DWORD i, j; + len /= 2; + LPWSTR str = (LPWSTR)out; + for (i = 0, j = 0; i < len; i++) + { + WCHAR c = str[i]; + if (!uni_filter->Find(c)) + str[j++] = c; + } + memset(str + j, 0, (len - j) * 2); + len = j * 2; + } + else + { + DWORD i, j; + for (i = 0, j = 0; i < len; i++) + { + WORD c = out[i]; + if (!IsDBCSLeadByte(c & 0xFF)) + { + if (!mb_filter->Find(c)) + out[j++] = c & 0xFF; + } + else if (i + 1 < len) + { + + c = out[i + 1]; + c <<= 8; + c |= out[i]; + if (!mb_filter->Find(c)) + { + out[j++] = c & 0xFF; + out[j++] = c >> 8; + } + i++; + } + } + memset(out + j, 0, len - j); + len = j; + } + } + return len; +} + +DWORD ThreadOutput(TextThread* thread, BYTE* out, DWORD len, DWORD new_line, PVOID data, bool space) +{ + if (len == 0) + return len; + DWORD status = thread->Status(); + if (status & CURRENT_SELECT) + { + if (new_line) + { + if (thread->Number() == 0) + texts->AddText(L"\r\n", 2, true); + else + texts->AddText(L"\r\n\r\n", 4, true); + } + else if (status & USING_UNICODE) + { + texts->AddText((LPWSTR)out, len / 2, false); + } + else + { + int uni_len = MB_WC_count((char*)out, len); + LPWSTR str = new WCHAR[uni_len + 1]; + MB_WC((char*)out, str, uni_len + 1); + str[uni_len] = L'\0'; + texts->AddText(str, uni_len, false); + delete str; + } + } + return len; +} + +bool GetHookParam(DWORD pid, DWORD hook_addr, HookParam& hp) +{ + if (!pid) + return false; + ProcessRecord *pr = ::man->GetProcessRecord(pid); + if (!pr) + return false; + bool result = false; + WaitForSingleObject(pr->hookman_mutex, 0); + const Hook *hks = (Hook *)pr->hookman_map; + for (int i = 0; i < MAX_HOOK; i++) + { + if (hks[i].Address() == hook_addr) + { + hp = hks[i].hp; + result = true; + break; + } + } + ReleaseMutex(pr->hookman_mutex); + return result; +} + +std::wstring GetEntryString(TextThread& thread) +{ + CHAR entry[512]; + thread.GetEntryString(entry, 512); + return toUnicodeString(entry); +} + +std::wstring CreateEntryWithLink(TextThread& thread, std::wstring& entry) +{ + std::wstring entryWithLink = entry; + if (thread.Link()) + entryWithLink += L"->" + ToHexString(thread.LinkNumber()); + if (thread.PID() == 0) + entryWithLink += L"ConsoleOutput"; + HookParam hp = {}; + if (GetHookParam(thread.PID(), thread.Addr(), hp)) + entryWithLink += L" (" + GetCode(hp, thread.PID()) + L")"; + return entryWithLink; +} + +void AddToCombo(TextThread& thread, bool replace) +{ + std::wstring entry = GetEntryString(thread); + std::wstring entryWithLink = CreateEntryWithLink(thread, entry); + int i = ComboBox_FindString(hwndCombo, -1, entry.c_str()); + if (replace) + { + int sel = ComboBox_GetCurSel(hwndCombo); + if (i != CB_ERR) + ComboBox_DeleteString(hwndCombo, i); + ComboBox_AddString(hwndCombo, entryWithLink.c_str()); + ComboBox_SetCurSel(hwndCombo, sel); + } + else + { + if (i == CB_ERR) + ComboBox_AddString(hwndCombo, entryWithLink.c_str()); + // Why set current selection to 0 when the new thread is selected? + if (thread.Status() & CURRENT_SELECT) + ComboBox_SetCurSel(hwndCombo, 0); + } +} + +void RemoveFromCombo(TextThread* thread) +{ + CHAR entry[512]; + thread->GetEntryString(entry, 512); + std::wstring unicodeEntry = toUnicodeString(entry); + if (thread->PID() == 0) + unicodeEntry += L"ConsoleOutput"; + int i = ComboBox_FindString(hwndCombo, 0, unicodeEntry.c_str()); + if (i != CB_ERR) + { + if (ComboBox_DeleteString(hwndCombo, i) == CB_ERR) + ConsoleOutput(ErrorDeleteCombo); + } +} + +void ComboSelectCurrent(TextThread* thread) +{ + ComboBox_SetCurSel(hwndCombo, thread->Number()); +} + +DWORD SetEditText(LPWSTR wc) +{ + DWORD line; + Edit_SetText(hwndEdit, wc); + line = Edit_GetLineCount(hwndEdit); + SendMessage(hwndEdit, EM_LINESCROLL, 0, line); + return 0; +} + +DWORD ThreadReset(TextThread* thread) +{ + texts->ClearBuffer(); + man->SetCurrent(thread); + thread->LockVector(); + DWORD uni = thread->Status() & USING_UNICODE; + if (uni) + { + DWORD len = 0; + LPWSTR wc = (LPWSTR)thread->GetStore(&len); + len /= 2; + wc[len] = L'\0'; + SetEditText(wc); + } + else + { + DWORD len = MB_WC_count((char*)thread->Storage(), thread->Used()); + LPWSTR wc = new WCHAR[len + 1]; + MB_WC((char*)thread->Storage(), wc, len + 1); + wc[len] = L'\0'; + SetEditText(wc); + delete wc; + } + WCHAR buffer[16]; + std::swprintf(buffer, L"%04X", thread->Number()); + DWORD tmp = ComboBox_FindString(hwndCombo, 0, buffer); + if (tmp != CB_ERR) + ComboBox_SetCurSel(hwndCombo, tmp); + thread->UnlockVector(); + return 0; +} + +DWORD AddRemoveLink(TextThread* thread) +{ + AddToCombo(*thread, true); + return 0; +} + +bool IsUnicodeHook(const ProcessRecord& pr, DWORD hook); +void AddLinksToHookManager(const Profile* pf, size_t thread_index, const TextThread* thread); + +DWORD ThreadCreate(TextThread* thread) +{ + thread->RegisterOutputCallBack(ThreadOutput, 0); + thread->RegisterFilterCallBack(ThreadFilter, 0); + AddToCombo(*thread, false); + const auto& tp = thread->GetThreadParameter(); + auto pr = man->GetProcessRecord(tp->pid); + if (pr == NULL) + return 0; + if (IsUnicodeHook(*pr, tp->hook)) + thread->Status() |= USING_UNICODE; + auto pf = pfman->GetProfile(tp->pid); + if (!pf) + return 0; + const std::wstring& hook_name = GetHookNameByAddress(*pr, thread->GetThreadParameter()->hook); + auto thread_profile = pf->FindThread(thread->GetThreadParameter(), hook_name); + if (thread_profile != pf->Threads().end()) + { + (*thread_profile)->HookManagerIndex() = thread->Number(); + auto thread_index = thread_profile - pf->Threads().begin(); + AddLinksToHookManager(pf, thread_index, thread); + if (pf->IsThreadSelected(thread_profile)) + ThreadReset(thread); + } + return 0; +} + +bool IsUnicodeHook(const ProcessRecord& pr, DWORD hook) +{ + bool res = false; + WaitForSingleObject(pr.hookman_mutex, 0); + auto hooks = (const Hook*)pr.hookman_map; + for (DWORD i = 0; i < MAX_HOOK; i++) + { + if (hooks[i].Address() == hook) + { + res = hooks[i].Type() & USING_UNICODE; + break; + } + } + ReleaseMutex(pr.hookman_mutex); + return res; +} + +void AddLinksToHookManager(const Profile* pf, size_t thread_index, const TextThread* thread) +{ + for (auto lp = pf->Links().begin(); lp != pf->Links().end(); ++lp) + { + if ((*lp)->FromIndex() == thread_index) + { + WORD to_index = pf->Threads()[(*lp)->ToIndex()]->HookManagerIndex(); + if (to_index != 0) + man->AddLink(thread->Number(), to_index); + } + if ((*lp)->ToIndex() == thread_index) + { + WORD from_index = pf->Threads()[(*lp)->FromIndex()]->HookManagerIndex(); + if (from_index != 0) + man->AddLink(from_index, thread->Number()); + } + } +} + +DWORD ThreadRemove(TextThread* thread) +{ + RemoveFromCombo(thread); + return 0; +} + +DWORD RegisterProcessList(DWORD pid) +{ + auto path = GetProcessPath(pid); + if (!path.empty()) + { + WCHAR str[MAX_PATH]; + std::swprintf(str, L"%04d:%s", pid, path.substr(path.rfind(L'\\') + 1).c_str()); + ComboBox_AddString(hwndProcessComboBox, str); + if (ComboBox_GetCount(hwndProcessComboBox) == 1) + ComboBox_SetCurSel(hwndProcessComboBox, 0); + } + return 0; +} + +DWORD RemoveProcessList(DWORD pid) +{ + WCHAR str[MAX_PATH]; + std::swprintf(str, L"%04d", pid); + DWORD i = ComboBox_FindString(hwndProcessComboBox, 0, str); + DWORD j = ComboBox_GetCurSel(hwndProcessComboBox); + if (i != CB_ERR) + { + DWORD k = ComboBox_DeleteString(hwndProcessComboBox, i); + if (i == j) + ComboBox_SetCurSel(hwndProcessComboBox, 0); + } + return 0; +} + +DWORD RefreshProfileOnNewHook(DWORD pid) +{ + return 0; +} + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_CREATE: + CreateButtons(hWnd); + // Add text to the window. + Edit_LimitText(hwndEdit, -1); + SendMessage(hwndEdit, WM_INPUTLANGCHANGEREQUEST, 0, 0x411); + proc = (WNDPROC)SetWindowLong(hwndEdit, GWL_WNDPROC, (LONG)EditProc); + proccmd = (WNDPROC)SetWindowLong(hwndCmd, GWL_WNDPROC, (LONG)EditCmdProc); + hwndCombo = CreateWindow(L"ComboBox", NULL, + WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | + CBS_SORT | WS_VSCROLL | WS_TABSTOP, + 0, 0, 0, 0, hWnd, 0, hIns, NULL); + { + HDC hDC = GetDC(hWnd); + int nHeight = -MulDiv(12, GetDeviceCaps(hDC, LOGPIXELSY), 72); + ReleaseDC(hWnd, hDC); + HFONT hf = CreateFont(nHeight, 0, 0, 0, FW_LIGHT, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET, + OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, + L"MS Gothic"); + hWhiteBrush = GetStockBrush(WHITE_BRUSH); + SendMessage(hwndCmd, WM_SETFONT, (WPARAM)hf, 0); + SendMessage(hwndEdit, WM_SETFONT, (WPARAM)hf, 0); + SendMessage(hwndCombo, WM_SETFONT, (WPARAM)hf, 0); + SendMessage(hwndProcessComboBox, WM_SETFONT, (WPARAM)hf, 0); + texts = new TextBuffer(hwndEdit); + man->RegisterThreadCreateCallback(ThreadCreate); + man->RegisterThreadRemoveCallback(ThreadRemove); + man->RegisterThreadResetCallback(ThreadReset); + TextThread* console = man->FindSingle(0); + console->RegisterOutputCallBack(ThreadOutput, NULL); + AddToCombo(*console, false); + man->RegisterProcessAttachCallback(RegisterProcessList); + man->RegisterProcessDetachCallback(RemoveProcessList); + man->RegisterProcessNewHookCallback(RefreshProfileOnNewHook); + man->RegisterAddRemoveLinkCallback(AddRemoveLink); + man->RegisterConsoleCallback(ConsoleOutput); + Host_Start(); + { + static const WCHAR program_name[] = L"Interactive Text Hooker"; + //static const WCHAR program_version[] = L"3.0"; + static WCHAR version_info[256]; + std::swprintf(version_info, L"%s %s (%s)", program_name, program_version, build_date); + man->AddConsoleOutput(version_info); + man->AddConsoleOutput(InitMessage); + } + + if (background == 0) + man->AddConsoleOutput(BackgroundMsg); + } + + return 0; + case WM_COMMAND: + { + DWORD wmId, wmEvent, dwId; + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + switch (wmEvent) + { + case EN_VSCROLL: + { + SCROLLBARINFO info = { sizeof(info) }; + GetScrollBarInfo(hwndEdit, OBJID_VSCROLL, &info); + InvalidateRect(hwndEdit, 0, 1); + ValidateRect(hwndEdit, &info.rcScrollBar); + RedrawWindow(hwndEdit, 0, 0, RDW_ERASE); + } + break; + case CBN_SELENDOK: + { + if ((HWND)lParam == hwndProcessComboBox) + return 0; + dwId = ComboBox_GetCurSel(hwndCombo); + int len = ComboBox_GetLBTextLen(hwndCombo, dwId); + if (len > 0) + { + LPWSTR pwcEntry = new WCHAR[len + 1]; + len = ComboBox_GetLBText(hwndCombo, dwId, pwcEntry); + DWORD num = std::stoul(pwcEntry, NULL, 16); + man->SelectCurrent(num); + delete[] pwcEntry; + } + } + return 0; + case BN_CLICKED: + ClickButton(hWnd, (HWND)lParam); + break; + default: + break; + } + } + break; + case WM_SETFOCUS: + SetFocus(hwndEdit); + return 0; + case WM_SIZE: + { + WORD width = LOWORD(lParam); + WORD height = HIWORD(lParam); + DWORD l = width / 7; + WORD h = HIWORD(GetDialogBaseUnits()); // height of the system font + h = h + (h / 2); + HDC hDC = GetDC(hWnd); + RECT rc; + GetClientRect(hWnd, &rc); + FillRect(hDC, &rc, hWhiteBrush); + ReleaseDC(hWnd, hDC); + MoveWindow(hwndProcess, 0, 0, l, h, TRUE); + MoveWindow(hwndOption, l * 1, 0, l, h, TRUE); + MoveWindow(hwndTop, l * 2, 0, l, h, TRUE); + MoveWindow(hwndClear, l * 3, 0, l, h, TRUE); + MoveWindow(hwndRemoveLink, l * 4, 0, l, h, TRUE); + MoveWindow(hwndRemoveHook, l * 5, 0, l, h, TRUE); + MoveWindow(hwndSave, l * 6, 0, width - 6 * l, h, TRUE); + l *= 2; + MoveWindow(hwndProcessComboBox, 0, h, l, 200, TRUE); + MoveWindow(hwndCmd, l, h, width - l, h, TRUE); + MoveWindow(hwndCombo, 0, h * 2, width, 200, TRUE); + h *= 3; + MoveWindow(hwndEdit, 0, h, width, height - h, TRUE); + } + return 0; + case WM_DESTROY: + man->RegisterThreadCreateCallback(0); + man->RegisterThreadRemoveCallback(0); + man->RegisterThreadResetCallback(0); + man->RegisterProcessAttachCallback(0); + man->RegisterProcessDetachCallback(0); + //delete texts; + SaveSettings(); + PostQuitMessage(0); + return 0; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + +DWORD WINAPI FlushThread(LPVOID lParam) +{ + TextBuffer* t = (TextBuffer*)lParam; + while (t->Running()) + { + t->Flush(); + Sleep(10); + } + return 0; +} diff --git a/i18n/gui_korean/window.h b/i18n/gui_korean/window.h new file mode 100644 index 0000000..68fc565 --- /dev/null +++ b/i18n/gui_korean/window.h @@ -0,0 +1,20 @@ +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com) + * This file is part of the Interactive Text Hooker. + + * Interactive Text Hooker is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "ITH.h"