From 0017728fb4a75027d03fd8a2b50785be8f75d189 Mon Sep 17 00:00:00 2001 From: Bepis <36346617+bbepis@users.noreply.github.com> Date: Wed, 30 Mar 2016 11:03:33 +1100 Subject: [PATCH] Initial Commit --- AA2TranslationLoader.sln | 22 + .../AA2TranslationLoader.csproj | 56 + AA2TranslationLoader/ListViewHeaderHelper.cs | 210 +++ AA2TranslationLoader/Program.cs | 390 ++++++ .../Properties/AssemblyInfo.cs | 20 + AA2TranslationLoader/Resources/icon.ico | Bin 0 -> 7358 bytes AA2TranslationLoader/TabControlHelper.cs | 200 +++ AA2TranslationLoader/app.config | 3 + AA2TranslationLoader/dictionary.xml | 1241 +++++++++++++++++ 9 files changed, 2142 insertions(+) create mode 100644 AA2TranslationLoader.sln create mode 100644 AA2TranslationLoader/AA2TranslationLoader.csproj create mode 100644 AA2TranslationLoader/ListViewHeaderHelper.cs create mode 100644 AA2TranslationLoader/Program.cs create mode 100644 AA2TranslationLoader/Properties/AssemblyInfo.cs create mode 100644 AA2TranslationLoader/Resources/icon.ico create mode 100644 AA2TranslationLoader/TabControlHelper.cs create mode 100644 AA2TranslationLoader/app.config create mode 100644 AA2TranslationLoader/dictionary.xml diff --git a/AA2TranslationLoader.sln b/AA2TranslationLoader.sln new file mode 100644 index 0000000..ac203b1 --- /dev/null +++ b/AA2TranslationLoader.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AA2TranslationLoader", "AA2TranslationLoader\AA2TranslationLoader.csproj", "{C2833569-5FE1-41CE-AB8B-32A56C2D8422}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C2833569-5FE1-41CE-AB8B-32A56C2D8422}.Debug|x86.ActiveCfg = Debug|x86 + {C2833569-5FE1-41CE-AB8B-32A56C2D8422}.Debug|x86.Build.0 = Debug|x86 + {C2833569-5FE1-41CE-AB8B-32A56C2D8422}.Release|x86.ActiveCfg = Release|x86 + {C2833569-5FE1-41CE-AB8B-32A56C2D8422}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/AA2TranslationLoader/AA2TranslationLoader.csproj b/AA2TranslationLoader/AA2TranslationLoader.csproj new file mode 100644 index 0000000..60ce628 --- /dev/null +++ b/AA2TranslationLoader/AA2TranslationLoader.csproj @@ -0,0 +1,56 @@ + + + + {C2833569-5FE1-41CE-AB8B-32A56C2D8422} + Debug + x86 + Exe + AA2TranslationLoader + v4.0 + 4 + + + + x86 + + + bin\Debug\ + true + full + false + + + bin\Release\ + true + pdbonly + true + + + Resources\icon.ico + + + AA2TranslationLoader.Program + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + + \ No newline at end of file diff --git a/AA2TranslationLoader/ListViewHeaderHelper.cs b/AA2TranslationLoader/ListViewHeaderHelper.cs new file mode 100644 index 0000000..4a18514 --- /dev/null +++ b/AA2TranslationLoader/ListViewHeaderHelper.cs @@ -0,0 +1,210 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace AA2TranslationLoader +{ + internal class ListViewHeaderHelper + { + public struct HDITEM + { + public uint mask; + + public int cxy; + + public IntPtr pszText; + + public IntPtr hbm; + + public int cchTextMax; + + public int fmt; + + public IntPtr lParam; + + public int iImage; + + public int iOrder; + + public uint type; + + public IntPtr pvFilter; + + public uint state; + } + + private const int HDM_FIRST = 4608; + + private const int HDM_GETITEM = 4611; + + private const int HDM_SETITEM = 4612; + + private const int HDM_GETITEMCOUNT = 4608; + + private const uint HDI_TEXT = 2u; + + private const uint PROCESS_ALL_ACCESS = 2035711u; + + private const uint MEM_COMMIT = 4096u; + + private const uint MEM_RELEASE = 32768u; + + private const uint PAGE_READWRITE = 4u; + + [DllImport("user32.dll")] + public static extern IntPtr SendMessage(IntPtr hWnd, int message, int wParam, IntPtr lParam); + + [DllImport("user32.dll")] + public static extern bool SendMessage(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam); + + [DllImport("kernel32")] + private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, int dwProcessId); + + [DllImport("kernel32")] + private static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, uint flAllocationType, uint flProtect); + + [DllImport("kernel32")] + private static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, uint dwFreeType); + + [DllImport("kernel32")] + private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref ListViewHeaderHelper.HDITEM lvColumnBuffer, int dwSize, IntPtr lpNumberOfBytesWritten); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int dwSize, IntPtr lpNumberOfBytesWritten); + + [DllImport("kernel32")] + private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int dwSize, IntPtr lpNumberOfBytesRead); + + [DllImport("kernel32")] + private static extern bool CloseHandle(IntPtr hObject); + + public static int GetColumnCount(IntPtr hWnd) + { + return (int)ListViewHeaderHelper.SendMessage(hWnd, 4608, 0, IntPtr.Zero); + } + + public static void SetColumnHeaderText(IntPtr hWnd, int processId, int tabIndex, string newText, string targetEncoding) + { + if (!string.IsNullOrEmpty(newText)) + { + IntPtr intPtr = IntPtr.Zero; + IntPtr intPtr2 = IntPtr.Zero; + IntPtr zero = IntPtr.Zero; + int num = Marshal.SizeOf(typeof(ListViewHeaderHelper.HDITEM)); + try + { + intPtr = ListViewHeaderHelper.OpenProcess(2035711u, false, processId); + if (intPtr == IntPtr.Zero) + { + throw new Exception("OpenProcess failed"); + } + intPtr2 = ListViewHeaderHelper.VirtualAllocEx(intPtr, IntPtr.Zero, 1024, 4096u, 4u); + if (intPtr2 == IntPtr.Zero) + { + throw new Exception("VirtualAllocEx failed"); + } + ListViewHeaderHelper.HDITEM hDITEM = default(ListViewHeaderHelper.HDITEM); + hDITEM.mask = 2u; + hDITEM.pszText = (IntPtr)(intPtr2.ToInt32() + num); + hDITEM.cchTextMax = 255; + if (!ListViewHeaderHelper.WriteProcessMemory(intPtr, intPtr2, ref hDITEM, num, IntPtr.Zero)) + { + throw new Exception(string.Format("WriteProcessMemory failed (struct copy, text={0})", newText)); + } + byte[] bytes = Encoding.GetEncoding(targetEncoding).GetBytes(newText); + if (!ListViewHeaderHelper.WriteProcessMemory(intPtr, hDITEM.pszText, bytes, num, IntPtr.Zero)) + { + throw new Exception(string.Format("WriteProcessMemory failed (string buffer copy, text={0})", newText)); + } + ListViewHeaderHelper.SendMessage(hWnd, 4612, new IntPtr(tabIndex), intPtr2); + } + finally + { + if (zero != IntPtr.Zero) + { + Marshal.FreeHGlobal(zero); + } + if (intPtr2 != IntPtr.Zero) + { + ListViewHeaderHelper.VirtualFreeEx(intPtr, intPtr2, 0, 32768u); + } + if (intPtr != IntPtr.Zero) + { + ListViewHeaderHelper.CloseHandle(intPtr); + } + } + } + } + + public static string GetColumnHeaderText(IntPtr hWnd, int processId, int colIndex, string targetEncoding) + { + IntPtr intPtr = IntPtr.Zero; + IntPtr intPtr2 = IntPtr.Zero; + IntPtr intPtr3 = IntPtr.Zero; + int num = Marshal.SizeOf(typeof(ListViewHeaderHelper.HDITEM)); + string result = ""; + try + { + intPtr = ListViewHeaderHelper.OpenProcess(2035711u, false, processId); + if (intPtr == IntPtr.Zero) + { + throw new Exception("OpenProcess failed"); + } + intPtr3 = Marshal.AllocHGlobal(1024); + intPtr2 = ListViewHeaderHelper.VirtualAllocEx(intPtr, IntPtr.Zero, 1024, 4096u, 4u); + if (intPtr2 == IntPtr.Zero) + { + throw new Exception("VirtualAllocEx failed"); + } + ListViewHeaderHelper.HDITEM hDITEM = default(ListViewHeaderHelper.HDITEM); + hDITEM.mask = 2u; + hDITEM.pszText = (IntPtr)(intPtr2.ToInt32() + num); + hDITEM.cchTextMax = 255; + if (!ListViewHeaderHelper.WriteProcessMemory(intPtr, intPtr2, ref hDITEM, num, IntPtr.Zero)) + { + throw new Exception("WriteProcessMemory failed"); + } + ListViewHeaderHelper.SendMessage(hWnd, 4611, new IntPtr(colIndex), intPtr2); + if (!ListViewHeaderHelper.ReadProcessMemory(intPtr, intPtr2, intPtr3, 1024, IntPtr.Zero)) + { + throw new Exception("ReadProcessMemory failed"); + } + byte[] array = new byte[255]; + Marshal.Copy((IntPtr)(intPtr3.ToInt32() + num), array, 0, 255); + result = ListViewHeaderHelper.DecodeString(array, targetEncoding); + } + finally + { + if (intPtr3 != IntPtr.Zero) + { + Marshal.FreeHGlobal(intPtr3); + } + if (intPtr2 != IntPtr.Zero) + { + ListViewHeaderHelper.VirtualFreeEx(intPtr, intPtr2, 0, 32768u); + } + if (intPtr != IntPtr.Zero) + { + ListViewHeaderHelper.CloseHandle(intPtr); + } + } + return result; + } + + private static string DecodeString(byte[] buffer, string targetEncoding) + { + int num = Array.IndexOf(buffer, 0, 0); + if (num < 0) + { + num = buffer.Length; + } + return Encoding.GetEncoding(targetEncoding).GetString(buffer, 0, num); + } + + public static string ByteArrayToHexRepresentation(byte[] ba) + { + string text = BitConverter.ToString(ba); + return text.Replace("-", ""); + } + } +} diff --git a/AA2TranslationLoader/Program.cs b/AA2TranslationLoader/Program.cs new file mode 100644 index 0000000..834f2dd --- /dev/null +++ b/AA2TranslationLoader/Program.cs @@ -0,0 +1,390 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Windows.Forms; +using System.Xml.Serialization; + +namespace AA2TranslationLoader +{ + public class Program + { + [XmlType(AnonymousType = true)] + public class ReplacementDictionary + { + public class Replacement + { + [XmlElement(ElementName = "Japanese")] + public string TargetString + { + get; + set; + } + + [XmlElement(ElementName = "Translated")] + public string ReplacementString + { + get; + set; + } + } + + [XmlElement(ElementName = "Language")] + public string TranslationLanguage + { + get; + set; + } + + [XmlElement(ElementName = "TargetEncoding")] + public string EncodingName + { + get; + set; + } + + [XmlElement(ElementName = "ExecutableName")] + public string GameExeName + { + get; + set; + } + + [XmlElement(ElementName = "SchemaVersion")] + public int SchemaVersion + { + get; + set; + } + + [XmlElement(ElementName = "UpdateNote")] + public string UpdateNote + { + get; + set; + } + + [XmlArrayItem(ElementName = "Replacement")] + public List Replacements + { + get; + set; + } + + public ReplacementDictionary() + { + this.Replacements = new List(); + } + } + + private delegate bool EnumThreadWindowsDelegate(IntPtr hWnd, IntPtr lParam); + + private delegate bool EnumChildWindowsDelegate(IntPtr hWnd, IntPtr lParam); + + private const uint RDW_INVALIDATE = 1u; + + private const uint SW_HIDE = 0u; + + private const uint SW_SHOW = 5u; + + private const int GWL_STYLE = -16; + + private const int TCS_FORCELABELLEFT = 32; + + private const int DEFAULT_GUI_FONT = 17; + + private const int BS_BITMAP = 128; + + private const uint WM_SETFONT = 48u; + + private static List _knownHandles = new List(); + + private static Dictionary _replacements; + + private static bool _debug; + + private static void Main(string[] args) + { + + Console.WriteLine("AA2TL - Artificial Academy 2 Translation Loader v1.3"); + Console.WriteLine("======================================================"); + Console.WriteLine(""); + Console.WriteLine("Please remember to use AppLocale or change your system"); + Console.WriteLine("locale and date/time format to Japanese."); + Console.WriteLine(""); + if (args.Length > 0 && args[0].Equals("-debug")) + { + Console.WriteLine("Debug switch enabled.\n"); + Program._debug = true; + } + Program.ReplacementDictionary replacementDictionary = new Program.ReplacementDictionary(); + try + { + Console.WriteLine("Loading dictionary.xml..."); + if (!File.Exists(string.Format("{0}\\dictionary.xml", AppDomain.CurrentDomain.BaseDirectory))) + { + Console.WriteLine(" dictionary.xml was not found."); + Console.WriteLine(" Place dictionary.xml in the same folder as AA2TL."); + Program.PressAnyKey(); + } + Program._replacements = new Dictionary(); + string xml = File.ReadAllText(string.Format("{0}\\dictionary.xml", AppDomain.CurrentDomain.BaseDirectory)); + replacementDictionary = (Program.ReplacementDictionary)Program.DeserializeXml(xml); + foreach (Program.ReplacementDictionary.Replacement current in replacementDictionary.Replacements) + { + if (!Program._replacements.ContainsKey(current.TargetString) && !current.TargetString.Equals(current.ReplacementString)) + { + Program._replacements.Add(current.TargetString, current.ReplacementString); + } + } + Console.WriteLine(" {0}", replacementDictionary.UpdateNote); + Console.WriteLine(" Target: {0}.exe ({1})", replacementDictionary.GameExeName, replacementDictionary.EncodingName); + Console.WriteLine(" Loaded {0} translations ({1}).", Program._replacements.Count, replacementDictionary.TranslationLanguage); + } + catch (Exception ex) + { + Console.WriteLine(" {0}", ex.GetType()); + Console.WriteLine(" {0}", ex.Message); + Console.WriteLine(" Try redownloading the dictionary.xml file."); + Program.PressAnyKey(); + } + Console.WriteLine(""); + Process[] processesByName = Process.GetProcessesByName(replacementDictionary.GameExeName); + Process process; + if (processesByName.Length > 0) + { + Console.Write("Attaching to existing {0}.exe instance (PID {1})...", replacementDictionary.GameExeName, processesByName[0].Id); + process = processesByName[0]; + } + else + { + Console.Write("Launching {0}.exe...", replacementDictionary.GameExeName); + if (!File.Exists(string.Format("{0}\\{1}.exe", AppDomain.CurrentDomain.BaseDirectory, replacementDictionary.GameExeName))) + { + Console.WriteLine(""); + Console.WriteLine(" {0}.exe was not found.", replacementDictionary.GameExeName); + Console.WriteLine(" Place AA2TL in your AA2 Maker folder."); + Program.PressAnyKey(); + } + process = Process.Start(string.Format("{0}\\{1}.exe", AppDomain.CurrentDomain.BaseDirectory, replacementDictionary.GameExeName)); + } + Thread.Sleep(1000); + Console.WriteLine(" ready!"); + if (!Program._debug) + { + Program.ShowWindow(Program.GetConsoleWindow(), 0u); + } + try + { + while (!process.HasExited) + { + Stopwatch stopwatch = Stopwatch.StartNew(); + IntPtr[] array = Program.EnumerateProcessWindows(process.Id); + if (array != null && array.Length > 0) + { + IntPtr[] array2 = array; + for (int i = 0; i < array2.Length; i++) + { + IntPtr intPtr = array2[i]; + string text = Program.GetControlText(intPtr); + string controlClassName = Program.GetControlClassName(intPtr); + if (text.Contains("\r\n")) + { + text = text.Replace("\r\n", "\n"); + } + if (!Program._knownHandles.Contains(intPtr)) + { + Program._knownHandles.Add(intPtr); + Program.SetControlFont(intPtr); + if (!text.Equals("左目") && !text.Equals("右目") && !text.Equals("両方") && controlClassName.Contains("Button") && !text.Equals(string.Empty)) + { + Program.ClearControlImage(intPtr); + } + } + if (controlClassName.Equals("SysTabControl32")) + { + for (int j = 0; j < TabControlHelper.GetTabCount(intPtr); j++) + { + string tabText = TabControlHelper.GetTabText(intPtr, process.Id, j, replacementDictionary.EncodingName); + bool flag = Program._replacements.ContainsKey(tabText); + if (j == 0 && !flag) + { + break; + } + Program.SetTabControlLeftAlignment(intPtr); + if (flag) + { + TabControlHelper.SetTabText(intPtr, process.Id, j, Program._replacements[tabText], replacementDictionary.EncodingName); + } + } + } + else if (controlClassName.Equals("SysHeader32")) + { + for (int j = 0; j < ListViewHeaderHelper.GetColumnCount(intPtr); j++) + { + string columnHeaderText = ListViewHeaderHelper.GetColumnHeaderText(intPtr, process.Id, j, replacementDictionary.EncodingName); + bool flag = Program._replacements.ContainsKey(columnHeaderText); + if (j == 0 && !flag) + { + break; + } + if (flag) + { + ListViewHeaderHelper.SetColumnHeaderText(intPtr, process.Id, j, Program._replacements[columnHeaderText], replacementDictionary.EncodingName); + } + } + } + else if (!controlClassName.Equals("ComboBox")) + { + if (Program._replacements.ContainsKey(text) && !string.IsNullOrEmpty(text)) + { + Program.SetControlCaption(intPtr, Program._replacements[text]); + } + } + } + stopwatch.Stop(); + if (Program._debug) + { + Console.Write("\rReplacement loop took {0}ms. ", stopwatch.ElapsedMilliseconds); + } + Thread.Sleep(400); + } + } + } + catch (Exception ex) + { + Program.ShowWindow(Program.GetConsoleWindow(), 5u); + Console.Write("\n\n"); + Console.WriteLine("====================================================="); + Console.WriteLine("AA2TL has crashed."); + Console.WriteLine("{0} will continue running, but will not be translated.", replacementDictionary.GameExeName); + Console.WriteLine(ex.ToString()); + Program.PressAnyKey(); + } + Console.WriteLine("\n{0} has been closed.", replacementDictionary.GameExeName); + } + + private static object DeserializeXml(string xml) + { + XmlSerializer xmlSerializer = new XmlSerializer(typeof(Program.ReplacementDictionary), new XmlRootAttribute("ReplacementDictionary")); + StringReader textReader = new StringReader(xml); + return xmlSerializer.Deserialize(textReader); + } + + private static void PressAnyKey() + { + Console.WriteLine("\nPress any key to exit."); + Console.ReadKey(); + Environment.Exit(1); + } + + private static string GetControlClassName(IntPtr hWnd) + { + StringBuilder stringBuilder = new StringBuilder(256); + Program.GetClassName(hWnd, stringBuilder, stringBuilder.Capacity); + return stringBuilder.ToString(); + } + + [DllImport("user32.dll")] + private static extern bool EnumThreadWindows(int dwThreadId, Program.EnumThreadWindowsDelegate callback, IntPtr lParam); + + [DllImport("user32.dll")] + private static extern bool EnumChildWindows(IntPtr window, Program.EnumChildWindowsDelegate callback, IntPtr lParam); + + [DllImport("user32.dll")] + private static extern IntPtr GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); + + [DllImport("user32.dll")] + private static extern int GetWindowLong(IntPtr hWnd, int nIndex); + + [DllImport("user32.dll")] + private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); + + [DllImport("user32.dll")] + private static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate, IntPtr hrgnUpdate, uint flags); + + [DllImport("kernel32.dll")] + private static extern IntPtr GetConsoleWindow(); + + [DllImport("user32.dll")] + private static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern bool SetWindowText(IntPtr hwnd, string lpString); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern int GetWindowTextLength(IntPtr hWnd); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool PostMessage(IntPtr hWnd, uint message, IntPtr wParam, IntPtr lParam); + + [DllImport("gdi32.dll")] + private static extern IntPtr GetStockObject(int fnObject); + + private static IntPtr[] EnumerateProcessWindows(int processId) + { + List parentWindowHandles = new List(); + List allWindowHandles = new List(); + foreach (ProcessThread processThread in Process.GetProcessById(processId).Threads) + { + Program.EnumThreadWindows(processThread.Id, delegate(IntPtr hWnd, IntPtr lParam) + { + parentWindowHandles.Add(hWnd); + allWindowHandles.Add(hWnd); + return true; + }, IntPtr.Zero); + } + foreach (IntPtr current in parentWindowHandles) + { + Program.EnumChildWindows(current, delegate(IntPtr hWnd, IntPtr lParam) + { + allWindowHandles.Add(hWnd); + return true; + }, IntPtr.Zero); + } + return allWindowHandles.ToArray(); + } + + private static void ClearControlImage(IntPtr hWnd) + { + int num = Program.GetWindowLong(hWnd, -16); + num &= -129; + Program.SetWindowLong(hWnd, -16, num); + } + + private static string GetControlText(IntPtr hWnd) + { + int windowTextLength = Program.GetWindowTextLength(hWnd); + StringBuilder stringBuilder = new StringBuilder(windowTextLength + 1); + Program.GetWindowText(hWnd, stringBuilder, stringBuilder.Capacity); + return stringBuilder.ToString(); + } + + private static void SetControlCaption(IntPtr hWnd, string caption) + { + Program.SetWindowText(hWnd, caption); + Program.RedrawWindow(hWnd, IntPtr.Zero, IntPtr.Zero, 1u); + } + + private static void SetTabControlLeftAlignment(IntPtr hWnd) + { + int num = Program.GetWindowLong(hWnd, -16); + num |= 32; + Program.SetWindowLong(hWnd, -16, num); + } + + private static void SetControlFont(IntPtr hWnd) + { + //IntPtr stockObject = Program.GetStockObject(17); + //Program.PostMessage(hWnd, WM_SETFONT, myFont, (IntPtr)1); + } + } +} diff --git a/AA2TranslationLoader/Properties/AssemblyInfo.cs b/AA2TranslationLoader/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..61156ec --- /dev/null +++ b/AA2TranslationLoader/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +using System; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyVersion("1.3.0.0")] +[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] +[assembly: AssemblyCompany("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCopyright("Copyright ©2016 /aa2g/")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyFileVersion("1.3.0.0")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyTitle("AA2TranslationLoader")] +[assembly: AssemblyTrademark("")] +[assembly: CompilationRelaxations(8)] +[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] +[assembly: ComVisible(false)] +[assembly: Guid("882f7107-c652-4dc8-abe1-35b17d62c0a2")] diff --git a/AA2TranslationLoader/Resources/icon.ico b/AA2TranslationLoader/Resources/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..0e53bbd247e6d39c182a62e1bf868e7ce4cd1b24 GIT binary patch literal 7358 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 literal 0 HcmV?d00001 diff --git a/AA2TranslationLoader/TabControlHelper.cs b/AA2TranslationLoader/TabControlHelper.cs new file mode 100644 index 0000000..31c9a76 --- /dev/null +++ b/AA2TranslationLoader/TabControlHelper.cs @@ -0,0 +1,200 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace AA2TranslationLoader +{ + internal class TabControlHelper + { + private struct TCITEM + { + public uint mask; + + public int dwState; + + public int dwStateMask; + + public IntPtr pszText; + + public int cchTextMax; + + public int iImage; + + public int lParam; + } + + private const int TCM_FIRST = 4864; + + private const int TCM_GETITEMCOUNT = 4868; + + private const int TCM_GETITEM = 4869; + + private const int TCM_SETITEM = 4870; + + private const int TCIF_TEXT = 1; + + private const uint PROCESS_ALL_ACCESS = 2035711u; + + private const uint MEM_COMMIT = 4096u; + + private const uint MEM_RELEASE = 32768u; + + private const uint PAGE_READWRITE = 4u; + + [DllImport("user32.dll")] + public static extern IntPtr SendMessage(IntPtr hWnd, int message, int wParam, IntPtr lParam); + + [DllImport("user32.dll")] + public static extern bool SendMessage(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam); + + [DllImport("kernel32")] + private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, int dwProcessId); + + [DllImport("kernel32")] + private static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, uint flAllocationType, uint flProtect); + + [DllImport("kernel32")] + private static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, uint dwFreeType); + + [DllImport("kernel32")] + private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref TabControlHelper.TCITEM tcitemBuffer, int dwSize, IntPtr lpNumberOfBytesWritten); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int dwSize, IntPtr lpNumberOfBytesWritten); + + [DllImport("kernel32")] + private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int dwSize, IntPtr lpNumberOfBytesRead); + + [DllImport("kernel32")] + private static extern bool CloseHandle(IntPtr hObject); + + public static int GetTabCount(IntPtr hWnd) + { + return (int)TabControlHelper.SendMessage(hWnd, 4868, 0, IntPtr.Zero); + } + + public static void SetTabText(IntPtr hWnd, int processId, int tabIndex, string newText, string targetEncoding) + { + if (!string.IsNullOrEmpty(newText)) + { + IntPtr intPtr = IntPtr.Zero; + IntPtr intPtr2 = IntPtr.Zero; + IntPtr zero = IntPtr.Zero; + int num = Marshal.SizeOf(typeof(TabControlHelper.TCITEM)); + try + { + intPtr = TabControlHelper.OpenProcess(2035711u, false, processId); + if (intPtr == IntPtr.Zero) + { + throw new Exception("OpenProcess failed"); + } + intPtr2 = TabControlHelper.VirtualAllocEx(intPtr, IntPtr.Zero, 1024, 4096u, 4u); + if (intPtr2 == IntPtr.Zero) + { + throw new Exception("VirtualAllocEx failed"); + } + TabControlHelper.TCITEM tCITEM = default(TabControlHelper.TCITEM); + tCITEM.mask = 1u; + tCITEM.pszText = (IntPtr)(intPtr2.ToInt32() + num); + tCITEM.cchTextMax = 255; + if (!TabControlHelper.WriteProcessMemory(intPtr, intPtr2, ref tCITEM, num, IntPtr.Zero)) + { + throw new Exception(string.Format("WriteProcessMemory failed (struct copy, text={0})", newText)); + } + byte[] bytes = Encoding.GetEncoding(targetEncoding).GetBytes(newText); + if (!TabControlHelper.WriteProcessMemory(intPtr, tCITEM.pszText, bytes, num, IntPtr.Zero)) + { + throw new Exception(string.Format("WriteProcessMemory failed (string buffer copy, text={0})", newText)); + } + TabControlHelper.SendMessage(hWnd, 4870, new IntPtr(tabIndex), intPtr2); + } + finally + { + if (zero != IntPtr.Zero) + { + Marshal.FreeHGlobal(zero); + } + if (intPtr2 != IntPtr.Zero) + { + TabControlHelper.VirtualFreeEx(intPtr, intPtr2, 0, 32768u); + } + if (intPtr != IntPtr.Zero) + { + TabControlHelper.CloseHandle(intPtr); + } + } + } + } + + public static string GetTabText(IntPtr hWnd, int processId, int tabIndex, string targetEncoding) + { + IntPtr intPtr = IntPtr.Zero; + IntPtr intPtr2 = IntPtr.Zero; + IntPtr intPtr3 = IntPtr.Zero; + int num = Marshal.SizeOf(typeof(TabControlHelper.TCITEM)); + string result; + try + { + intPtr = TabControlHelper.OpenProcess(2035711u, false, processId); + if (intPtr == IntPtr.Zero) + { + throw new Exception("OpenProcess failed"); + } + intPtr3 = Marshal.AllocHGlobal(1024); + intPtr2 = TabControlHelper.VirtualAllocEx(intPtr, IntPtr.Zero, 1024, 4096u, 4u); + if (intPtr2 == IntPtr.Zero) + { + throw new Exception("VirtualAllocEx failed"); + } + TabControlHelper.TCITEM tCITEM = default(TabControlHelper.TCITEM); + tCITEM.mask = 1u; + tCITEM.pszText = (IntPtr)(intPtr2.ToInt32() + num); + tCITEM.cchTextMax = 255; + if (!TabControlHelper.WriteProcessMemory(intPtr, intPtr2, ref tCITEM, num, IntPtr.Zero)) + { + throw new Exception("WriteProcessMemory failed"); + } + TabControlHelper.SendMessage(hWnd, 4869, new IntPtr(tabIndex), intPtr2); + if (!TabControlHelper.ReadProcessMemory(intPtr, intPtr2, intPtr3, 1024, IntPtr.Zero)) + { + throw new Exception("ReadProcessMemory failed"); + } + byte[] array = new byte[255]; + Marshal.Copy((IntPtr)(intPtr3.ToInt32() + num), array, 0, 255); + result = TabControlHelper.DecodeString(array, targetEncoding); + } + finally + { + if (intPtr3 != IntPtr.Zero) + { + Marshal.FreeHGlobal(intPtr3); + } + if (intPtr2 != IntPtr.Zero) + { + TabControlHelper.VirtualFreeEx(intPtr, intPtr2, 0, 32768u); + } + if (intPtr != IntPtr.Zero) + { + TabControlHelper.CloseHandle(intPtr); + } + } + return result; + } + + private static string DecodeString(byte[] buffer, string targetEncoding) + { + int num = Array.IndexOf(buffer, 0, 0); + if (num < 0) + { + num = buffer.Length; + } + return Encoding.GetEncoding(targetEncoding).GetString(buffer, 0, num); + } + + public static string ByteArrayToHexRepresentation(byte[] ba) + { + string text = BitConverter.ToString(ba); + return text.Replace("-", ""); + } + } +} diff --git a/AA2TranslationLoader/app.config b/AA2TranslationLoader/app.config new file mode 100644 index 0000000..fcd0c93 --- /dev/null +++ b/AA2TranslationLoader/app.config @@ -0,0 +1,3 @@ + + + diff --git a/AA2TranslationLoader/dictionary.xml b/AA2TranslationLoader/dictionary.xml new file mode 100644 index 0000000..2d7bb22 --- /dev/null +++ b/AA2TranslationLoader/dictionary.xml @@ -0,0 +1,1241 @@ + + + + + + English + + /aa2g/ Windows 10 update + + AA2Edit + + shift-jis + + 6 + + + + 初期設定 + Initialization + + + ゲーム開始 + Game Start + + + 動作設定 + Configuration + + + システム情報 + System Info + + + マニュアルを読む + View Manual + + + 終了 + Exit + + + はじめに… + A brief word... + + +  この作品は全てフィクションです。 +作品内に登場する人名・団体名・地名・事件及び時代背景・職業は全て架空のものであり、実際のものとは一切関係ありません。 +  This is a work of fiction. Any names or places depicted are fictitious, and have no relations to anything in reality. + + +  このゲームの内容はあくまで創作物でありゲームです。 このゲームの内容と同じことを現実に行うと法律によって処罰されるときがあります。ゲームの内容は芝居でありフィクションですので、絶対にゲームのマネをしたり実際にやったりしないで下さい。 +  Don't do anything in real life that you see in the game. Reproduction of depicted events may result in action by the law. + + +  このゲームの登場人物はすべて18歳以上です。 +  Characters in this game are 18 or older. + + +  このゲームは作品内容および演出上、18歳未満の方の購入・プレイが禁止されています。 +  Brought to you by /hgg/, /aa2g/ and the Hongfire AA2 Translation Team. + + + + コンフィグ + Configuration + + + キャンセル + Cancel + + + 簡易設定 + Basic Setup + + + パフォーマンス + Performance + + + ノーマル + Normal + + + クォリティ + Quality + + + 画面サイズ + Screen Resolution + + + カスタム + Advanced + + + 全般 + General + + + ゲーム設定 + Game Settings + + + マウス設定 + Mouse Settings + + + その他 + Etc. + + + テクスチャを綺麗にする + Smooth Textures + + + バイリニア補間を使用する + Bilinear Filtering + + + + 頂点処理を +ハードウェアで処理する + Hardware Vertex Processing + + + MipMap設定 + Mipmap Settings + + + 綺麗 + Best + + + 描画方法 + Rendering Method + --> + + 設定1 + Type 1 + + + 設定2 + Type 2 + + + ※設定2にすると、速度が向上する可能性が +  ありますが、描画が乱れる場合があります。 + * Type 2 runs faster, but may result in graphical anomalies. + + + ブラーを有効にする + Enable Blur + + + 後光シェーダーを有効にする + Enable Rim Lighting + + + 影テクスチャ + Shadow Resolution + + + アンチエイリアス + Anti-aliasing + + + マウススピード + Mouse Speed + + + 少し速い + Fast + + + 速い + Faster + + + + ダブルマウスを使用する + Use Double Mouse + + + サブマウス登録 + Register Submouse + + + メインマウス登録 + Register Main Mouse + + + ※登録させたい方のマウスでボタンをクリックしてください。 + * Click on the button with the mouse you want to register. + + + + ジンコウガクエン2 きゃらめいく + Artificial Academy 2 Character Maker + + + メイン画面 + Main Screen + + + キャラクター + Character + + + 表示 + Display + + + 削除 + Delete + + + カメラ + Camera + + + リセット + Reset + + + + + Chest + + + + Crotch + + + 男 保存先フォルダを開く + Browse Male Folder + + + 女 保存先フォルダを開く + Browse Female Folder + + + 女キャラクター作成 + Create Female Character + + + 男キャラクター作成 + Create Male Character + + + 確認 + Confirm + + + 本当に削除してもいいですか? + Do you really want to delete this character? + + + 日付 + Date + + + 性別 + Sex + + + + キャラクター作成画面 + Character Maker Screen + + + メイン画面に戻る + Return to Main Screen + + + 初期化 + Default + + + ランダム + Random + + + オールランダム + All Random + + + 新規作成 + New Character + + + 読み込む + Open File + + + 保存先フォルダを開く + Open Destination Folder + + + 保存 + Save + + + キャラクター作成 + Character Creation + + + ※ファイル名に使用できる文字は、「 a~z 」「 A~Z 」「 0~9 」「 - 」「 _ 」です。 + *You can use the characters 「 a~z 」「 A~Z 」「 0~9 」「 - 」「 _ 」. + + +  また、文字数は半角16文字までとなっています。 +  File names must be between 1 and 16 characters. + + +  (例:Cha00_00) +  (Example: Cha00_00) + + + ファイル名: + File name: + + + ファイル名 + File name + + + 読み込み + Load + + + + システム + System + + + 体色 + Body Color + + + + Face + + + + Eyes + + + 眼色 + Eye Color + + + + Eyebrows + + + 顔ほか + Face Details + + + + Hair + + + 髪色 + Hair Color + + + 人格 + Character + + + 性格 + Personality + + + 個性 + Traits + + + + 低い + Lowest + + + 低め + Low + + + 基本 + Average + + + 標準 + Standard + + + 高め + High + + + 高い + Highest + + + 華奢 + Delicate + + + + 長身 + Tall + + + 巨漢 + Fat + + + 細め + Thin + + + 太め + Chubby + + + + Soft + + + + Medium + + + + Hard + + + 手数 + No restraint + + + 一撃 + One Blow + + + 変則 + Irregular + + + 普通 + Normal + + + 異性のみ + Hetero + + + 異性より + Lean hetero + + + 両方 + Bisexual + + + 同性より + Lean homo + + + 同性のみ + Homo + + + なし + None + + + あり + Yes + + + + 追加 + Add + + + + + Lively + + + + Delicate + + + + Cheerful + + + + Quiet + + + + Playful + + + + Frisky + + + + Kind + + + + Joyful + + + + Ordinary + + + + Irritated + + + + Harsh + + + + Sweet + + + + Creepy + + + + Reserved + + + + Dignified + + + + Aloof + + + + Smart + + + + Genuine + + + + Mature + + + + Lazy + + + + Manly + + + + Cadet + + + + Caring + + + + Carefree + + + + + Gentle + + + + Positive + + + + Otaku + + + + Savage + + + + Schemer + + + + Warm + + + + チョロイ + Easygoing + + + 熱血友情 + Affable + + + 男性苦手 + Bad with Guys + + + 女性苦手 + Bad with Girls + + + チャーム + Charming + + + ツンデレ + Tsundere + + + 侠気 + Chivalrous + + + ミーハー + Trendy + + + 素直 + Obedient + + + 前向き + Positive + + + 照れ屋 + Shy + + + ヤキモチ + Jealous + + + 豆腐精神 + Melancholy + + + スケベ + Perverted + + + 真面目 + Serious + + + クール + Calm + + + 直情的 + Impulsive + + + ぽややん + Absentminded + + + 暴力的 + Violent + + + 草食 + Passive + + + 世話焼き + Meddlesome + + + 委員長 + Class Prez + + + お喋り + Chatty + + + ハラペコ + Always Hungry + + + 恋愛脳 + Romantic + + + 一途 + Singleminded + + + 優柔不断 + Indecisive + + + 負けん気 + Competitive + + + 腹黒 + Scheming + + + 勤勉 + Diligent + + + 奔放 + Wild + + + M気質 + Masochist + + + 汗かき + Sweaty + + + 心の闇 + Evil + + + 難聴 + Deaf + + + 例の弱み + Exploitable + + + 未性徴 + Asexual + + + 強運 + Lucky + + + + キス + Kissing + + + 胸愛撫 + Breast Caressing + + + 女性器愛撫 + Vagina Caressing + + + 男性器愛撫 + Penis Caressing + + + クンニ + Cunnilingus + + + フェラ + Fellatio + + + 男バック挿入 + Doggy Style + + + 女主導挿入 + Femdom + + + アナル全般 + Anal Play + + + 生性器挿入 + No Condom + + + 精飲 + Swallowing + + + 中出し + Creampies + + + 精液掛け + Bukkake + + + + 体の種類 + Body Type + + + 身長 + Height + + + 体型 + Figure + + + 頭の大きさ + Head Size + + + ウエスト + Waist + + + 頭の長さ + Head Length + + + 大きさ + Size + + + + Shape + + + 丸み + Roundness + + + 向き + Direction + + + 高さ + Height + + + 間隔 + Spacing + + + 奥行き + Depth + + + 柔らかさ + Softness + + + 乳輪の大きさ + Areola Size + + + 色合い + Hue + + + 鮮やかさ + Saturation + + + 明るさ + Brightness + + + 肌の色 + Skin Color + + + 乳首の色 + Nipple Color + + + 乳首の濃さ + Nipple Opacity + + + 日焼け跡 + Tan Mark + + + 日焼け濃さ + Tan Opacity + + + モザイク + Mosaic + + + アンダー形 + Pubic Shape + + + アンダー濃さ + Pubic Opacity + + + アンダー色 + Pubic Color + + + 乳首の種類 + Nipple Type + + + 顔形 + Face Type + + + 目の横幅 + Eye Width + + + 目の高さ + Eye Position + + + 目の間隔 + Eye Spacing + + + 目の角度 + Eye Angle + + + 目の縦幅 + Eye Height + + + 外部ファイルを使用する + Use External File + + + 開く + Browse + + + 瞳の形 + Iris Shape + + + 瞳の横幅 + Iris Width + + + 瞳の高さ + Iris Position + + + 瞳の種類 + Iris Type + + + ハイライト種類 + Highlight Type + + + 瞳の縦幅 + Iris Height + + + 瞳の色 + Eye Color + + + 左目 + Left Eye + + + 右目 + Right Eye + + + 髪へ反映 + Hair + + + アンダーヘアへ反映 + Pubic Hair + + + 眉の形 + Brow Shape + + + 眉の角度 + Brow Angle + + + 眉の色 + Brow Color + + + 色の同期 + Match Color + + + 上睫毛 + Upper Eyelid + + + 下睫毛 + Lower Eyelid + + + 眼鏡 + Glasses + + + 眼鏡の色 + Glasses Color + + + ほくろ + Moles + + + + Lip Color + + + 唇の濃さ + Lip Opacity + + + まぶた + Eyelid + + + 前髪 + Front Hair + + + 横髪 + Side Hair + + + 後髪 + Back Hair + + + 付毛 + Hair Extension + + + 髪の調整 + Adjustment + + + 左右反転 + Flip Horiz. + + + 反転 + Flip + + + 眉へ反映 + Eyebrows + + + 髪の色 + Hair Color + + + 苗字 + Last Name + + + 名前 + First Name + + + 社交性 + Sociability + + + 貞操観念 + Virtue + + + 性愛対象 + Orientation + + + 性交経験 + Sexual Exp. + + + 肛交経験 + Anal Exp. + + + プロフィール + Profile + + + 喧嘩スタイル + Fighting Style + + + 知力 + Intelligence + + + 体力 + Strength + + + ※255文字まで入力できます + * Up to 255 characters. + + + 声調整 + Voice Pitch + + + +    個性 + +※2個まで +選択出来ます +   Character Traits +* Choose up + to two + + +    H好み + +※2個まで +選択出来ます +   Sexual Preferences +* Choose up + to two + + + 持ち物 愛 + Lover's Item + + + 持ち物 友 + Friend's Item + + + 持ち物 H + Sexual Item + + + + すでに同名のファイルが存在します。 +上書きしますか? + A file with the same name already exists. Do you want to overwrite it? + + + キャラクター情報を作成しました。 + Character created. + + + キャラクターが保存されていない可能性があります。 +メイン画面に戻りますか? + You may not have saved your character. Are you sure you want to return to the main menu? + + + 選択 + Selection + + + 設定 + OK + + + 選択された画面サイズはデスクトップの画面領域を超えているので自動修正されます。 + The chosen screen resolution exceeds the size of your desktop and has been automatically changed. + + + ディスプレイ画面領域の修正 + Screen Resolution Changed + + + ファイル名が入力されていません。 + No file name was entered. + + + \ No newline at end of file