PDA

View Full Version : Interfacing Windows SDK HelloWin



Charles Pegge
03-07-2008, 18:10
This is the hardcore stuff :)

Not the ultimate version by any means - it is quite bulky since it contains all the necesaries for Windows SDK in a single file. And the type declarations are not really required for the code to work in this example.

I've used some slightly exotic code to place the procedures table pointer immediately before wndproc so it can be picked up by this procedure. (This code has no absolute addresses at assembly time or EXE fixups - everything has to start off relative )

Getting Windows to spin from scratch in ASM is quite a challenge so I hope this will be useful as a starting point, with some useful pieces for SDK programming.



' Windows Hello World
' #2
' with winmain message loop and wndproc
' 3 July 2008
' Charles Pegge


Uses "Oxygen"
Uses "File"

dim src as string
src="
type WNDCLASS
(
;40 bytes
4 STYLE
4 lpfnwndproc
4 cbClsextra
4 cbWndExtra
4 hInstance
4 hIcon
4 hCursor
4 hbrBackground
4 lpszMenuName
4 lpszClassName
)

type MSG
(
; 28 bytes
4 hwnd;
4 message
4 wParam
4 lParam
4 time
8 pt
)


indexers `esi` offset 0 ascending
esi=getmemory 1024
call WndProcLocate
mov [eax-4],esi ; store sys proc table pointer here

var 4 kernel32,user32,GDI32

kernel32=LoadLibrary `kernel32.dll`
user32=LoadLibrary `user32.dll`
GDI32=LoadLibrary `GDI32.dll`

bind kernel32
(
GetCommandLine GetCommandLineA ; @0
GetModuleHandle GetModuleHandleA ; @4
ExitProcess ExitProcess ; @4
)

bind user32
(
LoadIcon LoadIconA ; @8
LoadCursor LoadCursorA ; @8
RegisterClass RegisterClassA ; @4
MessageBox MessageBoxA ; @4
CreateWindowEx CreateWindowExA ; @48
ShowWindow ShowWindow ; @8
UpdateWindow UpdateWindow ; @4
GetMessage GetMessageA ; @16
TranslateMessage TranslateMessage ; @4
DispatchMessage DispatchMessageA ; @4
PostQuitMessage PostQuitMessage ; @4
BeginPaint BeginPaint ; @8
EndPaint EndPaint ; @8
GetClientRect GetClientRect ; @8
DrawText DrawTextA ; @20
PostMessage PostMessageA ; @16
DefWindowProc DefWindowProcA ; @16
)


bind GDI32
(
GetStockObject GetStockObject ; @4
)


'

def SW_NORMAL 1
def SW_SHOWDEFAULT 10


var 4 cmdline,inst

cmdline=GetCommandLine
inst=GetModuleHandle 0
proc WinMain inst,0,cmdline,SW_NORMAL
freememory esi
ret


o2 !10 ; align 16 bytes


;-------
WinMain:
;-------
'

def CS_VREDRAW 1
def CS_HREDRAW 2
def IDI_APPLICATION 32512
def IDC_ARROW 32512
def WHITE_BRUSH 0
def MB_ICONERROR 16

def CW_USEDEFAULT 0x80000000
def WS_OVERLAPPEDWINDOW 0x00cf0000

push ebp
mov ebp,esp
;allocate stack space
sub esp,100
; setup class data
mov edi,esp
'
def wclass edi
def style [edi]
def pWndproc [edi+4]
def cbClsExtra [edi+08]
def cbWndExtra [edi+12]
def hInstance [edi+16]
def icon [edi+20]
def cursor [edi+24]
def background [edi+28]
def MenuName [edi+32]
def ClassName [edi+36]

; window handle
def hWnd [edi+40]

mov eax,CS_HREDRAW '
or eax,CS_VREDRAW '
mov style,eax
pWndProc=proc WndProcLocate
mov cbClsExtra,0
mov cbWndExtra,0
mov eax,[ebp+8]
mov hInstance,eax
icon=LoadIcon 0, IDI_APPLICATION
cursor=LoadCursor 0,IDC_ARROW
background=GetStockObject WHITE_BRUSH '
mov MenuName,0
`HelloWin`
mov ClassName,eax
RegisterClass wclass

cmp eax,0
( '
jnz exit '
MessageBox 0,`Registration failed`,`Problem`,MB_ICONERROR '
xor eax,eax ' zero eax
jmp long end_app ' jmp xitwm
) '


hWnd=CreateWindowEx 0, ClassName,`Hello Window`,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,640,480,
0,0,hInstance,0

(
cmp eax,0 '
jnz exit '
MessageBox 0,`Unable to create window`,`problem`,MB_ICONERROR
xor eax,eax ' zero eax
jmp long end_app ' jmp xitwm
) '
ShowWindow hWnd,[ebp+20] ' show
UpdateWindow hWnd


' MESSAGE LOOP '

add edi,40 ; place for wmsg struc
(
GetMessage edi,0,0,0 '
cmp eax,0
jz exit
TranslateMessage edi
DispatchMessage edi
repeat
) '
mov eax,[edi+8] ' Msg.wParam 3rd param

end_app:
; deallocate stack space
mov esp,ebp
pop ebp '
ret 16 '
; end of WinMain


type RECT
(
; 16 bytes
4 left
4 top
4 right
4 bottom
)

type PAINTSTRUCT
(
; 64 bytes
4 hDC
4 fErase
rect rcPaint
4 fRestore
4 fIncUpdate
32 rgbReserved
)

;-------------
WndProcLocate:
;-------------

; return absolute location of WndProc
o2 !10 ; align 16
o2 e8 00 00 00 00 ; call next location
o2 58 83 c0 0b c3 ; pop this into eax and add 11 then ret
o2 00 00 00 00 00 00 ; round to 15 bytes

;-------
WndProc:
;-------
def hWnd [ebp+08]
def wMsg [ebp+12] '
def wParam [ebp+16] '
def lParam [ebp+20] '

def WM_CREATE 1
def WM_DESTROY 2
def WM_PAINT 15
def WM_CLOSE 16
def WM_KEYDOWN 256

push ebp '
mov ebp,esp
push esi
;
; restore sys procs table pointer
call WndProcLocate
mov esi, [eax-4]
;
; not using stack locals so no subractions for esp

'
mov eax,wMsg
(
(
cmp eax, WM_CREATE '
jnz exit
xor eax,eax
jmp long endselect
) ; end create

(
cmp eax, WM_DESTROY
jnz exit
PostQuitMessage 0
xor eax,eax
jmp long endselect
) ; end destroy

(
cmp eax,WM_PAINT
jnz exit
sub esp,100 ; extra workspace
def cRect [ebp-60]
def hDC [ebp-20]
def Paintst [ebp-100]
hDC=BeginPaint hWnd,&Paintst
GetClientRect hWnd,&cRect
; style
; 0x20 DT_SINGLELINE
; 0x04 DT_VCENTER
; 0x01 DT_CENTER
; 0x25
DrawText hDC,`Hello World!`,-1,&cRect,0x25
EndPaint hWnd,&Paintst
xor eax,eax
jmp long endselect
) ; end paint

(
cmp eax,WM_KEYDOWN
jnz exit
(
mov eax,wParam
cmp al,27 ' esc key
jnz exit
PostMessage hWnd,WM_CLOSE,0,0
)
xor eax,eax ' zero
jmp long endselect
) ; end keydown
; case else
DefWindowProc hWnd,wMsg,wParam,lParam
) ; end select
endselect:
;
pop esi
mov esp,ebp
pop ebp
ret 16


"
'File_Save("z.txt",o2_view_file(src))
if len(o2_error) then msgbox 0,o2_error
o2_asmo src
o2_exec

ErosOlmi
03-07-2008, 19:29
Charles,

it is impressive the level you have reached in Oxygen. It is a complete language per se.
What a massive work reading your FreeBasic sources.

My hat down!

PS:
maybe the only problem is that every Oxygen script is dependant from "o2asm.data" data file that must be present in the same directory of the script otherwise there is a possible GPF.

Charles Pegge
03-07-2008, 22:44
Thank you Eros. It's all open ended as to how the language facility will be used. It is more discovery than invention so I am gradually learning how to use it :)

For o2asm.data I suggest it goes into a folder called oxygen, located in thinbasic\lib. This location could also be used to hold any other future intrinsic parts.

Is this the best fit for the thinBasic file system?

ErosOlmi
03-07-2008, 23:12
Well, the problem can also exists when creating thinBasic bundled executable.
How to know executable is dependant from "o2asm.data" so it has to be included in bundled exe?

I think an option could be the following:

include current "o2asm.data" data directly inside Oxygen module so it is part of the module. I suppose the current file already has the most used cpu operands so it is already very exaustive
when Oxygen module is loaded, it can check for an optional file (named as you prefer for example "o2asmUser.data" or whatever) present in the same path of Oxygen module. If that file exists, loads new operands. Consider that you can get the directory where Oxygen module has being loaded using the parameter passed to "LoadLocalSymbols(sPath)" function. Because that directory can change, thinCore pass to every "LoadLocalSymbols" function to every loaded module the directory where it is loading it.


In this way Oxygen is not dependant from any external file but at the same time it is still open to new operands.

Maybe another option can be to create a new Oxygen keywords that loads external commands as string or file name: "O2_LoadAdditionalOps(StringBuffer)". This function to be executed in the script before any other Oxygen functions.

In either cases it is user responsability to manage stuff but at the same time no GPF due to missing data.
What do you think?

Ciao
Eros

Charles Pegge
04-07-2008, 00:46
Thanks Eros,

I am not familiar with bundling yet - not sure where to find loadLocalSymbols.

Does thinBasic_GetRunTimeInfo("APP_PATH") work within bundles? Do you retain the same directory structure for required modules ie .\Lib\thinBasic_*.dll?

My test system looks for o2asm.data in the current directory - then it tries APP_PATH\lib\oxygen\o2asm.data

ErosOlmi
04-07-2008, 00:56
thinBasic engine (thinCore.dll) loads modules using the path finding described in http://www.thinbasic.com/public/products/thinBasic/help/html/uses.htm under "Remarks" section. So you cannot know where the modules is loaded from at compile time. All is dynamic and follows the following order:
1. Source script path
2. Source script path + Lib
3. Source script path + Bin
4. Source script path + Mod
5. Source script path + Lib + "thinBasic_" + ModuleName
6. Source script path + Bin + "thinBasic_" + ModuleName
7. Source script path + Mod + "thinBasic_" + ModuleName
...reserved...
11. thinBasic path
12. thinBasic path + Lib
13. thinBasic path + Bin
14. thinBasic path + Mod
15. thinBasic path + Lib + "thinBasic_" + ModuleName
16. thinBasic path + Bin + "thinBasic_" + ModuleName
17. thinBasic path + Mod + "thinBasic_" + ModuleName

For this reason, when the module is loaded, thinCore pass to it the directory infor where it was loaded from.
How doe this happening?
When thinCore.dll loads thinBasic_Oxygen, it calls Oxygen exported function "LoadLocalSymbols" (you will find it in your FreeBasic source file named "thinBasic_Oxygen.bas"). "LoadLocalSymbols" has the following declare:

FUNCTION LoadLocalSymbols Cdecl ALIAS "LoadLocalSymbols" (BYVAL sPath AS STRING) AS Long EXPORT
sPath parameters is filled with the directory where thinBasic engine (thinCore.dll) found Oxygen module. As I sayd before this directory can change. For example when you execute a source thinBasic script, usually it is "\thinBasic\Lib\". But when you execute a bundled exe thinBasic script, that directory is usually equal to the directory where the bundled EXE is located.

Hope this can help.
Eros

Charles Pegge
04-07-2008, 01:38
Yes thank you Eros. I've got the picture now. I'll try some bundling later on today. But first an appointment with Morpheus. Good night.

ErosOlmi
04-07-2008, 01:48
... But first an appointment with Morpheus. Good night.

;)
Me too. Good night.

kryton9
04-07-2008, 07:02
Thanks Charles, I got it to run. Now to see if I can figure out what is going on. Thanks again for the example!

Charles Pegge
04-07-2008, 09:56
Glad it works Kent. If you can figure out what is going on please let me know :) Windows SDK is so demanding as you can see from all the procs required to get it up and running.

Eros,
I have been experimenting with bundles this morning using spath in LoadLocalSymbols. I am using a folder called oxygenlib which normally sits alongside thinbasic_Oxygen.dll, wherever that might be.

The bundles work well - no problem in locating files including asm scripts. But if the compiled bundle is run from my development directory, it deletes or renders hidden all the original modules, asm files and folders used to create the bundle. This seems to be a consequence of the bundle's cleanup operation. I did not specify a target directory for the bundle though - would it be possible to make the default behaviour safer?

Petr Schreiber
04-07-2008, 09:56
This is fantastic example Charles,
hardcore work - but still well structured.


Petr

ErosOlmi
04-07-2008, 10:41
Well, bundled exe will delete all exploded files if flag for deletion is on. So if you include "o2asm.data" file, it will be deleted.

I still prefer one of my suggestions (or any other that will not create extenal dependancies) because this creates very few confusion to users both for testing and for script distribution. But how to go with module is up to you.

Ciao
Eros

Charles Pegge
04-07-2008, 12:20
Yes Eros, I agree, from the modular point of view it makes sense to reduce external bits and pieces, so I will incorporate the soft coded instructions back into the Oxygen Module - after all the full source code is provided - easy to mod, so my conscience is clear :)

I think it is unlikely that anyone will need to customise the op codes for a particular application .- they have to be industry standard.

Should be ready later today.

ErosOlmi
04-07-2008, 12:26
... so my conscience is clear :)


Well, your conscience will be always clear.
You have provided a so great module with full source code (repeat, full source code ! ) and functionalities that you've got credits for at least 10 years!
;)

Charles Pegge
04-07-2008, 13:25
Phew! that wasn't too bad. No more o2asm.data. Updated in time for your next release I hope.

There's a substantial amount of test material now which really helps with quickly verifying software mods.

Eros if you flatter me too much my head will no longer fit my hat and I will have to get a new head! :o

Michael Clease
04-07-2008, 14:08
Here is some old stuff I found which you might be interested in looking at Charles.

Charles Pegge
04-07-2008, 15:41
Thanks Abraxas. It's mostly 16 bit DOS but there is a windows 95 32 bit demo in the 'companion disk' folder, using TASM with macros and prototypes.