Okay, here's a good one. In MASM, it's possible to create a struct and use it to model what would otherwise be a C++ class, or perhaps a COM object. Even simulate polymorphism and inheritance in some ways. Good enough. Now, here's where the question begins: with the struct, everything is public, so-to-speak. Let's say I wanted some variables which will be relevant to each instance of the type, but won't be exposed to the outside world (private members). In struct, there's no way to do this, since it's all private. If I have local variables in the asm file of relevance, there is a single copy, and if I have 10 of these structures in use, and they all need to do something, specially on a thread, I"m screwed. Two ways of solving this, create an array of the "private" variables, indexed to the number of "structs" in use. Which is a crummy solution. The next solution I thought of, is to leave the private memebers out of the struct defined in the include file for people to use. This requires they be the last members or you're screwed. But I can see this wouldn't be good either. Anyone have a better way of achieving this??? Thanks, _Shawn
Posted on 2001-03-11 22:01:00 by _Shawn
Provide the user with an external struct and use another one interally. If the user can access the private members, then you haven't wrapped them good enough - or you over documented the interface :P The interface defines the amount of containment that you have. The more dynamic the interface - the less containment you have, and the more cohesion between your code and the external code. Assembly language programmers tend to favor a lot of cohesion - the code is faster, but not as universal. The rest of modern programming has went full speed in the other direction. Just my twisted view :P bitRAKE
Posted on 2001-03-11 23:10:00 by bitRAKE
How to 'contain' a class. A class in the OOP sense has a public interface, and a private implementation. It would be nice if we say had a proc named CONSTRUCTOR that wouldn't get confused with the other 12 classes we need, each having it's own procedure of the same name. In my current project, that's the situation I have. In just a sense of general cleanliness, I wanted to do just such a containment, mostly to insure some of the stuff I was writing was truly re-useable (i.e., didn't sneak in any global variables). Here's how I did it, using several COM classes. Each class goes inside a .asm file for a separate compilation to object code. Whatever needs to be public goes into a separate .inc file. This file gets included into that .asm, and whatever other .asm modules are going to use the class. Here's a list of the exports for my cProject Class from the cProject.inc file:

sLIBID_Project     TEXTEQU    {blah blah blah}
sCLSID_cProject    TEXTEQU    {blah blah blah}
sIID_IProject      TEXTEQU    {blah blah blah}

externdef          LIBID_Project:  GUID
externdef          CLSID_cProject: GUID
externdef          IID_IProject:   GUID
externdef          ProjectClass:   ClassItem

pLIBID_Project     EQU   OFFSET LIBID_Project
pCLSID_cProject    EQU   OFFSET CLSID_cProject
pIID_IProject      EQU   OFFSET IID_IProject

ProjectCreationInfo	STRUCT
	{some custom members to create specific initiated object types)
ProjectCreationInfo	ENDS

_vtIProject MACRO CastName:REQ
{one of those silly interface definition macros with all the comethods thingies}
ENDM

IProject              STRUCT
    _vtIProject IProject
IProject              ENDS
Thus, the interface for the Class is public, ready for use by the rest of the project. As are the GUIDS, either as text (which is probably not needed), buy more importantly, the GUIDS themselves are defined in the .data area of the Class, and the pointers to them are defined. Hiding inside this list is this curious item:

externdef          ProjectClass:   ClassItem
The ClassItem is the structure that defines the class to the CoLib AllocObject proc. It's quite important to export this, as it is used to create new objects through this procedure, like so:

invoke AllocObject, ADDR pProj, ADDR ProjectClass, NULL, ADDR pci
Where pProj is the COM object pointer we get in return, and pci is a ProjectCreationInfo structure to initialize the newborn object to a specific project. (The NULL is for the outer Unknown, since it's not being aggregated we don't indicate one). The .asm file is compiled to a library with this:

ml /nologo /c /coff cProject.asm
lib cProject.obj /out:cProject.lib
In use, the project (small 'p') using this class includes the .inc and includelib the .lib of this Class. The ProjectObjData (the private object instance data structure) is NOT accessable to the whole project. In fact, all the private variables, structures, procedures, in fact, everything but some GUIDS and the ClassItem are hidden inside the library. Post Mortem: One thing to note this code in NOT for a DLL server, so no ClassMap is needed. The ClassMap needs specific info for each class (the ClassItem), arranged into a structure list. You would need some way (code?) to copy individual ClassItems into a single monolithic list. My latest thinking on ClassMaps is they should be a list of ClassItem pointers to get around this limitation. However, this would break all existing projects written with CoLib. Get ready for this, CoLib 2.0 will be using these ClassItem pointers. (Now Hiro, don't you go moving this thread to the COM section) ;-) This message was edited by Ernie, on 3/12/2001 2:16:40 AM
Posted on 2001-03-12 01:10:00 by Ernie
Good going Ernie! I'd like to...oh, boy...encapsulate the Web Browser control in a lib so it will be easier for everyone to use. I haven't posted it yet anyway (because I can't to get ASM code to talk to the HTML DOM). Any words of wizdom? Xtreme
Posted on 2001-03-12 09:23:00 by xtreme
Ernie, So this means that I have a struct for example, in my asm file, and then what I want exposed goes into the inc (that's also included with the (asm?) or the one that goes to the users?? and is used by the other modules of the project? Does this also mean that the private data would be the last members of the struct to ensure that they can be hidden without alignment problems? Thanks, Shawn
Posted on 2001-03-12 10:00:00 by _Shawn
Yes, the inc file of public information is shared by both the class asm and with the rest of the project. This keeps everyone playing the same game.
Posted on 2001-03-12 10:42:00 by Ernie
The SmallTalk solution is to make all data private, and to allow access via "getter" and "setter" functions. In ASM, these functions could be macros, which would eliminate the CALL-RET overhead.
Posted on 2001-03-12 14:15:00 by tank
Is it possible to nest structures and then access them, like in VB I can say X = mystruc.substruct.value In asm, is such a thing possible? This would happen if a structure contains a member which is another structure _SHawn
Posted on 2001-03-12 19:30:00 by _Shawn
Yep. Possible. I think the limit is 20 nestings deep. Just be aware that myself and others note bugs as you do this, in my case it was forgetting default values. However, since that time I have not been able to make the bug re-occure (damnit, I spent a bad Sunday morning tracking it and making a work-around, I should keep the bad source too?) Anyway, say you have:

S1 STRUCT
  A1 DW ?
S1 ENDS

S2 STRUCT
  B1 DW ?
  Ax S1 {}
S2 ENDS

SS2 S2  {}

Then you can access it as

mov S2.Ax.A1, null
Posted on 2001-03-12 23:52:00 by Ernie