0

I am trying to send a String from Java (First app) to c++ (the Second app with a message-only window).

So firstly, what I tried is this: I adapted this example into my code and got this on the java side

    STRMSG msg = new STRMSG();
    msg.message = "test";
    //msg.write(); // Idk exactly why because i thought JNA does this before every call. Works the same without

    cds = new COPYDATASTRUCT();
    cds.dwData = new ULONG_PTR(UniqueWindowMessageID);
    cds.cbData = msg.size();
    cds.lpData = msg.getPointer();
    cds.write(); // But here it is somehow needed because otherwise the message will not arrive.

    JNA.USER32.INSTANCE.SendMessage(
        msgOnlyWnd, WinUser.WM_COPYDATA,
        null,
        new LPARAM(Pointer.nativeValue(cds.getPointer()))
    );

Oh, and STRMSG looks like this (also adapted from the example):

public class STRMSG extends Structure {

    public STRMSG() {
        super();
    }

    public STRMSG(Pointer p) {
        super(p);
        read();
    }

    public String message;

    protected List<String> getFieldOrder() {
        return Arrays.asList("message");
    }
}

On the c++ side, I got my message-only window, and I can catch the WM_COPYDATA message successfully.

But somehow, my String value is empty here:

    case WM_COPYDATA: {
        PCOPYDATASTRUCT cds = (PCOPYDATASTRUCT)lParam;
        if (cds->dwData == UniqueWindowMessageID) { // <- works 
            STRMSG* msgStruct = (STRMSG*)cds->lpData; // <- The message struct is corrupt i guess

            cout << msgStruct->message << endl; // Will just endl in the console
        }
        break;
    }

This is the struct on the c++ side:

const struct STRMSG {
    string message;
};

Besides this attempt, I also tried to adapt my struct so it contains a BYTE* (byte[]) and the size so I can create a String out of the bytes and the size using this: (source)

std::string s(reinterpret_cast<char const*>(inputParam), lengthParam);

But my struct isn't that what it should be in any way. So the data is somehow faulty, and IDK what I am doing wrong here.

Any help is appreciated.

EDIT: I also looked at the data while debugging. I didn't get anything:

enter image description here

EDIT2:

After the comment Remy my COPYDATASTRUCT looks like this:

    byte[] msg = "test".getBytes();
    cds = new COPYDATASTRUCT();
    cds.dwData = new ULONG_PTR(UniqueWindowMessageID);
    cds.cbData = msg.length;
    cds.lpData = msg // how??
    cds.write();

But how should I map the cds.lpData to the byte[]?

Nur1
  • 418
  • 4
  • 11
  • 2
    We already covered this in your [previous question](https://stackoverflow.com/q/68696561/65863). Your Java code is making the same mistake your C++ code was making. You are sending only the `STRMSG` struct, but not the string data it points to. And now you are compounding the problem because the Java code is sending Java's `string` type which is not compatible with C++'s `std::string` type. There is no reason to have the `STRMSG` struct in this code at all, so get rid of it. Have the Java code encode the `string` to a `byte[]` array and then `WM_COPYDATA` can send those bytes to C++ – Remy Lebeau Aug 15 '21 at 19:23
  • Oh my god... your're right. Will try. I was blinded by the examples of JNA. – Nur1 Aug 15 '21 at 19:34
  • @RemyLebeau Ok so basically after removing the Structs completely. How do I map the `cds.lpData` (which is a `Pointer`) to the `byte[]`? (I also updated the question) – Nur1 Aug 15 '21 at 20:24
  • [Converting String to Pointer for JNA](https://stackoverflow.com/questions/10158582/) – Remy Lebeau Aug 15 '21 at 20:37
  • With regard to your comment questions: JNA does auto-write Structures when they are passed as arguments to native methods. But you never pass that. So you are allocating native memory for `STRMSG` and obtaining a pointer to it, but never writing your String to it. Which you would have lost the allocation to anyway, so it wouldn't work even with the write. – Daniel Widdis Aug 15 '21 at 22:28

1 Answers1

0

Ok, basically, after the help of Remy Lebeau (as always), I managed to include the NativeString Class in my project, which allows me to get the Pointer of the NativeString and use it directly in my COPYDATASTRUCT.

I had to inline some method contents in my own NativeString Class because some of them were also not visible.

Anyway, here is the snippet I used to build my COPYDATASTRUCT the sending part didn't change.

NativeString ns = new NativeString("Hello String", true); //true so its a wide string
cds = new COPYDATASTRUCT();
cds.dwData = new ULONG_PTR(UniqueWindowMessageID);
cds.cbData = ns.length()*2; //Without *2 the text will be only the half
cds.lpData = ns.getPointer();
cds.write();

And this is how I handle the received WM_COPYDATA message on the C++ side:

case WM_COPYDATA: {
    PCOPYDATASTRUCT cds = (PCOPYDATASTRUCT)lParam;
    if (cds->dwData == UniqueWindowMessageID) {
        wchar_t* msg = (wchar_t*)cds->lpData;
        wcout << msg << endl;
    }
    break;
}

Thanks again @Remy Lebeau

Nur1
  • 418
  • 4
  • 11