Currently, as i have said before, Thomas and myself are busy hacking out a new 'compiler' tool to ease the development of Object Classes in MASM. The entire developed syntax was basically an extension of Ernie's COM work.

I quickly built an earlier version, but it needed more 'editor' like features ~ realizing we humans tend to change our minds :) (Its still available on my web-site for those interested).

My question is concerning how many people are truely interested in this appending style of ASM programming? I felt i got a luke warm reaction when I made the first version, and to my surprise i found out it wasnt the cumbersom tool design, but more often than not, people dont truely understand the High Level lingo of Objects and Classes. (Quite understandable in an ASM world... :) )

So, having explained my reasons, please choose the best option that fits how you feel about OOP in MASM. Our second tool design is total new and fresh, and will continue regardless, but i would like to know how I should to begin to package & introduce its strengths to the community...

Thanx alot..

NaN
Posted on 2001-07-19 22:07:32 by NaN
I've edited your thread topic a bit so it would more easily attract people :grin:
Posted on 2001-07-19 23:12:22 by Hiroshimator
Hmmm, there's no choice that fits me :(. I've got a pretty good concept
of OOP, and I think it can be very useful from time to time. But, I don't
know if it will be useful for me in asm. I guess it depends on a couple
of factors.

First is it easy to use? If it's a lot more work than a procedural methods,
I'll stick to procedural methods.

Second, how large is the overhead? As far as I can see, you should
be able to get the overhead down pretty much, but it will of course
depend on you implementation :).

Will you use the COM? Or something that looks like it? In other ways,
will it be possible to use your tool to build interfaces for existing
COM objects?

This sounds like a pretty interesting project, keep up the good work.
Posted on 2001-07-20 00:23:49 by f0dder
To add some more details about the format of the objects: The classes are quite compact and there isn't much overhead. It definitely doesn't uses COM but it uses some of the basic things that COM uses (really basic things)..
A class is simply a structure with variables as normal data (dwords, words whatever you like), and a set of pointers to it's methods (not in a separate vtable, just plain in the structure). A method is simply a normal procedure, but with of course an lpThis as first parameter.
That's about it right now.. In the previous object tool NaN created the structure is initialized in the constructor with a set of movs, but we plan to do this smarter in the next version, like an already filled structure with initial data and a memory copy in the constructor, to save bytes and time.. The methods are invoked with about the same macro Ernie wrote to call COM object methods.
So I don't think there's much overhead. But I will not be writing everything in classes now (although the next object tool is, for cooperating easily), but for some things it can be very handy because every object has it's own data space..
However, if we want to implement some more high level things like inheritance (which could be useful too), we have a bigger problem. As the macro syntax of MASM is not powerfull enough to handle multi-layer multi-class inheritance (well maybe it can be done in macro's but we don't want 1000 lines of macros and another 1000 for each class definition :) ). A solution could be writing a preparser that parses the file before masm gets it but I think many people won't like this (because then wysi NOT wyc). Although the parser won't change much, only fill in the right address for a method call, I don't think people will like the idea of a parser that does things behind your back.. Maybe we add a poll for this though.

Thomas

P.S. If you want to get an example of the class definition, download the previous tool at NaN's site, there is an example in the zip file.

edit: Is it easy to use? Well it's not hard to modify the file by hand but it's not really fun to change all the definitions if you just want to add a method. But this is solved by the object tool. While the first object tool is simply a generator for a new class, the next will be able to load up existing files and let you modify procedure definitions, variables, methods etc on the fly like you would do in Visual C++. The tool preserves all your existing code and just changes the code as you would do it yourself.. It's not that it's too complicated to modify the class yourself, it's just that it's too much work:alright:
Posted on 2001-07-20 04:24:20 by Thomas
to some people, COM is a monster and dare not touch it. but to most, COM is a must and the reasons are undefine except to one individual. COM is quite new and will grow over the next 2 or 3 years (or better yet, it's growing right now!) if you're coding for windows and not understanding what COM is, i'm sure you will be behind as technology grows... i'm not windows' fan (you know... a thing that blow air when you're hot?) but still believe that your project will be a great asset for those who are coding in windows. and i think you should continue on that project cause the bar is running fast!

reason why i don't code COM in masm:
VC++ has COM. :)

masm is my hammer.
Posted on 2001-07-20 07:14:35 by disease_2000

First is it easy to use? If it's a lot more work than a procedural methods, I'll stick to procedural methods.


Yes its easy to use. As Thomas described, Its use is a direct parallel to how you would use COM's.. The difference is instead of "coinvoke" there is "METHOD". To create a new instance there is "NEWOBJECT" and to destroy this instance there is "DESTROY". (Theses are in my first package on my web-site). To further this thought, once you have a class written the way you want it, it should be completely re-usable in ANY project (saving development time on future projects..).

Currently, the first Object Creator tool only generates new class files for you (based on the methods/variables you want in your class). This is easy to use, as it builds a template, and all you do is code your methods much like normal functions. But if you want to add a new method, it required manual editing which is a bit more work. (Just like COM's, there is a fucntion pointer system (generated by the Object creator)). The function pointer system is based off Ernie's COM model. There is 4 separate lines to add in 4 sections + the method code to add per Method. This can be annoying to keep modifying, and is why i devised the tool in the first place. To keep it to the point of just adding Method code, and let the "red-tape" be taken care of by the Tool.

So, In direct answer: No, once the second version is complete it will be no more work than procedural Methods. (You still have to think about what you want ~ but this is the same in normal procedural coding :) )


Second, how large is the overhead? As far as I can see, you should be able to get the overhead down pretty much, but it will of course depend on you implementation .


Again, Thomas has this pretty well wrapped up. I would just like to add that what i was getting as was the # of lines needed to implement function pointing (described a bit above). Its alot of repetative typing and easy to loose track of a typo in the midst of it!. This is all set-up for the compiler however, non of this gets translated into code!! It just allows the compiler to understand that some structure members are function offsets (Methods procs), so it wont complain when you compile something like "invoke eax" (which is basically what is in the METHOD macro).


Will you use the COM? Or something that looks like it? In other ways, will it be possible to use your tool to build interfaces for existing COM objects?


Definitely! The system is based off the COM structure but in no way is it COM. Every method proc is essencially a funtion. And thus has all the capabilities a function would. What you choos to do in a method is up to you!



More Facts:
========

The Class File has:
- The function pointing "red-tape" the MASM wants.
- A structure having :DWORD offsets for methods + variables
- The Structure is termed a "Class" (but still just a Struct)
- Every Class MUST have a "Constructor" method offset
- Every Class MUST have a "Destructor" method offset
- All Method Function code. (just like normal functions + 1 more param LpTHIS)


Objects in more Detail
================

When the above is compiled, only the Method Function code makes it to bits and bytes in your exe. (In essence Classes are "Function Organization" practices).

To use a Class, an area of Dynamic memory is reserved (based on the Class stucture size ~ small!!), using the "NEWOBJECT myClass" Macro. This allocated memory address is returned as an "Object Instance" pointer. Just before the the macro returns this, the Class constructor method (a must) is called, were the function offsets are assigned to the "Method" members.

So, an "Instance" has varaiables and a bunch of Method offsets. Taking up minimal memory. The varialbes are Private to the memory allocated (like a normal stucture allocated in memory).

When another "instance" is created, the Method offsets will again point to the same Method code, but the variables (all having the same Name) will be in a separate memory space, and thus be unqiue between instances. This is why they are call "Instances" Every INSTANCE is unique in the data it holds, but its Variable names, and Method behaviour is not!.

Method can be written to Do something like Get_Variable_Y, (which should retrieve the data from the instance's Y variable).

When an instance calles a Method, secretely behind the scenes, the first parameter is the address pointer to the instance in memory (lpTHIS). The method function then uses the address pointer to correctly get the Y variable data from the specific instance!! This is how once 'function' can service an infinite # of instances, and correctly get the unique Y data in each Instance.

So to recap in less English: (and simplified a bit)


.. Method Red Tape for MASM ...

PointClass STRUCT
Destructor RedTapeDefinedType1 ?
X_DataVar DD ?
Y_DataVar DD ?
Get_Y RedTapeDefinedType2 ?
Get_X RedTapeDefinedType3 ?
PointClass ENDS

.code

Constructor PROC lpTHIS:DWORD, X_Data:DWORD, Y_Data:DWORD

mov edx, lpTHIS
assume edx:PTR PointClass

mov [edx].Get_Y, offset Get_Y_Function
mov [edx].Get_X, offset Get_X_Function
mov [edx].X_DataVar, X_Data
mov [edx].Y_DataVar, Y_Data

assume edx:NOTHING
ret
Constructor ENDP

Get_Y_Function PROC lpTHIS:DWORD
mov edx, lpTHIS
assume edx:PTR PointClass

mov eax, [edx].Y_DataVar

assume edx:NOTHING
ret
Get_Y_Function ENDP


So in use you would see this:



NEWOBJECT PointClass, 10, 20
mov Piont1, eax

NEWOBJECT PointClass, 0, 1002
mov Piont2, eax

METHOD Point1, PointClass, Get_Y

; EAX == 20

METHOD Point2, PointClass, Get_Y

; EAX == 1002

DESTROY Point1
DESTROY Point2


If you notice in the Method code for Get_Y, it never specifically 'knows' the address of the varaible because it is given to the method when its entered.

As well each instance is == to the structure size. (20 bytes for this), and only one set of functions are needed for any number of instances.

An example of its use could be better understood as a HTML_Link class. Where each instance on creation places a Static Label on a window, saving its handle in the object class. Each URL is stored within the instance as variable data, and has a method "gotoURL" for each instance.

Th gotoURL method would be coded to recieve the given handle from the BN_CLICKED message a compare it to its own instance handle. If it is the same, then do URL code..., esle return NULL.

All URL instances encapsulate unique data about themselves (URL links), yet have a common method to do something about it (gotoURL).

Anyways this has become WWWWWWWWWWWWAAAAAAAAAAAYYYYYYY tooooo long, so i stop while im ahead.... (my Girlfriend wants the computer back :rolleyes: )

NaN
:stupid: bables too much
Posted on 2001-07-20 13:36:34 by NaN
what if future version of masm has built-in oop?
Posted on 2001-07-20 14:11:51 by disease_2000
what if future version of masm has built-in oop?



Well, we don't have it now. Also, we don't know whether there will be a future version of MASM, we don't know whether there won't. If there is, then appropriate modifications can be adapted. Otherwise, it would appear this helps.

However, I think the future MASM is closer to what the .NET MSIL program is, it's all interpreted :(


Thanks,
_Shawn
Posted on 2001-07-20 15:30:49 by _Shawn
I choose the last option, but I'd like to add: I know it's going to slow my code down if I use it, but I know it will speed up my coding. I think OOP in MASM is for people who want to stick with one language and get HLL features (IMHO).

Personally, I'd prefer a preprocessor and to have the OO stuff integrated into ASM like a language extention. I'd also like the ablity to reduce any object from object representation to basic ASM - this would allow the programmer to throw things together at a high level and then thrash around at a lower level optimizing stuff - destroying the object concept locally.
Posted on 2001-07-20 16:29:54 by bitRAKE
i'm very interest in the tutorial :) if it's possible that you two can make one that is easy for beginner.
Posted on 2001-07-20 16:49:30 by nop
Tutorials and Examples are definitely planned... Kinda why i wanted such feedback to learn basically what the going views are, so i may better taylor tutorials.

All in all i think there results look good, but i will give it some more time and see...

I would also like to say that BitRake is correct, it will add the overhead of function calling rather than directly coding functions inline with your code. As well there tends to be more single-purpose functions. So speed is ever so slightly diminished in most cases. As well he is also correct in that it will help you code faster. Good Classes allow for re-usability, and its best to write any class for this in mind. However, I do tend to deviate when i feel that the extra overhead out weighs its re-usability use. No one says you must adhear to any rules with this. If you want to write a class while knowing something is in global memory and dont care for re-usability, then skip the "Set_Parameter" method to pass data to the instance and just write your code to reference it directly.

OOP pro's really tend to frown on this, but who cares if you can afford it here and there to save runing speed.

As well, I used the object 'format' and made a few modifications to handle all the tab selections on the new tool. Currently there is 5 master selections in a tree-view and each selection has two tab displays (Properties and Actual code). So in all there is 10 separate window 'displays' to toggle between when browsing the tree or tabs. To do this, use "ShowWindow" alot!!! I need to first hide all controls on one display, and then show all the correct controls for the new display. This would be a nightmare if it wasnt for objects. My solution was about 10 lines of code to manage....

I built a TABDISPLAY class with no varialbes and only 4 methods (Tab_X_Create, Tab_X_Show, Tab_X_Hide, Tab_X_Destroy). Then I erased the Method code generated (Actual Funtion Code) and edited the constructor to accept 4 parameters, and set the method offsets like so:


; This is the constructor (Init)
TABDISP_Init PROC lpTHIS:DWORD, Create:DWORD, Destroy:DWORD, \
Show:DWORD, Hide:DWORD, hWin:DWORD
mov eax, lpTHIS
m2m (TABDISP PTR [eax]).destroy, Destroy
m2m (TABDISP PTR [eax]).Hide, Hide
m2m (TABDISP PTR [eax]).Show, Show

push hWin
mov eax, Create
call eax

ret
TABDISP_Init ENDP

Sample Creation Code:


; Private Var TV Group (Code Edit Tab) ; --======================
NEWOBJECT TABDISP, offset T2PrVarCreate, offset T2PrVarDestroy, \
offset T2PrVarShow, offset T2PrVarHide, hWin
mov hT2PrVar, eax

This allows me to assign a Method Routine to a given instance on creation (Rather than the same one for all instances).

Every Unique tab display was written in a separate file, each having a these 4 behavior code for its unique display.
(( Sample: Code Window Tab for Private Variables ))

.code
T2PrVarCreate PROC hWin:DWORD
; Place all create code here for this tab display
; Do Edit Control
invoke CreateWindowEx, WS_EX_CLIENTEDGE ,
ADDR edClass, ADDR szObject,
WS_CHILD or WS_HSCROLL or WS_VSCROLL or \
ES_AUTOHSCROLL or ES_AUTOVSCROLL or \
ES_MULTILINE or ES_LEFT,
ED_X,ED_Y,ED_WD,ED_HT,hWin,Edit1ID,
hInstance,NULL
mov hEdit1, eax
DebugPrint ">> Tab 2 Private Var Created <<"
ret

T2PrVarCreate ENDP

T2PrVarShow PROC
; Do Show Window Stuff here for this display
invoke ShowWindow, hEdit1, SW_SHOW
DebugPrint ">> Tab 2 Private Var Shown <<"
ret
T2PrVarShow ENDP

T2PrVarHide PROC
; Do Hide window stuff here for this display
invoke ShowWindow, hEdit1, SW_HIDE
DebugPrint ">> Tab 2 Private Var Hidden <<"
ret
T2PrVarHide ENDP

T2PrVarDestroy PROC
; if needed, destroy any reserved memory created...
DebugPrint ">> Tab 2 Private Var Destroyed <<"
ret
T2PrVarDestroy ENDP

I create one instance of this class for each display, and then when the Tree-view message comes in saying Selection was made, no thinking is needed to decide which display it is and which display is currently shown.

I simply get the current object handle being displayed (stored globally) and call its Hide method (METHOD eax, TABDISP, Hide) and then get the lParam outa the tree selection (which houses the TABDISP handle for its selection) and call its show method (METHOD ecx, TABDISP, Show).

Thats it for thinking it thru... all that deals with each display is nicely encapsulated in each file in to these four groups and since each insance is UNIQUE, yet has the same Method names I can do this with out problem.

There is no real savings here as there is a 1:1 relation between the number of method's to write, and the number of instances created. I would at least provide the same code in a proceedural way!, but using the Class i can easily manage them without a case-like if structure to determine which function should be executed next.. The uniqeness of each instance allowes me to 'bundle' fucntions together under common names as described above, and then the handler routine doesnt care about the specifics.. it just wants to "hide" one and "show" the next...

Neat Trick eh?

:alright:
NaN
Posted on 2001-07-20 23:27:15 by NaN
Will the object constructor (actually the object creation method) take arguments?

A variable ammount of arguments?

Well, will it?


;=)
Posted on 2001-07-22 18:43:46 by Ernie
correct me if i am wrong but OOP = using structs etc, so is this not already integrated into masm?
Posted on 2001-07-22 21:13:04 by SubHuman
Nah, OOP isn't part of MASM.

No matter, I do OOP all the time in MASM.

OOP is about objects, and yes an object is just a glorified instanced structure.

BUT, just having structures doesn't mean you have OOP. OOP means you can create, manupulate, employ, persist, and destroy objects. Not to mention the code development advantages of inheritance and encapsulation.

Most of this has been worked out already by many people. The only piece I've never seen is implimentation inheritance (ie, reusing code from a base class without rewriting it). I've never really needed this (or actually seen it as a great tool) or I'd have worked on it too.
Posted on 2001-07-22 22:29:14 by Ernie
Will the object constructor (actually the object creation method) take arguments?

A variable ammount of arguments?

Well, will it?


Yes, the macro was designed for flexibility in this area.. the DESTROY macro however doesnt have a variable argument list... no need to make this process complex or problems could arise when one object destroys another object in a recursive nature (TreeView killing its Data Objects).. Simply go "DESTROY TreeInstance", and the destructor of the TreeView Class 'should' recurse its own tree first, and destroy all the objects it houses. In this situation, having a possible parameter list for 'some' classes would mean doing research on this class just to destroy it!! (( These were my reasons in not providing the option in the destroy macro ))

Back to you question, here is the actual NEWOBJECT macro...
NEWOBJECT MACRO ObjType:REQ, args:VARARG


LOCAL instring
instring CATSTR <invoke >,<&ObjType>,<_Init, eax>
IFNB <args>
instring CATSTR instring, <, >, <&args>
ENDIF

invoke GetProcessHeap
invoke HeapAlloc, eax, NULL, SIZEOF ObjType

push eax
instring
pop eax
ENDM


About inheritance, I did say at one point i had it figured out, but it then realized a fatal problem so its back in the R&D department :grin: . It has prooven to be a tricky foe, there is solutions however, but nothing that doesnt involve pre-processing befor ML.exe gets ahold of your ASM. (Thomas pointed out that while there is very little change (modify your object structures), most people probably wouldnt like the lost of control with their code... as well as not seeing what is actually being piped into ML after the pre-processing). The is other options available as well, but we decided to just get the version 2 up with the technical abilities the first one did + the editor features for re-loading and editing existing classes. Once this is going another version will tackle these issues..


:alright:
NaN
Posted on 2001-07-22 23:55:04 by NaN