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 アプリケーションと 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++ を使用して Java アプリケーションの仲介役として機能する C++ コードを作成することをお勧めします。

于 2011-08-07T00:56:45.597 に答える
2

まず、私は Java 開発者ではなく、以下のコードをテストしていませんが、WM_COPYDATA を理解しているので、あなたの質問に対して妥当な回答をすることができます。

WM_COPYDATAメッセージは、Windows で次のように定義されているCOPYDATASTRUCT (のアドレス) へのポインターを送信します。

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

Java からは、 sun.misc.Unsafe クラスのメソッドを使用してこれを手動で読み取る必要があります。手動とは、メモリアドレスを自分で計算する必要があることを意味します。

dwDataアプリケーションがそれ自体に使用できる整数値です。 lpDataアプリケーションが渡したいデータを保持しているバッファへのポインタです。 cbData含まれているバッファー内のバイト数ですlpData

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 に答える