PDA

View Full Version : OOP Framework - reveals oxygen bug -



efgee
12-09-2010, 04:14
Hi,
the following code shows how an oop framework could be implemented.

In any case there is a oxygen bug that reveals himself - as 2 lines in the "FrameworkTest.o2inc" need to be commented out in order to make the compiled exe not crash but run smoothly...

This is the framework dll:


' Framework.o2bas
'
' OOP Application Framework
' efgee

#file "oFramework.dll"

; =======
; imports
; =======
dim as long kernel32 = LoadLibrary ("kernel32.dll")
bind kernel32 (
GetCommandLine_ GetCommandLineA : @0
GetModuleHandle_ GetModuleHandleA : @4
ExitProcess_ ExitProcess : @4
)


dim as long user32 = LoadLibrary "user32.dll"
bind user32 (
MessageBox_ MessageBoxA : @16
DestroyWindow_ DestroyWindow : @4
GetMessage_ GetMessageA : @16
TranslateMessage_ TranslateMessage : @4
DispatchMessage_ DispatchMessageA : @4
PostMessage_ PostMessageA : @16
PostQuitMessage_ PostQuitMessage : @4
DefWindowProc_ DefWindowProcA : @16
LoadIcon_ LoadIconA : @8
LoadCursor_ LoadCursorA : @8
RegisterClass_ RegisterClassA : @4
CreateWindowEx_ CreateWindowExA : @48
ShowWindow_ ShowWindow : @8
UpdateWindow_ UpdateWindow : @4
' BeginPaint_ BeginPaint : @8
' EndPaint EndPaint : @8
' GetClientRect GetClientRect : @8
' DrawText DrawTextA : @20
' SetParent SetParent : @8
' SetClassLong SetClassLong : @12
)


dim as long GDI32 = LoadLibrary ("GDI32.dll")
bind GDI32 (
GetStockObject_ GetStockObject : @4
)

; ==========
; structures
; ==========
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


; c style definition is possible too...
struct point {
x as long
y as long
}

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


; ========
; declares
; ========
declare function WndProc (byval hWnd as long, byval wMsg as long, byval wParam as long, byval lparam as long) as long


; =========
; constants
; =========
def true 1
def false 0
def fail -1

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
def SW_NORMAL 1
def SW_SHOWDEFAULT 10
def WM_CREATE 1
def WM_DESTROY 2
def WM_PAINT 15
def WM_CLOSE 16
def WM_KEYDOWN 256
def WS_VISIBLE 0x10000000
def WS_CHILD 0x40000000
def BS_TEXT 0
def MB_OK 0
def MB_ICONERROR 0x00000010
def MB_ICONQUESTION 0x00000020
def MB_ICONWARNING 0x00000030
def MB_ICONINFORMATION 0x00000040

; =========
; variables
; =========

; public static _MainWindow as LONG

extern


' ============================================================================
'
' oAPP - is the application class
' -
' - Run - message loop, returns error code if occured...
' - Quit - kills main window, initiates message loop to end
' - CommandLine - returns the command line (at start of program)
' - InfoBox - info message box
' - ErrorBox - error message box
' - QuestionBox - question message box
' - WarningBox - warning message box
'
' ============================================================================
class oAPP alias "oAPP" export
private static _Instance as LONG
private static _Return as LONG
private static _Message as MSG
private static _Command as string
private static _LastWindow as LONG
private static _LastChild as long
private static _ExitCode as long

method ctor()
method dtor()
method Instance() as long
method Run()
method Quit()
method CommandLine() as string
method InfoBox(_Text as string)
method ErrorBox(_Text as string)
method QuestionBox(_Text as string)
method WarningBox(_Text as string)
/
end class

methods of oAPP
' ===========
' CONSTRUCTOR
' ===========
method ctor()

print "APP ctor"
this._Instance = GetModuleHandle_(0)

zstring ptr _cmd
&_cmd = GetCommandLine_()
this._Command = _cmd

end method


' ==========
' DESTRUCTOR
' ==========
method dtor()
' do something

print "APP dtor"
freelibrary (kernel32)
freelibrary (user32)
'freelibrary (gdi32)

'PostQuitMessage_( 0 )
ExitProcess_(this._ExitCode)
end method


' ========
' INSTANCE
' ========
method Instance() as long

method = this._Instance

end method


' ===
' RUN
' ===
method run()

;MESSAGE LOOP
;
do while this._Return := GetMessage_(&this._message, 0, 0, 0)

if this._Return == -1 then
'do something significant
'like closing open files etc.
else
TranslateMessage_(&this._message)
DispatchMessage_(&this._message)
end if

wend
;


this._ExitCode = this._message.wparam

end method


' ====
' Quit
' ====
method Quit()
; DestroyWindow_(this._MainWindow)
PostQuitMessage_( 0 )
end method


' ===========
' COMMANDLINE
' ===========
method CommandLine() as string
method = this._Command
end method


' =======
' INFOBOX
' =======
method InfoBox(_Text as string)
long style
style = MB_ICONINFORMATION | MB_OK
MessageBox_(_LastWindow, *_Text, "Info", style)
end method


' ========
' ErrorBOX
' ========
method ErrorBox(_Text as string)
long style
style = MB_ICONERROR | MB_OK
MessageBox_(_LastWindow, *_Text, "Error", style)
end method


' ===========
' QuestionBOX
' ===========
method QuestionBox(_Text as string)
long style
style = MB_ICONQUESTION | MB_OK
MessageBox_(_LastWindow, *_Text, "Question", style)
end method


' ==========
' WarningBOX
' ==========
method WarningBox(_Text as string)
long style
style = MB_ICONWARNING | MB_OK
MessageBox_(_LastWindow, *_Text, "Warning", style)
end method

end methods

'end extern


'extern
' ====
' FORM - proper description still missing...
' ====
class oFORM alias "oFORM" export

protected static _Instance as LONG
protected static _MainWindow as LONG
protected static _LastWindow as LONG
protected static _LastChild as LONG


hwnd as long
wc as WndClass

method ctor ()
print "FORM ctor"

this._Instance = GetModuleHandle_(0)

with this.wc
.style = CS_HREDRAW or CS_VREDRAW
.lpfnWndProc = &WndProc
.cbClsExtra = 0
.cbWndExtra = 0
.hInstance = this._Instance
.hIcon = LoadIcon_(0, IDI_APPLICATION)
.hCursor = LoadCursor_(0, IDC_ARROW)
.hbrBackground = GetStockObject_(WHITE_BRUSH)
.lpszMenuName = 0
.lpszClassName = "HelloWin"
end with

if not RegisterClass_(&this.wc)
MessageBox_(0, "Registration failed", "Problem", MB_ICONERROR)
exit method
end if

this.hWnd = CreateWindowEx_(0,
wc.lpszClassName,
"Hello OOP Window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
0,
this._Instance,
0)

if not this.hWnd then
MessageBox_(0, "Unable to create window", "problem", MB_ICONERROR)
exit method
end if

if not this._MainWindow
this._MainWindow = this.hWnd
end if

_LastWindow = this.hWnd
'this._LastWindow = this.hWnd
'print this._LastWindow

end method


method dtor()
print "FORM dtor"
;freelibrary (kernel32)
;freelibrary (user32)
'freelibrary (gdi32)
end method

public
method show()

ShowWindow_(this.hWnd, true)
UpdateWindow_(this.hWnd)

end method

end class

end extern

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

function = 0

select wMsg

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

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

PostQuitMessage_( 0 )

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

function = DefWindowProc_(hWnd, wMsg, wParam, lParam)

end select

end function ;WndProc


This is the test program:


' FrameworkTest.o2bas
'
' Test of OOP Application Framework
' efgee

#file "oFrameworkTest.exe"
#include "oFrameworkTest.o2inc"

; =====
; ENTRY
; =====
new oAPP app
new oFORM frm

app.infobox("Hi")
app.errorbox("Huh...")
app.warningbox("Wait")
app.questionbox("What")

frm.Show
app.run()

delete frm
delete app

; =========
; end entry
; =========



This is the include file for the test program (has 2 line commented out because of oxygen bug):


' FrameworkTest.o2inc
'
' Test of OOP Application Framework - Include File
' efgee

; ======
; macros
; ======
def new
dim as %1 byref %2
&%2 = news sizeof %1
%2.ctor()
end def

def delete
%1.dtor()
frees &%1
end def

extern lib "oFramework.dll"

class oAPP alias "oAPP"
protected static _Instance as LONG
protected static _Return as LONG
protected static _Message as MSG
protected static _Command as string
protected static _LastWindow as LONG
'protected static _LastChild as long ' this line needs to be commented out
'protected static _ExitCode as long ' this line needs to be commented out

method ctor()
method dtor()
method Instance() as long
method Run()
method Quit()
method CommandLine() as string
method InfoBox(_Text as string)
method ErrorBox(_Text as string)
method QuestionBox(_Text as string)
method WarningBox(_Text as string)
/
end class

class oFORM alias "oFORM"

protected static _Instance as LONG
protected static _MainWindow as LONG
protected static _LastWindow as LONG
protected static _LastChild as LONG

method ctor()
method dtor()
method show()
/
end class

end extern


; =========
; variables
; =========



----

Also it would be nice if the dll and the test program could share the class definition (when methods/end methods in the dll code is used) as they are the same except the first 2 lines (with big classes it would ease coding):

DLL code:


extern
class oAPP alias "oAPP" export
...


INC code:


extern lib "oFramework.dll"
class oAPP alias "oAPP"
...


If the syntax could be changed to:

DLL code:


extern lib export
#include "oFrameworkTest.o2inc"
end extern

methods of oAPP
...
end methods


INC code:


extern lib "oFramework.dll"
#include "oFrameworkTest.o2inc"
end extern


...and in the "oFrameworkTest.o2inc" file there would be the class definition:


class oAPP alias "oAPP"
...
end class


Or similar...

bye
efgee

Charles Pegge
12-09-2010, 07:35
Yikes! that looks complicated.

I would have great difficulty in unpicking that.

Could you put in some comments to explain the intent of each section of the program? We need some human interfacing here :)

Charles

Charles Pegge
12-09-2010, 15:18
efgee,

The problem was the client lacked some type definitions and the error went unreported.

So I have put the types into an inc file shared by the class library and its client test program.

I can see a few things I need to do like supporting a common definition of the classes as you suggested

Charles

efgee
12-09-2010, 19:01
Charles,
you are right, forgot hwnd and wc.

Also you put methods first, before protected class members (vars) is this a must?

What's the BackSlash real functionality?

Yes, supporting a common definition of the classes would be awesome.

Thank you
efgee

Charles Pegge
12-09-2010, 22:20
You do not have to put methods before static members but if you have a composite class-and-method block then methods will be first on the list. I want to change this behaviour and ensure that the members are always ordered as the script specifies.

The / slash marks the end of virtual members and the beginning of real members. (to which the compiler may add invisible virtual table pointers.)

Charles

Charles Pegge
13-09-2010, 13:53
efgee,

I've posted another Oxygen on sourceforge and it will support the syntax to allow single class definitions.

ClientSide:


extern lib "oFramework.dll"
include "frameworkdefs.inc"
end extern


Server/Library side


extern export
include "frameworkdefs.inc"
end extern


Then the export and lib attributes can be removed from the class header itself.

The test client now looks like this:

Client script


' FrameworkTest.o2bas
'
' Test of OOP Application Framework
' efgee

basic

#file "oFrameworkTest.exe"

extern lib "oFramework.dll"
include "frameworkdefs.inc"
end extern


; =====
; ENTRY
; =====

new oAPP app
new oFORM frm

app.infobox("Hi")
app.errorbox("Huh...")
app.warningbox("Wait")
app.questionbox("What")

frm.Show
app.run()

delete frm
delete app

; =========
; end entry
; =========


; =====
; CHECK
; =====

'print structureof oform


Charles

efgee
13-09-2010, 18:09
Charles,
you are THE MAN :eusaclap:

I'm really thankful that you can devote a lot of time to this project of yours.

Your dedication is outstanding!

Finally a native compiler were coding is fun again :eusadance:

Thank you
efgee

Charles Pegge
14-09-2010, 00:16
Most kind :)

Nearly three years full time on this project so far, but good fun and I've learnt so much in that time.

Charles

efgee
17-09-2010, 20:30
Hello Charles,

There is something strange happening that prevents me to do more things with Oxygen:

If another class is added the program stops working; a messagebox appears with the name _setup_newClass and thats it.

You can test it yourself:

1.) copy the oFORM class definition in the include file and rename it to: class oA_FORM alias "oA_FORM" export
2.) copy the oFORM methods in the dll source code and rename the methods header to: "methods of oA_FORM"
3.) compile dll and test program
4.) at start of test program a messagebox will appear with the text: "_setup_oA_FORM"

Hope it's an easy fix.

Thanks
efgee

Charles Pegge
18-09-2010, 05:56
Hi efgee,

Lets see your program :)

Charles

Charles Pegge
18-09-2010, 14:37
One possible reason for the problem is the client picking up the wrong dll. (if it has the same name). I've been caught by this a few times when testing programs in different locations.

The client picks up the old version and does not see your new classes.

Charles

efgee
18-09-2010, 21:02
Charles,
attached is a zip file with the 3 modified files.

I've modified them to the instructions above.

bye
efgee

Charles Pegge
19-09-2010, 03:45
Thanks efgee,

this is odd behaviour. The library side appears to be ok - the setup functions for each class show up in a PE viewer as expected. Yet the client cannot access the third function whichever one that happens to be...

Charles

Charles Pegge
19-09-2010, 16:58
The solution!

Organise the group of classes so that their names are in ascending ascii order. The DLL linker expects the symbol names to ascend and will not locate those which are out of order.

I will resolve this by sorting the entries before building the DLL but meanwhile here is the ascending order of classes

Bear in mind that CAPs come first followed by underscore followed by lowercase.


Charles



' ============================================================================
'
' oAPP - is the application class
' -
' - Run - message loop, returns error code if occured...
' - Quit - kills main window, initiates message loop to end
' - CommandLine - returns the command line (at start of program)
' - InfoBox - info message box
' - ErrorBox - error message box
' - QuestionBox - question message box
' - WarningBox - warning message box
'
' ============================================================================



class oAPP alias "oAPP"

method ctor()
method dtor()
method Instance() as long
method Run()
method Quit()
method CommandLine() as string
method InfoBox(_Text as string)
method ErrorBox(_Text as string)
method QuestionBox(_Text as string)
method WarningBox(_Text as string)

private

_Instance as LONG
_Return as LONG
_Message as MSG
_Command as string
_LastWindow as LONG
_LastChild as long
_ExitCode as long
/
end class

class oA_FORM alias "oA_FORM"

method ctor()
method dtor()
method show()

protected

_Instance as LONG
_MainWindow as LONG
_LastWindow as LONG
_LastChild as LONG
/
hwnd as long
wc as WndClass
end class



class oFORM alias "oFORM"

method ctor()
method dtor()
method show()

protected

_Instance as LONG
_MainWindow as LONG
_LastWindow as LONG
_LastChild as LONG
/
hwnd as long
wc as WndClass
end class