You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于修改JavaFX程序以自动交互Delphi7程序的技术方案问询

修改JavaFX程序以自动交互Delphi 7程序的两种技术方案

嘿,这个需求我之前帮朋友处理过类似的,给你两种靠谱的方向,你可以根据自己的技术栈和复杂度来选:


方案一:自动触发Delphi对话框并填充值(模拟用户交互)

这个方案的核心是用Java调用Windows原生API,模拟用户手动打开对话框、输入值、点击确认的操作,优点是对Delphi程序完全无侵入,不用改它的代码。

  • 具体步骤:

    1. 给JavaFX项目引入**JNA(Java Native Access)**库,它能让Java直接调用Windows API,不用写复杂的JNI代码。
    2. 用Windows自带的**Spy++**工具,找到Delphi程序主窗口的标题、对话框输入控件的类名(Delphi的输入框通常是TEdit)、确认按钮的类名(TButton)和按钮文本,这些是定位控件的关键。
    3. 用JNA调用Windows API的FindWindow、FindWindowEx找到对应窗口和控件的句柄,再用SendMessage给控件发送消息填充值、模拟点击。
  • 简化的Java代码示例:

// 先通过JNA映射需要的Windows API
public interface User32 extends StdCallLibrary {
    User32 INSTANCE = Native.load("user32", User32.class);
    
    HWND FindWindow(String lpClassName, String lpWindowName);
    HWND FindWindowEx(HWND hwndParent, HWND hwndChildAfter, String lpszClass, String lpszWindow);
    int SendMessage(HWND hWnd, int msg, WPARAM wParam, String lParam);
    
    // 定义Windows消息常量
    int WM_SETTEXT = 0x000C;
    int BM_CLICK = 0x00F5;
}

// 在JavaFX的业务方法里调用
public void autoFillDelphiDialog(String windowTitle, String inputValue) {
    // 定位Delphi程序的主窗口
    HWND mainWindow = User32.INSTANCE.FindWindow(null, windowTitle);
    if (mainWindow == null) {
        System.out.println("找不到目标Delphi程序窗口");
        return;
    }

    // 找到对话框里的输入控件(替换成你用Spy++查到的类名/文本)
    HWND editControl = User32.INSTANCE.FindWindowEx(mainWindow, null, "TEdit", null);
    if (editControl != null) {
        // 给输入框填充值
        User32.INSTANCE.SendMessage(editControl, User32.WM_SETTEXT, null, inputValue);
    }

    // 找到确认按钮并模拟点击
    HWND confirmBtn = User32.INSTANCE.FindWindowEx(mainWindow, null, "TButton", "确定");
    if (confirmBtn != null) {
        User32.INSTANCE.SendMessage(confirmBtn, User32.BM_CLICK, null, null);
    }
}
  • 小提示:如果Delphi的对话框是模态的,你需要先触发它弹出(比如给主窗口发送消息触发显示对话框的事件),再定位控件;另外如果有多个同类型控件,可能需要通过控件的相对位置或者更精确的文本定位。

方案二:直接修改Delphi程序的内存值(绕过界面)

如果觉得模拟交互太繁琐,或者需要更高的效率,可以直接找到Delphi程序中存储该值的内存地址,用Java修改内存,缺点是复杂度高,需要一点逆向知识。

  • 具体步骤:

    1. 用Cheat Engine这类内存调试工具,定位到Delphi程序中存储目标值的内存地址。如果是全局变量,能找到静态基址+偏移量(重启程序后地址不变);如果是堆内存,每次重启地址会变,需要通过特征码扫描或者指针链定位。
    2. 用JNA调用Windows API的OpenProcess打开Delphi程序的进程,申请写内存的权限。
    3. 调用WriteProcessMemory把JavaFX生成的新值直接写入找到的内存地址。
  • 简化的Java代码示例:

public interface Kernel32 extends StdCallLibrary {
    Kernel32 INSTANCE = Native.load("kernel32", Kernel32.class);
    
    HANDLE OpenProcess(int dwDesiredAccess, boolean bInheritHandle, int dwProcessId);
    boolean WriteProcessMemory(HANDLE hProcess, Pointer lpBaseAddress, byte[] lpBuffer, int nSize, IntByReference lpNumberOfBytesWritten);
    boolean CloseHandle(HANDLE hObject);
}

// 写入内存的方法,processId是Delphi程序的进程ID,memoryAddress是找到的内存地址
public void writeToDelphiMemory(int processId, long memoryAddress, int valueToWrite) {
    // 打开进程,申请写内存和操作内存的权限
    int processAccess = 0x0020 | 0x0008; // PROCESS_VM_WRITE | PROCESS_VM_OPERATION
    HANDLE processHandle = Kernel32.INSTANCE.OpenProcess(processAccess, false, processId);
    if (processHandle == null) {
        System.out.println("无法打开Delphi进程,可能权限不足");
        return;
    }

    // 把要写入的int值转成字节数组
    byte[] valueBytes = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(valueToWrite).array();
    Pointer memoryPointer = new Pointer(memoryAddress);
    IntByReference bytesWritten = new IntByReference(0);

    // 执行内存写入
    boolean success = Kernel32.INSTANCE.WriteProcessMemory(processHandle, memoryPointer, valueBytes, valueBytes.length, bytesWritten);
    if (success) {
        System.out.println("内存修改成功,写入了" + bytesWritten.getValue() + "字节");
    } else {
        System.out.println("内存修改失败");
    }

    // 记得关闭进程句柄,避免资源泄漏
    Kernel32.INSTANCE.CloseHandle(processHandle);
}
  • 小提示:修改内存有风险,可能导致Delphi程序崩溃,建议先在测试环境反复验证;如果程序开启了ASLR(地址空间布局随机化),静态基址可能会变,需要重新定位。

两种方案各有优劣:方案一简单安全,适合大多数场景;方案二高效但需要逆向知识。你可以根据自己的实际情况选择。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 11:23:01