it 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.
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 19 years ago!