• Welcome to Powerbasic Museum 2020-B.
 

News:

Forum in repository mode. No new members allowed.

Main Menu

[SDK] 05 - Take control of your BUTTONS

Started by Patrice Terrier, August 11, 2007, 01:35:45 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Patrice Terrier

WORK IN PROGRESS
This is the fifth post of a serie, where I shall try to explain how to take complete control over SDI window.

This is a major release, because most of the basic functions I wanted to put in, are now there.

You can now create three type of buttons

1 - zButImage

2 - zPushButton

3 - zFrameButton

With small modifications it could be possible to create more, like ckeck box or radio button, using the "ZBUTIMAGE" class.

You can even use zFrameButton to draw a static image.

I have added a new temporary double buffer, that can be used to remove flickering when drawing complex child controls.

'// Create temporary double buffer

FUNCTION zDoubleBuffer(BYVAL hDC AS LONG, BYVAL x AS LONG, BYVAL y AS LONG, BYVAL Action AS LONG) STATIC AS LONG
    DIM Xx AS LONG, Yy AS LONG, UseDC AS LONG, hDCTemp AS LONG, hBMTemp AS LONG, hBMPrev AS LONG
    IF Action THEN
     ' Create OFF screen bitmap to avoid flickering and allow smooth display
     ' ---------------------------------------------------------------------
       hDCTemp = CreateCompatibleDC(hDC)
       hBMTemp = CreateCompatibleBitmap(hDC, x, y)
       hBMPrev = SelectObject(hDCTemp, hBMTemp)
       Xx = x: Yy = y
       UseDC = hDC
       FUNCTION = hDCTemp
    ELSE
     ' End of OFF screen drawing, fast BitBlt to the target display Window
     ' -------------------------------------------------------------------
     ' Draw final result to the target window
       CALL BitBlt(UseDC, x, y, Xx, Yy, hDCTemp, 0, 0, %SRCCOPY)
     ' Deallocate system resources
       CALL SelectObject(hDCTemp, hBMPrev)
       CALL DeleteObject(hBMTemp)
       CALL DeleteDC(hDCTemp)
       FUNCTION = 0
    END IF

END FUNCTION

 
The %ANCHOR_CENTER_HORZ_BOTTOM has been enhanced, you can see it on the multimedia buttons as well as the frame button drawn arround them, when you resize the form.

All images have been reworked to use transparent opacity and little shadow to give your form a professionnal look like this one:



Nice isn't it ?

Patrice Terrier
www.zapsolution.com
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Theo Gottwald

That Button is really state-of-the-art. They are just perfect in design!

José Roca


Petr Schreiber

Hi Patrice,

it isn't nice, it is beautiful !


Thanks,
Petr
AMD Sempron 3400+ | 1GB RAM @ 533MHz | GeForce 6200 / GeForce 9500GT | 32bit Windows XP SP3

psch.thinbasic.com

Eros Olmi

Well, a big thanks is not enough, really.
And best of all, source code is full of many little secrets to learn from and master  :o

Thanks!
thinBasic Script Interpreter - www.thinbasic.com | www.thinbasic.com/community
Win7Pro 64bit - 8GB Ram - Intel i7 M620 2.67GHz - NVIDIA Quadro FX1800M 1GB

Patrice Terrier

QuoteAnd best of all, source code is full of many little secrets to learn from and master

Yep, very few programmers are knowing these little secrets, except you now, of course ;)

More to come...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Eros Olmi

You mean I was the only one not to know all those secrets?
Oh no, I'm always the last one to know things! :P
thinBasic Script Interpreter - www.thinbasic.com | www.thinbasic.com/community
Win7Pro 64bit - 8GB Ram - Intel i7 M620 2.67GHz - NVIDIA Quadro FX1800M 1GB

Kent Sarikaya

Beautiful look to the window and controls, it is as beautiful as the api coding is long, I guess no shortcuts to beauty :)

Patrice Terrier

#8
Quoteit is as beautiful as the api coding is long

This is because I choose to put everyting in the EXE for the tutorial pupose, however usually most of classes coding are done in DLL (see the size of the Windows API's DLLs).

Ultimatly most of the code should be moved into a DLL, where some more nice stuffs can be done, that couldn't be done in a EXE, like low level advanced  hooking functions.

Example of thing that can be done only with a DLL:

FUNCTION HookFunction (hLib AS DWORD, Func AS STRING, HookProc AS DWORD, OrigProc AS DWORD) AS LONG
    LOCAL lpImageDosHeader          AS IMAGE_DOS_HEADER PTR
    LOCAL lpImageNtHeaders          AS IMAGE_NT_HEADERS PTR
    LOCAL lpImageImportDescriptor   AS IMAGE_IMPORT_DESCRIPTOR PTR
    LOCAL lpImageImportByName       AS IMAGE_IMPORT_BY_NAME PTR
    LOCAL lpFuncNameRef             AS DWORD PTR
    LOCAL lpFuncAddr                AS DWORD PTR
    LOCAL flOldProtect              AS DWORD

    lpImageDosHeader = hLib

    IF @lpImageDosHeader.e_magic <> %IMAGE_DOS_SIGNATURE THEN EXIT FUNCTION ' invalid DOS signature
    lpImageNtHeaders = lpImageDosHeader + @lpImageDosHeader.e_lfanew
    IF @lpImageNtHeaders.Signature <> %IMAGE_NT_SIGNATURE THEN EXIT FUNCTION  ' invalid NT signature
    IF @lpImageNtHeaders.FileHeader.SizeOfOptionalHeader <> SIZEOF( @lpImageNtHeaders.OptionalHeader) OR _
       @lpImageNtHeaders.OptionalHeader.Magic <> %IMAGE_NT_OPTIONAL_HDR32_MAGIC THEN EXIT FUNCTION

    IF @lpImageNtHeaders.OptionalHeader.NumberOfRvaAndSizes <= %IMAGE_DIRECTORY_ENTRY_IMPORT THEN EXIT FUNCTION ' IMPORT section does not exist

    lpImageImportDescriptor = @lpImageNtHeaders.OptionalHeader.DataDirectory( %IMAGE_DIRECTORY_ENTRY_IMPORT ).VirtualAddress + lpImageDosHeader
    IF lpImageImportDescriptor = lpImageDosHeader THEN EXIT FUNCTION

    WHILE @lpImageImportDescriptor.OriginalFirstThunk <> 0
     ' DllName @lpImageImportDescriptor.pName + lpImageDosHeader = Asciiz Ptr
       lpFuncNameRef = @lpImageImportDescriptor.OriginalFirstThunk + lpImageDosHeader
       lpFuncAddr = @lpImageImportDescriptor.FirstThunk         + lpImageDosHeader

       DO WHILE @lpFuncNameRef <> 0
          lpImageImportByName = @lpFuncNameRef + lpImageDosHeader
          IF (@lpFuncNameRef AND %IMAGE_ORDINAL_FLAG) THEN

          ELSEIF @lpImageImportByName.ImpName = Func THEN
             IF VirtualProtect(BYVAL lpFuncAddr, 4, %PAGE_READWRITE, flOldProtect) = 0 THEN EXIT FUNCTION
             OrigProc = @lpFuncAddr: @lpFuncAddr = HookProc
             IF FlushInstructionCache(GetCurrentProcess, BYVAL @lpFuncAddr, 4) = 0 THEN EXIT FUNCTION
             IF flOldProtect <> %PAGE_READWRITE THEN VirtualProtect BYVAL lpFuncAddr, 4, flOldProtect, flOldProtect
             FUNCTION = 1: EXIT FUNCTION ' Success
          END IF
          INCR lpFuncNameRef
          INCR lpFuncAddr
       LOOP
       INCR lpImageImportDescriptor
    LOOP
END FUNCTION


The code above is being used to hook/replace existing API directly within Windows DLLs!

and here is an example that shows you how to use it, to replace the core API BeginPaint EndPaint by your own code.

Quote
FUNCTION GetMsgProc(BYVAL nCode AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG

   IF nCode < 0 THEN
      FUNCTION = CallNextHookEx(BYVAL hHook, BYVAL nCode, BYVAL wParam, BYVAL lParam)
   ELSEIF hHookDone = %FALSE THEN
      CALL HookFunction(GetModuleHandle(BYVAL %NULL), "BeginPaint", CODEPTR(skBeginPaint), hBeginPaint)
      CALL HookFunction(GetModuleHandle(BYVAL %NULL), "EndPaint", CODEPTR(skEndPaint), hEndPaint)
      hHookDone = %TRUE
   END IF

END FUNCTION

FUNCTION zBeginPaint ALIAS "zBeginPaint" (BYVAL hWnd AS LONG, ps AS PAINTSTRUCT) EXPORT AS LONG
    LOCAL rw AS RECT
    LOCAL pt AS POINTAPI
    Item& = skChild(hWnd&)
    IF Item& THEN
       hOwner& = skPopupOwner(hWnd&)
       OwnerItem& = skItem(hOwner&)
       IF OwnerItem& THEN
          IF Win(OwnerItem&).MemDC THEN
             ps.hDC = Win(OwnerItem&).MemDC
             ps.fErase = 0

             CALL GetWindowRect(hOwner&, rw)
             pt.X = 0: pt.Y = 0: CALL ClientToScreen(hWnd&, pt)
             ofX& = pt.X - rw.nLeft: ofY& = pt.Y - rw.nTop
             CALL GetClientRect(hWnd&, rw)

             ps.rcPaint.nLeft   = ofX&
             ps.rcPaint.nTop    = ofY&
             ps.rcPaint.nRight  = ofX& + rw.nRight
             ps.rcPaint.nBottom = ofY& + rw.nBottom

             ps.fRestore   = 0
             ps.fIncUpdate = 0
             FOR K& = 0 TO 31: ps.rgbReserved(K&) = 0: NEXT
             FUNCTION = ps.hDC
             EXIT FUNCTION
          END IF
       END IF
    END IF
    CALL DWORD hBeginPaint USING BeginPaint (hWnd, ps) TO Ret&
    FUNCTION = Ret&

END FUNCTION

Of course this kind of thing requires a very good knowledge of the core API, and you must know exactly what you are doing or be assured that you will crash your computer.
:'(

This is one of the reason why Microsoft put ahead managed code, to protect the OS from direct access to the low level FLAT API engine, no more hackers/hookers there  :)


PS: The BeginPaint EndPaint hook function is a quick cut and past from my WinLIFT SkinEngine, that was written 10 years ago!

Patrice Terrier
www.zapsolution.com
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Edwin Knoppert

I wonder if HookFunction() is valid on kernel32.exe api's
Afaik this is a special 'lib' which is shared among apps.

I might be wrong.

Otherwise thanks for this one.

Patrice Terrier

Edwin,

QuoteI wonder if HookFunction() is valid on kernel32.exe api's Afaik this is a special 'lib' which is shared among apps.

From my own experiencs all the hook functions being used in my DLLs are working with all Windows flavor including VISTA.

By the way Edwin, did you remember this Browse For Folder function, we have been working together with you and Semen, would you mind if I post its source code there?

I would like to make this board, a kind of SDK's Gurus code section ;)
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Edwin Knoppert

That code was rewritten and embedded into PwrDev.

Patrice Terrier

Hi Edwin

I also rewrite it myself with drag & drop capabilities

May be we have done the same work twice ;)
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Edwin Knoppert

I was testing hooking "CreateFileA" on my XP computer but no result.
A list build via @lpImageImportByName.ImpName shows NtCreateFile and openfile and such.
These might be the actual functions and even unicode.

My function calls CreateFileA though.

Any ideas?
I am not sure if using a simple getprocaddress() on the last part (below: ElseIf @lpImageImportByName.ImpName = Func Then ) wouldn't be sufficient.


Patrice Terrier

Edwin

If hooking fails, then you could try the very advanced features like "detours" or "trampolin"
PDF document there: Binary interception of Win32 functions

Patrice Terrier
www.zapsolution.com
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com