I have been pottering around the C/C++ documentation on "typedef enum" and it gives the appearance of being a clapped out old technique for replacing long lists of C #define statements and while I probably would not write MASM code using such an ancient technique, the SDK header files have a reasonable number of structures that have "enum" members and without some technique to emulate the "enum" format those structures cannot be used in MASM.
The unallocated form of structures are sequentiall numbered based on the data size, 1 for BYTE, 2 for WORD etc .... which appears to be an internal method of MASM keeping track of the size of structure members but it does not lend itself well to non-sequential nuberings so i have tried out another method of initialised structure members but it has the limitation that it must be allocated in the initialised data section. This is the test piece.
IF 0 ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Build this template with "CONSOLE ASSEMBLE AND LINK"
ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include\masm32rt.inc
ENUM TEXTEQU <STRUCT>
POWERS_OF_2 ENUM
item0 dd ?
item1 dd ?
item2 dd ?
item3 dd ?
item4 dd ?
item5 dd ?
item6 dd ?
item7 dd ?
item8 dd ?
item9 dd ?
item10 dd ?
item11 dd ?
POWERS_OF_2 ENDS
POWERS_OF_2_UNUM_VALUES_@@@@ equ <0,1,2,4,8,16,32,64,128,256,512,1024>
NEWSTRUCT STRUCT
somevalue dd ?
pow POWERS_OF_2 <POWERS_OF_2_UNUM_VALUES_@@@@>
anothervalue dd ?
NEWSTRUCT ENDS
.data
po2 NEWSTRUCT <> ; initialised ENUM data must be in initialised data section
.code
start:
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
call main
inkey
exit
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
main proc
print ustr$(po2.pow.item0),13,10
print ustr$(po2.pow.item1),13,10
print ustr$(po2.pow.item2),13,10
print ustr$(po2.pow.item3),13,10
print ustr$(po2.pow.item4),13,10
print ustr$(po2.pow.item5),13,10
print ustr$(po2.pow.item6),13,10
print ustr$(po2.pow.item7),13,10
print ustr$(po2.pow.item8),13,10
print ustr$(po2.pow.item9),13,10
print ustr$(po2.pow.item10),13,10
print ustr$(po2.pow.item11),13,10
ret
main endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end start
The output is as follows.
0
1
2
4
8
16
32
64
128
256
512
1024
Press any key to continue ...
Now what I wonder is if there are any problems in performing this action where the data size is set where properly an "enum" data type is effectively no sized equates. I note that the later C++ header files embed the enum values in a structure and are usually typed as ULONG or similar 32 bit DWORD sized values.
As far as the Windows headers are concerned I have yet to find an enumerated type that is not a DWORD.
When I was experimenting with the first version I created two small C apps to see what the Microsoft compilers do with enumerates.
//=============================================================================
#include <windows.h>
#include <conio.h>
#include <stdio.h>
#include <AccCtrl.h>
//=============================================================================
/*
typedef enum _SE_OBJECT_TYPE
{
SE_UNKNOWN_OBJECT_TYPE = 0,
SE_FILE_OBJECT,
SE_SERVICE,
SE_PRINTER,
SE_REGISTRY_KEY,
SE_LMSHARE,
SE_KERNEL_OBJECT,
SE_WINDOW_OBJECT,
SE_DS_OBJECT,
SE_DS_OBJECT_ALL,
SE_PROVIDER_DEFINED_OBJECT,
SE_WMIGUID_OBJECT,
SE_REGISTRY_WOW64_32KEY
} SE_OBJECT_TYPE;
typedef struct _OBJECTS_AND_NAME_A
{
DWORD ObjectsPresent;
SE_OBJECT_TYPE ObjectType;
LPSTR ObjectTypeName;
LPSTR InheritedObjectTypeName;
LPSTR ptstrName;
} OBJECTS_AND_NAME_A, *POBJECTS_AND_NAME_A;
*/
int main(void)
{
OBJECTS_AND_NAME_A oana;
oana.ObjectsPresent = 123;
oana.ObjectType = SE_UNKNOWN_OBJECT_TYPE;
printf("%d\t%d\t",oana.ObjectsPresent,oana.ObjectType);
printf("%d\n",sizeof(oana.ObjectType));
oana.ObjectsPresent = 123;
oana.ObjectType = SE_FILE_OBJECT;
printf("%d\t%d\t",oana.ObjectsPresent,oana.ObjectType);
printf("%d\n",sizeof(oana.ObjectType));
oana.ObjectsPresent = 123;
oana.ObjectType = SE_SERVICE;
printf("%d\t%d\t",oana.ObjectsPresent,oana.ObjectType);
printf("%d\n",sizeof(oana.ObjectType));
// With C, even when the enumeration named, you can substitute
// values that are not defined in the the enumeration.
oana.ObjectsPresent = 123;
oana.ObjectType = -1;
printf("%d\t%d\t",oana.ObjectsPresent,oana.ObjectType);
printf("%d\n",sizeof(oana.ObjectType));
getch();
return 0;
}
123 0 4
123 1 4
123 2 4
123 -1 4
//=============================================================================
#include <windows.h>
#include <conio.h>
#include <stdio.h>
//=============================================================================
/*
typedef enum {
BIDI_NULL = 0,
BIDI_INT = 1,
BIDI_FLOAT = 2,
BIDI_BOOL = 3,
BIDI_STRING = 4,
BIDI_TEXT = 5,
BIDI_ENUM = 6,
BIDI_BLOB = 7
} BIDI_TYPE;
typedef struct _BINARY_CONTAINER {
DWORD cbBuf;
LPBYTE pData;
} BINARY_CONTAINER, *PBINARY_CONTAINER;
typedef struct _BIDI_DATA {
DWORD dwBidiType;
union {
BOOL bData;
INT iData;
LPWSTR sData;
FLOAT fData;
BINARY_CONTAINER biData;
} u;
} BIDI_DATA, *PBIDI_DATA, *LPBIDI_DATA;
*/
//
// This causes redefinition errors because the names of the enumerators
// must be unique within the scope where the enum is defined.
//
/*
typedef enum
{
BIDI_NULL = 0,
BIDI_INT = 1,
BIDI_FLOAT = 2,
BIDI_BOOL = 3,
BIDI_STRING = 4,
BIDI_TEXT = 5,
BIDI_ENUM = 6,
BIDI_BLOB = 7
} SOME_OTHER_NAME;
*/
int main(void)
{
BIDI_DATA bid;
bid.dwBidiType = BIDI_NULL;
printf("BIDI_NULL %d\n",bid.dwBidiType);
bid.dwBidiType = BIDI_INT;
printf("BIDI_INT %d\n",bid.dwBidiType);
bid.dwBidiType = BIDI_FLOAT;
printf("BIDI_FLOAT %d\n",bid.dwBidiType);
bid.dwBidiType = BIDI_BLOB;
printf("BIDI_BLOB %d\n",bid.dwBidiType);
printf("sizeof(BINARY_CONTAINER) %d\n",sizeof(BINARY_CONTAINER));
printf("sizeof(BIDI_DATA) %d\n",sizeof(BIDI_DATA));
getch();
return 0;
}
BIDI_NULL 0
BIDI_INT 1
BIDI_FLOAT 2
BIDI_BLOB 7
sizeof(BINARY_CONTAINER) 8
sizeof(BIDI_DATA) 12
set file="test"
set PATH=C:\Program Files\Microsoft Visual C++ Toolkit 2003\bin;%PATH%
set INCLUDE=C:\Program Files\Microsoft SDK\include;C:\Program Files\Microsoft Visual C++ Toolkit 2003\include;%INCLUDE%
set LIB=C:\Program Files\Microsoft SDK\Lib;C:\Program Files\Microsoft Visual C++ Toolkit 2003\lib;%LIB%
cl /W4 /FA %file%.c
pause
I still cannot see any situation where a straightforward ENUM macro would not work as well as a structure definition, and be easier to create and use.
Michael,
> I still cannot see any situation where a straightforward ENUM macro would not work as well as a structure definition, and be easier to create and use.
I would be interested to see what you had in mind with a macro, even if its just a sketch of how it is supposed to work. Where I have problems in building assembler include files is when a structure has a member that has a "typedef enum" as one of its members.
typedef enum _FILE_ID_TYPE {
FileIdType,
ObjectIdType,
MaximumFileIdType
} FILE_ID_TYPE, *PFILE_ID_TYPE;
typedef struct FILE_ID_DESCRIPTOR {
DWORD dwSize; // Size of the struct
FILE_ID_TYPE Type; // Describes the type of identifier passed in.
union {
LARGE_INTEGER FileId;
GUID ObjectId;
};
} FILE_ID_DESCRIPTOR, *LPFILE_ID_DESCRIPTOR;
Now I am open to suggestion here but normally from within a structure you reference a data structure like an enum in the same manner as a nested struct that is outside the struct definition.
_Type FILE_ID_TYPE <>
For the enum macros, drizz has posted several versions along with some related stuff:
http://www.masm32.com/board/index.php?topic=13269.msg103175#msg103175
http://www.masm32.com/board/index.php?topic=9038.msg65478#msg65478
http://www.masm32.com/board/index.php?topic=5366.msg40204#msg40204
I have had a look at the macros that Drizz has posted but I am none the wiser in how they should be used. Its technically trivial to produce a sequence of numbers with an equate,
name equ <1,2,3,4,5,6,7,8>
and of course there are other ways of doing it but I need a technique where the enumeration can be called from a structure like a C style "typedef enum". This is why I have so far tried using a structure as it can be called from another structiure with conventional notation.