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:
(http://www.zapsolution.com/pictures/sdk/zskin05.png)
Nice isn't it ?
Patrice Terrier
www.zapsolution.com
That Button is really state-of-the-art. They are just perfect in design!
¡Bravo, maestro! Hats off to you!
Hi Patrice,
it isn't nice, it is beautiful !
Thanks,
Petr
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!
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...
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
Beautiful look to the window and controls, it is as beautiful as the api coding is long, I guess no shortcuts to beauty :)
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
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.
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 ;)
That code was rewritten and embedded into PwrDev.
Hi Edwin
I also rewrite it myself with drag & drop capabilities
May be we have done the same work twice ;)
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.
Edwin
If hooking fails, then you could try the very advanced features like "detours" or "trampolin"
PDF document there: Binary interception of Win32 functions (http://research.microsoft.com/~galenh/Publications/HuntUsenixNt99.pdf)
Patrice Terrier
www.zapsolution.com
The first post of this thread has been updated, to fix the ZIP file corruption caused by the "Server Collapse".
...