0

我需要使用来自 Java 应用程序的 Window 消息传递与 C# 应用程序通信。从我的应用程序中,我注册了用于通信的消息。我能够成功获取 C# 应用程序的窗口句柄并注册消息。C# 应用程序通过发送 WM_COPYDATA 响应消息来响应消息。我可以达到收到 WM_COPYDATA 的程度。但我不确定如何从响应消息中提取消息内容。

如果我能获得一个示例代码,它使用 jniwrap 和 winpack 库从 java 应用程序的 WM_COPYDATA 消息中读取内容,这真的很有帮助。如果 lParam 的内容是 Structure 类型会更有帮助。

我必须编辑代码以删除敏感数据

以下代码通过窗口名称获取其他应用程序的窗口句柄,注册请求和响应消息,然后发送内容为空的请求消息。

private Library user32; 
private long appHandle; 

public void sendRequest() {
    long requestMsgId = (int)this.registerWindowMessage("WM_TBD_SN_REQEST");
    long responseMsgId = (int)this.registerWindowMessage("WM_TBD_SN_RESPONSE");

    long tbdHandle = findWindow(null, "TestApp");

    this.sendWindowsMessage(new Handle(tbdHandle), new Int(requestMsgId), new Handle(this.appHandle), new Pointer.Void());

}

public long sendWindowsMessage(final Parameter... args) {
    final Function sendMessage = this.user32.getFunction("SendMessageA");
    LongInt longInt = new LongInt();
    sendMessage.invoke(longInt, args);
    return longInt.getValue();
}

public long findWindow(final String classname, final String windowName) {
    final Function findWindow = this.user32.getFunction("FindWindowA");
    Parameter cName = null;
    if (classname == null || classname.equals("")) {
        cName = new Pointer.Void();
    }
    else {
        cName = new AnsiString(classname);
    }
    LongInt longInt = new LongInt();
    findWindow.invoke(longInt, cName, new AnsiString(windowName));
    return longInt.getValue();
}

public long registerWindowMessage(String message) {
    final Function findWindow = this.user32.getFunction("RegisterWindowMessageA");
    LongInt longInt = new LongInt();
    findWindow.invoke(longInt, new AnsiString(message));
    return longInt.getValue();
}

这是自定义窗口过程,它将代替我的应用程序窗口的本机过程

public class MyWindowProc extends WindowProc {

    @Override
    public void callback() {

        if (this._msg.getValue() == Msg.WM_COPYDATA) {
//      I can get to this point, but not sure how I can get the information from the message          
//                The WM_TBD_SN_RESPONSE structure consists of four fields
//                1.  hWnd Field --- window handle of the calling application...
//                2.  msg Field --- WM_COPYDATA message code
//                3.  wData Field --- TDB application's window handle
//                4.  pData Field --- contains a CopyDataStruct
//                      CopyDataStruct.pData – contains the Serial Number ----> how to extract this?
//                      CopyDataStruct.dwData – contains the message code for WM_TBD_SN_RESPONSE (this should match responseMsgId)

        }
        else {
            super.callback();
        }

    }
}

请帮忙。提前致谢。

4

2 回答 2

2

首先,我不是 Java 开发人员,也没有测试过下面的代码,但我确实了解 WM_COPYDATA,因此我可以对您的问题做出合理的回答。

WM_COPYDATA消息发送一个指向(即 a 的地址)COPYDATASTRUCT的指针,该指针由 Windows 定义为:

struct COPYDATASTRUCT {
  ULONG_PTR dwData;
  DWORD     cbData;
  PVOID     lpData;
}

在 Java 中,您必须使用sun.misc.Unsafe 类中的方法手动阅读此内容。手动我的意思是你必须自己计算内存地址。

dwData是应用程序可以为自己使用的整数值。 lpData是指向保存应用程序想要传递的数据的缓冲区的指针。 cbDatalpData包含的缓冲区中的字节数。

在 Windows 中,aULONG_PTR在 32 位系统上是 4 个字节,在 64 位系统上是 8 个字节。ADWORD总是 4 个字节。PVOID 是一个指针(即内存地址),在 32 位系统上为 4 个字节,在 64 位系统上为 8 个字节。

因此,在 32 位系统dwData上,偏移量为 0,cbData偏移量为 4,lpData偏移量为 8。在 64 位系统dwData上,偏移量仍为 0,但cbData偏移量为 8,lpData偏移量为 16。

import sun.misc;

final int dwDataOffset = 0;
final int cbDataOffset = 4;  // Change to 8 for 64 bit
final int lpDataOffset = 8;  // Change to 16 for 64 bit

int cpDataAddr = this._pData.getValue();         // This will return the address of the struct (I assume this syntax is correct) - change to long for 64 bit
int messageCode= Unsafe.getInt(cpDataAddr+dwDataOffset);  // Change to getLong for 64 bit
int dataSize = Unsafe.getInt(cbDataAddr+cbDataOffset);
int dataAddress = Unsafe.GetInt(cbDataAddr+lpDataOffset); // Change to getLong for 64 bit

// Create a buffer to hold the data from lpData
byte[] data = new byte[dataSize];
for (int i = 0; i < dataSize; i++)
   data[i] = Unsafe.getByte(dataAddress+i);

一旦您完成的数据将包含应用程序传入的原始数据,在您的情况下就是许可证。如果许可证是一个字符串,您应该能够将字节数组传递给 String 构造函数。如果它是一个更复杂的数据结构,您将不得不Unsafe像我们为COPYDATASTRUCT

于 2011-08-06T23:01:58.583 回答
2

在 Java 应用程序和 C# 应用程序之间发送消息有一种更简单的方法。使用 TCP 传输 tcp://127.0.0.1:portnum 使用 ZeroMQ 消息 ZeroMQ 指南http://zguide.zeromq.org/page:all显示了几十个通信模式的示例,您只需几行代码即可实现.

有些人不使用它,因为它不支持 Windows 上的 IPC 传输,但它确实支持 TCP 传输,并且作为 IPC 解决方案工作得很好,因为内核认识到它是一个本地目的地并快捷方式不需要的 TCP/ IP堆栈处理。

您提到您正在尝试控制您无法访问其源代码的 C# 程序。这种类型的事情通常称为屏幕抓取,您最好使用托管间谍编写一个简单的 C# 应用程序,或者使用 Spy++ 编写一些 C++ 代码作为 Java 应用程序的中介。

于 2011-08-07T00:56:45.597 回答