使用 chiitrans 的方式 https://github.com/alexbft/chiitrans ,将Textractor的CLI改为dll,供.Net使用
代码放github了 https://github.com/lgztx96/texthost ,没有qt,只取了必要部分编译为dll
也没啥好说的,直接导出就行,不过函数名总是有奇奇怪怪的前缀后缀,加了个.def文件解决。
最后直接调用就行了,一些无符号数可以改为有符号数,需要Textractor的texthook.dll放同一目录,使用剪贴板监视需要传递一个窗口句柄。移钩子的功能挺好用的,不然可能有很多没用的钩子
//用于搜索钩子的结构体参数,32bit size=608 ,64bit size=632
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct SearchParam
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)]
public Byte[] pattern;
public Int32 Length;
public Int32 Offset;
public Int32 SearchTime;
public Int32 MaxRecords;
public Int32 Codepage;
[MarshalAs(UnmanagedType.SysUInt)]
public IntPtr Padding;
[MarshalAs(UnmanagedType.SysUInt)]
public IntPtr MinAddress;
[MarshalAs(UnmanagedType.SysUInt)]
public IntPtr MaxAddress;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 120)]
public String BoundaryModule;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 120)]
public String ExportModule;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 30)]
public String Text;
public IntPtr HookPostProcessor;
};
#region 回调委托
internal delegate void ProcessCallback(uint processId);
internal delegate void OnCreateThread(
long threadId,
uint processId,
ulong address,
ulong context,
ulong subcontext,
[MarshalAs(UnmanagedType.LPWStr)] string name,
[MarshalAs(UnmanagedType.LPWStr)] string hookCode
);
internal delegate void OnRemoveThread(long threadId);
internal delegate void OnOutputText(long threadId,[MarshalAs(UnmanagedType.LPWStr)] string text);
#endregion
internal class TextHostLib
{
[DllImport("texthost.dll")]
internal static extern int TextHostInit(
ProcessCallback OnConnect,
ProcessCallback OnDisconnect,
OnCreateThread OnCreateThread,
OnRemoveThread OnRemoveThread,
OnOutputText OnOutputText
);
[DllImport("texthost.dll")]
internal static extern int InsertHook(
uint processId,
[MarshalAs(UnmanagedType.LPWStr)] string hookCode
);
[DllImport("texthost.dll")]
internal static extern int RemoveHook(uint processId, ulong address);
[DllImport("texthost.dll")]
internal extern static int InjectProcess(uint processId);
[DllImport("texthost.dll")]
internal extern static int DetachProcess(uint processId);
[DllImport("texthost.dll")]
internal extern static int AddClipboardThread(IntPtr windowHandle);
}
这样造个自己的vnr就很容易了。正在龟速进行自己的vnr计划

Comments | 7 条评论
是不是可以读取本地文本呢?Hook游戏文字,输出对应翻译?
@御坂凛 不是很明白你的意思,通过OnOutputFunc委托就可以获取文本,接下来要读文本文件(类似于vnr的人工字幕)还是在线翻译都行。
还是类似vnr的内嵌翻译,这个就不是这样,要根据游戏引擎具体来弄
@lgztx 想要读取翻译文件,输出人工字幕。
Textractor加了一个ExampleExtension插件,编程框能显示对应的中文,但不知怎么输出到字幕界面。
期待你的VNR~
P.S.博客设计好好看!
作者你好,经过试用,发现了一些问题。
添加了委托之后,稍微使用一会就会出现如下异常:
托管调试助手 “CallbackOnCollectedDelegate”
对“xxx.TextHostLib+OnOutputFunc::Invoke”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们。
经过查阅相关资料应该是GC自动回收导致的问题,但是我使用了诸如把委托对象放在类中声明,改成静态变量、使用GCHandle、使用GC.KeepAlive()等方法都不能解决,请问你是否有方法解决这个问题呢?
@★果冻★ 我倒是没有遇到你说的问题,现在我玩生肉也基本用自己的工具玩,使用textractor代码就是按照chiitrans的代码改了一下。当然具体问题可以一起探讨,合作也没问题。
人人都想造一个自己的vnr(老乡好
@1157735334 很久没登博客了,我也在github上见过你,原来是老乡,感觉你对vnr也很有兴趣。