by Richard Russell, January 2012
In Windows, every User Interface (UI) thread must have a message pump (or message loop), the function of which is to serialise and dispatch incoming messages to their destination windows.
In BBC BASIC for Windows the message pump is provided by the Run Time Engine, and generally the programmer doesn't need to be aware of it. For anybody who may be interested, this is its C code:
while (GetMessage (&msg, NULL, 0, 0) != FALSE ) { if (((hwndMDIC == NULL) || !TranslateMDISysAccel (hwndMDIC, &msg)) && ((haccel == NULL) || !TranslateAccelerator (hwacc, haccel, &msg))) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } }
Very occasionally there may be a requirement to use a different message pump. For example, in order for keyboard navigation to work in a dialogue box, the message pump must include a call to the IsDialogMessage API.
Until very recently I believed that it was impossible to replace the existing BB4W message pump, and that therefore the only way to provide a different one was to start a new thread (each thread has its own message pump). This is the principal reason why the WINLIB2 library creates a new thread for every new dialogue box created.
However I have discovered that in fact there is a way of replacing the 'main' message pump, and the procedure listed below does exactly that:
DEF PROCnewmessagepump LOCAL K%, L%, M%, N%, O%, P%, S%, U%, code%, pass% DIM code% 130, L% -1 FOR pass% = 8 TO 10 STEP 2 P% = code% [OPT pass% .K% add esp,28 ret 16 .N% sub esp,28 push 0 : call "ReplyMessage" .U% push @hwnd% : call "IsWindow" : or eax,eax : jz K% mov eax,esp : push 0 : push 0 : push 0 : push eax call "GetMessage" : or eax,eax : jz K% push esp : push @haccel% : push @hwnd% : call "TranslateAccelerator" or eax,eax : jnz U% call "GetForegroundWindow" cmp eax,@hwnd% : jz S% push esp : push eax : call "IsDialogMessage" or eax,eax : jnz U% .S% push esp : call "TranslateMessage" push esp : call "DispatchMessage" jmps U% .M% cmp dword [esp+8],&502 : jz N% pop eax : push [^O%] : push eax : jmp "CallWindowProc" ] NEXT pass% SYS "GetWindowLong", @hwnd%, -4 TO O% SYS "SetWindowLong", @hwnd%, -4, M% SYS "SendMessage", @hwnd%, &502, 0, 0 SYS "SetWindowLong", @hwnd%, -4, O% SYS "SendMessage", @hwnd%, 0, 0, 0 ENDPROC