-
Notifications
You must be signed in to change notification settings - Fork 101
Open
Description
I implemented a Java sample!
/*
* author: [wjw](https://github.com/wjw465150)
* date: 2024年11月7日 14:43:06
* note:
*/
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.text.MessageFormat;
import java.util.Base64;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
public class MMMojoCallUsage {
interface MMMojoCall extends Library {
public static MMMojoCall MMMojoCallDLL = Native.load("./win32-x86-64/MMMojoCall.dll", MMMojoCall.class);
/**
* @brief 初始化 mmmojo(_64).dll
* @param mmmojo_dll_path mmmojo(_64).dll所在路径
* @return 是否初始化成功
*/
boolean InitMMMojoDLLFuncs(String mmmojo_dll_path);
/**
* @brief 初始化全局MMMojo环境 (全局调一次)
* @param argc 当前进程的参数个数
* @param argv 当前进程的参数
* @return 是否初始化成功
*/
boolean InitMMMojoGlobal(int argc, String argv);
/**
* @brief 以纯C的方式导出XPluginMgr类 方便其他语言调用
* @param mgr_type 0为XPluginManager, 1为OCRManager, 2为UtilityManager
* @return XPluginMgr对象指针 失败返回NULL
*/
Pointer GetInstanceXPluginMgr(int mgr_type);
/**
* @brief 根据字符串调用相应的函数
* @param class_ptr 类指针
* @param mgr_type 类的类型
* @param func_name 函数名
* @param ret_ptr 存储返回值的指针 如果不使用返回值则传入NULL
* @param ... 参数 一定要对应函数的正确参数 内部不做检查
* @return 执行状态 0失败 1成功 2未知错误
*/
int CallFuncXPluginMgr(Pointer class_ptr, int mgr_type, String func_name, Pointer ret_ptr, Object... args);
/**
* @brief 销毁XPluginMgr类指针
* @param XPluginMgr对象指针
*/
void ReleaseInstanceXPluginMgr(Pointer mgr_ptr);
/**
* SetReadOnPush 回调函数的接口
*/
interface SetResCallback extends Callback {
/** 回调方法
*
* @param pic_path 图片路径
* @param data 数据
* @param data_size 数据大小
*/
void callback(String pic_path, Pointer data, int data_size);
/**
* 获取结果
*
* @param timeout the timeout
* @param unit the unit
* @return the string
* @throws InterruptedException the interrupted exception
* @throws ExecutionException the execution exception
* @throws TimeoutException the timeout exception
*/
String get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
}
static String mmmojocallGetLastErrStr(Pointer ocrMgr) {
Pointer retPtr = new Memory(8); // ULONGLONG的指针
MMMojoCall.MMMojoCallDLL.CallFuncXPluginMgr(ocrMgr, 0, "GetLastErrStr", retPtr);
return retPtr.getPointer(0).getString(0);
}
public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
String wechatOcrDir = "C:\\Users\\wjw\\AppData\\Roaming\\Tencent\\WeChat\\XPlugin\\Plugins\\WeChatOCR\\7079\\extracted\\WeChatOCR.exe";
String wechatDir = "C:\\Program Files\\Tencent\\WeChat\\[3.9.12.17]";
String imgPath = ".\\test.png";
// 加载mmmojo(_64).dll并获取导出函数, 只需要调用一次.
if(!MMMojoCall.MMMojoCallDLL.InitMMMojoDLLFuncs(wechatDir)) {
System.out.println("\033[31m[!] mmmojocall::InitMMMojoDLLFuncs ERR!\033[0m");
System.exit(-1);
} else {
System.out.println("\033[31m[+] InitMMMojoDLLFuncs Over!\033[0m");
}
// 初始化MMMojo (包括ThreadPool等), 只需要调用一次.
MMMojoCall.MMMojoCallDLL.InitMMMojoGlobal(0, null);
//导出 OCRManager
Pointer ocrMgr = MMMojoCall.MMMojoCallDLL.GetInstanceXPluginMgr(1);
try(Memory retPtr = new Memory(8) /* ULONGLONG的指针 */) {
retPtr.clear(retPtr.size());
MMMojoCall.MMMojoCallDLL.CallFuncXPluginMgr(ocrMgr, 1, "SetExePath", retPtr, wechatOcrDir);
if(retPtr.getPointer(0) == null) {
String errStr = mmmojocallGetLastErrStr(ocrMgr);
System.out.println(MessageFormat.format("\033[31m[!] {0}\033[0m",errStr));
System.exit(-1);
}
MMMojoCall.MMMojoCallDLL.CallFuncXPluginMgr(ocrMgr, 1, "SetUsrLibDir", retPtr, wechatDir);
if(retPtr.getPointer(0) == null) {
String errStr = mmmojocallGetLastErrStr(ocrMgr);
System.out.println(MessageFormat.format("\033[31m[!] {0}\033[0m",errStr));
System.exit(-1);
}
//设置传给用户回调函数的数据类型(protobuf/json)
//use_json 如果为true则传递json字符串, 为false则传递序列化后的pb二进制数据
MMMojoCall.MMMojoCallDLL.CallFuncXPluginMgr(ocrMgr, 1, "SetCallbackDataMode", retPtr, true);
//设置接收结果的回调函数.
SetResCallbackImp setResCallbackImp = new SetResCallbackImp();
MMMojoCall.MMMojoCallDLL.CallFuncXPluginMgr(ocrMgr, 1, "SetReadOnPush", retPtr, setResCallbackImp);
MMMojoCall.MMMojoCallDLL.CallFuncXPluginMgr(ocrMgr, 1, "StartWeChatOCR", retPtr);
if(retPtr.getPointer(0) == null) {
String errStr = mmmojocallGetLastErrStr(ocrMgr);
System.out.println(MessageFormat.format("\033[31m[!] {0}\033[0m",errStr));
System.exit(-1);
}
System.out.println("\033[31m[+] StartWeChatOCR OK!\033[0m");
imgPath = Path.of(imgPath).toAbsolutePath().toString(); // 注意文件路径里不能有中文字符
MMMojoCall.MMMojoCallDLL.CallFuncXPluginMgr(ocrMgr, 1, "DoOCRTask", retPtr, imgPath);
if(retPtr.getPointer(0) == null) {
String errStr = mmmojocallGetLastErrStr(ocrMgr);
System.out.println(MessageFormat.format("\033[31m[!] {0}\033[0m",errStr));
System.exit(-1);
}
String strOcr = setResCallbackImp.get(10, TimeUnit.SECONDS);
System.out.println(strOcr);
{ // 转换成JsonObject
JsonObject rawJsonObj = JsonParser.parseString(strOcr).getAsJsonObject();
//System.out.println(rawJsonObj);
JsonArray jsonArray = rawJsonObj.getAsJsonObject("ocr_result").getAsJsonArray("single_result");
jsonArray.asList().forEach(jsonElement -> {
String strBase64 = jsonElement.getAsJsonObject().get("single_str_utf8").getAsString();
String strTxt = new String(Base64.getDecoder().decode(strBase64), StandardCharsets.UTF_8);
System.out.println(strTxt);
});
}
// 销毁MMMojo环境以及WeChatOCR.exe进程
MMMojoCall.MMMojoCallDLL.CallFuncXPluginMgr(ocrMgr, 1, "KillWeChatOCR", retPtr);
} finally {
// 销毁XPluginMgr类指针
MMMojoCall.MMMojoCallDLL.ReleaseInstanceXPluginMgr(ocrMgr);
}
}
static final class SetResCallbackImp implements MMMojoCall.SetResCallback {
CompletableFuture<String> futurePdf = new CompletableFuture<>();
@Override
public void callback(String pic_path, Pointer data, int data_size) {
if (pic_path == null) {
futurePdf.complete(null);
} else {
byte[] byteArray = data.getByteArray(0, data_size);
futurePdf.complete(new String(byteArray, StandardCharsets.UTF_8));
}
}
@Override
public String get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return futurePdf.get(timeout, unit);
}
}
}Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels