News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Relative unlimited size array/list?

Started by Krozgen, December 08, 2005, 05:05:55 AM

Previous topic - Next topic

Krozgen

Unlike before, I went through the help files this time :) Unfortunately, unlike with the floating point, I don't quite know what I'm looking for. Basically, I want a program that'll use EnumWindows (with two callbacks) that will... hide and show windows. Their functionalities are as follows:

Hide windows will, for each window, see if that window is visible. If it is, then it will add the window's handle to an array (preferrably a dynamic one of sorts...?), hide it, and move onto the next window. After all windows are hidden, the program's window will set a global hotkey that will bring the assembly window back to visible.

Show windows will, for each window in the aforementioned array, go back and un-hide them all.

The purpose is almost a form of protection. I want to hide all my windows, and be able to summon them back by using my program (most likely with a password for added security). The beauty of it is, if they try to use task manager or somesuch to kill it, it'll still leave all the windows hidden. One other thing I might implement is a timer so that every second, it will re-hide all visible windows (and append them to the array) while in the "hidden" mode.

My main problem is, I don't know how to implement a dynamically sized array. I've looked around and seen an example of linked lists, some HLA thing, a lot of stuff... but I don't fully understand it, or it's seemingly far too complicated for this. Is there an easier way? Thanks in advance.

sluggy

Quote from: Krozgen on December 08, 2005, 05:05:55 AMMy main problem is, I don't know how to implement a dynamically sized array. I've looked around and seen an example of linked lists, some HLA thing, a lot of stuff... but I don't fully understand it, or it's seemingly far too complicated for this. Is there an easier way? Thanks in advance.
Your question is: "how should i keep track of my windows?". This one really is way simpler than you thought. Instead of trying to search sites and/or posts looking for the one correct answer to this question, just sit down and think about it logically for 10 minutes - you will slap your forehead when you realise that you were making it more difficult than what it actually is. And linked lists are easy too, just take the time to read a couple of different tutorials on them, and you will agree with me  :8)

For this issue, a linked list is technically your best option because you have a variable number of windows. OTOH, a linked list could be overkill because you wouldn't have that many windows.

Your *array* doesn't have to be variable in size - it is just the number of used array elements that will vary. So why don't you allocate an array of maybe 100 elements in size, knowing that you will probably only ever use 20 to 30 of those elements at any one time?

The thing you haven't thought of is: "when i make a window visible because it is in my list, should it really be visible? What if the application had made it invisible and i am over-riding that?".

I suggest you take a different approach that requires absolutely no coding at all!!!! Just use a secure OS (ie not Win9x), and use a screen saver, or lock the machine  :lol



Krozgen

I'm going to start with the end of your post first, if you don't mind, Sluggy :)

QuoteI suggest you take a different approach that requires absolutely no coding at all!!!! Just use a secure OS (ie not Win9x), and use a screen saver, or lock the machine

It's not so much the purpose of the program that I'm interested in as the concepts learned in making it. By testing out enumwindows and learning about arrays / linked lists in assembly in this manner, I'll learn fifty times faster (just my preference).

As to a fixed size array - I've already figured that out :) I was going to use one, but for one, I'm not wholly sure that it'll be less than the size I allocate (and I really like saving space!!!), and two, a dynamic array is the way to go (or a linked list), imho. That's the whole point of them.

You said a linked list is technically my best option, this I knew beforehand, and if it's as easy as you say to implement one, then it shouldn't be overkill... no?  :8)

And the final thing you mentioned (to make this response complete, before I go try to find some more linked list material)...
QuoteThe thing you haven't thought of is: "when i make a window visible because it is in my list, should it really be visible? What if the application had made it invisible and i am over-riding that?".

That's exactly why I'm making the linked list :) I'm going to check to make sure it's already visible, and if it is, then add it to my spiffy new list. When I un-hide the windows, I'll restore only those windows to a visible position. If you think that won't work, then please provide a feasible alternative ^_^

So... I guess what I'm trying to say here is, I'm just using this as a method of learning. If you have a suggestion for a program to make next to learn some other cool aspect of assembly, let me know! In the meantime, I'm off to look up some more linked list stuff  :U

zooba

Don't forget to look up memory allocation stuff too.

Linked lists in other languages might be fun, but they can get ugly very easily in assembly language :bg

Krozgen

Eh, I went with a fixed size array... did the job perfectly. I hope no one will mind my posting the full source here... eh, it's relevant :)

hideshow.asm

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    .386                       ; create 32 bit code
    .model flat, stdcall       ; 32 bit memory model
    option casemap :none       ; case sensitive

    include \masm32\include\windows.inc
    include \masm32\include\masm32.inc
    include \masm32\include\user32.inc
    include \masm32\include\kernel32.inc

    includelib \masm32\lib\masm32.lib
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib

    WndProc   PROTO :DWORD,:DWORD,:DWORD,:DWORD ; define procedure

    .data

    dlgname         db "HideShowWindowsDialog",0
    passwordprompt  db "Password? :|",0
    invalidpass     db "Invalid password :(",0
    validpass       db "Valid password :)",0
    HandleArray     dword 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
    NumWinsHidden   dword 0
    LoopCounter     byte  0
    WindowsHidden   bool  0
    TempPassword    dword ?

    .data?

    hInstance   dd ?    ; instance for dialogbox
   
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
   
    .code

start:

    invoke GetModuleHandle, NULL
    mov hInstance, eax
    invoke DialogBoxParam, hInstance, ADDR dlgname, NULL, ADDR WndProc, NULL
    invoke ExitProcess, eax

; -------------------------------------------------------------------------

WndProc proc hWin   :DWORD,
             uMsg   :DWORD,
             wParam :DWORD,
             lParam :DWORD

    .if uMsg == WM_COMMAND ; a button has been pressed

        .if wParam == 100       ; "Find Open & Hide"
            .if WindowsHidden == 0
                mov eax,offset HandleArray
                mov LoopCounter,0
               
                loop_to_initialize:
                    mov ebx, 0
                    mov [eax],ebx
                    add eax,4
                    inc LoopCounter
                cmp LoopCounter,30
                jl loop_to_initialize
   
                mov NumWinsHidden,0
                       
                push 0
                push offset CountNumberVisibleWindowsProcCallback
                call EnumWindows

                push SW_HIDE
                call HideOrRecallWindows
   
                mov WindowsHidden, 1
   
                invoke ShowWindow,hWin,SW_SHOW
               
                ;invoke SetDlgItemInt, hWin, 150, NumWinsHidden, TRUE
                invoke SetDlgItemText, hWin, 150, addr passwordprompt
            .endif
        .elseif wParam == 101   ; "Recall Open & Show"
            .if WindowsHidden == 1
                invoke GetDlgItemInt, hWin, 150, TempPassword, 10
                .if eax == 1337
                    push SW_SHOW
                    call HideOrRecallWindows
                    invoke SetDlgItemText, hWin, 150, addr validpass
                    mov WindowsHidden, 0
                .elseif
                    invoke SetDlgItemText, hWin, 150, addr invalidpass
                .endif
            .endif
        .elseif wParam == 200   ; exit button
            .if WindowsHidden==0
                invoke EndDialog,hWin,NULL
            .endif
        .endif
       
    .elseif uMsg == WM_CLOSE ; X button

        .if WindowsHidden==0
            invoke EndDialog,hWin,NULL
        .endif
       
    .endif

    xor eax,eax     ; THIS LINE IS KEY! Without it, no dialog "window" appears,
                    ; and the program goes into an infinite loop.
    ret
   
WndProc endp

; -------------------------------------------------------------------------

CountNumberVisibleWindowsProcCallback proc  hWin :DWORD, lParam :DWORD

    push ebx

    invoke IsWindowVisible,hWin
    .if eax == TRUE
        mov ebx,NumWinsHidden
        shl ebx,2
        add ebx,offset HandleArray
        mov eax, hWin
        mov [ebx],eax
        inc NumWinsHidden
    .endif

    mov eax, 1 
    pop ebx
    ret

CountNumberVisibleWindowsProcCallback endp

; -------------------------------------------------------------------------

HideOrRecallWindows proc  HideOrShow :WORD

    push ebx
   
    mov ebx,offset HandleArray
    mov LoopCounter,0
   
    loop_to_hide:
        mov eax,[ebx]
        invoke ShowWindow,eax,HideOrShow
        add ebx,4
        inc LoopCounter
    cmp LoopCounter,30
    jl loop_to_hide

    pop ebx
    ret

HideOrRecallWindows endp

; -------------------------------------------------------------------------

end start

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««


rsrc.rc

#include "\masm32\include\resource.h"

HideShowWindowsDialog DIALOGEX 0, 0, 159, 200
STYLE DS_3DLOOK | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Hide / Show Windows App"
FONT 8, "Tahoma"
{
   CONTROL "Find Open and &Hide", 100, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 7, 22, 146, 14
   CONTROL "Recall Open and &Show", 101, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 7, 40, 146, 14
   CONTROL "&Quit", 200, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 6, 180, 50, 14
   CONTROL "Password?", 150, EDIT, ES_CENTER | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 6, 5, 147, 13
}




It's pretty clear what it does... very basic, but helped me learn "arrays". Yea... so basically, it's limited to 30 windows. That amount could be easily modified, but it will always be fixed. At present, the exe is just over 3 KB, and when rar'ed, just below 1 KB. Not bad for a first go, in my opinion :)

zooba

HandleArray     dword 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

This line could be simplified by using the DUP operator:

HandleArray     DWORD 30 DUP (0)

Then you can replace the 30 with an equate and never look at it again.

Also, if you declare it in the uninitialised data section (.data?), it won't make your executable larger:

.data?
    HandleArray        DWORD 30 DUP (?)


Note though that MASM doesn't like very large amounts of DUPs (ie. 10000+, depending on your computer) and tends to take a long time - search the forum for more on this

Cheers,

Zooba

Krozgen

Thank you so much! One sample of code I originally found as an example of arrays used the DUP, but I didn't underestand it. I also appreciate the info on the data? section; never understood that either! AWSOME! *Dances* How does it not affect the .exe size, if you don't mind me asking?

- EDIT -

Uh... I tried the modification, and it seems to work perfectly, but the executable size didn't go down at all :( Any explanation...?

zooba

Quote from: Krozgen on December 13, 2005, 04:15:19 AMHow does it not affect the .exe size, if you don't mind me asking?

Using the '.data?' section tells the assembler it doesn't have to remember what goes into the data. So it just remembers how much data there is and when your executable loads it will allocate that amount. Notice that you cannot initialise anything in the .data? section:

.data?
    dwNumber DWORD 123    ; illegal
    dwNumber DWORD ?    ; legal


The '.data' section remembers how much data and actually keeps a copy of all the data in the executable (where else can it keep it?). So if you disassemble an executable containing:

.data
    HandleArray    DWORD 30 DUP (0)


You will find 30 DWORDs (120 bytes) all filled with zeros. However:

.data?
    HandleArray    DWORD 30 DUP (?)


will not produce 120 bytes worth of zeros. On the downside, there is no way of guaranteeing the values of the variables (and the assembler won't check how you access it like a HLL will), so you have to make sure you initialise it manually. In your case, you are keeping track of the number of handles separately, so you can do this.

In response to your edit, what is your current executable size? There is a minimum size which you can only go below using special linkers. Try using 300 instead of 30 (in both .data and .data?) and see if there is a difference.


Krozgen

Ah, very cool explanation :) The .exe is 3,072 bytes... changing the 30 to 300 didn't change anything, so maybe the minimum size is 3 KB? Eh... UPX couldn't compress it anymore, interestingly enough.

Vortex

Hi Krozgen,

Try Pelle's PoLink to link your object file, it will reduce the size of your executables. PoLink cames with Hutch's masm32 package.

Krozgen

Good, got the .exe down to 2,048 bytes (2 KB). The makefile's been changed to:


@echo off

if not exist rsrc.rc goto over1
\masm32\bin\rc /v rsrc.rc
\masm32\bin\cvtres /machine:ix86 rsrc.res
:over1

if exist "hideshow.obj" del "hideshow.obj"
if exist "hideshow.exe" del "hideshow.exe"

\masm32\bin\ml /c /coff "hideshow.asm"
if errorlevel 1 goto errasm

if not exist rsrc.obj goto nores

REM \masm32\bin\Link /SUBSYSTEM:WINDOWS "hideshow.obj" rsrc.res
\masm32\bin\polink /SUBSYSTEM:WINDOWS "hideshow.obj" rsrc.res
if errorlevel 1 goto errlink

dir "hideshow.*"
goto TheEnd

:nores
REM \masm32\bin\Link /SUBSYSTEM:WINDOWS "hideshow.obj"
\masm32\bin\polink /SUBSYSTEM:WINDOWS "hideshow.obj"
if errorlevel 1 goto errlink
dir "hideshow.*"
goto TheEnd

:errlink
echo _
echo Link error
goto TheEnd

:errasm
echo _
echo Assembly Error
goto TheEnd

:TheEnd

pause


You can see where I changed it with the REMs. Is this what you were referring to? If there's any other way of getting it down further, please let me know.