RegisterWindowMessage and SendMessage

Hey there! Some background so you can better answer my question:
I’m a beginner in Julia (with a long background in hobbyist coding in various languages).
I set myself to learn the language by creating an automation module, instead of the usual helloworld/AOC way.

How ever, I ran in some problems in a couple of very basic API call’s and I’m too green to realise why.
Here are the snippets, SendMessage times out on every handle I try (Error 258). Which in my basic understanding means that some of the arguments are wrong, but I can’t see which and why.

const HANDLE                    = Ptr{Cvoid}
const LPSTR                     = Vector{UInt8}

function RegisterWindowMessage(message::String)
    msg = Vector{UInt8}(message)
    return ccall((:RegisterWindowMessageA, "user32"), stdcall, Cint, (Ptr{Vector{UInt8}},), Ref(msg) )
end

function SendWindowMessage(handle::HANDLE, msg::Cint)
    buffer = LPSTR(undef, 512)
    retval = ccall((:SendMessageA, "user32"), stdcall, Cint, (HANDLE, Cint, Cint, Ptr{UInt8}), handle, msg, sizeof(buffer), buffer)
    if retval == 0     
        return "NA"
    else
        buffer[end] = 0
        return String(unsafe_string(pointer(buffer),retval))
    end
end

msg = RegisterWindowMessage("WM_GETCONTROLNAME")
SendWindowMessage(HANDLE(app.HWND), msg))

Sorry if the snippets are formatted wrong, couldn’t find codeblock option :frowning:

Hello, I’m not exactly sure what your code should achieve and what desired output is, but I can help your from Julia side.

The code you provided isn’t self contained so I modified it a bit:

const HANDLE = Ptr{Cvoid}
const LPSTR = Vector{UInt8}

function RegisterWindowMessage(message::String)
    msg = Vector{UInt8}(message)
    return ccall((:RegisterWindowMessageA, "user32"), stdcall, Cint, (Ptr{Vector{UInt8}},), Ref(msg) )
end

function SendWindowMessage(handle::HANDLE, msg::Cint)
    buffer = LPSTR(undef, 512)
    retval = ccall((:SendMessageA, "user32"), stdcall, Cint, (HANDLE, Cint, Cint, Ptr{UInt8}), handle, msg, sizeof(buffer), buffer)
    if retval == 0     
        return "NA"
    else
        buffer[end] = 0
        return String(unsafe_string(pointer(buffer),retval))
    end
end

function main()
    hwnd = Ptr{Int32}(Int64(0xffff))

    msg = RegisterWindowMessage("WM_GETCONTROLNAME")
    @show msg

    SendWindowMessage(HANDLE(hwnd), msg)
end

This is the output I get:

julia> main()
msg = 49822
"\0"

I can give you working example with SendMessageA, but I haven’t used RegisterWindowMessageA before, so I don’t know about that.

Sorry about that, I really can’t give a working example without being able to pick a process from your computer.
I’m also a bit uncertain about which part of the code you need clarification on, so I’m going to explain the full process.

I pick a running process (ie. calculator.exe) and list all the childwindows it has, then I’ll select on of them (ie. “+”-button) and save the handle of that window.
I register WM_CONTROLNAME message, and receive the message id from the API call, which I use with “SendMessageA” as the msg.

The “SendMessageA” call should cause WinAPI to write the child window’s name to the provided buffer.

The same way this snippet works ( You need to provide a hwnd of type PTR{Cvoid} )

function GetWindowText(handle::HANDLE)
    name = LPSTR(undef, 256)
    length = ccall((:GetWindowTextA, "user32"), stdcall, Cint, (HANDLE, Ptr{UInt8}, Cint), handle, name, sizeof(name))
    if length == 0
        return ""
    else
        name[end] = 0
        name_str = String(unsafe_string(pointer(name),length))
    end
    return name_str
end

I’d love to have a look at your working SendMessageA example, even if it’s about a different message.

Sorry, I still can’t figure out how to fix your code. Have you tried implementing this in another language?

Anyway, I extracted an example from my code:

const WM_CLOSE = 0x000010

function findwindowex(class::AbstractString, child::Ptr{Int32})
    hwnd = ccall((:FindWindowExA, "user32"), Ptr{Int32}, 
                (Ptr{Int32}, Ptr{Int32}, Cstring, Cstring),
                Ptr{Int32}(), child, class, C_NULL)
    return hwnd
end

function sendmessage(hwnd::Ptr{Int32}, msg::UInt32, wparam::Ptr{Int32}, lparam::Ptr{Int32})
    ccall((:SendMessageA, "user32"), Int32, 
            (Ptr{Int32}, UInt32, Ptr{Int32}, Ptr{Int32}),
            hwnd, msg, wparam, lparam)
end

function main()
    hwnd = findwindowex("Notepad", Ptr{Int32}())
    sendmessage(hwnd, WM_CLOSE, Ptr{Int32}(), Ptr{Int32}())
end

This should close Notepad.