2011-08-06 25 views
0

Javaアプリケーションからのウィンドウメッセージを使用してC#アプリケーションと通信する必要があります。私のアプリケーションからは、通信に使用するメッセージを登録します。私は正常にC#アプリケーションのウィンドウハンドルを取得し、メッセージを登録することができます。 C#アプリケーションは、WM_COPYDATA応答メッセージを送信してメッセージに応答します。 私はWM_COPYDATAが受信されるポイントに到達できます。しかし、私はどのように応答メッセージからメッセージの内容を抽出するか分からない。ウィンドウメッセージングを使用したJAVAとC#間のアプリケーション間通信

jniwrapとwinpackライブラリを使用して、JavaアプリケーションからWM_COPYDATAメッセージのコンテンツを読み込むサンプルコードを取得できれば本当に役に立ちます。 lParamの内容が構造型の場合に役立ちます。

私は、次のコードは、そのウィンドウ名で、他のアプリケーションのウィンドウハンドルを取得する要求メッセージと応答メッセージのために登録すると、空のコンテンツで要求メッセージを送信する機密データに

を削除するためにコードを編集する必要がありました。

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

    } 
} 

のネイティブPROCの代わりに置換されるカスタムウィンドウプロシージャ、です。前もって感謝します。

+1

最初に試したことをお見せできますか? –

+0

質問にコードを追加しました。ありがとうございました。 – Developer

答えて

2

私はJava開発者ではありません。以下のコードはテストしていませんが、WM_COPYDATAを理解していますので、あなたの質問に合理的な回答をすることができます。手動sun.misc.Unsafe classのメソッドを使用してこれを読んでする必要がありますJavaから

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

WM_COPYDATAメッセージは、としてWindowsによって定義されるCOPYDATASTRUCT(つまり、のアドレスである)へのポインタを送信します。手動では、自分でメモリアドレスを計算する必要があることを意味します。

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

Windowsでは、ULONG_PTRは、32ビットシステムでは4バイト、64ビットシステムでは8バイトです。 DWORDは常に4バイトです。ポインタ(すなわちメモリアドレス)であるPVOIDは、32ビットシステムでは4バイトであり、64ビットシステムでは8バイトである。

だから32ビットシステムdwDataにATでcbData 4をオフセット、及びでlpDataは、64ビットシステムdwData 8.オフセット、オフセット0さはオフセット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

+0

ありがとうございます。私はこれを試してみましょう。これを行う簡単な方法はありませんか? – Developer

+0

それはうまくいった。ありがとうございました! – Developer

2

JavaアプリケーションとC#アプリケーション間でメッセージを送信する方がずっと簡単です。 TCPトランスポートtcp://127.0.0.1:portnumを使用したZeroMQメッセージの使用ZeroMQガイドhttp://zguide.zeromq.org/page:allには、ほんの数行のコードで実装できる数多くの通信パターンの例が示されています。

WindowsでのIPCトランスポートをサポートしていないため、TCPトランスポートをサポートしていて、カーネルがローカルの宛先でありショートカットであることを認識しているため、不要なTCP/IPスタック処理。

ソースコードにアクセスできないC#プログラムを制御しようとしていることに言及しました。この種のものはスクリーンスクレイピングと呼ばれることが多く、Managed SpyやSpy ++を使ったC++コードを使って簡単なC#アプリケーションを作成して、Javaアプリケーションの仲介役を果たす方が良いかもしれません。

+0

ZeroMQを提案していただきありがとうございます。残念ながら、C#アプリケーションは別の会社によって提供されており、変更することはできませんので、このソリューションを使用することはできません。 – Developer

関連する問題