2011-08-06 6 views
0

Java 응용 프로그램의 Window 메시징을 사용하여 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

먼저 자바 개발자가 아니며 아래 코드를 테스트하지 않았지만 WM_COPYDATA를 이해하므로 질문에 대한 합리적인 답변을 얻을 수 있습니다. 수동으로 sun.misc.Unsafe class의 방법을 사용하여 이것을 읽을해야합니다 자바에서

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

:

WM_COPYDATA 메시지로 Windows에 의해 정의된다 COPYDATASTRUCT (즉,의 주소)에 대한 포인터를 보냅니다. 수동으로 직접 메모리 주소를 계산해야 할 것입니다.

dwData은 응용 프로그램이 자체적으로 사용할 수있는 정수 값입니다. lpData은 응용 프로그램이 전달하고자하는 데이터를 보유하고있는 버퍼에 대한 포인터입니다. cbDatalpData에 들어있는 버퍼의 바이트 수입니다.

Windows에서 ULONG_PTR은 32 비트 시스템에서는 4 바이트이고 64 비트 시스템에서는 8 바이트입니다. DWORD은 항상 4 바이트입니다. 포인터 (즉, 메모리 어드레스) 인 PVOID는 32 비트 시스템에서는 4 바이트이고, 64 비트 시스템에서는 8 바이트이다. 0, cbData가에서 4 오프셋과 lpData가에 dwData 여전히 0로 오프셋되는 64 비트 시스템 8. 옵셋 있지만 8 오프셋에 cbData이고, lpData시에 32 비트 시스템 dwData에 따라서

는 오프셋 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 생성자에 전달할 수 있어야합니다.더 복잡한 데이터 구조라면 COPYDATASTRUCT과 같은 방법으로 Unsafe 메서드를 사용하여 읽어야합니다.

+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 전송을 지원하며 커널이 로컬 대상이며 바로 가기임을 인식하기 때문에 IPC 솔루션으로 올바르게 작동합니다 불필요한 TCP/IP 스택 처리.

당신은 소스 코드에 액세스 할 수없는 C# 프로그램을 제어하려고한다고 언급했습니다. 이러한 유형의 것을 흔히 화면 스크래핑이라고하며 Managed Spy 또는 Spy ++를 사용하는 C++ 코드를 사용하여 Java 응용 프로그램의 중개자 역할을하는 간단한 C# 응용 프로그램을 작성하는 것이 좋습니다.

+0

ZeroMQ를 제안 해 주셔서 감사합니다. 불행히도 우리는이 솔루션을 사용할 수 없습니다. C# 애플리케이션은 다른 회사에서 제공하기 때문에 변경할 수 없습니다. – Developer