Callback to WinAPI

Hi,
I’m trying to rewrite the following code from
https://sjohannes.wordpress.com/2012/03/23/win32-python-getting-all-window-titles/
from Python to Julia

import ctypes

EnumWindows = ctypes.windll.user32.EnumWindows
EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))
GetWindowText = ctypes.windll.user32.GetWindowTextW
GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
IsWindowVisible = ctypes.windll.user32.IsWindowVisible

titles = []
def foreach_window(hwnd, lParam):
    if IsWindowVisible(hwnd):
        length = GetWindowTextLength(hwnd)
        buff = ctypes.create_unicode_buffer(length + 1)
        GetWindowText(hwnd, buff, length + 1)
        titles.append(buff.value)
    return True
EnumWindows(EnumWindowsProc(foreach_window), 0)
print(titles)

The code lists titles of all currently visible windows.
I’m struggling with how to specify the stdcall calling convention for the callback function. In a simple ccall one can specify the calling convention

tickCount = ccall( (:GetTickCount, "kernel32"), stdcall, UInt32, () )

but for callback, the function pointer created by cfunction has no calling convention property. Is such functionality available?

Cheers,
Petr

No, calling convention specification is not supported for cfunction. But calling conventions are unified on 64-bit Windows so this won’t matter unless you are on 32-bit Windows.

see also: stdcall with cfunction? · Issue #5613 · JuliaLang/julia · GitHub

@ihnorton Thank you for the explanation. Still my attempt crashes julia:

function foreach_window{T}(hwnd::T, lParam::T)
   return convert(Cint, 1)::Cint
end
const windowEnumCallback = cfunction(foreach_window, Cint, (Ref{Cint}, Ref{Cint}))
ccall((:EnumWindows, "User32"), stdcall, Cint, (Ptr{Void}, Ptr{Cint}), windowEnumCallback, Ref{Cint}(0))

the signatures are

BOOL WINAPI EnumWindows(
  _In_ WNDENUMPROC lpEnumFunc,
  _In_ LPARAM      lParam
);
BOOL CALLBACK EnumWindowsProc(
  _In_ HWND   hwnd,
  _In_ LPARAM lParam
);

I’m also interested.

Please review the C interface section of the manual. There are a few problems, such as:

  • the cfunction signature must match the function declaration
  • Ref is Julia-owned memory, so it doesn’t make sense in the cfunction signature
  • foreach_window should not be parameterized by type ({T})
  • passing a Ref{Cint}(0) to EnumWindows doesn’t make sense – it’s just a long.

The code below works; hopefully enough to get you going:

typealias HANDLE Ptr{Void}
typealias LPARAM Clong

handles = HANDLE[]

function foreach_window(hwnd::HANDLE, lParam::LPARAM)
    push!(handles, hwnd)
    return convert(Cint, 1)::Cint
end
const windowEnumCallback = cfunction(foreach_window, Cint, (HANDLE, LPARAM))

ccall((:EnumWindows, "User32"), stdcall, Cint, (Ptr{Void}, LPARAM), windowEnumCallback, 0)

(I have some old demo code here that might be helpful – although I have no idea if it works at all in current Julia)

Works great, thank you Isaiah. Making clarification in manual.