使用窗口消息传递在 JAVA 和 C# 之间进行应用程序间通信

发布于 2024-11-28 09:28:08 字数 2765 浏览 1 评论 0原文

我需要使用来自 Java 应用程序的窗口消息传递与 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();
        }

    }
}

请帮忙。提前致谢。

I need to communicate with C# application using Window messaging from Java application. From my application I register for messages used for communicating. I am able to successfully get the window handle of the C# application and register messages. C# application responds to the messages by sending WM_COPYDATA response messages.
I can get to a point where WM_COPYDATA is received. But I am not sure how to extract the message content from the response message.

Really helps if I can get a sample code which reads content from WM_COPYDATA message from java application using jniwrap and winpack libraries. Will be more helpful if the content of lParam is of Structure type.

I had to edit the code to remove sensitive data

The following code gets the other application's window handle by its window name, registers for request and response messages and then sends the request message with empty content.

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();
}

This is the custom window procedure, that will be substituted in place of the native proc for my application's window

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();
        }

    }
}

Please help. Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

静水深流 2024-12-05 09:28:08

首先,我不是 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 中,ULONG_PTR 在 32 位系统上为 4 个字节,在 64 位系统上为 8 个字节。 DWORD 始终为 4 个字节。 PVOID是一个指针(即内存地址),在32位系统上为4字节,在64位系统上为8字节。

因此,在 32 位系统上,dwData 位于偏移量 0,cbData 位于偏移量 4,lpData 位于偏移量 8。在 64 位系统上 < code>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 所做的那样

First off I'm not a Java developer and I haven't tested the code below, but I do understand WM_COPYDATA so I can make a reasonable answer to your question.

The WM_COPYDATA message sends a pointer to (that is the address of a) COPYDATASTRUCT which is defined by Windows as:

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

From Java you will have to read this manually using the methods in the sun.misc.Unsafe class. By manually I mean you will have to calculate the memory addresses yourself.

dwData is an integer value the application can use for itself. lpData is a pointer to a buffer holding data that the application wanted to pass. cbData is the number of bytes in the buffer that lpData contains.

In Windows a ULONG_PTR is 4 bytes on a 32 bit system and 8 bytes on a 64 bit system. A DWORD is 4 bytes always. A PVOID, which is a pointer (i.e. a memory address) is 4 bytes on a 32 bit system and 8 bytes on a 64 bit system.

So on a 32 bit system dwData is at offset 0, cbData at offset 4, and lpData at offset 8. On a 64 bit system dwData is still at offset 0, but cbData is at offset 8, and lpData at offset 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);

Once your done data will contain the raw data that the application passed in, which is in your case the license. If the license is a string you should be able to pass the byte array to the String constructor. If it is a more complex data structure you will have to read it in using the Unsafe methods just like we did for the COPYDATASTRUCT

ぶ宁プ宁ぶ 2024-12-05 09:28:08

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

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

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

There is a much easier way to send messages between a Java application and a C# application. Use ZeroMQ messages using the TCP transport tcp://127.0.0.1:portnum The ZeroMQ guide http://zguide.zeromq.org/page:all shows dozens of examples of communication patterns that yu can implement with only a few lines of code.

Some people don't use it because it does not support the IPC transport on Windows, but it does support the TCP transport and that works just fine as an IPC solution because the kernel recognizes that it is a local destination and shortcuts the unneeded TCP/IP stack processing.

You mentioned that you are trying to control a C# program for which you have no access to the source code. This type of thing is often called screen-scraping, and you might be better off by writing a simple C# application using Managed Spy or some C++ code using Spy++ to act as an intermediary for your Java application.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文