flat assembler
Message board for the users of flat assembler.

Index > Windows > How to keep one window on top of another

Author
Thread Post new topic Reply to topic
DergMoney



Joined: 29 Apr 2015
Posts: 34
DergMoney 25 May 2015, 15:41
Hi,

I create a small window. I want to keep this on top (z-order) of another *particular* window not created by me. I am not trying to create a WS_EX_TOPMOST window, i.e. I don't want my window to be on top of *all* others, just one in particular.

I am able to get the handle to the window I want to be on top of.

How can I ensure mine stays on top of it?

Thanks
Post 25 May 2015, 15:41
View user's profile Send private message Reply with quote
cod3b453



Joined: 25 Aug 2004
Posts: 618
cod3b453 25 May 2015, 18:09
Could subclass the other window and look for WM_SETFOCUS/ACTIVATE or similar to trigger your window to force it on top Question
Post 25 May 2015, 18:09
View user's profile Send private message Reply with quote
DergMoney



Joined: 29 Apr 2015
Posts: 34
DergMoney 25 May 2015, 18:15
Thanks for the reply,

Can I subclass a window that wasn't created by me (i.e. a different application)? If 'yes' could you give me an example?


Last edited by DergMoney on 25 May 2015, 18:19; edited 1 time in total
Post 25 May 2015, 18:15
View user's profile Send private message Reply with quote
DergMoney



Joined: 29 Apr 2015
Posts: 34
DergMoney 25 May 2015, 18:17
I was thinking that I'd have to set up a hook using WH_CALLWNDPROCRET but it would need to be running constantly and afaik that is hard on resources
Post 25 May 2015, 18:17
View user's profile Send private message Reply with quote
El Tangas



Joined: 11 Oct 2003
Posts: 120
Location: Sunset Empire
El Tangas 25 May 2015, 18:23
I suppose you can use the SetWindowLong function, since you have the handle to the target window, and use it to intercept the target WindowProc.

Or maybe you can create your window as owned by the target window, so it will always stay on top of it (but it will be destroyed if the target is closed).

Never actually tried to do any of this stuff, but in theory, should work.
Post 25 May 2015, 18:23
View user's profile Send private message Reply with quote
DergMoney



Joined: 29 Apr 2015
Posts: 34
DergMoney 25 May 2015, 18:24
Ah! SetWindowLong() looks like it might do the trick, thanks cod3b453 and El Tangas Wink
Post 25 May 2015, 18:24
View user's profile Send private message Reply with quote
DergMoney



Joined: 29 Apr 2015
Posts: 34
DergMoney 25 May 2015, 19:10
Dang, I'm getting an 'Access is denied" error.

The error is being thrown at

invoke SetWindowLong, [hWndPS], GWL_WNDPROC, psWndProc


The full code is below, in this instance I'm trying it with the windows calculator...

Code:
format PE GUI 4.0
entry start

include "%fasminc%\win32a.inc"

section '.code' code readable executable

    start:
        invoke  GetModuleHandle, 0
        mov         [wc.hInstance], eax
        invoke  LoadIcon, 0, IDI_APPLICATION
        mov         [wc.hIcon], eax
        invoke  LoadCursor, 0, IDC_ARROW
        mov         [wc.hCursor], eax
        invoke  RegisterClass, wc
        or          eax,eax
        jz          error
        invoke  CreateWindowEx, NULL, ClassMain, AppName, WS_OVERLAPPEDWINDOW or WS_VISIBLE, 100, 100, 600, 200, NULL, NULL, [wc.hInstance], NULL
        test    eax,eax
        jz          error
        mov     [hWndMain], eax
        invoke  EnumWindows, EnumWindowsProc, 0

    msgLoop:
        invoke  GetMessage, msg, NULL, 0, 0
        or          eax, eax
        jz          endLoop
        invoke  TranslateMessage, msg
        invoke  DispatchMessage, msg
        jmp         msgLoop
    error:
        invoke  MessageBox, NULL, errorStr, NULL, MB_ICONERROR + MB_OK
    endLoop:
        invoke  ExitProcess, [msg.wParam]

proc WndProc hwnd, wmsg, wparam, lparam
        push    ebx esi edi
        cmp     [wmsg], WM_DESTROY
        je      .wmDestroy
    .defWndProc:
        invoke  DefWindowProc, [hwnd], [wmsg], [wparam], [lparam]
        jmp     .finish
    .wmDestroy:
        invoke  SetWindowLong, [hWndPS], GWL_WNDPROC, [psWndProcHnd]
        invoke  PostQuitMessage, 0
        xor         eax, eax
    .finish:
        pop     edi esi ebx
        ret
endp

proc EnumWindowsProc hwnd, lparam
        push    ebx esi edi
        invoke  GetWindowText, [hwnd], strBuff, 1000
        or      eax, eax
        jz      .retTrue
        invoke  lstrlen, strBuff
        mov     ecx, eax
        mov     al, "C"
        mov     edi, strBuff
        repne   scasb
        jne     .retTrue
        mov     esi, searchStr + 1
        invoke  lstrlen, searchStr
        dec     eax
        mov     ecx, eax
        rep     cmpsb
        jne     .retTrue
        invoke  GetClassName, [hwnd], strBuff, 1000
        invoke  lstrlen, psClass
        mov     ecx, eax
        mov     esi, psClass
        mov     edi, strBuff
        rep     cmpsb
        jne     .retTrue

        ; have found the calculator window

        push    [hwnd]
        pop     [hWndPS]
        invoke  SetWindowLong, [hWndPS], GWL_WNDPROC, psWndProc
        or      eax, eax
        jnz     @f
        call    showError
        jmp     .retFalse
    @@:
        mov     [psWndProcHnd], eax         ; save address of the calculator WndProc

    .retFalse:
        mov     eax, FALSE
        jmp     .finish
    .retTrue:
        mov     eax, TRUE
    .finish:
        pop     edi esi ebx
        ret
endp        

proc psWndProc, hwnd, wmsg, wparam, lparam
        
        push    ebx edi esi
        invoke  CallWindowProc, [psWndProcHnd], [hWndPS], [msg], [wparam], [lparam]
        pop     esi edi ebx
        ret
endp


showError: 
        pushad 
        invoke  GetLastError 
        invoke  FormatMessage, FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, eax, LANG_NEUTRAL, errStrBuff, 0, NULL
        invoke  MessageBox, HWND_DESKTOP, [errStrBuff], NULL, MB_ICONERROR or MB_OK 
        popad 
        ret 

section '.data' data readable writeable
    ClassMain   db "WinClass", 00
    AppName     db "My App", 00
    errorStr    db "oops!", 00
    hWndMain    dd ?
    hWndPS      dd ?
    psWndProcHnd dd ?
    titlePS     db 1002 dup ?
    strBuff     db 1002 dup ?
    wordBuff    db 40 dup ?
    space       db " ", 00
    errStrBuff  dd ?
    wc          WNDCLASS CS_HREDRAW or CS_VREDRAW, WndProc, 0, 0, NULL, NULL, NULL, COLOR_BTNFACE + 1, NULL, ClassMain
    msg         MSG
    searchStr   db "Calculator", 00
    rect        RECT
    numStr      db "%i", 00
    psClass     db "CalcFrame", 00

section '.idata' import data readable writeable 
library kernel32,'KERNEL32.DLL',\ 
        user32,  'USER32.DLL',\ 
        gdi32,   'GDI32.DLL',\ 
        comdlg32,'COMDLG32.DLL',\ 
        advapi32,'ADVAPI32.DLL',\ 
        comctl32,'COMCTL32.DLL',\
        msvcrt, 'msvcrt.dll'

include '%fasminc%\api\Kernel32.inc' 
include '%fasminc%\api\User32.inc' 
include '%fasminc%\api\Gdi32.inc' 
include '%fasminc%\api\Comdlg32.inc' 
include '%fasminc%\api\Advapi32.inc' 
include '%fasminc%\api\Comctl32.inc'
import msvcrt,\ 
        sprintf,'sprintf'
    
Post 25 May 2015, 19:10
View user's profile Send private message Reply with quote
El Tangas



Joined: 11 Oct 2003
Posts: 120
Location: Sunset Empire
El Tangas 25 May 2015, 19:17
It's never as easy as we would like Sad

Quote:
An application can subclass a system class, but should not subclass a window class created by another process.


Quote:

GWL_WNDPROC -4

Sets a new address for the window procedure.

You cannot change this attribute if the window does not belong to the same process as the calling thread


I'm sure there must be a way, so maybe someone more knowledgeable will have the answer.
Post 25 May 2015, 19:17
View user's profile Send private message Reply with quote
DergMoney



Joined: 29 Apr 2015
Posts: 34
DergMoney 25 May 2015, 19:28
El Tangas wrote:
Or maybe you can create your window as owned by the target window, so it will always stay on top of it (but it will be destroyed if the target is closed).


Haven't tried this yet. I'll let you know how it goes Wink

Thanks for your interest.
Post 25 May 2015, 19:28
View user's profile Send private message Reply with quote
DergMoney



Joined: 29 Apr 2015
Posts: 34
DergMoney 25 May 2015, 20:14
El Tangas, you're a star. Created my new window with calculator as owner and all is good Very Happy

btw, closing the calculator doesn't close my new window because it has a separate WndProc Wink

Thanks
Post 25 May 2015, 20:14
View user's profile Send private message Reply with quote
El Tangas



Joined: 11 Oct 2003
Posts: 120
Location: Sunset Empire
El Tangas 25 May 2015, 20:49
Cool Smile
Can you post the code? Might be useful.
Post 25 May 2015, 20:49
View user's profile Send private message Reply with quote
DergMoney



Joined: 29 Apr 2015
Posts: 34
DergMoney 25 May 2015, 22:00
El Tangas wrote:
Cool Smile
Can you post the code? Might be useful.


The extra WndProc in the code doesn't actually do anything as it is a test example to add to a bigger project but here ya go Wink

Code:
format PE GUI 4.0
entry start

include "%fasminc%\win32a.inc"

section '.code' code readable executable

    start:
        invoke  GetModuleHandle, 0
        mov         [wc.hInstance], eax
        mov     [wcHUD.hInstance], eax
        invoke  LoadIcon, 0, IDI_APPLICATION
        mov         [wc.hIcon], eax
        mov         [wcHUD.hIcon], eax
        invoke  LoadCursor, 0, IDC_ARROW
        mov         [wc.hCursor], eax
        mov         [wcHUD.hCursor], eax
        invoke  RegisterClass, wc
        invoke  RegisterClass, wcHUD
        or          eax,eax
        jz          error
        invoke  CreateWindowEx, NULL, ClassMain, AppName, WS_OVERLAPPEDWINDOW or WS_VISIBLE, 100, 100, 600, 200, NULL, NULL, [wc.hInstance], NULL
        test    eax,eax
        jz          error
        mov     [hWndMain], eax
        invoke  EnumWindows, EnumWindowsProc, 0

    msgLoop:
        invoke  GetMessage, msg, NULL, 0, 0
        or          eax, eax
        jz          endLoop
        invoke  TranslateMessage, msg
        invoke  DispatchMessage, msg
        jmp         msgLoop
    error:
        invoke  MessageBox, NULL, errorStr, NULL, MB_ICONERROR + MB_OK
    endLoop:
        invoke  ExitProcess, [msg.wParam]

proc WndProc hwnd, wmsg, wparam, lparam
        push    ebx esi edi
        cmp     [wmsg], WM_DESTROY
        je      .wmDestroy
    .defWndProc:
        invoke  DefWindowProc, [hwnd], [wmsg], [wparam], [lparam]
        jmp     .finish
    .wmDestroy:
        invoke  DestroyWindow, [hWndHUD]
        invoke  PostQuitMessage, 0
        xor         eax, eax
    .finish:
        pop     edi esi ebx
        ret
endp

proc EnumWindowsProc hwnd, lparam
        push    ebx esi edi
        invoke  GetWindowText, [hwnd], strBuff, 1000
        or      eax, eax
        jz      .retTrue


        invoke  lstrlen, strBuff
        mov     ecx, eax
        mov     al, "C"
        mov     edi, strBuff
        repne   scasb
        jne     .retTrue
        mov     esi, searchStr + 1
        invoke  lstrlen, searchStr
        dec     eax
        mov     ecx, eax
        rep     cmpsb
        jne     .retTrue
        invoke  GetClassName, [hwnd], strBuff, 1000
        invoke  lstrlen, psClass
        mov     ecx, eax
        mov     esi, psClass
        mov     edi, strBuff
        rep     cmpsb
        jne     .retTrue

        ; have found the calculator window
;        int3
        push    [hwnd]
        pop     [hWndPS]
        invoke  CreateWindowEx, WS_EX_LAYERED, ClassHUD, NULL, WS_POPUP or WS_VISIBLE, 800, 100, 150, 75, [hWndPS], NULL, [wcHUD.hInstance], NULL
        test    eax,eax
        jz          error
        mov     [hWndHUD], eax
        invoke  SetLayeredWindowAttributes, [hWndHUD], 0, 255, LWA_ALPHA
        invoke  SetFocus, [hWndPS]

    .retFalse:
        mov     eax, FALSE
        jmp     .finish
    .retTrue:
        mov     eax, TRUE
    .finish:
        pop     edi esi ebx
        ret
endp        

proc WndProcHUD hwnd, wmsg, wparam, lparam
        push    ebx edi esi
    .defWndProc:
        invoke  DefWindowProc, [hwnd], [wmsg], [wparam], [lparam]
        jmp     .finish
    .finish:
        pop     esi edi ebx
        ret
endp


showError: 
        pushad 
        invoke  GetLastError 
        invoke  FormatMessage, FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, eax, LANG_NEUTRAL, errStrBuff, 0, NULL
        invoke  MessageBox, HWND_DESKTOP, [errStrBuff], NULL, MB_ICONERROR or MB_OK 
        popad 
        ret 

section '.data' data readable writeable
    ClassMain   db "WinClass", 00
    ClassHUD    db "hud", 00
    hWndHUD     dd ?
    AppName     db "My App", 00
    errorStr    db "oops!", 00
    hWndMain    dd ?
    hWndPS      dd ?
    psWndProcHnd dd ?
    titlePS     db 1002 dup ?
    strBuff     db 1002 dup ?
    wordBuff    db 40 dup ?
    space       db " ", 00
    errStrBuff  dd ?
    wc          WNDCLASS CS_HREDRAW or CS_VREDRAW, WndProc, 0, 0, NULL, NULL, NULL, COLOR_BTNFACE + 1, NULL, ClassMain
    msg         MSG
    searchStr   db "Calculator", 00
    rect        RECT
    numStr      db "%i", 00
    psClass     db "CalcFrame", 00
    wcHUD       WNDCLASS CS_HREDRAW or CS_VREDRAW, WndProcHUD, 0, 0, NULL, NULL, NULL, COLOR_BTNFACE + 4, NULL, ClassHUD

section '.idata' import data readable writeable 
library kernel32,'KERNEL32.DLL',\ 
        user32,  'USER32.DLL',\ 
        gdi32,   'GDI32.DLL',\ 
        comdlg32,'COMDLG32.DLL',\ 
        advapi32,'ADVAPI32.DLL',\ 
        comctl32,'COMCTL32.DLL',\
        msvcrt, 'msvcrt.dll'

include '%fasminc%\api\Kernel32.inc' 
include '%fasminc%\api\User32.inc' 
include '%fasminc%\api\Gdi32.inc' 
include '%fasminc%\api\Comdlg32.inc' 
include '%fasminc%\api\Advapi32.inc' 
include '%fasminc%\api\Comctl32.inc'
import msvcrt,\ 
        sprintf,'sprintf'
    
Post 25 May 2015, 22:00
View user's profile Send private message Reply with quote
El Tangas



Joined: 11 Oct 2003
Posts: 120
Location: Sunset Empire
El Tangas 26 May 2015, 00:21
Tnx. It's just that I haven't programed in windows for some years, so I just enjoy looking at some code snippets to refresh my memory. Its ok if the code is not complete.
Post 26 May 2015, 00:21
View user's profile Send private message Reply with quote
DergMoney



Joined: 29 Apr 2015
Posts: 34
DergMoney 26 May 2015, 01:12
El Tangas wrote:
Tnx. It's just that I haven't programed in windows for some years, so I just enjoy looking at some code snippets to refresh my memory. Its ok if the code is not complete.


The code given is complete. If you compile this and open the windows calculator program, the black box I create will stay above it in z-order but not any other unconnected apps. Wink

In case you have any problems compiling it here is the executable


Description:
Download
Filename: findcalc.zip
Filesize: 1.1 KB
Downloaded: 195 Time(s)

Post 26 May 2015, 01:12
View user's profile Send private message Reply with quote
El Tangas



Joined: 11 Oct 2003
Posts: 120
Location: Sunset Empire
El Tangas 26 May 2015, 09:06
Tnx. No problem recompiling (reassembling, actually Wink ), but I found a problem if you want to release your complete project later (some calculator add-on, I guess?). Since you search for "Calculator", it can't find my calc because my windows is not in english. I recompiled with the correct string in my language "Calculadora", works fine.
Post 26 May 2015, 09:06
View user's profile Send private message Reply with quote
DergMoney



Joined: 29 Apr 2015
Posts: 34
DergMoney 26 May 2015, 09:21
Thanks for the heads-up on the language issue you encountered. I only aimed my example at the windows calculator since all viewers of this thread running windows will have it on their computer.
I probably won't make this into a commercial package but afaik the application it is aimed at always has its title bar in english anyway. Other language users get all the menus etc in their chosen language, just not the title bar. It is something I would check in more depth of course if I did decide to go further Wink
Post 26 May 2015, 09:21
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.