PDA

View Full Version : Windows API `Hello World!`



Charles Pegge
20-03-2009, 21:58
This will be instantly recognisable to any one who has worked direclty with the Windows API.





' Windows Hello World
' with winmain message loop and wndproc
' Revised 20 Mar 2009
' Charles Pegge


Uses "Oxygen","File"

dim src as string
src="

type WNDCLASS
;40 bytes
STYLE as long
lpfnwndproc as long
cbClsextra as long
cbWndExtra as long
hInstance as long
hIcon as long
hCursor as long
hbrBackground as long
lpszMenuName as long
lpszClassName as long
end type

type point
x as long
y as long
end type

type MSG
; 28 bytes
hwnd as long
message as long
wParam as long
lParam as long
time as long
pt as point
end type

dim kernel32,user32,GDI32 as long
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


dim cmdline,inst as long

cmdline=GetCommandLine
inst=GetModuleHandle 0

declare Function WinMain(byval inst as long ,byval prevInst as long ,byval cmdline as long , byval show as long) as long
declare function WndProc(byval hWnd as long, byval wMsg as long, byval wParam as long, byval lparam as long) as long


WinMain inst,0,cmdline,SW_NORMAL

freelibrary kernel32
freelibrary user32
freelibrary gdi32
terminate

; o2 !10 ; align 16 bytes

;=====================================

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

def CW_USEDEFAULT 0x80000000
def WS_OVERLAPPEDWINDOW 0x00cf0000


'------------------------------------------------------------
Function WinMain(byval inst as long ,byval prevInst as long,
byval cmdline as long , byval show as long) as long
'===========================================================
'
; window handle

dim a,b,c,hWnd as long
dim wc as WndClass
dim wm as MSG

with wc. '
style=CS_HREDRAW or CS_VREDRAW
lpfnWndProc=&WndProc '#long#long#long#long
cbClsExtra=0
cbWndExtra=0
hInstance=inst
hIcon=LoadIcon 0, IDI_APPLICATION
hCursor=LoadCursor 0,IDC_ARROW
hbrBackground=GetStockObject WHITE_BRUSH '
lpszMenuName=0
lpszClassName=`HelloWin`
end with

if not RegisterClass &wc
MessageBox 0,`Registration failed`,`Problem`,MB_ICONERROR
exit function
end if '

hWnd=CreateWindowEx 0,wc.lpszClassName,`Hello Window`,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,640,480,
0,0,inst,0

if not hWnd then
MessageBox 0,`Unable to create window`,`problem`,MB_ICONERROR
exit function
end if
'
ShowWindow hWnd,show
UpdateWindow hWnd
;
;MESSAGE LOOP
;
while GetMessage &wm,0,0,0
TranslateMessage &wm
DispatchMessage &wm
wend
;
function=wm.wparam

end function ; end of WinMain


type RECT
; 16 bytes
left as long
top as long
right as long
bottom as long
end type

type rgbacolor
red as byte
green as byte
blue as byte
alpha as byte
end type

type PAINTSTRUCT
; 64 bytes
hDC as long
fErase as long
rcPaint as rect
fRestore as long
fIncUpdate as long
rgb as rgbacolor
Reserved as 32
end type

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

'-----------------------------------------
function WndProc ( byval hWnd as long,
byval wMsg as long, byval wParam as long,
byval lparam as long ) as long callback
'=========================================

dim cRect as rect
dim Paintst as paintstruct
dim hDC as long

select wMsg

'--------------
case WM_CREATE
'=============

'--------------
case WM_DESTROY
'===============

PostQuitMessage 0

'------------
case WM_PAINT
'============

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

'--------------
case WM_KEYDOWN
'==============

if wParam=27 then
PostMessage hWnd,WM_CLOSE,0,0
end if

'--------
case else
'========

function=DefWindowProc hWnd,wMsg,wParam,lParam

end select

end function ' WndProc

"

o2_basic src

'File_Save("t.txt",o2_len+$cr+o2_error+"o2h "+o2_prep src ) ': stop
if len(o2_error) then msgbox 0,o2_error : stop

o2_exec

marcuslee
21-03-2009, 15:45
It is amazing how much code it takes to do something so simple. That's why I like BASIC syntax. But, sometimes it is good to remind yourself what all is going on in the background.

Mark

Charles Pegge
21-03-2009, 16:25
Hi Mark,
Yes the Windows API is a ponderous beast - but the program here also incorporates a chunk of the Windows equates which are normally hidden away somewher in header files.

In the 4 port Viewer example, The header files for Opengl, supplied with thinBasic are invoked and they contain about 5000 equates :shock: It does make you wonder.

Charles.

zlatkoAB
21-03-2009, 20:11
Hi...
Charles, i'm fascinating with your oxigen compiler. :)
But why this example dont work on my computer.
I have downloaded last thinBasic release and your TBO2H zip with
.dll?
I do next:
Copy and paste this example in ThinAir and start.
But I recive error message :
Error code 18
Error description Unknown keyword
Line number 262
Line code O2_Basic src

What i do wrong? :roll:

marcuslee
21-03-2009, 20:22
But I recive error message :
Error code 18
Error description Unknown keyword
Line number 262
Line code O2_Basic src

What i do wrong? :roll:


I had this same problem when I tried to open it. I replaced the DLL file that comes with TB with the one you downloaded seperately.

The DLLs are found in the thinbasic/Lib folder of your TB installation. Put the newsest Oxygen DLL in there. You will probably have to replace it with an older one.


Mark

Charles Pegge
21-03-2009, 20:41
As this is a prerelease version of Oxygen, the best thing to do is to leave the DLL in the same directory as the scripts that use it. thinBasic will then use this version instead of the original (Assembler only) Oxygen.

Did you manage to capture the full script ZLatko? I know it is a bit lengthy for a posting. There is a copy in the zip file 029.tbasic

Charles

marcuslee
21-03-2009, 20:46
As this is a prerelease version of Oxygen, the best thing to do is to leave the DLL in the same directory as the scripts that use it. thinBasic will then use this version instead of the original (Assembler only) Oxygen.



Good thing to know, and the safer way to do it. But, of course, you could make a back up of the original ... which I didn't do ... :oops: Oh well, not that worried about it. :unguee:


Mark

zlatkoAB
21-03-2009, 21:02
Sorry I think that I make mistake :roll:
I don't know that i use tb 1.7.0.0 so I uninstall 1.7.0.0 and just
download 1.7.7.0 .
Then I unpak oxigen.zip in oxygen folder .
Finaly I found this example 029 and work fine.
Great! :)
I'm little curious,someona told me that is not posible made
window from api with interpreter becose lpfnwndproc can't be
fired from interpreter.
I see that in this example is posible.

lpfnwndproc as long
So is this thing do .dll included in zip?
Or is this normal thing which can be executed from other
interpreter which support api-s?

Zlatko

Charles Pegge
21-03-2009, 21:54
Hi Zlatco,

If your interpreter supports API calls then you can certainly run Windows from it directly

This is the code which you may not see in other compilers. It calls WinMain, and it is what you have to do at the very start of your procedure.




dim cmdline,inst as long

cmdline=GetCommandLine
inst=GetModuleHandle 0

declare Function WinMain(byval inst as long ,byval prevInst as long ,byval cmdline as long , byval show as long) as long
declare function WndProc(byval hWnd as long, byval wMsg as long, byval wParam as long, byval lparam as long) as long


WinMain inst,0,cmdline,SW_NORMAL




But you may encounter timing problems if you try to run the message loop in interpreted code. In some of my early experiments with scripting languages, Some Windows messages seemed to time out. So you will probably need to manage the message loop as an internal operation.

Charles

zlatkoAB
21-03-2009, 22:21
Charles you are great,thanks. :D
Yes I see something similiar but without WinMain .
Yes CBasic support API-s.
I have error with
"kernel32",_GetCommandLine ALIAS GetCommandLineA(),STRING
Ok i will try on your way.

Zlatko

Charles Pegge
21-03-2009, 22:31
You dont often need getCommandline, this works fine :)



inst=GetModuleHandle 0
WinMain inst,0,0,SW_NORMAL

zlatkoAB
21-03-2009, 22:56
Aha...
Ok I will try tomorow,becose i get sleep.
Thanks again... :)

zlatkoAB
22-03-2009, 14:27
Charles i try all posible combination but still refuse to work :(

Charles Pegge
22-03-2009, 16:35
Hi Zlatco

You can run a message box even before entering WinMain and see whether your system returns a plausible module handle. (Zero means it wont give you one.). Messageboxes are one of the best debugging tools when dealing with low level Windows stuff, (As long as they are not used inside a long loop :) )


In O2H:


cmdline=GetCommandLine
inst=GetModuleHandle 0
print str inst

zlatkoAB
22-03-2009, 16:51
Hi Charles...
I know that MessageBox is great tool and i use them alot when i make
some stuff in my interpreter.
but this time I think that is useless I think that CBasic is limited in
current case (Paul told me that is not posibile?)
If you wish I can sand you Pm with source code.
You are expert in this area.
I do everithing but whitout succses,I'm little bit disapointed.

Charles Pegge
22-03-2009, 18:07
Have you looked at FreeBasic, Zlatco? I chose to use it for Oxygen because of its cross-platform capability and compiling down to x86 code, of course. Though I have not explored all of its features, I find it to be very stable,predictable and fast, which are all essential for building higher level software systems.

Charles.

zlatkoAB
22-03-2009, 18:55
Yes Free Basic is good and probably is capable for producing
Window from API becose is compiler.
I already have EBasic which is capable for that.
As i see thinBasic can't produce Window from API directly
without your oxigen module and without .dll included.
Or maby I'm wrong?

Thanks Zlatko

Charles Pegge
22-03-2009, 19:25
ThinBasic can certainly call any DLL directly by using a declaration with a LIB specification. The main issue is can it handle a low level callback for an interpreted Wndproc - Eros would be able to answer this one :)

Charles

zlatkoAB
22-03-2009, 20:16
Yes the main problem is in WinProc.
So how return function directly

case else
function=DefWindowProc hWnd,wMsg,wParam,lParam

To here:


lpfnWndProc=&WndProc '#long#long#long#long

This part don't work from CBasic.
Maby thinBasic can do that.
If can ,that would be fantastic.
So Eros what you say it is posible directly from thinBasic open
window with API-s-?

Michael Hartlef
23-03-2009, 14:24
Paul told me that is not posibile?



Hi Zlatko,

don't believe everything you get told by this guy, especially when he sells a competing commercial product.

There is allways a possibility.

Cheers
Michael

zlatkoAB
23-03-2009, 16:39
Hi Michael...

I don't believe everything what he saying but this time i think
that is true.It looks that is Cbasic limited in this concret problem.
I have source code from VB6 for API Window but I don't try them
yet.As i see thinBasic can do that with oxygen modul and with
oxygen .dll .
Maby it's posible directly - that would be cool.

Zlatko

Michael Hartlef
23-03-2009, 17:02
Ok, I thought he ment in general not possible.

zlatkoAB
24-03-2009, 08:33
Hi I must say that is very interesting problematic and like Charles say
i find something very interesting on Free Basic Forum.Look code:

#Include "windows.bi"

Dim As MSG msg ' Message variable (stores massages)
Dim As HWND hWnd ' Window variable

' Create window
hWnd = CreateWindowEx( 0, "#32770", "Hello", WS_OVERLAPPEDWINDOW Or WS_VISIBLE, 100, 100, 500, 300, 0, 0, 0, 0 )

While GetMessage( @msg, 0, 0, 0 ) ' Get message from window
TranslateMessage( @msg )
DispatchMessage( @msg )

Select Case msg.hwnd
Case hWnd ' If msg is window hwnd: get messages from window
Select Case msg.message
Case 273 ' Get message when 'X' was pressed
End
End Select
End Select
Wend

You must say that look very simple. :roll:
And little bit weird.So i try something similiar on CBasic and work
but not properly.I can open new window,without focus and can not
be closed with closebox button"X".One interesting thing ,window is
like standalone compiled app :shock:
I don't try on thinBasic bacose i don't know shape of APi-s.
Is the same like this or different?

DECLARE "user32",CreateWindowExA(dwExStyle AS INT,lpClassName AS STRING,lpWindowName AS STRING,dwStyle AS INT,x AS INT,y AS INT,nWidth AS INT,nHeight AS INT,hWndParent AS INT,hMenu AS INT,hInstance AS INT,lpParam AS INT),INT
DECLARE "user32",GetMessageA(lpMsg AS MSG,hwnd AS INT,wMsgFilterMin AS INT,wMsgFilterMax AS INT),INT
DECLARE "user32",TranslateMessage(lpMsg AS MSG),INT
DECLARE "user32",DispatchMessageA(lpMsg AS MSG),INT
DECLARE "user32", PostQuitMessage(nExitCode AS INT)

Charles Pegge
24-03-2009, 11:08
Hi Zlatco,

Try 256 instead of 273. 256 is the WM_KEYDOWN message -

this is what I tried in o2h (wm is the message variable)




while GetMessage &wm,0,0,0
TranslateMessage &wm
DispatchMessage &wm
'
select wm.hwnd
case hwnd
if wm.message=256 then print `key down` : exit do
end select
'
wend

zlatkoAB
24-03-2009, 13:12
Hi Charles...

I always recive error that Argument is wrong type in

While GetMessageA( wmsg,0, 0, 0 ) :' Get message from window

So which message close window?
Or what argument is wrong ,hmm it looks very tricky.

Charles Pegge
24-03-2009, 14:36
GetMessage needs the address of the message: varptr(msg) &msg or @msg, whatevever syntax Cbasic uses.

I am assuming the Win header files follow the standard C version.

Charles

zlatkoAB
24-03-2009, 17:14
Aha I see ...
So there is the main problem .
CBasic can't pass or see adress so only I can try with pointer.
But i think that is not posible.
Whatever thanks on all answers,Charles.

Zlatko