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

标签 c# java java-native-interface wm-copydata

我需要使用 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();
}

这是自定义窗口过程,它将取代我的应用程序窗口的 native 过程

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

    }
}

请帮忙。提前致谢。

最佳答案

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

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

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

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

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 位系统上位系统 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

所做的那样

关于c# - 使用窗口消息传递在 JAVA 和 C# 之间进行应用程序间通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6968325/

相关文章:

c# - 使用 linq 从集合中删除项目

c# - 为什么VS要求不使用内联代码?

java - 应用程序 C++/Java 依赖

java - C 错误的 JNI 访问对象数组

c# - 应该同时使用 AppDomain.UnhandledException 和 Application.DispatcherUnhandledException 吗?

c# - 在 ASP .NET Core Web API Controller 中注入(inject) Serilog 的 ILogger 接口(interface)

java - 验证模拟对象中的对象被传递到 Mockito 中的参数

java - Hibernate 批量插入内存泄漏

java - 如何在java中用 "XXXXX"替换字符串值?

Java JNI 和 future 的任务